]> Pileus Git - ~andy/gtk/blob - gtk/gtkviewport.c
Add a 'type' parameter, make public.
[~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, viewport->hadjustment);
204       break;
205     case PROP_VADJUSTMENT:
206       g_value_set_object (value, 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       g_object_notify (G_OBJECT (viewport), "shadow_type");
439     }
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   border_width = GTK_CONTAINER (widget)->border_width;
470
471   bin = GTK_BIN (widget);
472   viewport = GTK_VIEWPORT (widget);
473   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
474
475   attributes.x = widget->allocation.x + border_width;
476   attributes.y = widget->allocation.y + border_width;
477   attributes.width = widget->allocation.width - border_width * 2;
478   attributes.height = widget->allocation.height - border_width * 2;
479   attributes.window_type = GDK_WINDOW_CHILD;
480   attributes.wclass = GDK_INPUT_OUTPUT;
481   attributes.visual = gtk_widget_get_visual (widget);
482   attributes.colormap = gtk_widget_get_colormap (widget);
483
484   event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
485   /* We select on button_press_mask so that button 4-5 scrolls are trapped.
486    */
487   attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
488
489   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
490
491   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
492                                    &attributes, attributes_mask);
493   gdk_window_set_user_data (widget->window, viewport);
494
495   if (viewport->shadow_type != GTK_SHADOW_NONE)
496     {
497       attributes.x = widget->style->xthickness;
498       attributes.y = widget->style->ythickness;
499     }
500   else
501     {
502       attributes.x = 0;
503       attributes.y = 0;
504     }
505
506   attributes.width = MAX (1, (gint)widget->allocation.width - attributes.x * 2 - border_width * 2);
507   attributes.height = MAX (1, (gint)widget->allocation.height - attributes.y * 2 - border_width * 2);
508   attributes.event_mask = 0;
509
510   viewport->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
511   gdk_window_set_user_data (viewport->view_window, viewport);
512
513   attributes.x = 0;
514   attributes.y = 0;
515
516   if (bin->child)
517     {
518       attributes.width = viewport->hadjustment->upper;
519       attributes.height = viewport->vadjustment->upper;
520     }
521   
522   attributes.event_mask = event_mask;
523
524   viewport->bin_window = gdk_window_new (viewport->view_window, &attributes, attributes_mask);
525   gdk_window_set_user_data (viewport->bin_window, viewport);
526
527   if (bin->child)
528     gtk_widget_set_parent_window (bin->child, viewport->bin_window);
529
530   widget->style = gtk_style_attach (widget->style, widget->window);
531   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
532   gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
533
534    gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
535                       GTK_SHADOW_NONE,
536                       NULL, widget, "viewportbin",
537                       0, 0, -1, -1);
538    
539   gdk_window_show (viewport->bin_window);
540   gdk_window_show (viewport->view_window);
541 }
542
543 static void
544 gtk_viewport_unrealize (GtkWidget *widget)
545 {
546   GtkViewport *viewport = GTK_VIEWPORT (widget);
547
548   gdk_window_set_user_data (viewport->view_window, NULL);
549   gdk_window_destroy (viewport->view_window);
550   viewport->view_window = NULL;
551
552   gdk_window_set_user_data (viewport->bin_window, NULL);
553   gdk_window_destroy (viewport->bin_window);
554   viewport->bin_window = NULL;
555
556   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
557     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
558 }
559
560 static void
561 gtk_viewport_paint (GtkWidget    *widget,
562                     GdkRectangle *area)
563 {
564   GtkViewport *viewport;
565
566   g_return_if_fail (GTK_IS_VIEWPORT (widget));
567   g_return_if_fail (area != NULL);
568
569   if (GTK_WIDGET_DRAWABLE (widget))
570     {
571       viewport = GTK_VIEWPORT (widget);
572
573       gtk_draw_shadow (widget->style, widget->window,
574                        GTK_STATE_NORMAL, viewport->shadow_type,
575                        0, 0, -1, -1);
576     }
577 }
578
579 static gint
580 gtk_viewport_expose (GtkWidget      *widget,
581                      GdkEventExpose *event)
582 {
583   GtkViewport *viewport;
584   GtkBin *bin;
585
586   if (GTK_WIDGET_DRAWABLE (widget))
587     {
588       viewport = GTK_VIEWPORT (widget);
589       bin = GTK_BIN (widget);
590
591       if (event->window == widget->window)
592         gtk_viewport_paint (widget, &event->area);
593       else if (event->window == viewport->bin_window)
594         {
595           gtk_paint_flat_box(widget->style, viewport->bin_window, 
596                              GTK_STATE_NORMAL, GTK_SHADOW_NONE,
597                              &event->area, widget, "viewportbin",
598                              0, 0, -1, -1);
599           
600           (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
601         }
602         
603
604     }
605
606   return FALSE;
607 }
608
609 static void
610 gtk_viewport_add (GtkContainer *container,
611                   GtkWidget    *child)
612 {
613   GtkBin *bin;
614
615   g_return_if_fail (GTK_IS_WIDGET (child));
616
617   bin = GTK_BIN (container);
618   g_return_if_fail (bin->child == NULL);
619
620   gtk_widget_set_parent_window (child, GTK_VIEWPORT (bin)->bin_window);
621
622   GTK_CONTAINER_CLASS (parent_class)->add (container, child);
623 }
624
625 static void
626 gtk_viewport_size_request (GtkWidget      *widget,
627                            GtkRequisition *requisition)
628 {
629   GtkViewport *viewport;
630   GtkBin *bin;
631   GtkRequisition child_requisition;
632
633   viewport = GTK_VIEWPORT (widget);
634   bin = GTK_BIN (widget);
635
636   requisition->width = (GTK_CONTAINER (widget)->border_width +
637                         GTK_WIDGET (widget)->style->xthickness) * 2;
638
639   requisition->height = (GTK_CONTAINER (widget)->border_width * 2 +
640                          GTK_WIDGET (widget)->style->ythickness) * 2;
641
642   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
643     {
644       gtk_widget_size_request (bin->child, &child_requisition);
645       requisition->width += child_requisition.width;
646       requisition->height += child_requisition.height;
647     }
648 }
649
650 static void
651 gtk_viewport_size_allocate (GtkWidget     *widget,
652                             GtkAllocation *allocation)
653 {
654   GtkViewport *viewport = GTK_VIEWPORT (widget);
655   GtkBin *bin = GTK_BIN (widget);
656   GtkAllocation child_allocation;
657   gint hval, vval;
658   gint border_width = GTK_CONTAINER (widget)->border_width;
659
660   /* demand creation */
661   if (!viewport->hadjustment)
662     gtk_viewport_set_hadjustment (viewport, NULL);
663   if (!viewport->vadjustment)
664     gtk_viewport_set_vadjustment (viewport, NULL);
665
666   /* If our size changed, and we have a shadow, queue a redraw on widget->window to
667    * redraw the shadow correctly.
668    */
669   if (GTK_WIDGET_MAPPED (widget) &&
670       viewport->shadow_type != GTK_SHADOW_NONE &&
671       (widget->allocation.width != allocation->width ||
672        widget->allocation.height != allocation->height))
673     gdk_window_invalidate_rect (widget->window, NULL, FALSE);
674   
675   widget->allocation = *allocation;
676
677   child_allocation.x = 0;
678   child_allocation.y = 0;
679
680   if (viewport->shadow_type != GTK_SHADOW_NONE)
681     {
682       child_allocation.x = widget->style->xthickness;
683       child_allocation.y = widget->style->ythickness;
684     }
685
686   child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2 - border_width * 2);
687   child_allocation.height = MAX (1, allocation->height - child_allocation.y * 2 - border_width * 2);
688
689   if (GTK_WIDGET_REALIZED (widget))
690     {
691       gdk_window_move_resize (widget->window,
692                               allocation->x + border_width,
693                               allocation->y + border_width,
694                               allocation->width - border_width * 2,
695                               allocation->height - border_width * 2);
696
697       gdk_window_move_resize (viewport->view_window,
698                               child_allocation.x,
699                               child_allocation.y,
700                               child_allocation.width,
701                               child_allocation.height);
702     }
703
704   viewport->hadjustment->page_size = child_allocation.width;
705   viewport->hadjustment->step_increment = child_allocation.width * 0.1;
706   viewport->hadjustment->page_increment = child_allocation.width * 0.9;
707
708   viewport->vadjustment->page_size = child_allocation.height;
709   viewport->vadjustment->step_increment = child_allocation.height * 0.1;
710   viewport->vadjustment->page_increment = child_allocation.height * 0.9;
711
712   hval = viewport->hadjustment->value;
713   vval = viewport->vadjustment->value;
714
715   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
716     {
717       GtkRequisition child_requisition;
718       gtk_widget_get_child_requisition (bin->child, &child_requisition);
719       
720       viewport->hadjustment->lower = 0;
721       viewport->hadjustment->upper = MAX (child_requisition.width,
722                                           child_allocation.width);
723
724       hval = CLAMP (hval, 0,
725                     viewport->hadjustment->upper -
726                     viewport->hadjustment->page_size);
727
728       viewport->vadjustment->lower = 0;
729       viewport->vadjustment->upper = MAX (child_requisition.height,
730                                           child_allocation.height);
731
732       vval = CLAMP (vval, 0,
733                     viewport->vadjustment->upper -
734                     viewport->vadjustment->page_size);
735     }
736
737   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
738     {
739       child_allocation.x = 0;
740       child_allocation.y = 0;
741
742       child_allocation.width = viewport->hadjustment->upper;
743       child_allocation.height = viewport->vadjustment->upper;
744
745       if (GTK_WIDGET_REALIZED (widget))
746         gdk_window_resize (viewport->bin_window,
747                            child_allocation.width,
748                            child_allocation.height);
749
750       child_allocation.x = 0;
751       child_allocation.y = 0;
752       gtk_widget_size_allocate (bin->child, &child_allocation);
753     }
754
755   gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed");
756   gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed");
757   if (viewport->hadjustment->value != hval)
758     {
759       viewport->hadjustment->value = hval;
760       gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed");
761     }
762   if (viewport->vadjustment->value != vval)
763     {
764       viewport->vadjustment->value = vval;
765       gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed");
766     }
767 }
768
769 static void
770 gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
771                                  gpointer       data)
772 {
773   GtkViewport *viewport;
774
775   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
776   g_return_if_fail (GTK_IS_VIEWPORT (data));
777
778   viewport = GTK_VIEWPORT (data);
779 }
780
781 static void
782 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
783                                        gpointer       data)
784 {
785   GtkViewport *viewport;
786   GtkBin *bin;
787   GtkAllocation child_allocation;
788
789   g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
790   g_return_if_fail (GTK_IS_VIEWPORT (data));
791
792   viewport = GTK_VIEWPORT (data);
793   bin = GTK_BIN (data);
794
795   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
796     {
797       child_allocation.x = 0;
798       child_allocation.y = 0;
799
800       if (viewport->hadjustment->lower != (viewport->hadjustment->upper -
801                                            viewport->hadjustment->page_size))
802         child_allocation.x =  viewport->hadjustment->lower - viewport->hadjustment->value;
803
804       if (viewport->vadjustment->lower != (viewport->vadjustment->upper -
805                                            viewport->vadjustment->page_size))
806         child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value;
807
808       if (GTK_WIDGET_REALIZED (viewport))
809         {
810           gdk_window_move (viewport->bin_window,
811                            child_allocation.x,
812                            child_allocation.y);
813       
814           gdk_window_process_updates (viewport->bin_window, TRUE);
815         }
816     }
817 }
818
819 static void
820 gtk_viewport_style_set (GtkWidget *widget,
821                         GtkStyle  *previous_style)
822 {
823    GtkViewport *viewport;
824    
825    if (GTK_WIDGET_REALIZED (widget) &&
826        !GTK_WIDGET_NO_WINDOW (widget))
827      {
828         viewport = GTK_VIEWPORT (widget);
829         
830         gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
831         gtk_style_set_background (widget->style, widget->window, widget->state);
832      }
833 }