stage: make it possible to queue a relayout only

This adds a private ->relayout_pending boolean similar in spirit to
redraw_pending. This will allow us to queue a relayout without
implicitly queueing a redraw; instead we can depend on the actions
of a relayout to queue any necessary redraw.
This commit is contained in:
Robert Bragg 2010-09-07 20:08:00 +01:00
parent f8a6e36f1b
commit 6d5f6449dd
2 changed files with 73 additions and 53 deletions

View File

@ -225,47 +225,6 @@ clutter_get_accessibility_enabled (void)
return cally_get_cally_initialized (); return cally_get_cally_initialized ();
} }
void
_clutter_stage_maybe_relayout (ClutterActor *stage)
{
gfloat natural_width, natural_height;
ClutterActorBox box = { 0, };
CLUTTER_STATIC_TIMER (relayout_timer,
"Mainloop", /* no parent */
"Layouting",
"The time spent reallocating the stage",
0 /* no application private data */);
/* avoid reentrancy */
if (!CLUTTER_ACTOR_IN_RELAYOUT (stage))
{
CLUTTER_TIMER_START (_clutter_uprof_context, relayout_timer);
CLUTTER_NOTE (ACTOR, "Recomputing layout");
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
natural_width = natural_height = 0;
clutter_actor_get_preferred_size (stage,
NULL, NULL,
&natural_width, &natural_height);
box.x1 = 0;
box.y1 = 0;
box.x2 = natural_width;
box.y2 = natural_height;
CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
(int) natural_width,
(int) natural_height);
clutter_actor_allocate (stage, &box, CLUTTER_ALLOCATION_NONE);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
CLUTTER_TIMER_STOP (_clutter_uprof_context, relayout_timer);
}
}
void void
_clutter_do_redraw (ClutterStage *stage) _clutter_do_redraw (ClutterStage *stage)
{ {
@ -278,9 +237,6 @@ _clutter_do_redraw (ClutterStage *stage)
_clutter_stage_set_pick_buffer_valid (stage, FALSE); _clutter_stage_set_pick_buffer_valid (stage, FALSE);
_clutter_stage_reset_picks_per_frame_counter (stage); _clutter_stage_reset_picks_per_frame_counter (stage);
/* Before we can paint, we have to be sure we have the latest layout */
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
_clutter_backend_ensure_context (ctx->backend, stage); _clutter_backend_ensure_context (ctx->backend, stage);
/* Setup FPS count - not currently across *all* stages rather than per */ /* Setup FPS count - not currently across *all* stages rather than per */

View File

@ -120,6 +120,7 @@ struct _ClutterStagePrivate
GArray *paint_volume_stack; GArray *paint_volume_stack;
guint relayout_pending : 1;
guint redraw_pending : 1; guint redraw_pending : 1;
guint is_fullscreen : 1; guint is_fullscreen : 1;
guint is_cursor_visible : 1; guint is_cursor_visible : 1;
@ -673,7 +674,54 @@ _clutter_stage_needs_update (ClutterStage *stage)
priv = stage->priv; priv = stage->priv;
return priv->redraw_pending; return priv->relayout_pending || priv->redraw_pending;
}
void
_clutter_stage_maybe_relayout (ClutterActor *actor)
{
ClutterStage *stage = CLUTTER_STAGE (actor);
ClutterStagePrivate *priv = stage->priv;
gfloat natural_width, natural_height;
ClutterActorBox box = { 0, };
CLUTTER_STATIC_TIMER (relayout_timer,
"Mainloop", /* no parent */
"Layouting",
"The time spent reallocating the stage",
0 /* no application private data */);
if (!priv->relayout_pending)
return;
priv->relayout_pending = FALSE;
/* avoid reentrancy */
if (!CLUTTER_ACTOR_IN_RELAYOUT (stage))
{
CLUTTER_TIMER_START (_clutter_uprof_context, relayout_timer);
CLUTTER_NOTE (ACTOR, "Recomputing layout");
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
natural_width = natural_height = 0;
clutter_actor_get_preferred_size (CLUTTER_ACTOR (stage),
NULL, NULL,
&natural_width, &natural_height);
box.x1 = 0;
box.y1 = 0;
box.x2 = natural_width;
box.y2 = natural_height;
CLUTTER_NOTE (ACTOR, "Allocating (0, 0 - %d, %d) for the stage",
(int) natural_width,
(int) natural_height);
clutter_actor_allocate (CLUTTER_ACTOR (stage),
&box, CLUTTER_ALLOCATION_NONE);
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_IN_RELAYOUT);
CLUTTER_TIMER_STOP (_clutter_uprof_context, relayout_timer);
}
} }
/** /**
@ -693,17 +741,15 @@ _clutter_stage_do_update (ClutterStage *stage)
priv = stage->priv; priv = stage->priv;
if (!priv->redraw_pending) /* NB: We need to ensure we have an up to date layout *before* we
return FALSE; * check or clear the pending redraws flag since a relayout may
* queue a redraw.
/* clutter_do_redraw() will also call maybe_relayout(), but since a relayout
* can queue a redraw, we want to do the relayout before we clear the
* update_idle to avoid painting the stage twice. Calling maybe_relayout()
* twice in a row is cheap because of caching of requested and allocated
* size.
*/ */
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage)); _clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
if (!priv->redraw_pending)
return FALSE;
CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage); CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage);
_clutter_do_redraw (stage); _clutter_do_redraw (stage);
@ -721,6 +767,20 @@ _clutter_stage_do_update (ClutterStage *stage)
return TRUE; return TRUE;
} }
static void
clutter_stage_real_queue_relayout (ClutterActor *self)
{
ClutterStage *stage = CLUTTER_STAGE (self);
ClutterStagePrivate *priv = stage->priv;
ClutterActorClass *parent_class;
priv->relayout_pending = TRUE;
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
parent_class->queue_relayout (self);
}
static void static void
clutter_stage_real_queue_redraw (ClutterActor *actor, clutter_stage_real_queue_redraw (ClutterActor *actor,
ClutterActor *leaf) ClutterActor *leaf)
@ -1112,6 +1172,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
actor_class->unrealize = clutter_stage_unrealize; actor_class->unrealize = clutter_stage_unrealize;
actor_class->show = clutter_stage_show; actor_class->show = clutter_stage_show;
actor_class->hide = clutter_stage_hide; actor_class->hide = clutter_stage_hide;
actor_class->queue_relayout = clutter_stage_real_queue_relayout;
actor_class->queue_redraw = clutter_stage_real_queue_redraw; actor_class->queue_redraw = clutter_stage_real_queue_redraw;
actor_class->apply_transform = clutter_stage_real_apply_transform; actor_class->apply_transform = clutter_stage_real_apply_transform;
@ -1471,6 +1532,8 @@ clutter_stage_init (ClutterStage *self)
priv->fog.z_near = 1.0; priv->fog.z_near = 1.0;
priv->fog.z_far = 2.0; priv->fog.z_far = 2.0;
priv->relayout_pending = TRUE;
clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE); clutter_actor_set_reactive (CLUTTER_ACTOR (self), TRUE);
clutter_stage_set_title (self, g_get_prgname ()); clutter_stage_set_title (self, g_get_prgname ());
clutter_stage_set_key_focus (self, NULL); clutter_stage_set_key_focus (self, NULL);
@ -2617,6 +2680,7 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv; priv = stage->priv;
priv->relayout_pending = TRUE;
priv->redraw_pending = TRUE; priv->redraw_pending = TRUE;
master_clock = _clutter_master_clock_get_default (); master_clock = _clutter_master_clock_get_default ();