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