+static void
+viewport_get_view_allocation (GtkViewport *viewport,
+ GtkAllocation *view_allocation)
+{
+ 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->shadow_type != GTK_SHADOW_NONE)
+ {
+ view_allocation->x = widget->style->xthickness;
+ view_allocation->y = widget->style->ythickness;
+ }
+
+ 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);
+}
+
+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)
+ {
+ 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);
+
+ viewport_get_view_allocation (viewport, &view_allocation);
+
+ 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_VISIBLE (bin->child))
+ {
+ GtkRequisition child_requisition;
+
+ gtk_widget_get_child_requisition (bin->child, &child_requisition);
+ hadjustment->upper = MAX (child_requisition.width, view_allocation.width);
+ }
+ else
+ hadjustment->upper = view_allocation.width;
+
+ viewport_reclamp_adjustment (hadjustment, value_changed);
+}
+
+static void
+viewport_set_vadjustment_values (GtkViewport *viewport,
+ gboolean *value_changed)
+{
+ 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 (bin->child && GTK_WIDGET_VISIBLE (bin->child))
+ {
+ 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 == *adjustmentp)
+ return;
+
+ if (!adjustment)
+ adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0));
+
+ *adjustmentp = adjustment;
+ g_object_ref (adjustment);
+ gtk_object_sink (GTK_OBJECT (adjustment));
+
+ 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);
+}
+