[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 void
_clutter_stage_maybe_setup_viewport (ClutterStage *stage) _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; ClutterPerspective perspective;
guint width, height; guint width, height;

View File

@ -62,7 +62,8 @@ typedef enum {
*/ */
CLUTTER_ACTOR_IN_PAINT = 1 << 4, /* Used to avoid recursion */ CLUTTER_ACTOR_IN_PAINT = 1 << 4, /* Used to avoid recursion */
CLUTTER_ACTOR_IN_RELAYOUT = 1 << 5, /* 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; } ClutterPrivateFlags;
typedef enum { typedef enum {

View File

@ -438,6 +438,12 @@ event_translate (ClutterBackend *backend,
xevent->xconfigure.height); xevent->xconfigure.height);
stage_x11->handling_configure = FALSE; 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; res = FALSE;
break; break;

View File

@ -282,13 +282,30 @@ clutter_stage_x11_allocate (ClutterActor *self,
queue. Handling the first event will undo the work of setting queue. Handling the first event will undo the work of setting
the second property which will cause it to keep generating the second property which will cause it to keep generating
events in an infinite loop. See bug #810 */ events in an infinite loop. See bug #810 */
if (stage_x11->xwin != None if (stage_x11->xwin != None &&
&& !stage_x11->is_foreign_xwin !stage_x11->is_foreign_xwin &&
&& !stage_x11->handling_configure) !stage_x11->handling_configure)
XResizeWindow (stage_x11->xdpy, {
stage_x11->xwin, XResizeWindow (stage_x11->xdpy,
stage_x11->xwin_width, stage_x11->xwin,
stage_x11->xwin_height); 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); clutter_stage_x11_fix_window_size (stage_x11);
@ -298,9 +315,6 @@ clutter_stage_x11_allocate (ClutterActor *self,
clutter_actor_unrealize (self); clutter_actor_unrealize (self);
clutter_actor_realize (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 */ /* 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, CLUTTER_ACTOR_MAPPED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED); CLUTTER_ACTOR_UNSET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_MAPPED);
} }