2008-05-12 Emmanuele Bassi <ebassi@openedhand.com>

Rework the stage wrapper/implementation relation: remove
	duplicated code and all the bookkeeping from the backends into
	ClutterStage whenever possible, to reduce the amount of	work a
	backend must do (and possibly get wrong). Thanks to Tommi
	Komulainen.

	* clutter/clutter-main.c:
	(clutter_init_with_args), (clutter_init): Realize the default
	stage after creation. The default stage is special, because we
	use it in the initialization sequence. This removes the burden
	from the backends and reduces the things a backend can get
	wrong.

	* clutter/clutter-stage.c:
	(clutter_stage_show): Make sure to realize the implementation if
	it hasn't been realized yet.

	(clutter_stage_realize): Set the REALIZED flag and call
	clutter_stage_ensure_current() if the implementation was
	successfully realized.

	(clutter_stage_unrealized): Call clutter_stage_ensure_current()
	on unrealize.

	* clutter/glx/clutter-backend-glx.c:
	(clutter_backend_glx_create_stage): Do not realize the stage anymore
	when creating it, and let the normal realization sequence take
	place.

	(clutter_backend_glx_ensure_context): Trap for X11 errors.

	* clutter/glx/clutter-stage-glx.c:
	(clutter_stage_glx_realize): Chain up to the X11 implementation
	so that we can set up the window state (title, cursor visibility)
	when we actually have a X window. Also, do not call
	clutter_stage_ensure_current(), and rely on the wrapper to do
	it for us. This means we can drop setting the REALIZED flag on
	the wrapper.

	(clutter_stage_glx_unrealize): Do not call
	clutter_stage_ensure_current() ourselves, and rely on the wrapper
	to do it for us.

	* clutter/x11/clutter-stage-x11.c:
	(set_wm_title),	(set_cursor_visible): Move the WM title and
	cursor visibility code inside their own functions.

	(clutter_stage_x11_realize): Set the window title and whether the
	cursor is visible or not after realizing the stage.

	(clutter_stage_x11_set_cursor_visible),
	(clutter_stage_x11_set_title): Call set_wm_title() and
	set_cursor_visible().

	(clutter_stage_x11_finalize): Free the title string.

	* clutter/x11/clutter-stage-x11.h: Save more of the stage state,
	so that we can set it even when the stage hasn't been realized
	yet.

	* clutter/eglnative/clutter-backend-egl.c:
	(clutter_backend_egl_create_stage):
	* clutter/eglnative/clutter-stage-egl.c:
	(clutter_stage_egl_unrealize),
	(clutter_stage_egl_realize): Update the eglnative backend.

	* clutter/eglx/clutter-backend-egl.c:
	(clutter_backend_egl_ensure_context),
	(clutter_backend_egl_create_stage):
	* clutter/eglx/clutter-stage-egl.c:
	(clutter_stage_egl_unrealize),
	(clutter_stage_egl_realize): Update the eglx backend.

	* clutter/sdl/clutter-backend-sdl.c:
	(clutter_backend_sdl_create_stage):
	* clutter/sdl/clutter-stage-sdl.c:
	(clutter_stage_sdl_realize): Update the sdl backend.

	* clutter/fruity/clutter-backend-fruity.c:
	(clutter_backend_fruity_create_stage):
	* clutter/sdl/clutter-stage-fruity.c:
	(clutter_stage_fruity_realize): Update the fruity backend.

	* tests/test-multistage.c (on_button_press): Bail out if
	clutter_stage_new() returns NULL.

	* HACKING.backends: Update backend writing documentation.
This commit is contained in:
Emmanuele Bassi 2008-05-12 15:26:37 +00:00
parent c76e576141
commit 101a3cac4e
17 changed files with 315 additions and 241 deletions

View File

@ -1,3 +1,93 @@
2008-05-12 Emmanuele Bassi <ebassi@openedhand.com>
Rework the stage wrapper/implementation relation: remove
duplicated code and all the bookkeeping from the backends into
ClutterStage whenever possible, to reduce the amount of work a
backend must do (and possibly get wrong). Thanks to Tommi
Komulainen.
* clutter/clutter-main.c:
(clutter_init_with_args), (clutter_init): Realize the default
stage after creation. The default stage is special, because we
use it in the initialization sequence. This removes the burden
from the backends and reduces the things a backend can get
wrong.
* clutter/clutter-stage.c:
(clutter_stage_show): Make sure to realize the implementation if
it hasn't been realized yet.
(clutter_stage_realize): Set the REALIZED flag and call
clutter_stage_ensure_current() if the implementation was
successfully realized.
(clutter_stage_unrealized): Call clutter_stage_ensure_current()
on unrealize.
* clutter/glx/clutter-backend-glx.c:
(clutter_backend_glx_create_stage): Do not realize the stage anymore
when creating it, and let the normal realization sequence take
place.
(clutter_backend_glx_ensure_context): Trap for X11 errors.
* clutter/glx/clutter-stage-glx.c:
(clutter_stage_glx_realize): Chain up to the X11 implementation
so that we can set up the window state (title, cursor visibility)
when we actually have a X window. Also, do not call
clutter_stage_ensure_current(), and rely on the wrapper to do
it for us. This means we can drop setting the REALIZED flag on
the wrapper.
(clutter_stage_glx_unrealize): Do not call
clutter_stage_ensure_current() ourselves, and rely on the wrapper
to do it for us.
* clutter/x11/clutter-stage-x11.c:
(set_wm_title), (set_cursor_visible): Move the WM title and
cursor visibility code inside their own functions.
(clutter_stage_x11_realize): Set the window title and whether the
cursor is visible or not after realizing the stage.
(clutter_stage_x11_set_cursor_visible),
(clutter_stage_x11_set_title): Call set_wm_title() and
set_cursor_visible().
(clutter_stage_x11_finalize): Free the title string.
* clutter/x11/clutter-stage-x11.h: Save more of the stage state,
so that we can set it even when the stage hasn't been realized
yet.
* clutter/eglnative/clutter-backend-egl.c:
(clutter_backend_egl_create_stage):
* clutter/eglnative/clutter-stage-egl.c:
(clutter_stage_egl_unrealize),
(clutter_stage_egl_realize): Update the eglnative backend.
* clutter/eglx/clutter-backend-egl.c:
(clutter_backend_egl_ensure_context),
(clutter_backend_egl_create_stage):
* clutter/eglx/clutter-stage-egl.c:
(clutter_stage_egl_unrealize),
(clutter_stage_egl_realize): Update the eglx backend.
* clutter/sdl/clutter-backend-sdl.c:
(clutter_backend_sdl_create_stage):
* clutter/sdl/clutter-stage-sdl.c:
(clutter_stage_sdl_realize): Update the sdl backend.
* clutter/fruity/clutter-backend-fruity.c:
(clutter_backend_fruity_create_stage):
* clutter/sdl/clutter-stage-fruity.c:
(clutter_stage_fruity_realize): Update the fruity backend.
* tests/test-multistage.c (on_button_press): Bail out if
clutter_stage_new() returns NULL.
* HACKING.backends: Update backend writing documentation.
2008-05-12 Robert Bragg <bob@openedhand.com> 2008-05-12 Robert Bragg <bob@openedhand.com>
* clutter/clutter-timeline.c: * clutter/clutter-timeline.c:

View File

@ -58,6 +58,10 @@ pointer is returned (with its reference count increased). The GObject
API reference describes how to use the ::constructor virtual function API reference describes how to use the ::constructor virtual function
to implement a singleton, so you should refer to that. to implement a singleton, so you should refer to that.
The ClutterBackend implementation should hold a single drawing context
for its entire lifetime; stage implementations should be "made current"
when needed.
When implementing the ClutterBackend subclass these virtual functions When implementing the ClutterBackend subclass these virtual functions
can be overridden: can be overridden:
@ -106,10 +110,8 @@ can be overridden:
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (impl)); _clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (impl));
The backend must also call clutter_actor_realize() on the stage in case of error, the backend must return NULL and set the passed
implementation, and then check if the stage has been realized, using GError.
the CLUTTER_ACTOR_IS_REALIZED() macro; if the stage was not
realized, it must return NULL and set the passed GError.
Implementing the stage Implementing the stage
---------------------- ----------------------
@ -130,9 +132,7 @@ the stage implementation should:
- create a new native window handle - create a new native window handle
- if the backend doesn't have a drawing context (either GL or GLES), - if the backend doesn't have a drawing context (either GL or GLES),
create one and assing it to the backend create one and assing it to the backend
- set the CLUTTER_ACTOR_REALIZED flag on *both* the wrapper and the - set the CLUTTER_ACTOR_REALIZED flag on itself
stage implementation (this is very important)
- call clutter_stage_ensure_current() with the wrapper instance
In case of failure, the CLUTTER_ACTOR_REALIZED flag should be unset on In case of failure, the CLUTTER_ACTOR_REALIZED flag should be unset on
the stage implementation. the stage implementation.
@ -141,7 +141,6 @@ Inside the ::unrealize function the stage implementation should:
- unset the CLUTTER_ACTOR_REALIZED flag on itself - unset the CLUTTER_ACTOR_REALIZED flag on itself
- destroy the native window handle - destroy the native window handle
- call clutter_stage_ensure_current() with the wrapper instance
NOTES NOTES
===== =====
@ -152,9 +151,6 @@ implementation for event handling and window management.
Usual points of failure for backends are: Usual points of failure for backends are:
- not setting the CLUTTER_ACTOR_REALIZED flag on the stage implementation
and the stage wrapper inside the ::realized virtual function before
calling clutter_stage_ensure_current();
- calling public API, like clutter_actor_paint(), or checking properties - calling public API, like clutter_actor_paint(), or checking properties
on the stage implementation instead of the ClutterStage wrapper. on the stage implementation instead of the ClutterStage wrapper.

View File

@ -1103,6 +1103,16 @@ clutter_init_with_args (int *argc,
return CLUTTER_INIT_ERROR_INTERNAL; return CLUTTER_INIT_ERROR_INTERNAL;
} }
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the default stage");
return CLUTTER_INIT_ERROR_INTERNAL;
}
_clutter_backend_init_events (clutter_context->backend); _clutter_backend_init_events (clutter_context->backend);
_clutter_feature_init (); _clutter_feature_init ();
@ -1195,6 +1205,14 @@ clutter_init (int *argc,
return CLUTTER_INIT_ERROR_INTERNAL; return CLUTTER_INIT_ERROR_INTERNAL;
} }
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_critical ("Unable to realize the default stage");
return CLUTTER_INIT_ERROR_INTERNAL;
}
/* Initiate event collection */ /* Initiate event collection */
_clutter_backend_init_events (context->backend); _clutter_backend_init_events (context->backend);

View File

@ -187,13 +187,16 @@ clutter_stage_realize (ClutterActor *self)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
/* then realize the implementation */ CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->realize (priv->impl); CLUTTER_ACTOR_GET_CLASS (priv->impl)->realize (priv->impl);
/* set the flag on the wrapper if the implementation was successful */ /* ensure that the stage is using the context if the
* realization sequence was successful
*/
if (CLUTTER_ACTOR_IS_REALIZED (priv->impl)) if (CLUTTER_ACTOR_IS_REALIZED (priv->impl))
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED); clutter_stage_ensure_current (CLUTTER_STAGE (self));
else else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
} }
@ -209,6 +212,8 @@ clutter_stage_unrealize (ClutterActor *self)
/* and then unrealize the implementation */ /* and then unrealize the implementation */
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl); CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
} }
static void static void
@ -217,6 +222,10 @@ clutter_stage_show (ClutterActor *self)
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
if (!CLUTTER_ACTOR_IS_REALIZED (priv->impl))
clutter_actor_realize (priv->impl);
clutter_actor_show (priv->impl); clutter_actor_show (priv->impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);

View File

@ -100,19 +100,6 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage)); _clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
g_object_unref (stage);
return NULL;
}
backend_egl->stage = CLUTTER_ACTOR (stage_egl); backend_egl->stage = CLUTTER_ACTOR (stage_egl);
return stage; return stage;

View File

@ -62,8 +62,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface); eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE; stage_egl->egl_surface = EGL_NO_SURFACE;
} }
clutter_stage_ensure_current (stage_egl->wrapper);
} }
static void static void
@ -179,7 +177,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
} }
CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context"); CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context");
CLUTTER_ACTOR_SET_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_egl, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_SET_FLAGS (stage_egl, CLUTTER_ACTOR_REALIZED);
/* eglnative can have only one stage */ /* eglnative can have only one stage */
@ -202,8 +199,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
CLUTTER_SET_PRIVATE_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
} }
static void static void

View File

@ -81,6 +81,8 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
if (!backend_egl->egl_context) if (!backend_egl->egl_context)
return; return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we /* we might get here inside the final dispose cycle, so we
* need to handle this gracefully * need to handle this gracefully
*/ */
@ -100,6 +102,11 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
stage_egl->egl_surface, stage_egl->egl_surface,
stage_egl->egl_surface, stage_egl->egl_surface,
backend_egl->egl_context); backend_egl->egl_context);
if (clutter_x11_untrap_x_errors ())
g_critical ("Unable to make the stage window 0x%x the current "
"EGLX drawable",
(int) stage_x11->xwin);
} }
} }
@ -245,19 +252,6 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
stage_x11->xscreen, stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root); (unsigned int) stage_x11->xwin_root);
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
g_object_unref (stage);
return NULL;
}
return stage; return stage;
} }

View File

@ -63,8 +63,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
stage_egl->egl_surface = EGL_NO_SURFACE; stage_egl->egl_surface = EGL_NO_SURFACE;
} }
clutter_stage_ensure_current (stage_x11->wrapper);
XSync (stage_x11->xdpy, False); XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors (); clutter_x11_untrap_x_errors ();
@ -91,6 +89,11 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (G_LIKELY (!is_offscreen)) if (G_LIKELY (!is_offscreen))
{ {
int c;
int num_configs;
int max_tex_units;
EGLConfig *all_configs;
EGLint cfg_attribs[] = { EGLint cfg_attribs[] = {
EGL_BUFFER_SIZE, EGL_DONT_CARE, EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_RED_SIZE, 5, EGL_RED_SIZE, 5,
@ -104,49 +107,48 @@ clutter_stage_egl_realize (ClutterActor *actor)
2, 2,
&config_count); &config_count);
int c; eglGetConfigs (clutter_eglx_display (), NULL, 0, &num_configs);
int num_configs;
EGLConfig *all_configs;
eglGetConfigs (clutter_eglx_display(), NULL, 0, &num_configs);
all_configs = g_malloc (num_configs * sizeof (EGLConfig)); all_configs = g_malloc (num_configs * sizeof (EGLConfig));
eglGetConfigs (clutter_eglx_display (),
eglGetConfigs (clutter_eglx_display(),
all_configs, all_configs,
num_configs, num_configs,
&num_configs); &num_configs);
for (c=0; c<num_configs; ++c) for (c = 0; c < num_configs; ++c)
{ {
EGLint red=-1, green=-1, blue=-1, alpha=-1, stencil=-1; EGLint red = -1, green = -1, blue = -1, alpha = -1, stencil = -1;
eglGetConfigAttrib (clutter_eglx_display(),
eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c], all_configs[c],
EGL_RED_SIZE, &red); EGL_RED_SIZE, &red);
eglGetConfigAttrib (clutter_eglx_display(), eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c], all_configs[c],
EGL_GREEN_SIZE, &green); EGL_GREEN_SIZE, &green);
eglGetConfigAttrib (clutter_eglx_display(), eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c], all_configs[c],
EGL_BLUE_SIZE, &blue); EGL_BLUE_SIZE, &blue);
eglGetConfigAttrib (clutter_eglx_display(), eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c], all_configs[c],
EGL_ALPHA_SIZE, &alpha); EGL_ALPHA_SIZE, &alpha);
eglGetConfigAttrib (clutter_eglx_display(), eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c], all_configs[c],
EGL_STENCIL_SIZE, &stencil); EGL_STENCIL_SIZE, &stencil);
printf("EGLConfig === R:%d G:%d B:%d A:%d S:%d \n", CLUTTER_NOTE (BACKEND, "EGLConfig == R:%d G:%d B:%d A:%d S:%d \n",
red, green, blue, alpha, stencil); red, green, blue, alpha, stencil);
} }
int max_tex_units = 0; max_tex_units = 0;
glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_units); glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_tex_units);
printf("Texture units: %d\n", max_tex_units); CLUTTER_NOTE (BACKEND, "Texture units: %d\n", max_tex_units);
g_free (all_configs); g_free (all_configs);
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglGetConfigs failed"); {
g_critical ("eglGetConfigs failed");
goto fail;
}
status = eglChooseConfig (backend_egl->edpy, status = eglChooseConfig (backend_egl->edpy,
cfg_attribs, cfg_attribs,
@ -155,7 +157,10 @@ clutter_stage_egl_realize (ClutterActor *actor)
&config_count); &config_count);
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglChooseConfig failed"); {
g_critical ("eglChooseConfig failed");
goto fail;
}
if (stage_x11->xwin == None) if (stage_x11->xwin == None)
stage_x11->xwin = stage_x11->xwin =
@ -198,9 +203,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (stage_egl->egl_surface == EGL_NO_SURFACE) if (stage_egl->egl_surface == EGL_NO_SURFACE)
{ {
g_critical ("Unable to create an EGL surface"); g_critical ("Unable to create an EGL surface");
goto fail;
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
} }
if (G_UNLIKELY (backend_egl->egl_context == None)) if (G_UNLIKELY (backend_egl->egl_context == None))
@ -215,26 +218,26 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (backend_egl->egl_context == EGL_NO_CONTEXT) if (backend_egl->egl_context == EGL_NO_CONTEXT)
{ {
g_critical ("Unable to create a suitable EGL context"); g_critical ("Unable to create a suitable EGL context");
goto fail;
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
} }
} }
/* this will make sure to set the current context */ CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context");
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
} }
else else
{ {
g_warning("EGLX Backend does not support offscreen rendering"); g_critical ("EGLX Backend does not support offscreen rendering");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); goto fail;
return;
} }
CLUTTER_SET_PRIVATE_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_SYNC_MATRICES); /* we need to chain up to the X11 stage implementation in order to
* set the window state in case we set it before realizing the stage
*/
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->realize (actor);
return;
fail:
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
} }
static void static void

View File

@ -99,19 +99,6 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage)); _clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
g_object_unref (stage);
return NULL;
}
backend_egl->stage = CLUTTER_ACTOR (stage_egl); backend_egl->stage = CLUTTER_ACTOR (stage_egl);
return stage; return stage;

View File

@ -61,8 +61,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface); eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE; stage_egl->egl_surface = EGL_NO_SURFACE;
} }
clutter_stage_ensure_current (stage_egl->wrapper);
} }
static void static void
@ -108,7 +106,11 @@ clutter_stage_egl_realize (ClutterActor *actor)
&config_count); &config_count);
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglChooseConfig failed"); {
g_critical ("eglChooseConfig failed");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
if (stage_egl->egl_surface != EGL_NO_SURFACE) if (stage_egl->egl_surface != EGL_NO_SURFACE)
{ {
@ -133,7 +135,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (stage_egl->egl_surface == EGL_NO_SURFACE) if (stage_egl->egl_surface == EGL_NO_SURFACE)
{ {
g_critical ("Unable to create an EGL surface"); g_critical ("Unable to create an EGL surface");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return; return;
} }
@ -173,29 +174,24 @@ clutter_stage_egl_realize (ClutterActor *actor)
/* this will make sure to set the current context */ /* this will make sure to set the current context */
CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context"); CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context");
CLUTTER_ACTOR_SET_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_egl, CLUTTER_ACTOR_REALIZED);
/* this should be done in ClutterBackend::ensure_context */
status = eglMakeCurrent (backend_egl->edpy, status = eglMakeCurrent (backend_egl->edpy,
stage_egl->egl_surface, stage_egl->egl_surface,
stage_egl->egl_surface, stage_egl->egl_surface,
backend_egl->egl_context); backend_egl->egl_context);
if (status != EGL_TRUE) if (status != EGL_TRUE)
g_warning ("eglMakeCurrent"); {
g_critical ("eglMakeCurrent failed");
/*clutter_stage_ensure_current (stage_egl->wrapper);*/ CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
} }
else else
{ {
g_warning("EGL Backend does not yet support offscreen rendering\n"); g_warning("EGL Backend does not yet support offscreen rendering\n");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
} }
CLUTTER_SET_PRIVATE_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
} }
static void static void

View File

@ -382,6 +382,8 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
if (backend_glx->gl_context == None) if (backend_glx->gl_context == None)
return; return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we /* we might get here inside the final dispose cycle, so we
* need to handle this gracefully * need to handle this gracefully
*/ */
@ -408,6 +410,11 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
stage_x11->xwin, stage_x11->xwin,
backend_glx->gl_context); backend_glx->gl_context);
} }
if (clutter_x11_untrap_x_errors ())
g_critical ("Unable to make the stage window 0x%x the current "
"GLX drawable",
(int) stage_x11->xwin);
} }
} }
@ -459,7 +466,7 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
CLUTTER_NOTE (BACKEND, "Creating stage of type `%s'", CLUTTER_NOTE (BACKEND, "Creating stage of type `%s'",
g_type_name (CLUTTER_STAGE_TYPE)); g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_STAGE_TYPE, NULL); stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
/* copy backend data into the stage */ /* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage); stage_x11 = CLUTTER_STAGE_X11 (stage);
@ -477,24 +484,6 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
stage_x11->xscreen, stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root); (unsigned int) stage_x11->xwin_root);
/* needed ? */
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
/* FIXME - is this needed? we should call realize inside the clutter
* init sequence for the default stage, and let the usual realization
* sequence be used for any other stage
*/
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
g_object_unref (stage);
return NULL;
}
return stage; return stage;
} }

View File

@ -102,9 +102,6 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
stage_x11->xwin = None; stage_x11->xwin = None;
} }
/* As unrealised the context will now get cleared */
clutter_stage_ensure_current (stage_x11->wrapper);
XSync (stage_x11->xdpy, False); XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors (); clutter_x11_untrap_x_errors ();
@ -115,10 +112,10 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
static void static void
clutter_stage_glx_realize (ClutterActor *actor) clutter_stage_glx_realize (ClutterActor *actor)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor);
ClutterBackendGLX *backend_glx; ClutterBackendGLX *backend_glx;
gboolean is_offscreen; gboolean is_offscreen;
CLUTTER_NOTE (MISC, "Realizing main stage"); CLUTTER_NOTE (MISC, "Realizing main stage");
@ -214,11 +211,8 @@ clutter_stage_glx_realize (ClutterActor *actor)
} }
} }
/* this will make sure to set the current context */ CLUTTER_NOTE (BACKEND, "Marking stage as realized");
CLUTTER_NOTE (BACKEND, "Marking stage as realized and setting context");
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
} }
else else
{ {
@ -281,20 +275,14 @@ clutter_stage_glx_realize (ClutterActor *actor)
} }
} }
clutter_x11_trap_x_errors (); CLUTTER_NOTE (BACKEND, "Marking stage as realized");
/* below will call glxMakeCurrent */
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
if (clutter_x11_untrap_x_errors ())
{
g_critical ("Unable to set up offscreen context.");
goto fail;
}
} }
/* we need to chain up to the X11 stage implementation in order to
* set the window state in case we set it before realizing the stage
*/
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->realize (actor);
return; return;
fail: fail:

View File

@ -95,19 +95,6 @@ clutter_backend_sdl_create_stage (ClutterBackend *backend,
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage)); _clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage));
g_object_set_data (G_OBJECT (stage), "clutter-backend", backend);
clutter_actor_realize (stage);
if (!CLUTTER_ACTOR_IS_REALIZED (stage))
{
g_set_error (error, CLUTTER_INIT_ERROR,
CLUTTER_INIT_ERROR_INTERNAL,
"Unable to realize the main stage");
g_object_unref (stage);
return NULL;
}
backend_sdl->stage = stage_sdl; backend_sdl->stage = stage_sdl;
return stage; return stage;

View File

@ -80,31 +80,21 @@ clutter_stage_sdl_realize (ClutterActor *actor)
0, flags) == NULL) 0, flags) == NULL)
{ {
CLUTTER_NOTE (BACKEND, "SDL appears not to handle this mode - %s", CLUTTER_NOTE (BACKEND, "SDL appears not to handle this mode - %s",
SDL_GetError()); SDL_GetError ());
CLUTTER_ACTOR_UNSET_FLAGS (stage_sdl, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_sdl->wrapper, return;
CLUTTER_ACTOR_REALIZED);
return;
} }
else else
{ CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_sdl, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_SET_FLAGS (stage_sdl->wrapper, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_sdl->wrapper);
}
} }
else else
{ {
/* FIXME */ /* FIXME */
g_warning("SDL Backend does not yet support offscreen rendering\n"); g_critical ("SDL Backend does not yet support offscreen rendering");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
} }
CLUTTER_NOTE (BACKEND, "SDL stage realized");
CLUTTER_SET_PRIVATE_FLAGS (stage_sdl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
} }
static void static void

View File

@ -229,6 +229,83 @@ clutter_stage_x11_request_coords (ClutterActor *self,
box); box);
} }
static inline void
set_wm_title (ClutterStageX11 *stage_x11)
{
ClutterBackendX11 *backend_x11 = stage_x11->backend;
if (stage_x11->xwin == None)
return;
if (stage_x11->title == NULL)
{
XDeleteProperty (stage_x11->xdpy,
stage_x11->xwin,
backend_x11->atom_NET_WM_NAME);
}
else
{
XChangeProperty (stage_x11->xdpy,
stage_x11->xwin,
backend_x11->atom_NET_WM_NAME,
backend_x11->atom_UTF8_STRING,
8,
PropModeReplace,
(unsigned char *) stage_x11->title,
(int) strlen (stage_x11->title));
}
}
static inline void
set_cursor_visible (ClutterStageX11 *stage_x11)
{
if (stage_x11->xwin == None)
return;
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)",
stage_x11->is_cursor_visible ? "visible" : "invisible",
(unsigned int) stage_x11->xwin);
if (stage_x11->is_cursor_visible)
{
#if 0 /* HAVE_XFIXES - seems buggy/unreliable */
XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XUndefineCursor (stage_x11->xdpy, stage_x11->xwin);
#endif /* HAVE_XFIXES */
}
else
{
#if 0 /* HAVE_XFIXES - seems buggy/unreliable, check cursor in firefox
* loading page after hiding.
*/
XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XColor col;
Pixmap pix;
Cursor curs;
pix = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin, 1, 1, 1);
memset (&col, 0, sizeof (col));
curs = XCreatePixmapCursor (stage_x11->xdpy,
pix, pix,
&col, &col,
1, 1);
XFreePixmap (stage_x11->xdpy, pix);
XDefineCursor (stage_x11->xdpy, stage_x11->xwin, curs);
#endif /* HAVE_XFIXES */
}
}
static void
clutter_stage_x11_realize (ClutterActor *actor)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
set_wm_title (stage_x11);
set_cursor_visible (stage_x11);
}
static void static void
clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window, clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
gboolean is_fullscreen) gboolean is_fullscreen)
@ -325,42 +402,9 @@ clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
if (stage_x11->xwin == None) stage_x11->is_cursor_visible = (cursor_visible == TRUE);
return;
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)", set_cursor_visible (stage_x11);
cursor_visible ? "visible" : "invisible",
(unsigned int) stage_x11->xwin);
if (cursor_visible)
{
#if 0 /* HAVE_XFIXES - seems buggy/unreliable */
XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XUndefineCursor (stage_x11->xdpy, stage_x11->xwin);
#endif /* HAVE_XFIXES */
}
else
{
#if 0 /* HAVE_XFIXES - seems buggy/unreliable, check cursor in firefox
* loading page after hiding.
*/
XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XColor col;
Pixmap pix;
Cursor curs;
pix = XCreatePixmap (stage_x11->xdpy, stage_x11->xwin, 1, 1, 1);
memset (&col, 0, sizeof (col));
curs = XCreatePixmapCursor (stage_x11->xdpy,
pix, pix,
&col, &col,
1, 1);
XFreePixmap (stage_x11->xdpy, pix);
XDefineCursor (stage_x11->xdpy, stage_x11->xwin, curs);
#endif /* HAVE_XFIXES */
}
} }
static void static void
@ -368,28 +412,11 @@ clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
const gchar *title) const gchar *title)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterBackendX11 *backend_x11 = stage_x11->backend;
if (stage_x11->xwin == None) g_free (stage_x11->title);
return; stage_x11->title = g_strdup (title);
if (title == NULL) set_wm_title (stage_x11);
{
XDeleteProperty (stage_x11->xdpy,
stage_x11->xwin,
backend_x11->atom_NET_WM_NAME);
}
else
{
XChangeProperty (stage_x11->xdpy,
stage_x11->xwin,
backend_x11->atom_NET_WM_NAME,
backend_x11->atom_UTF8_STRING,
8,
PropModeReplace,
(unsigned char*)title,
(int)strlen(title));
}
} }
static void static void
@ -407,6 +434,16 @@ clutter_stage_x11_get_wrapper (ClutterStageWindow *stage_window)
return CLUTTER_ACTOR (CLUTTER_STAGE_X11 (stage_window)->wrapper); return CLUTTER_ACTOR (CLUTTER_STAGE_X11 (stage_window)->wrapper);
} }
static void
clutter_stage_x11_finalize (GObject *gobject)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (gobject);
g_free (stage_x11->title);
G_OBJECT_CLASS (clutter_stage_x11_parent_class)->finalize (gobject);
}
static void static void
clutter_stage_x11_dispose (GObject *gobject) clutter_stage_x11_dispose (GObject *gobject)
{ {
@ -424,8 +461,10 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = clutter_stage_x11_finalize;
gobject_class->dispose = clutter_stage_x11_dispose; gobject_class->dispose = clutter_stage_x11_dispose;
actor_class->realize = clutter_stage_x11_realize;
actor_class->show = clutter_stage_x11_show; actor_class->show = clutter_stage_x11_show;
actor_class->hide = clutter_stage_x11_hide; actor_class->hide = clutter_stage_x11_hide;
actor_class->request_coords = clutter_stage_x11_request_coords; actor_class->request_coords = clutter_stage_x11_request_coords;
@ -447,13 +486,13 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
stage->is_foreign_xwin = FALSE; stage->is_foreign_xwin = FALSE;
stage->fullscreen_on_map = FALSE; stage->fullscreen_on_map = FALSE;
stage->handling_configure = FALSE; stage->handling_configure = FALSE;
stage->is_cursor_visible = TRUE;
stage->title = NULL;
stage->wrapper = NULL; stage->wrapper = NULL;
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL); CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL);
#if 0
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
#endif
} }
static void static void

View File

@ -45,8 +45,10 @@ struct _ClutterStageX11
{ {
ClutterGroup parent_instance; ClutterGroup parent_instance;
guint is_foreign_xwin : 1; guint is_foreign_xwin : 1;
guint fullscreen_on_map : 1; guint fullscreen_on_map : 1;
guint handling_configure : 1;
guint is_cursor_visible : 1;
Display *xdpy; Display *xdpy;
Window xwin_root; Window xwin_root;
@ -56,7 +58,7 @@ struct _ClutterStageX11
gint xwin_width; gint xwin_width;
gint xwin_height; /* FIXME target_width / height */ gint xwin_height; /* FIXME target_width / height */
Pixmap xpixmap; Pixmap xpixmap;
gboolean handling_configure; gchar *title;
ClutterBackendX11 *backend; ClutterBackendX11 *backend;
ClutterStageState state; ClutterStageState state;

View File

@ -10,7 +10,7 @@ tex_button_cb (ClutterActor *actor,
clutter_actor_hide (actor); clutter_actor_hide (actor);
} }
static void static gboolean
on_button_press (ClutterActor *actor, on_button_press (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
gpointer data) gpointer data)
@ -26,6 +26,8 @@ on_button_press (ClutterActor *actor,
ClutterBehaviour *r_behave; ClutterBehaviour *r_behave;
new_stage = clutter_stage_new (); new_stage = clutter_stage_new ();
if (!new_stage)
return FALSE;
/* FIXME: below should really be automatic */ /* FIXME: below should really be automatic */
/* clutter_stage_ensure_cogl_context (CLUTTER_STAGE(new_stage)); */ /* clutter_stage_ensure_cogl_context (CLUTTER_STAGE(new_stage)); */
@ -36,7 +38,7 @@ on_button_press (ClutterActor *actor,
tex = clutter_texture_new_from_file ("redhand.png", NULL); tex = clutter_texture_new_from_file ("redhand.png", NULL);
if (!tex) if (!tex)
g_error("pixbuf load failed"); g_error ("pixbuf load failed");
clutter_actor_set_reactive (tex, TRUE); clutter_actor_set_reactive (tex, TRUE);
g_signal_connect (tex, "button-press-event", g_signal_connect (tex, "button-press-event",
@ -88,6 +90,8 @@ on_button_press (ClutterActor *actor,
clutter_timeline_start (timeline); clutter_timeline_start (timeline);
clutter_actor_show_all (new_stage); clutter_actor_show_all (new_stage);
return TRUE;
} }
int int