[x11] Fix a race condition when resizing a stage

There is a race condition when we resize a stage before showing
it on X11.

The race goes like this:

  - clutter_init() creates the default stage and realize it, which
    will cause a 640x480 Window to be created
  - call set_size(800, 600) on the stage will cause the Window to be
    resized to 800x600
  - call show() on the stage for the first time will cause COGL
    to set up an 800 by 600 GL viewport
  - the Window will be mapped, which will cause X to notify the
    window manager that the Window should be resized to 800x600
  - the window manager will approve the resize
  - X resizes the drawable to 800x600

To fix the race, we need to defer COGL from setting up the viewport
until we receive a ConfigureNotify event and the X server has resized
the Drawable.

In order to defer the call to cogl_setup_viewport() we add a new
private flag, CLUTTER_STAGE_IN_RESIZE; the flag is checked whenever
we need to change the viewport size along with the SYNC_MATRICES
private flag. Thus, cogl_setup_viewport() will be called only if
SYNC_MATRICES is set and IN_RESIZE is not set.
This commit is contained in:
Emmanuele Bassi 2009-01-09 12:06:46 +00:00
parent efd7ad7e55
commit 00a3c69868
4 changed files with 34 additions and 13 deletions

View File

@ -147,7 +147,8 @@ _clutter_stage_maybe_relayout (ClutterActor *stage)
void
_clutter_stage_maybe_setup_viewport (ClutterStage *stage)
{
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
if ((CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES) &&
!(CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_STAGE_IN_RESIZE))
{
ClutterPerspective perspective;
guint width, height;

View File

@ -62,7 +62,8 @@ typedef enum {
*/
CLUTTER_ACTOR_IN_PAINT = 1 << 4, /* Used to avoid recursion */
CLUTTER_ACTOR_IN_RELAYOUT = 1 << 5, /* Used to avoid recursion */
CLUTTER_TEXTURE_IN_CLONE_PAINT = 1 << 6 /* Used for safety in clones */
CLUTTER_TEXTURE_IN_CLONE_PAINT = 1 << 6, /* Used for safety in clones */
CLUTTER_STAGE_IN_RESIZE = 1 << 7 /* Used to mark stage resizes */
} ClutterPrivateFlags;
typedef enum {

View File

@ -438,6 +438,12 @@ event_translate (ClutterBackend *backend,
xevent->xconfigure.height);
stage_x11->handling_configure = FALSE;
/* the resize process is complete, so we can remove the
* in-resize flag and allow the viewport to be resized
*/
CLUTTER_UNSET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper),
CLUTTER_STAGE_IN_RESIZE);
}
res = FALSE;
break;

View File

@ -282,13 +282,30 @@ clutter_stage_x11_allocate (ClutterActor *self,
queue. Handling the first event will undo the work of setting
the second property which will cause it to keep generating
events in an infinite loop. See bug #810 */
if (stage_x11->xwin != None
&& !stage_x11->is_foreign_xwin
&& !stage_x11->handling_configure)
XResizeWindow (stage_x11->xdpy,
stage_x11->xwin,
stage_x11->xwin_width,
stage_x11->xwin_height);
if (stage_x11->xwin != None &&
!stage_x11->is_foreign_xwin &&
!stage_x11->handling_configure)
{
XResizeWindow (stage_x11->xdpy,
stage_x11->xwin,
stage_x11->xwin_width,
stage_x11->xwin_height);
/* resizing is an asynchronous process; to avoid races
* with the window manager, we flag the wrapper as being
* "in resize", so that the SYNC_MATRICES flag will not
* cause a call to cogl_get_viewport().
*
* the flag is unset inside clutter-event-x11.c, after
* we receive a ConfigureNotify event. XXX - need to
* check what happens when running without a window manager
*/
CLUTTER_SET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper),
CLUTTER_STAGE_IN_RESIZE);
}
CLUTTER_SET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper),
CLUTTER_ACTOR_SYNC_MATRICES);
clutter_stage_x11_fix_window_size (stage_x11);
@ -298,9 +315,6 @@ clutter_stage_x11_allocate (ClutterActor *self,
clutter_actor_unrealize (self);
clutter_actor_realize (self);
}
CLUTTER_SET_PRIVATE_FLAGS (CLUTTER_ACTOR (stage_x11->wrapper),
CLUTTER_ACTOR_SYNC_MATRICES);
}
/* chain up to fill in actor->priv->allocation */
@ -769,4 +783,3 @@ clutter_stage_x11_unmap (ClutterStageX11 *stage_x11)
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED);
}