Unlike other container widgets, GtkStack would allocate its children prior to moving its windows, which might prevent further valid size allocation signals to be emitted. Re-order the size allocation of child widgets to be performed after moving the GtkStack windows. Thanks to Owen for spotting the real issue here. https://bugzilla.gnome.org/show_bug.cgi?id=767713
		
			
				
	
	
		
			2454 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2454 lines
		
	
	
		
			79 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2013 Red Hat, Inc.
 | 
						|
 *
 | 
						|
 * This program is free software; you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU Lesser General Public License as published by
 | 
						|
 * the Free Software Foundation; either version 2 of the License, or (at your
 | 
						|
 * option) any later version.
 | 
						|
 *
 | 
						|
 * This program 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 Lesser General Public
 | 
						|
 * License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Lesser General Public License
 | 
						|
 * along with this program; if not, write to the Free Software Foundation,
 | 
						|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 | 
						|
 *
 | 
						|
 * Author: Alexander Larsson <alexl@redhat.com>
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "config.h"
 | 
						|
 | 
						|
#include <gtk/gtk.h>
 | 
						|
#include "gtkstack.h"
 | 
						|
#include "gtkprivate.h"
 | 
						|
#include "gtkintl.h"
 | 
						|
#include "gtkcsscustomgadgetprivate.h"
 | 
						|
#include "gtkcontainerprivate.h"
 | 
						|
#include "gtkprogresstrackerprivate.h"
 | 
						|
#include "gtksettingsprivate.h"
 | 
						|
#include "gtkwidgetprivate.h"
 | 
						|
#include "a11y/gtkstackaccessible.h"
 | 
						|
#include "a11y/gtkstackaccessibleprivate.h"
 | 
						|
#include <math.h>
 | 
						|
#include <string.h>
 | 
						|
 | 
						|
/**
 | 
						|
 * SECTION:gtkstack
 | 
						|
 * @Short_description: A stacking container
 | 
						|
 * @Title: GtkStack
 | 
						|
 * @See_also: #GtkNotebook, #GtkStackSwitcher
 | 
						|
 *
 | 
						|
 * The GtkStack widget is a container which only shows
 | 
						|
 * one of its children at a time. In contrast to GtkNotebook,
 | 
						|
 * GtkStack does not provide a means for users to change the
 | 
						|
 * visible child. Instead, the #GtkStackSwitcher widget can be
 | 
						|
 * used with GtkStack to provide this functionality.
 | 
						|
 *
 | 
						|
 * Transitions between pages can be animated as slides or
 | 
						|
 * fades. This can be controlled with gtk_stack_set_transition_type().
 | 
						|
 * These animations respect the #GtkSettings:gtk-enable-animations
 | 
						|
 * setting.
 | 
						|
 *
 | 
						|
 * The GtkStack widget was added in GTK+ 3.10.
 | 
						|
 *
 | 
						|
 * # CSS nodes
 | 
						|
 *
 | 
						|
 * GtkStack has a single CSS node named stack.
 | 
						|
 */
 | 
						|
 | 
						|
/**
 | 
						|
 * GtkStackTransitionType:
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_NONE: No transition
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_CROSSFADE: A cross-fade
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT: Slide from left to right
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT: Slide from right to left
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_UP: Slide from bottom up
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN: Slide from top down
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT: Slide from left or right according to the children order
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN: Slide from top down or bottom up according to the order
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_UP: Cover the old page by sliding up. Since 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_DOWN: Cover the old page by sliding down. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_LEFT: Cover the old page by sliding to the left. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_RIGHT: Cover the old page by sliding to the right. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_UNDER_UP: Uncover the new page by sliding up. Since 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_UNDER_DOWN: Uncover the new page by sliding down. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_UNDER_LEFT: Uncover the new page by sliding to the left. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT: Uncover the new page by sliding to the right. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN: Cover the old page sliding up or uncover the new page sliding down, according to order. Since: 3.12
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP: Cover the old page sliding down or uncover the new page sliding up, according to order. Since: 3.14
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT: Cover the old page sliding left or uncover the new page sliding right, according to order. Since: 3.14
 | 
						|
 * @GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT: Cover the old page sliding right or uncover the new page sliding left, according to order. Since: 3.14
 | 
						|
 *
 | 
						|
 * These enumeration values describe the possible transitions
 | 
						|
 * between pages in a #GtkStack widget.
 | 
						|
 *
 | 
						|
 * New values may be added to this enumeration over time.
 | 
						|
 */
 | 
						|
 | 
						|
/* TODO:
 | 
						|
 *  filter events out events to the last_child widget during transitions
 | 
						|
 */
 | 
						|
 | 
						|
enum  {
 | 
						|
  PROP_0,
 | 
						|
  PROP_HOMOGENEOUS,
 | 
						|
  PROP_HHOMOGENEOUS,
 | 
						|
  PROP_VHOMOGENEOUS,
 | 
						|
  PROP_VISIBLE_CHILD,
 | 
						|
  PROP_VISIBLE_CHILD_NAME,
 | 
						|
  PROP_TRANSITION_DURATION,
 | 
						|
  PROP_TRANSITION_TYPE,
 | 
						|
  PROP_TRANSITION_RUNNING,
 | 
						|
  PROP_INTERPOLATE_SIZE,
 | 
						|
  LAST_PROP
 | 
						|
};
 | 
						|
 | 
						|
enum
 | 
						|
{
 | 
						|
  CHILD_PROP_0,
 | 
						|
  CHILD_PROP_NAME,
 | 
						|
  CHILD_PROP_TITLE,
 | 
						|
  CHILD_PROP_ICON_NAME,
 | 
						|
  CHILD_PROP_POSITION,
 | 
						|
  CHILD_PROP_NEEDS_ATTENTION,
 | 
						|
  LAST_CHILD_PROP
 | 
						|
};
 | 
						|
 | 
						|
typedef struct _GtkStackChildInfo GtkStackChildInfo;
 | 
						|
 | 
						|
struct _GtkStackChildInfo {
 | 
						|
  GtkWidget *widget;
 | 
						|
  gchar *name;
 | 
						|
  gchar *title;
 | 
						|
  gchar *icon_name;
 | 
						|
  gboolean needs_attention;
 | 
						|
  GtkWidget *last_focus;
 | 
						|
};
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  GList *children;
 | 
						|
 | 
						|
  GdkWindow* bin_window;
 | 
						|
  GdkWindow* view_window;
 | 
						|
 | 
						|
  GtkStackChildInfo *visible_child;
 | 
						|
 | 
						|
  GtkCssGadget *gadget;
 | 
						|
 | 
						|
  gboolean hhomogeneous;
 | 
						|
  gboolean vhomogeneous;
 | 
						|
 | 
						|
  GtkStackTransitionType transition_type;
 | 
						|
  guint transition_duration;
 | 
						|
 | 
						|
  GtkStackChildInfo *last_visible_child;
 | 
						|
  cairo_surface_t *last_visible_surface;
 | 
						|
  GtkAllocation last_visible_surface_allocation;
 | 
						|
  guint tick_id;
 | 
						|
  GtkProgressTracker tracker;
 | 
						|
  gboolean first_frame_skipped;
 | 
						|
 | 
						|
  gint last_visible_widget_width;
 | 
						|
  gint last_visible_widget_height;
 | 
						|
 | 
						|
  gboolean interpolate_size;
 | 
						|
 | 
						|
  GtkStackTransitionType active_transition_type;
 | 
						|
 | 
						|
} GtkStackPrivate;
 | 
						|
 | 
						|
static GParamSpec *stack_props[LAST_PROP] = { NULL, };
 | 
						|
static GParamSpec *stack_child_props[LAST_CHILD_PROP] = { NULL, };
 | 
						|
 | 
						|
static void     gtk_stack_add                            (GtkContainer  *widget,
 | 
						|
                                                          GtkWidget     *child);
 | 
						|
static void     gtk_stack_remove                         (GtkContainer  *widget,
 | 
						|
                                                          GtkWidget     *child);
 | 
						|
static void     gtk_stack_forall                         (GtkContainer  *container,
 | 
						|
                                                          gboolean       include_internals,
 | 
						|
                                                          GtkCallback    callback,
 | 
						|
                                                          gpointer       callback_data);
 | 
						|
static void     gtk_stack_compute_expand                 (GtkWidget     *widget,
 | 
						|
                                                          gboolean      *hexpand,
 | 
						|
                                                          gboolean      *vexpand);
 | 
						|
static void     gtk_stack_size_allocate                  (GtkWidget     *widget,
 | 
						|
                                                          GtkAllocation *allocation);
 | 
						|
static gboolean gtk_stack_draw                           (GtkWidget     *widget,
 | 
						|
                                                          cairo_t       *cr);
 | 
						|
static void     gtk_stack_get_preferred_height           (GtkWidget     *widget,
 | 
						|
                                                          gint          *minimum_height,
 | 
						|
                                                          gint          *natural_height);
 | 
						|
static void     gtk_stack_get_preferred_height_for_width (GtkWidget     *widget,
 | 
						|
                                                          gint           width,
 | 
						|
                                                          gint          *minimum_height,
 | 
						|
                                                          gint          *natural_height);
 | 
						|
static void     gtk_stack_get_preferred_width            (GtkWidget     *widget,
 | 
						|
                                                          gint          *minimum_width,
 | 
						|
                                                          gint          *natural_width);
 | 
						|
static void     gtk_stack_get_preferred_width_for_height (GtkWidget     *widget,
 | 
						|
                                                          gint           height,
 | 
						|
                                                          gint          *minimum_width,
 | 
						|
                                                          gint          *natural_width);
 | 
						|
static void     gtk_stack_finalize                       (GObject       *obj);
 | 
						|
static void     gtk_stack_get_property                   (GObject       *object,
 | 
						|
                                                          guint          property_id,
 | 
						|
                                                          GValue        *value,
 | 
						|
                                                          GParamSpec    *pspec);
 | 
						|
static void     gtk_stack_set_property                   (GObject       *object,
 | 
						|
                                                          guint          property_id,
 | 
						|
                                                          const GValue  *value,
 | 
						|
                                                          GParamSpec    *pspec);
 | 
						|
static void     gtk_stack_get_child_property             (GtkContainer  *container,
 | 
						|
                                                          GtkWidget     *child,
 | 
						|
                                                          guint          property_id,
 | 
						|
                                                          GValue        *value,
 | 
						|
                                                          GParamSpec    *pspec);
 | 
						|
static void     gtk_stack_set_child_property             (GtkContainer  *container,
 | 
						|
                                                          GtkWidget     *child,
 | 
						|
                                                          guint          property_id,
 | 
						|
                                                          const GValue  *value,
 | 
						|
                                                          GParamSpec    *pspec);
 | 
						|
static void     gtk_stack_unschedule_ticks               (GtkStack      *stack);
 | 
						|
static gint     get_bin_window_x                         (GtkStack            *stack,
 | 
						|
                                                          const GtkAllocation *allocation);
 | 
						|
static gint     get_bin_window_y                         (GtkStack            *stack,
 | 
						|
                                                          const GtkAllocation *allocation);
 | 
						|
 | 
						|
G_DEFINE_TYPE_WITH_PRIVATE (GtkStack, gtk_stack, GTK_TYPE_CONTAINER)
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_dispose (GObject *obj)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (obj);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  priv->visible_child = NULL;
 | 
						|
 | 
						|
  G_OBJECT_CLASS (gtk_stack_parent_class)->dispose (obj);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_finalize (GObject *obj)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (obj);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_stack_unschedule_ticks (stack);
 | 
						|
 | 
						|
  if (priv->last_visible_surface != NULL)
 | 
						|
    cairo_surface_destroy (priv->last_visible_surface);
 | 
						|
 | 
						|
  g_clear_object (&priv->gadget);
 | 
						|
 | 
						|
  G_OBJECT_CLASS (gtk_stack_parent_class)->finalize (obj);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_property (GObject   *object,
 | 
						|
                        guint       property_id,
 | 
						|
                        GValue     *value,
 | 
						|
                        GParamSpec *pspec)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (object);
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case PROP_HOMOGENEOUS:
 | 
						|
      g_value_set_boolean (value, gtk_stack_get_homogeneous (stack));
 | 
						|
      break;
 | 
						|
    case PROP_HHOMOGENEOUS:
 | 
						|
      g_value_set_boolean (value, gtk_stack_get_hhomogeneous (stack));
 | 
						|
      break;
 | 
						|
    case PROP_VHOMOGENEOUS:
 | 
						|
      g_value_set_boolean (value, gtk_stack_get_vhomogeneous (stack));
 | 
						|
      break;
 | 
						|
    case PROP_VISIBLE_CHILD:
 | 
						|
      g_value_set_object (value, gtk_stack_get_visible_child (stack));
 | 
						|
      break;
 | 
						|
    case PROP_VISIBLE_CHILD_NAME:
 | 
						|
      g_value_set_string (value, gtk_stack_get_visible_child_name (stack));
 | 
						|
      break;
 | 
						|
    case PROP_TRANSITION_DURATION:
 | 
						|
      g_value_set_uint (value, gtk_stack_get_transition_duration (stack));
 | 
						|
      break;
 | 
						|
    case PROP_TRANSITION_TYPE:
 | 
						|
      g_value_set_enum (value, gtk_stack_get_transition_type (stack));
 | 
						|
      break;
 | 
						|
    case PROP_TRANSITION_RUNNING:
 | 
						|
      g_value_set_boolean (value, gtk_stack_get_transition_running (stack));
 | 
						|
      break;
 | 
						|
    case PROP_INTERPOLATE_SIZE:
 | 
						|
      g_value_set_boolean (value, gtk_stack_get_interpolate_size (stack));
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_set_property (GObject     *object,
 | 
						|
                        guint         property_id,
 | 
						|
                        const GValue *value,
 | 
						|
                        GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (object);
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case PROP_HOMOGENEOUS:
 | 
						|
      gtk_stack_set_homogeneous (stack, g_value_get_boolean (value));
 | 
						|
      break;
 | 
						|
    case PROP_HHOMOGENEOUS:
 | 
						|
      gtk_stack_set_hhomogeneous (stack, g_value_get_boolean (value));
 | 
						|
      break;
 | 
						|
    case PROP_VHOMOGENEOUS:
 | 
						|
      gtk_stack_set_vhomogeneous (stack, g_value_get_boolean (value));
 | 
						|
      break;
 | 
						|
    case PROP_VISIBLE_CHILD:
 | 
						|
      gtk_stack_set_visible_child (stack, g_value_get_object (value));
 | 
						|
      break;
 | 
						|
    case PROP_VISIBLE_CHILD_NAME:
 | 
						|
      gtk_stack_set_visible_child_name (stack, g_value_get_string (value));
 | 
						|
      break;
 | 
						|
    case PROP_TRANSITION_DURATION:
 | 
						|
      gtk_stack_set_transition_duration (stack, g_value_get_uint (value));
 | 
						|
      break;
 | 
						|
    case PROP_TRANSITION_TYPE:
 | 
						|
      gtk_stack_set_transition_type (stack, g_value_get_enum (value));
 | 
						|
      break;
 | 
						|
    case PROP_INTERPOLATE_SIZE:
 | 
						|
      gtk_stack_set_interpolate_size (stack, g_value_get_boolean (value));
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_realize (GtkWidget *widget)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkAllocation allocation;
 | 
						|
  GdkWindowAttr attributes = { 0 };
 | 
						|
  GdkWindowAttributesType attributes_mask;
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  gtk_widget_set_realized (widget, TRUE);
 | 
						|
  gtk_widget_set_window (widget, g_object_ref (gtk_widget_get_parent_window (widget)));
 | 
						|
 | 
						|
  gtk_css_gadget_get_content_allocation (priv->gadget, &allocation, NULL);
 | 
						|
 | 
						|
  attributes.x = allocation.x;
 | 
						|
  attributes.y = allocation.y;
 | 
						|
  attributes.width = allocation.width;
 | 
						|
  attributes.height = allocation.height;
 | 
						|
  attributes.window_type = GDK_WINDOW_CHILD;
 | 
						|
  attributes.wclass = GDK_INPUT_OUTPUT;
 | 
						|
  attributes.visual = gtk_widget_get_visual (widget);
 | 
						|
  attributes.event_mask =
 | 
						|
    gtk_widget_get_events (widget);
 | 
						|
  attributes_mask = (GDK_WA_X | GDK_WA_Y) | GDK_WA_VISUAL;
 | 
						|
 | 
						|
  priv->view_window =
 | 
						|
    gdk_window_new (gtk_widget_get_window (GTK_WIDGET (stack)),
 | 
						|
                    &attributes, attributes_mask);
 | 
						|
  gtk_widget_register_window (widget, priv->view_window);
 | 
						|
 | 
						|
  attributes.x = get_bin_window_x (stack, &allocation);
 | 
						|
  attributes.y = get_bin_window_y (stack, &allocation);
 | 
						|
  attributes.width = allocation.width;
 | 
						|
  attributes.height = allocation.height;
 | 
						|
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      info = l->data;
 | 
						|
      attributes.event_mask |= gtk_widget_get_events (info->widget);
 | 
						|
    }
 | 
						|
 | 
						|
  priv->bin_window =
 | 
						|
    gdk_window_new (priv->view_window, &attributes, attributes_mask);
 | 
						|
  gtk_widget_register_window (widget, priv->bin_window);
 | 
						|
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      info = l->data;
 | 
						|
 | 
						|
      gtk_widget_set_parent_window (info->widget, priv->bin_window);
 | 
						|
    }
 | 
						|
 | 
						|
  gdk_window_show (priv->bin_window);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_unrealize (GtkWidget *widget)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_widget_unregister_window (widget, priv->bin_window);
 | 
						|
  gdk_window_destroy (priv->bin_window);
 | 
						|
  priv->bin_window = NULL;
 | 
						|
  gtk_widget_unregister_window (widget, priv->view_window);
 | 
						|
  gdk_window_destroy (priv->view_window);
 | 
						|
  priv->view_window = NULL;
 | 
						|
 | 
						|
  GTK_WIDGET_CLASS (gtk_stack_parent_class)->unrealize (widget);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_map (GtkWidget *widget)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  GTK_WIDGET_CLASS (gtk_stack_parent_class)->map (widget);
 | 
						|
 | 
						|
  gdk_window_show (priv->view_window);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_unmap (GtkWidget *widget)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gdk_window_hide (priv->view_window);
 | 
						|
 | 
						|
  GTK_WIDGET_CLASS (gtk_stack_parent_class)->unmap (widget);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_class_init (GtkStackClass *klass)
 | 
						|
{
 | 
						|
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | 
						|
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 | 
						|
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
 | 
						|
 | 
						|
  object_class->get_property = gtk_stack_get_property;
 | 
						|
  object_class->set_property = gtk_stack_set_property;
 | 
						|
  object_class->dispose = gtk_stack_dispose;
 | 
						|
  object_class->finalize = gtk_stack_finalize;
 | 
						|
 | 
						|
  widget_class->size_allocate = gtk_stack_size_allocate;
 | 
						|
  widget_class->draw = gtk_stack_draw;
 | 
						|
  widget_class->realize = gtk_stack_realize;
 | 
						|
  widget_class->unrealize = gtk_stack_unrealize;
 | 
						|
  widget_class->map = gtk_stack_map;
 | 
						|
  widget_class->unmap = gtk_stack_unmap;
 | 
						|
  widget_class->get_preferred_height = gtk_stack_get_preferred_height;
 | 
						|
  widget_class->get_preferred_height_for_width = gtk_stack_get_preferred_height_for_width;
 | 
						|
  widget_class->get_preferred_width = gtk_stack_get_preferred_width;
 | 
						|
  widget_class->get_preferred_width_for_height = gtk_stack_get_preferred_width_for_height;
 | 
						|
  widget_class->compute_expand = gtk_stack_compute_expand;
 | 
						|
 | 
						|
  container_class->add = gtk_stack_add;
 | 
						|
  container_class->remove = gtk_stack_remove;
 | 
						|
  container_class->forall = gtk_stack_forall;
 | 
						|
  container_class->set_child_property = gtk_stack_set_child_property;
 | 
						|
  container_class->get_child_property = gtk_stack_get_child_property;
 | 
						|
  gtk_container_class_handle_border_width (container_class);
 | 
						|
 | 
						|
  stack_props[PROP_HOMOGENEOUS] =
 | 
						|
      g_param_spec_boolean ("homogeneous", P_("Homogeneous"), P_("Homogeneous sizing"),
 | 
						|
                            TRUE,
 | 
						|
                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
 | 
						|
  /**
 | 
						|
   * GtkStack:hhomogeneous:
 | 
						|
   *
 | 
						|
   * %TRUE if the stack allocates the same width for all children.
 | 
						|
   *
 | 
						|
   * Since: 3.16
 | 
						|
   */
 | 
						|
  stack_props[PROP_HHOMOGENEOUS] =
 | 
						|
      g_param_spec_boolean ("hhomogeneous", P_("Horizontally homogeneous"), P_("Horizontally homogeneous sizing"),
 | 
						|
                            TRUE,
 | 
						|
                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
 | 
						|
  /**
 | 
						|
   * GtkStack:vhomogeneous:
 | 
						|
   *
 | 
						|
   * %TRUE if the stack allocates the same height for all children.
 | 
						|
   *
 | 
						|
   * Since: 3.16
 | 
						|
   */
 | 
						|
  stack_props[PROP_VHOMOGENEOUS] =
 | 
						|
      g_param_spec_boolean ("vhomogeneous", P_("Vertically homogeneous"), P_("Vertically homogeneous sizing"),
 | 
						|
                            TRUE,
 | 
						|
                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
  stack_props[PROP_VISIBLE_CHILD] =
 | 
						|
      g_param_spec_object ("visible-child", P_("Visible child"), P_("The widget currently visible in the stack"),
 | 
						|
                           GTK_TYPE_WIDGET,
 | 
						|
                           GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
  stack_props[PROP_VISIBLE_CHILD_NAME] =
 | 
						|
      g_param_spec_string ("visible-child-name", P_("Name of visible child"), P_("The name of the widget currently visible in the stack"),
 | 
						|
                           NULL,
 | 
						|
                           GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
  stack_props[PROP_TRANSITION_DURATION] =
 | 
						|
      g_param_spec_uint ("transition-duration", P_("Transition duration"), P_("The animation duration, in milliseconds"),
 | 
						|
                         0, G_MAXUINT, 200,
 | 
						|
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
  stack_props[PROP_TRANSITION_TYPE] =
 | 
						|
      g_param_spec_enum ("transition-type", P_("Transition type"), P_("The type of animation used to transition"),
 | 
						|
                         GTK_TYPE_STACK_TRANSITION_TYPE, GTK_STACK_TRANSITION_TYPE_NONE,
 | 
						|
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
  stack_props[PROP_TRANSITION_RUNNING] =
 | 
						|
      g_param_spec_boolean ("transition-running", P_("Transition running"), P_("Whether or not the transition is currently running"),
 | 
						|
                            FALSE,
 | 
						|
                            GTK_PARAM_READABLE);
 | 
						|
  stack_props[PROP_INTERPOLATE_SIZE] =
 | 
						|
      g_param_spec_boolean ("interpolate-size", P_("Interpolate size"), P_("Whether or not the size should smoothly change when changing between differently sized children"),
 | 
						|
                            FALSE,
 | 
						|
                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 | 
						|
 | 
						|
 | 
						|
  g_object_class_install_properties (object_class, LAST_PROP, stack_props);
 | 
						|
 | 
						|
  stack_child_props[CHILD_PROP_NAME] =
 | 
						|
    g_param_spec_string ("name",
 | 
						|
                         P_("Name"),
 | 
						|
                         P_("The name of the child page"),
 | 
						|
                         NULL,
 | 
						|
                         GTK_PARAM_READWRITE);
 | 
						|
 | 
						|
  stack_child_props[CHILD_PROP_TITLE] =
 | 
						|
    g_param_spec_string ("title",
 | 
						|
                         P_("Title"),
 | 
						|
                         P_("The title of the child page"),
 | 
						|
                         NULL,
 | 
						|
                         GTK_PARAM_READWRITE);
 | 
						|
 | 
						|
  stack_child_props[CHILD_PROP_ICON_NAME] =
 | 
						|
    g_param_spec_string ("icon-name",
 | 
						|
                         P_("Icon name"),
 | 
						|
                         P_("The icon name of the child page"),
 | 
						|
                         NULL,
 | 
						|
                         GTK_PARAM_READWRITE);
 | 
						|
 | 
						|
  stack_child_props[CHILD_PROP_POSITION] =
 | 
						|
    g_param_spec_int ("position",
 | 
						|
                      P_("Position"),
 | 
						|
                      P_("The index of the child in the parent"),
 | 
						|
                      -1, G_MAXINT,
 | 
						|
                      0,
 | 
						|
                      GTK_PARAM_READWRITE);
 | 
						|
 | 
						|
  /**
 | 
						|
   * GtkStack:needs-attention:
 | 
						|
   *
 | 
						|
   * Sets a flag specifying whether the child requires the user attention.
 | 
						|
   * This is used by the #GtkStackSwitcher to change the appearance of the
 | 
						|
   * corresponding button when a page needs attention and it is not the
 | 
						|
   * current one.
 | 
						|
   *
 | 
						|
   * Since: 3.12
 | 
						|
   */
 | 
						|
  stack_child_props[CHILD_PROP_NEEDS_ATTENTION] =
 | 
						|
    g_param_spec_boolean ("needs-attention",
 | 
						|
                         P_("Needs Attention"),
 | 
						|
                         P_("Whether this page needs attention"),
 | 
						|
                         FALSE,
 | 
						|
                         GTK_PARAM_READWRITE);
 | 
						|
 | 
						|
  gtk_container_class_install_child_properties (container_class, LAST_CHILD_PROP, stack_child_props);
 | 
						|
 | 
						|
  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_STACK_ACCESSIBLE);
 | 
						|
  gtk_widget_class_set_css_name (widget_class, "stack");
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_new:
 | 
						|
 *
 | 
						|
 * Creates a new #GtkStack container.
 | 
						|
 *
 | 
						|
 * Returns: a new #GtkStack
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
GtkWidget *
 | 
						|
gtk_stack_new (void)
 | 
						|
{
 | 
						|
  return g_object_new (GTK_TYPE_STACK, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static GtkStackChildInfo *
 | 
						|
find_child_info_for_widget (GtkStack  *stack,
 | 
						|
                            GtkWidget *child)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      info = l->data;
 | 
						|
      if (info->widget == child)
 | 
						|
        return info;
 | 
						|
    }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
reorder_child (GtkStack  *stack,
 | 
						|
               GtkWidget *child,
 | 
						|
               gint       position)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GList *l;
 | 
						|
  GList *old_link = NULL;
 | 
						|
  GList *new_link = NULL;
 | 
						|
  GtkStackChildInfo *child_info = NULL;
 | 
						|
  gint num = 0;
 | 
						|
 | 
						|
  l = priv->children;
 | 
						|
 | 
						|
  /* Loop to find the old position and link of child, new link of child and
 | 
						|
   * total number of children. new_link will be NULL if the child should be
 | 
						|
   * moved to the end (in case of position being < 0 || >= num)
 | 
						|
   */
 | 
						|
  while (l && (new_link == NULL || old_link == NULL))
 | 
						|
    {
 | 
						|
      /* Record the new position if found */
 | 
						|
      if (position == num)
 | 
						|
        new_link = l;
 | 
						|
 | 
						|
      if (old_link == NULL)
 | 
						|
        {
 | 
						|
          GtkStackChildInfo *info;
 | 
						|
          info = l->data;
 | 
						|
 | 
						|
          /* Keep trying to find the current position and link location of the child */
 | 
						|
          if (info->widget == child)
 | 
						|
            {
 | 
						|
              old_link = l;
 | 
						|
              child_info = info;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
      l = l->next;
 | 
						|
      num++;
 | 
						|
    }
 | 
						|
 | 
						|
  g_return_if_fail (old_link != NULL);
 | 
						|
 | 
						|
  if (old_link == new_link || (old_link->next == NULL && new_link == NULL))
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->children = g_list_delete_link (priv->children, old_link);
 | 
						|
  priv->children = g_list_insert_before (priv->children, new_link, child_info);
 | 
						|
 | 
						|
  gtk_container_child_notify_by_pspec (GTK_CONTAINER (stack), child, stack_child_props[CHILD_PROP_POSITION]);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_child_property (GtkContainer *container,
 | 
						|
                              GtkWidget    *child,
 | 
						|
                              guint         property_id,
 | 
						|
                              GValue       *value,
 | 
						|
                              GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (container);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
 | 
						|
  info = find_child_info_for_widget (stack, child);
 | 
						|
  if (info == NULL)
 | 
						|
    {
 | 
						|
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case CHILD_PROP_NAME:
 | 
						|
      g_value_set_string (value, info->name);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_TITLE:
 | 
						|
      g_value_set_string (value, info->title);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_ICON_NAME:
 | 
						|
      g_value_set_string (value, info->icon_name);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_POSITION:
 | 
						|
      g_value_set_int (value, g_list_index (priv->children, info));
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_NEEDS_ATTENTION:
 | 
						|
      g_value_set_boolean (value, info->needs_attention);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_set_child_property (GtkContainer *container,
 | 
						|
                              GtkWidget    *child,
 | 
						|
                              guint         property_id,
 | 
						|
                              const GValue *value,
 | 
						|
                              GParamSpec   *pspec)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (container);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
  GtkStackChildInfo *info2;
 | 
						|
  gchar *name;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  info = find_child_info_for_widget (stack, child);
 | 
						|
  if (info == NULL)
 | 
						|
    {
 | 
						|
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  switch (property_id)
 | 
						|
    {
 | 
						|
    case CHILD_PROP_NAME:
 | 
						|
      name = g_value_dup_string (value);
 | 
						|
      for (l = priv->children; l != NULL; l = l->next)
 | 
						|
        {
 | 
						|
          info2 = l->data;
 | 
						|
          if (info == info2)
 | 
						|
            continue;
 | 
						|
          if (g_strcmp0 (info2->name, name) == 0)
 | 
						|
            {
 | 
						|
              g_warning ("Duplicate child name in GtkStack: %s", name);
 | 
						|
              break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
      g_free (info->name);
 | 
						|
      info->name = name;
 | 
						|
 | 
						|
      gtk_container_child_notify_by_pspec (container, child, pspec);
 | 
						|
 | 
						|
      if (priv->visible_child == info)
 | 
						|
        g_object_notify_by_pspec (G_OBJECT (stack),
 | 
						|
                                  stack_props[PROP_VISIBLE_CHILD_NAME]);
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_TITLE:
 | 
						|
      g_free (info->title);
 | 
						|
      info->title = g_value_dup_string (value);
 | 
						|
      gtk_container_child_notify_by_pspec (container, child, pspec);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_ICON_NAME:
 | 
						|
      g_free (info->icon_name);
 | 
						|
      info->icon_name = g_value_dup_string (value);
 | 
						|
      gtk_container_child_notify_by_pspec (container, child, pspec);
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_POSITION:
 | 
						|
      reorder_child (stack, child, g_value_get_int (value));
 | 
						|
      break;
 | 
						|
 | 
						|
    case CHILD_PROP_NEEDS_ATTENTION:
 | 
						|
      info->needs_attention = g_value_get_boolean (value);
 | 
						|
      gtk_container_child_notify_by_pspec (container, child, pspec);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
is_left_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_LEFT);
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
is_right_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_RIGHT);
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
is_up_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_UP ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_UP);
 | 
						|
}
 | 
						|
 | 
						|
static inline gboolean
 | 
						|
is_down_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_DOWN);
 | 
						|
}
 | 
						|
 | 
						|
/* Transitions that cause the bin window to move */
 | 
						|
static inline gboolean
 | 
						|
is_window_moving_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_UP ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_UP ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_DOWN ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_LEFT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_RIGHT);
 | 
						|
}
 | 
						|
 | 
						|
/* Transitions that change direction depending on the relative order of the
 | 
						|
old and new child */
 | 
						|
static inline gboolean
 | 
						|
is_direction_dependent_transition (GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  return (transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT ||
 | 
						|
          transition_type == GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT);
 | 
						|
}
 | 
						|
 | 
						|
/* Returns simple transition type for a direction dependent transition, given
 | 
						|
whether the new child (the one being switched to) is first in the stacking order
 | 
						|
(added earlier). */
 | 
						|
static inline GtkStackTransitionType
 | 
						|
get_simple_transition_type (gboolean               new_child_first,
 | 
						|
                            GtkStackTransitionType transition_type)
 | 
						|
{
 | 
						|
  switch (transition_type)
 | 
						|
    {
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT : GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN : GTK_STACK_TRANSITION_TYPE_SLIDE_UP;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_DOWN : GTK_STACK_TRANSITION_TYPE_OVER_UP;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_UP : GTK_STACK_TRANSITION_TYPE_OVER_DOWN;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT : GTK_STACK_TRANSITION_TYPE_OVER_LEFT;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT:
 | 
						|
      return new_child_first ? GTK_STACK_TRANSITION_TYPE_UNDER_LEFT : GTK_STACK_TRANSITION_TYPE_OVER_RIGHT;
 | 
						|
    default: ;
 | 
						|
    }
 | 
						|
  return transition_type;
 | 
						|
}
 | 
						|
 | 
						|
static gint
 | 
						|
get_bin_window_x (GtkStack            *stack,
 | 
						|
                  const GtkAllocation *allocation)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  int x = 0;
 | 
						|
 | 
						|
  if (gtk_progress_tracker_get_state (&priv->tracker) != GTK_PROGRESS_STATE_AFTER)
 | 
						|
    {
 | 
						|
      if (is_left_transition (priv->active_transition_type))
 | 
						|
        x = allocation->width * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      if (is_right_transition (priv->active_transition_type))
 | 
						|
        x = -allocation->width * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
    }
 | 
						|
 | 
						|
  return x;
 | 
						|
}
 | 
						|
 | 
						|
static gint
 | 
						|
get_bin_window_y (GtkStack            *stack,
 | 
						|
                  const GtkAllocation *allocation)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  int y = 0;
 | 
						|
 | 
						|
  if (gtk_progress_tracker_get_state (&priv->tracker) != GTK_PROGRESS_STATE_AFTER)
 | 
						|
    {
 | 
						|
      if (is_up_transition (priv->active_transition_type))
 | 
						|
        y = allocation->height * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      if (is_down_transition(priv->active_transition_type))
 | 
						|
        y = -allocation->height * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
    }
 | 
						|
 | 
						|
  return y;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_progress_updated (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_widget_queue_draw (GTK_WIDGET (stack));
 | 
						|
 | 
						|
  if (!priv->vhomogeneous || !priv->hhomogeneous)
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
 | 
						|
  if (priv->bin_window != NULL &&
 | 
						|
      is_window_moving_transition (priv->active_transition_type))
 | 
						|
    {
 | 
						|
      GtkAllocation allocation;
 | 
						|
      gtk_widget_get_allocation (GTK_WIDGET (stack), &allocation);
 | 
						|
      gdk_window_move (priv->bin_window,
 | 
						|
                       get_bin_window_x (stack, &allocation), get_bin_window_y (stack, &allocation));
 | 
						|
    }
 | 
						|
 | 
						|
  if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
 | 
						|
    {
 | 
						|
      if (priv->last_visible_surface != NULL)
 | 
						|
        {
 | 
						|
          cairo_surface_destroy (priv->last_visible_surface);
 | 
						|
          priv->last_visible_surface = NULL;
 | 
						|
        }
 | 
						|
 | 
						|
      if (priv->last_visible_child != NULL)
 | 
						|
        {
 | 
						|
          gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE);
 | 
						|
          priv->last_visible_child = NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
gtk_stack_transition_cb (GtkWidget     *widget,
 | 
						|
                         GdkFrameClock *frame_clock,
 | 
						|
                         gpointer       user_data)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  if (priv->first_frame_skipped)
 | 
						|
    gtk_progress_tracker_advance_frame (&priv->tracker,
 | 
						|
                                        gdk_frame_clock_get_frame_time (frame_clock));
 | 
						|
  else
 | 
						|
    priv->first_frame_skipped = TRUE;
 | 
						|
 | 
						|
  /* Finish animation early if not mapped anymore */
 | 
						|
  if (!gtk_widget_get_mapped (widget))
 | 
						|
    gtk_progress_tracker_finish (&priv->tracker);
 | 
						|
 | 
						|
  gtk_stack_progress_updated (GTK_STACK (widget));
 | 
						|
 | 
						|
  if (gtk_progress_tracker_get_state (&priv->tracker) == GTK_PROGRESS_STATE_AFTER)
 | 
						|
    {
 | 
						|
      priv->tick_id = 0;
 | 
						|
      g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_TRANSITION_RUNNING]);
 | 
						|
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_schedule_ticks (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  if (priv->tick_id == 0)
 | 
						|
    {
 | 
						|
      priv->tick_id =
 | 
						|
        gtk_widget_add_tick_callback (GTK_WIDGET (stack), gtk_stack_transition_cb, stack, NULL);
 | 
						|
      g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_TRANSITION_RUNNING]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_unschedule_ticks (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  if (priv->tick_id != 0)
 | 
						|
    {
 | 
						|
      gtk_widget_remove_tick_callback (GTK_WIDGET (stack), priv->tick_id);
 | 
						|
      priv->tick_id = 0;
 | 
						|
      g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_TRANSITION_RUNNING]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static GtkStackTransitionType
 | 
						|
effective_transition_type (GtkStack               *stack,
 | 
						|
                           GtkStackTransitionType  transition_type)
 | 
						|
{
 | 
						|
  if (gtk_widget_get_direction (GTK_WIDGET (stack)) == GTK_TEXT_DIR_RTL)
 | 
						|
    {
 | 
						|
      switch (transition_type)
 | 
						|
        {
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_LEFT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_OVER_RIGHT;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_OVER_LEFT;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
 | 
						|
          return GTK_STACK_TRANSITION_TYPE_UNDER_LEFT;
 | 
						|
        default: ;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  return transition_type;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_start_transition (GtkStack               *stack,
 | 
						|
                            GtkStackTransitionType  transition_type,
 | 
						|
                            guint                   transition_duration)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkWidget *widget = GTK_WIDGET (stack);
 | 
						|
 | 
						|
  if (gtk_widget_get_mapped (widget) &&
 | 
						|
      gtk_settings_get_enable_animations (gtk_widget_get_settings (widget)) &&
 | 
						|
      transition_type != GTK_STACK_TRANSITION_TYPE_NONE &&
 | 
						|
      transition_duration != 0 &&
 | 
						|
      priv->last_visible_child != NULL)
 | 
						|
    {
 | 
						|
      priv->active_transition_type = effective_transition_type (stack, transition_type);
 | 
						|
      priv->first_frame_skipped = FALSE;
 | 
						|
      gtk_stack_schedule_ticks (stack);
 | 
						|
      gtk_progress_tracker_start (&priv->tracker,
 | 
						|
                                  priv->transition_duration * 1000,
 | 
						|
                                  0,
 | 
						|
                                  1.0);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      gtk_stack_unschedule_ticks (stack);
 | 
						|
      priv->active_transition_type = GTK_STACK_TRANSITION_TYPE_NONE;
 | 
						|
      gtk_progress_tracker_finish (&priv->tracker);
 | 
						|
    }
 | 
						|
 | 
						|
  gtk_stack_progress_updated (GTK_STACK (widget));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
set_visible_child (GtkStack               *stack,
 | 
						|
                   GtkStackChildInfo      *child_info,
 | 
						|
                   GtkStackTransitionType  transition_type,
 | 
						|
                   guint                   transition_duration)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
  GtkWidget *widget = GTK_WIDGET (stack);
 | 
						|
  GList *l;
 | 
						|
  GtkWidget *toplevel;
 | 
						|
  GtkWidget *focus;
 | 
						|
  gboolean contains_focus = FALSE;
 | 
						|
 | 
						|
  /* if we are being destroyed, do not bother with transitions
 | 
						|
   * and notifications
 | 
						|
   */
 | 
						|
  if (gtk_widget_in_destruction (widget))
 | 
						|
    return;
 | 
						|
 | 
						|
  /* If none, pick first visible */
 | 
						|
  if (child_info == NULL)
 | 
						|
    {
 | 
						|
      for (l = priv->children; l != NULL; l = l->next)
 | 
						|
        {
 | 
						|
          info = l->data;
 | 
						|
          if (gtk_widget_get_visible (info->widget))
 | 
						|
            {
 | 
						|
              child_info = info;
 | 
						|
              break;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (child_info == priv->visible_child)
 | 
						|
    return;
 | 
						|
 | 
						|
  toplevel = gtk_widget_get_toplevel (widget);
 | 
						|
  if (GTK_IS_WINDOW (toplevel))
 | 
						|
    {
 | 
						|
      focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
 | 
						|
      if (focus &&
 | 
						|
          priv->visible_child &&
 | 
						|
          priv->visible_child->widget &&
 | 
						|
          gtk_widget_is_ancestor (focus, priv->visible_child->widget))
 | 
						|
        {
 | 
						|
          contains_focus = TRUE;
 | 
						|
 | 
						|
          if (priv->visible_child->last_focus)
 | 
						|
            g_object_remove_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
 | 
						|
                                          (gpointer *)&priv->visible_child->last_focus);
 | 
						|
          priv->visible_child->last_focus = focus;
 | 
						|
          g_object_add_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
 | 
						|
                                     (gpointer *)&priv->visible_child->last_focus);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->last_visible_child)
 | 
						|
    gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE);
 | 
						|
  priv->last_visible_child = NULL;
 | 
						|
 | 
						|
  if (priv->last_visible_surface != NULL)
 | 
						|
    cairo_surface_destroy (priv->last_visible_surface);
 | 
						|
  priv->last_visible_surface = NULL;
 | 
						|
 | 
						|
  if (priv->visible_child && priv->visible_child->widget)
 | 
						|
    {
 | 
						|
      if (gtk_widget_is_visible (widget))
 | 
						|
        {
 | 
						|
          GtkAllocation allocation;
 | 
						|
 | 
						|
          priv->last_visible_child = priv->visible_child;
 | 
						|
          gtk_widget_get_allocated_size (priv->last_visible_child->widget, &allocation, NULL);
 | 
						|
          priv->last_visible_widget_width = allocation.width;
 | 
						|
          priv->last_visible_widget_height = allocation.height;
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          gtk_widget_set_child_visible (priv->visible_child->widget, FALSE);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  gtk_stack_accessible_update_visible_child (stack,
 | 
						|
                                             priv->visible_child ? priv->visible_child->widget : NULL,
 | 
						|
                                             child_info ? child_info->widget : NULL);
 | 
						|
 | 
						|
  priv->visible_child = child_info;
 | 
						|
 | 
						|
  if (child_info)
 | 
						|
    {
 | 
						|
      gtk_widget_set_child_visible (child_info->widget, TRUE);
 | 
						|
 | 
						|
      if (contains_focus)
 | 
						|
        {
 | 
						|
          if (child_info->last_focus)
 | 
						|
            gtk_widget_grab_focus (child_info->last_focus);
 | 
						|
          else
 | 
						|
            gtk_widget_child_focus (child_info->widget, GTK_DIR_TAB_FORWARD);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if ((child_info == NULL || priv->last_visible_child == NULL) &&
 | 
						|
      is_direction_dependent_transition (transition_type))
 | 
						|
    {
 | 
						|
      transition_type = GTK_STACK_TRANSITION_TYPE_NONE;
 | 
						|
    }
 | 
						|
  else if (is_direction_dependent_transition (transition_type))
 | 
						|
    {
 | 
						|
      gboolean i_first = FALSE;
 | 
						|
      for (l = priv->children; l != NULL; l = l->next)
 | 
						|
        {
 | 
						|
	  if (child_info == l->data)
 | 
						|
	    {
 | 
						|
	      i_first = TRUE;
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  if (priv->last_visible_child == l->data)
 | 
						|
	    break;
 | 
						|
        }
 | 
						|
 | 
						|
      transition_type = get_simple_transition_type (i_first, transition_type);
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->hhomogeneous && priv->vhomogeneous)
 | 
						|
    gtk_widget_queue_allocate (widget);
 | 
						|
  else
 | 
						|
    gtk_widget_queue_resize (widget);
 | 
						|
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_VISIBLE_CHILD]);
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack),
 | 
						|
                            stack_props[PROP_VISIBLE_CHILD_NAME]);
 | 
						|
 | 
						|
  gtk_stack_start_transition (stack, transition_type, transition_duration);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
stack_child_visibility_notify_cb (GObject    *obj,
 | 
						|
                                  GParamSpec *pspec,
 | 
						|
                                  gpointer    user_data)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (user_data);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkWidget *child = GTK_WIDGET (obj);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
 | 
						|
  child_info = find_child_info_for_widget (stack, child);
 | 
						|
 | 
						|
  if (priv->visible_child == NULL &&
 | 
						|
      gtk_widget_get_visible (child))
 | 
						|
    set_visible_child (stack, child_info, priv->transition_type, priv->transition_duration);
 | 
						|
  else if (priv->visible_child == child_info &&
 | 
						|
           !gtk_widget_get_visible (child))
 | 
						|
    set_visible_child (stack, NULL, priv->transition_type, priv->transition_duration);
 | 
						|
 | 
						|
  if (child_info == priv->last_visible_child)
 | 
						|
    {
 | 
						|
      gtk_widget_set_child_visible (priv->last_visible_child->widget, FALSE);
 | 
						|
      priv->last_visible_child = NULL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_add_titled:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @child: the widget to add
 | 
						|
 * @name: the name for @child
 | 
						|
 * @title: a human-readable title for @child
 | 
						|
 *
 | 
						|
 * Adds a child to @stack.
 | 
						|
 * The child is identified by the @name. The @title
 | 
						|
 * will be used by #GtkStackSwitcher to represent
 | 
						|
 * @child in a tab bar, so it should be short.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_add_titled (GtkStack   *stack,
 | 
						|
                     GtkWidget   *child,
 | 
						|
                     const gchar *name,
 | 
						|
                     const gchar *title)
 | 
						|
{
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
  g_return_if_fail (GTK_IS_WIDGET (child));
 | 
						|
 | 
						|
  gtk_container_add_with_properties (GTK_CONTAINER (stack),
 | 
						|
                                     child,
 | 
						|
                                     "name", name,
 | 
						|
                                     "title", title,
 | 
						|
                                     NULL);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_add_named:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @child: the widget to add
 | 
						|
 * @name: the name for @child
 | 
						|
 *
 | 
						|
 * Adds a child to @stack.
 | 
						|
 * The child is identified by the @name.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_add_named (GtkStack   *stack,
 | 
						|
                    GtkWidget   *child,
 | 
						|
                    const gchar *name)
 | 
						|
{
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
  g_return_if_fail (GTK_IS_WIDGET (child));
 | 
						|
 | 
						|
  gtk_container_add_with_properties (GTK_CONTAINER (stack),
 | 
						|
                                     child,
 | 
						|
                                     "name", name,
 | 
						|
                                     NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_add (GtkContainer *container,
 | 
						|
               GtkWidget    *child)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (container);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
 | 
						|
  g_return_if_fail (child != NULL);
 | 
						|
 | 
						|
  child_info = g_slice_new (GtkStackChildInfo);
 | 
						|
  child_info->widget = child;
 | 
						|
  child_info->name = NULL;
 | 
						|
  child_info->title = NULL;
 | 
						|
  child_info->icon_name = NULL;
 | 
						|
  child_info->needs_attention = FALSE;
 | 
						|
  child_info->last_focus = NULL;
 | 
						|
 | 
						|
  priv->children = g_list_append (priv->children, child_info);
 | 
						|
 | 
						|
  gtk_widget_set_child_visible (child, FALSE);
 | 
						|
  gtk_widget_set_parent_window (child, priv->bin_window);
 | 
						|
  gtk_widget_set_parent (child, GTK_WIDGET (stack));
 | 
						|
 | 
						|
  if (priv->bin_window)
 | 
						|
    gdk_window_set_events (priv->bin_window,
 | 
						|
                           gdk_window_get_events (priv->bin_window) |
 | 
						|
                           gtk_widget_get_events (child));
 | 
						|
 | 
						|
  g_signal_connect (child, "notify::visible",
 | 
						|
                    G_CALLBACK (stack_child_visibility_notify_cb), stack);
 | 
						|
 | 
						|
  gtk_container_child_notify_by_pspec (container, child, stack_child_props[CHILD_PROP_POSITION]);
 | 
						|
 | 
						|
  if (priv->visible_child == NULL &&
 | 
						|
      gtk_widget_get_visible (child))
 | 
						|
    set_visible_child (stack, child_info, priv->transition_type, priv->transition_duration);
 | 
						|
 | 
						|
  if (priv->hhomogeneous || priv->vhomogeneous || priv->visible_child == child_info)
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_remove (GtkContainer *container,
 | 
						|
                  GtkWidget    *child)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (container);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
  gboolean was_visible;
 | 
						|
 | 
						|
  child_info = find_child_info_for_widget (stack, child);
 | 
						|
  if (child_info == NULL)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->children = g_list_remove (priv->children, child_info);
 | 
						|
 | 
						|
  g_signal_handlers_disconnect_by_func (child,
 | 
						|
                                        stack_child_visibility_notify_cb,
 | 
						|
                                        stack);
 | 
						|
 | 
						|
  was_visible = gtk_widget_get_visible (child);
 | 
						|
 | 
						|
  child_info->widget = NULL;
 | 
						|
 | 
						|
  if (priv->visible_child == child_info)
 | 
						|
    set_visible_child (stack, NULL, priv->transition_type, priv->transition_duration);
 | 
						|
 | 
						|
  if (priv->last_visible_child == child_info)
 | 
						|
    priv->last_visible_child = NULL;
 | 
						|
 | 
						|
  gtk_widget_unparent (child);
 | 
						|
 | 
						|
  g_free (child_info->name);
 | 
						|
  g_free (child_info->title);
 | 
						|
  g_free (child_info->icon_name);
 | 
						|
 | 
						|
  if (child_info->last_focus)
 | 
						|
    g_object_remove_weak_pointer (G_OBJECT (child_info->last_focus),
 | 
						|
                                  (gpointer *)&child_info->last_focus);
 | 
						|
 | 
						|
  g_slice_free (GtkStackChildInfo, child_info);
 | 
						|
 | 
						|
  if ((priv->hhomogeneous || priv->vhomogeneous) && was_visible)
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_child_by_name:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @name: the name of the child to find
 | 
						|
 *
 | 
						|
 * Finds the child of the #GtkStack with the name given as
 | 
						|
 * the argument. Returns %NULL if there is no child with this
 | 
						|
 * name.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none) (nullable): the requested child of the #GtkStack
 | 
						|
 *
 | 
						|
 * Since: 3.12
 | 
						|
 */
 | 
						|
GtkWidget *
 | 
						|
gtk_stack_get_child_by_name (GtkStack    *stack,
 | 
						|
                             const gchar *name)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *info;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), NULL);
 | 
						|
  g_return_val_if_fail (name != NULL, NULL);
 | 
						|
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      info = l->data;
 | 
						|
      if (info->name && strcmp (info->name, name) == 0)
 | 
						|
        return info->widget;
 | 
						|
    }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_homogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @homogeneous: %TRUE to make @stack homogeneous
 | 
						|
 *
 | 
						|
 * Sets the #GtkStack to be homogeneous or not. If it
 | 
						|
 * is homogeneous, the #GtkStack will request the same
 | 
						|
 * size for all its children. If it isn't, the stack
 | 
						|
 * may change size when a different child becomes visible.
 | 
						|
 *
 | 
						|
 * Since 3.16, homogeneity can be controlled separately
 | 
						|
 * for horizontal and vertical size, with the
 | 
						|
 * #GtkStack:hhomogeneous and #GtkStack:vhomogeneous.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_homogeneous (GtkStack *stack,
 | 
						|
                           gboolean  homogeneous)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  homogeneous = !!homogeneous;
 | 
						|
 | 
						|
  if ((priv->hhomogeneous && priv->vhomogeneous) == homogeneous)
 | 
						|
    return;
 | 
						|
 | 
						|
  g_object_freeze_notify (G_OBJECT (stack));
 | 
						|
 | 
						|
  if (priv->hhomogeneous != homogeneous)
 | 
						|
    {
 | 
						|
      priv->hhomogeneous = homogeneous;
 | 
						|
      g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_HHOMOGENEOUS]);
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->vhomogeneous != homogeneous)
 | 
						|
    {
 | 
						|
      priv->vhomogeneous = homogeneous;
 | 
						|
      g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_VHOMOGENEOUS]);
 | 
						|
    }
 | 
						|
 | 
						|
  if (gtk_widget_get_visible (GTK_WIDGET(stack)))
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_HOMOGENEOUS]);
 | 
						|
  g_object_thaw_notify (G_OBJECT (stack));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_homogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Gets whether @stack is homogeneous.
 | 
						|
 * See gtk_stack_set_homogeneous().
 | 
						|
 *
 | 
						|
 * Returns: whether @stack is homogeneous.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
gboolean
 | 
						|
gtk_stack_get_homogeneous (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), FALSE);
 | 
						|
 | 
						|
  return priv->hhomogeneous && priv->vhomogeneous;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_hhomogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @hhomogeneous: %TRUE to make @stack horizontally homogeneous
 | 
						|
 *
 | 
						|
 * Sets the #GtkStack to be horizontally homogeneous or not.
 | 
						|
 * If it is homogeneous, the #GtkStack will request the same
 | 
						|
 * width for all its children. If it isn't, the stack
 | 
						|
 * may change width when a different child becomes visible.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_hhomogeneous (GtkStack *stack,
 | 
						|
                            gboolean  hhomogeneous)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  hhomogeneous = !!hhomogeneous;
 | 
						|
 | 
						|
  if (priv->hhomogeneous == hhomogeneous)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->hhomogeneous = hhomogeneous;
 | 
						|
 | 
						|
  if (gtk_widget_get_visible (GTK_WIDGET(stack)))
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_HHOMOGENEOUS]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_hhomogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Gets whether @stack is horizontally homogeneous.
 | 
						|
 * See gtk_stack_set_hhomogeneous().
 | 
						|
 *
 | 
						|
 * Returns: whether @stack is horizontally homogeneous.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
gboolean
 | 
						|
gtk_stack_get_hhomogeneous (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), FALSE);
 | 
						|
 | 
						|
  return priv->hhomogeneous;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_vhomogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @vhomogeneous: %TRUE to make @stack vertically homogeneous
 | 
						|
 *
 | 
						|
 * Sets the #GtkStack to be vertically homogeneous or not.
 | 
						|
 * If it is homogeneous, the #GtkStack will request the same
 | 
						|
 * height for all its children. If it isn't, the stack
 | 
						|
 * may change height when a different child becomes visible.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_vhomogeneous (GtkStack *stack,
 | 
						|
                            gboolean  vhomogeneous)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  vhomogeneous = !!vhomogeneous;
 | 
						|
 | 
						|
  if (priv->vhomogeneous == vhomogeneous)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->vhomogeneous = vhomogeneous;
 | 
						|
 | 
						|
  if (gtk_widget_get_visible (GTK_WIDGET(stack)))
 | 
						|
    gtk_widget_queue_resize (GTK_WIDGET (stack));
 | 
						|
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack), stack_props[PROP_VHOMOGENEOUS]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_vhomogeneous:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Gets whether @stack is vertically homogeneous.
 | 
						|
 * See gtk_stack_set_vhomogeneous().
 | 
						|
 *
 | 
						|
 * Returns: whether @stack is vertically homogeneous.
 | 
						|
 *
 | 
						|
 * Since: 3.16
 | 
						|
 */
 | 
						|
gboolean
 | 
						|
gtk_stack_get_vhomogeneous (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), FALSE);
 | 
						|
 | 
						|
  return priv->vhomogeneous;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_transition_duration:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Returns the amount of time (in milliseconds) that
 | 
						|
 * transitions between pages in @stack will take.
 | 
						|
 *
 | 
						|
 * Returns: the transition duration
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
guint
 | 
						|
gtk_stack_get_transition_duration (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), 0);
 | 
						|
 | 
						|
  return priv->transition_duration;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_transition_duration:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @duration: the new duration, in milliseconds
 | 
						|
 *
 | 
						|
 * Sets the duration that transitions between pages in @stack
 | 
						|
 * will take.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_transition_duration (GtkStack *stack,
 | 
						|
                                   guint     duration)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  if (priv->transition_duration == duration)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->transition_duration = duration;
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack),
 | 
						|
                            stack_props[PROP_TRANSITION_DURATION]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_transition_type:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Gets the type of animation that will be used
 | 
						|
 * for transitions between pages in @stack.
 | 
						|
 *
 | 
						|
 * Returns: the current transition type of @stack
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
GtkStackTransitionType
 | 
						|
gtk_stack_get_transition_type (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), GTK_STACK_TRANSITION_TYPE_NONE);
 | 
						|
 | 
						|
  return priv->transition_type;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_transition_type:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @transition: the new transition type
 | 
						|
 *
 | 
						|
 * Sets the type of animation that will be used for
 | 
						|
 * transitions between pages in @stack. Available
 | 
						|
 * types include various kinds of fades and slides.
 | 
						|
 *
 | 
						|
 * The transition type can be changed without problems
 | 
						|
 * at runtime, so it is possible to change the animation
 | 
						|
 * based on the page that is about to become current.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_transition_type (GtkStack              *stack,
 | 
						|
                              GtkStackTransitionType  transition)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  if (priv->transition_type == transition)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->transition_type = transition;
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack),
 | 
						|
                            stack_props[PROP_TRANSITION_TYPE]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_transition_running:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Returns whether the @stack is currently in a transition from one page to
 | 
						|
 * another.
 | 
						|
 *
 | 
						|
 * Returns: %TRUE if the transition is currently running, %FALSE otherwise.
 | 
						|
 *
 | 
						|
 * Since: 3.12
 | 
						|
 */
 | 
						|
gboolean
 | 
						|
gtk_stack_get_transition_running (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), FALSE);
 | 
						|
 | 
						|
  return (priv->tick_id != 0);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_interpolate_size:
 | 
						|
 * @stack: A #GtkStack
 | 
						|
 * @interpolate_size: the new value
 | 
						|
 *
 | 
						|
 * Sets whether or not @stack will interpolate its size when
 | 
						|
 * changing the visible child. If the #GtkStack:interpolate-size
 | 
						|
 * property is set to %TRUE, @stack will interpolate its size between
 | 
						|
 * the current one and the one it'll take after changing the
 | 
						|
 * visible child, according to the set transition duration.
 | 
						|
 *
 | 
						|
 * Since: 3.18
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_interpolate_size (GtkStack *stack,
 | 
						|
                                gboolean  interpolate_size)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  interpolate_size = !!interpolate_size;
 | 
						|
 | 
						|
  if (priv->interpolate_size == interpolate_size)
 | 
						|
    return;
 | 
						|
 | 
						|
  priv->interpolate_size = interpolate_size;
 | 
						|
  g_object_notify_by_pspec (G_OBJECT (stack),
 | 
						|
                            stack_props[PROP_INTERPOLATE_SIZE]);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_interpolate_size:
 | 
						|
 * @stack: A #GtkStack
 | 
						|
 *
 | 
						|
 * Returns wether the #GtkStack is set up to interpolate between
 | 
						|
 * the sizes of children on page switch.
 | 
						|
 *
 | 
						|
 * Returns: %TRUE if child sizes are interpolated
 | 
						|
 *
 | 
						|
 * Since: 3.18
 | 
						|
 */
 | 
						|
gboolean
 | 
						|
gtk_stack_get_interpolate_size (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), FALSE);
 | 
						|
 | 
						|
  return priv->interpolate_size;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_visible_child:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Gets the currently visible child of @stack, or %NULL if
 | 
						|
 * there are no visible children.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none) (nullable): the visible child of the #GtkStack
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
GtkWidget *
 | 
						|
gtk_stack_get_visible_child (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), NULL);
 | 
						|
 | 
						|
  return priv->visible_child ? priv->visible_child->widget : NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_get_visible_child_name:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 *
 | 
						|
 * Returns the name of the currently visible child of @stack, or
 | 
						|
 * %NULL if there is no visible child.
 | 
						|
 *
 | 
						|
 * Returns: (transfer none) (nullable): the name of the visible child of the #GtkStack
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
const gchar *
 | 
						|
gtk_stack_get_visible_child_name (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  g_return_val_if_fail (GTK_IS_STACK (stack), NULL);
 | 
						|
 | 
						|
  if (priv->visible_child)
 | 
						|
    return priv->visible_child->name;
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_visible_child:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @child: a child of @stack
 | 
						|
 *
 | 
						|
 * Makes @child the visible child of @stack.
 | 
						|
 *
 | 
						|
 * If @child is different from the currently
 | 
						|
 * visible child, the transition between the
 | 
						|
 * two will be animated with the current
 | 
						|
 * transition type of @stack.
 | 
						|
 *
 | 
						|
 * Note that the @child widget has to be visible itself
 | 
						|
 * (see gtk_widget_show()) in order to become the visible
 | 
						|
 * child of @stack.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_visible_child (GtkStack  *stack,
 | 
						|
                             GtkWidget *child)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
  g_return_if_fail (GTK_IS_WIDGET (child));
 | 
						|
 | 
						|
  child_info = find_child_info_for_widget (stack, child);
 | 
						|
  if (child_info == NULL)
 | 
						|
    {
 | 
						|
      g_warning ("Given child of type '%s' not found in GtkStack",
 | 
						|
                 G_OBJECT_TYPE_NAME (child));
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  if (gtk_widget_get_visible (child_info->widget))
 | 
						|
    set_visible_child (stack, child_info,
 | 
						|
                       priv->transition_type,
 | 
						|
                       priv->transition_duration);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_visible_child_name:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @name: the name of the child to make visible
 | 
						|
 *
 | 
						|
 * Makes the child with the given name visible.
 | 
						|
 *
 | 
						|
 * If @child is different from the currently
 | 
						|
 * visible child, the transition between the
 | 
						|
 * two will be animated with the current
 | 
						|
 * transition type of @stack.
 | 
						|
 *
 | 
						|
 * Note that the child widget has to be visible itself
 | 
						|
 * (see gtk_widget_show()) in order to become the visible
 | 
						|
 * child of @stack.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_visible_child_name (GtkStack   *stack,
 | 
						|
                                 const gchar *name)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_stack_set_visible_child_full (stack, name, priv->transition_type);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * gtk_stack_set_visible_child_full:
 | 
						|
 * @stack: a #GtkStack
 | 
						|
 * @name: the name of the child to make visible
 | 
						|
 * @transition: the transition type to use
 | 
						|
 *
 | 
						|
 * Makes the child with the given name visible.
 | 
						|
 *
 | 
						|
 * Note that the child widget has to be visible itself
 | 
						|
 * (see gtk_widget_show()) in order to become the visible
 | 
						|
 * child of @stack.
 | 
						|
 *
 | 
						|
 * Since: 3.10
 | 
						|
 */
 | 
						|
void
 | 
						|
gtk_stack_set_visible_child_full (GtkStack               *stack,
 | 
						|
                                  const gchar            *name,
 | 
						|
                                  GtkStackTransitionType  transition)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info, *info;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  g_return_if_fail (GTK_IS_STACK (stack));
 | 
						|
 | 
						|
  if (name == NULL)
 | 
						|
    return;
 | 
						|
 | 
						|
  child_info = NULL;
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      info = l->data;
 | 
						|
      if (info->name != NULL &&
 | 
						|
          strcmp (info->name, name) == 0)
 | 
						|
        {
 | 
						|
          child_info = info;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (child_info == NULL)
 | 
						|
    {
 | 
						|
      g_warning ("Child name '%s' not found in GtkStack", name);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  if (gtk_widget_get_visible (child_info->widget))
 | 
						|
    set_visible_child (stack, child_info, transition, priv->transition_duration);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_forall (GtkContainer *container,
 | 
						|
                  gboolean      include_internals,
 | 
						|
                  GtkCallback   callback,
 | 
						|
                  gpointer      callback_data)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (container);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  l = priv->children;
 | 
						|
  while (l)
 | 
						|
    {
 | 
						|
      child_info = l->data;
 | 
						|
      l = l->next;
 | 
						|
 | 
						|
      (* callback) (child_info->widget, callback_data);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_compute_expand (GtkWidget *widget,
 | 
						|
                          gboolean  *hexpand_p,
 | 
						|
                          gboolean  *vexpand_p)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  gboolean hexpand, vexpand;
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
  GtkWidget *child;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  hexpand = FALSE;
 | 
						|
  vexpand = FALSE;
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      child_info = l->data;
 | 
						|
      child = child_info->widget;
 | 
						|
 | 
						|
      if (!hexpand &&
 | 
						|
          gtk_widget_compute_expand (child, GTK_ORIENTATION_HORIZONTAL))
 | 
						|
        hexpand = TRUE;
 | 
						|
 | 
						|
      if (!vexpand &&
 | 
						|
          gtk_widget_compute_expand (child, GTK_ORIENTATION_VERTICAL))
 | 
						|
        vexpand = TRUE;
 | 
						|
 | 
						|
      if (hexpand && vexpand)
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
  *hexpand_p = hexpand;
 | 
						|
  *vexpand_p = vexpand;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_draw_crossfade (GtkWidget *widget,
 | 
						|
                          cairo_t   *cr)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  gdouble progress = gtk_progress_tracker_get_progress (&priv->tracker, FALSE);
 | 
						|
 | 
						|
  cairo_push_group (cr);
 | 
						|
  gtk_container_propagate_draw (GTK_CONTAINER (stack),
 | 
						|
                                priv->visible_child->widget,
 | 
						|
                                cr);
 | 
						|
  cairo_save (cr);
 | 
						|
 | 
						|
  /* Multiply alpha by progress */
 | 
						|
  cairo_set_source_rgba (cr, 1, 1, 1, progress);
 | 
						|
  cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
 | 
						|
  cairo_paint (cr);
 | 
						|
 | 
						|
  if (priv->last_visible_surface)
 | 
						|
    {
 | 
						|
      cairo_set_source_surface (cr, priv->last_visible_surface,
 | 
						|
                                priv->last_visible_surface_allocation.x,
 | 
						|
                                priv->last_visible_surface_allocation.y);
 | 
						|
      cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
 | 
						|
      cairo_paint_with_alpha (cr, MAX (1.0 - progress, 0));
 | 
						|
    }
 | 
						|
 | 
						|
  cairo_restore (cr);
 | 
						|
 | 
						|
  cairo_pop_group_to_source (cr);
 | 
						|
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 | 
						|
  cairo_paint (cr);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_draw_under (GtkWidget *widget,
 | 
						|
                      cairo_t   *cr)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkAllocation allocation;
 | 
						|
  gint x, y, width, height, pos_x, pos_y;
 | 
						|
 | 
						|
  gtk_widget_get_allocation (widget, &allocation);
 | 
						|
  x = y = 0;
 | 
						|
  width = allocation.width;
 | 
						|
  height = allocation.height;
 | 
						|
  pos_x = pos_y = 0;
 | 
						|
 | 
						|
  switch (priv->active_transition_type)
 | 
						|
    {
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN:
 | 
						|
      y = 0;
 | 
						|
      height = allocation.height * (gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      pos_y = height;
 | 
						|
      break;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_UNDER_UP:
 | 
						|
      y = allocation.height * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      height = allocation.height - y;
 | 
						|
      pos_y = y - allocation.height;
 | 
						|
      break;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
 | 
						|
      x = allocation.width * (1 - gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      width = allocation.width - x;
 | 
						|
      pos_x = x - allocation.width;
 | 
						|
      break;
 | 
						|
    case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
 | 
						|
      x = 0;
 | 
						|
      width = allocation.width * (gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE));
 | 
						|
      pos_x = width;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      g_assert_not_reached ();
 | 
						|
    }
 | 
						|
 | 
						|
  cairo_save (cr);
 | 
						|
  cairo_rectangle (cr, x, y, width, height);
 | 
						|
  cairo_clip (cr);
 | 
						|
 | 
						|
  gtk_container_propagate_draw (GTK_CONTAINER (stack),
 | 
						|
                                priv->visible_child->widget,
 | 
						|
                                cr);
 | 
						|
 | 
						|
  cairo_restore (cr);
 | 
						|
 | 
						|
  if (priv->last_visible_surface)
 | 
						|
    {
 | 
						|
      cairo_set_source_surface (cr, priv->last_visible_surface, pos_x, pos_y);
 | 
						|
      cairo_paint (cr);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_draw_slide (GtkWidget *widget,
 | 
						|
                      cairo_t   *cr)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  if (priv->last_visible_surface &&
 | 
						|
      gtk_cairo_should_draw_window (cr, priv->view_window))
 | 
						|
    {
 | 
						|
      GtkAllocation allocation;
 | 
						|
      int x, y;
 | 
						|
 | 
						|
      gtk_widget_get_allocation (widget, &allocation);
 | 
						|
 | 
						|
      x = get_bin_window_x (stack, &allocation);
 | 
						|
      y = get_bin_window_y (stack, &allocation);
 | 
						|
 | 
						|
      switch (priv->active_transition_type)
 | 
						|
        {
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT:
 | 
						|
          x -= allocation.width;
 | 
						|
          break;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT:
 | 
						|
          x += allocation.width;
 | 
						|
          break;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_UP:
 | 
						|
          y -= allocation.height;
 | 
						|
          break;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN:
 | 
						|
          y += allocation.height;
 | 
						|
          break;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_UP:
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_DOWN:
 | 
						|
          y = 0;
 | 
						|
          break;
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_LEFT:
 | 
						|
        case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT:
 | 
						|
          x = 0;
 | 
						|
          break;
 | 
						|
        default:
 | 
						|
          g_assert_not_reached ();
 | 
						|
          break;
 | 
						|
        }
 | 
						|
 | 
						|
      x += priv->last_visible_surface_allocation.x;
 | 
						|
      y += priv->last_visible_surface_allocation.y;
 | 
						|
 | 
						|
 | 
						|
      if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_END &&
 | 
						|
          priv->last_visible_widget_height > allocation.height)
 | 
						|
        y -= priv->last_visible_widget_height - allocation.height;
 | 
						|
      else if (gtk_widget_get_valign (priv->last_visible_child->widget) == GTK_ALIGN_CENTER)
 | 
						|
        y -= (priv->last_visible_widget_height - allocation.height) / 2;
 | 
						|
 | 
						|
      cairo_save (cr);
 | 
						|
      cairo_set_source_surface (cr, priv->last_visible_surface, x, y);
 | 
						|
      cairo_paint (cr);
 | 
						|
      cairo_restore (cr);
 | 
						|
     }
 | 
						|
 | 
						|
  if (gtk_cairo_should_draw_window (cr, priv->bin_window))
 | 
						|
    gtk_container_propagate_draw (GTK_CONTAINER (stack),
 | 
						|
                                  priv->visible_child->widget,
 | 
						|
                                  cr);
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
gtk_stack_draw (GtkWidget *widget,
 | 
						|
                cairo_t   *cr)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_css_gadget_draw (priv->gadget, cr);
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static gboolean
 | 
						|
gtk_stack_render (GtkCssGadget *gadget,
 | 
						|
                  cairo_t      *cr,
 | 
						|
                  int           x,
 | 
						|
                  int           y,
 | 
						|
                  int           width,
 | 
						|
                  int           height,
 | 
						|
                  gpointer      data)
 | 
						|
{
 | 
						|
  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  cairo_t *pattern_cr;
 | 
						|
 | 
						|
  if (gtk_cairo_should_draw_window (cr, priv->view_window))
 | 
						|
    {
 | 
						|
      GtkStyleContext *context;
 | 
						|
 | 
						|
      context = gtk_widget_get_style_context (widget);
 | 
						|
      gtk_render_background (context,
 | 
						|
                             cr,
 | 
						|
                             0, 0,
 | 
						|
                             gtk_widget_get_allocated_width (widget),
 | 
						|
                             gtk_widget_get_allocated_height (widget));
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->visible_child)
 | 
						|
    {
 | 
						|
      if (gtk_progress_tracker_get_state (&priv->tracker) != GTK_PROGRESS_STATE_AFTER)
 | 
						|
        {
 | 
						|
          if (priv->last_visible_surface == NULL &&
 | 
						|
              priv->last_visible_child != NULL)
 | 
						|
            {
 | 
						|
              gtk_widget_get_allocation (priv->last_visible_child->widget,
 | 
						|
                                         &priv->last_visible_surface_allocation);
 | 
						|
              priv->last_visible_surface =
 | 
						|
                gdk_window_create_similar_surface (gtk_widget_get_window (widget),
 | 
						|
                                                   CAIRO_CONTENT_COLOR_ALPHA,
 | 
						|
                                                   priv->last_visible_surface_allocation.width,
 | 
						|
                                                   priv->last_visible_surface_allocation.height);
 | 
						|
              pattern_cr = cairo_create (priv->last_visible_surface);
 | 
						|
              /* We don't use propagate_draw here, because we don't want to apply
 | 
						|
               * the bin_window offset
 | 
						|
               */
 | 
						|
              gtk_widget_draw (priv->last_visible_child->widget, pattern_cr);
 | 
						|
              cairo_destroy (pattern_cr);
 | 
						|
            }
 | 
						|
 | 
						|
          cairo_rectangle (cr,
 | 
						|
                           0, 0,
 | 
						|
                           gtk_widget_get_allocated_width (widget),
 | 
						|
                           gtk_widget_get_allocated_height (widget));
 | 
						|
          cairo_clip (cr);
 | 
						|
 | 
						|
          switch (priv->active_transition_type)
 | 
						|
            {
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_CROSSFADE:
 | 
						|
	      if (gtk_cairo_should_draw_window (cr, priv->bin_window))
 | 
						|
		gtk_stack_draw_crossfade (widget, cr);
 | 
						|
              break;
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_SLIDE_UP:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_OVER_UP:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_OVER_DOWN:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_OVER_LEFT:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT:
 | 
						|
              gtk_stack_draw_slide (widget, cr);
 | 
						|
              break;
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_UNDER_UP:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_UNDER_DOWN:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
 | 
						|
            case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
 | 
						|
	      if (gtk_cairo_should_draw_window (cr, priv->bin_window))
 | 
						|
		gtk_stack_draw_under (widget, cr);
 | 
						|
              break;
 | 
						|
            default:
 | 
						|
              g_assert_not_reached ();
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
      else if (gtk_cairo_should_draw_window (cr, priv->bin_window))
 | 
						|
        gtk_container_propagate_draw (GTK_CONTAINER (stack),
 | 
						|
                                      priv->visible_child->widget,
 | 
						|
                                      cr);
 | 
						|
    }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_size_allocate (GtkWidget     *widget,
 | 
						|
                         GtkAllocation *allocation)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkAllocation clip;
 | 
						|
 | 
						|
  gtk_widget_set_allocation (widget, allocation);
 | 
						|
 | 
						|
  gtk_css_gadget_allocate (priv->gadget,
 | 
						|
                           allocation,
 | 
						|
                           gtk_widget_get_allocated_baseline (widget),
 | 
						|
                           &clip);
 | 
						|
 | 
						|
  gtk_widget_set_clip (widget, &clip);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_allocate (GtkCssGadget        *gadget,
 | 
						|
                    const GtkAllocation *allocation,
 | 
						|
                    int                  baseline,
 | 
						|
                    GtkAllocation       *out_clip,
 | 
						|
                    gpointer             data)
 | 
						|
{
 | 
						|
  GtkWidget *widget;
 | 
						|
  GtkStack *stack;
 | 
						|
  GtkStackPrivate *priv;
 | 
						|
  GtkAllocation child_allocation;
 | 
						|
 | 
						|
  widget = gtk_css_gadget_get_owner (gadget);
 | 
						|
  stack = GTK_STACK (widget);
 | 
						|
  priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  child_allocation.x = 0;
 | 
						|
  child_allocation.y = 0;
 | 
						|
 | 
						|
  if (gtk_widget_get_realized (widget))
 | 
						|
    {
 | 
						|
      gdk_window_move_resize (priv->view_window,
 | 
						|
                              allocation->x, allocation->y,
 | 
						|
                              allocation->width, allocation->height);
 | 
						|
      gdk_window_move_resize (priv->bin_window,
 | 
						|
                              get_bin_window_x (stack, allocation), get_bin_window_y (stack, allocation),
 | 
						|
                              allocation->width, allocation->height);
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->last_visible_child)
 | 
						|
    {
 | 
						|
      int min, nat;
 | 
						|
      gtk_widget_get_preferred_width (priv->last_visible_child->widget, &min, &nat);
 | 
						|
      child_allocation.width = MAX (min, allocation->width);
 | 
						|
      gtk_widget_get_preferred_height_for_width (priv->last_visible_child->widget,
 | 
						|
                                                 child_allocation.width,
 | 
						|
                                                 &min, &nat);
 | 
						|
      child_allocation.height = MAX (min, allocation->height);
 | 
						|
 | 
						|
      gtk_widget_size_allocate (priv->last_visible_child->widget, &child_allocation);
 | 
						|
    }
 | 
						|
 | 
						|
  child_allocation.width = allocation->width;
 | 
						|
  child_allocation.height = allocation->height;
 | 
						|
 | 
						|
  if (priv->visible_child)
 | 
						|
    {
 | 
						|
      int min, nat;
 | 
						|
      GtkAlign valign;
 | 
						|
 | 
						|
      gtk_widget_get_preferred_height_for_width (priv->visible_child->widget,
 | 
						|
                                                 allocation->width,
 | 
						|
                                                 &min, &nat);
 | 
						|
      if (priv->interpolate_size)
 | 
						|
        {
 | 
						|
          valign = gtk_widget_get_valign (priv->visible_child->widget);
 | 
						|
          child_allocation.height = MAX (nat, allocation->height);
 | 
						|
          if (valign == GTK_ALIGN_END &&
 | 
						|
              child_allocation.height > allocation->height)
 | 
						|
            child_allocation.y -= nat - allocation->height;
 | 
						|
          else if (valign == GTK_ALIGN_CENTER &&
 | 
						|
                   child_allocation.height > allocation->height)
 | 
						|
            child_allocation.y -= (nat - allocation->height) / 2;
 | 
						|
        }
 | 
						|
 | 
						|
      gtk_widget_size_allocate (priv->visible_child->widget, &child_allocation);
 | 
						|
    }
 | 
						|
  gtk_container_get_children_clip (GTK_CONTAINER (widget), out_clip);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_preferred_width (GtkWidget *widget,
 | 
						|
                               gint      *minimum,
 | 
						|
                               gint      *natural)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_css_gadget_get_preferred_size (priv->gadget,
 | 
						|
                                     GTK_ORIENTATION_HORIZONTAL,
 | 
						|
                                     -1,
 | 
						|
                                     minimum, natural,
 | 
						|
                                     NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_preferred_width_for_height (GtkWidget *widget,
 | 
						|
                                          gint       height,
 | 
						|
                                          gint      *minimum,
 | 
						|
                                          gint      *natural)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_css_gadget_get_preferred_size (priv->gadget,
 | 
						|
                                     GTK_ORIENTATION_HORIZONTAL,
 | 
						|
                                     height,
 | 
						|
                                     minimum, natural,
 | 
						|
                                     NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_preferred_height (GtkWidget *widget,
 | 
						|
                                gint      *minimum,
 | 
						|
                                gint      *natural)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_css_gadget_get_preferred_size (priv->gadget,
 | 
						|
                                     GTK_ORIENTATION_VERTICAL,
 | 
						|
                                     -1,
 | 
						|
                                     minimum, natural,
 | 
						|
                                     NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_get_preferred_height_for_width (GtkWidget *widget,
 | 
						|
                                          gint       width,
 | 
						|
                                          gint      *minimum,
 | 
						|
                                          gint      *natural)
 | 
						|
{
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_css_gadget_get_preferred_size (priv->gadget,
 | 
						|
                                     GTK_ORIENTATION_VERTICAL,
 | 
						|
                                     width,
 | 
						|
                                     minimum, natural,
 | 
						|
                                     NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
#define LERP(a, b, t) ((a) + (((b) - (a)) * (1.0 - (t))))
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_measure (GtkCssGadget   *gadget,
 | 
						|
                   GtkOrientation  orientation,
 | 
						|
                   int             for_size,
 | 
						|
                   int            *minimum,
 | 
						|
                   int            *natural,
 | 
						|
                   int            *minimum_baseline,
 | 
						|
                   int            *natural_baseline,
 | 
						|
                   gpointer        data)
 | 
						|
{
 | 
						|
  GtkWidget *widget = gtk_css_gadget_get_owner (gadget);
 | 
						|
  GtkStack *stack = GTK_STACK (widget);
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
  GtkStackChildInfo *child_info;
 | 
						|
  GtkWidget *child;
 | 
						|
  gint child_min, child_nat;
 | 
						|
  GList *l;
 | 
						|
 | 
						|
  *minimum = 0;
 | 
						|
  *natural = 0;
 | 
						|
 | 
						|
  for (l = priv->children; l != NULL; l = l->next)
 | 
						|
    {
 | 
						|
      child_info = l->data;
 | 
						|
      child = child_info->widget;
 | 
						|
 | 
						|
      if (((orientation == GTK_ORIENTATION_VERTICAL && !priv->vhomogeneous) ||
 | 
						|
           (orientation == GTK_ORIENTATION_HORIZONTAL && !priv->hhomogeneous)) &&
 | 
						|
           priv->visible_child != child_info)
 | 
						|
        continue;
 | 
						|
 | 
						|
      if (gtk_widget_get_visible (child))
 | 
						|
        {
 | 
						|
          if (orientation == GTK_ORIENTATION_VERTICAL)
 | 
						|
            {
 | 
						|
              if (for_size < 0)
 | 
						|
                gtk_widget_get_preferred_height (child, &child_min, &child_nat);
 | 
						|
              else
 | 
						|
                gtk_widget_get_preferred_height_for_width (child, for_size, &child_min, &child_nat);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              if (for_size < 0)
 | 
						|
                gtk_widget_get_preferred_width (child, &child_min, &child_nat);
 | 
						|
              else
 | 
						|
                gtk_widget_get_preferred_width_for_height (child, for_size, &child_min, &child_nat);
 | 
						|
            }
 | 
						|
 | 
						|
          *minimum = MAX (*minimum, child_min);
 | 
						|
          *natural = MAX (*natural, child_nat);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
  if (priv->last_visible_child != NULL)
 | 
						|
    {
 | 
						|
      if (orientation == GTK_ORIENTATION_VERTICAL && !priv->vhomogeneous)
 | 
						|
        {
 | 
						|
          gdouble t = priv->interpolate_size ? gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE) : 1.0;
 | 
						|
          *minimum = LERP (*minimum, priv->last_visible_widget_height, t);
 | 
						|
          *natural = LERP (*natural, priv->last_visible_widget_height, t);
 | 
						|
        }
 | 
						|
      if (orientation == GTK_ORIENTATION_HORIZONTAL && !priv->hhomogeneous)
 | 
						|
        {
 | 
						|
          gdouble t = priv->interpolate_size ? gtk_progress_tracker_get_ease_out_cubic (&priv->tracker, FALSE) : 1.0;
 | 
						|
          *minimum = LERP (*minimum, priv->last_visible_widget_width, t);
 | 
						|
          *natural = LERP (*natural, priv->last_visible_widget_width, t);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
gtk_stack_init (GtkStack *stack)
 | 
						|
{
 | 
						|
  GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
 | 
						|
 | 
						|
  gtk_widget_set_has_window (GTK_WIDGET (stack), FALSE);
 | 
						|
 | 
						|
  priv->vhomogeneous = TRUE;
 | 
						|
  priv->hhomogeneous = TRUE;
 | 
						|
  priv->transition_duration = 200;
 | 
						|
  priv->transition_type = GTK_STACK_TRANSITION_TYPE_NONE;
 | 
						|
 | 
						|
  priv->gadget = gtk_css_custom_gadget_new_for_node (gtk_widget_get_css_node (GTK_WIDGET (stack)),
 | 
						|
                                                     GTK_WIDGET (stack),
 | 
						|
                                                     gtk_stack_measure,
 | 
						|
                                                     gtk_stack_allocate,
 | 
						|
                                                     gtk_stack_render,
 | 
						|
                                                     NULL,
 | 
						|
                                                     NULL);
 | 
						|
 | 
						|
}
 |