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>
* 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
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
can be overridden:
@ -106,10 +110,8 @@ can be overridden:
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (impl));
The backend must also call clutter_actor_realize() on the stage
implementation, and then check if the stage has been realized, using
the CLUTTER_ACTOR_IS_REALIZED() macro; if the stage was not
realized, it must return NULL and set the passed GError.
in case of error, the backend must return NULL and set the passed
GError.
Implementing the stage
----------------------
@ -130,9 +132,7 @@ the stage implementation should:
- create a new native window handle
- if the backend doesn't have a drawing context (either GL or GLES),
create one and assing it to the backend
- set the CLUTTER_ACTOR_REALIZED flag on *both* the wrapper and the
stage implementation (this is very important)
- call clutter_stage_ensure_current() with the wrapper instance
- set the CLUTTER_ACTOR_REALIZED flag on itself
In case of failure, the CLUTTER_ACTOR_REALIZED flag should be unset on
the stage implementation.
@ -141,7 +141,6 @@ Inside the ::unrealize function the stage implementation should:
- unset the CLUTTER_ACTOR_REALIZED flag on itself
- destroy the native window handle
- call clutter_stage_ensure_current() with the wrapper instance
NOTES
=====
@ -152,9 +151,6 @@ implementation for event handling and window management.
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
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;
}
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_feature_init ();
@ -1195,6 +1205,14 @@ clutter_init (int *argc,
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 */
_clutter_backend_init_events (context->backend);

View File

@ -187,13 +187,16 @@ clutter_stage_realize (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
/* then realize the implementation */
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
g_assert (priv->impl != NULL);
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))
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
}
@ -209,6 +212,8 @@ clutter_stage_unrealize (ClutterActor *self)
/* and then unrealize the implementation */
g_assert (priv->impl != NULL);
CLUTTER_ACTOR_GET_CLASS (priv->impl)->unrealize (priv->impl);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
}
static void
@ -217,6 +222,10 @@ clutter_stage_show (ClutterActor *self)
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
if (!CLUTTER_ACTOR_IS_REALIZED (priv->impl))
clutter_actor_realize (priv->impl);
clutter_actor_show (priv->impl);
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));
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);
return stage;

View File

@ -62,8 +62,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
clutter_stage_ensure_current (stage_egl->wrapper);
}
static void
@ -179,7 +177,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
}
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);
/* eglnative can have only one stage */
@ -202,8 +199,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
CLUTTER_SET_PRIVATE_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
}
static void

View File

@ -81,6 +81,8 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
if (!backend_egl->egl_context)
return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
@ -100,6 +102,11 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend,
stage_egl->egl_surface,
stage_egl->egl_surface,
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,
(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;
}

View File

@ -63,8 +63,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
stage_egl->egl_surface = EGL_NO_SURFACE;
}
clutter_stage_ensure_current (stage_x11->wrapper);
XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
@ -91,6 +89,11 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (G_LIKELY (!is_offscreen))
{
int c;
int num_configs;
int max_tex_units;
EGLConfig *all_configs;
EGLint cfg_attribs[] = {
EGL_BUFFER_SIZE, EGL_DONT_CARE,
EGL_RED_SIZE, 5,
@ -104,14 +107,9 @@ clutter_stage_egl_realize (ClutterActor *actor)
2,
&config_count);
int c;
int num_configs;
EGLConfig *all_configs;
eglGetConfigs (clutter_eglx_display (), NULL, 0, &num_configs);
all_configs = g_malloc (num_configs * sizeof (EGLConfig));
eglGetConfigs (clutter_eglx_display (),
all_configs,
num_configs,
@ -120,6 +118,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
for (c = 0; c < num_configs; ++c)
{
EGLint red = -1, green = -1, blue = -1, alpha = -1, stencil = -1;
eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c],
EGL_RED_SIZE, &red);
@ -135,18 +134,21 @@ clutter_stage_egl_realize (ClutterActor *actor)
eglGetConfigAttrib (clutter_eglx_display (),
all_configs[c],
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);
}
int max_tex_units = 0;
max_tex_units = 0;
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);
if (status != EGL_TRUE)
g_warning ("eglGetConfigs failed");
{
g_critical ("eglGetConfigs failed");
goto fail;
}
status = eglChooseConfig (backend_egl->edpy,
cfg_attribs,
@ -155,7 +157,10 @@ clutter_stage_egl_realize (ClutterActor *actor)
&config_count);
if (status != EGL_TRUE)
g_warning ("eglChooseConfig failed");
{
g_critical ("eglChooseConfig failed");
goto fail;
}
if (stage_x11->xwin == None)
stage_x11->xwin =
@ -198,9 +203,7 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (stage_egl->egl_surface == EGL_NO_SURFACE)
{
g_critical ("Unable to create an EGL surface");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
goto fail;
}
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)
{
g_critical ("Unable to create a suitable EGL context");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
goto fail;
}
}
/* this will make sure to set the current context */
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);
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
else
{
g_warning("EGLX Backend does not support offscreen rendering");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
g_critical ("EGLX Backend does not support offscreen rendering");
goto fail;
}
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

View File

@ -99,19 +99,6 @@ clutter_backend_egl_create_stage (ClutterBackend *backend,
_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);
return stage;

View File

@ -61,8 +61,6 @@ clutter_stage_egl_unrealize (ClutterActor *actor)
eglDestroySurface (clutter_egl_display (), stage_egl->egl_surface);
stage_egl->egl_surface = EGL_NO_SURFACE;
}
clutter_stage_ensure_current (stage_egl->wrapper);
}
static void
@ -108,7 +106,11 @@ clutter_stage_egl_realize (ClutterActor *actor)
&config_count);
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)
{
@ -133,7 +135,6 @@ clutter_stage_egl_realize (ClutterActor *actor)
if (stage_egl->egl_surface == EGL_NO_SURFACE)
{
g_critical ("Unable to create an EGL surface");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
@ -173,29 +174,24 @@ clutter_stage_egl_realize (ClutterActor *actor)
/* this will make sure to set the current 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,
stage_egl->egl_surface,
stage_egl->egl_surface,
backend_egl->egl_context);
if (status != EGL_TRUE)
g_warning ("eglMakeCurrent");
/*clutter_stage_ensure_current (stage_egl->wrapper);*/
{
g_critical ("eglMakeCurrent failed");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
}
else
{
g_warning("EGL Backend does not yet support offscreen rendering\n");
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
CLUTTER_SET_PRIVATE_FLAGS (stage_egl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
}
static void

View File

@ -382,6 +382,8 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
if (backend_glx->gl_context == None)
return;
clutter_x11_trap_x_errors ();
/* we might get here inside the final dispose cycle, so we
* need to handle this gracefully
*/
@ -408,6 +410,11 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend,
stage_x11->xwin,
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'",
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 */
stage_x11 = CLUTTER_STAGE_X11 (stage);
@ -477,24 +484,6 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
stage_x11->xscreen,
(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;
}

View File

@ -102,9 +102,6 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
stage_x11->xwin = None;
}
/* As unrealised the context will now get cleared */
clutter_stage_ensure_current (stage_x11->wrapper);
XSync (stage_x11->xdpy, False);
clutter_x11_untrap_x_errors ();
@ -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 and setting context");
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_NOTE (BACKEND, "Marking stage as realized");
CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (stage_x11->wrapper);
}
else
{
@ -281,20 +275,14 @@ clutter_stage_glx_realize (ClutterActor *actor)
}
}
clutter_x11_trap_x_errors ();
/* below will call glxMakeCurrent */
CLUTTER_ACTOR_SET_FLAGS (stage_x11->wrapper, CLUTTER_ACTOR_REALIZED);
CLUTTER_NOTE (BACKEND, "Marking stage as 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;
fail:

View File

@ -95,19 +95,6 @@ clutter_backend_sdl_create_stage (ClutterBackend *backend,
_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;
return stage;

View File

@ -82,29 +82,19 @@ clutter_stage_sdl_realize (ClutterActor *actor)
CLUTTER_NOTE (BACKEND, "SDL appears not to handle this mode - %s",
SDL_GetError ());
CLUTTER_ACTOR_UNSET_FLAGS (stage_sdl, CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (stage_sdl->wrapper,
CLUTTER_ACTOR_REALIZED);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
return;
}
else
{
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);
}
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
else
{
/* 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);
return;
}
CLUTTER_NOTE (BACKEND, "SDL stage realized");
CLUTTER_SET_PRIVATE_FLAGS (stage_sdl->wrapper, CLUTTER_ACTOR_SYNC_MATRICES);
}
static void

View File

@ -229,6 +229,83 @@ clutter_stage_x11_request_coords (ClutterActor *self,
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
clutter_stage_x11_set_fullscreen (ClutterStageWindow *stage_window,
gboolean is_fullscreen)
@ -325,42 +402,9 @@ clutter_stage_x11_set_cursor_visible (ClutterStageWindow *stage_window,
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
if (stage_x11->xwin == None)
return;
stage_x11->is_cursor_visible = (cursor_visible == TRUE);
CLUTTER_NOTE (BACKEND, "setting cursor state ('%s') over stage window (%u)",
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 */
}
set_cursor_visible (stage_x11);
}
static void
@ -368,28 +412,11 @@ clutter_stage_x11_set_title (ClutterStageWindow *stage_window,
const gchar *title)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterBackendX11 *backend_x11 = stage_x11->backend;
if (stage_x11->xwin == None)
return;
g_free (stage_x11->title);
stage_x11->title = g_strdup (title);
if (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*)title,
(int)strlen(title));
}
set_wm_title (stage_x11);
}
static void
@ -407,6 +434,16 @@ clutter_stage_x11_get_wrapper (ClutterStageWindow *stage_window)
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
clutter_stage_x11_dispose (GObject *gobject)
{
@ -424,8 +461,10 @@ clutter_stage_x11_class_init (ClutterStageX11Class *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = clutter_stage_x11_finalize;
gobject_class->dispose = clutter_stage_x11_dispose;
actor_class->realize = clutter_stage_x11_realize;
actor_class->show = clutter_stage_x11_show;
actor_class->hide = clutter_stage_x11_hide;
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->fullscreen_on_map = FALSE;
stage->handling_configure = FALSE;
stage->is_cursor_visible = TRUE;
stage->title = NULL;
stage->wrapper = NULL;
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_IS_TOPLEVEL);
#if 0
CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
#endif
}
static void

View File

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

View File

@ -10,7 +10,7 @@ tex_button_cb (ClutterActor *actor,
clutter_actor_hide (actor);
}
static void
static gboolean
on_button_press (ClutterActor *actor,
ClutterEvent *event,
gpointer data)
@ -26,6 +26,8 @@ on_button_press (ClutterActor *actor,
ClutterBehaviour *r_behave;
new_stage = clutter_stage_new ();
if (!new_stage)
return FALSE;
/* FIXME: below should really be automatic */
/* clutter_stage_ensure_cogl_context (CLUTTER_STAGE(new_stage)); */
@ -88,6 +90,8 @@ on_button_press (ClutterActor *actor,
clutter_timeline_start (timeline);
clutter_actor_show_all (new_stage);
return TRUE;
}
int