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