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