]> Pileus Git - ~andy/gtk/blob - gtk/gtkviewport.c
Close comment.
[~andy/gtk] / gtk / gtkviewport.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "gtksignal.h"
28 #include "gtkviewport.h"
29 #include "gtkintl.h"
30 #include "gtkmarshalers.h"
31
32 enum {
33   PROP_0,
34   PROP_HADJUSTMENT,
35   PROP_VADJUSTMENT,
36   PROP_SHADOW_TYPE
37 };
38
39
40 static void gtk_viewport_class_init               (GtkViewportClass *klass);
41 static void gtk_viewport_init                     (GtkViewport      *viewport);
42 static void gtk_viewport_destroy                  (GtkObject        *object);
43 static void gtk_viewport_set_property             (GObject         *object,
44                                                    guint            prop_id,
45                                                    const GValue    *value,
46                                                    GParamSpec      *pspec);
47 static void gtk_viewport_get_property             (GObject         *object,
48                                                    guint            prop_id,
49                                                    GValue          *value,
50                                                    GParamSpec      *pspec);
51 static void gtk_viewport_set_scroll_adjustments   (GtkViewport      *viewport,
52                                                    GtkAdjustment    *hadjustment,
53                                                    GtkAdjustment    *vadjustment);
54 static void gtk_viewport_realize                  (GtkWidget        *widget);
55 static void gtk_viewport_unrealize                (GtkWidget        *widget);
56 static void gtk_viewport_paint                    (GtkWidget        *widget,
57                                                    GdkRectangle     *area);
58 static gint gtk_viewport_expose                   (GtkWidget        *widget,
59                                                    GdkEventExpose   *event);
60 static void gtk_viewport_add                      (GtkContainer     *container,
61                                                    GtkWidget        *widget);
62 static void gtk_viewport_size_request             (GtkWidget        *widget,
63                                                    GtkRequisition   *requisition);
64 static void gtk_viewport_size_allocate            (GtkWidget        *widget,
65                                                    GtkAllocation    *allocation);
66 static void gtk_viewport_adjustment_changed       (GtkAdjustment    *adjustment,
67                                                    gpointer          data);
68 static void gtk_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
69                                                    gpointer          data);
70 static void gtk_viewport_style_set                (GtkWidget *widget,
71                                                    GtkStyle  *previous_style);
72
73 static GtkBinClass *parent_class;
74
75 GtkType
76 gtk_viewport_get_type (void)
77 {
78   static GtkType viewport_type = 0;
79
80   if (!viewport_type)
81     {
82       static const GtkTypeInfo viewport_info =
83       {
84         "GtkViewport",
85         sizeof (GtkViewport),
86         sizeof (GtkViewportClass),
87         (GtkClassInitFunc) gtk_viewport_class_init,
88         (GtkObjectInitFunc) gtk_viewport_init,
89         /* reserved_1 */ NULL,
90         /* reserved_2 */ NULL,
91         (GtkClassInitFunc) NULL,
92       };
93
94       viewport_type = gtk_type_unique (GTK_TYPE_BIN, &viewport_info);
95     }
96
97   return viewport_type;
98 }
99
100 static void
101 gtk_viewport_class_init (GtkViewportClass *class)
102 {
103   GtkObjectClass *object_class;
104   GObjectClass   *gobject_class;
105   GtkWidgetClass *widget_class;
106   GtkContainerClass *container_class;
107
108   object_class = (GtkObjectClass*) class;
109   gobject_class = G_OBJECT_CLASS (class);
110   widget_class = (GtkWidgetClass*) class;
111   container_class = (GtkContainerClass*) class;
112   parent_class = (GtkBinClass*) gtk_type_class (GTK_TYPE_BIN);
113
114   gobject_class->set_property = gtk_viewport_set_property;
115   gobject_class->get_property = gtk_viewport_get_property;
116   object_class->destroy = gtk_viewport_destroy;
117   
118   widget_class->realize = gtk_viewport_realize;
119   widget_class->unrealize = gtk_viewport_unrealize;
120   widget_class->expose_event = gtk_viewport_expose;
121   widget_class->size_request = gtk_viewport_size_request;
122   widget_class->size_allocate = gtk_viewport_size_allocate;
123   widget_class->style_set = gtk_viewport_style_set;
124   
125   container_class->add = gtk_viewport_add;
126
127   class->set_scroll_adjustments = gtk_viewport_set_scroll_adjustments;
128
129   g_object_class_install_property (gobject_class,
130                                    PROP_HADJUSTMENT,
131                                    g_param_spec_object ("hadjustment",
132                                                         _("Horizontal adjustment"),
133                                                         _("The GtkAdjustment that determines the values of the horizontal position for this viewport."),
134                                                         GTK_TYPE_ADJUSTMENT,
135                                                         G_PARAM_READWRITE));
136
137   g_object_class_install_property (gobject_class,
138                                    PROP_VADJUSTMENT,
139                                    g_param_spec_object ("vadjustment",
140                                                         _("Vertical adjustment"),
141                                                         _("The GtkAdjustment that determines the values of the vertical position for this viewport."),
142                                                         GTK_TYPE_ADJUSTMENT,
143                                                         G_PARAM_READWRITE));
144
145   g_object_class_install_property (gobject_class,
146                                    PROP_SHADOW_TYPE,
147                                    g_param_spec_enum ("shadow_type",
148                                                       _("Shadow type"),
149                                                       _("Determines how the shadowed box around the viewport is drawn."),
150                                                       GTK_TYPE_SHADOW_TYPE,
151                                                       GTK_SHADOW_IN,
152                                                       G_PARAM_READWRITE));
153
154   widget_class->set_scroll_adjustments_signal =
155     gtk_signal_new ("set_scroll_adjustments",
156                     GTK_RUN_LAST,
157                     GTK_CLASS_TYPE (object_class),
158                     GTK_SIGNAL_OFFSET (GtkViewportClass, set_scroll_adjustments),
159                     _gtk_marshal_VOID__OBJECT_OBJECT,
160                     GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
161 }
162
163 static void
164 gtk_viewport_set_property (GObject         *object,
165                            guint            prop_id,
166                            const GValue    *value,
167                            GParamSpec      *pspec)
168 {
169   GtkViewport *viewport;
170
171   viewport = GTK_VIEWPORT (object);
172
173   switch (prop_id)
174     {
175     case PROP_HADJUSTMENT:
176       gtk_viewport_set_hadjustment (viewport, g_value_get_object (value));
177       break;
178     case PROP_VADJUSTMENT:
179       gtk_viewport_set_vadjustment (viewport, g_value_get_object (value));
180       break;
181     case PROP_SHADOW_TYPE:
182       gtk_viewport_set_shadow_type (viewport, g_value_get_enum (value));
183       break;
184     default:
185       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186       break;
187     }
188 }
189
190 static void
191 gtk_viewport_get_property (GObject         *object,
192                            guint            prop_id,
193                            GValue          *value,
194                            GParamSpec      *pspec)
195 {
196   GtkViewport *viewport;
197
198   viewport = GTK_VIEWPORT (object);
199
200   switch (prop_id)
201     {
202     case PROP_HADJUSTMENT:
203       g_value_set_object (value, G_OBJECT (viewport->hadjustment));
204       break;
205     case PROP_VADJUSTMENT:
206       g_value_set_object (value, G_OBJECT (viewport->vadjustment));
207       break;
208     case PROP_SHADOW_TYPE:
209       g_value_set_enum (value, viewport->shadow_type);
210       break;
211     default:
212       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
213       break;
214     }
215 }
216
217 static void
218 gtk_viewport_init (GtkViewport *viewport)
219 {
220   GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW);
221
222   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (viewport), FALSE);
223   gtk_container_set_resize_mode (GTK_CONTAINER (viewport), GTK_RESIZE_QUEUE);
224   
225   viewport->shadow_type = GTK_SHADOW_IN;
226   viewport->view_window = NULL;
227   viewport->bin_window = NULL;
228   viewport->hadjustment = NULL;
229   viewport->vadjustment = NULL;
230 }
231
232 /**
233  * gtk_viewport_new:
234  * @hadjustment: horizontal adjustment.
235  * @vadjustment: vertical adjustment.
236  * @returns: a new #GtkViewport.
237  *
238  * Creates a new #GtkViewport with the given adjustments.
239  *
240  **/
241 GtkWidget*
242 gtk_viewport_new (GtkAdjustment *hadjustment,
243                   GtkAdjustment *vadjustment)
244 {
245   GtkWidget *viewport;
246
247   viewport = gtk_widget_new (GTK_TYPE_VIEWPORT,
248                              "hadjustment", hadjustment,
249                              "vadjustment", vadjustment,
250                              NULL);
251
252   return viewport;
253 }
254
255 static void
256 gtk_viewport_destroy (GtkObject *object)
257 {
258   GtkViewport *viewport = GTK_VIEWPORT (object);
259
260   if (viewport->hadjustment)
261     {
262       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
263       gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
264       viewport->hadjustment = NULL;
265     }
266   if (viewport->vadjustment)
267     {
268       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
269       gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
270       viewport->vadjustment = NULL;
271     }
272
273   GTK_OBJECT_CLASS (parent_class)->destroy (object);
274 }
275
276 /**
277  * gtk_viewport_get_hadjustment:
278  * @viewport: a #GtkViewport.
279  * 
280  * Returns the horizontal adjustment of the viewport.
281  *
282  * Return value: the horizontal adjustment of @viewport.
283  **/
284 GtkAdjustment*
285 gtk_viewport_get_hadjustment (GtkViewport *viewport)
286 {
287   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
288
289   if (!viewport->hadjustment)
290     gtk_viewport_set_hadjustment (viewport, NULL);
291
292   return viewport->hadjustment;
293 }
294
295 /**
296  * gtk_viewport_get_vadjustment:
297  * @viewport: a #GtkViewport.
298  * 
299  * Returns the vertical adjustment of the viewport.
300  *
301  * Return value: the vertical adjustment of @viewport.
302  **/
303 GtkAdjustment*
304 gtk_viewport_get_vadjustment (GtkViewport *viewport)
305 {
306   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
307
308   if (!viewport->vadjustment)
309     gtk_viewport_set_vadjustment (viewport, NULL);
310
311   return viewport->vadjustment;
312 }
313
314 /**
315  * gtk_viewport_set_hadjustment:
316  * @viewport: a #GtkViewport.
317  * @adjustment: a #GtkAdjustment.
318  * 
319  * Sets the horizontal adjustment of the viewport.
320  **/
321 void
322 gtk_viewport_set_hadjustment (GtkViewport   *viewport,
323                               GtkAdjustment *adjustment)
324 {
325   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
326   if (adjustment)
327     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
328
329   if (viewport->hadjustment && viewport->hadjustment != adjustment)
330     {
331       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
332       gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
333       viewport->hadjustment = NULL;
334     }
335
336   if (!adjustment)
337     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
338                                                      0.0, 0.0, 0.0));
339
340   if (viewport->hadjustment != adjustment)
341     {
342       viewport->hadjustment = adjustment;
343       gtk_object_ref (GTK_OBJECT (viewport->hadjustment));
344       gtk_object_sink (GTK_OBJECT (viewport->hadjustment));
345       
346       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
347                           (GtkSignalFunc) gtk_viewport_adjustment_changed,
348                           (gpointer) viewport);
349       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
350                           (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
351                           (gpointer) viewport);
352
353       gtk_viewport_adjustment_changed (adjustment, viewport);
354     }
355
356   g_object_notify (G_OBJECT (viewport), "hadjustment");
357 }
358
359 /**
360  * gtk_viewport_set_vadjustment:
361  * @viewport: a #GtkViewport.
362  * @adjustment: a #GtkAdjustment.
363  * 
364  * Sets the vertical adjustment of the viewport.
365  **/
366 void
367 gtk_viewport_set_vadjustment (GtkViewport   *viewport,
368                               GtkAdjustment *adjustment)
369 {
370   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
371   if (adjustment)
372     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
373
374   if (viewport->vadjustment && viewport->vadjustment != adjustment)
375     {
376       gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
377       gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
378       viewport->vadjustment = NULL;
379     }
380
381   if (!adjustment)
382     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
383                                                      0.0, 0.0, 0.0));
384
385   if (viewport->vadjustment != adjustment)
386     {
387       viewport->vadjustment = adjustment;
388       gtk_object_ref (GTK_OBJECT (viewport->vadjustment));
389       gtk_object_sink (GTK_OBJECT (viewport->vadjustment));
390       
391       gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
392                           (GtkSignalFunc) gtk_viewport_adjustment_changed,
393                           (gpointer) viewport);
394       gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
395                           (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
396                           (gpointer) viewport);
397
398       gtk_viewport_adjustment_changed (adjustment, viewport);
399     }
400
401   g_object_notify (G_OBJECT (viewport), "vadjustment");
402 }
403
404 static void
405 gtk_viewport_set_scroll_adjustments (GtkViewport      *viewport,
406                                      GtkAdjustment    *hadjustment,
407                                      GtkAdjustment    *vadjustment)
408 {
409   if (viewport->hadjustment != hadjustment)
410     gtk_viewport_set_hadjustment (viewport, hadjustment);
411   if (viewport->vadjustment != vadjustment)
412     gtk_viewport_set_vadjustment (viewport, vadjustment);
413 }
414
415 /** 
416  * gtk_viewport_set_shadow_type:
417  * @viewport: a #GtkViewport.
418  * @type: the new shadow type.
419  *
420  * Sets the shadow type of the viewport.
421  **/ 
422 void
423 gtk_viewport_set_shadow_type (GtkViewport   *viewport,
424                               GtkShadowType  type)
425 {
426   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
427
428   if ((GtkShadowType) viewport->shadow_type != type)
429     {
430       viewport->shadow_type = type;
431
432       if (GTK_WIDGET_VISIBLE (viewport))
433         {
434           gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation));
435           gtk_widget_queue_draw (GTK_WIDGET (viewport));
436         }
437     }
438
439   g_object_notify (G_OBJECT (viewport), "shadow_type");
440 }
441
442 /**
443  * gtk_viewport_get_shadow_type:
444  * @viewport: a #GtkViewport
445  *
446  * Gets the shadow type of the #GtkViewport. See
447  * gtk_viewport_set_shadow_type().
448  
449  * Return value: the shadow type 
450  **/
451 GtkShadowType
452 gtk_viewport_get_shadow_type (GtkViewport *viewport)
453 {
454   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), GTK_SHADOW_NONE);
455
456   return viewport->shadow_type;
457 }
458
459 static void
460 gtk_viewport_realize (GtkWidget *widget)
461 {
462   GtkBin *bin;
463   GtkViewport *viewport;
464   GdkWindowAttr attributes;
465   gint attributes_mask;
466   gint event_mask;
467   gint border_width;
468
469   g_return_if_fail (GTK_IS_VIEWPORT (widget));
470
471   border_width = GTK_CONTAINER (widget)->border_width;
472
473   bin = GTK_BIN (widget);
474   viewport = GTK_VIEWPORT (widget);
475   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
476
477   attributes.x = widget->allocation.x + border_width;
478   attributes.y = widget->allocation.y + border_width;
479   attributes.width = widget->allocation.width - border_width * 2;
480   attributes.height = widget->allocation.height - border_width * 2;
481   attributes.window_type = GDK_WINDOW_CHILD;
482   attributes.wclass = GDK_INPUT_OUTPUT;
483   attributes.visual = gtk_widget_get_visual (widget);
484   attributes.colormap = gtk_widget_get_colormap (widget);
485
486   event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
487   /* We select on button_press_mask so that button 4-5 scrolls are trapped.
488    */
489   attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
490
491   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
492
493   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
494                                    &attributes, attributes_mask);
495   gdk_window_set_user_data (widget->window, viewport);
496
497   if (viewport->shadow_type != GTK_SHADOW_NONE)
498     {
499       attributes.x = widget->style->xthickness;
500       attributes.y = widget->style->ythickness;
501     }
502   else
503     {
504       attributes.x = 0;
505       attributes.y = 0;
506     }
507
508   attributes.width = MAX (1, (gint)widget->allocation.width - attributes.x * 2 - border_width * 2);
509   attributes.height = MAX (1, (gint)widget->allocation.height - attributes.y * 2 - border_width * 2);
510   attributes.event_mask = 0;
511
512   viewport->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
513   gdk_window_set_user_data (viewport->view_window, viewport);
514
515   attributes.x = 0;
516   attributes.y = 0;
517
518   if (bin->child)
519     {
520       attributes.width = viewport->hadjustment->upper;
521       attributes.height = viewport->vadjustment->upper;
522     }
523   
524   attributes.event_mask = event_mask;
525
526   viewport->bin_window = gdk_window_new (viewport->view_window, &attributes, attributes_mask);
527   gdk_window_set_user_data (viewport->bin_window, viewport);
528
529   if (bin->child)
530     gtk_widget_set_parent_window (bin->child, viewport->bin_window);
531
532   widget->style = gtk_style_attach (widget->style, widget->window);
533   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
534   gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
535
536    gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
537                       GTK_SHADOW_NONE,
538                       NULL, widget, "viewportbin",
539                       0, 0, -1, -1);
540    
541   gdk_window_show (viewport->bin_window);
542   gdk_window_show (viewport->view_window);
543 }
544
545 static void
546 gtk_viewport_unrealize (GtkWidget *widget)
547 {
548   GtkViewport *viewport;
549
550   g_return_if_fail (GTK_IS_VIEWPORT (widget));
551
552   viewport = GTK_VIEWPORT (widget);
553
554   gdk_window_set_user_data (viewport->view_window, NULL);
555   gdk_window_destroy (viewport->view_window);
556   viewport->view_window = NULL;
557
558   gdk_window_set_user_data (viewport->bin_window, NULL);
559   gdk_window_destroy (viewport->bin_window);
560   viewport->bin_window = NULL;
561
562   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
563     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
564 }
565
566 static void
567 gtk_viewport_paint (GtkWidget    *widget,
568                     GdkRectangle *area)
569 {
570   GtkViewport *viewport;
571
572   g_return_if_fail (GTK_IS_VIEWPORT (widget));
573   g_return_if_fail (area != NULL);
574
575   if (GTK_WIDGET_DRAWABLE (widget))
576     {
577       viewport = GTK_VIEWPORT (widget);
578
579       gtk_draw_shadow (widget->style, widget->window,
580                        GTK_STATE_NORMAL, viewport->shadow_type,
581                        0, 0, -1, -1);
582     }
583 }
584
585 static gint
586 gtk_viewport_expose (GtkWidget      *widget,
587                      GdkEventExpose *event)
588 {
589   GtkViewport *viewport;
590   GtkBin *bin;
591   GdkEventExpose child_event;
592
593   g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE);
594   g_return_val_if_fail (event != NULL, FALSE);
595
596   if (GTK_WIDGET_DRAWABLE (widget))
597     {
598       viewport = GTK_VIEWPORT (widget);
599       bin = GTK_BIN (widget);
600
601       if (event->window == widget->window)
602         gtk_viewport_paint (widget, &event->area);
603       else if (event->window == viewport->bin_window)
604         {
605           child_event = *event;
606
607           gtk_paint_flat_box(widget->style, viewport->bin_window, 
608                              GTK_STATE_NORMAL, GTK_SHADOW_NONE,
609                              &event->area, widget, "viewportbin",
610                              0, 0, -1, -1);
611           
612           (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
613         }
614         
615
616     }
617
618   return FALSE;
619 }
620
621 static void
622 gtk_viewport_add (GtkContainer *container,
623                   GtkWidget    *child)
624 {
625   GtkBin *bin;
626
627   g_return_if_fail (GTK_IS_VIEWPORT (container));
628   g_return_if_fail (child != NULL);
629
630   bin = GTK_BIN (container);
631   g_return_if_fail (bin->child == NULL);
632
633   gtk_widget_set_parent_window (child, GTK_VIEWPORT (bin)->bin_window);
634
635   GTK_CONTAINER_CLASS (parent_class)->add (container, child);
636 }
637
638 static void
639 gtk_viewport_size_request (GtkWidget      *widget,
640                            GtkRequisition *requisition)
641 {
642   GtkViewport *viewport;
643   GtkBin *bin;
644   GtkRequisition child_requisition;
645
646   g_return_if_fail (GTK_IS_VIEWPORT (widget));
647   g_return_if_fail (requisition != NULL);
648
649   viewport = GTK_VIEWPORT (widget);
650   bin = GTK_BIN (widget);
651
652   requisition->width = (GTK_CONTAINER (widget)->border_width +
653                         GTK_WIDGET (widget)->style->xthickness) * 2;
654
655   requisition->height = (GTK_CONTAINER (widget)->border_width * 2 +
656                          GTK_WIDGET (widget)->style->ythickness) * 2;
657
658   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
659     {
660       gtk_widget_size_request (bin->child, &child_requisition);
661       requisition->width += child_requisition.width;
662       requisition->height += child_requisition.height;
663     }
664 }
665
666 static void
667 gtk_viewport_size_allocate (GtkWidget     *widget,
668                             GtkAllocation *allocation)
669 {
670   GtkViewport *viewport = GTK_VIEWPORT (widget);
671   GtkBin *bin = GTK_BIN (widget);
672   GtkAllocation child_allocation;
673   gint hval, vval;
674   gint border_width = GTK_CONTAINER (widget)->border_width;
675
676   /* demand creation */
677   if (!viewport->hadjustment)
678     gtk_viewport_set_hadjustment (viewport, NULL);
679   if (!viewport->vadjustment)
680     gtk_viewport_set_hadjustment (viewport, NULL);
681
682   /* If our size changed, and we have a shadow, queue a redraw on widget->window to
683    * redraw the shadow correctly.
684    */
685   if (GTK_WIDGET_MAPPED (widget) &&
686       viewport->shadow_type != GTK_SHADOW_NONE &&
687       (widget->allocation.width != allocation->width ||
688        widget->allocation.height != allocation->height))
689     gdk_window_invalidate_rect (widget->window, NULL, FALSE);
690   
691   widget->allocation = *allocation;
692
693   child_allocation.x = 0;
694   child_allocation.y = 0;
695
696   if (viewport->shadow_type != GTK_SHADOW_NONE)
697     {
698       child_allocation.x = widget->style->xthickness;
699       child_allocation.y = widget->style->ythickness;
700     }
701
702   child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2 - border_width * 2);
703   child_allocation.height = MAX (1, allocation->height - child_allocation.y * 2 - border_width * 2);
704
705   if (GTK_WIDGET_REALIZED (widget))
706     {
707       gdk_window_move_resize (widget->window,
708                               allocation->x + border_width,
709                               allocation->y + border_width,
710                               allocation->width - border_width * 2,
711                               allocation->height - border_width * 2);
712
713       gdk_window_move_resize (viewport->view_window,
714                               child_allocation.x,
715                               child_allocation.y,
716                               child_allocation.width,
717                               child_allocation.height);
718     }
719
720   viewport->hadjustment->page_size = child_allocation.width;
721   viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2;
722   viewport->hadjustment->step_increment = 10;
723
724   viewport->vadjustment->page_size = child_allocation.height;
725   viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2;
726   viewport->vadjustment->step_increment = 10;
727
728   hval = viewport->hadjustment->value;
729   vval = viewport->vadjustment->value;
730
731   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
732     {
733       GtkRequisition child_requisition;
734       gtk_widget_get_child_requisition (bin->child, &child_requisition);
735       
736       viewport->hadjustment->lower = 0;
737       viewport->hadjustment->upper = MAX (child_requisition.width,
738                                           child_allocation.width);
739
740       hval = CLAMP (hval, 0,
741                     viewport->hadjustment->upper -
742                     viewport->hadjustment->page_size);
743
744       viewport->vadjustment->lower = 0;
745       viewport->vadjustment->upper = MAX (child_requisition.height,
746                                           child_allocation.height);
747
748       vval = CLAMP (vval, 0,
749                     viewport->vadjustment->upper -
750                     viewport->vadjustment->page_size);
751     }
752
753   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
754     {
755       child_allocation.x = 0;
756       child_allocation.y = 0;
757
758       child_allocation.width = viewport->hadjustment->upper;
759       child_allocation.height = viewport->vadjustment->upper;
760
761       if (GTK_WIDGET_REALIZED (widget))
762         gdk_window_resize (viewport->bin_window,
763                            child_allocation.width,
764                            child_allocation.height);
765
766       child_allocation.x = 0;
767       child_allocation.y = 0;
768       gtk_widget_size_allocate (bin->child, &child_allocation);
769     }
770
771   gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed");
772   gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed");
773   if (viewport->hadjustment->value != hval)
774     {
775       viewport->hadjustment->value = hval;
776       gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed");
777     }
778   if (viewport->vadjustment->value != vval)
779     {
780       viewport->vadjustment->value = vval;
781       gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed");
782     }
783 }
784
785 static void
786 gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
787                                  gpointer       data)
788 {
789   GtkViewport *viewport;
790
791   g_return_if_fail (adjustment != NULL);
792   g_return_if_fail (GTK_IS_VIEWPORT (data));
793
794   viewport = GTK_VIEWPORT (data);
795 }
796
797 static void
798 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
799                                        gpointer       data)
800 {
801   GtkViewport *viewport;
802   GtkBin *bin;
803   GtkAllocation child_allocation;
804
805   g_return_if_fail (adjustment != NULL);
806   g_return_if_fail (GTK_IS_VIEWPORT (data));
807
808   viewport = GTK_VIEWPORT (data);
809   bin = GTK_BIN (data);
810
811   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
812     {
813       child_allocation.x = 0;
814       child_allocation.y = 0;
815
816       if (viewport->hadjustment->lower != (viewport->hadjustment->upper -
817                                            viewport->hadjustment->page_size))
818         child_allocation.x =  viewport->hadjustment->lower - viewport->hadjustment->value;
819
820       if (viewport->vadjustment->lower != (viewport->vadjustment->upper -
821                                            viewport->vadjustment->page_size))
822         child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value;
823
824       if (GTK_WIDGET_REALIZED (viewport))
825         {
826           gdk_window_move (viewport->bin_window,
827                            child_allocation.x,
828                            child_allocation.y);
829       
830           gdk_window_process_updates (viewport->bin_window, TRUE);
831         }
832     }
833 }
834
835 static void
836 gtk_viewport_style_set (GtkWidget *widget,
837                         GtkStyle  *previous_style)
838 {
839    GtkViewport *viewport;
840    
841    if (GTK_WIDGET_REALIZED (widget) &&
842        !GTK_WIDGET_NO_WINDOW (widget))
843      {
844         viewport = GTK_VIEWPORT (widget);
845         
846         gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
847         gtk_style_set_background (widget->style, widget->window, widget->state);
848      }
849 }