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.
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)
{
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)
{
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 *
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);
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);
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 */
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);
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,
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;
gboolean must_not_be_implemented;
gboolean is_class_closure;
+ char *invoker;
+
GList *parameters;
GIrNodeParam *result;
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))
{
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");
else
vfunc->offset = 0;
+ vfunc->invoker = g_strdup (invoker);
+
iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
iface->members = g_list_append (iface->members, vfunc);
* @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.
guint16 signal;
guint16 struct_offset;
- guint16 reserved2;
+ guint16 invoker : 10; /* Number of bits matches @index in FunctionBlob */
+ guint16 reserved2 : 6;
guint32 reserved3;
guint32 signature;
_COMMENT_HEADER = '*\n '
# Tags - annotations applyed to comment blocks
+TAG_VFUNC = 'virtual'
TAG_SINCE = 'since'
TAG_DEPRECATED = 'deprecated'
TAG_RETURNS = 'returns'
block = self._blocks.get(class_.type_name)
self._parse_node_common(class_, block)
self._parse_constructors(class_.constructors)
- self._parse_methods(class_.methods)
- self._parse_methods(class_.static_methods)
+ self._parse_methods(class_, class_.methods)
+ self._parse_vfuncs(class_, class_.virtual_methods)
+ self._parse_methods(class_, class_.static_methods)
self._parse_properties(class_, class_.properties)
self._parse_signals(class_, class_.signals)
self._parse_fields(class_, class_.fields)
def _parse_interface(self, interface):
block = self._blocks.get(interface.type_name)
self._parse_node_common(interface, block)
- self._parse_methods(interface.methods)
+ self._parse_methods(interface, interface.methods)
+ self._parse_vfuncs(interface, interface.virtual_methods)
self._parse_properties(interface, interface.properties)
self._parse_signals(interface, interface.signals)
self._parse_fields(interface, interface.fields)
block = self._blocks.get(record.symbol)
self._parse_node_common(record, block)
self._parse_constructors(record.constructors)
- self._parse_methods(record.methods)
+ self._parse_methods(record, record.methods)
self._parse_fields(record, record.fields)
if block:
record.doc = block.comment
block = self._blocks.get(boxed.name)
self._parse_node_common(boxed, block)
self._parse_constructors(boxed.constructors)
- self._parse_methods(boxed.methods)
+ self._parse_methods(boxed, boxed.methods)
if block:
boxed.doc = block.comment
self._parse_node_common(union, block)
self._parse_fields(union, union.fields)
self._parse_constructors(union.constructors)
- self._parse_methods(union.methods)
+ self._parse_methods(union, union.methods)
if block:
union.doc = block.comment
for prop in properties:
self._parse_property(parent, prop)
- def _parse_methods(self, methods):
+ def _parse_methods(self, parent, methods):
for method in methods:
- self._parse_function(method)
+ self._parse_method(parent, method)
+
+ def _parse_vfuncs(self, parent, vfuncs):
+ for vfunc in vfuncs:
+ self._parse_vfunc(parent, vfunc)
def _parse_signals(self, parent, signals):
for signal in signals:
if block:
callback.doc = block.comment
+ def _parse_callable(self, callable, block):
+ self._parse_node_common(callable, block)
+ self._parse_params(callable, callable.parameters, block)
+ self._parse_return(callable, callable.retval, block)
+ if block:
+ callable.doc = block.comment
+
def _parse_function(self, func):
block = self._blocks.get(func.symbol)
- self._parse_node_common(func, block)
- self._parse_params(func, func.parameters, block)
- self._parse_return(func, func.retval, block)
- if block:
- func.doc = block.comment
+ self._parse_callable(func, block)
def _parse_signal(self, parent, signal):
block = self._blocks.get('%s::%s' % (parent.type_name, signal.name))
self._parse_node_common(signal, block)
- self._parse_deprecated(signal, block)
# We're only attempting to name the signal parameters if
# the number of parameter tags (@foo) is the same or greater
# than the number of signal parameters
if block:
signal.doc = block.comment
+ def _parse_method(self, parent, meth):
+ block = self._blocks.get(meth.symbol)
+ self._parse_function(meth)
+ virtual = self._get_tag(block, TAG_VFUNC)
+ if virtual:
+ invoker_name = virtual.value
+ matched = False
+ for vfunc in parent.virtual_methods:
+ if vfunc.name == invoker_name:
+ matched = True
+ vfunc.invoker = meth.name
+ break
+ if not matched:
+ print "warning: unmatched virtual invoker %r for method %r" % \
+ (invoker_name, meth.symbol)
+
+ def _parse_vfunc(self, parent, vfunc):
+ key = '%s::%s' % (parent.type_name, vfunc.name)
+ self._parse_callable(vfunc, self._blocks.get(key))
+
def _parse_field(self, parent, field):
if isinstance(field, Callback):
self._parse_callback(field)
def __str__(self):
return '%s-%s' % (self.name, self.version)
+class Callable(Node):
-class Function(Node):
-
- def __init__(self, name, retval, parameters, symbol, throws=None):
+ def __init__(self, name, retval, parameters, throws):
Node.__init__(self, name)
self.retval = retval
self.parameters = parameters
- self.symbol = symbol
self.throws = not not throws
+ self.doc = None
+
+ def __repr__(self):
+ return '%s(%r, %r, %r)' % (self.__class__.__name__,
+ self.name, self.retval,
+ self.parameters)
+
+class Function(Callable):
+
+ def __init__(self, name, retval, parameters, symbol, throws=None):
+ Callable.__init__(self, name, retval, parameters, throws)
+ self.symbol = symbol
self.is_method = False
self.doc = None
if parameter.name == name:
return parameter
- def __repr__(self):
- return '%s(%r, %r, %r)' % (self.__class__.__name__,
- self.name, self.retval,
- self.parameters)
+class VFunction(Callable):
-class VFunction(Function):
- pass
+ def __init__(self, name, retval, parameters, throws):
+ Callable.__init__(self, name, retval, parameters, throws)
+ self.invoker = None
+
+ @classmethod
+ def from_callback(cls, cb):
+ obj = cls(cb.name, cb.retval, cb.parameters[1:],
+ cb.throws)
+ return obj
class Type(Node):
self.glib_type_struct = None
self.is_abstract = is_abstract
self.methods = []
+ self.virtual_methods = []
self.static_methods = []
self.interfaces = []
self.constructors = []
Node.__init__(self, name)
self.parent = parent
self.methods = []
+ self.virtual_methods = []
self.glib_type_struct = None
self.properties = []
self.fields = []
attrs.append(('c:type', alias.ctype))
self.write_tag('alias', attrs)
- def _write_function(self, func, tag_name='function'):
- attrs = [('name', func.name),
- ('c:identifier', func.symbol)]
- if func.doc:
- attrs.append(('doc', func.doc))
- self._append_version(func, attrs)
- self._append_deprecated(func, attrs)
- self._append_throws(func, attrs)
+ def _write_callable(self, callable, tag_name, extra_attrs):
+ attrs = [('name', callable.name)]
+ attrs.extend(extra_attrs)
+ if callable.doc:
+ attrs.append(('doc', callable.doc))
+ self._append_version(callable, attrs)
+ self._append_deprecated(callable, attrs)
+ self._append_throws(callable, attrs)
with self.tagcontext(tag_name, attrs):
- self._write_attributes(func)
- self._write_return_type(func.retval)
- self._write_parameters(func.parameters)
+ self._write_attributes(callable)
+ self._write_return_type(callable.retval)
+ self._write_parameters(callable.parameters)
+
+ def _write_function(self, func, tag_name='function'):
+ attrs = [('c:identifier', func.symbol)]
+ self._write_callable(func, tag_name, attrs)
def _write_method(self, method):
self._write_function(method, tag_name='method')
self._write_constructor(method)
for method in node.static_methods:
self._write_static_method(method)
+ for vfunc in node.virtual_methods:
+ self._write_vfunc(vfunc)
for method in node.methods:
self._write_method(method)
for prop in node.properties:
self._write_attributes(prop)
self._write_type(prop.type)
+ def _write_vfunc(self, vf):
+ attrs = []
+ if vf.invoker:
+ attrs.append(('invoker', vf.invoker))
+ self._write_callable(vf, 'virtual-method', attrs)
+
def _write_callback(self, callback):
- # FIXME: reuse _write_function
- attrs = [('name', callback.name), ('c:type', callback.ctype)]
- if callback.doc:
- attrs.append(('doc', callback.doc))
- self._append_version(callback, attrs)
- self._append_deprecated(callback, attrs)
- self._append_throws(callback, attrs)
- with self.tagcontext('callback', attrs):
- self._write_attributes(callback)
- self._write_return_type(callback.retval)
- self._write_parameters(callback.parameters)
+ attrs = [('c:type', callback.ctype)]
+ self._write_callable(callback, 'callback', attrs)
def _boxed_attrs(self, boxed):
return [('glib:type-name', boxed.type_name),
from .ast import (Alias, Bitfield, Callback, Constant, Enum, Function, Member,
Namespace, Parameter, Property, Record, Return, Type, Union,
- Field, type_name_from_ctype,
+ Field, VFunction, type_name_from_ctype,
default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL)
from .transformer import Names
from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
- GLibBoxedUnion, GLibBoxedOther, GLibRecord, type_names)
+ GLibBoxedUnion, GLibBoxedOther, GLibRecord,
+ type_names)
from .utils import to_underscores, to_underscores_noprefix
default_array_types['guchar*'] = TYPE_UINT8
except KeyError, e:
print "WARNING: DELETING node %s: %s" % (node.name, e)
self._remove_attribute(node.name)
+ # Another pass, since we need to have the methods parsed
+ # in order to correctly modify them after class/record
+ # pairing
+ for (ns, node) in nodes:
# associate GtkButtonClass with GtkButton
if isinstance(node, Record):
self._pair_class_record(node)
self._resolve_quarks()
# Fourth pass: ensure all types are known
if not self._noclosure:
- self._validate(nodes)
+ self._resolve_types(nodes)
+
+ self._validate(nodes)
# Create a new namespace with what we found
namespace = Namespace(self._namespace_name, self._namespace_version)
for field in maybe_class.fields:
if isinstance(field, Field):
field.writable = False
- # TODO: remove this, we should be computing vfuncs instead
- if isinstance(pair_class, GLibInterface):
- for field in maybe_class.fields[1:]:
- pair_class.fields.append(field)
+
+ # Loop through fields to determine which are virtual
+ # functions and which are signal slots by
+ # assuming everything that doesn't share a name
+ # with a known signal is a virtual slot.
+ for field in maybe_class.fields:
+ if not isinstance(field, Callback):
+ continue
+ # Check the first parameter is the object
+ if len(field.parameters) == 0:
+ continue
+ firstparam_type = field.parameters[0].type
+ if firstparam_type != pair_class:
+ continue
+ # Also double check we don't have a signal with this
+ # name.
+ matched_signal = False
+ for signal in pair_class.signals:
+ if signal.name.replace('-', '_') == field.name:
+ matched_signal = True
+ break
+ if matched_signal:
+ continue
+ vfunc = VFunction.from_callback(field)
+ pair_class.virtual_methods.append(vfunc)
+
+ # Take the set of virtual methods we found, and try
+ # to pair up with any matching methods using the
+ # name+signature.
+ for vfunc in pair_class.virtual_methods:
+ for method in pair_class.methods:
+ if (method.name != vfunc.name or
+ method.retval != vfunc.retval or
+ method.parameters != vfunc.parameters):
+ continue
+ vfunc.invoker = method.name
+
gclass_struct = GLibRecord.from_record(class_struct)
self._remove_attribute(class_struct.name)
self._add_attribute(gclass_struct, True)
def _resolve_alias(self, alias):
alias.target = self._resolve_type_name(alias.target, alias.target)
- # Validation
-
- def _validate(self, nodes):
+ def _resolve_types(self, nodes):
nodes = list(self._names.names.itervalues())
i = 0
self._validating = True
i += 1
self._print_statistics()
self._validating = False
+
+ # Validation
+
+ def _validate_interface(self, iface):
+ for vfunc in iface.virtual_methods:
+ if not vfunc.invoker:
+ print ("warning: Interface %r virtual function %r " + \
+ "has no known invoker") % (iface.name, vfunc.name)
+
+ # This function is called at the very end, before we hand back the
+ # completed namespace to the writer. Add static analysis checks here.
+ def _validate(self, nodes):
+ for (name, node) in nodes:
+ if isinstance(node, GLibInterface):
+ self._validate_interface(node)
G_OBJECT_CLASS (test_obj_parent_class)->dispose (gobject);
}
+static int
+test_obj_default_matrix (TestObj *obj, const char *somestr)
+{
+ return 42;
+}
+
static void
test_obj_class_init (TestObjClass *klass)
{
g_object_class_install_property (gobject_class,
PROP_TEST_OBJ_BARE,
pspec);
+
+ klass->matrix = test_obj_default_matrix;
}
static void
return x;
}
+/**
+ * test_obj_do_matrix:
+ * @obj: A #TestObj
+ * @somestr: Meaningless string
+ *
+ * This method is virtual. Notably its name differs from the virtual
+ * slot name, which makes it useful for testing bindings handle this
+ * case.
+ *
+ * Virtual: matrix
+ */
+int
+test_obj_do_matrix (TestObj *obj, const char *somestr)
+{
+ return TEST_OBJ_GET_CLASS (obj)->matrix (obj, somestr);
+}
+
/**
* test_callback:
* @callback: (scope call):
#define TEST_TYPE_OBJ (test_obj_get_type ())
#define TEST_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJ, TestObj))
#define TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJ))
+#define TEST_OBJ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJ, TestObjClass))
typedef struct _TestObj TestObj;
typedef struct _TestObjClass TestObjClass;
{
GObjectClass parent_class;
+ int (*matrix) (TestObj *obj, const char *somestr);
+
guint test_signal;
};
void test_obj_set_bare (TestObj *obj, GObject *bare);
double test_obj_static_method (int x);
+/* virtual */
+int test_obj_do_matrix (TestObj *obj, const char *somestr);
+
/* callback */
typedef int (*TestCallback) ();
typedef int (*TestCallbackUserData) (gpointer user_data);
gitestthrows_LDADD = $(top_builddir)/girepository/libgirepository-1.0.la $(GIREPO_LIBS)
TESTS = gitestrepo gitestthrows
-TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG) \
- XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)"
+TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" \
+ XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)" $(DEBUG)
\ No newline at end of file
info = g_irepository_find_by_name (repo, "Gio", "ThisDoesNotExist");
g_assert (info == NULL);
+ /* vfunc tests */
+ {
+ GIVFuncInfo *vfunc;
+ GIFunctionInfo *invoker;
+
+ /* Test vfunc with invoker on interface */
+ info = g_irepository_find_by_name (repo, "Gio", "File");
+ g_assert (info != NULL);
+
+ vfunc = g_interface_info_find_vfunc ((GIInterfaceInfo*)info, "read_async");
+ g_assert (vfunc != NULL);
+
+ invoker = g_vfunc_info_get_invoker (vfunc);
+ g_assert (invoker != NULL);
+
+ g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "read_async") == 0);
+
+ /* Test vfunc with no known invoker on object */
+ info = g_irepository_find_by_name (repo, "GObject", "Object");
+ g_assert (info != NULL);
+
+ vfunc = g_object_info_find_vfunc ((GIObjectInfo*)info, "dispose");
+ g_assert (vfunc != NULL);
+
+ /* Ok, maybe we should mark g_object_run_dispose as the invoker for
+ * dispose, but...eh. It's pretty special however you cut it.
+ */
+ invoker = g_vfunc_info_get_invoker (vfunc);
+ g_assert (invoker == NULL);
+
+ /* Test vfunc with invoker on object */
+ info = g_irepository_find_by_name (repo, "Gio", "AppLaunchContext");
+ g_assert (info != NULL);
+
+ vfunc = g_object_info_find_vfunc ((GIObjectInfo*)info, "get_display");
+ g_assert (vfunc != NULL);
+
+ invoker = g_vfunc_info_get_invoker (vfunc);
+ g_assert (invoker != NULL);
+ g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "get_display") == 0);
+
+ /* And let's be sure we can find the method directly */
+
+ invoker = g_object_info_find_method ((GIObjectInfo*)info, "get_display");
+ g_assert (invoker != NULL);
+ g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "get_display") == 0);
+ }
+
exit(0);
}
glib:type-name="FooInterface"
glib:get-type="foo_interface_get_type"
glib:type-struct="InterfaceIface">
- <callback name="do_foo" c:type="do_foo">
+ <virtual-method name="do_foo" invoker="do_foo">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
- <parameter name="self" transfer-ownership="none">
- <type name="Interface" c:type="FooInterface*"/>
+ <parameter name="x" transfer-ownership="none">
+ <type name="int" c:type="int"/>
</parameter>
</parameters>
- </callback>
+ </virtual-method>
+ <method name="do_foo" c:identifier="foo_interface_do_foo">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ <parameters>
+ <parameter name="x" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </method>
</interface>
<record name="InterfaceIface"
c:type="FooInterfaceIface"
<parameter name="self" transfer-ownership="none">
<type name="Interface" c:type="FooInterface*"/>
</parameter>
+ <parameter name="x" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
</parameters>
</callback>
</record>
<type name="int" c:type="int"/>
</return-value>
</function>
+ <virtual-method name="virtual_method" invoker="virtual_method">
+ <return-value transfer-ownership="none">
+ <type name="boolean" c:type="gboolean"/>
+ </return-value>
+ <parameters>
+ <parameter name="first_param" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </virtual-method>
+ <virtual-method name="read_fn" invoker="read">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ <parameters>
+ <parameter name="offset" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </virtual-method>
<method name="external_type" c:identifier="foo_object_external_type">
<return-value transfer-ownership="full">
<type name="utility.Object" c:type="UtilityObject*"/>
</parameter>
</parameters>
</method>
+ <method name="virtual_method" c:identifier="foo_object_virtual_method">
+ <return-value transfer-ownership="none">
+ <type name="boolean" c:type="gboolean"/>
+ </return-value>
+ <parameters>
+ <parameter name="first_param" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </method>
+ <method name="read"
+ c:identifier="foo_object_read"
+ doc="Read some stuff.">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ <parameters>
+ <parameter name="offset" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </method>
<property name="string" writable="1" construct="1">
<type name="utf8" c:type="gchararray"/>
</property>
</parameter>
</parameters>
</callback>
+ <callback name="read_fn" c:type="read_fn">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ <parameters>
+ <parameter name="object" transfer-ownership="none">
+ <type name="Object" c:type="FooObject*"/>
+ </parameter>
+ <parameter name="offset" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none">
+ <type name="int" c:type="int"/>
+ </parameter>
+ </parameters>
+ </callback>
</record>
<constant name="PIE_IS_TASTY" value="3.14159">
<type name="double"/>
glib:get-type="foo_sub_interface_get_type"
glib:type-struct="SubInterfaceIface">
<prerequisite name="Interface"/>
+ <virtual-method name="do_bar" invoker="do_bar">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ </virtual-method>
<method name="do_bar" c:identifier="foo_sub_interface_do_bar">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
</method>
- <callback name="do_bar" c:type="do_bar">
- <return-value transfer-ownership="none">
+ <glib:signal name="destroy-event">
+ <return-value transfer-ownership="full">
<type name="none" c:type="void"/>
</return-value>
- <parameters>
- <parameter name="self" transfer-ownership="none">
- <type name="SubInterface" c:type="FooSubInterface*"/>
- </parameter>
- </parameters>
- </callback>
+ </glib:signal>
</interface>
<record name="SubInterfaceIface"
c:type="FooSubInterfaceIface"
<field name="parent_iface">
<type name="GObject.TypeInterface" c:type="GTypeInterface"/>
</field>
+ <callback name="destroy_event" c:type="destroy_event">
+ <return-value transfer-ownership="none">
+ <type name="none" c:type="void"/>
+ </return-value>
+ <parameters>
+ <parameter name="self" transfer-ownership="none">
+ <type name="SubInterface" c:type="FooSubInterface*"/>
+ </parameter>
+ </parameters>
+ </callback>
<callback name="do_bar" c:type="do_bar">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
<member name="second" value="2"/>
<member name="third" value="4"/>
</bitfield>
- <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface"/>
+ <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface">
+ <method name="do_foo" c:identifier="foo_interface_do_foo">
+ <return-value transfer-ownership="none">
+ <type name="none"/>
+ </return-value>
+ <parameters>
+ <parameter name="x" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </method>
+ <virtual-method name="do_foo" offset="0" invoker="do_foo">
+ <return-value transfer-ownership="none">
+ <type name="none"/>
+ </return-value>
+ <parameters>
+ <parameter name="x" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </virtual-method>
+ </interface>
<record name="InterfaceIface" glib:is-gtype-struct="1">
<field name="parent_iface">
<type name="GObject.TypeInterface"/>
</parameter>
</parameters>
</method>
+ <method name="virtual_method" c:identifier="foo_object_virtual_method">
+ <return-value transfer-ownership="none">
+ <type name="boolean"/>
+ </return-value>
+ <parameters>
+ <parameter name="first_param" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </method>
+ <method name="read" c:identifier="foo_object_read">
+ <return-value transfer-ownership="none">
+ <type name="none"/>
+ </return-value>
+ <parameters>
+ <parameter name="offset" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </method>
<property name="string" writable="1" construct="1">
<type name="utf8"/>
</property>
</parameter>
</parameters>
</glib:signal>
+ <virtual-method name="virtual_method" offset="0" invoker="virtual_method">
+ <return-value transfer-ownership="none">
+ <type name="boolean"/>
+ </return-value>
+ <parameters>
+ <parameter name="first_param" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </virtual-method>
+ <virtual-method name="read_fn" offset="0" invoker="read">
+ <return-value transfer-ownership="none">
+ <type name="none"/>
+ </return-value>
+ <parameters>
+ <parameter name="offset" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ <parameter name="length" transfer-ownership="none">
+ <type name="int"/>
+ </parameter>
+ </parameters>
+ </virtual-method>
</class>
<record name="ObjectClass" glib:is-gtype-struct="1">
<field name="parent_class">
<type name="none"/>
</return-value>
</method>
+ <glib:signal name="destroy-event" when="LAST">
+ <return-value transfer-ownership="full">
+ <type name="none"/>
+ </return-value>
+ </glib:signal>
+ <virtual-method name="do_bar" offset="0" invoker="do_bar">
+ <return-value transfer-ownership="none">
+ <type name="none"/>
+ </return-value>
+ </virtual-method>
</interface>
<record name="SubInterfaceIface" glib:is-gtype-struct="1">
<field name="parent_iface">
#include "foo.h"
+#include "girepository.h"
/* A hidden type not exposed publicly, similar to GUPNP's XML wrapper
object */
int foo_init_argv_address (int *argc, char ***argv);
void foo_private_function (FooObject *foo);
void foo_test_unsigned (unsigned int uint);
-void foo_interface_do_foo (FooInterface *self);
-void foo_do_foo (FooInterface *self);
+void foo_interface_do_foo (FooInterface *self, int x);
+void foo_do_foo (FooInterface *self, int x);
int foo_enum_method (FooEnumType foo_enum);
FooHidden * foo_hidden_copy (const FooHidden *boxed);
void foo_hidden_free (FooHidden *boxed);
return object_type;
}
-void foo_interface_do_foo (FooInterface *self)
+void foo_interface_do_foo (FooInterface *self, int x)
{
- FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self);
+ FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self, x);
}
enum {
iface->do_foo = foo_do_foo;
}
+enum {
+ SUBIFACE_DESTROY_EVENT,
+ SUBIFACE_LAST_SIGNAL
+};
+
+static void
+foo_sub_interface_class_init (gpointer g_class, gpointer class_data);
+
+static guint foo_subiface_signals[SUBIFACE_LAST_SIGNAL] = { 0 };
+
GType
foo_sub_interface_get_type (void)
{
object_type = g_type_register_static_simple (G_TYPE_INTERFACE,
"FooSubInterface",
sizeof (FooSubInterfaceIface),
- NULL, 0, NULL, 0);
+ foo_sub_interface_class_init, 0, NULL, 0);
g_type_interface_add_prerequisite (object_type, FOO_TYPE_INTERFACE);
}
return object_type;
}
+static void
+foo_sub_interface_class_init (gpointer g_class, gpointer class_data)
+{
+ foo_subiface_signals[SUBIFACE_DESTROY_EVENT] =
+ g_signal_new ("destroy-event", FOO_TYPE_SUBINTERFACE,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (FooSubInterfaceIface, destroy_event),
+ NULL, NULL,
+ gi_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 0,
+ G_TYPE_NONE);
+}
+
void foo_sub_interface_do_bar (FooSubInterface *self)
{
FOO_SUBINTERFACE_GET_INTERFACE(self)->do_bar (self);
}
void
-foo_do_foo (FooInterface *self)
+foo_do_foo (FooInterface *self, int x)
{
return g_strdup ("foo");
}
+/**
+ * foo_object_read:
+ * @object: obj
+ * @offset: offset
+ * @length: length
+ *
+ * Read some stuff.
+ *
+ * Virtual: read_fn
+ */
+void
+foo_object_read (FooObject *object, int offset, int length)
+{
+
+}
+
G_DEFINE_ABSTRACT_TYPE (FooSubobject, foo_subobject, FOO_TYPE_OBJECT);
static void
{
GTypeInterface parent_iface;
- void (*do_foo) (FooInterface *self);
+ void (*do_foo) (FooInterface *self, int x);
};
GType foo_interface_get_type (void) G_GNUC_CONST;
+void foo_interface_do_foo (FooInterface *iface, int x);
+
struct _FooSubInterfaceIface
{
GTypeInterface parent_iface;
+ /* signals */
+
+ void (*destroy_event) (FooSubInterface *self);
+
+ /* virtual table */
+
void (*do_bar) (FooSubInterface *self);
};
GObjectClass parent_class;
gboolean (* virtual_method) (FooObject *object, int first_param);
+
+ /* Intended to match GFile */
+ void (*read_fn) (FooObject *object, int offset, int length);
};
gint foo_init (void);
void foo_object_handle_glyph (FooObject *object, UtilityGlyph glyph);
+gboolean foo_object_virtual_method (FooObject *object, int first_param);
+
+void foo_object_read (FooObject *object, int offset, int length);
+
int foo_object_static_meth ();
struct _FooSubobject
{
GIVFuncInfoFlags flags;
const gchar *name;
+ GIFunctionInfo *invoker;
gboolean deprecated;
gint offset;
flags = g_vfunc_info_get_flags (info);
deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
offset = g_vfunc_info_get_offset (info);
+ invoker = g_vfunc_info_get_invoker (info);
- xml_start_element (file, "vfunc");
+ xml_start_element (file, "virtual-method");
xml_printf (file, " name=\"%s\"", name);
if (deprecated)
xml_printf (file, " offset=\"%d\"", offset);
+ if (invoker)
+ xml_printf (file, " invoker=\"%s\"", g_base_info_get_name ((GIBaseInfo*)invoker));
+
write_callable_info (namespace, (GICallableInfo*)info, file);
- xml_end_element (file, "vfunc");
+ xml_end_element (file, "virtual-method");
}
static void