--- /dev/null
+/* -*-C-*-
+
+Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
+ 2016, 2017 Matthew Birkholz
+
+This file is part of a Gtk plugin for MIT/GNU Scheme Pucked.
+
+This plugin is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+This plugin is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this plugin; if not, write to the Free Software Foundation,
+Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+*/
+
+/* A specialized GtkScrolledWindow. See documentation of
+ <gtk-scrolled-view>. */
+
+#include "gtkscrolledview.h"
+
+static void gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static void gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *layout,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+
+G_DEFINE_TYPE (GtkScrolledView, gtk_scrolled_view,
+ GTK_TYPE_SCROLLED_WINDOW)
+
+static void
+gtk_scrolled_view_class_init (GtkScrolledViewClass *class)
+{
+ GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
+
+ widget_class->get_preferred_width = gtk_scrolled_window_get_preferred_width;
+ widget_class->get_preferred_height = gtk_scrolled_window_get_preferred_height;
+ widget_class->get_preferred_height_for_width = gtk_scrolled_window_get_preferred_height_for_width;
+ widget_class->get_preferred_width_for_height = gtk_scrolled_window_get_preferred_width_for_height;
+}
+
+static void
+gtk_scrolled_view_init (GtkScrolledView *scrolled_view)
+{
+ g_assert (GTK_SCROLLED_WINDOW (scrolled_view) ->priv != NULL);
+}
+
+/**
+ * gtk_scrolled_view_new:
+ * @hadjustment: (allow-none): horizontal adjustment
+ * @vadjustment: (allow-none): vertical adjustment
+ *
+ * Creates a new scrolling window.
+ *
+ * The two arguments are the scrolling window's adjustments; these will be
+ * shared with the scrollbars and the child widget to keep the bars in sync
+ * with the child. Usually you want to pass %NULL for the adjustments, which
+ * will cause the scrolling window to create them for you.
+ *
+ * Returns: a new scrolling window
+ */
+GtkWidget*
+gtk_scrolled_view_new (GtkAdjustment *hadjustment,
+ GtkAdjustment *vadjustment)
+{
+ GtkWidget *scrolled_view;
+
+ if (hadjustment)
+ g_return_val_if_fail (GTK_IS_ADJUSTMENT (hadjustment), NULL);
+
+ if (vadjustment)
+ g_return_val_if_fail (GTK_IS_ADJUSTMENT (vadjustment), NULL);
+
+ scrolled_view = g_object_new (GTK_TYPE_SCROLLED_VIEW,
+ "hadjustment", hadjustment,
+ "vadjustment", vadjustment,
+ NULL);
+
+ return scrolled_view;
+}
+\f
+/* The following definitions were copied unchanged from
+ gtkscrolledwindow.c v3.18.9 unless otherwise noted. The geometry
+ protocol methods in v3.20.9 now use private gadget functions, but
+ the v3.18.9 code is still correct, so it is used instead. This
+ presumably means limited CSS styling for GtkScrolledView (until the
+ gadget functions are no longer private).
+
+ struct _GtkProgressTracker v3.22.11
+ struct Indicator v3.22.11
+ struct _GtkScrolledWindowPrivate v3.22.11
+ static gint _gtk_scrolled_window_get_scrollbar_spacing ()
+ static void gtk_scrolled_window_get_preferred_size () PATCHED
+ static void gtk_scrolled_window_get_preferred_width ()
+ static void gtk_scrolled_window_get_preferred_height ()
+ static void gtk_scrolled_window_get_preferred_height_for_width ()
+ static void gtk_scrolled_window_get_preferred_width_for_height ()
+*/
+
+typedef struct _GtkProgressTracker GtkProgressTracker;
+
+struct _GtkProgressTracker
+{
+ gboolean is_running;
+ guint64 last_frame_time;
+ guint64 duration;
+ gdouble iteration;
+ gdouble iteration_count;
+};
+
+typedef struct
+{
+ GtkWidget *scrollbar;
+ GdkWindow *window;
+ gboolean over; /* either mouse over, or while dragging */
+ gint64 last_scroll_time;
+ guint conceil_timer;
+
+ gdouble current_pos;
+ gdouble source_pos;
+ gdouble target_pos;
+ GtkProgressTracker tracker;
+ guint tick_id;
+ guint over_timeout_id;
+} Indicator;
+
+typedef long GtkCssGadget;
+typedef long GtkCssNode;
+
+struct _GtkScrolledWindowPrivate
+{
+ GtkWidget *hscrollbar;
+ GtkWidget *vscrollbar;
+
+ GtkCssGadget *gadget;
+ GtkCssNode *overshoot_node[4];
+ GtkCssNode *undershoot_node[4];
+
+ Indicator hindicator;
+ Indicator vindicator;
+
+ GtkCornerType window_placement;
+ guint16 shadow_type;
+
+ guint hscrollbar_policy : 2;
+ guint vscrollbar_policy : 2;
+ guint hscrollbar_visible : 1;
+ guint vscrollbar_visible : 1;
+ guint focus_out : 1; /* used by ::move-focus-out implementation */
+ guint overlay_scrolling : 1;
+ guint use_indicators : 1;
+ guint auto_added_viewport : 1;
+ guint propagate_natural_width : 1;
+ guint propagate_natural_height : 1;
+
+ gint min_content_width;
+ gint min_content_height;
+ gint max_content_width;
+ gint max_content_height;
+
+ guint scroll_events_overshoot_id;
+
+ /* Kinetic scrolling */
+ GtkGesture *long_press_gesture;
+ GtkGesture *swipe_gesture;
+
+ GArray *scroll_history;
+ GdkDevice *scroll_device;
+ GdkWindow *scroll_window;
+ GdkCursor *scroll_cursor;
+
+ /* These two gestures are mutually exclusive */
+ GtkGesture *drag_gesture;
+ GtkGesture *pan_gesture;
+
+ gdouble drag_start_x;
+ gdouble drag_start_y;
+
+ GdkDevice *drag_device;
+ guint kinetic_scrolling : 1;
+ guint capture_button_press : 1;
+ guint in_drag : 1;
+
+ guint deceleration_id;
+
+ gdouble x_velocity;
+ gdouble y_velocity;
+
+ gdouble unclamped_hadj_value;
+ gdouble unclamped_vadj_value;
+};
+
+static gint
+_gtk_scrolled_window_get_scrollbar_spacing (GtkScrolledWindow *scrolled_window)
+{
+ GtkScrolledWindowClass *class;
+
+ g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window), 0);
+
+ class = GTK_SCROLLED_WINDOW_GET_CLASS (scrolled_window);
+
+ if (class->scrollbar_spacing >= 0)
+ return class->scrollbar_spacing;
+ else
+ {
+ gint scrollbar_spacing;
+
+ gtk_widget_style_get (GTK_WIDGET (scrolled_window),
+ "scrollbar-spacing", &scrollbar_spacing,
+ NULL);
+
+ return scrollbar_spacing;
+ }
+}
+
+static void
+gtk_scrolled_window_get_preferred_size (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
+ GtkScrolledWindowPrivate *priv = scrolled_window->priv;
+ GtkBin *bin = GTK_BIN (scrolled_window);
+ GtkWidget *child;
+ gint min_size, nat_size;
+
+ child = gtk_bin_get_child (bin);
+ if (child && gtk_widget_get_visible (child))
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_widget_get_preferred_width (child, &min_size, &nat_size);
+ if (priv->min_content_width >= 0)
+ min_size = MAX (min_size, priv->min_content_width);
+ }
+ else /* GTK_ORIENTATION_VERTICAL */
+ {
+ gtk_widget_get_preferred_height (child, &min_size, &nat_size);
+ if (priv->min_content_height >= 0)
+ min_size = MAX (min_size, priv->min_content_height);
+ }
+ }
+
+ if (!priv->use_indicators)
+ {
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (priv->vscrollbar_policy != GTK_POLICY_NEVER)
+ {
+ gint min_width, nat_width;
+ gint scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+ gtk_widget_get_preferred_width (priv->vscrollbar, &min_width, &nat_width);
+ min_size += MAX (0, scrollbar_spacing + min_width);
+ nat_size += MAX (0, scrollbar_spacing + nat_width);
+ }
+ if (priv->hscrollbar_policy != GTK_POLICY_NEVER)
+ {
+ gint min_width, nat_width;
+ gtk_widget_get_preferred_width (priv->hscrollbar, &min_width, &nat_width);
+ min_size = MAX (min_size, min_width);
+ nat_size = MAX (nat_size, nat_width);
+ }
+ }
+ else /* orientation == GTK_ORIENTATION_VERTICAL */
+ {
+ if (priv->hscrollbar_policy != GTK_POLICY_NEVER)
+ {
+ gint min_height, nat_height;
+ gint scrollbar_spacing = _gtk_scrolled_window_get_scrollbar_spacing (scrolled_window);
+ gtk_widget_get_preferred_height (priv->hscrollbar, &min_height, &nat_height);
+ min_size += MAX (0, scrollbar_spacing + min_height);
+ nat_size += MAX (0, scrollbar_spacing + nat_height);
+ }
+ if (priv->vscrollbar_policy != GTK_POLICY_NEVER)
+ {
+ gint min_height, nat_height;
+ gtk_widget_get_preferred_height (priv->vscrollbar, &min_height, &nat_height);
+ min_size = MAX (min_size, min_height);
+ nat_size = MAX (nat_size, nat_height);
+ }
+ }
+ }
+
+ if (priv->shadow_type != GTK_SHADOW_NONE)
+ {
+ GtkStyleContext *context;
+ GtkStateFlags state;
+ GtkBorder padding, border;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (widget));
+ state = gtk_style_context_get_state (context);
+
+ gtk_style_context_get_padding (context, state, &padding);
+ gtk_style_context_get_border (context, state, &border);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ min_size += padding.left + padding.right + border.left + border.right;
+ nat_size += padding.left + padding.right + border.left + border.right;
+ }
+ else
+ {
+ min_size += padding.top + padding.bottom + border.top + border.bottom;
+ nat_size += padding.top + padding.bottom + border.top + border.bottom;
+ }
+ }
+
+ *minimum_size = min_size;
+ *natural_size = nat_size;
+}
+
+static void
+gtk_scrolled_window_get_preferred_width (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
+}
+
+static void
+gtk_scrolled_window_get_preferred_height (GtkWidget *widget,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ gtk_scrolled_window_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
+}
+
+static void
+gtk_scrolled_window_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height)
+{
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, minimum_height, natural_height);
+}
+
+static void
+gtk_scrolled_window_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width)
+{
+ GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, minimum_width, natural_width);
+}