summaryrefslogtreecommitdiff
path: root/girepository
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2009-02-27 19:02:48 -0500
committerColin Walters <walters@verbum.org>2009-03-05 15:52:12 -0500
commitfdbe3cc3e1cfaa546648a76b1dca72beead0b65b (patch)
tree01156e22ec59d29c642d59ce7ad75f383d77466a /girepository
parentb8e3172424ba956a0d18eae8deb305310b2cab74 (diff)
downloadgobject-introspection-fdbe3cc3e1cfaa546648a76b1dca72beead0b65b.tar.gz
Bug 557383 - Virtual method support
Broadly speaking, this change adds the concept of <vfunc> to the .gir. The typelib already had most of the infrastructure for virtual functions, though there is one API addition. The scanner assumes that any class callback slot that doesn't match a signal name is a virtual. In the .gir, we write out *both* the <method> wrapper and a <vfunc>. If we can determine an association between them (based on the names matching, or a new Virtual: annotation), then we notate that in the .gir. The typelib gains an association from the vfunc to the function, if it exists. This will be useful for bindings since they already know how to consume FunctionInfo.
Diffstat (limited to 'girepository')
-rw-r--r--girepository/ginfo.c116
-rw-r--r--girepository/girepository.h5
-rw-r--r--girepository/girnode.c37
-rw-r--r--girepository/girnode.h2
-rw-r--r--girepository/girparser.c6
-rw-r--r--girepository/gtypelib.h8
6 files changed, 170 insertions, 4 deletions
diff --git a/girepository/ginfo.c b/girepository/ginfo.c
index fcc5f098..d522a565 100644
--- a/girepository/ginfo.c
+++ b/girepository/ginfo.c
@@ -1527,6 +1527,63 @@ g_object_info_get_vfunc (GIObjectInfo *info,
base->typelib, offset);
}
+static GIVFuncInfo *
+find_vfunc (GIBaseInfo *base,
+ guint32 offset,
+ gint n_vfuncs,
+ const gchar *name)
+{
+ /* FIXME hash */
+ Header *header = (Header *)base->typelib->data;
+ gint i;
+
+ for (i = 0; i < n_vfuncs; i++)
+ {
+ VFuncBlob *fblob = (VFuncBlob *)&base->typelib->data[offset];
+ const gchar *fname = (const gchar *)&base->typelib->data[fblob->name];
+
+ if (strcmp (name, fname) == 0)
+ return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base,
+ base->typelib, offset);
+
+ offset += header->vfunc_blob_size;
+ }
+
+ return NULL;
+}
+
+/**
+ * g_object_info_find_vfunc:
+ * @info: An #GIObjectInfo
+ * @name: The name of a virtual function to find.
+ *
+ * Locate a virtual function slot with name @name. Note that the namespace
+ * for virtuals is distinct from that of methods; there may or may not be
+ * a concrete method associated for a virtual. If there is one, it may
+ * be retrieved using #g_vfunc_info_get_invoker. See the documentation for
+ * that function for more information on invoking virtuals.
+ *
+ * Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
+ */
+GIVFuncInfo *
+g_object_info_find_vfunc (GIObjectInfo *info,
+ const gchar *name)
+{
+ gint offset;
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ Header *header = (Header *)base->typelib->data;
+ ObjectBlob *blob = (ObjectBlob *)&base->typelib->data[base->offset];
+
+ offset = base->offset + header->object_blob_size
+ + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+ + blob->n_fields * header->field_blob_size
+ + blob->n_properties * header->property_blob_size
+ + blob->n_methods * header->function_blob_size
+ + blob->n_signals * header->signal_blob_size;
+
+ return find_vfunc (base, offset, blob->n_vfuncs, name);
+}
+
gint
g_object_info_get_n_constants (GIObjectInfo *info)
{
@@ -1728,6 +1785,34 @@ g_interface_info_get_vfunc (GIInterfaceInfo *info,
base->typelib, offset);
}
+/**
+ * g_interface_info_find_vfunc:
+ * @info: An #GIObjectInfo
+ * @name: The name of a virtual function to find.
+ *
+ * Locate a virtual function slot with name @name. See the documentation
+ * for #g_object_info_find_vfunc for more information on virtuals.
+ *
+ * Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
+ */
+GIVFuncInfo *
+g_interface_info_find_vfunc (GIInterfaceInfo *info,
+ const gchar *name)
+{
+ gint offset;
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ Header *header = (Header *)base->typelib->data;
+ InterfaceBlob *blob = (InterfaceBlob *)&base->typelib->data[base->offset];
+
+ offset = base->offset + header->interface_blob_size
+ + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2
+ + blob->n_properties * header->property_blob_size
+ + blob->n_methods * header->function_blob_size
+ + blob->n_signals * header->signal_blob_size;
+
+ return find_vfunc (base, offset, blob->n_vfuncs, name);
+}
+
gint
g_interface_info_get_n_constants (GIInterfaceInfo *info)
{
@@ -1913,6 +1998,37 @@ g_vfunc_info_get_signal (GIVFuncInfo *info)
return NULL;
}
+/**
+ * g_vfunc_info_get_invoker:
+ * @info: A #GIVFuncInfo
+ *
+ * If this virtual function has an associated invoker method, this
+ * method will return it. An invoker method is a C entry point.
+ *
+ * Not all virtuals will have invokers.
+ *
+ * Return value: (transfer full): An invoker function, or %NULL if none known
+ */
+GIFunctionInfo *
+g_vfunc_info_get_invoker (GIVFuncInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ VFuncBlob *blob = (VFuncBlob *)&base->typelib->data[base->offset];
+ GIBaseInfo *container = base->container;
+ GIInfoType parent_type;
+
+ /* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */
+ if (blob->invoker == 1023)
+ return NULL;
+
+ parent_type = g_base_info_get_type (container);
+ if (parent_type == GI_INFO_TYPE_OBJECT)
+ return g_object_info_get_method ((GIObjectInfo*)container, blob->invoker);
+ else if (parent_type == GI_INFO_TYPE_INTERFACE)
+ return g_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker);
+ else
+ g_assert_not_reached ();
+}
/* GIConstantInfo functions */
GITypeInfo *
diff --git a/girepository/girepository.h b/girepository/girepository.h
index 4059adc0..1058570f 100644
--- a/girepository/girepository.h
+++ b/girepository/girepository.h
@@ -470,6 +470,8 @@ GISignalInfo * g_object_info_get_signal (GIObjectInfo *in
gint g_object_info_get_n_vfuncs (GIObjectInfo *info);
GIVFuncInfo * g_object_info_get_vfunc (GIObjectInfo *info,
gint n);
+GIVFuncInfo * g_object_info_find_vfunc (GIObjectInfo *info,
+ const gchar *name);
gint g_object_info_get_n_constants (GIObjectInfo *info);
GIConstantInfo * g_object_info_get_constant (GIObjectInfo *info,
gint n);
@@ -495,6 +497,8 @@ GISignalInfo * g_interface_info_get_signal (GIInterfaceInfo *in
gint g_interface_info_get_n_vfuncs (GIInterfaceInfo *info);
GIVFuncInfo * g_interface_info_get_vfunc (GIInterfaceInfo *info,
gint n);
+GIVFuncInfo * g_interface_info_find_vfunc (GIInterfaceInfo *info,
+ const gchar *name);
gint g_interface_info_get_n_constants (GIInterfaceInfo *info);
GIConstantInfo * g_interface_info_get_constant (GIInterfaceInfo *info,
gint n);
@@ -527,6 +531,7 @@ typedef enum
GIVFuncInfoFlags g_vfunc_info_get_flags (GIVFuncInfo *info);
gint g_vfunc_info_get_offset (GIVFuncInfo *info);
GISignalInfo * g_vfunc_info_get_signal (GIVFuncInfo *info);
+GIFunctionInfo * g_vfunc_info_get_invoker (GIVFuncInfo *info);
/* GIConstantInfo */
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 22c0aee0..01e83ace 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -265,6 +265,7 @@ g_ir_node_free (GIrNode *node)
GIrNodeVFunc *vfunc = (GIrNodeVFunc *)node;
g_free (node->name);
+ g_free (vfunc->invoker);
for (l = vfunc->parameters; l; l = l->next)
g_ir_node_free ((GIrNode *)l->data);
g_list_free (vfunc->parameters);
@@ -1186,6 +1187,30 @@ g_ir_find_node (GIrModule *module,
return node != NULL;
}
+static int
+get_index_of_member_type (GIrNodeInterface *node,
+ GIrNodeTypeId type,
+ const char *name)
+{
+ guint index = -1;
+ GList *l;
+
+ for (l = node->members; l; l = l->next)
+ {
+ GIrNode *node = l->data;
+
+ if (node->type != type)
+ continue;
+
+ index++;
+
+ if (strcmp (node->name, name) == 0)
+ break;
+ }
+
+ return index;
+}
+
static void
serialize_type (GIrModule *module,
GList *modules,
@@ -1759,6 +1784,18 @@ g_ir_node_build_typelib (GIrNode *node,
blob->class_closure = 0; /* FIXME */
blob->reserved = 0;
+ if (vfunc->invoker)
+ {
+ int index = get_index_of_member_type ((GIrNodeInterface*)parent, G_IR_NODE_FUNCTION, vfunc->invoker);
+ if (index == -1)
+ {
+ g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name);
+ }
+ blob->invoker = (guint) index;
+ }
+ else
+ blob->invoker = 0x3ff; /* max of 10 bits */
+
blob->struct_offset = vfunc->offset;
blob->reserved2 = 0;
blob->signature = signature;
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 2a1f6b23..238593ae 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -214,6 +214,8 @@ struct _GIrNodeVFunc
gboolean must_not_be_implemented;
gboolean is_class_closure;
+ char *invoker;
+
GList *parameters;
GIrNodeParam *result;
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 006ed3b7..9afd8585 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -2080,7 +2080,7 @@ start_vfunc (GMarkupParseContext *context,
ParseContext *ctx,
GError **error)
{
- if (strcmp (element_name, "vfunc") == 0 &&
+ if (strcmp (element_name, "virtual-method") == 0 &&
(ctx->state == STATE_CLASS ||
ctx->state == STATE_INTERFACE))
{
@@ -2089,12 +2089,14 @@ start_vfunc (GMarkupParseContext *context,
const gchar *override;
const gchar *is_class_closure;
const gchar *offset;
+ const gchar *invoker;
name = find_attribute ("name", attribute_names, attribute_values);
must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);
override = find_attribute ("override", attribute_names, attribute_values);
is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
offset = find_attribute ("offset", attribute_names, attribute_values);
+ invoker = find_attribute ("invoker", attribute_names, attribute_values);
if (name == NULL)
MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -2138,6 +2140,8 @@ start_vfunc (GMarkupParseContext *context,
else
vfunc->offset = 0;
+ vfunc->invoker = g_strdup (invoker);
+
iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
iface->members = g_list_append (iface->members, vfunc);
diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h
index db5fe117..f6ad8c97 100644
--- a/girepository/gtypelib.h
+++ b/girepository/gtypelib.h
@@ -843,9 +843,10 @@ typedef struct {
* @class_closure: Set if this virtual function is the class closure of a signal.
* @signal: The index of the signal in the list of signals of the object or
* interface to which this virtual function belongs.
- * @struct_offset:
- * The offset of the function pointer in the class struct. The value
+ * @struct_offset: The offset of the function pointer in the class struct. The value
* 0xFFFF indicates that the struct offset is unknown.
+ * @invoker: If a method invoker for this virtual exists, this is the offset in the
+ * class structure of the method. If no method is known, this value will be 0x3ff.
* @signature:
* Offset of the SignatureBlob describing the parameter types and the
* return value type.
@@ -861,7 +862,8 @@ typedef struct {
guint16 signal;
guint16 struct_offset;
- guint16 reserved2;
+ guint16 invoker : 10; /* Number of bits matches @index in FunctionBlob */
+ guint16 reserved2 : 6;
guint32 reserved3;
guint32 signature;