[gobject-introspection] g-ir-compiler: Add support for callback fields on GObjects



commit 7027bb256d0d1ab5dd58b6d7fb02ff2f547ae4c2
Author: Simon Feltman <sfeltman src gnome org>
Date:   Thu Feb 27 02:05:54 2014 -0800

    g-ir-compiler: Add support for callback fields on GObjects
    
    Use ParseState enum instead of a boolean for the ParseContexts embedded_type
    flag. This allows specific tracking of the embedded type currently being
    parsed which can now either be STATE_STRUCT_FIELD or STATE_CLASS_FIELD (or
    allow for future expansion). Add ParseState::STATE_NONE as the default for
    this field.
    
    Fix GObject FieldBlob validation to take into account the sizeof
    CallbackBlobs (copied from the struct validator).
    
    Add static g_object_info_get_field_offset which parallels
    g_struct_info_get_field_offset which is needed since callback fields may
    vary in size.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=725198

 girepository/giobjectinfo.c                        |   71 ++++++++++++--------
 girepository/girparser.c                           |   41 ++++++------
 girepository/gitypelib.c                           |    9 ++-
 .../Regress.TestObj-function_ptr.page              |   14 ++++
 .../Regress.TestObj.function_ptr.page              |   24 +++++++
 .../Regress.TestObj.function_ptr.page              |   19 +++++
 .../Regress.TestObj.function_ptr.page              |   21 ++++++
 tests/scanner/Regress-1.0-expected.gir             |    7 ++
 tests/scanner/regress.h                            |    3 +
 9 files changed, 159 insertions(+), 50 deletions(-)
---
diff --git a/girepository/giobjectinfo.c b/girepository/giobjectinfo.c
index 3e3b312..d92a861 100644
--- a/girepository/giobjectinfo.c
+++ b/girepository/giobjectinfo.c
@@ -48,6 +48,40 @@
  */
 
 /**
+ * g_object_info_get_field_offset:
+ * @info: a #GIObjectInfo
+ * @n: index of queried field
+ *
+ * Obtain the offset of the specified field.
+ *
+ * Returns: field offset in bytes
+ */
+static gint32
+g_object_info_get_field_offset (GIObjectInfo *info,
+                                gint          n)
+{
+  GIRealInfo *rinfo = (GIRealInfo *)info;
+  Header *header = (Header *)rinfo->typelib->data;
+  ObjectBlob *blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
+  guint32 offset;
+  gint i;
+  FieldBlob *field_blob;
+
+  offset = rinfo->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2;
+
+  for (i = 0; i < n; i++)
+    {
+      field_blob = (FieldBlob *)&rinfo->typelib->data[offset];
+      offset += header->field_blob_size;
+      if (field_blob->has_embedded_type)
+        offset += header->callback_blob_size;
+    }
+
+  return offset;
+}
+
+/**
  * g_object_info_get_parent:
  * @info: a #GIObjectInfo
  *
@@ -251,18 +285,11 @@ g_object_info_get_field (GIObjectInfo *info,
 {
   gint offset;
   GIRealInfo *rinfo = (GIRealInfo *)info;
-  Header *header;
-  ObjectBlob *blob;
 
   g_return_val_if_fail (info != NULL, NULL);
   g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL);
 
-  header = (Header *)rinfo->typelib->data;
-  blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
-
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + n * header->field_blob_size;
+  offset = g_object_info_get_field_offset(info, n);
 
   return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, (GIBaseInfo*)info, rinfo->typelib, offset);
 }
@@ -313,9 +340,7 @@ g_object_info_get_property (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + n * header->property_blob_size;
 
   return (GIPropertyInfo *) g_info_new (GI_INFO_TYPE_PROPERTY, (GIBaseInfo*)info,
@@ -370,9 +395,7 @@ g_object_info_get_method (GIObjectInfo *info,
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size
     + n * header->function_blob_size;
 
@@ -406,9 +429,7 @@ g_object_info_find_method (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size +
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size;
 
   return _g_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_methods, name);
@@ -518,9 +539,7 @@ g_object_info_get_signal (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + n * header->signal_blob_size;
@@ -609,9 +628,7 @@ g_object_info_get_vfunc (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size
@@ -652,9 +669,7 @@ g_object_info_find_vfunc (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size;
@@ -769,9 +784,7 @@ g_object_info_get_constant (GIObjectInfo *info,
   header = (Header *)rinfo->typelib->data;
   blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
 
-  offset = rinfo->offset + header->object_blob_size
-    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
-    + blob->n_fields * header->field_blob_size
+  offset = g_object_info_get_field_offset(info, blob->n_fields)
     + blob->n_properties * header->property_blob_size
     + blob->n_methods * header->function_blob_size
     + blob->n_signals * header->signal_blob_size
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 82005fc..c7feb6a 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -62,37 +62,38 @@ struct _GIrParser
 
 typedef enum
 {
+  STATE_NONE = 0,
   STATE_START,
   STATE_END,
   STATE_REPOSITORY,
   STATE_INCLUDE,
-  STATE_C_INCLUDE,
-  STATE_PACKAGE,  /* 5 */
+  STATE_C_INCLUDE,     /* 5 */
+  STATE_PACKAGE,
   STATE_NAMESPACE,
   STATE_ENUM,
   STATE_BITFIELD,
-  STATE_FUNCTION,
-  STATE_FUNCTION_RETURN,  /* 10 */
+  STATE_FUNCTION,      /* 10 */
+  STATE_FUNCTION_RETURN,
   STATE_FUNCTION_PARAMETERS,
   STATE_FUNCTION_PARAMETER,
   STATE_CLASS,
-  STATE_CLASS_FIELD,
-  STATE_CLASS_PROPERTY,  /* 15 */
+  STATE_CLASS_FIELD,   /* 15 */
+  STATE_CLASS_PROPERTY,
   STATE_INTERFACE,
   STATE_INTERFACE_PROPERTY,
   STATE_INTERFACE_FIELD,
-  STATE_IMPLEMENTS,
-  STATE_PREREQUISITE,    /* 20 */
+  STATE_IMPLEMENTS,    /* 20 */
+  STATE_PREREQUISITE,
   STATE_BOXED,
   STATE_BOXED_FIELD,
   STATE_STRUCT,
-  STATE_STRUCT_FIELD,
-  STATE_UNION,           /* 25 */
+  STATE_STRUCT_FIELD,  /* 25 */
+  STATE_UNION,
   STATE_UNION_FIELD,
   STATE_NAMESPACE_CONSTANT,
   STATE_CLASS_CONSTANT,
-  STATE_INTERFACE_CONSTANT,
-  STATE_ALIAS,           /* 30 */
+  STATE_INTERFACE_CONSTANT,  /* 30 */
+  STATE_ALIAS,
   STATE_TYPE,
   STATE_ATTRIBUTE,
   STATE_PASSTHROUGH
@@ -123,7 +124,7 @@ struct _ParseContext
   GList *type_stack;
   GList *type_parameters;
   int type_depth;
-  gboolean in_embedded_type;
+  ParseState in_embedded_state;
 };
 #define CURRENT_NODE(ctx) ((GIrNode *)((ctx)->node_stack->data))
 
@@ -807,7 +808,7 @@ start_function (GMarkupParseContext *context,
   const gchar *throws;
   GIrNodeFunction *function;
   gboolean found = FALSE;
-  gboolean in_embedded_type;
+  ParseState in_embedded_state = STATE_NONE;
 
   switch (ctx->state)
     {
@@ -830,8 +831,10 @@ start_function (GMarkupParseContext *context,
     case STATE_ENUM:
       found = strcmp (element_name, "function") == 0;
       break;
+    case STATE_CLASS_FIELD:
     case STATE_STRUCT_FIELD:
       found = (found || strcmp (element_name, "callback") == 0);
+      in_embedded_state = ctx->state;
       break;
     default:
       break;
@@ -840,12 +843,10 @@ start_function (GMarkupParseContext *context,
   if (!found)
     return FALSE;
 
-  in_embedded_type = ctx->state == STATE_STRUCT_FIELD;
-
   if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION))
     return TRUE;
 
-  ctx->in_embedded_type = in_embedded_type;
+  ctx->in_embedded_state = in_embedded_state;
 
   name = find_attribute ("name", attribute_names, attribute_values);
   shadows = find_attribute ("shadows", attribute_names, attribute_values);
@@ -3210,10 +3211,10 @@ end_element_handler (GMarkupParseContext *context,
        else
          {
             g_debug("case STATE_FUNCTION %d", CURRENT_NODE (ctx)->type);
-            if (ctx->in_embedded_type)
+            if (ctx->in_embedded_state != STATE_NONE)
               {
-                ctx->in_embedded_type = FALSE;
-                state_switch (ctx, STATE_STRUCT_FIELD);
+                state_switch (ctx, ctx->in_embedded_state);
+                ctx->in_embedded_state = STATE_NONE;
               }
            else if (CURRENT_NODE (ctx)->type == G_IR_NODE_INTERFACE)
              state_switch (ctx, STATE_INTERFACE);
diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c
index 8883496..41b54fd 100644
--- a/girepository/gitypelib.c
+++ b/girepository/gitypelib.c
@@ -1773,10 +1773,17 @@ validate_object_blob (ValidateContext *ctx,
 
   push_context (ctx, get_string_nofail (typelib, blob->name));
 
-  for (i = 0; i < blob->n_fields; i++, offset2 += sizeof (FieldBlob))
+  for (i = 0; i < blob->n_fields; i++)
     {
+      FieldBlob *blob = (FieldBlob*) &typelib->data[offset2];
+
       if (!validate_field_blob (ctx, offset2, error))
        return FALSE;
+
+      offset2 += sizeof (FieldBlob);
+      /* Special case fields which are callbacks. */
+      if (blob->has_embedded_type)
+        offset2 += sizeof (CallbackBlob);
     }
 
   for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob))
diff --git a/tests/scanner/Regress-1.0-C-expected/Regress.TestObj-function_ptr.page 
b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj-function_ptr.page
new file mode 100644
index 0000000..dca9a51
--- /dev/null
+++ b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj-function_ptr.page
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj-function_ptr"
+      type="topic"
+      style="field"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="Regress.TestObj" group="field" type="guide"/>
+  </info>
+  <title>Regress.TestObj->function_ptr</title>
+
+
+</page>
diff --git a/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.function_ptr.page 
b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.function_ptr.page
new file mode 100644
index 0000000..3456540
--- /dev/null
+++ b/tests/scanner/Regress-1.0-C-expected/Regress.TestObj.function_ptr.page
@@ -0,0 +1,24 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.function_ptr"
+      type="topic"
+      style="callback"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="index" group="callback" type="guide"/>
+    </info>
+  <title>Regress.TestObj.function_ptr</title>
+  <synopsis><code mime="text/x-csrc">
+void function_ptr (void);
+  </code></synopsis>
+
+
+<terms>
+<item>
+<title><code>Returns</code></title>
+
+</item>
+</terms>
+
+</page>
diff --git a/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.function_ptr.page 
b/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.function_ptr.page
new file mode 100644
index 0000000..d9f3754
--- /dev/null
+++ b/tests/scanner/Regress-1.0-Gjs-expected/Regress.TestObj.function_ptr.page
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.function_ptr"
+      type="topic"
+      style="callback"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="index" group="callback" type="guide"/>
+  </info>
+  <title>Regress.TestObj.function_ptr</title>
+  <synopsis><code mime="text/x-gjs">
+function onfunction_ptr(): void {
+}
+  </code></synopsis>
+
+
+
+</page>
diff --git a/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.function_ptr.page 
b/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.function_ptr.page
new file mode 100644
index 0000000..caa0c19
--- /dev/null
+++ b/tests/scanner/Regress-1.0-Python-expected/Regress.TestObj.function_ptr.page
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<page id="Regress.TestObj.function_ptr"
+      type="topic"
+      style="callback"
+      xmlns="http://projectmallard.org/1.0/";
+      xmlns:api="http://projectmallard.org/experimental/api/";
+      xmlns:ui="http://projectmallard.org/1.0/ui/";>
+  <info>
+    <link xref="index" group="callback" type="guide"/>
+  </info>
+  <title>Regress.TestObj.function_ptr</title>
+  <synopsis><code mime="text/x-python">
+ returns(none)
+def on_function_ptr():
+  </code></synopsis>
+
+
+<terms>
+</terms>
+
+</page>
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index d25e41c..82c11d3 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -3450,6 +3450,13 @@ raise an error.</doc>
       <field name="gtype">
         <type name="GType" c:type="GType"/>
       </field>
+      <field name="function_ptr">
+        <callback name="function_ptr">
+          <return-value transfer-ownership="none">
+            <type name="none" c:type="void"/>
+          </return-value>
+        </callback>
+      </field>
       <glib:signal name="all"
                    when="first"
                    no-recurse="1"
diff --git a/tests/scanner/regress.h b/tests/scanner/regress.h
index ad2cb1f..004ae36 100644
--- a/tests/scanner/regress.h
+++ b/tests/scanner/regress.h
@@ -488,6 +488,9 @@ struct _RegressTestObj
   double some_double;
   char* string;
   GType gtype;
+
+  /* < private > */
+  void (*function_ptr)();
 };
 
 typedef void (*RegressTestExternallyDefinedCallback) (RegressTestObj *obj, int someint);


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