]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkviewport.c
Deprecate widget flag: GTK_WIDGET_MAPPED
[~andy/gtk] / gtk / gtkviewport.c
index 34dd90c807ff8ac4ac1e107b1f1fd7ad77469e4e..d9e35fb0d2b3ab58c149e971dd5360b994d377a0 100644 (file)
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
-#include "gtksignal.h"
+#include "config.h"
 #include "gtkviewport.h"
 #include "gtkintl.h"
+#include "gtkmarshalers.h"
+#include "gtkprivate.h"
+#include "gtkalias.h"
 
 enum {
   PROP_0,
@@ -36,8 +39,7 @@ enum {
 };
 
 
-static void gtk_viewport_class_init               (GtkViewportClass *klass);
-static void gtk_viewport_init                     (GtkViewport      *viewport);
+static void gtk_viewport_finalize                 (GObject          *object);
 static void gtk_viewport_destroy                  (GtkObject        *object);
 static void gtk_viewport_set_property             (GObject         *object,
                                                   guint            prop_id,
@@ -50,8 +52,6 @@ static void gtk_viewport_get_property             (GObject         *object,
 static void gtk_viewport_set_scroll_adjustments          (GtkViewport      *viewport,
                                                   GtkAdjustment    *hadjustment,
                                                   GtkAdjustment    *vadjustment);
-static void gtk_viewport_map                      (GtkWidget        *widget);
-static void gtk_viewport_unmap                    (GtkWidget        *widget);
 static void gtk_viewport_realize                  (GtkWidget        *widget);
 static void gtk_viewport_unrealize                (GtkWidget        *widget);
 static void gtk_viewport_paint                    (GtkWidget        *widget,
@@ -64,39 +64,12 @@ static void gtk_viewport_size_request             (GtkWidget        *widget,
                                                   GtkRequisition   *requisition);
 static void gtk_viewport_size_allocate            (GtkWidget        *widget,
                                                   GtkAllocation    *allocation);
-static void gtk_viewport_adjustment_changed       (GtkAdjustment    *adjustment,
-                                                  gpointer          data);
 static void gtk_viewport_adjustment_value_changed (GtkAdjustment    *adjustment,
                                                   gpointer          data);
 static void gtk_viewport_style_set                (GtkWidget *widget,
                                                   GtkStyle  *previous_style);
 
-static GtkBinClass *parent_class;
-
-GtkType
-gtk_viewport_get_type (void)
-{
-  static GtkType viewport_type = 0;
-
-  if (!viewport_type)
-    {
-      static const GtkTypeInfo viewport_info =
-      {
-       "GtkViewport",
-       sizeof (GtkViewport),
-       sizeof (GtkViewportClass),
-       (GtkClassInitFunc) gtk_viewport_class_init,
-       (GtkObjectInitFunc) gtk_viewport_init,
-       /* reserved_1 */ NULL,
-        /* reserved_2 */ NULL,
-        (GtkClassInitFunc) NULL,
-      };
-
-      viewport_type = gtk_type_unique (GTK_TYPE_BIN, &viewport_info);
-    }
-
-  return viewport_type;
-}
+G_DEFINE_TYPE (GtkViewport, gtk_viewport, GTK_TYPE_BIN)
 
 static void
 gtk_viewport_class_init (GtkViewportClass *class)
@@ -110,14 +83,12 @@ gtk_viewport_class_init (GtkViewportClass *class)
   gobject_class = G_OBJECT_CLASS (class);
   widget_class = (GtkWidgetClass*) class;
   container_class = (GtkContainerClass*) class;
-  parent_class = (GtkBinClass*) gtk_type_class (GTK_TYPE_BIN);
 
+  gobject_class->finalize = gtk_viewport_finalize;
   gobject_class->set_property = gtk_viewport_set_property;
   gobject_class->get_property = gtk_viewport_get_property;
   object_class->destroy = gtk_viewport_destroy;
   
-  widget_class->map = gtk_viewport_map;
-  widget_class->unmap = gtk_viewport_unmap;
   widget_class->realize = gtk_viewport_realize;
   widget_class->unrealize = gtk_viewport_unrealize;
   widget_class->expose_event = gtk_viewport_expose;
@@ -132,35 +103,47 @@ gtk_viewport_class_init (GtkViewportClass *class)
   g_object_class_install_property (gobject_class,
                                    PROP_HADJUSTMENT,
                                    g_param_spec_object ("hadjustment",
-                                                       _("Horizontal adjustment"),
-                                                       _("The GtkAdjustment that determines the values of the horizontal position for this viewport."),
+                                                       P_("Horizontal adjustment"),
+                                                       P_("The GtkAdjustment that determines the values of the horizontal position for this viewport"),
                                                         GTK_TYPE_ADJUSTMENT,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (gobject_class,
                                    PROP_VADJUSTMENT,
                                    g_param_spec_object ("vadjustment",
-                                                       _("Vertical adjustment"),
-                                                       _("The GtkAdjustment that determines the values of the vertical position for this viewport."),
+                                                       P_("Vertical adjustment"),
+                                                       P_("The GtkAdjustment that determines the values of the vertical position for this viewport"),
                                                         GTK_TYPE_ADJUSTMENT,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
   g_object_class_install_property (gobject_class,
                                    PROP_SHADOW_TYPE,
-                                   g_param_spec_enum ("shadow_type",
-                                                     _("Shadow type"),
-                                                     _("Determines how the shadowed box around the viewport is drawn."),
+                                   g_param_spec_enum ("shadow-type",
+                                                     P_("Shadow type"),
+                                                     P_("Determines how the shadowed box around the viewport is drawn"),
                                                      GTK_TYPE_SHADOW_TYPE,
                                                      GTK_SHADOW_IN,
-                                                     G_PARAM_READWRITE));
-
+                                                     GTK_PARAM_READWRITE));
+
+  /**
+   * GtkViewport::set-scroll-adjustments
+   * @horizontal: the horizontal #GtkAdjustment
+   * @vertical: the vertical #GtkAdjustment
+   *
+   * Set the scroll adjustments for the viewport. Usually scrolled containers
+   * like #GtkScrolledWindow will emit this signal to connect two instances
+   * of #GtkScrollbar to the scroll directions of the #GtkViewport.
+   */
   widget_class->set_scroll_adjustments_signal =
-    gtk_signal_new ("set_scroll_adjustments",
-                   GTK_RUN_LAST,
-                   GTK_CLASS_TYPE (object_class),
-                   GTK_SIGNAL_OFFSET (GtkViewportClass, set_scroll_adjustments),
-                   gtk_marshal_VOID__OBJECT_OBJECT,
-                   GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
+    g_signal_new (I_("set-scroll-adjustments"),
+                 G_OBJECT_CLASS_TYPE (gobject_class),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                 G_STRUCT_OFFSET (GtkViewportClass, set_scroll_adjustments),
+                 NULL, NULL,
+                 _gtk_marshal_VOID__OBJECT_OBJECT,
+                 G_TYPE_NONE, 2,
+                 GTK_TYPE_ADJUSTMENT,
+                 GTK_TYPE_ADJUSTMENT);
 }
 
 static void
@@ -203,10 +186,10 @@ gtk_viewport_get_property (GObject         *object,
   switch (prop_id)
     {
     case PROP_HADJUSTMENT:
-      g_value_set_object (value, G_OBJECT (viewport->hadjustment));
+      g_value_set_object (value, viewport->hadjustment);
       break;
     case PROP_VADJUSTMENT:
-      g_value_set_object (value, G_OBJECT (viewport->vadjustment));
+      g_value_set_object (value, viewport->vadjustment);
       break;
     case PROP_SHADOW_TYPE:
       g_value_set_enum (value, viewport->shadow_type);
@@ -222,6 +205,7 @@ gtk_viewport_init (GtkViewport *viewport)
 {
   GTK_WIDGET_UNSET_FLAGS (viewport, GTK_NO_WINDOW);
 
+  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (viewport), FALSE);
   gtk_container_set_resize_mode (GTK_CONTAINER (viewport), GTK_RESIZE_QUEUE);
   
   viewport->shadow_type = GTK_SHADOW_IN;
@@ -231,13 +215,22 @@ gtk_viewport_init (GtkViewport *viewport)
   viewport->vadjustment = NULL;
 }
 
+/**
+ * gtk_viewport_new:
+ * @hadjustment: horizontal adjustment.
+ * @vadjustment: vertical adjustment.
+ * @returns: a new #GtkViewport.
+ *
+ * Creates a new #GtkViewport with the given adjustments.
+ *
+ **/
 GtkWidget*
 gtk_viewport_new (GtkAdjustment *hadjustment,
                  GtkAdjustment *vadjustment)
 {
   GtkWidget *viewport;
 
-  viewport = gtk_widget_new (GTK_TYPE_VIEWPORT,
+  viewport = g_object_new (GTK_TYPE_VIEWPORT,
                             "hadjustment", hadjustment,
                             "vadjustment", vadjustment,
                             NULL);
@@ -245,31 +238,59 @@ gtk_viewport_new (GtkAdjustment *hadjustment,
   return viewport;
 }
 
+#define ADJUSTMENT_POINTER(viewport, orientation)         \
+  (((orientation) == GTK_ORIENTATION_HORIZONTAL) ?        \
+     &(viewport)->hadjustment : &(viewport)->vadjustment)
+
 static void
-gtk_viewport_destroy (GtkObject *object)
+viewport_disconnect_adjustment (GtkViewport    *viewport,
+                               GtkOrientation  orientation)
 {
-  GtkViewport *viewport = GTK_VIEWPORT (object);
+  GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);
 
-  if (viewport->hadjustment)
+  if (*adjustmentp)
     {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
-      gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
-      viewport->hadjustment = NULL;
-    }
-  if (viewport->vadjustment)
-    {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
-      gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
-      viewport->vadjustment = NULL;
+      g_signal_handlers_disconnect_by_func (*adjustmentp,
+                                           gtk_viewport_adjustment_value_changed,
+                                           viewport);
+      g_object_unref (*adjustmentp);
+      *adjustmentp = NULL;
     }
+}
+
+static void
+gtk_viewport_finalize (GObject *object)
+{
+  GtkViewport *viewport = GTK_VIEWPORT (object);
 
-  GTK_OBJECT_CLASS (parent_class)->destroy (object);
+  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
+  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
+
+  G_OBJECT_CLASS (gtk_viewport_parent_class)->finalize (object);
 }
 
+static void
+gtk_viewport_destroy (GtkObject *object)
+{
+  GtkViewport *viewport = GTK_VIEWPORT (object);
+
+  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL);
+  viewport_disconnect_adjustment (viewport, GTK_ORIENTATION_VERTICAL);
+
+  GTK_OBJECT_CLASS (gtk_viewport_parent_class)->destroy (object);
+}
+
+/**
+ * gtk_viewport_get_hadjustment:
+ * @viewport: a #GtkViewport.
+ * 
+ * Returns the horizontal adjustment of the viewport.
+ *
+ * Return value: the horizontal adjustment of @viewport.
+ **/
 GtkAdjustment*
 gtk_viewport_get_hadjustment (GtkViewport *viewport)
 {
-  g_return_val_if_fail (viewport != NULL, NULL);
   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
 
   if (!viewport->hadjustment)
@@ -278,10 +299,17 @@ gtk_viewport_get_hadjustment (GtkViewport *viewport)
   return viewport->hadjustment;
 }
 
+/**
+ * gtk_viewport_get_vadjustment:
+ * @viewport: a #GtkViewport.
+ * 
+ * Returns the vertical adjustment of the viewport.
+ *
+ * Return value: the vertical adjustment of @viewport.
+ **/
 GtkAdjustment*
 gtk_viewport_get_vadjustment (GtkViewport *viewport)
 {
-  g_return_val_if_fail (viewport != NULL, NULL);
   g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
 
   if (!viewport->vadjustment)
@@ -290,80 +318,187 @@ gtk_viewport_get_vadjustment (GtkViewport *viewport)
   return viewport->vadjustment;
 }
 
-void
-gtk_viewport_set_hadjustment (GtkViewport   *viewport,
-                             GtkAdjustment *adjustment)
+static void
+viewport_get_view_allocation (GtkViewport   *viewport,
+                             GtkAllocation *view_allocation)
 {
-  g_return_if_fail (viewport != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
-  if (adjustment)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  GtkWidget *widget = GTK_WIDGET (viewport);
+  GtkAllocation *allocation = &widget->allocation;
+  gint border_width = GTK_CONTAINER (viewport)->border_width;
+  
+  view_allocation->x = 0;
+  view_allocation->y = 0;
 
-  if (viewport->hadjustment && viewport->hadjustment != adjustment)
+  if (viewport->shadow_type != GTK_SHADOW_NONE)
     {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->hadjustment), viewport);
-      gtk_object_unref (GTK_OBJECT (viewport->hadjustment));
-      viewport->hadjustment = NULL;
+      view_allocation->x = widget->style->xthickness;
+      view_allocation->y = widget->style->ythickness;
     }
 
-  if (!adjustment)
-    adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
-                                                    0.0, 0.0, 0.0));
+  view_allocation->width = MAX (1, allocation->width - view_allocation->x * 2 - border_width * 2);
+  view_allocation->height = MAX (1, allocation->height - view_allocation->y * 2 - border_width * 2);
+}
 
-  if (viewport->hadjustment != adjustment)
+static void
+viewport_reclamp_adjustment (GtkAdjustment *adjustment,
+                            gboolean      *value_changed)
+{
+  gdouble value = adjustment->value;
+  
+  value = CLAMP (value, 0, adjustment->upper - adjustment->page_size);
+  if (value != adjustment->value)
     {
-      viewport->hadjustment = adjustment;
-      gtk_object_ref (GTK_OBJECT (viewport->hadjustment));
-      gtk_object_sink (GTK_OBJECT (viewport->hadjustment));
+      adjustment->value = value;
+      if (value_changed)
+       *value_changed = TRUE;
+    }
+  else if (value_changed)
+    *value_changed = FALSE;
+}
+
+static void
+viewport_set_hadjustment_values (GtkViewport *viewport,
+                                gboolean    *value_changed)
+{
+  GtkBin *bin = GTK_BIN (viewport);
+  GtkAllocation view_allocation;
+  GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
+  gdouble old_page_size;
+  gdouble old_upper;
+  gdouble old_value;
+  
+  viewport_get_view_allocation (viewport, &view_allocation);  
+
+  old_page_size = hadjustment->page_size;
+  old_upper = hadjustment->upper;
+  old_value = hadjustment->value;
+  hadjustment->page_size = view_allocation.width;
+  hadjustment->step_increment = view_allocation.width * 0.1;
+  hadjustment->page_increment = view_allocation.width * 0.9;
+  
+  hadjustment->lower = 0;
+
+  if (bin->child && gtk_widget_get_visible (bin->child))
+    {
+      GtkRequisition child_requisition;
       
-      gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                         (GtkSignalFunc) gtk_viewport_adjustment_changed,
-                         (gpointer) viewport);
-      gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                         (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
-                         (gpointer) viewport);
-
-      gtk_viewport_adjustment_changed (adjustment, viewport);
+      gtk_widget_get_child_requisition (bin->child, &child_requisition);
+      hadjustment->upper = MAX (child_requisition.width, view_allocation.width);
     }
+  else
+    hadjustment->upper = view_allocation.width;
 
-  g_object_notify (G_OBJECT (viewport), "hadjustment");
+  if (gtk_widget_get_direction (GTK_WIDGET (viewport)) == GTK_TEXT_DIR_RTL) 
+    {
+      gdouble dist = old_upper - (old_value + old_page_size);
+      hadjustment->value = hadjustment->upper - dist - hadjustment->page_size;
+      viewport_reclamp_adjustment (hadjustment, value_changed);
+      *value_changed = (old_value != hadjustment->value);
+    }
+  else
+    viewport_reclamp_adjustment (hadjustment, value_changed);
 }
 
-void
-gtk_viewport_set_vadjustment (GtkViewport   *viewport,
-                             GtkAdjustment *adjustment)
+static void
+viewport_set_vadjustment_values (GtkViewport *viewport,
+                                gboolean    *value_changed)
 {
-  g_return_if_fail (viewport != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
-  if (adjustment)
-    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+  GtkBin *bin = GTK_BIN (viewport);
+  GtkAllocation view_allocation;
+  GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
+
+  viewport_get_view_allocation (viewport, &view_allocation);  
+
+  vadjustment->page_size = view_allocation.height;
+  vadjustment->step_increment = view_allocation.height * 0.1;
+  vadjustment->page_increment = view_allocation.height * 0.9;
+  
+  vadjustment->lower = 0;
 
-  if (viewport->vadjustment && viewport->vadjustment != adjustment)
+  if (bin->child && gtk_widget_get_visible (bin->child))
     {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (viewport->vadjustment), viewport);
-      gtk_object_unref (GTK_OBJECT (viewport->vadjustment));
-      viewport->vadjustment = NULL;
+      GtkRequisition child_requisition;
+      
+      gtk_widget_get_child_requisition (bin->child, &child_requisition);
+      vadjustment->upper = MAX (child_requisition.height, view_allocation.height);
     }
+  else
+    vadjustment->upper = view_allocation.height;
+
+  viewport_reclamp_adjustment (vadjustment, value_changed);
+}
+
+static void
+viewport_set_adjustment (GtkViewport    *viewport,
+                        GtkOrientation  orientation,
+                        GtkAdjustment  *adjustment)
+{
+  GtkAdjustment **adjustmentp = ADJUSTMENT_POINTER (viewport, orientation);
+  gboolean value_changed;
+
+  if (adjustment && adjustment == *adjustmentp)
+    return;
 
   if (!adjustment)
     adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
                                                     0.0, 0.0, 0.0));
+  viewport_disconnect_adjustment (viewport, orientation);
+  *adjustmentp = adjustment;
+  g_object_ref_sink (adjustment);
 
-  if (viewport->vadjustment != adjustment)
-    {
-      viewport->vadjustment = adjustment;
-      gtk_object_ref (GTK_OBJECT (viewport->vadjustment));
-      gtk_object_sink (GTK_OBJECT (viewport->vadjustment));
-      
-      gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                         (GtkSignalFunc) gtk_viewport_adjustment_changed,
-                         (gpointer) viewport);
-      gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                         (GtkSignalFunc) gtk_viewport_adjustment_value_changed,
-                         (gpointer) viewport);
-
-      gtk_viewport_adjustment_changed (adjustment, viewport);
-    }
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    viewport_set_hadjustment_values (viewport, &value_changed);
+  else
+    viewport_set_vadjustment_values (viewport, &value_changed);
+
+  g_signal_connect (adjustment, "value-changed",
+                   G_CALLBACK (gtk_viewport_adjustment_value_changed),
+                   viewport);
+
+  gtk_adjustment_changed (adjustment);
+  
+  if (value_changed)
+    gtk_adjustment_value_changed (adjustment);
+  else
+    gtk_viewport_adjustment_value_changed (adjustment, viewport);
+}
+
+/**
+ * gtk_viewport_set_hadjustment:
+ * @viewport: a #GtkViewport.
+ * @adjustment: (allow-none): a #GtkAdjustment.
+ *
+ * Sets the horizontal adjustment of the viewport.
+ **/
+void
+gtk_viewport_set_hadjustment (GtkViewport   *viewport,
+                             GtkAdjustment *adjustment)
+{
+  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
+  if (adjustment)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  viewport_set_adjustment (viewport, GTK_ORIENTATION_HORIZONTAL, adjustment);
+
+  g_object_notify (G_OBJECT (viewport), "hadjustment");
+}
+
+/**
+ * gtk_viewport_set_vadjustment:
+ * @viewport: a #GtkViewport.
+ * @adjustment: (allow-none): a #GtkAdjustment.
+ *
+ * Sets the vertical adjustment of the viewport.
+ **/
+void
+gtk_viewport_set_vadjustment (GtkViewport   *viewport,
+                             GtkAdjustment *adjustment)
+{
+  g_return_if_fail (GTK_IS_VIEWPORT (viewport));
+  if (adjustment)
+    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
+
+  viewport_set_adjustment (viewport, GTK_ORIENTATION_VERTICAL, adjustment);
 
   g_object_notify (G_OBJECT (viewport), "vadjustment");
 }
@@ -373,81 +508,86 @@ gtk_viewport_set_scroll_adjustments (GtkViewport      *viewport,
                                     GtkAdjustment    *hadjustment,
                                     GtkAdjustment    *vadjustment)
 {
-  if (viewport->hadjustment != hadjustment)
-    gtk_viewport_set_hadjustment (viewport, hadjustment);
-  if (viewport->vadjustment != vadjustment)
-    gtk_viewport_set_vadjustment (viewport, vadjustment);
+  gtk_viewport_set_hadjustment (viewport, hadjustment);
+  gtk_viewport_set_vadjustment (viewport, vadjustment);
 }
 
+/** 
+ * gtk_viewport_set_shadow_type:
+ * @viewport: a #GtkViewport.
+ * @type: the new shadow type.
+ *
+ * Sets the shadow type of the viewport.
+ **/ 
 void
 gtk_viewport_set_shadow_type (GtkViewport   *viewport,
                              GtkShadowType  type)
 {
-  g_return_if_fail (viewport != NULL);
   g_return_if_fail (GTK_IS_VIEWPORT (viewport));
 
   if ((GtkShadowType) viewport->shadow_type != type)
     {
       viewport->shadow_type = type;
 
-      if (GTK_WIDGET_VISIBLE (viewport))
+      if (gtk_widget_get_visible (GTK_WIDGET (viewport)))
        {
          gtk_widget_size_allocate (GTK_WIDGET (viewport), &(GTK_WIDGET (viewport)->allocation));
          gtk_widget_queue_draw (GTK_WIDGET (viewport));
        }
-    }
 
-  g_object_notify (G_OBJECT (viewport), "shadow_type");
+      g_object_notify (G_OBJECT (viewport), "shadow-type");
+    }
 }
 
-
-static void
-gtk_viewport_map (GtkWidget *widget)
+/**
+ * gtk_viewport_get_shadow_type:
+ * @viewport: a #GtkViewport
+ *
+ * Gets the shadow type of the #GtkViewport. See
+ * gtk_viewport_set_shadow_type().
+ * Return value: the shadow type 
+ **/
+GtkShadowType
+gtk_viewport_get_shadow_type (GtkViewport *viewport)
 {
-  GtkBin *bin;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
-
-  GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
-  bin = GTK_BIN (widget);
+  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), GTK_SHADOW_NONE);
 
-  if (bin->child &&
-      GTK_WIDGET_VISIBLE (bin->child) &&
-      !GTK_WIDGET_MAPPED (bin->child))
-    gtk_widget_map (bin->child);
-
-  gdk_window_show (widget->window);
+  return viewport->shadow_type;
 }
 
-static void
-gtk_viewport_unmap (GtkWidget *widget)
+/**
+ * gtk_viewport_get_bin_window:
+ * @viewport: a #GtkViewport
+ *
+ * Gets the bin window of the #GtkViewport.
+ *
+ * Return value: a #GdkWindow
+ *
+ * Since: 2.20
+ **/
+GdkWindow*
+gtk_viewport_get_bin_window (GtkViewport *viewport)
 {
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
+  g_return_val_if_fail (GTK_IS_VIEWPORT (viewport), NULL);
 
-  GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
-  
-  gdk_window_hide (widget->window);
+  return viewport->bin_window;
 }
 
 static void
 gtk_viewport_realize (GtkWidget *widget)
 {
-  GtkBin *bin;
-  GtkViewport *viewport;
+  GtkViewport *viewport = GTK_VIEWPORT (widget);
+  GtkBin *bin = GTK_BIN (widget);
+  GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
+  GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
+  gint border_width = GTK_CONTAINER (widget)->border_width;
+  
+  GtkAllocation view_allocation;
   GdkWindowAttr attributes;
   gint attributes_mask;
   gint event_mask;
-  gint border_width;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
 
-  border_width = GTK_CONTAINER (widget)->border_width;
-
-  bin = GTK_BIN (widget);
-  viewport = GTK_VIEWPORT (widget);
   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
 
   attributes.x = widget->allocation.x + border_width;
@@ -470,32 +610,23 @@ gtk_viewport_realize (GtkWidget *widget)
                                   &attributes, attributes_mask);
   gdk_window_set_user_data (widget->window, viewport);
 
-  if (viewport->shadow_type != GTK_SHADOW_NONE)
-    {
-      attributes.x = widget->style->xthickness;
-      attributes.y = widget->style->ythickness;
-    }
-  else
-    {
-      attributes.x = 0;
-      attributes.y = 0;
-    }
-
-  attributes.width = MAX (1, (gint)widget->allocation.width - attributes.x * 2 - border_width * 2);
-  attributes.height = MAX (1, (gint)widget->allocation.height - attributes.y * 2 - border_width * 2);
+  viewport_get_view_allocation (viewport, &view_allocation);
+  
+  attributes.x = view_allocation.x;
+  attributes.y = view_allocation.y;
+  attributes.width = view_allocation.width;
+  attributes.height = view_allocation.height;
   attributes.event_mask = 0;
 
   viewport->view_window = gdk_window_new (widget->window, &attributes, attributes_mask);
   gdk_window_set_user_data (viewport->view_window, viewport);
 
-  attributes.x = 0;
-  attributes.y = 0;
-
-  if (bin->child)
-    {
-      attributes.width = viewport->hadjustment->upper;
-      attributes.height = viewport->vadjustment->upper;
-    }
+  gdk_window_set_back_pixmap (viewport->view_window, NULL, FALSE);
+  
+  attributes.x = - hadjustment->value;
+  attributes.y = - vadjustment->value;
+  attributes.width = hadjustment->upper;
+  attributes.height = vadjustment->upper;
   
   attributes.event_mask = event_mask;
 
@@ -509,10 +640,12 @@ gtk_viewport_realize (GtkWidget *widget)
   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
   gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
 
-   gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
-                     GTK_SHADOW_NONE,
-                     NULL, widget, "viewportbin",
-                     0, 0, -1, -1);
+  /* Call paint here to allow a theme to set the background without flashing
+   */
+  gtk_paint_flat_box(widget->style, viewport->bin_window, GTK_STATE_NORMAL,
+                    GTK_SHADOW_NONE,
+                    NULL, widget, "viewportbin",
+                    0, 0, -1, -1);
    
   gdk_window_show (viewport->bin_window);
   gdk_window_show (viewport->view_window);
@@ -521,12 +654,7 @@ gtk_viewport_realize (GtkWidget *widget)
 static void
 gtk_viewport_unrealize (GtkWidget *widget)
 {
-  GtkViewport *viewport;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
-
-  viewport = GTK_VIEWPORT (widget);
+  GtkViewport *viewport = GTK_VIEWPORT (widget);
 
   gdk_window_set_user_data (viewport->view_window, NULL);
   gdk_window_destroy (viewport->view_window);
@@ -536,27 +664,21 @@ gtk_viewport_unrealize (GtkWidget *widget)
   gdk_window_destroy (viewport->bin_window);
   viewport->bin_window = NULL;
 
-  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
-    (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+  GTK_WIDGET_CLASS (gtk_viewport_parent_class)->unrealize (widget);
 }
 
 static void
 gtk_viewport_paint (GtkWidget    *widget,
                    GdkRectangle *area)
 {
-  GtkViewport *viewport;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
-  g_return_if_fail (area != NULL);
-
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
-      viewport = GTK_VIEWPORT (widget);
+      GtkViewport *viewport = GTK_VIEWPORT (widget);
 
-      gtk_draw_shadow (widget->style, widget->window,
-                      GTK_STATE_NORMAL, viewport->shadow_type,
-                      0, 0, -1, -1);
+      gtk_paint_shadow (widget->style, widget->window,
+                       GTK_STATE_NORMAL, viewport->shadow_type,
+                       area, widget, "viewport",
+                       0, 0, -1, -1);
     }
 }
 
@@ -565,33 +687,22 @@ gtk_viewport_expose (GtkWidget      *widget,
                     GdkEventExpose *event)
 {
   GtkViewport *viewport;
-  GtkBin *bin;
-  GdkEventExpose child_event;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_VIEWPORT (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
 
-  if (GTK_WIDGET_DRAWABLE (widget))
+  if (gtk_widget_is_drawable (widget))
     {
       viewport = GTK_VIEWPORT (widget);
-      bin = GTK_BIN (widget);
 
       if (event->window == widget->window)
        gtk_viewport_paint (widget, &event->area);
       else if (event->window == viewport->bin_window)
        {
-         child_event = *event;
-
          gtk_paint_flat_box(widget->style, viewport->bin_window, 
                             GTK_STATE_NORMAL, GTK_SHADOW_NONE,
                             &event->area, widget, "viewportbin",
                             0, 0, -1, -1);
-         
-         (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
-       }
-       
 
+         GTK_WIDGET_CLASS (gtk_viewport_parent_class)->expose_event (widget, event);
+       }
     }
 
   return FALSE;
@@ -601,42 +712,33 @@ static void
 gtk_viewport_add (GtkContainer *container,
                  GtkWidget    *child)
 {
-  GtkBin *bin;
-
-  g_return_if_fail (container != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (container));
-  g_return_if_fail (child != NULL);
+  GtkBin *bin = GTK_BIN (container);
 
-  bin = GTK_BIN (container);
   g_return_if_fail (bin->child == NULL);
 
   gtk_widget_set_parent_window (child, GTK_VIEWPORT (bin)->bin_window);
 
-  GTK_CONTAINER_CLASS (parent_class)->add (container, child);
+  GTK_CONTAINER_CLASS (gtk_viewport_parent_class)->add (container, child);
 }
 
 static void
 gtk_viewport_size_request (GtkWidget      *widget,
                           GtkRequisition *requisition)
 {
-  GtkViewport *viewport;
-  GtkBin *bin;
+  GtkBin *bin = GTK_BIN (widget);
   GtkRequisition child_requisition;
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
-  g_return_if_fail (requisition != NULL);
+  requisition->width = GTK_CONTAINER (widget)->border_width;
 
-  viewport = GTK_VIEWPORT (widget);
-  bin = GTK_BIN (widget);
+  requisition->height = GTK_CONTAINER (widget)->border_width;
 
-  requisition->width = (GTK_CONTAINER (widget)->border_width +
-                       GTK_WIDGET (widget)->style->xthickness) * 2 + 5;
-
-  requisition->height = (GTK_CONTAINER (widget)->border_width * 2 +
-                        GTK_WIDGET (widget)->style->ythickness) * 2 + 5;
+  if (GTK_VIEWPORT (widget)->shadow_type != GTK_SHADOW_NONE)
+    {
+      requisition->width += 2 * widget->style->xthickness;
+      requisition->height += 2 * widget->style->ythickness;
+    }
 
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+  if (bin->child && gtk_widget_get_visible (bin->child))
     {
       gtk_widget_size_request (bin->child, &child_requisition);
       requisition->width += child_requisition.width;
@@ -648,167 +750,86 @@ static void
 gtk_viewport_size_allocate (GtkWidget     *widget,
                            GtkAllocation *allocation)
 {
-  GtkViewport *viewport;
-  GtkBin *bin;
+  GtkViewport *viewport = GTK_VIEWPORT (widget);
+  GtkBin *bin = GTK_BIN (widget);
+  gint border_width = GTK_CONTAINER (widget)->border_width;
+  gboolean hadjustment_value_changed, vadjustment_value_changed;
+  GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
+  GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
   GtkAllocation child_allocation;
-  gint hval, vval;
-  gint border_width;
-
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (widget));
-  g_return_if_fail (allocation != NULL);
 
+  /* If our size changed, and we have a shadow, queue a redraw on widget->window to
+   * redraw the shadow correctly.
+   */
+  if (gtk_widget_get_mapped (widget) &&
+      viewport->shadow_type != GTK_SHADOW_NONE &&
+      (widget->allocation.width != allocation->width ||
+       widget->allocation.height != allocation->height))
+    gdk_window_invalidate_rect (widget->window, NULL, FALSE);
+  
   widget->allocation = *allocation;
-  viewport = GTK_VIEWPORT (widget);
-  bin = GTK_BIN (widget);
-
-  /* demand creation */
-  if (!viewport->hadjustment)
-    gtk_viewport_set_hadjustment (viewport, NULL);
-  if (!viewport->vadjustment)
-    gtk_viewport_set_hadjustment (viewport, NULL);
-
-  border_width = GTK_CONTAINER (widget)->border_width;
-
+  
+  viewport_set_hadjustment_values (viewport, &hadjustment_value_changed);
+  viewport_set_vadjustment_values (viewport, &vadjustment_value_changed);
+  
   child_allocation.x = 0;
   child_allocation.y = 0;
-
-  if (viewport->shadow_type != GTK_SHADOW_NONE)
-    {
-      child_allocation.x = GTK_WIDGET (viewport)->style->xthickness;
-      child_allocation.y = GTK_WIDGET (viewport)->style->ythickness;
-    }
-
-  child_allocation.width = MAX (1, allocation->width - child_allocation.x * 2 - border_width * 2);
-  child_allocation.height = MAX (1, allocation->height - child_allocation.y * 2 - border_width * 2);
-
+  child_allocation.width = hadjustment->upper;
+  child_allocation.height = vadjustment->upper;
   if (GTK_WIDGET_REALIZED (widget))
     {
+      GtkAllocation view_allocation;
       gdk_window_move_resize (widget->window,
                              allocation->x + border_width,
                              allocation->y + border_width,
                              allocation->width - border_width * 2,
                              allocation->height - border_width * 2);
-
-      gdk_window_move_resize (viewport->view_window,
-                             child_allocation.x,
-                             child_allocation.y,
-                             child_allocation.width,
-                             child_allocation.height);
-    }
-
-  viewport->hadjustment->page_size = child_allocation.width;
-  viewport->hadjustment->page_increment = viewport->hadjustment->page_size / 2;
-  viewport->hadjustment->step_increment = 10;
-
-  viewport->vadjustment->page_size = child_allocation.height;
-  viewport->vadjustment->page_increment = viewport->vadjustment->page_size / 2;
-  viewport->vadjustment->step_increment = 10;
-
-  hval = viewport->hadjustment->value;
-  vval = viewport->vadjustment->value;
-
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
-    {
-      GtkRequisition child_requisition;
-      gtk_widget_get_child_requisition (bin->child, &child_requisition);
       
-      viewport->hadjustment->lower = 0;
-      viewport->hadjustment->upper = MAX (child_requisition.width,
-                                         child_allocation.width);
-
-      hval = CLAMP (hval, 0,
-                   viewport->hadjustment->upper -
-                   viewport->hadjustment->page_size);
-
-      viewport->vadjustment->lower = 0;
-      viewport->vadjustment->upper = MAX (child_requisition.height,
-                                         child_allocation.height);
-
-      vval = CLAMP (vval, 0,
-                   viewport->vadjustment->upper -
-                   viewport->vadjustment->page_size);
-    }
-
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
-    {
-      child_allocation.x = 0;
-      child_allocation.y = 0;
-
-      child_allocation.width = viewport->hadjustment->upper;
-      child_allocation.height = viewport->vadjustment->upper;
-
-      if (GTK_WIDGET_REALIZED (widget))
-       gdk_window_resize (viewport->bin_window,
-                          child_allocation.width,
-                          child_allocation.height);
-
-      child_allocation.x = 0;
-      child_allocation.y = 0;
-      gtk_widget_size_allocate (bin->child, &child_allocation);
-    }
-
-  gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "changed");
-  gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "changed");
-  if (viewport->hadjustment->value != hval)
-    {
-      viewport->hadjustment->value = hval;
-      gtk_signal_emit_by_name (GTK_OBJECT (viewport->hadjustment), "value_changed");
-    }
-  if (viewport->vadjustment->value != vval)
-    {
-      viewport->vadjustment->value = vval;
-      gtk_signal_emit_by_name (GTK_OBJECT (viewport->vadjustment), "value_changed");
+      viewport_get_view_allocation (viewport, &view_allocation);
+      gdk_window_move_resize (viewport->view_window,
+                             view_allocation.x,
+                             view_allocation.y,
+                             view_allocation.width,
+                             view_allocation.height);
+      gdk_window_move_resize (viewport->bin_window,
+                              - hadjustment->value,
+                              - vadjustment->value,
+                              child_allocation.width,
+                              child_allocation.height);
     }
-}
-
-static void
-gtk_viewport_adjustment_changed (GtkAdjustment *adjustment,
-                                gpointer       data)
-{
-  GtkViewport *viewport;
-
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (data));
-
-  viewport = GTK_VIEWPORT (data);
+  if (bin->child && gtk_widget_get_visible (bin->child))
+    gtk_widget_size_allocate (bin->child, &child_allocation);
+
+  gtk_adjustment_changed (hadjustment);
+  gtk_adjustment_changed (vadjustment);
+  if (hadjustment_value_changed)
+    gtk_adjustment_value_changed (hadjustment);
+  if (vadjustment_value_changed)
+    gtk_adjustment_value_changed (vadjustment);
 }
 
 static void
 gtk_viewport_adjustment_value_changed (GtkAdjustment *adjustment,
                                       gpointer       data)
 {
-  GtkViewport *viewport;
-  GtkBin *bin;
-  GtkAllocation child_allocation;
+  GtkViewport *viewport = GTK_VIEWPORT (data);
+  GtkBin *bin = GTK_BIN (data);
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
-  g_return_if_fail (GTK_IS_VIEWPORT (data));
-
-  viewport = GTK_VIEWPORT (data);
-  bin = GTK_BIN (data);
-
-  if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+  if (bin->child && gtk_widget_get_visible (bin->child)  &&
+      GTK_WIDGET_REALIZED (viewport))
     {
-      child_allocation.x = 0;
-      child_allocation.y = 0;
+      GtkAdjustment *hadjustment = gtk_viewport_get_hadjustment (viewport);
+      GtkAdjustment *vadjustment = gtk_viewport_get_vadjustment (viewport);
+      gint old_x, old_y;
+      gint new_x, new_y;
 
-      if (viewport->hadjustment->lower != (viewport->hadjustment->upper -
-                                          viewport->hadjustment->page_size))
-       child_allocation.x =  viewport->hadjustment->lower - viewport->hadjustment->value;
+      gdk_window_get_position (viewport->bin_window, &old_x, &old_y);
+      new_x = - hadjustment->value;
+      new_y = - vadjustment->value;
 
-      if (viewport->vadjustment->lower != (viewport->vadjustment->upper -
-                                          viewport->vadjustment->page_size))
-       child_allocation.y = viewport->vadjustment->lower - viewport->vadjustment->value;
-
-      if (GTK_WIDGET_REALIZED (viewport))
+      if (new_x != old_x || new_y != old_y)
        {
-         gdk_window_move (viewport->bin_window,
-                          child_allocation.x,
-                          child_allocation.y);
-      
+         gdk_window_move (viewport->bin_window, new_x, new_y);
          gdk_window_process_updates (viewport->bin_window, TRUE);
        }
     }
@@ -818,14 +839,15 @@ static void
 gtk_viewport_style_set (GtkWidget *widget,
                        GtkStyle  *previous_style)
 {
-   GtkViewport *viewport;
-   
    if (GTK_WIDGET_REALIZED (widget) &&
-       !GTK_WIDGET_NO_WINDOW (widget))
+       gtk_widget_get_has_window (widget))
      {
-       viewport = GTK_VIEWPORT (widget);
-       
+       GtkViewport *viewport = GTK_VIEWPORT (widget);
+
        gtk_style_set_background (widget->style, viewport->bin_window, GTK_STATE_NORMAL);
        gtk_style_set_background (widget->style, widget->window, widget->state);
      }
 }
+
+#define __GTK_VIEWPORT_C__
+#include "gtkaliasdef.c"