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