test program. covers run first/last/cleanup signal handlers, return value
authorTim Janik <timj@gtk.org>
Fri, 9 Mar 2001 14:02:30 +0000 (14:02 +0000)
committerTim Janik <timj@src.gnome.org>
Fri, 9 Mar 2001 14:02:30 +0000 (14:02 +0000)
Fri Mar  9 14:57:17 2001  Tim Janik  <timj@gtk.org>

        * testgruntime.c: test program. covers run first/last/cleanup signal
        handlers, return value accumulator, signal string returns, and
        interface types in signal arguments.

        * gtype.c (g_type_value_table_peek): for interface types without
        value table, try looking up a value table from an instantiatable
        prerequisite type (this is safe as an interface may only have
        one instantiatable prerequisiste).
        (type_check_is_value_type_U): same here.

        * gsignal.c (g_signal_newv): assert that return types never have
        G_SIGNAL_TYPE_STATIC_SCOPE set.
        (g_signal_newc): only create class closure if the class_offset is not
        0.

gobject/ChangeLog
gobject/Makefile.am
gobject/glib-genmarshal.c
gobject/gmarshal.list
gobject/gsignal.c
gobject/gtype.c
gobject/testgobject.c [new file with mode: 0644]
gobject/testgruntime.c [new file with mode: 0644]

index 309a18a..002a295 100644 (file)
@@ -1,3 +1,20 @@
+Fri Mar  9 14:57:17 2001  Tim Janik  <timj@gtk.org>
+
+       * testgruntime.c: test program. covers run first/last/cleanup signal
+       handlers, return value accumulator, signal string returns, and
+       interface types in signal arguments.
+
+       * gtype.c (g_type_value_table_peek): for interface types without
+       value table, try looking up a value table from an instantiatable
+       prerequisite type (this is safe as an interface may only have
+       one instantiatable prerequisiste).
+       (type_check_is_value_type_U): same here.
+
+       * gsignal.c (g_signal_newv): assert that return types never have
+       G_SIGNAL_TYPE_STATIC_SCOPE set.
+       (g_signal_newc): only create class closure if the class_offset is not
+       0.
+
 Fri Mar  9 10:14:00 2001  Tim Janik  <timj@gtk.org>
 
        * gparamspecs.c (g_param_spec_object): use g_type_is_a() to check
index 1005bee..fdf03bf 100644 (file)
@@ -143,14 +143,16 @@ libgobject_1_3_la_SOURCES = $(gruntime_target_sources)
 #
 # programs to compile and install
 #
-bin_PROGRAMS = gobject-query glib-genmarshal
+bin_PROGRAMS = gobject-query glib-genmarshal testgruntime
 # source files
 gobject_query_SOURCES = gobject-query.c
 glib_genmarshal_SOURCES = glib-genmarshal.c
+testgruntime_SOURCES = testgruntime.c
 # link programs against libgobject
 progs_LDADD = libgobject-1.3.la ../libglib-1.3.la
 glib_genmarshal_LDADD = ../libglib-1.3.la # can't have libgobject here
 gobject_query_LDADD = $(progs_LDADD)
+testgruntime_LDADD = $(progs_LDADD)
 
 #
 # manual pages to install
index 5b6b86b..fc19d17 100644 (file)
@@ -364,7 +364,7 @@ generate_marshal (const gchar *signame,
                  if (iarg->getter)
                    a++;
                }
-             fprintf (fout, "  g_return_if_fail (n_param_values >= %u);\n", 1 + a);
+             fprintf (fout, "  g_return_if_fail (n_param_values == %u);\n", 1 + a);
            }
        }
 
index 835fe85..9089106 100644 (file)
@@ -40,6 +40,7 @@ VOID:PARAM
 VOID:BOXED
 VOID:POINTER
 VOID:OBJECT
+STRING:OBJECT,POINTER
 
 # GRuntime specific marshallers
 VOID:UINT,POINTER
index 036ab4b..391b365 100644 (file)
@@ -1040,7 +1040,7 @@ g_signal_newc (const gchar         *signal_name,
   va_start (args, n_params);
 
   signal_id = g_signal_new_valist (signal_name, itype, signal_flags,
-                                   g_signal_type_cclosure_new (itype, class_offset),
+                                   class_offset ? g_signal_type_cclosure_new (itype, class_offset) : NULL,
                                   accumulator, accu_data, c_marshaller,
                                    return_type, n_params, args);
 
@@ -1069,6 +1069,7 @@ g_signal_newv (const gchar       *signal_name,
   g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
   if (n_params)
     g_return_val_if_fail (param_types != NULL, 0);
+  g_return_val_if_fail ((return_type & G_SIGNAL_TYPE_STATIC_SCOPE) == 0, 0);
   if (return_type == (G_TYPE_NONE & ~G_SIGNAL_TYPE_STATIC_SCOPE))
     g_return_val_if_fail (accumulator == NULL, 0);
   if (!accumulator)
@@ -1885,7 +1886,7 @@ signal_emit_R (SignalNode   *node,
 #ifdef G_ENABLE_DEBUG
   IF_DEBUG (SIGNALS, g_trace_instance_signals == instance || g_trap_instance_signals == instance)
     {
-      g_message ("%s::%s(%u) emitted (instance=%p signal-node=%p)\n",
+      g_message ("%s::%s(%u) emitted (instance=%p, signal-node=%p)",
                 g_type_name (G_TYPE_FROM_INSTANCE (instance)),
                 node->name, detail,
                 instance, node);
index 06a7303..3a181f0 100644 (file)
@@ -1163,6 +1163,21 @@ g_type_interface_add_prerequisite (GType interface_type,
   if (prerequisite_node->is_instantiatable)
     {
       guint i;
+      
+      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (iface); i++)
+       {
+         TypeNode *prnode = lookup_type_node_L (IFACE_NODE_PREREQUISITES (iface)[i]);
+
+         if (prnode->is_instantiatable)
+           {
+             g_warning ("adding prerequisite `%s' to interface `%s' conflicts with existing prerequisite `%s'",
+                        type_descriptive_name_L (prerequisite_type),
+                        type_descriptive_name_L (interface_type),
+                        type_descriptive_name_L (NODE_TYPE (prnode)));
+             G_WRITE_UNLOCK (&type_rw_lock);
+             return;
+           }
+       }
 
       for (i = 0; i < prerequisite_node->n_supers + 1; i++)
        type_iface_add_prerequisite_W (iface, lookup_type_node_L (prerequisite_node->supers[i]));
@@ -2584,10 +2599,30 @@ type_check_is_value_type_U (GType type)
   TypeNode *node;
 
   G_READ_LOCK (&type_rw_lock);
+ restart_check:
   node = lookup_type_node_L (type);
-  if (node && node->data && node->data->common.ref_count > 0 &&
-      node->data->common.value_table->value_init)
-    tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
+  if (node)
+    {
+      if (node->data && node->data->common.ref_count > 0 &&
+         node->data->common.value_table->value_init)
+       tflags = GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags));
+      else if (NODE_IS_IFACE (node))
+       {
+         guint i;
+
+         for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
+           {
+             GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
+             TypeNode *prnode = lookup_type_node_L (prtype);
+
+             if (prnode->is_instantiatable)
+               {
+                 type = prtype;
+                 goto restart_check;
+               }
+           }
+       }
+    }
   G_READ_UNLOCK (&type_rw_lock);
 
   return !(tflags & G_TYPE_FLAG_VALUE_ABSTRACT);
@@ -2616,13 +2651,45 @@ GTypeValueTable*
 g_type_value_table_peek (GType type)
 {
   TypeNode *node;
-  GTypeValueTable *vtable = NULL;
+  GTypeValueTable *vtable;
   
   G_READ_LOCK (&type_rw_lock);
+ restart_table_peek:
   node = lookup_type_node_L (type);
-  if (node && node->data && node->data->common.ref_count > 0 &&
-      node->data->common.value_table->value_init)
+  if (!node)
+    {
+      g_warning ("type id `%u' is invalid", type);
+      G_READ_UNLOCK (&type_rw_lock);
+      return NULL;
+    }
+  if (!node->data || node->data->common.ref_count < 1)
+    {
+      g_warning ("can't peek value table for type `%s' which is not currently referenced",
+                type_descriptive_name_L (type));
+      G_READ_UNLOCK (&type_rw_lock);
+      return NULL;
+    }
+  if (node->data->common.value_table->value_init)
     vtable = node->data->common.value_table;
+  else if (NODE_IS_IFACE (node))
+    {
+      guint i;
+
+      for (i = 0; i < IFACE_NODE_N_PREREQUISITES (node); i++)
+       {
+         GType prtype = IFACE_NODE_PREREQUISITES (node)[i];
+         TypeNode *prnode = lookup_type_node_L (prtype);
+
+         if (prnode->is_instantiatable)
+           {
+             type = prtype;
+             goto restart_table_peek;
+           }
+       }
+      vtable = NULL;
+    }
+  else
+    vtable = NULL;
   G_READ_UNLOCK (&type_rw_lock);
   
   return vtable;
diff --git a/gobject/testgobject.c b/gobject/testgobject.c
new file mode 100644 (file)
index 0000000..0ccb801
--- /dev/null
@@ -0,0 +1,184 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2001 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 "TestObject"
+#include       <glib-object.h>
+
+#define TEST_TYPE_OBJECT            (test_object_get_type ())
+#define TEST_OBJECT(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJECT, TestObject))
+#define TEST_OBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass))
+#define TEST_IS_OBJECT(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJECT))
+#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT))
+#define TEST_OBJECT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass))
+
+typedef struct _TestIface TestIface;
+typedef struct
+{
+  GTypeInterface base_iface;
+} TestIfaceClass;
+typedef struct
+{
+  GObject parent_instance;
+} TestObject;
+
+#define TEST_TYPE_IFACE           (test_iface_get_type ())
+#define TEST_IFACE(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_IFACE, TestIface))
+#define TEST_IS_IFACE(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_IFACE))
+#define TEST_IFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TEST_TYPE_IFACE, TestIfaceClass))
+
+GType
+test_iface_get_type (void)
+{
+  static GType test_iface_type = 0;
+
+  if (!test_iface_type)
+    {
+      static const GTypeInfo test_iface_info =
+      {
+       sizeof (TestIfaceClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+      };
+
+      test_iface_type = g_type_register_static (G_TYPE_INTERFACE, "TestIface", &test_iface_info, 0);
+      g_type_interface_add_prerequisite (test_iface_type, G_TYPE_OBJECT);
+    }
+
+  return test_iface_type;
+}
+
+typedef struct
+{
+  GObjectClass parent_class;
+
+  gchar* (*test_signal) (TestObject *tobject,
+                        TestIface  *iface_object,
+                        gpointer    tdata);
+} TestObjectClass;
+
+static void
+test_object_init (TestObject *tobject)
+{
+}
+
+static gboolean
+test_signal_accumulator (GSignalInvocationHint *ihint,
+                        GValue                *return_accu,
+                        const GValue          *handler_return,
+                        gpointer               data)
+{
+  gchar *accu_string = g_value_get_string (return_accu);
+  gchar *new_string = g_value_get_string (handler_return);
+  gchar *result_string;
+
+  if (accu_string)
+    result_string = g_strconcat (accu_string, new_string, NULL);
+  else if (new_string)
+    result_string = g_strdup (new_string);
+  else
+    result_string = NULL;
+
+  g_value_set_string_take_ownership (return_accu, result_string);
+
+  return TRUE;
+}
+
+static gchar*
+test_object_test_signal (TestObject *tobject,
+                        TestIface  *iface_object,
+                        gpointer    tdata)
+{
+  g_message ("::test_signal default_handler called");
+
+  g_return_val_if_fail (TEST_IS_IFACE (iface_object), NULL);
+  
+  return g_strdup ("<default_handler>");
+}
+
+static void
+test_object_class_init (TestObjectClass *class)
+{
+  /*  GObjectClass *gobject_class = G_OBJECT_CLASS (class); */
+
+  class->test_signal = test_object_test_signal;
+
+  g_signal_newc ("test-signal",
+                G_OBJECT_CLASS_TYPE (class),
+                G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+                G_STRUCT_OFFSET (TestObjectClass, test_signal),
+                test_signal_accumulator, NULL,
+                g_cclosure_marshal_STRING__OBJECT_POINTER,
+                G_TYPE_STRING, 2, TEST_TYPE_IFACE, G_TYPE_POINTER);
+}
+
+GType
+test_object_get_type (void)
+{
+  static GType test_object_type = 0;
+
+  if (!test_object_type)
+    {
+      static const GTypeInfo test_object_info =
+      {
+       sizeof (TestObjectClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) test_object_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (TestObject),
+       5,              /* n_preallocs */
+       (GInstanceInitFunc) test_object_init,
+      };
+      GInterfaceInfo iface_info = { NULL, NULL, NULL };
+
+      test_object_type = g_type_register_static (G_TYPE_OBJECT, "TestObject", &test_object_info, 0);
+      g_type_add_interface_static (test_object_type, TEST_TYPE_IFACE, &iface_info);
+    }
+
+  return test_object_type;
+}
+
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+  TestObject *tobject, *sigarg;
+  gchar *string = NULL;
+
+  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 (G_TYPE_DEBUG_OBJECTS | G_TYPE_DEBUG_SIGNALS);
+
+  tobject = g_object_new (TEST_TYPE_OBJECT, NULL);
+  sigarg = g_object_new (TEST_TYPE_OBJECT, NULL);
+  g_signal_emit_by_name (tobject, "test-signal", sigarg, NULL, &string);
+  g_message ("signal return: \"%s\"", string);
+  g_free (string);
+  
+  g_object_unref (sigarg);
+  g_object_unref (tobject);
+
+  g_message ("%s done", argv[0]);
+
+  return 0;
+}
diff --git a/gobject/testgruntime.c b/gobject/testgruntime.c
new file mode 100644 (file)
index 0000000..0ccb801
--- /dev/null
@@ -0,0 +1,184 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2001 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 "TestObject"
+#include       <glib-object.h>
+
+#define TEST_TYPE_OBJECT            (test_object_get_type ())
+#define TEST_OBJECT(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJECT, TestObject))
+#define TEST_OBJECT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OBJECT, TestObjectClass))
+#define TEST_IS_OBJECT(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJECT))
+#define TEST_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_OBJECT))
+#define TEST_OBJECT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJECT, TestObjectClass))
+
+typedef struct _TestIface TestIface;
+typedef struct
+{
+  GTypeInterface base_iface;
+} TestIfaceClass;
+typedef struct
+{
+  GObject parent_instance;
+} TestObject;
+
+#define TEST_TYPE_IFACE           (test_iface_get_type ())
+#define TEST_IFACE(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_IFACE, TestIface))
+#define TEST_IS_IFACE(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_IFACE))
+#define TEST_IFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TEST_TYPE_IFACE, TestIfaceClass))
+
+GType
+test_iface_get_type (void)
+{
+  static GType test_iface_type = 0;
+
+  if (!test_iface_type)
+    {
+      static const GTypeInfo test_iface_info =
+      {
+       sizeof (TestIfaceClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+      };
+
+      test_iface_type = g_type_register_static (G_TYPE_INTERFACE, "TestIface", &test_iface_info, 0);
+      g_type_interface_add_prerequisite (test_iface_type, G_TYPE_OBJECT);
+    }
+
+  return test_iface_type;
+}
+
+typedef struct
+{
+  GObjectClass parent_class;
+
+  gchar* (*test_signal) (TestObject *tobject,
+                        TestIface  *iface_object,
+                        gpointer    tdata);
+} TestObjectClass;
+
+static void
+test_object_init (TestObject *tobject)
+{
+}
+
+static gboolean
+test_signal_accumulator (GSignalInvocationHint *ihint,
+                        GValue                *return_accu,
+                        const GValue          *handler_return,
+                        gpointer               data)
+{
+  gchar *accu_string = g_value_get_string (return_accu);
+  gchar *new_string = g_value_get_string (handler_return);
+  gchar *result_string;
+
+  if (accu_string)
+    result_string = g_strconcat (accu_string, new_string, NULL);
+  else if (new_string)
+    result_string = g_strdup (new_string);
+  else
+    result_string = NULL;
+
+  g_value_set_string_take_ownership (return_accu, result_string);
+
+  return TRUE;
+}
+
+static gchar*
+test_object_test_signal (TestObject *tobject,
+                        TestIface  *iface_object,
+                        gpointer    tdata)
+{
+  g_message ("::test_signal default_handler called");
+
+  g_return_val_if_fail (TEST_IS_IFACE (iface_object), NULL);
+  
+  return g_strdup ("<default_handler>");
+}
+
+static void
+test_object_class_init (TestObjectClass *class)
+{
+  /*  GObjectClass *gobject_class = G_OBJECT_CLASS (class); */
+
+  class->test_signal = test_object_test_signal;
+
+  g_signal_newc ("test-signal",
+                G_OBJECT_CLASS_TYPE (class),
+                G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP,
+                G_STRUCT_OFFSET (TestObjectClass, test_signal),
+                test_signal_accumulator, NULL,
+                g_cclosure_marshal_STRING__OBJECT_POINTER,
+                G_TYPE_STRING, 2, TEST_TYPE_IFACE, G_TYPE_POINTER);
+}
+
+GType
+test_object_get_type (void)
+{
+  static GType test_object_type = 0;
+
+  if (!test_object_type)
+    {
+      static const GTypeInfo test_object_info =
+      {
+       sizeof (TestObjectClass),
+       NULL,           /* base_init */
+       NULL,           /* base_finalize */
+       (GClassInitFunc) test_object_class_init,
+       NULL,           /* class_finalize */
+       NULL,           /* class_data */
+       sizeof (TestObject),
+       5,              /* n_preallocs */
+       (GInstanceInitFunc) test_object_init,
+      };
+      GInterfaceInfo iface_info = { NULL, NULL, NULL };
+
+      test_object_type = g_type_register_static (G_TYPE_OBJECT, "TestObject", &test_object_info, 0);
+      g_type_add_interface_static (test_object_type, TEST_TYPE_IFACE, &iface_info);
+    }
+
+  return test_object_type;
+}
+
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+  TestObject *tobject, *sigarg;
+  gchar *string = NULL;
+
+  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 (G_TYPE_DEBUG_OBJECTS | G_TYPE_DEBUG_SIGNALS);
+
+  tobject = g_object_new (TEST_TYPE_OBJECT, NULL);
+  sigarg = g_object_new (TEST_TYPE_OBJECT, NULL);
+  g_signal_emit_by_name (tobject, "test-signal", sigarg, NULL, &string);
+  g_message ("signal return: \"%s\"", string);
+  g_free (string);
+  
+  g_object_unref (sigarg);
+  g_object_unref (tobject);
+
+  g_message ("%s done", argv[0]);
+
+  return 0;
+}