]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
046e5eb47280445e2ebee9cf89ba26c1726db017
[~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       viewport = GTK_VALUE_POINTER (*arg);
151       gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
152     case ARG_HSCROLLBAR_POLICY:
153       gtk_scrolled_window_set_policy (scrolled_window,
154                                       GTK_VALUE_ENUM (*arg),
155                                       scrolled_window->vscrollbar_policy);
156       break;
157     case ARG_VSCROLLBAR_POLICY:
158       gtk_scrolled_window_set_policy (scrolled_window,
159                                       scrolled_window->hscrollbar_policy,
160                                       GTK_VALUE_ENUM (*arg));
161       break;
162     default:
163       break;
164     }
165 }
166
167 static void
168 gtk_scrolled_window_get_arg (GtkObject        *object,
169                              GtkArg           *arg,
170                              guint             arg_id)
171 {
172   GtkScrolledWindow *scrolled_window;
173
174   scrolled_window = GTK_SCROLLED_WINDOW (object);
175
176   switch (arg_id)
177     {
178     case ARG_VIEWPORT:
179       GTK_VALUE_POINTER (*arg) = scrolled_window->viewport;
180       break;
181     case ARG_HSCROLLBAR_POLICY:
182       GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy;
183       break;
184     case ARG_VSCROLLBAR_POLICY:
185       GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy;
186       break;
187     default:
188       arg->type = GTK_TYPE_INVALID;
189       break;
190     }
191 }
192
193 static void
194 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
195 {
196   GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
197
198   gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
199
200   scrolled_window->hscrollbar = NULL;
201   scrolled_window->vscrollbar = NULL;
202   scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
203   scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
204   scrolled_window->autogenerated_viewport = FALSE;
205 }
206
207 GtkWidget*
208 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
209                          GtkAdjustment *vadjustment)
210 {
211   GtkWidget *scrolled_window;
212
213   scrolled_window = gtk_type_new (GTK_TYPE_SCROLLED_WINDOW);
214
215   gtk_scrolled_window_construct (GTK_SCROLLED_WINDOW (scrolled_window), hadjustment, vadjustment);
216
217   return scrolled_window;
218 }
219
220 void
221 gtk_scrolled_window_construct (GtkScrolledWindow *scrolled_window,
222                                GtkAdjustment     *hadjustment,
223                                GtkAdjustment     *vadjustment)
224 {
225   g_return_if_fail (scrolled_window != NULL);
226   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
227   g_return_if_fail (scrolled_window->hscrollbar == NULL);
228   g_return_if_fail (scrolled_window->vscrollbar == NULL);
229
230   scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
231   scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
232
233   hadjustment =
234     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
235   vadjustment =
236     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
237
238   gtk_signal_connect (GTK_OBJECT (hadjustment), "changed",
239                       (GtkSignalFunc) gtk_scrolled_window_adjustment_changed,
240                       (gpointer) scrolled_window);
241   gtk_signal_connect (GTK_OBJECT (vadjustment), "changed",
242                       (GtkSignalFunc) gtk_scrolled_window_adjustment_changed,
243                       (gpointer) scrolled_window);
244
245   gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
246   gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
247
248   gtk_widget_show (scrolled_window->hscrollbar);
249   gtk_widget_show (scrolled_window->vscrollbar);
250   
251   gtk_widget_ref (scrolled_window->hscrollbar);
252   gtk_widget_ref (scrolled_window->vscrollbar);
253 }
254
255 GtkAdjustment*
256 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
257 {
258   g_return_val_if_fail (scrolled_window != NULL, NULL);
259   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
260
261   return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
262 }
263
264 GtkAdjustment*
265 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
266 {
267   g_return_val_if_fail (scrolled_window != NULL, NULL);
268   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
269
270   return gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
271 }
272
273 void
274 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
275                                 GtkPolicyType      hscrollbar_policy,
276                                 GtkPolicyType      vscrollbar_policy)
277 {
278   g_return_if_fail (scrolled_window != NULL);
279   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
280
281   if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
282       (scrolled_window->vscrollbar_policy != vscrollbar_policy))
283     {
284       scrolled_window->hscrollbar_policy = hscrollbar_policy;
285       scrolled_window->vscrollbar_policy = vscrollbar_policy;
286
287       if (GTK_WIDGET (scrolled_window)->parent)
288         gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
289     }
290 }
291
292
293 static void
294 gtk_scrolled_window_destroy (GtkObject *object)
295 {
296   GtkScrolledWindow *scrolled_window;
297
298   g_return_if_fail (object != NULL);
299   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
300
301   scrolled_window = GTK_SCROLLED_WINDOW (object);
302
303   gtk_widget_destroy (scrolled_window->viewport);
304   gtk_widget_destroy (scrolled_window->hscrollbar);
305   gtk_widget_destroy (scrolled_window->vscrollbar);
306
307   if (GTK_OBJECT_CLASS (parent_class)->destroy)
308     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
309 }
310
311 static void
312 gtk_scrolled_window_finalize (GtkObject *object)
313 {
314   GtkScrolledWindow *scrolled_window;
315
316   scrolled_window = GTK_SCROLLED_WINDOW (object);
317   gtk_widget_unref (scrolled_window->viewport);
318   gtk_widget_unref (scrolled_window->hscrollbar);
319   gtk_widget_unref (scrolled_window->vscrollbar);
320
321   GTK_OBJECT_CLASS (parent_class)->finalize (object);
322 }
323
324 static void
325 gtk_scrolled_window_map (GtkWidget *widget)
326 {
327   GtkScrolledWindow *scrolled_window;
328
329   g_return_if_fail (widget != NULL);
330   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
331
332   if (!GTK_WIDGET_MAPPED (widget))
333     {
334       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
335       scrolled_window = GTK_SCROLLED_WINDOW (widget);
336
337       if (scrolled_window->viewport &&
338           GTK_WIDGET_VISIBLE (scrolled_window->viewport) &&
339           !GTK_WIDGET_MAPPED (scrolled_window->viewport))
340         gtk_widget_map (scrolled_window->viewport);
341
342       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
343           !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
344         gtk_widget_map (scrolled_window->hscrollbar);
345
346       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
347           !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
348         gtk_widget_map (scrolled_window->vscrollbar);
349     }
350 }
351
352 static void
353 gtk_scrolled_window_unmap (GtkWidget *widget)
354 {
355   GtkScrolledWindow *scrolled_window;
356
357   g_return_if_fail (widget != NULL);
358   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
359
360   if (GTK_WIDGET_MAPPED (widget))
361     {
362       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
363       scrolled_window = GTK_SCROLLED_WINDOW (widget);
364
365       if (scrolled_window->viewport &&
366           GTK_WIDGET_MAPPED (scrolled_window->viewport))
367         gtk_widget_unmap (scrolled_window->viewport);
368
369       if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
370         gtk_widget_unmap (scrolled_window->hscrollbar);
371
372       if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
373         gtk_widget_unmap (scrolled_window->vscrollbar);
374     }
375 }
376
377 static void
378 gtk_scrolled_window_draw (GtkWidget    *widget,
379                           GdkRectangle *area)
380 {
381   GtkScrolledWindow *scrolled_window;
382   GdkRectangle child_area;
383
384   g_return_if_fail (widget != NULL);
385   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
386   g_return_if_fail (area != NULL);
387
388   if (GTK_WIDGET_DRAWABLE (widget))
389     {
390       scrolled_window = GTK_SCROLLED_WINDOW (widget);
391
392       if (scrolled_window->viewport &&
393           gtk_widget_intersect (scrolled_window->viewport, area, &child_area))
394         gtk_widget_draw (scrolled_window->viewport, &child_area);
395
396       if (gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
397         gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
398
399       if (gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
400         gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
401     }
402 }
403
404 static void
405 gtk_scrolled_window_size_request (GtkWidget      *widget,
406                                   GtkRequisition *requisition)
407 {
408   GtkScrolledWindow *scrolled_window;
409   gint extra_height;
410   gint extra_width;
411
412   g_return_if_fail (widget != NULL);
413   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
414   g_return_if_fail (requisition != NULL);
415
416   scrolled_window = GTK_SCROLLED_WINDOW (widget);
417
418   requisition->width = 0;
419   requisition->height = 0;
420
421   if (scrolled_window->viewport &&
422       GTK_WIDGET_VISIBLE (scrolled_window->viewport))
423     {
424       gtk_widget_size_request (scrolled_window->viewport, &scrolled_window->viewport->requisition);
425
426       requisition->width += scrolled_window->viewport->requisition.width;
427       requisition->height += scrolled_window->viewport->requisition.height;
428     }
429
430   extra_width = 0;
431   extra_height = 0;
432
433   if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
434       GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
435     {
436       gtk_widget_size_request (scrolled_window->hscrollbar,
437                                &scrolled_window->hscrollbar->requisition);
438
439       requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width);
440       extra_height = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->hscrollbar->requisition.height;
441     }
442
443   if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
444       GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
445     {
446       gtk_widget_size_request (scrolled_window->vscrollbar,
447                                &scrolled_window->vscrollbar->requisition);
448
449       requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height);
450       extra_width = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->vscrollbar->requisition.width;
451     }
452
453   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width;
454   requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height;
455 }
456
457 static void
458 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
459                                    GtkAllocation *allocation)
460 {
461   GtkScrolledWindow *scrolled_window;
462   GtkAllocation viewport_allocation;
463   GtkAllocation child_allocation;
464   guint previous_hvis;
465   guint previous_vvis;
466   gint count;
467   
468   g_return_if_fail (widget != NULL);
469   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
470   g_return_if_fail (allocation != NULL);
471
472   scrolled_window = GTK_SCROLLED_WINDOW (widget);
473   widget->allocation = *allocation;
474
475   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
476     scrolled_window->hscrollbar_visible = TRUE;
477   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
478     scrolled_window->vscrollbar_visible = TRUE;
479
480   if (scrolled_window->viewport &&
481       GTK_WIDGET_VISIBLE (scrolled_window->viewport))
482     {
483       count = 0;
484
485       do {
486         gtk_scrolled_window_viewport_allocate (widget, &viewport_allocation);
487
488         child_allocation.x = viewport_allocation.x + allocation->x;
489         child_allocation.y = viewport_allocation.y + allocation->y;
490         child_allocation.width = viewport_allocation.width;
491         child_allocation.height = viewport_allocation.height;
492
493         previous_hvis = scrolled_window->hscrollbar_visible;
494         previous_vvis = scrolled_window->vscrollbar_visible;
495
496         gtk_widget_size_allocate (scrolled_window->viewport, &child_allocation);
497         /* If, after the first iteration, the hscrollbar and the
498          * vscrollbar flip visiblity, then we need both.
499          */
500         if ((count++) && 
501             (previous_hvis != scrolled_window->hscrollbar_visible) &&
502             (previous_vvis != scrolled_window->vscrollbar_visible))
503           {
504             scrolled_window->hscrollbar_visible = TRUE;
505             scrolled_window->vscrollbar_visible = TRUE;
506             break;
507           }
508
509         count++;
510       } while ((previous_hvis != scrolled_window->hscrollbar_visible) ||
511                (previous_vvis != scrolled_window->vscrollbar_visible));
512     }
513
514   if (scrolled_window->hscrollbar_visible)
515     {
516       if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
517         gtk_widget_show (scrolled_window->hscrollbar);
518
519       child_allocation.x = viewport_allocation.x;
520       child_allocation.y = viewport_allocation.y + viewport_allocation.height + SCROLLBAR_SPACING (scrolled_window);
521       child_allocation.width = viewport_allocation.width;
522       child_allocation.height = scrolled_window->hscrollbar->requisition.height;
523       child_allocation.x += allocation->x;
524       child_allocation.y += allocation->y;
525
526       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
527     }
528   else
529     {
530       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
531         gtk_widget_hide (scrolled_window->hscrollbar);
532     }
533
534   if (scrolled_window->vscrollbar_visible)
535     {
536       if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
537         gtk_widget_show (scrolled_window->vscrollbar);
538
539       child_allocation.x = viewport_allocation.x + viewport_allocation.width + SCROLLBAR_SPACING (scrolled_window);
540       child_allocation.y = viewport_allocation.y;
541       child_allocation.width = scrolled_window->vscrollbar->requisition.width;
542       child_allocation.height = viewport_allocation.height;
543       child_allocation.x += allocation->x;
544       child_allocation.y += allocation->y;
545
546       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
547     }
548   else
549     {
550       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
551         gtk_widget_hide (scrolled_window->vscrollbar);
552     }
553 }
554
555 static void
556 gtk_scrolled_window_add (GtkContainer *container,
557                          GtkWidget    *widget)
558 {
559   GtkScrolledWindow *scrolled_window;
560   GtkArgInfo *info_hadj;
561   GtkArgInfo *info_vadj;
562   GtkArg arg;
563   gchar *error;
564
565   g_return_if_fail (container != NULL);
566   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
567   g_return_if_fail (widget != NULL);
568
569   scrolled_window = GTK_SCROLLED_WINDOW (container);
570
571   if (scrolled_window->viewport)
572     gtk_container_remove (container, scrolled_window->viewport);
573
574   error = gtk_object_arg_get_info (GTK_OBJECT_TYPE (widget),
575                                    "hadjustment", &info_hadj);
576   if (!error)
577     {
578       error = gtk_object_arg_get_info (GTK_OBJECT_TYPE (widget),
579                                        "vadjustment", &info_vadj);
580   
581       if (!error)
582         {
583           gtk_object_set (GTK_OBJECT (widget),
584                           "hadjustment",
585                           gtk_scrolled_window_get_hadjustment
586                           (scrolled_window),
587                           "vadjustment",
588                           gtk_scrolled_window_get_vadjustment
589                           (scrolled_window),
590                           NULL);
591           scrolled_window->viewport = widget;
592           gtk_widget_set_parent (widget, GTK_WIDGET (scrolled_window));
593           gtk_widget_ref (widget);
594           scrolled_window->autogenerated_viewport = FALSE;
595         }
596     }
597
598   if (error)
599     {
600       g_free (error);
601
602       scrolled_window->viewport = gtk_viewport_new 
603         (gtk_scrolled_window_get_hadjustment (scrolled_window),
604          gtk_scrolled_window_get_vadjustment (scrolled_window));
605       gtk_widget_set_parent (scrolled_window->viewport,
606                              GTK_WIDGET (scrolled_window));
607       gtk_widget_ref (scrolled_window->viewport);
608       gtk_widget_show (scrolled_window->viewport);
609       scrolled_window->autogenerated_viewport = FALSE;
610
611       gtk_container_add (GTK_CONTAINER (scrolled_window->viewport), widget);
612
613       widget = scrolled_window->viewport;
614     }
615
616   if (GTK_WIDGET_VISIBLE (scrolled_window))
617     {
618       if (GTK_WIDGET_REALIZED (scrolled_window) &&
619           !GTK_WIDGET_REALIZED (widget))
620         gtk_widget_realize (widget);
621
622       if (GTK_WIDGET_MAPPED (scrolled_window) &&
623           !GTK_WIDGET_MAPPED (widget))
624         gtk_widget_map (widget);
625     }
626   
627   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (scrolled_window))
628     gtk_widget_queue_resize (widget);
629 }
630
631 static void
632 gtk_scrolled_window_remove (GtkContainer *container,
633                             GtkWidget    *widget)
634 {
635   GtkScrolledWindow *scrolled_window;
636
637   g_return_if_fail (container != NULL);
638   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
639   g_return_if_fail (widget != NULL);
640
641   scrolled_window = GTK_SCROLLED_WINDOW (container);
642   if (scrolled_window->viewport == widget ||
643       scrolled_window->hscrollbar == widget ||
644       scrolled_window->vscrollbar == widget)
645     {
646       /* this happens during destroy */
647
648       if (scrolled_window->viewport == widget)
649         scrolled_window->autogenerated_viewport = FALSE;
650
651       gtk_widget_unparent (widget);
652     }
653   else if (scrolled_window->autogenerated_viewport)
654     gtk_container_remove (GTK_CONTAINER (scrolled_window->viewport), widget);
655 }
656
657 static void
658 gtk_scrolled_window_forall (GtkContainer *container,
659                             gboolean      include_internals,
660                             GtkCallback   callback,
661                             gpointer      callback_data)
662 {
663   GtkScrolledWindow *scrolled_window;
664
665   g_return_if_fail (container != NULL);
666   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
667   g_return_if_fail (callback != NULL);
668
669   scrolled_window = GTK_SCROLLED_WINDOW (container);
670
671   if (scrolled_window->viewport)
672     (* callback) (scrolled_window->viewport, callback_data);
673   if (include_internals)
674     {
675       (* callback) (scrolled_window->vscrollbar, callback_data);
676       (* callback) (scrolled_window->hscrollbar, callback_data);
677     }
678 }
679
680 static void
681 gtk_scrolled_window_viewport_allocate (GtkWidget     *widget,
682                                        GtkAllocation *allocation)
683 {
684   GtkScrolledWindow *scrolled_window;
685
686   g_return_if_fail (widget != NULL);
687   g_return_if_fail (allocation != NULL);
688
689   scrolled_window = GTK_SCROLLED_WINDOW (widget);
690
691   allocation->x = GTK_CONTAINER (widget)->border_width;
692   allocation->y = GTK_CONTAINER (widget)->border_width;
693   allocation->width = MAX (1, widget->allocation.width - allocation->x * 2);
694   allocation->height = MAX (1, widget->allocation.height - allocation->y * 2);
695
696   if (scrolled_window->vscrollbar_visible)
697     allocation->width = MAX (1,
698       allocation->width - (scrolled_window->vscrollbar->requisition.width + SCROLLBAR_SPACING (scrolled_window)));
699   if (scrolled_window->hscrollbar_visible)
700     allocation->height = MAX (1, 
701       allocation->height - (scrolled_window->hscrollbar->requisition.height + SCROLLBAR_SPACING (scrolled_window)));
702 }
703
704 static void
705 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
706                                         gpointer       data)
707 {
708   GtkScrolledWindow *scrolled_win;
709   gboolean visible;
710
711   g_return_if_fail (adjustment != NULL);
712   g_return_if_fail (data != NULL);
713
714   scrolled_win = GTK_SCROLLED_WINDOW (data);
715
716   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
717     {
718       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
719         {
720           visible = scrolled_win->hscrollbar_visible;
721           scrolled_win->hscrollbar_visible =
722             ((adjustment->upper - adjustment->lower) > adjustment->page_size);
723           if (scrolled_win->hscrollbar_visible != visible)
724             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
725         }
726     }
727   else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
728     {
729       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
730         {
731           visible = scrolled_win->vscrollbar_visible;
732           scrolled_win->vscrollbar_visible =
733             ((adjustment->upper - adjustment->lower) > adjustment->page_size);
734           if (scrolled_win->vscrollbar_visible != visible)
735             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
736         }
737     }
738   else
739     {
740       g_warning ("could not determine which adjustment scrollbar received change signal for");
741       return;
742     }
743 }