static void gtk_revealer_real_realize (GtkWidget *widget) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkAllocation allocation; GdkWindowAttr attributes = { 0 }; GdkWindowAttributesType attributes_mask; GtkAllocation child_allocation; GtkWidget *child; GtkStyleContext *context; GtkRevealerTransitionType transition; gtk_widget_set_realized (widget, TRUE); gtk_widget_get_allocation (widget, &allocation); 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) | GDK_EXPOSURE_MASK; attributes_mask = (GDK_WA_X | GDK_WA_Y) | GDK_WA_VISUAL; priv->view_window = gdk_window_new (gtk_widget_get_parent_window ((GtkWidget*) revealer), &attributes, attributes_mask); gtk_widget_set_window (widget, priv->view_window); gtk_widget_register_window (widget, priv->view_window); gtk_revealer_get_child_allocation (revealer, &allocation, &child_allocation); attributes.x = 0; attributes.y = 0; attributes.width = child_allocation.width; attributes.height = child_allocation.height; transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) attributes.y = allocation.height - child_allocation.height; else if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) attributes.x = allocation.width - child_allocation.width; priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask); gtk_widget_register_window (widget, priv->bin_window); child = gtk_bin_get_child (GTK_BIN (revealer)); if (child != NULL) gtk_widget_set_parent_window (child, priv->bin_window); context = gtk_widget_get_style_context (widget); gtk_style_context_set_background (context, priv->view_window); gtk_style_context_set_background (context, priv->bin_window); gdk_window_show (priv->bin_window); }
static void gtk_revealer_real_get_preferred_width_for_height (GtkWidget *widget, gint height, gint *minimum_width_out, gint *natural_width_out) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gint minimum_width; gint natural_width; GtkRevealerTransitionType transition; GTK_WIDGET_CLASS (gtk_revealer_parent_class)->get_preferred_width_for_height (widget, height, &minimum_width, &natural_width); transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT || transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) natural_width = round (natural_width * priv->current_pos); minimum_width = MIN (minimum_width, natural_width); if (minimum_width_out) *minimum_width_out = minimum_width; if (natural_width_out) *natural_width_out = natural_width; }
static void gtk_revealer_real_get_preferred_height_for_width (GtkWidget *widget, gint width, gint *minimum_height_out, gint *natural_height_out) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gint minimum_height; gint natural_height; GtkRevealerTransitionType transition; GTK_WIDGET_CLASS (gtk_revealer_parent_class)->get_preferred_height_for_width (widget, width, &minimum_height, &natural_height); transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP || transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) natural_height = round (natural_height * priv->current_pos); minimum_height = MIN (minimum_height, natural_height); if (minimum_height_out) *minimum_height_out = minimum_height; if (natural_height_out) *natural_height_out = natural_height; }
static void gtk_revealer_start_animation (GtkRevealer *revealer, gdouble target) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkWidget *widget = GTK_WIDGET (revealer); GtkRevealerTransitionType transition; if (priv->target_pos == target) return; priv->target_pos = target; g_object_notify (G_OBJECT (revealer), "reveal-child"); transition = effective_transition (revealer); if (gtk_widget_get_mapped (widget) && priv->transition_duration != 0 && transition != GTK_REVEALER_TRANSITION_TYPE_NONE) { priv->source_pos = priv->current_pos; priv->start_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget)); priv->end_time = priv->start_time + (priv->transition_duration * 1000); if (priv->tick_id == 0) priv->tick_id = gtk_widget_add_tick_callback (widget, (GtkTickCallback)gtk_revealer_animate_cb, revealer, NULL); gtk_revealer_animate_step (revealer, priv->start_time); } else { gtk_revealer_set_position (revealer, target); } }
static void set_width_with_paddings (GtkRevealer *revealer, gint preferred_minimum_width, gint preferred_natural_width, gint *minimum_width_out, gint *natural_width_out) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gint minimum_width; gint natural_width; GtkRevealerTransitionType transition; GtkBorder padding; gint horizontal_padding; gtk_revealer_get_padding (revealer, &padding); horizontal_padding = padding.left + padding.right; minimum_width = preferred_minimum_width + horizontal_padding; natural_width = preferred_natural_width + horizontal_padding; transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT || transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) { /* Paddings are included in the animation */ minimum_width = round (minimum_width * priv->current_pos); natural_width = round (natural_width * priv->current_pos); } *minimum_width_out = MIN (minimum_width, natural_width); *natural_width_out = natural_width; }
static void set_height_with_paddings (GtkRevealer *revealer, gint preferred_minimum_height, gint preferred_natural_height, gint *minimum_height_out, gint *natural_height_out) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gint minimum_height; gint natural_height; GtkRevealerTransitionType transition; GtkBorder padding; gint vertical_padding; gtk_revealer_get_padding (revealer, &padding); vertical_padding = padding.top + padding.bottom; minimum_height = preferred_minimum_height + vertical_padding; natural_height = preferred_natural_height + vertical_padding; transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_NONE || transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP || transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) { /* Padding are included in the animation */ minimum_height = round (minimum_height * priv->current_pos); natural_height = round (natural_height * priv->current_pos); } *minimum_height_out = MIN (minimum_height, natural_height); *natural_height_out = natural_height; }
/** * gtk_revealer_get_reveal_child: * @revealer: a #GtkRevealer * * Returns whether the child is currently * revealed. See gtk_revealer_set_reveal_child(). * * This function returns %TRUE as soon as the transition * is to the revealed state is started. To learn whether * the child is fully revealed (ie the transition is completed), * use gtk_revealer_get_child_revealed(). * * Return value: %TRUE if the child is revealed. * * Since: 3.10 */ gboolean gtk_revealer_get_reveal_child (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_val_if_fail (GTK_IS_REVEALER (revealer), FALSE); return priv->target_pos != 0.0; }
/** * gtk_revealer_get_transition_duration: * @revealer: a #GtkRevealer * * Returns the amount of time (in milliseconds) that * transitions will take. * * Returns: the transition duration * * Since: 3.10 */ guint gtk_revealer_get_transition_duration (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_val_if_fail (GTK_IS_REVEALER (revealer), 0); return priv->transition_duration; }
/** * gtk_revealer_get_transition_type: * @revealer: a #GtkRevealer * * Gets the type of animation that will be used * for transitions in @revealer. * * Return value: the current transition type of @revealer * * Since: 3.10 */ GtkRevealerTransitionType gtk_revealer_get_transition_type (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_val_if_fail (GTK_IS_REVEALER (revealer), GTK_REVEALER_TRANSITION_TYPE_NONE); return priv->transition_type; }
/** * gtk_revealer_set_transition_duration: * @revealer: a #GtkRevealer * @duration: the new duration, in milliseconds * * Sets the duration that transitions will take. * * Since: 3.10 */ void gtk_revealer_set_transition_duration (GtkRevealer *revealer, guint value) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_if_fail (GTK_IS_REVEALER (revealer)); priv->transition_duration = value; g_object_notify (G_OBJECT (revealer), "transition-duration"); }
/** * gtk_revealer_get_child_revealed: * @revealer: a #GtkRevealer * * Returns whether the child is fully revealed, ie wether * the transition to the revealed state is completed. * * Return value: %TRUE if the child is fully revealed * * Since: 3.10 */ gboolean gtk_revealer_get_child_revealed (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gboolean animation_finished = (priv->target_pos == priv->current_pos); gboolean reveal_child = gtk_revealer_get_reveal_child (revealer); if (animation_finished) return reveal_child; else return !reveal_child; }
static void gtk_revealer_real_unrealize (GtkWidget *widget) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gtk_widget_unregister_window (widget, priv->bin_window); gdk_window_destroy (priv->bin_window); priv->view_window = NULL; GTK_WIDGET_CLASS (gtk_revealer_parent_class)->unrealize (widget); }
static void gtk_revealer_finalize (GObject *obj) { GtkRevealer *revealer = GTK_REVEALER (obj); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); if (priv->tick_id != 0) gtk_widget_remove_tick_callback (GTK_WIDGET (revealer), priv->tick_id); priv->tick_id = 0; G_OBJECT_CLASS (gtk_revealer_parent_class)->finalize (obj); }
static gboolean gtk_revealer_real_draw (GtkWidget *widget, cairo_t *cr) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); if (gtk_cairo_should_draw_window (cr, priv->bin_window)) GTK_WIDGET_CLASS (gtk_revealer_parent_class)->draw (widget, cr); return TRUE; }
static void gtk_revealer_stop_animation (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); priv->current_pos = priv->target_pos; if (priv->tick_id != 0) { gtk_widget_remove_tick_callback (GTK_WIDGET (revealer), priv->tick_id); priv->tick_id = 0; } }
/** * gtk_revealer_set_transition_type: * @revealer: a #GtkRevealer * @transition: the new transition type * * Sets the type of animation that will be used for * transitions in @revealer. Available types include * various kinds of fades and slides. * * Since: 3.10 */ void gtk_revealer_set_transition_type (GtkRevealer *revealer, GtkRevealerTransitionType transition) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_if_fail (GTK_IS_REVEALER (revealer)); priv->transition_type = transition; gtk_widget_queue_resize (GTK_WIDGET (revealer)); g_object_notify (G_OBJECT (revealer), "transition-type"); }
static void gtk_revealer_init (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); priv->transition_type = GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN; priv->transition_duration = 250; priv->current_pos = 0.0; priv->target_pos = 0.0; gtk_widget_set_has_window ((GtkWidget*) revealer, TRUE); gtk_widget_set_redraw_on_allocate ((GtkWidget*) revealer, FALSE); }
static void gtk_revealer_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkAllocation child_allocation; GtkWidget *child; gboolean window_visible; int bin_x, bin_y; GtkRevealerTransitionType transition; g_return_if_fail (allocation != NULL); gtk_widget_set_allocation (widget, allocation); gtk_revealer_get_child_allocation (revealer, allocation, &child_allocation); child = gtk_bin_get_child (GTK_BIN (revealer)); if (child != NULL && gtk_widget_get_visible (child)) gtk_widget_size_allocate (child, &child_allocation); if (gtk_widget_get_realized (widget)) { if (gtk_widget_get_mapped (widget)) { window_visible = allocation->width > 0 && allocation->height > 0; if (!window_visible && gdk_window_is_visible (priv->view_window)) gdk_window_hide (priv->view_window); if (window_visible && !gdk_window_is_visible (priv->view_window)) gdk_window_show (priv->view_window); } gdk_window_move_resize (priv->view_window, allocation->x, allocation->y, allocation->width, allocation->height); bin_x = 0; bin_y = 0; transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) bin_y = allocation->height - child_allocation.height; else if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) bin_x = allocation->width - child_allocation.width; gdk_window_move_resize (priv->bin_window, bin_x, bin_y, child_allocation.width, child_allocation.height); } }
/** * gtk_revealer_set_transition_duration: * @revealer: a #GtkRevealer * @duration: the new duration, in milliseconds * * Sets the duration that transitions will take. * * Since: 3.10 */ void gtk_revealer_set_transition_duration (GtkRevealer *revealer, guint value) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_if_fail (GTK_IS_REVEALER (revealer)); if (priv->transition_duration == value) return; priv->transition_duration = value; g_object_notify_by_pspec (G_OBJECT (revealer), props[PROP_TRANSITION_DURATION]); }
static void gtk_revealer_real_add (GtkContainer *container, GtkWidget *child) { GtkRevealer *revealer = GTK_REVEALER (container); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_if_fail (child != NULL); gtk_widget_set_parent_window (child, priv->bin_window); gtk_widget_set_child_visible (child, priv->current_pos != 0.0); GTK_CONTAINER_CLASS (gtk_revealer_parent_class)->add (container, child); }
/** * gtk_revealer_set_transition_type: * @revealer: a #GtkRevealer * @transition: the new transition type * * Sets the type of animation that will be used for * transitions in @revealer. Available types include * various kinds of fades and slides. * * Since: 3.10 */ void gtk_revealer_set_transition_type (GtkRevealer *revealer, GtkRevealerTransitionType transition) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); g_return_if_fail (GTK_IS_REVEALER (revealer)); if (priv->transition_type == transition) return; priv->transition_type = transition; gtk_widget_queue_resize (GTK_WIDGET (revealer)); g_object_notify_by_pspec (G_OBJECT (revealer), props[PROP_TRANSITION_TYPE]); }
static GtkRevealerTransitionType effective_transition (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); if (gtk_widget_get_direction (GTK_WIDGET (revealer)) == GTK_TEXT_DIR_RTL) { if (priv->transition_type == GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT) return GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT; else if (priv->transition_type == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) return GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT; } return priv->transition_type; }
static void gtk_revealer_animate_step (GtkRevealer *revealer, gint64 now) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gdouble t; t = 1.0; if (now < priv->end_time) t = (now - priv->start_time) / (gdouble) (priv->end_time - priv->start_time); t = ease_out_quad (t, 1.0); gtk_revealer_set_position (revealer, priv->source_pos + (t * (priv->target_pos - priv->source_pos))); }
static void gtk_revealer_real_style_updated (GtkWidget *widget) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkStyleContext* context; GTK_WIDGET_CLASS (gtk_revealer_parent_class)->style_updated (widget); if (gtk_widget_get_realized (widget)) { context = gtk_widget_get_style_context (widget); gtk_style_context_set_background (context, priv->bin_window); gtk_style_context_set_background (context, priv->view_window); } }
static void gtk_revealer_real_map (GtkWidget *widget) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkAllocation allocation; if (!gtk_widget_get_mapped (widget)) { gtk_widget_get_allocation (widget, &allocation); if (allocation.width > 0 && allocation.height > 0) gdk_window_show (priv->view_window); } GTK_WIDGET_CLASS (gtk_revealer_parent_class)->map (widget); }
static gboolean gtk_revealer_animate_cb (GtkRevealer *revealer, GdkFrameClock *frame_clock, gpointer user_data) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gint64 now; now = gdk_frame_clock_get_frame_time (frame_clock); gtk_revealer_animate_step (revealer, now); if (priv->current_pos == priv->target_pos) { priv->tick_id = 0; return FALSE; } return TRUE; }
static GtkRevealerTransitionType effective_transition (GtkRevealer *revealer) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gboolean animations_enabled; g_object_get (gtk_widget_get_settings (GTK_WIDGET (revealer)), "gtk-enable-animations", &animations_enabled, NULL); if (!animations_enabled) return GTK_REVEALER_TRANSITION_TYPE_NONE; if (gtk_widget_get_direction (GTK_WIDGET (revealer)) == GTK_TEXT_DIR_RTL) { if (priv->transition_type == GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT) return GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT; else if (priv->transition_type == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) return GTK_REVEALER_TRANSITION_TYPE_SLIDE_LEFT; } return priv->transition_type; }
static void gtk_revealer_set_position (GtkRevealer *revealer, gdouble pos) { GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); gboolean new_visible; GtkWidget *child; GtkRevealerTransitionType transition; priv->current_pos = pos; /* We check target_pos here too, because we want to ensure we set * child_visible immediately when starting a reveal operation * otherwise the child widgets will not be properly realized * after the reveal returns. */ new_visible = priv->current_pos != 0.0 || priv->target_pos != 0.0; child = gtk_bin_get_child (GTK_BIN (revealer)); if (child != NULL && new_visible != gtk_widget_get_child_visible (child)) gtk_widget_set_child_visible (child, new_visible); transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_CROSSFADE) { gtk_widget_set_opacity (GTK_WIDGET (revealer), priv->current_pos); gtk_widget_queue_draw (GTK_WIDGET (revealer)); } else { gtk_widget_queue_resize (GTK_WIDGET (revealer)); } if (priv->current_pos == priv->target_pos) g_object_notify (G_OBJECT (revealer), "child-revealed"); }
static void gtk_revealer_real_realize (GtkWidget *widget) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkAllocation allocation; GdkWindowAttr attributes = { 0 }; GdkWindowAttributesType attributes_mask; GtkAllocation child_allocation; GtkWidget *child; GtkRevealerTransitionType transition; GtkBorder padding; gtk_widget_set_realized (widget, TRUE); gtk_widget_get_allocation (widget, &allocation); 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_parent_window ((GtkWidget*) revealer), &attributes, attributes_mask); gtk_widget_set_window (widget, priv->view_window); gtk_widget_register_window (widget, priv->view_window); gtk_revealer_get_child_allocation (revealer, &allocation, &child_allocation); gtk_revealer_get_padding (revealer, &padding); attributes.x = 0; attributes.y = 0; attributes.width = child_allocation.width; attributes.height = child_allocation.height; /* See explanation on gtk_revealer_real_size_allocate */ transition = effective_transition (revealer); if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) { attributes.y = allocation.height - child_allocation.height - padding.bottom; attributes.x = padding.left; } else if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) { attributes.y = padding.top; attributes.x = allocation.width - child_allocation.width - padding.right; } else { attributes.y = padding.top; attributes.x = padding.left; } priv->bin_window = gdk_window_new (priv->view_window, &attributes, attributes_mask); gtk_widget_register_window (widget, priv->bin_window); child = gtk_bin_get_child (GTK_BIN (revealer)); if (child != NULL) gtk_widget_set_parent_window (child, priv->bin_window); gdk_window_show (priv->bin_window); }
static void gtk_revealer_real_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { GtkRevealer *revealer = GTK_REVEALER (widget); GtkRevealerPrivate *priv = gtk_revealer_get_instance_private (revealer); GtkAllocation child_allocation; GtkWidget *child; gboolean window_visible; int bin_x, bin_y; GtkRevealerTransitionType transition; GtkBorder padding; g_return_if_fail (allocation != NULL); gtk_widget_set_allocation (widget, allocation); gtk_revealer_get_child_allocation (revealer, allocation, &child_allocation); child = gtk_bin_get_child (GTK_BIN (revealer)); if (child != NULL && gtk_widget_get_visible (child)) gtk_widget_size_allocate (child, &child_allocation); if (gtk_widget_get_realized (widget)) { if (gtk_widget_get_mapped (widget)) { window_visible = allocation->width > 0 && allocation->height > 0; if (!window_visible && gdk_window_is_visible (priv->view_window)) gdk_window_hide (priv->view_window); if (window_visible && !gdk_window_is_visible (priv->view_window)) gdk_window_show (priv->view_window); } /* The view window will follow the revealer allocation, which is modified * along the animation */ gdk_window_move_resize (priv->view_window, allocation->x, allocation->y, allocation->width, allocation->height); gtk_revealer_get_padding (revealer, &padding); bin_x = 0; bin_y = 0; transition = effective_transition (revealer); /* The child allocation is fixed (it is not modified by the animation), * and it's origin is relative to the bin_window. * The bin_window has the same allocation as the child, and then the bin_window * deals with the relative positioning with respect to the revealer taking * into account the paddings of the revealer. * * For most of transitions, the bin_window moves along with the revealer, * as its allocation changes. * However for GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN * we need to first move the bin_window upwards and then slide it down in * the revealer. * Otherwise the child would appear as static and the revealer will allocate * following the animation, clipping the child. * To calculate the correct y position for this case: * allocation->height - child_allocation.height is the relative position * towards the revealer taking into account the animation progress with * both vertical paddings added, therefore we need to substract the part * that we don't want to take into account for the y position, which * in this case is the bottom padding. * * The same special treatment is needed for GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT. */ if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN) { bin_y = allocation->height - child_allocation.height - padding.bottom; bin_x = padding.left; } else if (transition == GTK_REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) { bin_y = padding.top; bin_x = allocation->width - child_allocation.width - padding.right; } else { bin_x = padding.left; bin_y = padding.top; } gdk_window_move_resize (priv->bin_window, bin_x, bin_y, child_allocation.width, child_allocation.height); } }