Re: [PATCH] g_type_default_interface_ref(), etc.



On Thu, 2003-09-25 at 17:25, Owen Taylor wrote:
> Here's a patch for:
> 
>  g_type_default_interface_ref()
>  g_type_default_interface_peek()
>  g_type_default_interface_unref()
> 
> as described in your last mail, with docs and a test case
> for both static and dynamic interfaces.

And the patch...
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/ChangeLog,v
retrieving revision 1.1405
diff -u -p -u -r1.1405 ChangeLog
--- ChangeLog	25 Sep 2003 19:01:54 -0000	1.1405
+++ ChangeLog	25 Sep 2003 21:22:30 -0000
@@ -1,3 +1,9 @@
+Thu Sep 25 15:43:08 2003  Owen Taylor  <otaylor redhat com>
+
+	* tests/gobject/testmodule.[ch] test/gobject/Makefile.am:
+	Dummy dynamic type module for testing type plugin code
+	and dynamic types.
+
 Thu Sep 25 15:01:37 2003  Owen Taylor  <otaylor redhat com>
 
 	* tests/Makefile.am (SUBDIRS): Add gobject/.
Index: docs/reference/glib/tmpl/threads.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/threads.sgml,v
retrieving revision 1.41
diff -u -p -u -r1.41 threads.sgml
--- docs/reference/glib/tmpl/threads.sgml	30 Jul 2003 22:31:23 -0000	1.41
+++ docs/reference/glib/tmpl/threads.sgml	25 Sep 2003 21:22:30 -0000
@@ -1613,9 +1613,6 @@ Any one-time initialization function mus
 struct.
 </para>
 
- status: the status of the function controled by this struct
- retval: the return value of the function controled by this struct. This field will be
-         %NULL unless <literal>status == G_ONCE_STATUS_READY</literal>.
 @Since: 2.4
 
 <!-- ##### ENUM GOnceStatus ##### -->
Index: docs/reference/gobject/gobject-sections.txt
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/gobject/gobject-sections.txt,v
retrieving revision 1.27
diff -u -p -u -r1.27 gobject-sections.txt
--- docs/reference/gobject/gobject-sections.txt	12 Sep 2003 20:37:29 -0000	1.27
+++ docs/reference/gobject/gobject-sections.txt	25 Sep 2003 21:22:30 -0000
@@ -56,6 +56,9 @@ g_type_class_peek_parent
 g_type_class_add_private
 g_type_interface_peek
 g_type_interface_peek_parent
+g_type_default_interface_ref
+g_type_default_interface_peek
+g_type_default_interface_unref
 g_type_children
 g_type_interfaces
 g_type_interface_prerequisites
Index: docs/reference/gobject/tmpl/gtype.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/gobject/tmpl/gtype.sgml,v
retrieving revision 1.24
diff -u -p -u -r1.24 gtype.sgml
--- docs/reference/gobject/tmpl/gtype.sgml	2 Sep 2003 17:57:21 -0000	1.24
+++ docs/reference/gobject/tmpl/gtype.sgml	25 Sep 2003 21:22:30 -0000
@@ -774,6 +774,50 @@ then possibly overriding some methods. 
    doesn't conform to the interface.
 
 
+<!-- ##### FUNCTION g_type_default_interface_ref ##### -->
+<para>
+Increments the reference count for the interface type @g_type,
+and returns the default interface vtable for the type.
+</para>
+<para>  
+If the type is not currently in use, then the default vtable
+for the type will be created and initalized by calling
+the default vtable init and base interface init functions for
+the type (the <structfield>class_init</structfield>,
+and <structfield>base_init</structfield> members of #GTypeInfo).
+Calling g_type_default_interface_ref() is useful when you
+want to make sure that signals and properties for an interface
+have been installed.
+</para>
+
+ g_type: an interface type
+ Returns: the default vtable for the interface; call 
+ g_type_default_interface_unref() when you are done using
+ the interface.
+
+<!-- ##### FUNCTION g_type_default_interface_peek ##### -->
+<para>
+If the interface type @g_type is currently in use, returns
+its default interface vtable.    
+</para>
+
+ g_type: an interface type 
+ Returns: the default vtable for the interface; or %NULL
+ if the type is not currently in use.
+
+<!-- ##### FUNCTION g_type_default_interface_unref ##### -->
+<para>
+Decrements the reference count for the type corresponding to the
+interface default vtable @g_iface. If the type is dynamic, then
+when no one is using the interface and all references have
+been released, the finalize function for the interface's default
+vtable (the <structfield>class_finalize</structfield> member of
+#GTypeInfo) will be called.
+</para>
+
+ g_iface: the default vtable structure for a interface, as
+  returned by g_type_default_interface_ref()
+
 <!-- ##### FUNCTION g_type_children ##### -->
 <para>
 Return a newly allocated and 0-terminated array of type IDs, listing the
Index: gobject/gtype.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.c,v
retrieving revision 1.66
diff -u -p -u -r1.66 gtype.c
--- gobject/gtype.c	2 Sep 2003 17:57:22 -0000	1.66
+++ gobject/gtype.c	25 Sep 2003 21:22:31 -0000
@@ -2486,6 +2486,69 @@ g_type_interface_peek_parent (gpointer g
   return vtable;
 }
 
+gpointer
+g_type_default_interface_ref (GType g_type)
+{
+  TypeNode *node;
+  
+  G_WRITE_LOCK (&type_rw_lock);
+  
+  node = lookup_type_node_I (g_type);
+  if (G_UNLIKELY (!node || !NODE_IS_IFACE (node) ||
+		  (node->data && node->data->common.ref_count < 1)))
+    {
+      G_WRITE_UNLOCK (&type_rw_lock);
+      g_warning ("cannot retrieve default vtable for invalid or non-interface type '%s'",
+		 type_descriptive_name_I (g_type));
+      return NULL;
+    }
+  
+  type_data_ref_Wm (node);
+
+  type_iface_ensure_dflt_vtable_Wm (node);
+
+  G_WRITE_UNLOCK (&type_rw_lock);
+  
+  return node->data->iface.dflt_vtable;
+}
+
+gpointer
+g_type_default_interface_peek (GType g_type)
+{
+  TypeNode *node;
+  gpointer class;
+  
+  node = lookup_type_node_I (g_type);
+  G_READ_LOCK (&type_rw_lock);
+  if (node && NODE_IS_IFACE (node) && node->data && node->data->iface.dflt_vtable)
+    class = node->data->iface.dflt_vtable;
+  else
+    class = NULL;
+  G_READ_UNLOCK (&type_rw_lock);
+  
+  return class;
+}
+
+void
+g_type_default_interface_unref (gpointer g_iface)
+{
+  TypeNode *node;
+  GTypeInterface *vtable = g_iface;
+  
+  g_return_if_fail (g_iface != NULL);
+  
+  node = lookup_type_node_I (vtable->g_type);
+  G_WRITE_LOCK (&type_rw_lock);
+  if (G_LIKELY (node && NODE_IS_IFACE (node) &&
+		node->data->iface.dflt_vtable == g_iface &&
+		node->data->common.ref_count > 0))
+    type_data_unref_Wm (node, FALSE);
+  else
+    g_warning ("cannot unreference invalid interface default vtable for '%s'",
+	       type_descriptive_name_I (vtable->g_type));
+  G_WRITE_UNLOCK (&type_rw_lock);
+}
+
 G_CONST_RETURN gchar*
 g_type_name (GType type)
 {
Index: gobject/gtype.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.h,v
retrieving revision 1.49
diff -u -p -u -r1.49 gtype.h
--- gobject/gtype.h	2 Sep 2003 17:57:22 -0000	1.49
+++ gobject/gtype.h	25 Sep 2003 21:22:31 -0000
@@ -183,6 +183,10 @@ gpointer              g_type_interface_p
 						      GType            iface_type);
 gpointer              g_type_interface_peek_parent   (gpointer         g_iface);
 
+gpointer              g_type_default_interface_ref   (GType            g_type);
+gpointer              g_type_default_interface_peek  (GType            g_type);
+void                  g_type_default_interface_unref (gpointer         g_iface);
+
 /* g_free() the returned arrays */
 GType*                g_type_children                (GType            type,
 						      guint           *n_children);
Index: tests/gobject/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/tests/gobject/Makefile.am,v
retrieving revision 1.1
diff -u -p -u -r1.1 Makefile.am
--- tests/gobject/Makefile.am	12 Sep 2003 20:37:09 -0000	1.1
+++ tests/gobject/Makefile.am	25 Sep 2003 21:22:31 -0000
@@ -16,7 +16,9 @@ noinst_LTLIBRARIES = libtestgobject.la
 libtestgobject_la_SOURCES =	\
 	testcommon.h		\
 	testmarshal.h		\
-	testmarshal.c
+	testmarshal.c		\
+	testmodule.c		\
+	testmodule.h
 
 if CROSS_COMPILING
   glib_genmarshal=$(GLIB_GENMARSHAL)
@@ -44,6 +46,7 @@ LDADD = $(libgobject) libtestgobject.la
 
 test_programs =					\
 	accumulator				\
+	defaultiface				\
 	ifaceinit				\
 	override
 
Index: tests/gobject/defaultiface.c
===================================================================
RCS file: tests/gobject/defaultiface.c
diff -N tests/gobject/defaultiface.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/gobject/defaultiface.c	25 Sep 2003 21:22:31 -0000
@@ -0,0 +1,191 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2001, 2003 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#undef	G_LOG_DOMAIN
+#define	G_LOG_DOMAIN "TestDefaultIface"
+
+#undef G_DISABLE_ASSERT
+#undef G_DISABLE_CHECKS
+#undef G_DISABLE_CAST_CHECKS
+
+#include <glib-object.h>
+
+#include "testcommon.h"
+#include "testmodule.h"
+
+/* This test tests getting the default vtable for an interface
+ * and the initialization and finalization of such default
+ * interfaces.
+ *
+ * We test this both for static and for dynamic interfaces.
+ */
+
+/**********************************************************************
+ * Static interface tests
+ **********************************************************************/
+
+typedef struct _TestStaticIfaceClass TestStaticIfaceClass;
+
+struct _TestStaticIfaceClass
+{
+  GTypeInterface base_iface;
+  guint val;
+};
+
+#define TEST_TYPE_STATIC_IFACE (test_static_iface_get_type ())
+
+static void
+test_static_iface_default_init (TestStaticIfaceClass *iface)
+{
+  iface->val = 42;
+}
+
+DEFINE_IFACE (TestStaticIface, test_static_iface,
+	      NULL, test_static_iface_default_init)
+
+static void
+test_static_iface (void)
+{
+  TestStaticIfaceClass *static_iface;
+
+  /* Not loaded until we call ref for the first time */
+  static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE);
+  g_assert (static_iface == NULL);
+
+  /* Ref loads */
+  static_iface = g_type_default_interface_ref (TEST_TYPE_STATIC_IFACE);
+  g_assert (static_iface && static_iface->val == 42);
+
+  /* Peek then works */
+  static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE);
+  g_assert (static_iface && static_iface->val == 42);
+  
+  /* Unref does nothing */
+  g_type_default_interface_unref (static_iface);
+  
+  /* And peek still works */
+  static_iface = g_type_default_interface_peek (TEST_TYPE_STATIC_IFACE);
+  g_assert (static_iface && static_iface->val == 42);
+}
+
+/**********************************************************************
+ * Dynamic interface tests
+ **********************************************************************/
+
+typedef struct _TestDynamicIfaceClass TestDynamicIfaceClass;
+
+struct _TestDynamicIfaceClass
+{
+  GTypeInterface base_iface;
+  guint val;
+};
+
+static GType test_dynamic_iface_type;
+static gboolean dynamic_iface_init = FALSE;
+
+#define TEST_TYPE_DYNAMIC_IFACE (test_dynamic_iface_type)
+
+static void
+test_dynamic_iface_default_init (TestStaticIfaceClass *iface)
+{
+  dynamic_iface_init = TRUE;
+  iface->val = 42;
+}
+
+static void
+test_dynamic_iface_default_finalize (TestStaticIfaceClass *iface)
+{
+  dynamic_iface_init = FALSE;
+}
+
+static void
+test_dynamic_iface_register (GTypeModule *module)
+{
+  static const GTypeInfo iface_info =			
+    {								
+      sizeof (TestDynamicIfaceClass),
+      (GBaseInitFunc)	   NULL,
+      (GBaseFinalizeFunc)  NULL,				
+      (GClassInitFunc)     test_dynamic_iface_default_init,
+      (GClassFinalizeFunc) test_dynamic_iface_default_finalize
+    };							
+
+  test_dynamic_iface_type = g_type_module_register_type (module, G_TYPE_INTERFACE,
+							 "TestDynamicIface", &iface_info, 0);
+}
+
+static void
+module_register (GTypeModule *module)
+{
+  test_dynamic_iface_register (module);
+}
+
+static void
+test_dynamic_iface (void)
+{
+  GTypeModule *module;
+  TestDynamicIfaceClass *dynamic_iface;
+
+  module = test_module_new (module_register);
+
+  /* Not loaded until we call ref for the first time */
+  dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE);
+  g_assert (dynamic_iface == NULL);
+
+  /* Ref loads */
+  dynamic_iface = g_type_default_interface_ref (TEST_TYPE_DYNAMIC_IFACE);
+  g_assert (dynamic_iface_init);
+  g_assert (dynamic_iface && dynamic_iface->val == 42);
+
+  /* Peek then works */
+  dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE);
+  g_assert (dynamic_iface && dynamic_iface->val == 42);
+  
+  /* Unref causes finalize */
+  g_type_default_interface_unref (dynamic_iface);
+  g_assert (!dynamic_iface_init);
+
+  /* Peek returns NULL */
+  dynamic_iface = g_type_default_interface_peek (TEST_TYPE_DYNAMIC_IFACE);
+  g_assert (dynamic_iface == NULL);
+  
+  /* Ref reloads */
+  dynamic_iface = g_type_default_interface_ref (TEST_TYPE_DYNAMIC_IFACE);
+  g_assert (dynamic_iface_init);
+  g_assert (dynamic_iface && dynamic_iface->val == 42);
+
+  /* And Unref causes finalize once more*/
+  g_type_default_interface_unref (dynamic_iface);
+  g_assert (!dynamic_iface_init);
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
+			  G_LOG_LEVEL_WARNING |
+			  G_LOG_LEVEL_CRITICAL);
+  g_type_init ();
+
+  test_static_iface ();
+  test_dynamic_iface ();
+  
+  return 0;
+}
Index: tests/gobject/testmodule.c
===================================================================
RCS file: tests/gobject/testmodule.c
diff -N tests/gobject/testmodule.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/gobject/testmodule.c	25 Sep 2003 21:22:31 -0000
@@ -0,0 +1,69 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * testmodule.c: Dummy dynamic type module
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "testmodule.h"
+#include "testcommon.h"
+
+static gboolean test_module_load   (GTypeModule *module);
+static void     test_module_unload (GTypeModule *module);
+
+static void
+test_module_class_init (TestModuleClass *class)
+{
+  GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (class);
+
+  module_class->load = test_module_load;
+  module_class->unload = test_module_unload;
+}
+
+DEFINE_TYPE (TestModule, test_module,
+	     test_module_class_init, NULL, NULL,
+	     G_TYPE_TYPE_MODULE)
+
+static gboolean
+test_module_load (GTypeModule *module)
+{
+  TestModule *test_module = TEST_MODULE (module);
+
+  test_module->register_func (module);
+  
+  return TRUE;
+}
+
+static void
+test_module_unload (GTypeModule *module)
+{
+}
+
+GTypeModule *
+test_module_new (TestModuleRegisterFunc register_func)
+{
+  TestModule *test_module = g_object_new (TEST_TYPE_MODULE, NULL);
+  GTypeModule *module = G_TYPE_MODULE (test_module);
+  
+  test_module->register_func = register_func;
+
+  /* Register the types initially */
+  g_type_module_use (module);
+  g_type_module_unuse (module);
+
+  return G_TYPE_MODULE (module);
+}
+
Index: tests/gobject/testmodule.h
===================================================================
RCS file: tests/gobject/testmodule.h
diff -N tests/gobject/testmodule.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/gobject/testmodule.h	25 Sep 2003 21:22:31 -0000
@@ -0,0 +1,57 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * testmodule.h: Dummy dynamic type module
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __TEST_MODULE_H__
+#define __TEST_MODULE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TestModule      TestModule;
+typedef struct _TestModuleClass TestModuleClass;
+
+#define TEST_TYPE_MODULE              (test_module_get_type ())
+#define TEST_MODULE(module)           (G_TYPE_CHECK_INSTANCE_CAST ((module), TEST_TYPE_MODULE, TestModule))
+#define TEST_MODULE_CLASS(class)      (G_TYPE_CHECK_CLASS_CAST ((class), TEST_TYPE_MODULE, TestModuleClass))
+#define TEST_IS_MODULE(module)        (G_TYPE_CHECK_INSTANCE_TYPE ((module), TEST_TYPE_MODULE))
+#define TEST_IS_MODULE_CLASS(class)   (G_TYPE_CHECK_CLASS_TYPE ((class), TEST_TYPE_MODULE))
+#define TEST_MODULE_GET_CLASS(module) (G_TYPE_INSTANCE_GET_CLASS ((module), TEST_TYPE_MODULE, TestModuleClass))
+
+typedef void (*TestModuleRegisterFunc) (GTypeModule *module);
+
+struct _TestModule 
+{
+  GTypeModule parent_instance;
+
+  TestModuleRegisterFunc register_func;
+};
+
+struct _TestModuleClass
+{
+  GTypeModuleClass parent_class;
+};
+
+GType        test_module_get_type      (void);
+GTypeModule *test_module_new           (TestModuleRegisterFunc register_func);
+
+G_END_DECLS
+
+#endif /* __TEST_MODULE_H__ */


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