diff --git a/ChangeLog b/ChangeLog index 37033fa23..a44fc2cb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,93 @@ +2008-05-12 Emmanuele Bassi + + 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 * clutter/clutter-timeline.c: diff --git a/HACKING.backends b/HACKING.backends index 538a3d31b..128be7529 100644 --- a/HACKING.backends +++ b/HACKING.backends @@ -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. diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c index 6622b1cf0..dc12a426e 100644 --- a/clutter/clutter-main.c +++ b/clutter/clutter-main.c @@ -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); diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c index 4ef258d25..55f328eb6 100644 --- a/clutter/clutter-stage.c +++ b/clutter/clutter-stage.c @@ -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); diff --git a/clutter/eglnative/clutter-backend-egl.c b/clutter/eglnative/clutter-backend-egl.c index f79a1da04..bc6f7b4e6 100644 --- a/clutter/eglnative/clutter-backend-egl.c +++ b/clutter/eglnative/clutter-backend-egl.c @@ -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; diff --git a/clutter/eglnative/clutter-stage-egl.c b/clutter/eglnative/clutter-stage-egl.c index 0e7d77d36..504376644 100644 --- a/clutter/eglnative/clutter-stage-egl.c +++ b/clutter/eglnative/clutter-stage-egl.c @@ -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 diff --git a/clutter/eglx/clutter-backend-egl.c b/clutter/eglx/clutter-backend-egl.c index 63ef6a6ee..6ff874157 100644 --- a/clutter/eglx/clutter-backend-egl.c +++ b/clutter/eglx/clutter-backend-egl.c @@ -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; } diff --git a/clutter/eglx/clutter-stage-egl.c b/clutter/eglx/clutter-stage-egl.c index bfd00c90e..62140298f 100644 --- a/clutter/eglx/clutter-stage-egl.c +++ b/clutter/eglx/clutter-stage-egl.c @@ -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,49 +107,48 @@ 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); + eglGetConfigs (clutter_eglx_display (), NULL, 0, &num_configs); all_configs = g_malloc (num_configs * sizeof (EGLConfig)); - - eglGetConfigs (clutter_eglx_display(), + eglGetConfigs (clutter_eglx_display (), all_configs, num_configs, &num_configs); - for (c=0; cedpy, 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 diff --git a/clutter/fruity/clutter-backend-fruity.c b/clutter/fruity/clutter-backend-fruity.c index 75400bcf4..35be50ce3 100644 --- a/clutter/fruity/clutter-backend-fruity.c +++ b/clutter/fruity/clutter-backend-fruity.c @@ -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; diff --git a/clutter/fruity/clutter-stage-fruity.c b/clutter/fruity/clutter-stage-fruity.c index 5050651b0..2380a4a00 100644 --- a/clutter/fruity/clutter-stage-fruity.c +++ b/clutter/fruity/clutter-stage-fruity.c @@ -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 diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index 5b738c1ca..66335ca1a 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -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; } diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index a60c75eef..f4a0920c0 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -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 (); @@ -115,10 +112,10 @@ clutter_stage_glx_unrealize (ClutterActor *actor) static void clutter_stage_glx_realize (ClutterActor *actor) { - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); - ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); + ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterBackendGLX *backend_glx; - gboolean is_offscreen; + gboolean is_offscreen; 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 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: diff --git a/clutter/sdl/clutter-backend-sdl.c b/clutter/sdl/clutter-backend-sdl.c index c443e547b..a06cd3957 100644 --- a/clutter/sdl/clutter-backend-sdl.c +++ b/clutter/sdl/clutter-backend-sdl.c @@ -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; diff --git a/clutter/sdl/clutter-stage-sdl.c b/clutter/sdl/clutter-stage-sdl.c index f71f1aa42..1c1f608c0 100644 --- a/clutter/sdl/clutter-stage-sdl.c +++ b/clutter/sdl/clutter-stage-sdl.c @@ -80,31 +80,21 @@ clutter_stage_sdl_realize (ClutterActor *actor) 0, flags) == NULL) { 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 (stage_sdl->wrapper, - CLUTTER_ACTOR_REALIZED); - return; + 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 diff --git a/clutter/x11/clutter-stage-x11.c b/clutter/x11/clutter-stage-x11.c index a3d99e6b4..e323b4b36 100644 --- a/clutter/x11/clutter-stage-x11.c +++ b/clutter/x11/clutter-stage-x11.c @@ -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 diff --git a/clutter/x11/clutter-stage-x11.h b/clutter/x11/clutter-stage-x11.h index 9d023d04c..bb2f9469c 100644 --- a/clutter/x11/clutter-stage-x11.h +++ b/clutter/x11/clutter-stage-x11.h @@ -45,8 +45,10 @@ struct _ClutterStageX11 { ClutterGroup parent_instance; - guint is_foreign_xwin : 1; - guint fullscreen_on_map : 1; + 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; diff --git a/tests/test-multistage.c b/tests/test-multistage.c index 81f67bfaa..e1b5498a5 100644 --- a/tests/test-multistage.c +++ b/tests/test-multistage.c @@ -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)); */ @@ -36,7 +38,7 @@ on_button_press (ClutterActor *actor, tex = clutter_texture_new_from_file ("redhand.png", NULL); if (!tex) - g_error("pixbuf load failed"); + g_error ("pixbuf load failed"); clutter_actor_set_reactive (tex, TRUE); g_signal_connect (tex, "button-press-event", @@ -88,6 +90,8 @@ on_button_press (ClutterActor *actor, clutter_timeline_start (timeline); clutter_actor_show_all (new_stage); + + return TRUE; } int