]> Pileus Git - ~andy/gtk/blob - gtk/gtkviewport.c
Fixed missing return from get_desired_width/height in GtkViewport (causing testgtk...
[~andy/gtk] / gtk / gtkviewport.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include "gtkviewport.h"
29 #include "gtkextendedlayout.h"
30 #include "gtkintl.h"
31 #include "gtkmarshalers.h"
32 #include "gtkprivate.h"
33 #include "gtkalias.h"
34
35 enum {
36   PROP_0,
37   PROP_HADJUSTMENT,
38   PROP_VADJUSTMENT,
39   PROP_SHADOW_TYPE
40 };
41
42
43 static void gtk_viewport_finalize                 (GObject          *object);
44 static void gtk_viewport_destroy                  (GtkObject        *object);
45 static void gtk_viewport_set_property             (GObject         *object,
46                                                    guint            prop_id,
47                                                    const GValue    *value,
48                                                    GParamSpec      *pspec);
49 static void gtk_viewport_get_property             (GObject         *object,
50                                                    guint            prop_id,
51                                                    GValue          *value,
52                                                    GParamSpec      *pspec);
53 static void gtk_viewport_set_scroll_adjustments   (GtkViewport      *viewport,
54                                                    GtkAdjustment    *hadjustment,
55                                                    GtkAdjustment    *vadjustment);
56 static void gtk_viewport_realize                  (GtkWidget        *widget);
57 static void gtk_viewport_unrealize                (GtkWidget        *widget);
58 static void gtk_viewport_paint                    (GtkWidget        *widget,
59                                                    GdkRectangle     *area);
60 static gint gtk_viewport_expose                   (GtkWidget        *widget,
61                                                    GdkEventExpose   *event);
62 static void gtk_viewport_add                      (GtkContainer     *container,
63                                                    GtkWidget        *widget);
64 static void gtk_viewport_size_allocate            (GtkWidget        *widget,
65                                                    GtkAllocation    *allocation);
66 static void gtk_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
67                                                    gpointer          data);
68 static void gtk_viewport_style_set                (GtkWidget *widget,
69                                                    GtkStyle  *previous_style);
70
71 static void gtk_viewport_extended_layout_init     (GtkExtendedLayoutIface *iface);
72 static void gtk_viewport_get_desired_width        (GtkExtendedLayout       *layout,
73                                                    gint                    *minimum_size,
74                                                    gint                    *natural_size);
75 static void gtk_viewport_get_desired_height       (GtkExtendedLayout       *layout,
76                                                    gint                    *minimum_size,
77                                                    gint                    *natural_size);
78
79
80 G_DEFINE_TYPE_WITH_CODE (GtkViewport, gtk_viewport, GTK_TYPE_BIN,
81                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
82                                                 gtk_viewport_extended_layout_init))
83
84 static void
85 gtk_viewport_class_init (GtkViewportClass *class)
86 {
87   GtkObjectClass *object_class;
88   GObjectClass   *gobject_class;
89   GtkWidgetClass *widget_class;
90   GtkContainerClass *container_class;
91
92   object_class = (GtkObjectClass*) class;
93   gobject_class = G_OBJECT_CLASS (class);
94   widget_class = (GtkWidgetClass*) class;
95   container_class = (GtkContainerClass*) class;
96
97   gobject_class->finalize = gtk_viewport_finalize;
98   gobject_class->set_property = gtk_viewport_set_property;
99   gobject_class->get_property = gtk_viewport_get_property;
100   object_class->destroy = gtk_viewport_destroy;
101   
102   widget_class->realize = gtk_viewport_realize;
103   widget_class->unrealize = gtk_viewport_unrealize;
104   widget_class->expose_event = gtk_viewport_expose;
105   widget_class->size_allocate = gtk_viewport_size_allocate;
106   widget_class->style_set = gtk_viewport_style_set;
107   
108   container_class->add = gtk_viewport_add;
109
110   class->set_scroll_adjustments = gtk_viewport_set_scroll_adjustments;
111
112   g_object_class_install_property (gobject_class,
113                                    PROP_HADJUSTMENT,
114                                    g_param_spec_object ("hadjustment",
115                                                         P_("Horizontal adjustment"),
116                                                         P_("The GtkAdjustment that determines the values of the horizontal position for this viewport"),
117                                                         GTK_TYPE_ADJUSTMENT,
118                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
119
120   g_object_class_install_property (gobject_class,
121                                    PROP_VADJUSTMENT,
122                                    g_param_spec_object ("vadjustment",
123                                                         P_("Vertical adjustment"),
124                                                         P_("The GtkAdjustment that determines the values of the vertical position for this viewport"),
125                                                         GTK_TYPE_ADJUSTMENT,
126                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
127
128   g_object_class_install_property (gobject_class,
129                                    PROP_SHADOW_TYPE,
130                                    g_param_spec_enum ("shadow-type",
131                                                       P_("Shadow type"),
132                                                       P_("Determines how the shadowed box around the viewport is drawn"),
133                                                       GTK_TYPE_SHADOW_TYPE,
134                                                       GTK_SHADOW_IN,
135                                                       GTK_PARAM_READWRITE));
136
137   /**
138    * GtkViewport::set-scroll-adjustments
139    * @horizontal: the horizontal #GtkAdjustment
140    * @vertical: the vertical #GtkAdjustment
141    *
142    * Set the scroll adjustments for the viewport. Usually scrolled containers
143    * like #GtkScrolledWindow will emit this signal to connect two instances
144    * of #GtkScrollbar to the scroll directions of the #GtkViewport.
145    */
146   widget_class->set_scroll_adjustments_signal =
147     g_signal_new (I_("set-scroll-adjustments"),
148                   G_OBJECT_CLASS_TYPE (gobject_class),
149                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
150                   G_STRUCT_OFFSET (GtkViewportClass, set_scroll_adjustments),
151                   NULL, NULL,
152                   _gtk_marshal_VOID__OBJECT_OBJECT,
153                   G_TYPE_NONE, 2,
154                   GTK_TYPE_ADJUSTMENT,
155                   GTK_TYPE_ADJUSTMENT);
156 }
157
158 static void
159 gtk_viewport_set_property (GObject         *object,
160                            guint            prop_id,
161                            const GValue    *value,
162                            GParamSpec      *pspec)
163 {
164   GtkViewport *viewport;
165
166   viewport = GTK_VIEWPORT (object);
167
168   switch (prop_id)
169     {
170     case PROP_HADJUSTMENT:
171       gtk_viewport_set_hadjustment (viewport, g_value_get_object (value));
172       break;
173     case PROP_VADJUSTMENT:
174       gtk_viewport_set_vadjustment (viewport, g_value_get_object (value));
175       break;
176     case PROP_SHADOW_TYPE:
177       gtk_viewport_set_shadow_type (viewport, g_value_get_enum (value));
178       break;
179     default:
180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181       break;
182     }
183 }
184
185 static void
186 gtk_viewport_get_property (GObject         *object,
187                            guint            prop_id,
188                            GValue          *value,
189                            GParamSpec      *pspec)
190 {
191   GtkViewport *viewport;
192
193   viewport = GTK_VIEWPORT (object);
194
195   switch (prop_id)
196     {
197     case PROP_HADJUSTMENT:
198       g_value_set_object (value, viewport->hadjustment);
199       break;
200     case PROP_VADJUSTMENT:
201       g_value_set_object (value, viewport->vadjustment);
202       break;
203     case PROP_SHADOW_TYPE:
204       g_value_set_enum (value, viewport->shadow_type);
205       break;
206     default:
207       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
208       break;
209     }
210 }
211
212 static void
213 gtk_viewport_init (GtkViewport *viewport)
214 {
215   gtk_widget_set_has_window (GTK_WIDGET (viewport), TRUE);
216
217   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (viewport), FALSE);
218   gtk_container_set_resize_mode (GTK_CONTAINER (viewport), GTK_RESIZE_QUEUE);
219   
220   viewport->shadow_type = GTK_SHADOW_IN;
221   viewport->view_window = NULL;
222   viewport->bin_window = NULL;
223   viewport->hadjustment = NULL;
224   viewport->vadjustment = NULL;
225 }
226
227 /**
228  * gtk_viewport_new:
229  * @hadjustment: horizontal adjustment.
230  * @vadjustment: vertical adjustment.
231  * @returns: a new #GtkViewport.
232  *
233  * Creates a new #GtkViewport with the given adjustments.
234  *
235  **/
236 GtkWidget*
237 gtk_viewport_new (GtkAdjustment *hadjustment,
238                   GtkAdjustment *vadjustment)
239 {
240   GtkWidget *viewport;
241
242   viewport = g_object_new (GTK_TYPE_VIEWPORT,
243                              "hadjustment", hadjustment,
244                              "vadjustment", vadjustment,
245                              NULL);
246
247   return viewport;
248 }
249
250 #define ADJUSTMENT_POINTER(viewport, orientation)         \
251   (((orientation) == GTK_ORIENTATION_HORIZONTAL) ?        \
252      &(viewport)->hadjustment : &(viewport)->vadjustment)
253
254 static void
255 viewport_disconnect_adjustment (GtkViewport    *viewport,
256                                 GtkOrientation  orientation)
257 {
258   GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);
259
260   if (*adjustmentp)
261     {
262       g_signal_handlers_disconnect_by_func (*adjustmentp,
263                                             gtk_viewport_adjustment_value_changed,
264                                             viewport);
265       g_object_unref (*adjustmentp);
266       *adjustmentp = NULL;
267     }
268 }
269
270 static void
271 gtk_viewport_finalize (GObject *object)
272 {
273   GtkViewport *viewport = GTK_VIEWPORT (object);
274
275   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
276   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
277
278   G_OBJECT_CLASS (gtk_viewport_parent_class)->finalize (object);
279 }
280
281 static void
282 gtk_viewport_destroy (GtkObject *object)
283 {
284   GtkViewport *viewport = GTK_VIEWPORT (object);
285
286   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
287   viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
288
289   GTK_OBJECT_CLASS (gtk_viewport_parent_class)->destroy (object);
290 }
291
292 /**
293  * gtk_viewport_get_hadjustment:
294  * @viewport: a #GtkViewport.
295  * 
296  * Returns the horizontal adjustment of the viewport.
297  *
298  * Return value: the horizontal adjustment of @viewport.
299  **/
300 GtkAdjustment*
301 gtk_viewport_get_hadjustment (GtkViewport *viewport)
302 {
303   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
304
305   if (!viewport->hadjustment)
306     gtk_viewport_set_hadjustment (viewport, NULL);
307
308   return viewport->hadjustment;
309 }
310
311 /**
312  * gtk_viewport_get_vadjustment:
313  * @viewport: a #GtkViewport.
314  * 
315  * Returns the vertical adjustment of the viewport.
316  *
317  * Return value: the vertical adjustment of @viewport.
318  **/
319 GtkAdjustment*
320 gtk_viewport_get_vadjustment (GtkViewport *viewport)
321 {
322   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
323
324   if (!viewport->vadjustment)
325     gtk_viewport_set_vadjustment (viewport, NULL);
326
327   return viewport->vadjustment;
328 }
329
330 static void
331 viewport_get_view_allocation (GtkViewport   *viewport,
332                               GtkAllocation *view_allocation)
333 {
334   GtkWidget *widget = GTK_WIDGET (viewport);
335   GtkAllocation *allocation = &widget->allocation;
336   gint border_width = GTK_CONTAINER (viewport)->border_width;
337   
338   view_allocation->x = 0;
339   view_allocation->y = 0;
340
341   if (viewport->shadow_type != GTK_SHADOW_NONE)
342     {
343       view_allocation->x = widget->style->xthickness;
344       view_allocation->y = widget->style->ythickness;
345     }
346
347   view_allocation->width = MAX (1, allocation->width - view_allocation->x * 2 - border_width * 2);
348   view_allocation->height = MAX (1, allocation->height - view_allocation->y * 2 - border_width * 2);
349 }
350
351 static void
352 viewport_reclamp_adjustment (GtkAdjustment *adjustment,
353                              gboolean      *value_changed)
354 {
355   gdouble value = adjustment->value;
356   
357   value = CLAMP (value, 0, adjustment->upper - adjustment->page_size);
358   if (value != adjustment->value)
359     {
360       adjustment->value = value;
361       if (value_changed)
362         *value_changed = TRUE;
363     }
364   else if (value_changed)
365     *value_changed = FALSE;
366 }
367
368 static void
369 viewport_set_hadjustment_values (GtkViewport *viewport,
370                                  gboolean    *value_changed)
371 {
372   GtkBin *bin = GTK_BIN (viewport);
373   GtkAllocation view_allocation;
374   GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
375   gdouble old_page_size;
376   gdouble old_upper;
377   gdouble old_value;
378   
379   viewport_get_view_allocation (viewport, &view_allocation);  
380
381   old_page_size = hadjustment->page_size;
382   old_upper = hadjustment->upper;
383   old_value = hadjustment->value;
384   hadjustment->page_size = view_allocation.width;
385   hadjustment->step_increment = view_allocation.width * 0.1;
386   hadjustment->page_increment = view_allocation.width * 0.9;
387   
388   hadjustment->lower = 0;
389
390   if (bin->child && gtk_widget_get_visible (bin->child))
391     {
392       GtkRequisition child_requisition;
393       
394       gtk_widget_get_child_requisition (bin->child, &child_requisition);
395       hadjustment->upper = MAX (child_requisition.width, view_allocation.width);
396     }
397   else
398     hadjustment->upper = view_allocation.width;
399
400   if (gtk_widget_get_direction (GTK_WIDGET (viewport)) == GTK_TEXT_DIR_RTL) 
401     {
402       gdouble dist = old_upper - (old_value + old_page_size);
403       hadjustment->value = hadjustment->upper - dist - hadjustment->page_size;
404       viewport_reclamp_adjustment (hadjustment, value_changed);
405       *value_changed = (old_value != hadjustment->value);
406     }
407   else
408     viewport_reclamp_adjustment (hadjustment, value_changed);
409 }
410
411 static void
412 viewport_set_vadjustment_values (GtkViewport *viewport,
413                                  gboolean    *value_changed)
414 {
415   GtkBin *bin = GTK_BIN (viewport);
416   GtkAllocation view_allocation;
417   GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
418
419   viewport_get_view_allocation (viewport, &view_allocation);  
420
421   vadjustment->page_size = view_allocation.height;
422   vadjustment->step_increment = view_allocation.height * 0.1;
423   vadjustment->page_increment = view_allocation.height * 0.9;
424   
425   vadjustment->lower = 0;
426
427   if (bin->child && gtk_widget_get_visible (bin->child))
428     {
429       gint natural_height;
430       
431       gtk_extended_layout_get_height_for_width (GTK_EXTENDED_LAYOUT (bin->child),
432                                                 view_allocation.width,
433                                                 NULL,
434                                                 &natural_height);
435       vadjustment->upper = MAX (natural_height, view_allocation.height);
436     }
437   else
438     vadjustment->upper = view_allocation.height;
439
440   viewport_reclamp_adjustment (vadjustment, value_changed);
441 }
442
443 static void
444 viewport_set_adjustment (GtkViewport    *viewport,
445                          GtkOrientation  orientation,
446                          GtkAdjustment  *adjustment)
447 {
448   GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);
449   gboolean value_changed;
450
451   if (adjustment && adjustment == *adjustmentp)
452     return;
453
454   if (!adjustment)
455     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
456                                                      0.0, 0.0, 0.0));
457   viewport_disconnect_adjustment (viewport, orientation);
458   *adjustmentp = adjustment;
459   g_object_ref_sink (adjustment);
460
461   if (orientation == GTK_ORIENTATION_HORIZONTAL)
462     viewport_set_hadjustment_values (viewport, &value_changed);
463   else
464     viewport_set_vadjustment_values (viewport, &value_changed);
465
466   g_signal_connect (adjustment, "value-changed",
467                     G_CALLBACK (gtk_viewport_adjustment_value_changed),
468                     viewport);
469
470   gtk_adjustment_changed (adjustment);
471   
472   if (value_changed)
473     gtk_adjustment_value_changed (adjustment);
474   else
475     gtk_viewport_adjustment_value_changed (adjustment, viewport);
476 }
477
478 /**
479  * gtk_viewport_set_hadjustment:
480  * @viewport: a #GtkViewport.
481  * @adjustment: (allow-none): a #GtkAdjustment.
482  *
483  * Sets the horizontal adjustment of the viewport.
484  **/
485 void
486 gtk_viewport_set_hadjustment (GtkViewport   *viewport,
487                               GtkAdjustment *adjustment)
488 {
489   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
490   if (adjustment)
491     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
492
493   viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, adjustment);
494
495   g_object_notify (G_OBJECT (viewport), "hadjustment");
496 }
497
498 /**
499  * gtk_viewport_set_vadjustment:
500  * @viewport: a #GtkViewport.
501  * @adjustment: (allow-none): a #GtkAdjustment.
502  *
503  * Sets the vertical adjustment of the viewport.
504  **/
505 void
506 gtk_viewport_set_vadjustment (GtkViewport   *viewport,
507                               GtkAdjustment *adjustment)
508 {
509   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
510   if (adjustment)
511     g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
512
513   viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, adjustment);
514
515   g_object_notify (G_OBJECT (viewport), "vadjustment");
516 }
517
518 static void
519 gtk_viewport_set_scroll_adjustments (GtkViewport      *viewport,
520                                      GtkAdjustment    *hadjustment,
521                                      GtkAdjustment    *vadjustment)
522 {
523   gtk_viewport_set_hadjustment (viewport, hadjustment);
524   gtk_viewport_set_vadjustment (viewport, vadjustment);
525 }
526
527 /** 
528  * gtk_viewport_set_shadow_type:
529  * @viewport: a #GtkViewport.
530  * @type: the new shadow type.
531  *
532  * Sets the shadow type of the viewport.
533  **/ 
534 void
535 gtk_viewport_set_shadow_type (GtkViewport   *viewport,
536                               GtkShadowType  type)
537 {
538   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
539
540   if ((GtkShadowType) viewport->shadow_type != type)
541     {
542       viewport->shadow_type = type;
543
544       if (gtk_widget_get_visible (GTK_WIDGET (viewport)))
545         {
546           gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation));
547           gtk_widget_queue_draw (GTK_WIDGET (viewport));
548         }
549
550       g_object_notify (G_OBJECT (viewport), "shadow-type");
551     }
552 }
553
554 /**
555  * gtk_viewport_get_shadow_type:
556  * @viewport: a #GtkViewport
557  *
558  * Gets the shadow type of the #GtkViewport. See
559  * gtk_viewport_set_shadow_type().
560  
561  * Return value: the shadow type 
562  **/
563 GtkShadowType
564 gtk_viewport_get_shadow_type (GtkViewport *viewport)
565 {
566   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), GTK_SHADOW_NONE);
567
568   return viewport->shadow_type;
569 }
570
571 /**
572  * gtk_viewport_get_bin_window:
573  * @viewport: a #GtkViewport
574  *
575  * Gets the bin window of the #GtkViewport.
576  *
577  * Return value: a #GdkWindow
578  *
579  * Since: 2.20
580  **/
581 GdkWindow*
582 gtk_viewport_get_bin_window (GtkViewport *viewport)
583 {
584   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
585
586   return viewport->bin_window;
587 }
588
589 static void
590 gtk_viewport_realize (GtkWidget *widget)
591 {
592   GtkViewport *viewport = GTK_VIEWPORT (widget);
593   GtkBin *bin = GTK_BIN (widget);
594   GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
595   GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
596   gint border_width = GTK_CONTAINER (widget)->border_width;
597   
598   GtkAllocation view_allocation;
599   GdkWindowAttr attributes;
600   gint attributes_mask;
601   gint event_mask;
602
603   gtk_widget_set_realized (widget, TRUE);
604
605   attributes.x = widget->allocation.x + border_width;
606   attributes.y = widget->allocation.y + border_width;
607   attributes.width = widget->allocation.width - border_width * 2;
608   attributes.height = widget->allocation.height - border_width * 2;
609   attributes.window_type = GDK_WINDOW_CHILD;
610   attributes.wclass = GDK_INPUT_OUTPUT;
611   attributes.visual = gtk_widget_get_visual (widget);
612   attributes.colormap = gtk_widget_get_colormap (widget);
613
614   event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
615   /* We select on button_press_mask so that button 4-5 scrolls are trapped.
616    */
617   attributes.event_mask = event_mask | GDK_BUTTON_PRESS_MASK;
618
619   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
620
621   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
622                                    &attributes, attributes_mask);
623   gdk_window_set_user_data (widget->window, viewport);
624
625   viewport_get_view_allocation (viewport, &view_allocation);
626   
627   attributes.x = view_allocation.x;
628   attributes.y = view_allocation.y;
629   attributes.width = view_allocation.width;
630   attributes.height = view_allocation.height;
631   attributes.event_mask = 0;
632
633   viewport->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
634   gdk_window_set_user_data (viewport->view_window, viewport);
635
636   gdk_window_set_back_pixmap (viewport->view_window, NULL, FALSE);
637   
638   attributes.x = - hadjustment->value;
639   attributes.y = - vadjustment->value;
640   attributes.width = hadjustment->upper;
641   attributes.height = vadjustment->upper;
642   
643   attributes.event_mask = event_mask;
644
645   viewport->bin_window = gdk_window_new (viewport->view_window, &attributes, attributes_mask);
646   gdk_window_set_user_data (viewport->bin_window, viewport);
647
648   if (bin->child)
649     gtk_widget_set_parent_window (bin->child, viewport->bin_window);
650
651   widget->style = gtk_style_attach (widget->style, widget->window);
652   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
653   gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
654
655   /* Call paint here to allow a theme to set the background without flashing
656    */
657   gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
658                      GTK_SHADOW_NONE,
659                      NULL, widget, "viewportbin",
660                      0, 0, -1, -1);
661    
662   gdk_window_show (viewport->bin_window);
663   gdk_window_show (viewport->view_window);
664 }
665
666 static void
667 gtk_viewport_unrealize (GtkWidget *widget)
668 {
669   GtkViewport *viewport = GTK_VIEWPORT (widget);
670
671   gdk_window_set_user_data (viewport->view_window, NULL);
672   gdk_window_destroy (viewport->view_window);
673   viewport->view_window = NULL;
674
675   gdk_window_set_user_data (viewport->bin_window, NULL);
676   gdk_window_destroy (viewport->bin_window);
677   viewport->bin_window = NULL;
678
679   GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unrealize (widget);
680 }
681
682 static void
683 gtk_viewport_paint (GtkWidget    *widget,
684                     GdkRectangle *area)
685 {
686   if (gtk_widget_is_drawable (widget))
687     {
688       GtkViewport *viewport = GTK_VIEWPORT (widget);
689
690       gtk_paint_shadow (widget->style, widget->window,
691                         GTK_STATE_NORMAL, viewport->shadow_type,
692                         area, widget, "viewport",
693                         0, 0, -1, -1);
694     }
695 }
696
697 static gint
698 gtk_viewport_expose (GtkWidget      *widget,
699                      GdkEventExpose *event)
700 {
701   GtkViewport *viewport;
702
703   if (gtk_widget_is_drawable (widget))
704     {
705       viewport = GTK_VIEWPORT (widget);
706
707       if (event->window == widget->window)
708         gtk_viewport_paint (widget, &event->area);
709       else if (event->window == viewport->bin_window)
710         {
711           gtk_paint_flat_box(widget->style, viewport->bin_window, 
712                              GTK_STATE_NORMAL, GTK_SHADOW_NONE,
713                              &event->area, widget, "viewportbin",
714                              0, 0, -1, -1);
715
716           GTK_WIDGET_CLASS (gtk_viewport_parent_class)->expose_event (widget, event);
717         }
718     }
719
720   return FALSE;
721 }
722
723 static void
724 gtk_viewport_add (GtkContainer *container,
725                   GtkWidget    *child)
726 {
727   GtkBin *bin = GTK_BIN (container);
728
729   g_return_if_fail (bin->child == NULL);
730
731   gtk_widget_set_parent_window (child, GTK_VIEWPORT (bin)->bin_window);
732
733   GTK_CONTAINER_CLASS (gtk_viewport_parent_class)->add (container, child);
734 }
735
736 static void
737 gtk_viewport_size_allocate (GtkWidget     *widget,
738                             GtkAllocation *allocation)
739 {
740   GtkViewport *viewport = GTK_VIEWPORT (widget);
741   GtkBin *bin = GTK_BIN (widget);
742   gint border_width = GTK_CONTAINER (widget)->border_width;
743   gboolean hadjustment_value_changed, vadjustment_value_changed;
744   GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
745   GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
746   GtkAllocation child_allocation;
747
748   /* If our size changed, and we have a shadow, queue a redraw on widget->window to
749    * redraw the shadow correctly.
750    */
751   if (gtk_widget_get_mapped (widget) &&
752       viewport->shadow_type != GTK_SHADOW_NONE &&
753       (widget->allocation.width != allocation->width ||
754        widget->allocation.height != allocation->height))
755     gdk_window_invalidate_rect (widget->window, NULL, FALSE);
756   
757   widget->allocation = *allocation;
758   
759   viewport_set_hadjustment_values (viewport, &hadjustment_value_changed);
760   viewport_set_vadjustment_values (viewport, &vadjustment_value_changed);
761   
762   child_allocation.x = 0;
763   child_allocation.y = 0;
764   child_allocation.width = hadjustment->upper;
765   child_allocation.height = vadjustment->upper;
766   if (gtk_widget_get_realized (widget))
767     {
768       GtkAllocation view_allocation;
769       gdk_window_move_resize (widget->window,
770                               allocation->x + border_width,
771                               allocation->y + border_width,
772                               allocation->width - border_width * 2,
773                               allocation->height - border_width * 2);
774       
775       viewport_get_view_allocation (viewport, &view_allocation);
776       gdk_window_move_resize (viewport->view_window,
777                               view_allocation.x,
778                               view_allocation.y,
779                               view_allocation.width,
780                               view_allocation.height);
781       gdk_window_move_resize (viewport->bin_window,
782                               - hadjustment->value,
783                               - vadjustment->value,
784                               child_allocation.width,
785                               child_allocation.height);
786     }
787   if (bin->child && gtk_widget_get_visible (bin->child))
788     gtk_widget_size_allocate (bin->child, &child_allocation);
789
790   gtk_adjustment_changed (hadjustment);
791   gtk_adjustment_changed (vadjustment);
792   if (hadjustment_value_changed)
793     gtk_adjustment_value_changed (hadjustment);
794   if (vadjustment_value_changed)
795     gtk_adjustment_value_changed (vadjustment);
796 }
797
798 static void
799 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
800                                        gpointer       data)
801 {
802   GtkViewport *viewport = GTK_VIEWPORT (data);
803   GtkBin *bin = GTK_BIN (data);
804
805   if (bin->child && gtk_widget_get_visible (bin->child) &&
806       gtk_widget_get_realized (GTK_WIDGET (viewport)))
807     {
808       GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
809       GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
810       gint old_x, old_y;
811       gint new_x, new_y;
812
813       gdk_window_get_position (viewport->bin_window, &old_x, &old_y);
814       new_x = - hadjustment->value;
815       new_y = - vadjustment->value;
816
817       if (new_x != old_x || new_y != old_y)
818         {
819           gdk_window_move (viewport->bin_window, new_x, new_y);
820           gdk_window_process_updates (viewport->bin_window, TRUE);
821         }
822     }
823 }
824
825 static void
826 gtk_viewport_style_set (GtkWidget *widget,
827                         GtkStyle  *previous_style)
828 {
829    if (gtk_widget_get_realized (widget) &&
830        gtk_widget_get_has_window (widget))
831      {
832         GtkViewport *viewport = GTK_VIEWPORT (widget);
833
834         gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
835         gtk_style_set_background (widget->style, widget->window, widget->state);
836      }
837 }
838
839
840 static void
841 gtk_viewport_extended_layout_init (GtkExtendedLayoutIface *iface)
842 {
843   iface->get_desired_width  = gtk_viewport_get_desired_width;
844   iface->get_desired_height = gtk_viewport_get_desired_height;
845 }
846
847 static void
848 gtk_viewport_get_desired_size (GtkExtendedLayout *layout,
849                                GtkOrientation     orientation,
850                                gint              *minimum_size,
851                                gint              *natural_size)
852 {
853   GtkWidget *child;
854   gint       child_min, child_nat;
855   gint       minimum, natural;
856
857   child = gtk_bin_get_child (GTK_BIN (layout));
858
859   /* XXX This should probably be (border_width * 2); but GTK+ has
860    * been doing this with a single border for a while now...
861    */
862   minimum = GTK_CONTAINER (layout)->border_width;
863
864   if (GTK_VIEWPORT (layout)->shadow_type != GTK_SHADOW_NONE)
865     {
866       if (orientation == GTK_ORIENTATION_HORIZONTAL)
867           minimum += 2 * GTK_WIDGET (layout)->style->xthickness;
868       else
869           minimum += 2 * GTK_WIDGET (layout)->style->ythickness;
870     }
871
872   natural = minimum;
873
874   if (child && gtk_widget_get_visible (child))
875     {
876       if (orientation == GTK_ORIENTATION_HORIZONTAL)
877         gtk_extended_layout_get_desired_width (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
878       else
879         gtk_extended_layout_get_desired_height (GTK_EXTENDED_LAYOUT (child), &child_min, &child_nat);
880
881       minimum += child_min;
882       natural += child_nat;
883     }
884
885   if (minimum_size)
886     *minimum_size = minimum;
887
888   if (natural_size)
889     *natural_size = natural;
890 }
891
892 static void
893 gtk_viewport_get_desired_width (GtkExtendedLayout *layout,
894                                 gint              *minimum_size,
895                                 gint              *natural_size)
896 {
897   gtk_viewport_get_desired_size (layout, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
898 }
899
900 static void
901 gtk_viewport_get_desired_height (GtkExtendedLayout *layout,
902                                  gint              *minimum_size,
903                                  gint              *natural_size)
904 {
905   gtk_viewport_get_desired_size (layout, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
906 }
907
908 #define __GTK_VIEWPORT_C__
909 #include "gtkaliasdef.c"