2006-12-04 Emmanuele Bassi <ebassi@openedhand.com>
authorEmmanuele Bassi <ebassi@openedhand.com>
Mon, 4 Dec 2006 19:19:53 +0000 (19:19 +0000)
committerEmmanuele Bassi <ebassi@openedhand.com>
Mon, 4 Dec 2006 19:19:53 +0000 (19:19 +0000)
Avoid clutter segfaulting when used without invoking
clutter_init().  This is needed when using api documentation
tools and every other tool relying on the GObject
introspection API (esp. on a headless box).  see the
note in clutter/clutter-feature.c:clutter_feature_init
for a full explanation.

* clutter/clutter-feature.c: Call clutter_feature_init()
when needed by one of the accessors of the features
structure.

* clutter/clutter-main.c:
* clutter/clutter-private.h: Remove clutter_feature_init()
public declaration: the features support check is done the
first time a feature is needed.

* clutter/clutter-main.c: Do not ever access the clutter
main context pointer directly; instead, obtain a pointer
to it via clutter_context_get_default(), which will always
return something valid.

ChangeLog
clutter/clutter-feature.c
clutter/clutter-main.c
clutter/clutter-private.h
doc/reference/Makefile.am
doc/reference/tmpl/clutter-behaviour-scale.sgml

index 139fc23..74615a3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,28 @@
 2006-12-04  Emmanuele Bassi  <ebassi@openedhand.com>
 
+       Avoid clutter segfaulting when used without invoking
+       clutter_init().  This is needed when using api documentation
+       tools and every other tool relying on the GObject
+       introspection API (esp. on a headless box).  see the
+       note in clutter/clutter-feature.c:clutter_feature_init
+       for a full explanation.
+
+       * clutter/clutter-feature.c: Call clutter_feature_init()
+       when needed by one of the accessors of the features
+       structure.
+
+       * clutter/clutter-main.c:
+       * clutter/clutter-private.h: Remove clutter_feature_init()
+       public declaration: the features support check is done the
+       first time a feature is needed.
+
+       * clutter/clutter-main.c: Do not ever access the clutter
+       main context pointer directly; instead, obtain a pointer
+       to it via clutter_context_get_default(), which will always
+       return something valid.
+
+2006-12-04  Emmanuele Bassi  <ebassi@openedhand.com>
+
        * clutter/clutter-private.h: Add our own READABLE,
        WRITABLE and READWRITE paramspec flags, declaring the
        string components of the properties GParamSpec as static;
index cb73d44..031fad5 100644 (file)
@@ -76,9 +76,11 @@ typedef struct ClutterFeatures
   gint                dri_fd;
   ClutterVBlankType   vblank_type;
 
+  guint               features_set : 1;
 } ClutterFeatures;
 
 static ClutterFeatures* __features = NULL;
+G_LOCK_DEFINE_STATIC (__features);
 
 /* #ifdef linux */
 #define DRM_VBLANK_RELATIVE 0x1;
@@ -125,10 +127,11 @@ static int drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
 
 /* Note must be called after context created */
 static gboolean 
-check_gl_extension (const gchar *name,  const gchar *ext)
+check_gl_extension (const gchar *name,
+                    const gchar *ext)
 {
-  gchar       *end;
-  gint         name_len, n;
+  gchar *end;
+  gint name_len, n;
 
   if (name == NULL || ext == NULL)
     return FALSE;
@@ -162,22 +165,27 @@ get_proc_address (const gchar *name)
       if (dlhand)
        {
          dlerror ();
-         get_proc_func 
-           = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
+
+         get_proc_func =
+            (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddress");
+
          if (dlerror () != NULL)
-           get_proc_func 
-             = (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
+            {
+              get_proc_func =
+                (GLXGetProcAddressProc) dlsym (dlhand, "glXGetProcAddressARB");
+            }
+
          if (dlerror () != NULL)
            {
              get_proc_func = NULL;
-             g_warning 
-               ("failed to bind GLXGetProcAddress or GLXGetProcAddressARB");
+             g_warning ("failed to bind GLXGetProcAddress "
+                         "or GLXGetProcAddressARB");
            }
        }
     }
 
   if (get_proc_func)
-    return get_proc_func ((unsigned char*)name);
+    return get_proc_func ((unsigned char*) name);
 
   return NULL;
 }
@@ -196,25 +204,54 @@ check_vblank_env (const char *name)
   return FALSE;
 }
 
-void
+/* clutter_feature_init:
+ * must be called with the static lock on __features held, to keep it
+ * mt-safe.
+ *
+ * XXX - here we need a bit of weird machinery in place.  the features
+ * are checked at run time, each time we try to access them - unless
+ * we already checked them once.  unfortunately, we need an open
+ * X display if we want to check them, so ideally we'd need to call
+ * clutter_init() before checking for any feature.  the generator for
+ * the api documentation, and more in general every tool relying on the
+ * introspection API provided by GObject, may well not be able to call
+ * clutter_init() (and neither they should be, as we might be running
+ * them on a headless build box).  so, we need a way to get the features
+ * without explicitely calling clutter_feature_init() inside clutter_init()
+ * and we also need to have an open X display when we test for the features.
+ * __features is dynamically allocated, and applications tend to badly
+ * crash when trying to access __features; so when can't use a NULL check
+ * to know whether we already invoked clutter_feature_init() once; hence,
+ * we must allocate it anyway, and have a flag to let us know when the
+ * features have been set - that is when clutter_feature_init() has been
+ * successfully completed with an open X display.
+ */
+static void
 clutter_feature_init (void)
 {
   const gchar *gl_extensions, *glx_extensions;
+  
+  CLUTTER_NOTE (MISC, "checking features");
 
-  if (__features != NULL)
+  if (!__features)
     {
-      g_warning ("You should never call clutter_feature_init() "
-                 "more than once.");
-      return;
+      CLUTTER_NOTE (MISC, "allocating features data");
+
+      __features = g_new0 (ClutterFeatures, 1);
+      memset(&__features->funcs, 0, sizeof(ClutterFeatureFuncs));
+      __features->features_set = FALSE; /* don't rely on zero-ing */
     }
 
-  __features = g_new0 (ClutterFeatures, 1);
-  memset(&__features->funcs, 0, sizeof(ClutterFeatureFuncs));
+  if (!clutter_xdisplay ())
+    return;
 
-  gl_extensions = (const gchar*)glGetString(GL_EXTENSIONS);
-  glx_extensions = glXQueryExtensionsString (clutter_xdisplay(), 
-                                            clutter_xscreen());
+  if (__features->features_set)
+    return;
 
+  gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
+  glx_extensions = glXQueryExtensionsString (clutter_xdisplay (),
+                                             clutter_xscreen ());
+  
   if (check_gl_extension ("GL_ARB_texture_rectangle", gl_extensions))
     __features->flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
 
@@ -228,8 +265,8 @@ clutter_feature_init (void)
     }
   else
     {
-      if (!check_vblank_env("dri") 
-         && check_gl_extension ("GLX_SGI_video_sync", glx_extensions))
+      if (!check_vblank_env("dri") && 
+         check_gl_extension ("GLX_SGI_video_sync", glx_extensions))
        {
          __features->funcs.get_video_sync = 
             (GLXGetVideoSyncProc) get_proc_address ("glXGetVideoSyncSGI");
@@ -237,8 +274,8 @@ clutter_feature_init (void)
          __features->funcs.wait_video_sync = 
            (GLXWaitVideoSyncProc) get_proc_address ("glXWaitVideoSyncSGI");
 
-         if (__features->funcs.get_video_sync != NULL
-             && __features->funcs.wait_video_sync != NULL)
+         if ((__features->funcs.get_video_sync != NULL) &&
+             (__features->funcs.wait_video_sync != NULL))
            {
              CLUTTER_NOTE (MISC, "vblank sync: using glx");
              
@@ -265,6 +302,18 @@ clutter_feature_init (void)
                         "vblank sync: no use-able mechanism found");
         }
     }
+
+  CLUTTER_NOTE (MISC, "features checked");
+
+  __features->features_set = TRUE;
+}
+
+static void
+clutter_feature_do_init (void)
+{
+  G_LOCK (__features);
+  clutter_feature_init ();
+  G_UNLOCK (__features);
 }
 
 /**
@@ -281,13 +330,15 @@ clutter_feature_init (void)
 gboolean
 clutter_feature_available (ClutterFeatureFlags feature)
 {
+  clutter_feature_do_init ();
+
   return (__features->flags & feature);
 }
 
 /**
  * clutter_feature_get_all:
  *
- * Returns all the suppoerted features.
+ * Returns all the supported features.
  *
  * Return value: a logical OR of all the supported features.
  *
@@ -296,6 +347,8 @@ clutter_feature_available (ClutterFeatureFlags feature)
 ClutterFeatureFlags
 clutter_feature_get_all (void)
 {
+  clutter_feature_do_init ();
+
   return __features->flags;
 }
 
@@ -309,14 +362,17 @@ clutter_feature_get_all (void)
 void
 clutter_feature_wait_for_vblank (void)
 {
+  clutter_feature_do_init ();
+
   switch (__features->vblank_type)
     {
     case CLUTTER_VBLANK_GLX:
       {
        unsigned int retraceCount;
-       __features->funcs.get_video_sync(&retraceCount);
-       __features->funcs.wait_video_sync(2, 
-                                         (retraceCount+1)%2, &retraceCount); 
+       __features->funcs.get_video_sync (&retraceCount);
+       __features->funcs.wait_video_sync (2, 
+                                          (retraceCount + 1) % 2,
+                                           &retraceCount); 
       }
       break;
     case CLUTTER_VBLANK_DRI:
index 66b5d0a..ca50cff 100644 (file)
@@ -235,16 +235,18 @@ clutter_dispatch_x_event (XEvent  *xevent,
 static void
 events_init()
 {
+  ClutterMainContext   *clutter_context;
   GMainContext         *gmain_context;
   int                   connection_number;
   GSource              *source;
   ClutterXEventSource  *display_source;
 
+  clutter_context = clutter_context_get_default ();
   gmain_context = g_main_context_default ();
 
   g_main_context_ref (gmain_context);
 
-  connection_number = ConnectionNumber (ClutterCntx->xdpy);
+  connection_number = ConnectionNumber (clutter_context->xdpy);
   
   source = g_source_new ((GSourceFuncs *)&x_event_funcs, 
                         sizeof (ClutterXEventSource));
@@ -253,7 +255,7 @@ events_init()
 
   display_source->event_poll_fd.fd     = connection_number;
   display_source->event_poll_fd.events = G_IO_IN;
-  display_source->display              = ClutterCntx->xdpy;
+  display_source->display              = clutter_context->xdpy;
   
   g_source_add_poll (source, &display_source->event_poll_fd);
   g_source_set_can_recurse (source, TRUE);
@@ -444,7 +446,9 @@ clutter_threads_leave (void)
 Display*
 clutter_xdisplay (void)
 {
-  return ClutterCntx->xdpy;
+  ClutterMainContext *context = CLUTTER_CONTEXT ();
+
+  return context->xdpy;
 }
 
 /**
@@ -457,7 +461,9 @@ clutter_xdisplay (void)
 int
 clutter_xscreen (void)
 {
-  return ClutterCntx->xscreen;
+  ClutterMainContext *context = CLUTTER_CONTEXT ();
+
+  return context->xscreen;
 }
 
 /**
@@ -470,7 +476,9 @@ clutter_xscreen (void)
 Window
 clutter_root_xwindow (void)
 {
-  return ClutterCntx->xwin_root;
+  ClutterMainContext *context = CLUTTER_CONTEXT ();
+
+  return context->xwin_root;
 }
 
 /**
@@ -867,9 +875,6 @@ clutter_init_with_args (int            *argc,
       return CLUTTER_INIT_ERROR_OPENGL;
     }
 
-  /* Check available features */
-  clutter_feature_init ();
-
   events_init ();
 
   return CLUTTER_INIT_SUCCESS;
@@ -927,9 +932,6 @@ clutter_init (int    *argc,
       return CLUTTER_INIT_ERROR_OPENGL;
     }
 
-  /* Check available features */
-  clutter_feature_init ();
-
   events_init ();
 
   return 1;
index 6dbde8f..b38ed6f 100644 (file)
@@ -83,8 +83,6 @@ typedef enum {
 #define CLUTTER_SET_PRIVATE_FLAGS(a,f)  G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) |= (f)); }G_STMT_END
 #define CLUTTER_UNSET_PRIVATE_FLAGS(a,f) G_STMT_START{ (CLUTTER_PRIVATE_FLAGS (a) &= ~(f)); }G_STMT_END
 
-void clutter_feature_init (void);
-
 #define CLUTTER_PARAM_READABLE  \
         G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB
 #define CLUTTER_PARAM_WRITABLE  \
index 9e5caa1..439f96f 100644 (file)
@@ -21,7 +21,7 @@ DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
 DOC_SOURCE_DIR=../../clutter
 
 # Extra options to pass to gtkdoc-scangobj. Not normally needed.
-SCANGOBJ_OPTIONS=--type-init-func="clutter_init(0,0)"
+SCANGOBJ_OPTIONS=
 
 # Extra options to supply to gtkdoc-scan.
 # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" 
index 910fe75..1fddbea 100644 (file)
@@ -23,6 +23,21 @@ ClutterBehaviourScale
 </para>
 
 
+<!-- ##### ARG ClutterBehaviourScale:scale-begin ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ClutterBehaviourScale:scale-end ##### -->
+<para>
+
+</para>
+
+<!-- ##### ARG ClutterBehaviourScale:scale-gravity ##### -->
+<para>
+
+</para>
+
 <!-- ##### STRUCT ClutterBehaviourScaleClass ##### -->
 <para>