From 2d3c47b2282e70cf514c3e4fce9f7d8ca4d9ff6c Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Tue, 15 Jan 2013 18:15:52 +0000 Subject: [PATCH] Snapshot/WIP --- clutter/clutter-actor.c | 247 +++++++++++++++++++++++----------------- 1 file changed, 144 insertions(+), 103 deletions(-) diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index 6dc9ebc72..58a9c078e 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2362,7 +2362,6 @@ clutter_actor_set_allocation_internal (ClutterActor *self, gboolean x1_changed, y1_changed, x2_changed, y2_changed; gboolean retval; ClutterActorBox old_alloc = { 0, }; - ClutterLayoutInfo *layout_info; obj = G_OBJECT (self); @@ -2378,19 +2377,6 @@ clutter_actor_set_allocation_internal (ClutterActor *self, priv->allocation = *box; priv->allocation_flags = flags; - /* update the position (the origin of the actor in parent-relative - * coordinates) and the bounds (the painted rectangle of an actor, - * in actor-relative coordinates) - */ - layout_info = _clutter_actor_get_layout_info (self); - layout_info->position.x = box->x1 - layout_info->margin.left; - layout_info->position.y = box->y1 - layout_info->margin.top; - - layout_info->bounds.origin.x = layout_info->margin.left; - layout_info->bounds.origin.y = layout_info->margin.top; - layout_info->bounds.size.width = box->x2 - box->x1; - layout_info->bounds.size.height = box->y2 - box->y1; - /* allocation is authoritative */ priv->needs_width_request = FALSE; priv->needs_height_request = FALSE; @@ -9607,6 +9593,7 @@ clutter_actor_adjust_allocation (ClutterActor *self, float nat_width, nat_height; ClutterRequestMode req_mode; + /* operate on a copy */ adj_allocation = *allocation; clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height); @@ -9716,39 +9703,119 @@ clutter_actor_allocate_internal (ClutterActor *self, clutter_actor_queue_redraw (self); } +static inline void +clutter_actor_adjust_frame (ClutterActor *self, + const ClutterRect *frame, + ClutterRect *adjusted) +{ + ClutterRect adj; + ClutterSize minimum; + ClutterSize natural; + + /* operate on a copy */ + adj = *frame; + + /* we want to hit the cache, so we use the public API */ + if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) + { + clutter_actor_get_preferred_width (self, -1, + &minimum.width, + &natural.width); + clutter_actor_get_preferred_height (self, adj.size.width, + &minimum.height, + &natural.height); + } + else if (self->priv->request_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) + { + clutter_actor_get_preferred_height (self, -1, + &minimum.height, + &natural.height); + clutter_actor_get_preferred_width (self, adj.size.height, + &minimum.width, + &natural.width); + } + +#ifdef CLUTTER_ENABLE_DEBUG + /* warn about underallocations */ + if (_clutter_diagnostic_enabled () && + ((minimum.width - adj.size.width) <= 0 || + (minimum.height - adjs.size.height) <= 0)) + { + ClutterActor *parent = clutter_actor_get_parent (self); + + /* the only actors that are allowed to be underallocated are the Stage, + * as it doesn't have an implicit size, and Actors that specifically + * told us that they want to opt-out from layout control mechanisms + * through the NO_LAYOUT escape hatch. + */ + if (parent != NULL && + !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0) + { + g_warning (G_STRLOC ": The actor '%s' is getting an allocation " + "of %.2f x %.2f from its parent actor '%s', but its " + "requested minimum size is of %.2f x %.2f", + _clutter_actor_get_debug_name (self), + adj.size.width, adj.size.height, + _clutter_actor_get_debug_name (parent), + minimum.width, minimum.height); + } + } +#endif + + /* we maintain the invariant that a frame cannot be adjusted + * to be outside the given one + */ + if (adj.origin.x < frame->origin.x || + adj.origin.y < frame->origin.y || + adj.size.width > frame->size.width || + adj.size.height > frame->size.height) + { + g_warning (G_STRLOC ": The actor '%s' tried to adjust its frame to " + "{ %.2f, %.2f - %.2f x %.2f }, which is outside of its " + "originally assigned frame of { %.2f, %.2f - %.2f x %.2f }; " + "we are going to ignore the adjustment.", + _clutter_actor_get_debug_name (self), + adj.origin.x, adj.origin.y, + adj.size.width, adj.size.height, + frame->origin.x, frame->origin.y, + frame->size.width, frame->size.height); + return; + } + + *adjusted = adj; +} + +static inline void +clutter_actor_ensure_allocation (ClutterActor *self) +{ + const ClutterLayoutInfo *info; + ClutterActorBox box; + + info = _clutter_actor_peek_layout_info (self); + + /* recompute the allocation from the position, bounds, and margins */ + box.x1 = info->position.x + info->margin.left; + box.y1 = info->position.y + info->margin.top; + box.x2 = box.x1 + + info->bounds.size.width + + info->margin.right; + box.y2 = box.y1 + + info->bounds.size.height + + info->margin.bottom; + + clutter_actor_allocate_internal (self, &box, 0); +} + static void clutter_actor_set_bounds_internal (ClutterActor *self, const ClutterRect *bounds) { ClutterLayoutInfo *info; - info = _clutter_actor_get_layout_info (self); - - CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); - info = _clutter_actor_get_layout_info (self); info->bounds = *bounds; - if (self->priv->parent != NULL && - !CLUTTER_ACTOR_IN_RELAYOUT (self->priv->parent)) - clutter_actor_queue_relayout (self); - else - { - ClutterActorBox box; - - box.x1 = info->position.x + info->margin.left; - box.y1 = info->position.y + info->margin.top; - box.x2 = box.x1 + info->bounds.size.width; - box.y2 = box.y1 + info->bounds.size.height; - - /* only relayout the children if the frame changed */ - if (clutter_actor_set_allocation_internal (self, &box, 0)) - clutter_actor_maybe_layout_children (self); - } - - CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); - - clutter_actor_queue_redraw (self); + clutter_actor_ensure_allocation (self); } static void @@ -9759,43 +9826,22 @@ clutter_actor_set_frame_internal (ClutterActor *self, info = _clutter_actor_get_layout_info (self); - CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); - /* 1. the position of the actor is the origin of the frame */ - info->position = frame->origin; + clutter_actor_adjust_position (self, frame, &info->position); - /* 2. the origin of the bounds are the margin */ - info->bounds.origin.x = info->margin.left; - info->bounds.origin.y = info->margin.top; - - /* 3a. the size of the bounds is the size of the frame, minus the margins */ - info->bounds.size.width = frame->size.width - - info->margin.left - - info->margin.right; + /* 2. the size of the bounds is the size of the frame, minus the margins */ + info->bounds.size.width = frame->size.width + - info->margin.left + - info->margin.right; info->bounds.size.height = frame->size.height - info->margin.top - info->margin.bottom; - /* 3b. the size must be greater than or equal to zero */ - info->bounds.size.width = MAX (info->bounds.size.width, 0.f); + /* 3. the size must be greater than or equal to zero */ + info->bounds.size.width = MAX (info->bounds.size.width, 0.f); info->bounds.size.height = MAX (info->bounds.size.height, 0.f); - { - ClutterActorBox box; - - box.x1 = info->position.x + info->margin.left; - box.y1 = info->position.y + info->margin.top; - box.x2 = box.x1 + info->bounds.size.width; - box.y2 = box.y1 + info->bounds.size.height; - - /* only relayout the children if the frame changed */ - if (clutter_actor_set_allocation_internal (self, &box, 0)) - clutter_actor_maybe_layout_children (self); - - clutter_actor_queue_redraw (self); - } - - CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT); + clutter_actor_ensure_allocation (self); } /** @@ -9811,8 +9857,8 @@ clutter_actor_set_frame_internal (ClutterActor *self, * * This function will adjust the stored allocation to take into account * the alignment flags set in the #ClutterActor:x-align and - * #ClutterActor:y-align properties, if the #ClutterActor:x-expand and - * the #ClutterActor:y-expand properties are set to %TRUE. + * #ClutterActor:y-align properties if the actor is given an allocation + * larger than its preferred size. * * This function will respect the easing state of the #ClutterActor and * interpolate between the current allocation and the new one. @@ -9861,7 +9907,7 @@ clutter_actor_allocate (ClutterActor *self, if (real_allocation.x2 < real_allocation.x1 || real_allocation.y2 < real_allocation.y1) { - g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f", + g_warning (G_STRLOC ": Actor '%s' tried to allocate a negative size of %.2f x %.2f", _clutter_actor_get_debug_name (self), real_allocation.x2 - real_allocation.x1, real_allocation.y2 - real_allocation.y1); @@ -20158,32 +20204,18 @@ void clutter_actor_set_bounds (ClutterActor *self, const ClutterRect *bounds) { - ClutterLayoutInfo *info; + const ClutterLayoutInfo *info; + ClutterRect old_bounds; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (bounds != NULL); - info = _clutter_actor_get_layout_info (self); - info->bounds = *bounds; + info = _clutter_actor_peek_layout_info (self); + old_bounds = info->bounds; - if (self->priv->parent != NULL && - !CLUTTER_ACTOR_IN_RELAYOUT (self->priv->parent)) - clutter_actor_queue_relayout (self); - else - { - ClutterActorBox box; - - box.x1 = info->position.x + info->margin.left; - box.y1 = info->position.y + info->margin.top; - box.x2 = box.x1 + info->bounds.size.width; - box.y2 = box.y1 + info->bounds.size.height; - - /* only relayout the children if the frame changed */ - if (clutter_actor_set_allocation_internal (self, &box, 0)) - clutter_actor_maybe_layout_children (self); - - clutter_actor_queue_redraw (self); - } + _clutter_actor_create_transition (self, obj_props[PROP_BOUNDS], + &old_bounds, + bounds); } /** @@ -20235,9 +20267,16 @@ clutter_actor_get_bounds (ClutterActor *self, * to compute the #ClutterActor:position and the #ClutterActor:bounds * properties of #ClutterActor. * - * This function should only be used when laying out the children of a - * #ClutterActor; to get the normalized paint region of an actor, you should - * use clutter_actor_get_bounds(). + * Whenever a new @frame is set, the #ClutterRect.origin of the + * #ClutterActor:bounds is left undisturbed; the #ClutterRect.size of the + * #ClutterActor:bounds is set to the width of the @frame minus the + * #ClutterActor:margin-left and #ClutterActor:margin-right values, and + * to the height of the @frame minus the #ClutterActor:margin-top and + * #ClutterActor:margin-bottom values. + * + * When painting a #ClutterActor, or when laying out the children of a + * #ClutterActor, it's preferred to use the #ClutterActor:bounds value, as + * it's been already normalized with the paintable area. * * Since: 1.14 */ @@ -20245,18 +20284,18 @@ void clutter_actor_set_frame (ClutterActor *self, const ClutterRect *frame) { - ClutterLayoutInfo *info; + const ClutterLayoutInfo *info; ClutterRect old_frame; g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (frame != NULL); - info = _clutter_actor_get_layout_info (self); + info = _clutter_actor_peek_layout_info (self); old_frame.origin = info->position; - old_frame.size.width = info->margin.left - + info->bounds.size.width - + info->margin.right; + old_frame.size.width = info->margin.left + + info->bounds.size.width + + info->margin.right; old_frame.size.height = info->margin.top + info->bounds.size.height + info->margin.bottom; @@ -20274,7 +20313,9 @@ clutter_actor_set_frame (ClutterActor *self, * Retrieves the frame of a #ClutterActor. * * The frame is a rectangle with an origin expressed in parent-relative - * coordinates, and the size including the margins of the actor. + * coordinates with the #ClutterRect.origin set to the #ClutterActor:position + * value, and the #ClutterRect.size set to the #ClutterActor:bounds value, + * but including the margins of the #ClutterActor. * * Since: 1.14 */ @@ -20296,9 +20337,9 @@ clutter_actor_get_frame (ClutterActor *self, info = _clutter_actor_peek_layout_info (self); - adjusted_width = info->margin.left - + info->bounds.size.width - + info->margin.right; + adjusted_width = info->margin.left + + info->bounds.size.width + + info->margin.right; adjusted_height = info->margin.top + info->bounds.size.height + info->margin.bottom;