diff --git a/doc/size-negotiation.txt b/doc/size-negotiation.txt new file mode 100644 index 000000000..8f4713d09 --- /dev/null +++ b/doc/size-negotiation.txt @@ -0,0 +1,85 @@ +Size negotiation in Clutter +--------------------------- + +Clutter uses a two-pass size negotiation mechanism. Each parent will ask its +children (if any) for their preferred size, which will affect the parent's own +preferred size; once this preferred size query returns to the stage, the stage +will allocate the size of each child, which in turn will allocate each one of +their own children, until it reaches the end of the scene graph. + +The preferred size of an actor is defined through the: + + get_preferred_width() + get_preferred_height() + +virtual functions that should be implemented by every actor. The virtual +functions will only be invoked if the corresponding flags: + + needs_width_request + needs_height_request + +are set; otherwise, the preferred size will be cached inside ClutterActor +itself. + +Actors can inform their parents that their preferred size has changed by using: + + clutter_actor_queue_relayout() + +on themselves. This function will "bubble up" through the scene graph, and it +will clear the: + + needs_width_request + needs_height_request + needs_allocation + +flags inside the actor and its parents up to the stage. + +At the beginning of the next frame, the stage will check if there is a relayout +pending, and it will ask each child for its preferred size; depending on the +state of the flags, the implementations for the virtual functions: + + get_preferred_width() + get_preferred_height() + allocate() + +will be invoked in that order. Each parent is responsible for calling +clutter_actor_allocate() on its children. + +Example +------- + +Let's consider a scene composed by actors following this layout: + + +---------------------------------------+ + |3 +=============+ +==+ +=============+ | + | | +-+ +-+ +-+ | | | |2 +-+ +----+ | | + | | | | | | | | | | | | |1| | | | | + | | +-+ +-+ +-+ | | | | +-+ +----+ | | + | +=============+ +==+ +=============+ | + +---------------------------------------+ + +The actor (1) calls queue_relayout(), which clears the needs_* flags on its +parent (2), and its grand-parent (3); the state of the other siblings will be +left untouched. + + +---------------------------------------+ + |a +=============+ +==+ +=============+ | + | |b+-+ +-+ +-+ | |f | |g +---+ +--+ | | + | | |c| |d| |e| | | | | |h | |i | | | + | | +-+ +-+ +-+ | | | | +---+ +--+ | | + | +=============+ +==+ +=============+ | + +---------------------------------------+ + +At the beginning of the following frame, clutter_actor_allocate() will be called +starting from the actor (a). Since its needs_* flags have been cleared, the +allocate() virtual function will be invoked. This will cause +clutter_actor_allocate() to be called on its children, starting from (b). The +size computed by the parent (a) for its child (b) hasn't changed, and its +needs_* flags haven't been cleared, so clutter_actor_allocate() will +short-circuit, and will not cause the implementation of the allocate() virtual +function for (b) to be called, effectively skipping the branch of the scene +graph. The same will happen for (f). + +The child (g) has the same size, but its needs_* flags will have been cleared, +so its allocate() implementation will be invoked; this will cause the (h) and +(i) children to be allocated as well.