2013-04-21 11:51:14 +00:00
/*
* 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"
2015-12-09 04:03:38 +00:00
# include "gtkcsscustomgadgetprivate.h"
# include "gtkcontainerprivate.h"
2016-03-01 06:24:39 +00:00
# include "gtkprogresstrackerprivate.h"
2016-05-01 04:39:55 +00:00
# include "gtksettingsprivate.h"
2015-12-09 04:03:38 +00:00
# include "gtkwidgetprivate.h"
2016-05-29 11:51:02 +00:00
# include "a11y/gtkstackaccessible.h"
# include "a11y/gtkstackaccessibleprivate.h"
2013-04-21 11:51:14 +00:00
# include <math.h>
# include <string.h>
2013-04-21 14:14:46 +00:00
/**
* 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 ,
2013-04-25 02:07:09 +00:00
* 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 .
2013-04-21 14:14:46 +00:00
*
* Transitions between pages can be animated as slides or
* fades . This can be controlled with gtk_stack_set_transition_type ( ) .
2014-01-22 01:58:13 +00:00
* These animations respect the # GtkSettings : gtk - enable - animations
2013-04-21 14:14:46 +00:00
* setting .
*
* The GtkStack widget was added in GTK + 3.10 .
2015-11-04 04:19:28 +00:00
*
* # CSS nodes
*
* GtkStack has a single CSS node named stack .
2013-04-21 14:14:46 +00:00
*/
/**
* GtkStackTransitionType :
* @ GTK_STACK_TRANSITION_TYPE_NONE : No transition
* @ GTK_STACK_TRANSITION_TYPE_CROSSFADE : A cross - fade
2013-04-22 00:17:40 +00:00
* @ 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
2013-06-13 18:33:42 +00:00
* @ 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
2013-08-31 16:00:47 +00:00
* @ 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
2014-03-19 03:42:59 +00:00
* @ 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
2013-04-21 14:14:46 +00:00
*
* These enumeration values describe the possible transitions
* between pages in a # GtkStack widget .
2013-08-31 16:00:47 +00:00
*
* New values may be added to this enumeration over time .
2013-04-21 14:14:46 +00:00
*/
2013-04-21 11:51:14 +00:00
/* TODO:
* filter events out events to the last_child widget during transitions
*/
enum {
PROP_0 ,
PROP_HOMOGENEOUS ,
2014-10-26 18:59:21 +00:00
PROP_HHOMOGENEOUS ,
PROP_VHOMOGENEOUS ,
2013-04-21 11:51:14 +00:00
PROP_VISIBLE_CHILD ,
PROP_VISIBLE_CHILD_NAME ,
PROP_TRANSITION_DURATION ,
2013-11-05 10:11:35 +00:00
PROP_TRANSITION_TYPE ,
2013-11-11 21:38:35 +00:00
PROP_TRANSITION_RUNNING ,
2015-07-19 15:39:41 +00:00
PROP_INTERPOLATE_SIZE ,
2013-11-05 10:11:35 +00:00
LAST_PROP
2013-04-21 11:51:14 +00:00
} ;
enum
{
CHILD_PROP_0 ,
CHILD_PROP_NAME ,
CHILD_PROP_TITLE ,
CHILD_PROP_ICON_NAME ,
2013-08-30 20:32:42 +00:00
CHILD_PROP_POSITION ,
2015-09-07 22:53:25 +00:00
CHILD_PROP_NEEDS_ATTENTION ,
LAST_CHILD_PROP
2013-04-21 11:51:14 +00:00
} ;
typedef struct _GtkStackChildInfo GtkStackChildInfo ;
struct _GtkStackChildInfo {
GtkWidget * widget ;
gchar * name ;
gchar * title ;
gchar * icon_name ;
2013-08-30 20:32:42 +00:00
gboolean needs_attention ;
2014-12-11 03:32:45 +00:00
GtkWidget * last_focus ;
2013-04-21 11:51:14 +00:00
} ;
2013-07-02 11:43:20 +00:00
typedef struct {
2013-04-21 11:51:14 +00:00
GList * children ;
GdkWindow * bin_window ;
GdkWindow * view_window ;
GtkStackChildInfo * visible_child ;
2015-12-09 04:03:38 +00:00
GtkCssGadget * gadget ;
2014-10-26 18:59:21 +00:00
gboolean hhomogeneous ;
gboolean vhomogeneous ;
2013-04-21 11:51:14 +00:00
GtkStackTransitionType transition_type ;
2013-04-22 01:31:29 +00:00
guint transition_duration ;
2013-04-21 11:51:14 +00:00
GtkStackChildInfo * last_visible_child ;
cairo_surface_t * last_visible_surface ;
GtkAllocation last_visible_surface_allocation ;
guint tick_id ;
2016-03-01 06:24:39 +00:00
GtkProgressTracker tracker ;
2016-03-02 01:19:50 +00:00
gboolean first_frame_skipped ;
2013-04-21 18:22:35 +00:00
2015-05-24 14:55:34 +00:00
gint last_visible_widget_width ;
gint last_visible_widget_height ;
2015-07-19 15:39:41 +00:00
gboolean interpolate_size ;
2013-04-21 18:22:35 +00:00
GtkStackTransitionType active_transition_type ;
2014-02-16 21:22:59 +00:00
2013-07-02 11:43:20 +00:00
} GtkStackPrivate ;
2013-04-21 11:51:14 +00:00
2013-11-05 10:11:35 +00:00
static GParamSpec * stack_props [ LAST_PROP ] = { NULL , } ;
2015-09-07 22:53:25 +00:00
static GParamSpec * stack_child_props [ LAST_CHILD_PROP ] = { NULL , } ;
2013-11-05 10:11:35 +00:00
2013-04-21 11:51:14 +00:00
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 ) ;
2015-12-09 04:03:38 +00:00
static gint get_bin_window_x ( GtkStack * stack ,
const GtkAllocation * allocation ) ;
static gint get_bin_window_y ( GtkStack * stack ,
const GtkAllocation * allocation ) ;
2013-04-21 11:51:14 +00:00
2013-06-27 19:02:52 +00:00
G_DEFINE_TYPE_WITH_PRIVATE ( GtkStack , gtk_stack , GTK_TYPE_CONTAINER )
2013-04-21 11:51:14 +00:00
2015-05-06 13:19:55 +00:00
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 ) ;
}
2013-04-21 11:51:14 +00:00
static void
gtk_stack_finalize ( GObject * obj )
{
GtkStack * stack = GTK_STACK ( obj ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
gtk_stack_unschedule_ticks ( stack ) ;
if ( priv - > last_visible_surface ! = NULL )
cairo_surface_destroy ( priv - > last_visible_surface ) ;
2015-12-09 04:03:38 +00:00
g_clear_object ( & priv - > gadget ) ;
2013-04-21 11:51:14 +00:00
G_OBJECT_CLASS ( gtk_stack_parent_class ) - > finalize ( obj ) ;
}
static void
gtk_stack_get_property ( GObject * object ,
2014-10-26 18:59:21 +00:00
guint property_id ,
GValue * value ,
GParamSpec * pspec )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( object ) ;
switch ( property_id )
{
case PROP_HOMOGENEOUS :
2014-10-26 18:59:21 +00:00
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 ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_VISIBLE_CHILD :
2013-11-25 01:39:13 +00:00
g_value_set_object ( value , gtk_stack_get_visible_child ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_VISIBLE_CHILD_NAME :
g_value_set_string ( value , gtk_stack_get_visible_child_name ( stack ) ) ;
break ;
case PROP_TRANSITION_DURATION :
2013-04-22 01:31:29 +00:00
g_value_set_uint ( value , gtk_stack_get_transition_duration ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_TRANSITION_TYPE :
2013-04-22 01:16:46 +00:00
g_value_set_enum ( value , gtk_stack_get_transition_type ( stack ) ) ;
2013-04-21 11:51:14 +00:00
break ;
2013-11-11 21:38:35 +00:00
case PROP_TRANSITION_RUNNING :
g_value_set_boolean ( value , gtk_stack_get_transition_running ( stack ) ) ;
break ;
2015-07-19 15:39:41 +00:00
case PROP_INTERPOLATE_SIZE :
g_value_set_boolean ( value , gtk_stack_get_interpolate_size ( stack ) ) ;
break ;
2013-04-21 11:51:14 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_set_property ( GObject * object ,
2014-10-26 18:59:21 +00:00
guint property_id ,
const GValue * value ,
GParamSpec * pspec )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( object ) ;
switch ( property_id )
{
case PROP_HOMOGENEOUS :
gtk_stack_set_homogeneous ( stack , g_value_get_boolean ( value ) ) ;
break ;
2014-10-26 18:59:21 +00:00
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 ;
2013-04-21 11:51:14 +00:00
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 :
2013-04-22 01:31:29 +00:00
gtk_stack_set_transition_duration ( stack , g_value_get_uint ( value ) ) ;
2013-04-21 11:51:14 +00:00
break ;
case PROP_TRANSITION_TYPE :
2013-04-22 01:16:46 +00:00
gtk_stack_set_transition_type ( stack , g_value_get_enum ( value ) ) ;
2013-04-21 11:51:14 +00:00
break ;
2015-07-19 15:39:41 +00:00
case PROP_INTERPOLATE_SIZE :
gtk_stack_set_interpolate_size ( stack , g_value_get_boolean ( value ) ) ;
break ;
2013-04-21 11:51:14 +00:00
default :
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object , property_id , pspec ) ;
break ;
}
}
static void
gtk_stack_realize ( GtkWidget * widget )
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkAllocation allocation ;
GdkWindowAttr attributes = { 0 } ;
GdkWindowAttributesType attributes_mask ;
GtkStackChildInfo * info ;
GList * l ;
gtk_widget_set_realized ( widget , TRUE ) ;
2016-01-26 13:02:55 +00:00
gtk_widget_set_window ( widget , g_object_ref ( gtk_widget_get_parent_window ( widget ) ) ) ;
2013-04-21 11:51:14 +00:00
2016-01-26 15:36:13 +00:00
gtk_css_gadget_get_content_allocation ( priv - > gadget , & allocation , NULL ) ;
2013-04-21 11:51:14 +00:00
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 =
2015-09-14 08:56:13 +00:00
gtk_widget_get_events ( widget ) ;
2013-04-21 11:51:14 +00:00
attributes_mask = ( GDK_WA_X | GDK_WA_Y ) | GDK_WA_VISUAL ;
priv - > view_window =
2016-01-26 13:02:55 +00:00
gdk_window_new ( gtk_widget_get_window ( GTK_WIDGET ( stack ) ) ,
2013-04-21 11:51:14 +00:00
& attributes , attributes_mask ) ;
gtk_widget_register_window ( widget , priv - > view_window ) ;
attributes . x = get_bin_window_x ( stack , & allocation ) ;
2016-01-26 15:36:13 +00:00
attributes . y = get_bin_window_y ( stack , & allocation ) ;
2013-04-21 11:51:14 +00:00
attributes . width = allocation . width ;
attributes . height = allocation . height ;
2014-08-11 14:49:46 +00:00
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info = l - > data ;
attributes . event_mask | = gtk_widget_get_events ( info - > widget ) ;
}
2013-04-21 11:51:14 +00:00
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 ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
gtk_widget_unregister_window ( widget , priv - > bin_window ) ;
gdk_window_destroy ( priv - > bin_window ) ;
2016-01-26 13:02:55 +00:00
priv - > bin_window = NULL ;
gtk_widget_unregister_window ( widget , priv - > view_window ) ;
gdk_window_destroy ( priv - > view_window ) ;
2013-04-21 11:51:14 +00:00
priv - > view_window = NULL ;
GTK_WIDGET_CLASS ( gtk_stack_parent_class ) - > unrealize ( widget ) ;
}
2016-01-26 13:02:55 +00:00
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 ) ;
}
2013-04-21 11:51:14 +00:00
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 ;
2015-05-06 13:19:55 +00:00
object_class - > dispose = gtk_stack_dispose ;
2013-04-21 11:51:14 +00:00
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 ;
2016-01-26 13:02:55 +00:00
widget_class - > map = gtk_stack_map ;
widget_class - > unmap = gtk_stack_unmap ;
2013-04-21 11:51:14 +00:00
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 ) ;
2014-06-07 03:30:44 +00:00
stack_props [ PROP_HOMOGENEOUS ] =
g_param_spec_boolean ( " homogeneous " , P_ ( " Homogeneous " ) , P_ ( " Homogeneous sizing " ) ,
2014-10-26 18:59:21 +00:00
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 ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-10-26 18:59:21 +00:00
/**
* 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 " ) ,
2014-06-07 03:30:44 +00:00
TRUE ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
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 ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
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 ,
2015-11-11 12:51:02 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2014-06-07 03:30:44 +00:00
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 ) ;
2015-07-19 15:39:41 +00:00
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 ,
2015-11-09 14:27:40 +00:00
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY ) ;
2015-07-19 15:39:41 +00:00
2013-11-05 10:11:35 +00:00
g_object_class_install_properties ( object_class , LAST_PROP , stack_props ) ;
2013-04-21 11:51:14 +00:00
2015-09-07 22:53:25 +00:00
stack_child_props [ CHILD_PROP_NAME ] =
2013-04-21 11:51:14 +00:00
g_param_spec_string ( " name " ,
P_ ( " Name " ) ,
P_ ( " The name of the child page " ) ,
NULL ,
2015-09-07 22:53:25 +00:00
GTK_PARAM_READWRITE ) ;
2013-04-21 11:51:14 +00:00
2015-09-07 22:53:25 +00:00
stack_child_props [ CHILD_PROP_TITLE ] =
2013-04-21 11:51:14 +00:00
g_param_spec_string ( " title " ,
P_ ( " Title " ) ,
P_ ( " The title of the child page " ) ,
NULL ,
2015-09-07 22:53:25 +00:00
GTK_PARAM_READWRITE ) ;
2013-04-21 11:51:14 +00:00
2015-09-07 22:53:25 +00:00
stack_child_props [ CHILD_PROP_ICON_NAME ] =
2013-04-21 11:51:14 +00:00
g_param_spec_string ( " icon-name " ,
P_ ( " Icon name " ) ,
P_ ( " The icon name of the child page " ) ,
NULL ,
2015-09-07 22:53:25 +00:00
GTK_PARAM_READWRITE ) ;
2013-04-21 11:51:14 +00:00
2015-09-07 22:53:25 +00:00
stack_child_props [ CHILD_PROP_POSITION ] =
2013-04-21 11:51:14 +00:00
g_param_spec_int ( " position " ,
P_ ( " Position " ) ,
P_ ( " The index of the child in the parent " ) ,
2015-09-07 22:53:25 +00:00
- 1 , G_MAXINT ,
0 ,
GTK_PARAM_READWRITE ) ;
2013-08-30 20:32:42 +00:00
/**
* 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
*/
2015-09-07 22:53:25 +00:00
stack_child_props [ CHILD_PROP_NEEDS_ATTENTION ] =
2013-08-30 20:32:42 +00:00
g_param_spec_boolean ( " needs-attention " ,
P_ ( " Needs Attention " ) ,
P_ ( " Whether this page needs attention " ) ,
FALSE ,
2015-09-07 22:53:25 +00:00
GTK_PARAM_READWRITE ) ;
gtk_container_class_install_child_properties ( container_class , LAST_CHILD_PROP , stack_child_props ) ;
2015-11-04 04:19:28 +00:00
2016-05-29 11:51:02 +00:00
gtk_widget_class_set_accessible_type ( widget_class , GTK_TYPE_STACK_ACCESSIBLE ) ;
2015-11-04 04:19:28 +00:00
gtk_widget_class_set_css_name ( widget_class , " stack " ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_new :
*
* Creates a new # GtkStack container .
*
* Returns : a new # GtkStack
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
GtkWidget *
gtk_stack_new ( void )
{
return g_object_new ( GTK_TYPE_STACK , NULL ) ;
}
static GtkStackChildInfo *
find_child_info_for_widget ( GtkStack * stack ,
GtkWidget * child )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 ;
2013-04-22 00:17:40 +00:00
/* Keep trying to find the current position and link location of the child */
2013-04-21 11:51:14 +00:00
if ( info - > widget = = child )
{
old_link = l ;
child_info = info ;
}
}
2014-11-10 23:45:58 +00:00
l = l - > next ;
2013-04-21 11:51:14 +00:00
num + + ;
}
g_return_if_fail ( old_link ! = NULL ) ;
2014-11-10 23:45:58 +00:00
if ( old_link = = new_link | | ( old_link - > next = = NULL & & new_link = = NULL ) )
2013-04-21 11:51:14 +00:00
return ;
priv - > children = g_list_delete_link ( priv - > children , old_link ) ;
priv - > children = g_list_insert_before ( priv - > children , new_link , child_info ) ;
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( GTK_CONTAINER ( stack ) , child , stack_child_props [ CHILD_PROP_POSITION ] ) ;
2013-04-21 11:51:14 +00:00
}
static void
gtk_stack_get_child_property ( GtkContainer * container ,
GtkWidget * child ,
guint property_id ,
GValue * value ,
GParamSpec * pspec )
{
GtkStack * stack = GTK_STACK ( container ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 :
2014-11-10 23:45:58 +00:00
g_value_set_int ( value , g_list_index ( priv - > children , info ) ) ;
2013-04-21 11:51:14 +00:00
break ;
2013-08-30 20:32:42 +00:00
case CHILD_PROP_NEEDS_ATTENTION :
g_value_set_boolean ( value , info - > needs_attention ) ;
break ;
2013-04-21 11:51:14 +00:00
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 ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkStackChildInfo * info ;
2013-04-22 00:41:22 +00:00
GtkStackChildInfo * info2 ;
gchar * name ;
GList * l ;
2013-04-21 11:51:14 +00:00
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 :
2013-04-22 00:41:22 +00:00
name = g_value_dup_string ( value ) ;
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
info2 = l - > data ;
2014-11-18 12:36:16 +00:00
if ( info = = info2 )
continue ;
2013-04-22 00:41:22 +00:00
if ( g_strcmp0 ( info2 - > name , name ) = = 0 )
{
2016-02-28 16:06:25 +00:00
g_warning ( " Duplicate child name in GtkStack: %s " , name ) ;
2013-04-22 00:41:22 +00:00
break ;
}
}
2013-04-21 11:51:14 +00:00
g_free ( info - > name ) ;
2013-04-22 00:41:22 +00:00
info - > name = name ;
2013-04-21 11:51:14 +00:00
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( container , child , pspec ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child = = info )
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_VISIBLE_CHILD_NAME ] ) ;
2013-04-21 11:51:14 +00:00
break ;
case CHILD_PROP_TITLE :
g_free ( info - > title ) ;
info - > title = g_value_dup_string ( value ) ;
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( container , child , pspec ) ;
2013-04-21 11:51:14 +00:00
break ;
case CHILD_PROP_ICON_NAME :
g_free ( info - > icon_name ) ;
info - > icon_name = g_value_dup_string ( value ) ;
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( container , child , pspec ) ;
2013-04-21 11:51:14 +00:00
break ;
case CHILD_PROP_POSITION :
reorder_child ( stack , child , g_value_get_int ( value ) ) ;
break ;
2013-08-30 20:32:42 +00:00
case CHILD_PROP_NEEDS_ATTENTION :
info - > needs_attention = g_value_get_boolean ( value ) ;
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( container , child , pspec ) ;
2013-08-30 20:32:42 +00:00
break ;
2013-04-21 11:51:14 +00:00
default :
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID ( container , property_id , pspec ) ;
break ;
}
}
2014-03-19 00:49:46 +00:00
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 | |
2014-03-19 03:42:59 +00:00
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 ) ;
2014-03-19 00:49:46 +00:00
}
/* 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 ;
2014-03-19 03:42:59 +00:00
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 ;
2014-05-02 21:15:49 +00:00
default : ;
2014-03-19 00:49:46 +00:00
}
return transition_type ;
}
2013-04-21 11:51:14 +00:00
static gint
2015-12-09 04:03:38 +00:00
get_bin_window_x ( GtkStack * stack ,
const GtkAllocation * allocation )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
int x = 0 ;
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
2014-03-19 00:49:46 +00:00
if ( is_left_transition ( priv - > active_transition_type ) )
2016-03-01 06:24:39 +00:00
x = allocation - > width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2014-03-19 00:49:46 +00:00
if ( is_right_transition ( priv - > active_transition_type ) )
2016-03-01 06:24:39 +00:00
x = - allocation - > width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-04-21 11:51:14 +00:00
}
return x ;
}
2013-04-22 00:17:40 +00:00
static gint
2015-12-09 04:03:38 +00:00
get_bin_window_y ( GtkStack * stack ,
const GtkAllocation * allocation )
2013-04-22 00:17:40 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-22 00:17:40 +00:00
int y = 0 ;
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-22 00:17:40 +00:00
{
2014-03-19 00:49:46 +00:00
if ( is_up_transition ( priv - > active_transition_type ) )
2016-03-01 06:24:39 +00:00
y = allocation - > height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2014-03-19 00:49:46 +00:00
if ( is_down_transition ( priv - > active_transition_type ) )
2016-03-01 06:24:39 +00:00
y = - allocation - > height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-04-22 00:17:40 +00:00
}
return y ;
}
2016-03-01 06:24:39 +00:00
static void
gtk_stack_progress_updated ( GtkStack * stack )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
gtk_widget_queue_draw ( GTK_WIDGET ( stack ) ) ;
2015-05-24 19:27:33 +00:00
if ( ! priv - > vhomogeneous | | ! priv - > hhomogeneous )
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > bin_window ! = NULL & &
2014-03-19 00:49:46 +00:00
is_window_moving_transition ( priv - > active_transition_type ) )
2013-04-21 11:51:14 +00:00
{
GtkAllocation allocation ;
gtk_widget_get_allocation ( GTK_WIDGET ( stack ) , & allocation ) ;
gdk_window_move ( priv - > bin_window ,
2013-04-22 00:17:40 +00:00
get_bin_window_x ( stack , & allocation ) , get_bin_window_y ( stack , & allocation ) ) ;
2013-04-21 11:51:14 +00:00
}
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) = = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
if ( priv - > last_visible_surface ! = NULL )
{
cairo_surface_destroy ( priv - > last_visible_surface ) ;
priv - > last_visible_surface = NULL ;
}
2015-05-24 19:15:44 +00:00
if ( priv - > last_visible_child ! = NULL )
{
gtk_widget_set_child_visible ( priv - > last_visible_child - > widget , FALSE ) ;
priv - > last_visible_child = NULL ;
}
2013-04-21 11:51:14 +00:00
}
}
static gboolean
2014-04-16 13:36:22 +00:00
gtk_stack_transition_cb ( GtkWidget * widget ,
2013-04-21 11:51:14 +00:00
GdkFrameClock * frame_clock ,
gpointer user_data )
{
2014-04-16 13:36:22 +00:00
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2016-03-02 01:19:50 +00:00
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 ;
2013-04-21 11:51:14 +00:00
/* Finish animation early if not mapped anymore */
2015-05-24 19:08:00 +00:00
if ( ! gtk_widget_get_mapped ( widget ) )
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_finish ( & priv - > tracker ) ;
gtk_stack_progress_updated ( GTK_STACK ( widget ) ) ;
2013-04-21 11:51:14 +00:00
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) = = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
priv - > tick_id = 0 ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
return FALSE ;
}
return TRUE ;
}
static void
gtk_stack_schedule_ticks ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > tick_id = = 0 )
{
priv - > tick_id =
2014-04-16 13:36:22 +00:00
gtk_widget_add_tick_callback ( GTK_WIDGET ( stack ) , gtk_stack_transition_cb , stack , NULL ) ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
}
}
static void
gtk_stack_unschedule_ticks ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > tick_id ! = 0 )
{
gtk_widget_remove_tick_callback ( GTK_WIDGET ( stack ) , priv - > tick_id ) ;
priv - > tick_id = 0 ;
2013-11-11 21:38:35 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_TRANSITION_RUNNING ] ) ;
2013-04-21 11:51:14 +00:00
}
}
2013-04-21 23:53:57 +00:00
static GtkStackTransitionType
effective_transition_type ( GtkStack * stack ,
GtkStackTransitionType transition_type )
{
if ( gtk_widget_get_direction ( GTK_WIDGET ( stack ) ) = = GTK_TEXT_DIR_RTL )
{
2014-03-19 00:49:46 +00:00
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 ;
2014-05-02 21:15:49 +00:00
default : ;
2014-03-19 00:49:46 +00:00
}
2013-04-21 23:53:57 +00:00
}
return transition_type ;
}
2013-04-21 11:51:14 +00:00
static void
2013-04-21 18:22:35 +00:00
gtk_stack_start_transition ( GtkStack * stack ,
GtkStackTransitionType transition_type ,
guint transition_duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkWidget * widget = GTK_WIDGET ( stack ) ;
if ( gtk_widget_get_mapped ( widget ) & &
2016-05-01 04:39:55 +00:00
gtk_settings_get_enable_animations ( gtk_widget_get_settings ( widget ) ) & &
2013-04-21 18:22:35 +00:00
transition_type ! = GTK_STACK_TRANSITION_TYPE_NONE & &
transition_duration ! = 0 & &
2013-04-21 11:51:14 +00:00
priv - > last_visible_child ! = NULL )
{
2013-04-21 23:53:57 +00:00
priv - > active_transition_type = effective_transition_type ( stack , transition_type ) ;
2016-03-02 01:19:50 +00:00
priv - > first_frame_skipped = FALSE ;
2013-04-21 11:51:14 +00:00
gtk_stack_schedule_ticks ( stack ) ;
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_start ( & priv - > tracker ,
priv - > transition_duration * 1000 ,
0 ,
1.0 ) ;
2013-04-21 11:51:14 +00:00
}
else
{
gtk_stack_unschedule_ticks ( stack ) ;
2013-04-21 18:22:35 +00:00
priv - > active_transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
2016-03-01 06:24:39 +00:00
gtk_progress_tracker_finish ( & priv - > tracker ) ;
2013-04-21 11:51:14 +00:00
}
2016-05-13 07:22:20 +00:00
gtk_stack_progress_updated ( GTK_STACK ( widget ) ) ;
2013-04-21 11:51:14 +00:00
}
static void
2013-04-21 18:22:35 +00:00
set_visible_child ( GtkStack * stack ,
GtkStackChildInfo * child_info ,
GtkStackTransitionType transition_type ,
guint transition_duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkStackChildInfo * info ;
GtkWidget * widget = GTK_WIDGET ( stack ) ;
GList * l ;
2014-12-11 03:32:45 +00:00
GtkWidget * toplevel ;
GtkWidget * focus ;
gboolean contains_focus = FALSE ;
2013-04-21 11:51:14 +00:00
2014-02-16 21:22:59 +00:00
/* if we are being destroyed, do not bother with transitions
2015-06-23 10:44:31 +00:00
* and notifications
*/
if ( gtk_widget_in_destruction ( widget ) )
2014-02-16 21:22:59 +00:00
return ;
2013-04-21 11:51:14 +00:00
/* 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 ;
2014-12-11 03:32:45 +00:00
toplevel = gtk_widget_get_toplevel ( widget ) ;
if ( GTK_IS_WINDOW ( toplevel ) )
{
focus = gtk_window_get_focus ( GTK_WINDOW ( toplevel ) ) ;
if ( focus & &
priv - > visible_child & &
2015-02-15 02:11:54 +00:00
priv - > visible_child - > widget & &
2014-12-11 03:32:45 +00:00
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 ) ;
}
}
2013-04-21 11:51:14 +00:00
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 ) )
2015-05-24 14:55:34 +00:00
{
2015-11-05 03:06:09 +00:00
GtkAllocation allocation ;
2015-05-24 14:55:34 +00:00
priv - > last_visible_child = priv - > visible_child ;
2015-11-05 03:06:09 +00:00
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 ;
2015-05-24 14:55:34 +00:00
}
2013-04-21 11:51:14 +00:00
else
2015-05-24 14:55:34 +00:00
{
gtk_widget_set_child_visible ( priv - > visible_child - > widget , FALSE ) ;
}
2013-04-21 11:51:14 +00:00
}
2016-05-29 11:51:02 +00:00
gtk_stack_accessible_update_visible_child ( stack ,
priv - > visible_child ? priv - > visible_child - > widget : NULL ,
child_info ? child_info - > widget : NULL ) ;
2013-04-21 11:51:14 +00:00
priv - > visible_child = child_info ;
if ( child_info )
2014-12-11 03:32:45 +00:00
{
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 ) ;
}
}
2013-04-21 11:51:14 +00:00
2013-06-13 18:33:42 +00:00
if ( ( child_info = = NULL | | priv - > last_visible_child = = NULL ) & &
2014-03-19 00:49:46 +00:00
is_direction_dependent_transition ( transition_type ) )
2013-06-13 18:33:42 +00:00
{
transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
}
2014-03-19 00:49:46 +00:00
else if ( is_direction_dependent_transition ( transition_type ) )
2013-06-13 18:33:42 +00:00
{
gboolean i_first = FALSE ;
2014-11-10 23:45:58 +00:00
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
2013-06-13 18:33:42 +00:00
{
if ( child_info = = l - > data )
{
i_first = TRUE ;
break ;
}
if ( priv - > last_visible_child = = l - > data )
break ;
}
2014-03-19 00:49:46 +00:00
transition_type = get_simple_transition_type ( i_first , transition_type ) ;
2013-06-13 18:33:42 +00:00
}
2015-11-04 18:11:14 +00:00
if ( priv - > hhomogeneous & & priv - > vhomogeneous )
gtk_widget_queue_allocate ( widget ) ;
else
gtk_widget_queue_resize ( widget ) ;
2013-11-05 10:18:37 +00:00
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 ] ) ;
2013-04-21 11:51:14 +00:00
2013-04-21 18:22:35 +00:00
gtk_stack_start_transition ( stack , transition_type , transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
static void
stack_child_visibility_notify_cb ( GObject * obj ,
GParamSpec * pspec ,
gpointer user_data )
{
GtkStack * stack = GTK_STACK ( user_data ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
else if ( priv - > visible_child = = child_info & &
! gtk_widget_get_visible ( child ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , NULL , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
if ( child_info = = priv - > last_visible_child )
{
gtk_widget_set_child_visible ( priv - > last_visible_child - > widget , FALSE ) ;
priv - > last_visible_child = NULL ;
}
}
2013-04-21 14:14:46 +00:00
/**
* 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
*/
2013-04-21 11:51:14 +00:00
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 ) ;
}
2013-04-21 14:14:46 +00:00
/**
* 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
*/
2013-04-21 11:51:14 +00:00
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 ,
2015-05-24 19:12:34 +00:00
GtkWidget * child )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( container ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 ;
2013-08-30 20:32:42 +00:00
child_info - > needs_attention = FALSE ;
2014-12-11 03:32:45 +00:00
child_info - > last_focus = NULL ;
2013-04-21 11:51:14 +00:00
priv - > children = g_list_append ( priv - > children , child_info ) ;
2016-05-20 22:07:10 +00:00
gtk_widget_set_child_visible ( child , FALSE ) ;
2013-04-21 11:51:14 +00:00
gtk_widget_set_parent_window ( child , priv - > bin_window ) ;
gtk_widget_set_parent ( child , GTK_WIDGET ( stack ) ) ;
2014-08-11 14:49:46 +00:00
if ( priv - > bin_window )
gdk_window_set_events ( priv - > bin_window ,
gdk_window_get_events ( priv - > bin_window ) |
gtk_widget_get_events ( child ) ) ;
2013-04-21 11:51:14 +00:00
g_signal_connect ( child , " notify::visible " ,
G_CALLBACK ( stack_child_visibility_notify_cb ) , stack ) ;
2015-09-07 22:53:25 +00:00
gtk_container_child_notify_by_pspec ( container , child , stack_child_props [ CHILD_PROP_POSITION ] ) ;
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child = = NULL & &
gtk_widget_get_visible ( child ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
2014-10-26 18:59:21 +00:00
if ( priv - > hhomogeneous | | priv - > vhomogeneous | | priv - > visible_child = = child_info )
2013-04-21 11:51:14 +00:00
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
}
static void
gtk_stack_remove ( GtkContainer * container ,
GtkWidget * child )
{
GtkStack * stack = GTK_STACK ( container ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , NULL , priv - > transition_type , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
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 ) ;
2014-12-11 03:32:45 +00:00
if ( child_info - > last_focus )
g_object_remove_weak_pointer ( G_OBJECT ( child_info - > last_focus ) ,
( gpointer * ) & child_info - > last_focus ) ;
2013-04-21 11:51:14 +00:00
g_slice_free ( GtkStackChildInfo , child_info ) ;
2014-10-26 18:59:21 +00:00
if ( ( priv - > hhomogeneous | | priv - > vhomogeneous ) & & was_visible )
2013-04-21 11:51:14 +00:00
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
}
2014-01-20 08:32:37 +00:00
/**
* 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 .
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the requested child of the # GtkStack
2014-01-20 08:32:37 +00:00
*
* 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 ;
}
2013-04-21 14:14:46 +00:00
/**
* 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 .
*
2014-10-26 18:59:21 +00:00
* Since 3.16 , homogeneity can be controlled separately
* for horizontal and vertical size , with the
* # GtkStack : hhomogeneous and # GtkStack : vhomogeneous .
*
2013-04-21 14:14:46 +00:00
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_homogeneous ( GtkStack * stack ,
gboolean homogeneous )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
homogeneous = ! ! homogeneous ;
2014-10-26 18:59:21 +00:00
if ( ( priv - > hhomogeneous & & priv - > vhomogeneous ) = = homogeneous )
2013-04-21 11:51:14 +00:00
return ;
2014-10-26 18:59:21 +00:00
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 ] ) ;
}
2013-04-21 11:51:14 +00:00
if ( gtk_widget_get_visible ( GTK_WIDGET ( stack ) ) )
gtk_widget_queue_resize ( GTK_WIDGET ( stack ) ) ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) , stack_props [ PROP_HOMOGENEOUS ] ) ;
2014-10-26 18:59:21 +00:00
g_object_thaw_notify ( G_OBJECT ( stack ) ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_homogeneous :
* @ stack : a # GtkStack
*
* Gets whether @ stack is homogeneous .
* See gtk_stack_set_homogeneous ( ) .
*
2014-02-19 23:49:43 +00:00
* Returns : whether @ stack is homogeneous .
2013-04-21 14:14:46 +00:00
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
gboolean
gtk_stack_get_homogeneous ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
2014-10-26 18:59:21 +00:00
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 ;
2015-05-24 19:15:44 +00:00
2014-10-26 18:59:21 +00:00
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 ;
2015-05-24 19:15:44 +00:00
2014-10-26 18:59:21 +00:00
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 ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_transition_duration :
* @ stack : a # GtkStack
*
2013-04-22 14:24:20 +00:00
* Returns the amount of time ( in milliseconds ) that
2013-04-21 14:14:46 +00:00
* transitions between pages in @ stack will take .
*
* Returns : the transition duration
*
* Since : 3.10
*/
2013-04-22 01:31:29 +00:00
guint
2013-04-21 11:51:14 +00:00
gtk_stack_get_transition_duration ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , 0 ) ;
2013-07-02 11:43:20 +00:00
return priv - > transition_duration ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_transition_duration :
* @ stack : a # GtkStack
2013-04-22 03:13:16 +00:00
* @ duration : the new duration , in milliseconds
2013-04-21 14:14:46 +00:00
*
* Sets the duration that transitions between pages in @ stack
* will take .
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_transition_duration ( GtkStack * stack ,
2013-04-22 03:13:16 +00:00
guint duration )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-06-07 03:35:53 +00:00
if ( priv - > transition_duration = = duration )
return ;
2013-07-02 11:43:20 +00:00
priv - > transition_duration = duration ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_TRANSITION_DURATION ] ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_get_transition_type :
* @ stack : a # GtkStack
*
* Gets the type of animation that will be used
* for transitions between pages in @ stack .
*
2014-02-19 23:49:43 +00:00
* Returns : the current transition type of @ stack
2013-04-21 14:14:46 +00:00
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
GtkStackTransitionType
gtk_stack_get_transition_type ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , GTK_STACK_TRANSITION_TYPE_NONE ) ;
2013-07-02 11:43:20 +00:00
return priv - > transition_type ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* gtk_stack_set_transition_type :
* @ stack : a # GtkStack
2013-04-22 03:13:16 +00:00
* @ transition : the new transition type
2013-04-21 14:14:46 +00:00
*
* 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
*/
2013-04-21 11:51:14 +00:00
void
2013-04-21 14:14:46 +00:00
gtk_stack_set_transition_type ( GtkStack * stack ,
2013-04-22 03:13:16 +00:00
GtkStackTransitionType transition )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-06-07 03:35:53 +00:00
if ( priv - > transition_type = = transition )
return ;
2013-07-02 11:43:20 +00:00
priv - > transition_type = transition ;
2013-11-05 10:18:37 +00:00
g_object_notify_by_pspec ( G_OBJECT ( stack ) ,
stack_props [ PROP_TRANSITION_TYPE ] ) ;
2013-04-21 11:51:14 +00:00
}
2013-11-11 21:38:35 +00:00
/**
* gtk_stack_get_transition_running :
* @ stack : a # GtkStack
*
* Returns whether the @ stack is currently in a transition from one page to
* another .
*
2014-02-19 23:49:43 +00:00
* Returns : % TRUE if the transition is currently running , % FALSE otherwise .
2013-11-11 21:38:35 +00:00
*
* 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 ) ;
}
2015-07-19 15:39:41 +00:00
/**
* gtk_stack_set_interpolate_size :
* @ stack : A # GtkStack
2015-08-09 21:31:36 +00:00
* @ interpolate_size : the new value
2015-07-19 15:39:41 +00:00
*
* Sets whether or not @ stack will interpolate its size when
2016-02-08 21:49:01 +00:00
* changing the visible child . If the # GtkStack : interpolate - size
2015-12-15 14:48:16 +00:00
* 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 .
2015-07-19 15:39:41 +00:00
*
* 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
*
2015-12-15 14:48:16 +00:00
* Returns wether the # GtkStack is set up to interpolate between
2016-01-19 11:52:58 +00:00
* the sizes of children on page switch .
2015-12-15 14:48:16 +00:00
*
* Returns : % TRUE if child sizes are interpolated
2015-07-19 15:39:41 +00:00
*
* Since : 3.18
*/
gboolean
gtk_stack_get_interpolate_size ( GtkStack * stack )
{
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-07-20 13:55:40 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , FALSE ) ;
2015-07-19 15:39:41 +00:00
return priv - > interpolate_size ;
}
2013-04-21 11:51:14 +00:00
/**
* gtk_stack_get_visible_child :
* @ stack : a # GtkStack
*
2013-04-21 14:14:46 +00:00
* Gets the currently visible child of @ stack , or % NULL if
* there are no visible children .
2013-04-21 11:51:14 +00:00
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the visible child of the # GtkStack
2013-04-21 14:14:46 +00:00
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
GtkWidget *
gtk_stack_get_visible_child ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
2013-07-02 11:43:20 +00:00
return priv - > visible_child ? priv - > visible_child - > widget : NULL ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* 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 .
*
2015-11-24 08:44:08 +00:00
* Returns : ( transfer none ) ( nullable ) : the name of the visible child of the # GtkStack
2013-04-21 14:14:46 +00:00
*
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
const gchar *
gtk_stack_get_visible_child_name ( GtkStack * stack )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
g_return_val_if_fail ( GTK_IS_STACK ( stack ) , NULL ) ;
2013-07-02 11:43:20 +00:00
if ( priv - > visible_child )
return priv - > visible_child - > name ;
2013-04-21 11:51:14 +00:00
return NULL ;
}
2013-04-21 14:14:46 +00:00
/**
* 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 .
*
2014-03-07 03:50:40 +00:00
* Note that the @ child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
*
2013-04-21 14:14:46 +00:00
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_visible_child ( GtkStack * stack ,
GtkWidget * child )
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 )
2013-10-07 12:46:16 +00:00
{
g_warning ( " Given child of type '%s' not found in GtkStack " ,
G_OBJECT_TYPE_NAME ( child ) ) ;
return ;
}
2013-04-21 11:51:14 +00:00
if ( gtk_widget_get_visible ( child_info - > widget ) )
2013-04-21 18:22:35 +00:00
set_visible_child ( stack , child_info ,
2013-07-02 11:43:20 +00:00
priv - > transition_type ,
priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
2013-04-21 14:14:46 +00:00
/**
* 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 .
*
2014-03-07 03:50:40 +00:00
* Note that the child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
*
2013-04-21 14:14:46 +00:00
* Since : 3.10
*/
2013-04-21 11:51:14 +00:00
void
gtk_stack_set_visible_child_name ( GtkStack * stack ,
const gchar * name )
2013-04-21 18:22:35 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2018-04-19 01:58:57 +00:00
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2013-07-02 11:43:20 +00:00
gtk_stack_set_visible_child_full ( stack , name , priv - > transition_type ) ;
2013-04-21 18:22:35 +00:00
}
/**
2013-04-22 15:19:54 +00:00
* gtk_stack_set_visible_child_full :
2013-04-21 18:22:35 +00:00
* @ stack : a # GtkStack
* @ name : the name of the child to make visible
2013-04-22 03:13:16 +00:00
* @ transition : the transition type to use
2013-04-21 18:22:35 +00:00
*
* Makes the child with the given name visible .
*
2014-03-07 03:50:40 +00:00
* Note that the child widget has to be visible itself
* ( see gtk_widget_show ( ) ) in order to become the visible
* child of @ stack .
*
2013-04-21 18:22:35 +00:00
* Since : 3.10
*/
void
gtk_stack_set_visible_child_full ( GtkStack * stack ,
const gchar * name ,
2013-04-22 03:13:16 +00:00
GtkStackTransitionType transition )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkStackChildInfo * child_info , * info ;
GList * l ;
g_return_if_fail ( GTK_IS_STACK ( stack ) ) ;
2014-11-25 05:14:47 +00:00
if ( name = = NULL )
return ;
2013-04-21 11:51:14 +00:00
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 ;
}
}
2013-10-07 12:46:16 +00:00
if ( child_info = = NULL )
{
g_warning ( " Child name '%s' not found in GtkStack " , name ) ;
return ;
}
if ( gtk_widget_get_visible ( child_info - > widget ) )
2013-04-22 03:13:16 +00:00
set_visible_child ( stack , child_info , transition , priv - > transition_duration ) ;
2013-04-21 11:51:14 +00:00
}
static void
gtk_stack_forall ( GtkContainer * container ,
gboolean include_internals ,
GtkCallback callback ,
gpointer callback_data )
{
GtkStack * stack = GTK_STACK ( container ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
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 ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2016-03-01 06:24:39 +00:00
gdouble progress = gtk_progress_tracker_get_progress ( & priv - > tracker , FALSE ) ;
2013-04-21 11:51:14 +00:00
2013-07-04 11:30:51 +00:00
cairo_push_group ( cr ) ;
gtk_container_propagate_draw ( GTK_CONTAINER ( stack ) ,
priv - > visible_child - > widget ,
cr ) ;
cairo_save ( cr ) ;
2016-03-01 06:24:39 +00:00
/* Multiply alpha by progress */
cairo_set_source_rgba ( cr , 1 , 1 , 1 , progress ) ;
2013-07-04 11:30:51 +00:00
cairo_set_operator ( cr , CAIRO_OPERATOR_DEST_IN ) ;
cairo_paint ( cr ) ;
2013-04-21 11:51:14 +00:00
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 ) ;
2016-03-01 06:24:39 +00:00
cairo_paint_with_alpha ( cr , MAX ( 1.0 - progress , 0 ) ) ;
2013-04-21 11:51:14 +00:00
}
2013-07-04 11:30:51 +00:00
cairo_restore ( cr ) ;
2013-04-21 11:51:14 +00:00
cairo_pop_group_to_source ( cr ) ;
2013-07-04 11:30:51 +00:00
cairo_set_operator ( cr , CAIRO_OPERATOR_OVER ) ;
cairo_paint ( cr ) ;
2013-04-21 11:51:14 +00:00
}
2013-08-31 16:00:47 +00:00
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 ;
2016-03-01 06:24:39 +00:00
height = allocation . height * ( gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
pos_y = height ;
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_UP :
2016-03-01 06:24:39 +00:00
y = allocation . height * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
height = allocation . height - y ;
pos_y = y - allocation . height ;
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT :
2016-03-01 06:24:39 +00:00
x = allocation . width * ( 1 - gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
width = allocation . width - x ;
pos_x = x - allocation . width ;
break ;
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT :
x = 0 ;
2016-03-01 06:24:39 +00:00
width = allocation . width * ( gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) ) ;
2013-08-31 16:00:47 +00:00
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 ) ;
}
}
2013-04-21 11:51:14 +00:00
static void
gtk_stack_draw_slide ( GtkWidget * widget ,
cairo_t * cr )
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2013-11-01 05:49:29 +00:00
if ( priv - > last_visible_surface & &
gtk_cairo_should_draw_window ( cr , priv - > view_window ) )
{
GtkAllocation allocation ;
int x , y ;
2013-04-21 11:51:14 +00:00
2013-11-01 05:49:29 +00:00
gtk_widget_get_allocation ( widget , & allocation ) ;
2013-04-22 00:17:40 +00:00
2013-11-01 05:49:29 +00:00
x = get_bin_window_x ( stack , & allocation ) ;
y = get_bin_window_y ( stack , & allocation ) ;
2013-04-22 00:17:40 +00:00
2013-11-01 05:49:29 +00:00
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 ;
}
2013-11-01 05:51:27 +00:00
x + = priv - > last_visible_surface_allocation . x ;
y + = priv - > last_visible_surface_allocation . y ;
2013-06-13 18:50:41 +00:00
2015-05-24 19:27:33 +00:00
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 ;
2013-04-21 11:51:14 +00:00
cairo_save ( cr ) ;
2013-04-22 00:17:40 +00:00
cairo_set_source_surface ( cr , priv - > last_visible_surface , x , y ) ;
2013-04-21 11:51:14 +00:00
cairo_paint ( cr ) ;
cairo_restore ( cr ) ;
}
2013-06-13 18:50:41 +00:00
if ( gtk_cairo_should_draw_window ( cr , priv - > bin_window ) )
gtk_container_propagate_draw ( GTK_CONTAINER ( stack ) ,
2015-05-24 19:12:34 +00:00
priv - > visible_child - > widget ,
cr ) ;
2013-04-21 11:51:14 +00:00
}
static gboolean
gtk_stack_draw ( GtkWidget * widget ,
cairo_t * cr )
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-12-09 04:03:38 +00:00
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 ) ;
2013-04-21 11:51:14 +00:00
cairo_t * pattern_cr ;
2014-07-12 05:16:33 +00:00
if ( gtk_cairo_should_draw_window ( cr , priv - > view_window ) )
{
GtkStyleContext * context ;
2015-05-24 19:15:44 +00:00
2014-07-12 05:16:33 +00:00
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 ) ) ;
}
2013-06-13 18:50:41 +00:00
if ( priv - > visible_child )
2013-04-21 11:51:14 +00:00
{
2016-03-01 06:24:39 +00:00
if ( gtk_progress_tracker_get_state ( & priv - > tracker ) ! = GTK_PROGRESS_STATE_AFTER )
2013-04-21 11:51:14 +00:00
{
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
2013-04-21 23:53:57 +00:00
* the bin_window offset
*/
2013-04-21 11:51:14 +00:00
gtk_widget_draw ( priv - > last_visible_child - > widget , pattern_cr ) ;
cairo_destroy ( pattern_cr ) ;
}
2016-01-21 00:44:47 +00:00
cairo_rectangle ( cr ,
0 , 0 ,
gtk_widget_get_allocated_width ( widget ) ,
gtk_widget_get_allocated_height ( widget ) ) ;
cairo_clip ( cr ) ;
2013-04-21 18:22:35 +00:00
switch ( priv - > active_transition_type )
2013-04-21 11:51:14 +00:00
{
case GTK_STACK_TRANSITION_TYPE_CROSSFADE :
2013-06-13 18:50:41 +00:00
if ( gtk_cairo_should_draw_window ( cr , priv - > bin_window ) )
gtk_stack_draw_crossfade ( widget , cr ) ;
2013-04-21 11:51:14 +00:00
break ;
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT :
case GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT :
2013-04-22 00:17:40 +00:00
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP :
case GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN :
2013-08-31 16:00:47 +00:00
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 :
2013-04-21 11:51:14 +00:00
gtk_stack_draw_slide ( widget , cr ) ;
break ;
2013-08-31 16:00:47 +00:00
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 ;
2013-04-21 11:51:14 +00:00
default :
g_assert_not_reached ( ) ;
}
}
2013-06-13 18:50:41 +00:00
else if ( gtk_cairo_should_draw_window ( cr , priv - > bin_window ) )
2013-04-21 11:51:14 +00:00
gtk_container_propagate_draw ( GTK_CONTAINER ( stack ) ,
priv - > visible_child - > widget ,
cr ) ;
}
2015-12-09 04:03:38 +00:00
return FALSE ;
2013-04-21 11:51:14 +00:00
}
static void
gtk_stack_size_allocate ( GtkWidget * widget ,
GtkAllocation * allocation )
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2015-12-09 04:03:38 +00:00
GtkAllocation clip ;
2013-04-21 11:51:14 +00:00
gtk_widget_set_allocation ( widget , allocation ) ;
2015-12-09 04:03:38 +00:00
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 ) ;
2015-11-30 15:35:04 +00:00
2013-04-21 11:51:14 +00:00
child_allocation . x = 0 ;
child_allocation . y = 0 ;
2016-02-26 20:58:36 +00:00
2016-11-02 09:08:17 +00:00
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 ) ;
}
2015-05-24 19:27:33 +00:00
2013-04-21 11:51:14 +00:00
if ( priv - > last_visible_child )
2016-03-19 02:27:31 +00:00
{
int min , nat ;
2016-02-26 20:58:36 +00:00
gtk_widget_get_preferred_width ( priv - > last_visible_child - > widget , & min , & nat ) ;
child_allocation . width = MAX ( min , allocation - > width ) ;
2016-03-19 02:27:31 +00:00
gtk_widget_get_preferred_height_for_width ( priv - > last_visible_child - > widget ,
2016-02-26 20:58:36 +00:00
child_allocation . width ,
2016-03-19 02:27:31 +00:00
& min , & nat ) ;
2016-02-26 20:58:36 +00:00
child_allocation . height = MAX ( min , allocation - > height ) ;
2016-03-19 02:27:31 +00:00
gtk_widget_size_allocate ( priv - > last_visible_child - > widget , & child_allocation ) ;
}
2013-04-21 11:51:14 +00:00
2016-02-26 20:58:36 +00:00
child_allocation . width = allocation - > width ;
child_allocation . height = allocation - > height ;
2013-04-21 11:51:14 +00:00
if ( priv - > visible_child )
2015-05-24 19:27:33 +00:00
{
int min , nat ;
2015-05-30 13:43:56 +00:00
GtkAlign valign ;
2015-05-24 19:27:33 +00:00
gtk_widget_get_preferred_height_for_width ( priv - > visible_child - > widget ,
allocation - > width ,
& min , & nat ) ;
2015-07-19 15:39:41 +00:00
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 ;
}
2016-02-26 20:58:22 +00:00
gtk_widget_size_allocate ( priv - > visible_child - > widget , & child_allocation ) ;
2015-05-24 19:27:33 +00:00
}
2015-12-09 04:03:38 +00:00
gtk_container_get_children_clip ( GTK_CONTAINER ( widget ) , out_clip ) ;
}
2015-05-24 19:27:33 +00:00
2013-04-21 11:51:14 +00:00
static void
2015-12-09 04:03:38 +00:00
gtk_stack_get_preferred_width ( GtkWidget * widget ,
gint * minimum ,
gint * natural )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
gtk_css_gadget_get_preferred_size ( priv - > gadget ,
GTK_ORIENTATION_HORIZONTAL ,
- 1 ,
minimum , natural ,
NULL , NULL ) ;
}
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
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 ) ;
2015-05-24 19:15:44 +00:00
2015-12-09 04:03:38 +00:00
gtk_css_gadget_get_preferred_size ( priv - > gadget ,
GTK_ORIENTATION_HORIZONTAL ,
height ,
minimum , natural ,
NULL , NULL ) ;
}
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
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 ) ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
gtk_css_gadget_get_preferred_size ( priv - > gadget ,
GTK_ORIENTATION_VERTICAL ,
- 1 ,
minimum , natural ,
NULL , NULL ) ;
2013-04-21 11:51:14 +00:00
}
static void
gtk_stack_get_preferred_height_for_width ( GtkWidget * widget ,
gint width ,
2015-12-09 04:03:38 +00:00
gint * minimum ,
gint * natural )
2013-04-21 11:51:14 +00:00
{
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
gtk_css_gadget_get_preferred_size ( priv - > gadget ,
GTK_ORIENTATION_VERTICAL ,
width ,
minimum , natural ,
NULL , NULL ) ;
2013-04-21 11:51:14 +00:00
}
2015-12-09 04:03:38 +00:00
# define LERP(a, b, t) ((a) + (((b) - (a)) * (1.0 - (t))))
2013-04-21 11:51:14 +00:00
static void
2015-12-09 04:03:38 +00:00
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 ) ;
2013-04-21 11:51:14 +00:00
GtkStack * stack = GTK_STACK ( widget ) ;
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
GtkStackChildInfo * child_info ;
GtkWidget * child ;
gint child_min , child_nat ;
GList * l ;
2015-12-09 04:03:38 +00:00
* minimum = 0 ;
* natural = 0 ;
2013-04-21 11:51:14 +00:00
for ( l = priv - > children ; l ! = NULL ; l = l - > next )
{
child_info = l - > data ;
child = child_info - > widget ;
2015-12-09 04:03:38 +00:00
if ( ( ( orientation = = GTK_ORIENTATION_VERTICAL & & ! priv - > vhomogeneous ) | |
( orientation = = GTK_ORIENTATION_HORIZONTAL & & ! priv - > hhomogeneous ) ) & &
2015-05-24 19:15:44 +00:00
priv - > visible_child ! = child_info )
2013-04-21 11:51:14 +00:00
continue ;
2015-12-09 04:03:38 +00:00
2013-04-21 11:51:14 +00:00
if ( gtk_widget_get_visible ( child ) )
{
2015-12-09 04:03:38 +00:00
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 ) ;
}
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
* minimum = MAX ( * minimum , child_min ) ;
* natural = MAX ( * natural , child_nat ) ;
2013-04-21 11:51:14 +00:00
}
}
2015-12-09 04:03:38 +00:00
if ( priv - > last_visible_child ! = NULL )
2013-04-21 11:51:14 +00:00
{
2015-12-09 04:03:38 +00:00
if ( orientation = = GTK_ORIENTATION_VERTICAL & & ! priv - > vhomogeneous )
{
2016-03-01 06:24:39 +00:00
gdouble t = priv - > interpolate_size ? gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) : 1.0 ;
2015-12-09 04:03:38 +00:00
* 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 )
{
2016-03-01 06:24:39 +00:00
gdouble t = priv - > interpolate_size ? gtk_progress_tracker_get_ease_out_cubic ( & priv - > tracker , FALSE ) : 1.0 ;
2015-12-09 04:03:38 +00:00
* minimum = LERP ( * minimum , priv - > last_visible_widget_width , t ) ;
* natural = LERP ( * natural , priv - > last_visible_widget_width , t ) ;
}
2013-04-21 11:51:14 +00:00
}
}
static void
2015-12-09 04:03:38 +00:00
gtk_stack_init ( GtkStack * stack )
2013-04-21 11:51:14 +00:00
{
2013-07-02 11:43:20 +00:00
GtkStackPrivate * priv = gtk_stack_get_instance_private ( stack ) ;
2013-04-21 11:51:14 +00:00
2016-01-26 13:02:55 +00:00
gtk_widget_set_has_window ( GTK_WIDGET ( stack ) , FALSE ) ;
2015-12-09 04:03:38 +00:00
priv - > vhomogeneous = TRUE ;
priv - > hhomogeneous = TRUE ;
priv - > transition_duration = 200 ;
priv - > transition_type = GTK_STACK_TRANSITION_TYPE_NONE ;
2013-04-21 11:51:14 +00:00
2015-12-09 04:03:38 +00:00
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 ) ;
2013-04-21 11:51:14 +00:00
}