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