]> Pileus Git - ~andy/gtk/blob - gtk/gtkscrolledwindow.c
removed assertements for constructed containers again, since this
[~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_HADJUSTMENT,
28   ARG_VADJUSTMENT,
29   ARG_HSCROLLBAR_POLICY,
30   ARG_VSCROLLBAR_POLICY,
31   ARG_WINDOW_PLACEMENT
32 };
33
34
35 static void gtk_scrolled_window_class_init         (GtkScrolledWindowClass *klass);
36 static void gtk_scrolled_window_init               (GtkScrolledWindow      *scrolled_window);
37 static void gtk_scrolled_window_set_arg            (GtkObject              *object,
38                                                     GtkArg                 *arg,
39                                                     guint                   arg_id);
40 static void gtk_scrolled_window_get_arg            (GtkObject              *object,
41                                                     GtkArg                 *arg,
42                                                     guint                   arg_id);
43 static void gtk_scrolled_window_destroy            (GtkObject              *object);
44 static void gtk_scrolled_window_finalize           (GtkObject              *object);
45 static void gtk_scrolled_window_map                (GtkWidget              *widget);
46 static void gtk_scrolled_window_unmap              (GtkWidget              *widget);
47 static void gtk_scrolled_window_draw               (GtkWidget              *widget,
48                                                     GdkRectangle           *area);
49 static void gtk_scrolled_window_size_request       (GtkWidget              *widget,
50                                                     GtkRequisition         *requisition);
51 static void gtk_scrolled_window_size_allocate      (GtkWidget              *widget,
52                                                     GtkAllocation          *allocation);
53 static void gtk_scrolled_window_add                (GtkContainer           *container,
54                                                     GtkWidget              *widget);
55 static void gtk_scrolled_window_remove             (GtkContainer           *container,
56                                                     GtkWidget              *widget);
57 static void gtk_scrolled_window_forall             (GtkContainer           *container,
58                                                     gboolean                include_internals,
59                                                     GtkCallback             callback,
60                                                     gpointer                callback_data);
61 static void gtk_scrolled_window_relative_allocation(GtkWidget              *widget,
62                                                     GtkAllocation          *allocation);
63 static void gtk_scrolled_window_adjustment_changed (GtkAdjustment          *adjustment,
64                                                     gpointer                data);
65
66
67 static GtkContainerClass *parent_class = NULL;
68
69
70 GtkType
71 gtk_scrolled_window_get_type (void)
72 {
73   static GtkType scrolled_window_type = 0;
74
75   if (!scrolled_window_type)
76     {
77       GtkTypeInfo scrolled_window_info =
78       {
79         "GtkScrolledWindow",
80         sizeof (GtkScrolledWindow),
81         sizeof (GtkScrolledWindowClass),
82         (GtkClassInitFunc) gtk_scrolled_window_class_init,
83         (GtkObjectInitFunc) gtk_scrolled_window_init,
84         /* reserved_1 */ NULL,
85         /* reserved_2 */ NULL,
86         (GtkClassInitFunc) NULL,
87       };
88
89       scrolled_window_type = gtk_type_unique (GTK_TYPE_CONTAINER, &scrolled_window_info);
90     }
91
92   return scrolled_window_type;
93 }
94
95 static void
96 gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
97 {
98   GtkObjectClass *object_class;
99   GtkWidgetClass *widget_class;
100   GtkContainerClass *container_class;
101
102   object_class = (GtkObjectClass*) class;
103   widget_class = (GtkWidgetClass*) class;
104   container_class = (GtkContainerClass*) class;
105   parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
106
107   gtk_object_add_arg_type ("GtkScrolledWindow::hadjustment",
108                            GTK_TYPE_ADJUSTMENT,
109                            GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
110                            ARG_HADJUSTMENT);
111   gtk_object_add_arg_type ("GtkScrolledWindow::vadjustment",
112                            GTK_TYPE_ADJUSTMENT,
113                            GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
114                            ARG_VADJUSTMENT);
115   gtk_object_add_arg_type ("GtkScrolledWindow::hscrollbar_policy",
116                            GTK_TYPE_POLICY_TYPE,
117                            GTK_ARG_READWRITE,
118                            ARG_HSCROLLBAR_POLICY);
119   gtk_object_add_arg_type ("GtkScrolledWindow::vscrollbar_policy",
120                            GTK_TYPE_POLICY_TYPE,
121                            GTK_ARG_READWRITE,
122                            ARG_VSCROLLBAR_POLICY);
123   gtk_object_add_arg_type ("GtkScrolledWindow::window_placement",
124                            GTK_TYPE_CORNER_TYPE,
125                            GTK_ARG_READWRITE,
126                            ARG_WINDOW_PLACEMENT);
127
128   object_class->set_arg = gtk_scrolled_window_set_arg;
129   object_class->get_arg = gtk_scrolled_window_get_arg;
130   object_class->destroy = gtk_scrolled_window_destroy;
131   object_class->finalize = gtk_scrolled_window_finalize;
132
133   widget_class->map = gtk_scrolled_window_map;
134   widget_class->unmap = gtk_scrolled_window_unmap;
135   widget_class->draw = gtk_scrolled_window_draw;
136   widget_class->size_request = gtk_scrolled_window_size_request;
137   widget_class->size_allocate = gtk_scrolled_window_size_allocate;
138
139   container_class->add = gtk_scrolled_window_add;
140   container_class->remove = gtk_scrolled_window_remove;
141   container_class->forall = gtk_scrolled_window_forall;
142
143   class->scrollbar_spacing = 5;
144 }
145
146 static void
147 gtk_scrolled_window_set_arg (GtkObject        *object,
148                              GtkArg           *arg,
149                              guint             arg_id)
150 {
151   GtkScrolledWindow *scrolled_window;
152
153   scrolled_window = GTK_SCROLLED_WINDOW (object);
154
155   switch (arg_id)
156     {
157     case ARG_HADJUSTMENT:
158       gtk_scrolled_window_set_hadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
159       break;
160     case ARG_VADJUSTMENT:
161       gtk_scrolled_window_set_vadjustment (scrolled_window, GTK_VALUE_POINTER (*arg));
162       break;
163     case ARG_HSCROLLBAR_POLICY:
164       gtk_scrolled_window_set_policy (scrolled_window,
165                                       GTK_VALUE_ENUM (*arg),
166                                       scrolled_window->vscrollbar_policy);
167       break;
168     case ARG_VSCROLLBAR_POLICY:
169       gtk_scrolled_window_set_policy (scrolled_window,
170                                       scrolled_window->hscrollbar_policy,
171                                       GTK_VALUE_ENUM (*arg));
172       break;
173     case ARG_WINDOW_PLACEMENT:
174       gtk_scrolled_window_set_placement (scrolled_window,
175                                          GTK_VALUE_ENUM (*arg));
176       break;
177     default:
178       break;
179     }
180 }
181
182 static void
183 gtk_scrolled_window_get_arg (GtkObject        *object,
184                              GtkArg           *arg,
185                              guint             arg_id)
186 {
187   GtkScrolledWindow *scrolled_window;
188
189   scrolled_window = GTK_SCROLLED_WINDOW (object);
190
191   switch (arg_id)
192     {
193     case ARG_HADJUSTMENT:
194       GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_hadjustment (scrolled_window);
195       break;
196     case ARG_VADJUSTMENT:
197       GTK_VALUE_POINTER (*arg) = gtk_scrolled_window_get_vadjustment (scrolled_window);
198       break;
199     case ARG_HSCROLLBAR_POLICY:
200       GTK_VALUE_ENUM (*arg) = scrolled_window->hscrollbar_policy;
201       break;
202     case ARG_VSCROLLBAR_POLICY:
203       GTK_VALUE_ENUM (*arg) = scrolled_window->vscrollbar_policy;
204       break;
205     case ARG_WINDOW_PLACEMENT:
206       GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement;
207       break;
208     default:
209       arg->type = GTK_TYPE_INVALID;
210       break;
211     }
212 }
213
214 static void
215 gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
216 {
217   GTK_WIDGET_SET_FLAGS (scrolled_window, GTK_NO_WINDOW);
218
219   gtk_container_set_resize_mode (GTK_CONTAINER (scrolled_window), GTK_RESIZE_QUEUE);
220
221   scrolled_window->child = NULL;
222   scrolled_window->hscrollbar = NULL;
223   scrolled_window->vscrollbar = NULL;
224   scrolled_window->hscrollbar_policy = GTK_POLICY_ALWAYS;
225   scrolled_window->vscrollbar_policy = GTK_POLICY_ALWAYS;
226   scrolled_window->hscrollbar_visible = FALSE;
227   scrolled_window->vscrollbar_visible = FALSE;
228   scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
229 }
230
231 GtkWidget*
232 gtk_scrolled_window_new (GtkAdjustment *hadjustment,
233                          GtkAdjustment *vadjustment)
234 {
235   GtkWidget *scrolled_window;
236
237   if (hadjustment)
238     g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
239
240   if (vadjustment)
241     g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
242
243   scrolled_window = gtk_widget_new (GTK_TYPE_SCROLLED_WINDOW,
244                                     "hadjustment", hadjustment,
245                                     "vadjustment", vadjustment,
246                                     NULL);
247
248   return scrolled_window;
249 }
250
251 void
252 gtk_scrolled_window_construct (GtkScrolledWindow *scrolled_window,
253                                GtkAdjustment     *hadjustment,
254                                GtkAdjustment     *vadjustment)
255 {
256   g_message ("gtk_scrolled_window_construct() is deprecated");
257   gtk_scrolled_window_set_hadjustment (scrolled_window, hadjustment);
258   gtk_scrolled_window_set_vadjustment (scrolled_window, vadjustment);
259   gtk_object_default_construct (GTK_OBJECT (scrolled_window));
260 }
261
262 void
263 gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
264                                      GtkAdjustment     *hadjustment)
265 {
266   g_return_if_fail (scrolled_window != NULL);
267   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
268   if (hadjustment)
269     g_return_if_fail (GTK_IS_ADJUSTMENT (hadjustment));
270   else
271     hadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
272
273   if (!scrolled_window->hscrollbar)
274     {
275       gtk_widget_push_composite_child ();
276       scrolled_window->hscrollbar = gtk_hscrollbar_new (hadjustment);
277       gtk_widget_pop_composite_child ();
278
279       gtk_widget_set_parent (scrolled_window->hscrollbar, GTK_WIDGET (scrolled_window));
280       gtk_widget_ref (scrolled_window->hscrollbar);
281       gtk_widget_show (scrolled_window->hscrollbar);
282     }
283   else
284     {
285       GtkAdjustment *old_adjustment;
286       
287       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
288       if (old_adjustment == hadjustment)
289         return;
290
291       gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
292                                      GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
293                                      scrolled_window);
294       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->hscrollbar),
295                                 hadjustment);
296     }
297   hadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar));
298   gtk_signal_connect (GTK_OBJECT (hadjustment),
299                       "changed",
300                       GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
301                       scrolled_window);
302   gtk_scrolled_window_adjustment_changed (hadjustment, scrolled_window);
303   
304   if (scrolled_window->child)
305     gtk_widget_scroll_adjustements (scrolled_window->child,
306                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
307                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
308 }
309
310 void
311 gtk_scrolled_window_set_vadjustment (GtkScrolledWindow *scrolled_window,
312                                      GtkAdjustment     *vadjustment)
313 {
314   g_return_if_fail (scrolled_window != NULL);
315   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
316   if (vadjustment)
317     g_return_if_fail (GTK_IS_ADJUSTMENT (vadjustment));
318   else
319     vadjustment = (GtkAdjustment*) gtk_object_new (GTK_TYPE_ADJUSTMENT, NULL);
320
321   if (!scrolled_window->vscrollbar)
322     {
323       gtk_widget_push_composite_child ();
324       scrolled_window->vscrollbar = gtk_vscrollbar_new (vadjustment);
325       gtk_widget_pop_composite_child ();
326
327       gtk_widget_set_parent (scrolled_window->vscrollbar, GTK_WIDGET (scrolled_window));
328       gtk_widget_ref (scrolled_window->vscrollbar);
329       gtk_widget_show (scrolled_window->vscrollbar);
330     }
331   else
332     {
333       GtkAdjustment *old_adjustment;
334       
335       old_adjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
336       if (old_adjustment == vadjustment)
337         return;
338
339       gtk_signal_disconnect_by_func (GTK_OBJECT (old_adjustment),
340                                      GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
341                                      scrolled_window);
342       gtk_range_set_adjustment (GTK_RANGE (scrolled_window->vscrollbar),
343                                 vadjustment);
344     }
345   vadjustment = gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar));
346   gtk_signal_connect (GTK_OBJECT (vadjustment),
347                       "changed",
348                       GTK_SIGNAL_FUNC (gtk_scrolled_window_adjustment_changed),
349                       scrolled_window);
350   gtk_scrolled_window_adjustment_changed (vadjustment, scrolled_window);
351
352   if (scrolled_window->child)
353     gtk_widget_scroll_adjustements (scrolled_window->child,
354                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
355                                     gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)));
356 }
357
358 GtkAdjustment*
359 gtk_scrolled_window_get_hadjustment (GtkScrolledWindow *scrolled_window)
360 {
361   g_return_val_if_fail (scrolled_window != NULL, NULL);
362   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
363
364   return (scrolled_window->hscrollbar ?
365           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)) :
366           NULL);
367 }
368
369 GtkAdjustment*
370 gtk_scrolled_window_get_vadjustment (GtkScrolledWindow *scrolled_window)
371 {
372   g_return_val_if_fail (scrolled_window != NULL, NULL);
373   g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), NULL);
374
375   return (scrolled_window->vscrollbar ?
376           gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar)) :
377           NULL);
378 }
379
380 void
381 gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
382                                 GtkPolicyType      hscrollbar_policy,
383                                 GtkPolicyType      vscrollbar_policy)
384 {
385   g_return_if_fail (scrolled_window != NULL);
386   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
387
388   if ((scrolled_window->hscrollbar_policy != hscrollbar_policy) ||
389       (scrolled_window->vscrollbar_policy != vscrollbar_policy))
390     {
391       scrolled_window->hscrollbar_policy = hscrollbar_policy;
392       scrolled_window->vscrollbar_policy = vscrollbar_policy;
393
394       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
395     }
396 }
397
398 void
399 gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
400                                    GtkCornerType      window_placement)
401 {
402   g_return_if_fail (scrolled_window != NULL);
403   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
404
405   if (scrolled_window->window_placement != window_placement)
406     {
407       scrolled_window->window_placement = window_placement;
408
409       gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
410     }
411 }
412
413 static void
414 gtk_scrolled_window_destroy (GtkObject *object)
415 {
416   GtkScrolledWindow *scrolled_window;
417
418   g_return_if_fail (object != NULL);
419   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (object));
420
421   scrolled_window = GTK_SCROLLED_WINDOW (object);
422
423   gtk_widget_unparent (scrolled_window->hscrollbar);
424   gtk_widget_unparent (scrolled_window->vscrollbar);
425   gtk_widget_destroy (scrolled_window->hscrollbar);
426   gtk_widget_destroy (scrolled_window->vscrollbar);
427
428   if (GTK_OBJECT_CLASS (parent_class)->destroy)
429     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
430 }
431
432 static void
433 gtk_scrolled_window_finalize (GtkObject *object)
434 {
435   GtkScrolledWindow *scrolled_window;
436
437   scrolled_window = GTK_SCROLLED_WINDOW (object);
438
439   gtk_widget_unref (scrolled_window->hscrollbar);
440   gtk_widget_unref (scrolled_window->vscrollbar);
441
442   GTK_OBJECT_CLASS (parent_class)->finalize (object);
443 }
444
445 static void
446 gtk_scrolled_window_map (GtkWidget *widget)
447 {
448   g_return_if_fail (widget != NULL);
449   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
450
451   if (!GTK_WIDGET_MAPPED (widget))
452     {
453       GtkScrolledWindow *scrolled_window;
454
455       scrolled_window = GTK_SCROLLED_WINDOW (widget);
456       GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
457
458       if (scrolled_window->child &&
459           GTK_WIDGET_VISIBLE (scrolled_window->child) &&
460           !GTK_WIDGET_MAPPED (scrolled_window->child))
461         gtk_widget_map (scrolled_window->child);
462
463       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
464           !GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
465         gtk_widget_map (scrolled_window->hscrollbar);
466
467       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
468           !GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
469         gtk_widget_map (scrolled_window->vscrollbar);
470
471       gtk_widget_queue_draw (widget);
472     }
473 }
474
475 static void
476 gtk_scrolled_window_unmap (GtkWidget *widget)
477 {
478   g_return_if_fail (widget != NULL);
479   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
480
481   if (GTK_WIDGET_MAPPED (widget))
482     {
483       GtkScrolledWindow *scrolled_window;
484
485       scrolled_window = GTK_SCROLLED_WINDOW (widget);
486       GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
487
488       if (scrolled_window->child &&
489           GTK_WIDGET_VISIBLE (scrolled_window->child) &&
490           GTK_WIDGET_MAPPED (scrolled_window->child))
491         gtk_widget_unmap (scrolled_window->child);
492
493       if (GTK_WIDGET_MAPPED (scrolled_window->hscrollbar))
494         gtk_widget_unmap (scrolled_window->hscrollbar);
495
496       if (GTK_WIDGET_MAPPED (scrolled_window->vscrollbar))
497         gtk_widget_unmap (scrolled_window->vscrollbar);
498
499       gtk_widget_queue_clear (widget);
500     }
501 }
502
503 static void
504 gtk_scrolled_window_draw (GtkWidget    *widget,
505                           GdkRectangle *area)
506 {
507   g_return_if_fail (widget != NULL);
508   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
509   g_return_if_fail (area != NULL);
510   
511   if (GTK_WIDGET_DRAWABLE (widget))
512     {
513       GtkScrolledWindow *scrolled_window;
514       GdkRectangle child_area;
515       
516       scrolled_window = GTK_SCROLLED_WINDOW (widget);
517       
518       if (scrolled_window->child && GTK_WIDGET_VISIBLE (scrolled_window->child) &&
519           gtk_widget_intersect (scrolled_window->child, area, &child_area))
520         gtk_widget_draw (scrolled_window->child, &child_area);
521
522       if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
523           gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
524         gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
525
526       if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
527           gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
528         gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
529     }
530 }
531
532 static void
533 gtk_scrolled_window_forall (GtkContainer *container,
534                             gboolean      include_internals,
535                             GtkCallback   callback,
536                             gpointer      callback_data)
537 {
538   GtkScrolledWindow *scrolled_window;
539
540   g_return_if_fail (container != NULL);
541   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
542   g_return_if_fail (callback != NULL);
543
544   scrolled_window = GTK_SCROLLED_WINDOW (container);
545
546   if (scrolled_window->child)
547     callback (scrolled_window->child, callback_data);
548   if (include_internals)
549     {
550       if (scrolled_window->vscrollbar)
551         callback (scrolled_window->vscrollbar, callback_data);
552       if (scrolled_window->hscrollbar)
553         callback (scrolled_window->hscrollbar, callback_data);
554     }
555 }
556
557 static void
558 gtk_scrolled_window_size_request (GtkWidget      *widget,
559                                   GtkRequisition *requisition)
560 {
561   GtkScrolledWindow *scrolled_window;
562   gint extra_height;
563   gint extra_width;
564
565   g_return_if_fail (widget != NULL);
566   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
567   g_return_if_fail (requisition != NULL);
568
569   scrolled_window = GTK_SCROLLED_WINDOW (widget);
570
571   requisition->width = 0;
572   requisition->height = 0;
573
574   if (scrolled_window->child && GTK_WIDGET_VISIBLE (scrolled_window->child))
575     {
576       gtk_widget_size_request (scrolled_window->child, &scrolled_window->child->requisition);
577
578       requisition->width += scrolled_window->child->requisition.width;
579       requisition->height += scrolled_window->child->requisition.height;
580     }
581
582   extra_width = 0;
583   extra_height = 0;
584
585   if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
586       GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
587     {
588       gtk_widget_size_request (scrolled_window->hscrollbar,
589                                &scrolled_window->hscrollbar->requisition);
590
591       requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width);
592       extra_height = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->hscrollbar->requisition.height;
593     }
594
595   if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
596       GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
597     {
598       gtk_widget_size_request (scrolled_window->vscrollbar,
599                                &scrolled_window->vscrollbar->requisition);
600
601       requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height);
602       extra_width = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->vscrollbar->requisition.width;
603     }
604
605   requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width;
606   requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height;
607 }
608
609 static void
610 gtk_scrolled_window_relative_allocation (GtkWidget     *widget,
611                                          GtkAllocation *allocation)
612 {
613   GtkScrolledWindow *scrolled_window;
614
615   g_return_if_fail (widget != NULL);
616   g_return_if_fail (allocation != NULL);
617
618   scrolled_window = GTK_SCROLLED_WINDOW (widget);
619
620   allocation->x = GTK_CONTAINER (widget)->border_width;
621   allocation->y = GTK_CONTAINER (widget)->border_width;
622   allocation->width = MAX (1, widget->allocation.width - allocation->x * 2);
623   allocation->height = MAX (1, widget->allocation.height - allocation->y * 2);
624
625   if (scrolled_window->vscrollbar_visible)
626     {
627       if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT ||
628           scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
629         allocation->x += (scrolled_window->vscrollbar->requisition.width +
630                           SCROLLBAR_SPACING (scrolled_window));
631
632       allocation->width = MAX (1, allocation->width -
633                                (scrolled_window->vscrollbar->requisition.width +
634                                 SCROLLBAR_SPACING (scrolled_window)));
635     }
636   if (scrolled_window->hscrollbar_visible)
637     {
638       if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT ||
639           scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
640         allocation->y += (scrolled_window->hscrollbar->requisition.height +
641                           SCROLLBAR_SPACING (scrolled_window));
642
643       allocation->height = MAX (1, allocation->height -
644                                 (scrolled_window->hscrollbar->requisition.height +
645                                  SCROLLBAR_SPACING (scrolled_window)));
646     }
647 }
648
649 static void
650 gtk_scrolled_window_size_allocate (GtkWidget     *widget,
651                                    GtkAllocation *allocation)
652 {
653   GtkScrolledWindow *scrolled_window;
654   GtkAllocation relative_allocation;
655   GtkAllocation child_allocation;
656   
657   g_return_if_fail (widget != NULL);
658   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
659   g_return_if_fail (allocation != NULL);
660
661   scrolled_window = GTK_SCROLLED_WINDOW (widget);
662   widget->allocation = *allocation;
663
664   if (scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
665     scrolled_window->hscrollbar_visible = TRUE;
666   if (scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
667     scrolled_window->vscrollbar_visible = TRUE;
668
669   if (scrolled_window->child && GTK_WIDGET_VISIBLE (scrolled_window->child))
670     {
671       gboolean previous_hvis;
672       gboolean previous_vvis;
673       guint count = 0;
674       
675       do
676         {
677           gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
678           
679           child_allocation.x = relative_allocation.x + allocation->x;
680           child_allocation.y = relative_allocation.y + allocation->y;
681           child_allocation.width = relative_allocation.width;
682           child_allocation.height = relative_allocation.height;
683           
684           previous_hvis = scrolled_window->hscrollbar_visible;
685           previous_vvis = scrolled_window->vscrollbar_visible;
686           
687           gtk_widget_size_allocate (scrolled_window->child, &child_allocation);
688
689           /* If, after the first iteration, the hscrollbar and the
690            * vscrollbar flip visiblity, then we need both.
691            */
692           if (count &&
693               previous_hvis != scrolled_window->hscrollbar_visible &&
694               previous_vvis != scrolled_window->vscrollbar_visible)
695             {
696               scrolled_window->hscrollbar_visible = TRUE;
697               scrolled_window->vscrollbar_visible = TRUE;
698
699               /* a new resize is already queued at this point,
700                * so we will immediatedly get reinvoked
701                */
702               return;
703             }
704           
705           count++;
706         }
707       while (previous_hvis != scrolled_window->hscrollbar_visible ||
708              previous_vvis != scrolled_window->vscrollbar_visible);
709     }
710   else
711     gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
712   
713   if (scrolled_window->hscrollbar_visible)
714     {
715       if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
716         gtk_widget_show (scrolled_window->hscrollbar);
717
718       child_allocation.x = relative_allocation.x;
719       if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
720           scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
721         child_allocation.y = (relative_allocation.y +
722                               relative_allocation.height +
723                               SCROLLBAR_SPACING (scrolled_window));
724       else
725         child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
726
727       child_allocation.width = relative_allocation.width;
728       child_allocation.height = scrolled_window->hscrollbar->requisition.height;
729       child_allocation.x += allocation->x;
730       child_allocation.y += allocation->y;
731
732       gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
733     }
734   else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
735     gtk_widget_hide (scrolled_window->hscrollbar);
736
737   if (scrolled_window->vscrollbar_visible)
738     {
739       if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
740         gtk_widget_show (scrolled_window->vscrollbar);
741
742       if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
743           scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
744         child_allocation.x = (relative_allocation.x +
745                               relative_allocation.width +
746                               SCROLLBAR_SPACING (scrolled_window));
747       else
748         child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
749
750       child_allocation.y = relative_allocation.y;
751       child_allocation.width = scrolled_window->vscrollbar->requisition.width;
752       child_allocation.height = relative_allocation.height;
753       child_allocation.x += allocation->x;
754       child_allocation.y += allocation->y;
755
756       gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
757     }
758   else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
759     gtk_widget_hide (scrolled_window->vscrollbar);
760 }
761
762
763 static void
764 gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
765                                         gpointer       data)
766 {
767   GtkScrolledWindow *scrolled_win;
768
769   g_return_if_fail (adjustment != NULL);
770   g_return_if_fail (data != NULL);
771
772   scrolled_win = GTK_SCROLLED_WINDOW (data);
773
774   if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->hscrollbar)))
775     {
776       if (scrolled_win->hscrollbar_policy == GTK_POLICY_AUTOMATIC)
777         {
778           gboolean visible;
779           
780           visible = scrolled_win->hscrollbar_visible;
781           scrolled_win->hscrollbar_visible = (adjustment->upper - adjustment->lower >
782                                               adjustment->page_size);
783           if (scrolled_win->hscrollbar_visible != visible)
784             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
785         }
786     }
787   else if (adjustment == gtk_range_get_adjustment (GTK_RANGE (scrolled_win->vscrollbar)))
788     {
789       if (scrolled_win->vscrollbar_policy == GTK_POLICY_AUTOMATIC)
790         {
791           gboolean visible;
792
793           visible = scrolled_win->vscrollbar_visible;
794           scrolled_win->vscrollbar_visible = (adjustment->upper - adjustment->lower >
795                                               adjustment->page_size);
796           if (scrolled_win->vscrollbar_visible != visible)
797             gtk_widget_queue_resize (GTK_WIDGET (scrolled_win));
798         }
799     }
800 }
801
802 static void
803 gtk_scrolled_window_add (GtkContainer *container,
804                          GtkWidget    *child)
805 {
806   GtkScrolledWindow *scrolled_window;
807
808   scrolled_window = GTK_SCROLLED_WINDOW (container);
809   g_return_if_fail (scrolled_window->child == NULL);
810
811   gtk_widget_set_parent (child, GTK_WIDGET (container));
812   scrolled_window->child = child;
813
814   /* this is a temporary message */
815   if (!gtk_widget_scroll_adjustements (child,
816                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
817                                        gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
818     g_message ("gtk_scrolled_window_add(): cannot add non scrollable widget "
819                "use gtk_scrolled_window_add_with_viewport() instead");
820
821   if (GTK_WIDGET_VISIBLE (scrolled_window))
822     {
823       if (GTK_WIDGET_REALIZED (scrolled_window) &&
824           !GTK_WIDGET_REALIZED (child))
825         gtk_widget_realize (child);
826
827       if (GTK_WIDGET_MAPPED (scrolled_window) &&
828           !GTK_WIDGET_MAPPED (child))
829         gtk_widget_map (child);
830     }
831   
832   if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (scrolled_window))
833     gtk_widget_queue_resize (child);
834 }
835
836 static void
837 gtk_scrolled_window_remove (GtkContainer *container,
838                             GtkWidget    *child)
839 {
840   GtkScrolledWindow *scrolled_window;
841   gboolean widget_was_visible;
842   
843   g_return_if_fail (container != NULL);
844   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (container));
845   g_return_if_fail (child != NULL);
846
847   scrolled_window = GTK_SCROLLED_WINDOW (container);
848   g_return_if_fail (scrolled_window->child == child);
849   
850   widget_was_visible = GTK_WIDGET_VISIBLE (child);
851   
852   gtk_widget_scroll_adjustements (child, NULL, NULL);
853   gtk_widget_unparent (child);
854   scrolled_window->child = NULL;
855   
856   if (widget_was_visible)
857     gtk_widget_queue_resize (GTK_WIDGET (container));
858 }
859
860 void
861 gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
862                                        GtkWidget         *child)
863 {
864   GtkWidget *viewport;
865
866   g_return_if_fail (scrolled_window != NULL);
867   g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
868   g_return_if_fail (child != NULL);
869   g_return_if_fail (GTK_IS_WIDGET (child));
870   g_return_if_fail (scrolled_window->child == NULL);
871   g_return_if_fail (child->parent == NULL);
872
873   viewport =
874     gtk_viewport_new (gtk_scrolled_window_get_hadjustment (scrolled_window),
875                       gtk_scrolled_window_get_vadjustment (scrolled_window));
876   gtk_widget_show (viewport);
877   gtk_container_add (GTK_CONTAINER (viewport), child);
878   gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
879 }