From c14a773e6144b2ade493a7c89b361133aadca122 Mon Sep 17 00:00:00 2001 From: Matt Birkholz Date: Mon, 14 Dec 2015 18:02:07 -0700 Subject: [PATCH] gtk: Port GtkScrolledView and GtkPanedView to Gtk+ 3.16.7. Attempt to pick from multiple implementations per the Gtk+ version. --- src/gtk/Makefile.in | 3 +- src/gtk/README | 28 +- src/gtk/autogen.sh | 19 + src/gtk/configure.ac | 33 +- src/gtk/gtkpanedview-3.16.7.c | 746 ++++++++++++++++++ .../{gtkpanedview.c => gtkpanedview-3.6.0.c} | 0 src/gtk/gtkscrolledview-3.16.7.c | 329 ++++++++ ...scrolledview.c => gtkscrolledview-3.6.0.c} | 0 8 files changed, 1147 insertions(+), 11 deletions(-) create mode 100755 src/gtk/autogen.sh create mode 100644 src/gtk/gtkpanedview-3.16.7.c rename src/gtk/{gtkpanedview.c => gtkpanedview-3.6.0.c} (100%) create mode 100644 src/gtk/gtkscrolledview-3.16.7.c rename src/gtk/{gtkscrolledview.c => gtkscrolledview-3.6.0.c} (100%) diff --git a/src/gtk/Makefile.in b/src/gtk/Makefile.in index baeaebb27..b69a041e0 100644 --- a/src/gtk/Makefile.in +++ b/src/gtk/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2011, 2012, 2013, 2014 Matthew Birkholz +# Copyright (C) 2011, 2012, 2013, 2014, 2015 Matthew Birkholz # # This file is part of an extension to MIT/GNU Scheme. # @@ -77,6 +77,7 @@ distclean: clean maintainer-clean: distclean rm -f configure config.h.in TAGS rm -rf autom4te.cache + rm -f gtkscrolledview.c gtkpanedview.c tags: etags *.h \ diff --git a/src/gtk/README b/src/gtk/README index a8cd1d78e..b069ffa91 100644 --- a/src/gtk/README +++ b/src/gtk/README @@ -1,8 +1,32 @@ -The gtk wrapper. +The Gtk+ wrapper. + +The good news first: this wrapper provides specialized Gtk+ widget +types that inherit the gesture and kinetic scrolling support in +GtkScrolledWindow. Thus a Scheme canvas can be scrolled like any +other widget. + +The bad news: Edwin requires these specialized widget types. +GtkScrolledWindow and GtkPaned do not suffice. The specialized types +require access to private members of their supertypes, so they need +a struct declaration matching the private declaration in the toolkit. + +The trick: Select an implementation of the special widgets that is +compatible with your system's toolkit. One is provided and +corresponds to the latest Ubuntu release. If your system is using a +matching or "close enough" version of the toolkit, you will get a +treat. + + Ubuntu Gtk+ + 15.10 3.16.7 + +The solution: Add GtkScrolledView and GtkPanedView to Gtk+. +Unfortunately, implementing both GtkScrolledWindow and GtkScrolledView +without duplicating a lot of code makes this a less-than-simple +extension of Gtk+. To build: - ./configure [--with-gtk=directory]... + ./configure make all check install The install target copies a shared library shim and compiled Scheme diff --git a/src/gtk/autogen.sh b/src/gtk/autogen.sh new file mode 100755 index 000000000..6263f54df --- /dev/null +++ b/src/gtk/autogen.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +test -n "$srcdir" || srcdir=`dirname "$0"` +test -n "$srcdir" || srcdir=. + +olddir=`pwd` +cd "$srcdir" + +AUTORECONF=`which autoreconf` +if test -z $AUTORECONF; then + echo "*** No autoreconf found, please install it ***" + exit 1 +fi + +autoreconf --force --install --verbose || exit $? + +cd "$olddir" +test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/src/gtk/configure.ac b/src/gtk/configure.ac index c9863bc08..51fcd2f73 100644 --- a/src/gtk/configure.ac +++ b/src/gtk/configure.ac @@ -1,16 +1,13 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT([MIT/GNU Scheme gtk interface], - [0.1], - [bug-mit-scheme@gnu.org], - [mit-scheme-gtk]) +AC_INIT([MIT/GNU Scheme gtk plugin], [0.2], [matt@birchwood-abbey.net], [mit-scheme-gtk]) AC_CONFIG_SRCDIR([gtk.pkg]) AC_CONFIG_HEADERS([config.h]) AC_COPYRIGHT( -[Copyright (C) 2013 Matthew Birkholz +[Copyright (C) 2013, 2015 Matthew Birkholz -This file is part of an extension to MIT/GNU Scheme. +This file is part of a plugin for MIT/GNU Scheme. MIT/GNU Scheme is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,9 +27,9 @@ USA. AH_TOP([/* -Copyright (C) 2013 Matthew Birkholz +Copyright (C) 2013, 2015 Matthew Birkholz -This file is part of MIT/GNU Scheme. +This file is part of a plugin for MIT/GNU Scheme. MIT/GNU Scheme is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -51,12 +48,32 @@ USA. */]) +AC_ARG_WITH([gtk-version], + AS_HELP_STRING([--with-gtk-version], + [Use widgets specialized for the given Gtk+ version [[guess]]])) +: ${with_gtk_version='guess'} + AC_CHECK_PROG([PKG_CONFIG], [pkg-config], [yes]) if ! pkg-config --exists gtk+-3.0 2>/dev/null; then AC_MSG_ERROR([Gtk 3.0 not found.]) fi +if pkg-config --exists 'gtk+-3.0 >= 3.16.7' 2>/dev/null; then + GTK_VERSION=3.16.7 +dnl elif pkg-config --exists 'gtk+-3.0 >= 3.14.13' 2>/dev/null; then +dnl GTK_VERSION=3.14.13 +dnl elif pkg-config --exists 'gkt+-3.0 >= 3.10.8' 2>/dev/null; then +dnl GTK_VERSION=3.10.8 +elif pkg-config --exists 'gkt+-3.0 >= 3.6.0' 2>/dev/null; then + GTK_VERSION=3.6.0 +else + AC_MSG_ERROR([Gtk version too old.]) +fi + +ln -sf gtkscrolledview-$GTK_VERSION.c gtkscrolledview.c +ln -sf gtkpanedview-$GTK_VERSION.c gtkpanedview.c + AC_SUBST([CFLAGS]) AC_SUBST([CPPFLAGS]) AC_SUBST([LDFLAGS]) diff --git a/src/gtk/gtkpanedview-3.16.7.c b/src/gtk/gtkpanedview-3.16.7.c new file mode 100644 index 000000000..c03e92580 --- /dev/null +++ b/src/gtk/gtkpanedview-3.16.7.c @@ -0,0 +1,746 @@ +/* -*-C-*- + +Copyright (C) 2015 Matthew Birkholz + +This file is part of MIT/GNU Scheme. + +MIT/GNU Scheme 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. + +MIT/GNU Scheme 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 MIT/GNU Scheme; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, +USA. + +*/ + +/* A specialized GtkPaned. See documentation of . */ + +#include "gtkpanedview.h" + +static void gtk_paned_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_paned_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); +static void gtk_paned_get_preferred_width_for_height + (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural); +static void gtk_paned_get_preferred_height_for_width + (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural); + +static void gtk_paned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static void gtk_paned_calc_position (GtkPaned *paned, + gint allocation, + gint child1_width, + gint child1_nat_width, + gint child2_width, + gint child2_nat_width); + +G_DEFINE_TYPE (GtkPanedView, gtk_paned_view, + GTK_TYPE_PANED) + +static void +gtk_paned_view_class_init (GtkPanedViewClass *class) +{ + GtkWidgetClass *widget_class = (GtkWidgetClass*) class; + + widget_class->get_preferred_width = gtk_paned_get_preferred_width; + widget_class->get_preferred_height = gtk_paned_get_preferred_height; + widget_class->get_preferred_height_for_width = gtk_paned_get_preferred_height_for_width; + widget_class->get_preferred_width_for_height = gtk_paned_get_preferred_width_for_height; + widget_class->size_allocate = gtk_paned_size_allocate; +} + +static void +gtk_paned_view_init (GtkPanedView *paned_view) +{ + g_assert (GTK_PANED (paned_view) ->priv != NULL); +} + +/** + * gtk_paned_view_new: + * @orientation: GTK_ORIENTATION_VERTICAL or GTK_ORIENTATION_HORIZONTAL. + * + * Creates a new paned view. + * + * Returns: a new paned view. + */ +GtkWidget* +gtk_paned_view_new (GtkOrientation orientation) +{ + return (g_object_new (GTK_TYPE_PANED_VIEW, + "orientation", orientation, + NULL)); +} + +/* Copied from gtkprivate.h. */ +#define OPPOSITE_ORIENTATION(_orientation) (1 - (_orientation)) + +/* Copied from gtksizerequest.c. */ +static void +_gtk_widget_get_preferred_size_for_size (GtkWidget *widget, + GtkOrientation orientation, + gint size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (size >= -1); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (size < 0) + gtk_widget_get_preferred_width (widget, minimum, natural); + else + gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural); + + if (minimum_baseline) + *minimum_baseline = -1; + if (natural_baseline) + *natural_baseline = -1; + } + else + { + gtk_widget_get_preferred_height_and_baseline_for_width (widget, + size, + minimum, + natural, + minimum_baseline, + natural_baseline); + } +} + +/* The following definitions were copied unchanged from gtkpaned.c + v3.16.7 unless otherwise noted. + + enum { CHILD1, CHILD2 } + struct _GtkPanedPrivate + static void gtk_paned_compute_position () PATCHED + static void gtk_paned_get_preferred_size_for_orientation () + static void gtk_paned_get_preferred_size_for_opposite_orientation () PATCHED + static void gtk_paned_get_preferred_size () + static void gtk_paned_get_preferred_width () + static void gtk_paned_get_preferred_height () + static void gtk_paned_get_preferred_width_for_height () + static void gtk_paned_get_preferred_height_for_width () + static void flip_child () + static void gtk_paned_set_child_visible () + static void gtk_paned_child_allocate () + static void gtk_paned_size_allocate () PATCHED + static void gtk_paned_calc_position () PATCHED +*/ + +enum { + CHILD1, + CHILD2 +}; + +struct _GtkPanedPrivate +{ + GtkPaned *first_paned; + GtkWidget *child1; + GtkWidget *child2; + GdkWindow *child1_window; + GdkWindow *child2_window; + GtkWidget *last_child1_focus; + GtkWidget *last_child2_focus; + GtkWidget *saved_focus; + GtkOrientation orientation; + + GdkCursorType cursor_type; + GdkRectangle handle_pos; + GdkWindow *handle; + + GtkGesture *pan_gesture; + + gint child1_size; + gint drag_pos; + gint last_allocation; + gint max_position; + gint min_position; + gint original_position; + + guint handle_prelit : 1; + guint in_recursion : 1; + guint child1_resize : 1; + guint child1_shrink : 1; + guint child2_resize : 1; + guint child2_shrink : 1; + guint position_set : 1; + guint panning : 1; +}; + +static void +gtk_paned_compute_position (GtkPaned *paned, + gint allocation, + gint child1_min, + gint child1_nat, + gint child2_min, + gint child2_nat, + gint *min_pos, + gint *max_pos, + gint *out_pos) +{ + GtkPanedPrivate *priv = paned->priv; + gint min, max, pos; + + min = (!priv->child1_resize ? child1_nat + : priv->child1_shrink ? 0 : child1_min); + + max = MAX (0, (allocation + - (!priv->child2_resize ? child2_nat + : priv->child2_shrink ? 0 : child2_min))); + max = MAX (min, max); + + if (!priv->position_set) + { + if (priv->child1_resize && !priv->child2_resize) + pos = MAX (0, allocation - child2_nat); + else if (!priv->child1_resize && priv->child2_resize) + pos = MIN (allocation, child1_nat); + else if (child1_nat + child2_nat != 0) + pos = allocation * ((gdouble)child1_nat / (child1_nat + child2_nat)) + 0.5; + else + pos = allocation * 0.5 + 0.5; + } + else + { + /* If the position was set before the initial allocation. + * (priv->last_allocation <= 0) just clamp it and leave it. + */ + if (priv->last_allocation > 0) + { + if (priv->child1_resize && !priv->child2_resize) + pos = priv->child1_size + allocation - priv->last_allocation; + else if (!(!priv->child1_resize && priv->child2_resize)) + pos = allocation * ((gdouble) priv->child1_size / (priv->last_allocation)) + 0.5; + else + pos = priv->child1_size; + } + else + pos = priv->child1_size; + } + + pos = CLAMP (pos, min, max); + + if (min_pos) + *min_pos = min; + if (max_pos) + *max_pos = max; + if (out_pos) + *out_pos = pos; +} + +static void +gtk_paned_get_preferred_size_for_orientation (GtkWidget *widget, + gint size, + gint *minimum, + gint *natural) +{ + GtkPaned *paned = GTK_PANED (widget); + GtkPanedPrivate *priv = paned->priv; + gint child_min, child_nat; + + *minimum = *natural = 0; + + if (priv->child1 && gtk_widget_get_visible (priv->child1)) + { + _gtk_widget_get_preferred_size_for_size (priv->child1, priv->orientation, size, &child_min, &child_nat, NULL, NULL); + if (priv->child1_shrink) + *minimum = 0; + else + *minimum = child_min; + *natural = child_nat; + } + + if (priv->child2 && gtk_widget_get_visible (priv->child2)) + { + _gtk_widget_get_preferred_size_for_size (priv->child2, priv->orientation, size, &child_min, &child_nat, NULL, NULL); + + if (!priv->child2_shrink) + *minimum += child_min; + *natural += child_nat; + } + + if (priv->child1 && gtk_widget_get_visible (priv->child1) && + priv->child2 && gtk_widget_get_visible (priv->child2)) + { + gint handle_size; + + gtk_widget_style_get (widget, "handle-size", &handle_size, NULL); + + *minimum += handle_size; + *natural += handle_size; + } +} + +static void +gtk_paned_get_preferred_size_for_opposite_orientation (GtkWidget *widget, + gint size, + gint *minimum, + gint *natural) +{ + GtkPaned *paned = GTK_PANED (widget); + GtkPanedPrivate *priv = paned->priv; + gint for_child1, for_child2; + gint child_min, child_nat; + + if (size > -1 && + priv->child1 && gtk_widget_get_visible (priv->child1) && + priv->child2 && gtk_widget_get_visible (priv->child2)) + { + gint child1_min, child1_nat, child2_min, child2_nat; + gint handle_size; + + gtk_widget_style_get (widget, "handle-size", &handle_size, NULL); + + _gtk_widget_get_preferred_size_for_size (priv->child1, priv->orientation, -1, &child1_min, &child1_nat, NULL, NULL); + _gtk_widget_get_preferred_size_for_size (priv->child2, priv->orientation, -1, &child2_min, &child2_nat, NULL, NULL); + + gtk_paned_compute_position (paned, + size - handle_size, child1_min, child1_nat, child2_min, child2_nat, + NULL, NULL, &for_child1); + + for_child2 = size - for_child1 - handle_size; + } + else + { + for_child1 = size; + for_child2 = size; + } + + *minimum = *natural = 0; + + if (priv->child1 && gtk_widget_get_visible (priv->child1)) + { + _gtk_widget_get_preferred_size_for_size (priv->child1, + OPPOSITE_ORIENTATION (priv->orientation), + for_child1, + &child_min, &child_nat, + NULL, NULL); + + *minimum = child_min; + *natural = child_nat; + } + + if (priv->child2 && gtk_widget_get_visible (priv->child2)) + { + _gtk_widget_get_preferred_size_for_size (priv->child2, + OPPOSITE_ORIENTATION (priv->orientation), + for_child2, + &child_min, &child_nat, + NULL, NULL); + + *minimum = MAX (*minimum, child_min); + *natural = MAX (*natural, child_nat); + } +} + +static void +gtk_paned_get_preferred_size (GtkWidget *widget, + GtkOrientation orientation, + gint size, + gint *minimum, + gint *natural) +{ + GtkPaned *paned = GTK_PANED (widget); + GtkPanedPrivate *priv = paned->priv; + + if (orientation == priv->orientation) + gtk_paned_get_preferred_size_for_orientation (widget, size, minimum, natural); + else + gtk_paned_get_preferred_size_for_opposite_orientation (widget, size, minimum, natural); +} + +static void +gtk_paned_get_preferred_width (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural); +} + +static void +gtk_paned_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural); +} + +static void +gtk_paned_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural) +{ + gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural); +} + +static void +gtk_paned_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural) +{ + gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural); +} + +static void +flip_child (GtkWidget *widget, + GtkAllocation *child_pos) +{ + GtkAllocation allocation; + gint x, width; + + gtk_widget_get_allocation (widget, &allocation); + x = allocation.x; + width = allocation.width; + + child_pos->x = 2 * x + width - child_pos->x - child_pos->width; +} + +static void +gtk_paned_set_child_visible (GtkPaned *paned, + guint id, + gboolean visible) +{ + GtkPanedPrivate *priv = paned->priv; + GtkWidget *child; + + child = id == CHILD1 ? priv->child1 : priv->child2; + + if (child == NULL) + return; + + gtk_widget_set_child_visible (child, visible); + + if (gtk_widget_get_mapped (GTK_WIDGET (paned))) + { + GdkWindow *window = id == CHILD1 ? priv->child1_window : priv->child2_window; + + if (visible != gdk_window_is_visible (window)) + { + if (visible) + gdk_window_show (window); + else + gdk_window_hide (window); + } + } +} + +static void +gtk_paned_child_allocate (GtkWidget *child, + GdkWindow *child_window, /* can be NULL */ + const GtkAllocation *window_allocation, + GtkAllocation *child_allocation) +{ + if (child_window) + gdk_window_move_resize (child_window, + window_allocation->x, window_allocation->y, + window_allocation->width, window_allocation->height); + + gtk_widget_size_allocate (child, child_allocation); +} + +static void +gtk_paned_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkPaned *paned = GTK_PANED (widget); + GtkPanedPrivate *priv = paned->priv; + + gtk_widget_set_allocation (widget, allocation); + + if (priv->child1 && gtk_widget_get_visible (priv->child1) && + priv->child2 && gtk_widget_get_visible (priv->child2)) + { + GtkAllocation child1_allocation, window1_allocation; + GtkAllocation child2_allocation, window2_allocation; + GtkAllocation priv_child1_allocation; + GdkRectangle old_handle_pos; + gint handle_size; + + gtk_widget_style_get (widget, "handle-size", &handle_size, NULL); + + old_handle_pos = priv->handle_pos; + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gint child1_width, child1_nat_width, child2_width, child2_nat_width; + + gtk_widget_get_preferred_width_for_height (priv->child1, + allocation->height, + &child1_width, &child1_nat_width); + gtk_widget_get_preferred_width_for_height (priv->child2, + allocation->height, + &child2_width, &child2_nat_width); + + gtk_paned_calc_position (paned, + MAX (1, allocation->width - handle_size), + child1_width, child1_nat_width, + child2_width, child2_nat_width); + + priv->handle_pos.x = allocation->x + priv->child1_size; + priv->handle_pos.y = allocation->y; + priv->handle_pos.width = handle_size; + priv->handle_pos.height = allocation->height; + + window1_allocation.height = window2_allocation.height = allocation->height; + window1_allocation.width = MAX (1, priv->child1_size); + window1_allocation.x = allocation->x; + window1_allocation.y = window2_allocation.y = allocation->y; + + window2_allocation.x = window1_allocation.x + priv->child1_size + priv->handle_pos.width; + window2_allocation.width = MAX (1, allocation->x + allocation->width - window2_allocation.x); + + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL) + { + flip_child (widget, &(window2_allocation)); + flip_child (widget, &(window1_allocation)); + flip_child (widget, &(priv->handle_pos)); + } + + child1_allocation.x = child1_allocation.y = 0; + child1_allocation.width = window1_allocation.width; + child1_allocation.height = window1_allocation.height; + if (child1_width > child1_allocation.width) + { + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_LTR) + child1_allocation.x -= child1_width - child1_allocation.width; + child1_allocation.width = child1_width; + } + + child2_allocation.x = child2_allocation.y = 0; + child2_allocation.width = window2_allocation.width; + child2_allocation.height = window2_allocation.height; + if (child2_width > child2_allocation.width) + { + if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL) + child2_allocation.x -= child2_width - child2_allocation.width; + child2_allocation.width = child2_width; + } + } + else + { + gint child1_height, child1_nat_height, child2_height, child2_nat_height; + + gtk_widget_get_preferred_height_for_width (priv->child1, + allocation->width, + &child1_height, &child1_nat_height); + gtk_widget_get_preferred_height_for_width (priv->child2, + allocation->width, + &child2_height, &child2_nat_height); + + gtk_paned_calc_position (paned, + MAX (1, allocation->height - handle_size), + child1_height, child1_nat_height, + child2_height, child2_nat_height); + + priv->handle_pos.x = allocation->x; + priv->handle_pos.y = allocation->y + priv->child1_size; + priv->handle_pos.width = allocation->width; + priv->handle_pos.height = handle_size; + + window1_allocation.width = window2_allocation.width = allocation->width; + window1_allocation.height = MAX (1, priv->child1_size); + window1_allocation.x = window2_allocation.x = allocation->x; + window1_allocation.y = allocation->y; + + window2_allocation.y = window1_allocation.y + priv->child1_size + priv->handle_pos.height; + window2_allocation.height = MAX (1, allocation->y + allocation->height - window2_allocation.y); + + child1_allocation.x = child1_allocation.y = 0; + child1_allocation.width = window1_allocation.width; + child1_allocation.height = window1_allocation.height; + if (child1_height > child1_allocation.height) + { + child1_allocation.y -= child1_height - child1_allocation.height; + child1_allocation.height = child1_height; + } + + child2_allocation.x = child2_allocation.y = 0; + child2_allocation.width = window2_allocation.width; + child2_allocation.height = window2_allocation.height; + if (child2_height > child2_allocation.height) + child2_allocation.height = child2_height; + } + + if (gtk_widget_get_mapped (widget) && + (old_handle_pos.x != priv->handle_pos.x || + old_handle_pos.y != priv->handle_pos.y || + old_handle_pos.width != priv->handle_pos.width || + old_handle_pos.height != priv->handle_pos.height)) + { + GdkWindow *window; + + window = gtk_widget_get_window (widget); + gdk_window_invalidate_rect (window, &old_handle_pos, FALSE); + gdk_window_invalidate_rect (window, &priv->handle_pos, FALSE); + } + + if (gtk_widget_get_realized (widget)) + { + GtkBorder margin; + + gtk_style_context_get_margin (gtk_widget_get_style_context (widget), + gtk_widget_get_state_flags (widget), + &margin); + + if (gtk_widget_get_mapped (widget)) + gdk_window_show (priv->handle); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gdk_window_move_resize (priv->handle, + priv->handle_pos.x - margin.left, + priv->handle_pos.y, + handle_size + margin.left + margin.right, + priv->handle_pos.height); + } + else + { + gdk_window_move_resize (priv->handle, + priv->handle_pos.x, + priv->handle_pos.y - margin.top, + priv->handle_pos.width, + handle_size + margin.top + margin.bottom); + } + } + + /* Now allocate the childen, making sure, when resizing not to + * overlap the windows + */ + gtk_widget_get_allocation (priv->child1, &priv_child1_allocation); + if (gtk_widget_get_mapped (widget) && + ((priv->orientation == GTK_ORIENTATION_HORIZONTAL && + priv_child1_allocation.width < child1_allocation.width) || + + (priv->orientation == GTK_ORIENTATION_VERTICAL && + priv_child1_allocation.height < child1_allocation.height))) + { + gtk_paned_child_allocate (priv->child2, + priv->child2_window, + &window2_allocation, + &child2_allocation); + gtk_paned_child_allocate (priv->child1, + priv->child1_window, + &window1_allocation, + &child1_allocation); + } + else + { + gtk_paned_child_allocate (priv->child1, + priv->child1_window, + &window1_allocation, + &child1_allocation); + gtk_paned_child_allocate (priv->child2, + priv->child2_window, + &window2_allocation, + &child2_allocation); + } + } + else + { + GtkAllocation window_allocation, child_allocation; + + if (gtk_widget_get_realized (widget)) + gdk_window_hide (priv->handle); + + window_allocation.x = allocation->x; + window_allocation.y = allocation->y; + window_allocation.width = allocation->width; + window_allocation.height = allocation->height; + child_allocation.x = child_allocation.y = 0; + child_allocation.width = allocation->width; + child_allocation.height = allocation->height; + + if (priv->child1 && gtk_widget_get_visible (priv->child1)) + { + gtk_paned_set_child_visible (paned, 0, TRUE); + if (priv->child2) + gtk_paned_set_child_visible (paned, 1, FALSE); + + gtk_paned_child_allocate (priv->child1, + priv->child1_window, + &window_allocation, + &child_allocation); + } + else if (priv->child2 && gtk_widget_get_visible (priv->child2)) + { + gtk_paned_set_child_visible (paned, 1, TRUE); + if (priv->child1) + gtk_paned_set_child_visible (paned, 0, FALSE); + + gtk_paned_child_allocate (priv->child2, + priv->child2_window, + &window_allocation, + &child_allocation); + } + else + { + if (priv->child1) + gtk_paned_set_child_visible (paned, 0, FALSE); + if (priv->child2) + gtk_paned_set_child_visible (paned, 1, FALSE); + } + } +} + +static void +gtk_paned_calc_position (GtkPaned *paned, + gint allocation, + gint child1_width, + gint child1_nat_width, + gint child2_width, + gint child2_nat_width) +{ + GtkPanedPrivate *priv = paned->priv; + gint old_position; + gint old_min_position; + gint old_max_position; + + old_position = priv->child1_size; + old_min_position = priv->min_position; + old_max_position = priv->max_position; + + gtk_paned_compute_position (paned, + allocation, child1_width, child1_nat_width, child2_width, child2_nat_width, + &priv->min_position, &priv->max_position, + &priv->child1_size); + + if (priv->child1) + gtk_paned_set_child_visible (paned, 0, priv->child1_size != 0); + + if (priv->child2) + gtk_paned_set_child_visible (paned, 1, priv->child1_size != allocation); + + g_object_freeze_notify (G_OBJECT (paned)); + if (priv->child1_size != old_position) + g_object_notify (G_OBJECT (paned), "position"); + if (priv->min_position != old_min_position) + g_object_notify (G_OBJECT (paned), "min-position"); + if (priv->max_position != old_max_position) + g_object_notify (G_OBJECT (paned), "max-position"); + g_object_thaw_notify (G_OBJECT (paned)); + + priv->last_allocation = allocation; +} diff --git a/src/gtk/gtkpanedview.c b/src/gtk/gtkpanedview-3.6.0.c similarity index 100% rename from src/gtk/gtkpanedview.c rename to src/gtk/gtkpanedview-3.6.0.c diff --git a/src/gtk/gtkscrolledview-3.16.7.c b/src/gtk/gtkscrolledview-3.16.7.c new file mode 100644 index 000000000..58b694a6d --- /dev/null +++ b/src/gtk/gtkscrolledview-3.16.7.c @@ -0,0 +1,329 @@ +/* -*-C-*- + +Copyright (C) 2012, 2013, 2015 Matthew Birkholz + +This file is part of MIT/GNU Scheme. + +MIT/GNU Scheme 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. + +MIT/GNU Scheme 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 MIT/GNU Scheme; 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 + . */ + +#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; +} + +/* The following definitions were copied unchanged from + gtkscrolledwindow.c v3.16.7 unless otherwise noted. + + struct Indicator + struct _GtkScrolledWindowPrivate + 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 +{ + 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; + gint64 start_time; + gint64 end_time; + guint tick_id; + guint over_timeout_id; +} Indicator; + +struct _GtkScrolledWindowPrivate +{ + GtkWidget *hscrollbar; + GtkWidget *vscrollbar; + + 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; + + gint min_content_width; + gint min_content_height; + + guint scroll_events_overshoot_id; + + /* Kinetic scrolling */ + GtkGesture *long_press_gesture; + GtkGesture *swipe_gesture; + + /* 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); +} diff --git a/src/gtk/gtkscrolledview.c b/src/gtk/gtkscrolledview-3.6.0.c similarity index 100% rename from src/gtk/gtkscrolledview.c rename to src/gtk/gtkscrolledview-3.6.0.c -- 2.25.1