[clutter/deprecate-default-stage: 7/11] Try to mop up the default stage mess



commit ef89a561431ce422dd8480fb7f56e849c67304b9
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Wed Nov 9 14:04:05 2011 +0000

    Try to mop up the default stage mess
    
    The default stage was a neat concept when we started Clutter out,
    somewhere in the Jurassic era; a singleton instance that gets created at
    initialization time, and remains the same for the entire duration of the
    process.
    
    Worked well enough when Clutter was a small library meant to be used to
    write fullscreen media browsers, but since the introduction of multiple
    stages, and Clutter being used to create all sorts of applications, the
    default stage is just a vestigial remainder of that past, like an
    appendix; something that complicates the layout of the code and
    introduces weird behaviour, so that you notice its existence only when
    something goes wrong.
    
    Some platforms we do support, though, only have one framebuffer, so it
    makes sense for them to have only one stage.
    
    At this point, the only sane thing to do is to go through the same code
    paths on all platforms, and that code path is the stage instance
    creation and initialization â i.e. clutter_stage_new() (or
    g_object_new() with CLUTTER_TYPE_STAGE).
    
    For platforms that support multiple stages, nothing has changed: the stage
    created by clutter_stage_get_default() will be set as the default one;
    if nobody calls it, the default stage is never created, and it just
    lives on as a meaningless check.
    
    For platforms that only support one stage, clutter_stage_new() and
    clutter_stage_get_default() will behave exactly the same the first time
    they are called: both will create a stage, and set it as the default.
    Calling clutter_stage_new() a second time is treated as a programmer
    error, and will result in Clutter aborting. This is a behavioural change
    because the existing behaviour or creating a new ClutterStage instance
    with the same ClutterStageWindow private implementation is, simply put,
    utterly braindamaged and I should have *never* had written it, and I
    apologize for it. In my defence, I didn't know any better at the time.
    
    This is the first step towards the complete deprecation of
    clutter_stage_get_default() and clutter_stage_is_default(), which will
    come later.

 clutter/clutter-backend.c |    5 --
 clutter/clutter-stage.c   |  114 +++++++++++++++++++++++++++++++--------------
 2 files changed, 79 insertions(+), 40 deletions(-)
---
diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c
index 7243cac..c082de8 100644
--- a/clutter/clutter-backend.c
+++ b/clutter/clutter-backend.c
@@ -380,14 +380,11 @@ _clutter_backend_create_stage (ClutterBackend  *backend,
                                GError         **error)
 {
   ClutterBackendClass *klass;
-  ClutterStageManager *stage_manager;
   ClutterStageWindow *stage_window;
 
   g_assert (CLUTTER_IS_BACKEND (backend));
   g_assert (CLUTTER_IS_STAGE (wrapper));
 
-  stage_manager = clutter_stage_manager_get_default ();
-
   klass = CLUTTER_BACKEND_GET_CLASS (backend);
   if (klass->create_stage != NULL)
     stage_window = klass->create_stage (backend, wrapper, error);
@@ -398,8 +395,6 @@ _clutter_backend_create_stage (ClutterBackend  *backend,
     return NULL;
 
   g_assert (CLUTTER_IS_STAGE_WINDOW (stage_window));
-  _clutter_stage_set_window (wrapper, stage_window);
-  _clutter_stage_manager_add_stage (stage_manager, wrapper);
 
   return stage_window;
 }
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index 416ca4f..f606ec2 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -30,11 +30,6 @@
  * #ClutterStage is a top level 'window' on which child actors are placed
  * and manipulated.
  *
- * Clutter creates a default stage upon initialization, which can be retrieved
- * using clutter_stage_get_default(). Clutter always provides the default
- * stage, unless the backend is unable to create one. The stage returned
- * by clutter_stage_get_default() is guaranteed to always be the same.
- *
  * Backends might provide support for multiple stages. The support for this
  * feature can be checked at run-time using the clutter_feature_available()
  * function and the %CLUTTER_FEATURE_STAGE_MULTIPLE flag. If the backend used
@@ -1498,6 +1493,45 @@ clutter_stage_real_apply_transform (ClutterActor *stage,
 }
 
 static void
+clutter_stage_constructed (GObject *gobject)
+{
+  ClutterStage *self = CLUTTER_STAGE (gobject);
+  ClutterStageManager *stage_manager;
+
+  stage_manager = clutter_stage_manager_get_default ();
+
+  _clutter_stage_manager_add_stage (stage_manager, self);
+
+  /* if this stage has been created on a backend that does not
+   * support multiple stages then it becomes the default stage
+   * as well; any other attempt at creating a ClutterStage will
+   * fail.
+   */
+  if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
+    {
+      if (G_UNLIKELY (clutter_stage_manager_get_default_stage (stage_manager) != NULL))
+        {
+          g_error ("Unable to create another stage: the backend of "
+                   "type '%s' does not support multiple stages. Use "
+                   "clutter_stage_get_default() instead to access the "
+                   "stage singleton.",
+                   G_OBJECT_TYPE_NAME (clutter_get_default_backend ()));
+        }
+
+      /* This will take care of automatically adding the stage to the
+       * stage manager and setting it as the default. Its floating
+       * reference will be claimed by the stage manager.
+       */
+      _clutter_stage_manager_set_default_stage (stage_manager, self);
+
+      /* the default stage is realized by default */
+      clutter_actor_realize (CLUTTER_ACTOR (self));
+    }
+
+  G_OBJECT_CLASS (clutter_stage_parent_class)->constructed (gobject);
+}
+
+static void
 clutter_stage_set_property (GObject      *object,
 			    guint         prop_id,
 			    const GValue *value,
@@ -1696,6 +1730,7 @@ clutter_stage_class_init (ClutterStageClass *klass)
   ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
   GParamSpec *pspec;
 
+  gobject_class->constructed = clutter_stage_constructed;
   gobject_class->set_property = clutter_stage_set_property;
   gobject_class->get_property = clutter_stage_get_property;
   gobject_class->dispose = clutter_stage_dispose;
@@ -2037,8 +2072,10 @@ static void
 clutter_stage_init (ClutterStage *self)
 {
   ClutterStagePrivate *priv;
+  ClutterStageWindow *impl;
   ClutterBackend *backend;
   cairo_rectangle_int_t geom;
+  GError *error;
 
   /* a stage is a top-level object */
   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IS_TOPLEVEL);
@@ -2047,25 +2084,31 @@ clutter_stage_init (ClutterStage *self)
 
   CLUTTER_NOTE (BACKEND, "Creating stage from the default backend");
   backend = clutter_get_default_backend ();
-  priv->impl = _clutter_backend_create_stage (backend, self, NULL);
-  if (!priv->impl)
-    {
-      g_warning ("Unable to create a new stage, falling back to the "
-                 "default stage.");
-      priv->impl = _clutter_stage_get_default_window ();
 
-      /* at this point we must have a default stage, or we're screwed */
-      g_assert (priv->impl != NULL);
+  error = NULL;
+  impl = _clutter_backend_create_stage (backend, self, &error);
+  if (G_UNLIKELY (impl == NULL))
+    {
+      if (error != NULL)
+        {
+          g_critical ("Unable to create a new stage implementation: %s",
+                      error->message);
+          g_error_free (error);
+        }
+      else
+        g_critical ("Unable to create a new stage implementation.");
     }
 
+  _clutter_stage_set_window (self, impl);
+
   priv->event_queue = g_queue_new ();
 
-  priv->is_fullscreen          = FALSE;
-  priv->is_user_resizable      = FALSE;
-  priv->is_cursor_visible      = TRUE;
-  priv->use_fog                = FALSE;
+  priv->is_fullscreen = FALSE;
+  priv->is_user_resizable = FALSE;
+  priv->is_cursor_visible = TRUE;
+  priv->use_fog = FALSE;
   priv->throttle_motion_events = TRUE;
-  priv->min_size_changed       = FALSE;
+  priv->min_size_changed = FALSE;
 
   /* XXX - we need to keep the invariant that calling
    * clutter_set_motion_event_enabled() before the stage creation
@@ -2133,15 +2176,26 @@ clutter_stage_init (ClutterStage *self)
 /**
  * clutter_stage_get_default:
  *
- * Returns the main stage. The default #ClutterStage is a singleton,
- * so the stage will be created the first time this function is
- * called (typically, inside clutter_init()); all the subsequent
- * calls to clutter_stage_get_default() will return the same instance.
+ * Retrieves a #ClutterStage singleton.
+ *
+ * This function is not as useful as it sounds, and will most likely
+ * by deprecated in the future. Application code should only create
+ * a #ClutterStage instance using clutter_stage_new(), and manage the
+ * lifetime of the stage manually.
+ *
+ * The default stage singleton has a platform-specific behaviour: on
+ * platforms without the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag
+ * set, the first #ClutterStage instance will also be set to be the
+ * default stage instance, and this function will always return a
+ * pointer to it.
  *
- * Clutter guarantess the existence of the default stage.
+ * On platforms with the %CLUTTER_FEATURE_STAGE_MULTIPLE feature flag
+ * set, the default stage will be created by the first call to this
+ * function, and every following call will return the same pointer to
+ * it.
  *
  * Return value: (transfer none) (type Clutter.Stage): the main
- *   #ClutterStage.  You should never destroy or unref the returned
+ *   #ClutterStage. You should never destroy or unref the returned
  *   actor.
  */
 ClutterActor *
@@ -3149,16 +3203,6 @@ G_DEFINE_BOXED_TYPE (ClutterFog, clutter_fog, clutter_fog_copy, clutter_fog_free
 ClutterActor *
 clutter_stage_new (void)
 {
-  if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_MULTIPLE))
-    {
-      g_warning ("Unable to create a new stage: the %s backend does not "
-                 "support multiple stages.",
-                 CLUTTER_FLAVOUR);
-      return NULL;
-    }
-
-  /* The stage manager will grab the floating reference when the stage
-     is added to it in the constructor */
   return g_object_new (CLUTTER_TYPE_STAGE, NULL);
 }
 
@@ -3480,7 +3524,7 @@ _clutter_stage_set_window (ClutterStage       *stage,
   g_return_if_fail (CLUTTER_IS_STAGE (stage));
   g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (stage_window));
 
-  if (stage->priv->impl)
+  if (stage->priv->impl != NULL)
     g_object_unref (stage->priv->impl);
 
   stage->priv->impl = stage_window;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]