Layouting in Clutter 2.0



Hi

As development is starting for Clutter 2 and we have a chance to break
API, I think it would be good to think about whether it would be worth
making any changes to the layouting mechanism.

The current model for layouting has a lot of properties which can be
quite confusing and difficult to explain. I think if we can simplify
this and still have the same functionality then it will be a good thing.

The model I think we should consider would be something like this:

The magic do-what-I-mean properties for the width and height will be
removed so that you are just left with the sizes reported by the
preferred size and the actor's actual allocation size. The allocation
size is just a normal property that you can set at any time with
clutter_actor_set_allocation. It doesn't have to be done during the
allocation cycle and it doesn't mandate that the actor also sets the
allocation on its children. Seeing as the width and height property
names are now unused we could consider renaming the allocation to just
be called width and height.

Reporting that an actor's preferred size has changed will be de-coupled
from queuing a relayout. We would just add a signal to ClutterActor that
just reports to anyone that's interested that the preferred size has
changed. It would be expected that a container would listen for this
signal on all of its children, but it's not necessary if the container
is ignoring the preferred sizes of the children. This would be useful
for example if the container is doing fixed positioning and doesn't
really care what the children want. There is no guarantee that anything
will happen in response to the preferred-size-change signal, ie, it's
not guaranteed that the actor will later have its allocation updated.

Queuing a relayout will be changed so that it doesn't bubble up the
hierarchy and queue a relayout on every ancestor. The âneeds_allocationâ
flag will be removed. Instead, the stage will maintain a list of actors
that need relayouting. Just before painting, the stage will keep pulling
off the head of this list and calling âallocateâ on that actor until the
list becomes empty. We might want to rename âallocateâ to âlayoutâ or
something to avoid confusing it with set_allocation. It should be
supported and expected that actors can queue a relayout and add
themselves to the list during the allocation cycle.

The list will be kept sorted in increasing order of the depth of the
actor. That way, the relayout callbacks for an actor's parent will
always be called before the actor's own relayout callback. This should
ensure that by the time the actor lays out its children it will have its
final size.

As an example, imagine you have a hierarchy like this:

                       +-------+
                       | stage |--------------------\
                       +-------+                     \
                      /       \                       \
           +--------------------+                 +--------------+
           | horizontal-layout  |                 | table-layout |
           +--------------------+                 +--------------+
          /        \            \                   /        \
    +-------+    +-----+   +---------------+  +------+    +------+
    |texture|    |label|   |vertical-layout|  |button|    |button|
    +-------+    +-----+   +---------------+  +------+    +------+
                              /        \
                         +------+    +------+
                         |button|    |button|
                         +------+    +------+

Imagine something in the application causes the label at the bottom to
change its text. This affects the label's preferred size so it emits its
preferred size change signal. It also needs repainting so it queues a
repaint. The label doesn't have any children so it doesn't need to queue
a relayout.

The horizontal layout is listening to the preferred size signal of all
of its children so it notices the label's request. Its own preferred
size is affected by this so it also emits its own signal. It needs to
relayout its children so it also queues a relayout. The layout doesn't
paint anything so it doesn't queue a repaint.

The stage isn't doing any layouting and doesn't care that the horizontal
layout's size has changed so it ignores it.

The main loop kicks in and recognises that label needs a redraw. Before
doing any painting the stage will always flush the relayout queue. The
only thing in the relayout queue is the horizontal layout so the stage
will immediately call the layout function of that. Nothing has changed
the layout's size so it will layout with the same size it had
previously. It will query the preferred size of all its children and
call set_allocation on all of them. The sizes will have changed because
more of the space is now given to the label. Changing the size of the
texture will cause it to queue a redraw.

When the vertical layout's size changes it will immediately queue a
relayout. Its preferred size has not changed and it doesn't paint
anything so it won't queue anything else.

The layout flushing code for the stage will now recognise that there is
another item in the queue and flush that before painting. The vertical
layout will set the size of its children. Neither of them have any
children of their own so they will just queue a redraw.

The layout cycle is now complete. The table-layout on the side has not
been touched at all because it is on an irrelevant branch.

The stage can now paint the scene possibly using the paint volumes of
the dirty actors that now have their final location.

Why would want to make this change?

â People seem to often encounter problems with the old system where they
  would accidentally queue a relayout during the allocation cycle. This
  ends up with awkward to solve bugs.

â We've had a fair few problems keeping track of the âneed_allocationâ
  flag. This is particularly problematic if containers do not allocate
  their children for whatever reason because then the flag will end up
  in an inconsistent state. This can prevent the allocation from
  bubbling up if the broken actor later again needs a relayout.

â The new model lets us optimise certain types of containers. For
  example, a container that is displaying a split pane with two actors
  might not care what the preferred size of the children are. In that
  case if one of the child panes needs a relayout, it doesn't need to
  involve the container or any of the ancestors.

â It makes it easier for example to implement scroll-view containers
  that don't want to bother allocating children that are not visible.

I'd be happy to help with a patch for something like this model if we
can agree on a plan.

Regards,
- Neil



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]