Commit 1e9822c7 authored by Johan Dahlin's avatar Johan Dahlin

Add support for non-GObject fundamental objects

This patch adds support for instantiable fundamental object types,
which are not GObject based. This is mostly interesting for being
able to support GstMiniObject's which are extensivly used in GStreamer.
Includes a big test case to the Everything module (inspired by
GstMiniObject) which should be used by language bindings who wishes to
test this functionallity.

This patch increases the size of the typelib and breaks compatibility
with older typelibs.

https://bugzilla.gnome.org/show_bug.cgi?id=568913
parent 01772763
......@@ -144,9 +144,14 @@ g_interface_info_find_vfunc
<FILE>giobjectinfo</FILE>
GI_IS_OBJECT_INFO
GIObjectInfo
GIObjectInfoGetValueFunction
GIObjectInfoRefFunction
GIObjectInfoSetValueFunction
GIObjectInfoUnrefFunction
g_object_info_get_type_name
g_object_info_get_type_init
g_object_info_get_abstract
g_object_info_get_fundamental
g_object_info_get_parent
g_object_info_get_n_interfaces
g_object_info_get_interface
......@@ -165,6 +170,14 @@ g_object_info_get_n_constants
g_object_info_get_constant
g_object_info_get_class_struct
g_object_info_find_vfunc
g_object_info_get_unref_function
g_object_info_get_unref_function_pointer
g_object_info_get_ref_function
g_object_info_get_ref_function_pointer
g_object_info_get_set_value_function
g_object_info_get_set_value_function_pointer
g_object_info_get_get_value_function
g_object_info_get_get_value_function_pointer
</SECTION>
<SECTION>
......
......@@ -161,6 +161,107 @@ and/or use gtk-doc annotations. -->
c:type="GInitiallyUnownedClass"/>
</field>
</record>
<class name="TestFundamentalObject"
c:type="TestFundamentalObject"
abstract="1"
glib:type-name="TestFundamentalObject"
glib:get-type="test_fundamental_object_get_type"
glib:type-struct="TestFundamentalObjectClass"
glib:fundamental="1"
glib:ref-func="test_fundamental_object_ref"
glib:unref-func="test_fundamental_object_unref"
glib:set-value-func="test_value_set_fundamental_object"
glib:get-value-func="test_value_get_fundamental_object">
<method name="ref" c:identifier="test_fundamental_object_ref">
<return-value transfer-ownership="full">
<type name="TestFundamentalObject" c:type="TestFundamentalObject*"/>
</return-value>
</method>
<method name="unref" c:identifier="test_fundamental_object_unref">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
</method>
<field name="instance">
<type name="GObject.TypeInstance" c:type="GTypeInstance"/>
</field>
<field name="refcount">
<type name="int" c:type="gint"/>
</field>
<field name="flags">
<type name="uint" c:type="guint"/>
</field>
</class>
<record name="TestFundamentalObjectClass"
c:type="TestFundamentalObjectClass"
glib:is-gtype-struct-for="TestFundamentalObject">
<field name="type_class">
<type name="GObject.TypeClass" c:type="GTypeClass"/>
</field>
<field name="copy">
<type name="TestFundamentalObjectCopyFunction"
c:type="TestFundamentalObjectCopyFunction"/>
</field>
<field name="finalize">
<type name="TestFundamentalObjectFinalizeFunction"
c:type="TestFundamentalObjectFinalizeFunction"/>
</field>
</record>
<callback name="TestFundamentalObjectCopyFunction"
c:type="TestFundamentalObjectCopyFunction">
<return-value transfer-ownership="full">
<type name="TestFundamentalObject" c:type="TestFundamentalObject*"/>
</return-value>
<parameters>
<parameter name="obj" transfer-ownership="none">
<type name="TestFundamentalObject" c:type="TestFundamentalObject*"/>
</parameter>
</parameters>
</callback>
<callback name="TestFundamentalObjectFinalizeFunction"
c:type="TestFundamentalObjectFinalizeFunction">
<return-value transfer-ownership="none">
<type name="none" c:type="void"/>
</return-value>
<parameters>
<parameter name="obj" transfer-ownership="none">
<type name="TestFundamentalObject" c:type="TestFundamentalObject*"/>
</parameter>
</parameters>
</callback>
<class name="TestFundamentalSubObject"
c:type="TestFundamentalSubObject"
parent="TestFundamentalObject"
glib:type-name="TestFundamentalSubObject"
glib:get-type="test_fundamental_sub_object_get_type"
glib:type-struct="TestFundamentalSubObjectClass"
glib:fundamental="1">
<constructor name="new" c:identifier="test_fundamental_sub_object_new">
<return-value transfer-ownership="full">
<type name="TestFundamentalSubObject"
c:type="TestFundamentalSubObject*"/>
</return-value>
<parameters>
<parameter name="data" transfer-ownership="none">
<type name="utf8" c:type="char*"/>
</parameter>
</parameters>
</constructor>
<field name="fundamental_object">
<type name="TestFundamentalObject" c:type="TestFundamentalObject"/>
</field>
<field name="data">
<type name="utf8" c:type="char*"/>
</field>
</class>
<record name="TestFundamentalSubObjectClass"
c:type="TestFundamentalSubObjectClass"
glib:is-gtype-struct-for="TestFundamentalSubObject">
<field name="fundamental_object_class">
<type name="TestFundamentalObjectClass"
c:type="TestFundamentalObjectClass"/>
</field>
</record>
<interface name="TestInterface"
c:type="EverythingTestInterface"
glib:type-name="EverythingTestInterface"
......
#include <string.h>
#include <stdlib.h>
#include <glib-object.h>
#include <gobject/gvaluecollector.h>
#include "everything.h"
static gboolean abort_on_error = TRUE;
......@@ -1896,6 +1899,296 @@ test_sub_obj_unset_bare (TestSubObj *obj)
test_obj_set_bare(TEST_OBJECT(obj), NULL);
}
/* TestFundamental */
TestFundamentalObject *
test_fundamental_object_ref (TestFundamentalObject * fundamental_object)
{
g_return_val_if_fail (fundamental_object != NULL, NULL);
g_atomic_int_inc (&fundamental_object->refcount);
return fundamental_object;
}
static void
test_fundamental_object_free (TestFundamentalObject * fundamental_object)
{
TestFundamentalObjectClass *mo_class;
test_fundamental_object_ref (fundamental_object);
mo_class = TEST_FUNDAMENTAL_OBJECT_GET_CLASS (fundamental_object);
mo_class->finalize (fundamental_object);
if (G_LIKELY (g_atomic_int_dec_and_test (&fundamental_object->refcount))) {
g_type_free_instance ((GTypeInstance *) fundamental_object);
}
}
void
test_fundamental_object_unref (TestFundamentalObject * fundamental_object)
{
g_return_if_fail (fundamental_object != NULL);
g_return_if_fail (fundamental_object->refcount > 0);
if (G_UNLIKELY (g_atomic_int_dec_and_test (&fundamental_object->refcount))) {
test_fundamental_object_free (fundamental_object);
}
}
static void
test_fundamental_object_replace (TestFundamentalObject ** olddata, TestFundamentalObject * newdata)
{
TestFundamentalObject *olddata_val;
g_return_if_fail (olddata != NULL);
olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
if (olddata_val == newdata)
return;
if (newdata)
test_fundamental_object_ref (newdata);
while (!g_atomic_pointer_compare_and_exchange ((gpointer *) olddata,
olddata_val, newdata)) {
olddata_val = g_atomic_pointer_get ((gpointer *) olddata);
}
if (olddata_val)
test_fundamental_object_unref (olddata_val);
}
static void
test_value_fundamental_object_init (GValue * value)
{
value->data[0].v_pointer = NULL;
}
static void
test_value_fundamental_object_free (GValue * value)
{
if (value->data[0].v_pointer) {
test_fundamental_object_unref (TEST_FUNDAMENTAL_OBJECT_CAST (value->data[0].v_pointer));
}
}
static void
test_value_fundamental_object_copy (const GValue * src_value, GValue * dest_value)
{
if (src_value->data[0].v_pointer) {
dest_value->data[0].v_pointer =
test_fundamental_object_ref (TEST_FUNDAMENTAL_OBJECT_CAST (src_value->data[0].
v_pointer));
} else {
dest_value->data[0].v_pointer = NULL;
}
}
static gpointer
test_value_fundamental_object_peek_pointer (const GValue * value)
{
return value->data[0].v_pointer;
}
static gchar *
test_value_fundamental_object_collect (GValue * value,
guint n_collect_values,
GTypeCValue * collect_values,
guint collect_flags)
{
if (collect_values[0].v_pointer) {
value->data[0].v_pointer =
test_fundamental_object_ref (collect_values[0].v_pointer);
} else {
value->data[0].v_pointer = NULL;
}
return NULL;
}
static gchar *
test_value_fundamental_object_lcopy (const GValue * value,
guint n_collect_values,
GTypeCValue * collect_values,
guint collect_flags)
{
gpointer *fundamental_object_p = collect_values[0].v_pointer;
if (!fundamental_object_p) {
return g_strdup_printf ("value location for '%s' passed as NULL",
G_VALUE_TYPE_NAME (value));
}
if (!value->data[0].v_pointer)
*fundamental_object_p = NULL;
else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
*fundamental_object_p = value->data[0].v_pointer;
else
*fundamental_object_p = test_fundamental_object_ref (value->data[0].v_pointer);
return NULL;
}
static void
test_fundamental_object_finalize (TestFundamentalObject * obj)
{
}
static TestFundamentalObject *
test_fundamental_object_copy_default (const TestFundamentalObject * obj)
{
g_warning ("TestFundamentalObject classes must implement TestFundamentalObject::copy");
return NULL;
}
static void
test_fundamental_object_class_init (gpointer g_class, gpointer class_data)
{
TestFundamentalObjectClass *mo_class = TEST_FUNDAMENTAL_OBJECT_CLASS (g_class);
mo_class->copy = test_fundamental_object_copy_default;
mo_class->finalize = test_fundamental_object_finalize;
}
static void
test_fundamental_object_init (GTypeInstance * instance, gpointer klass)
{
TestFundamentalObject *fundamental_object = TEST_FUNDAMENTAL_OBJECT_CAST (instance);
fundamental_object->refcount = 1;
}
/**
* TestFundamentalObject:
*
* Ref Func: test_fundamental_object_ref
* Unref Func: test_fundamental_object_unref
* Set Value Func: test_value_set_fundamental_object
* Get Value Func: test_value_get_fundamental_object
*/
GType
test_fundamental_object_get_type (void)
{
static GType _test_fundamental_object_type = 0;
if (G_UNLIKELY (_test_fundamental_object_type == 0)) {
static const GTypeValueTable value_table = {
test_value_fundamental_object_init,
test_value_fundamental_object_free,
test_value_fundamental_object_copy,
test_value_fundamental_object_peek_pointer,
(char *) "p",
test_value_fundamental_object_collect,
(char *) "p",
test_value_fundamental_object_lcopy
};
static const GTypeInfo fundamental_object_info = {
sizeof (TestFundamentalObjectClass),
NULL, NULL,
test_fundamental_object_class_init,
NULL,
NULL,
sizeof (TestFundamentalObject),
0,
(GInstanceInitFunc) test_fundamental_object_init,
&value_table
};
static const GTypeFundamentalInfo fundamental_object_fundamental_info = {
(G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE |
G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE)
};
_test_fundamental_object_type = g_type_fundamental_next ();
g_type_register_fundamental (_test_fundamental_object_type, "TestFundamentalObject",
&fundamental_object_info, &fundamental_object_fundamental_info, G_TYPE_FLAG_ABSTRACT);
}
return _test_fundamental_object_type;
}
/**
* test_value_set_fundamental_object: (skip)
* @value:
* @fundamental_object:
*/
void
test_value_set_fundamental_object (GValue * value, TestFundamentalObject * fundamental_object)
{
gpointer *pointer_p;
g_return_if_fail (TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT (value));
g_return_if_fail (fundamental_object == NULL || TEST_IS_FUNDAMENTAL_OBJECT (fundamental_object));
pointer_p = &value->data[0].v_pointer;
test_fundamental_object_replace ((TestFundamentalObject **) pointer_p, fundamental_object);
}
/**
* test_value_get_fundamental_object: (skip)
* @value:
*/
TestFundamentalObject *
test_value_get_fundamental_object (const GValue * value)
{
g_return_val_if_fail (TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT (value), NULL);
return value->data[0].v_pointer;
}
static TestFundamentalObjectClass *parent_class = NULL;
G_DEFINE_TYPE (TestFundamentalSubObject, test_fundamental_sub_object, TEST_TYPE_FUNDAMENTAL_OBJECT);
static TestFundamentalSubObject *
_test_fundamental_sub_object_copy (TestFundamentalSubObject * fundamental_sub_object)
{
TestFundamentalSubObject *copy;
copy = test_fundamental_sub_object_new(NULL);
copy->data = g_strdup(fundamental_sub_object->data);
return copy;
}
static void
test_fundamental_sub_object_finalize (TestFundamentalSubObject * fundamental_sub_object)
{
g_return_if_fail (fundamental_sub_object != NULL);
g_free(fundamental_sub_object->data);
test_fundamental_object_unref (TEST_FUNDAMENTAL_OBJECT (fundamental_sub_object));
}
static void
test_fundamental_sub_object_class_init (TestFundamentalSubObjectClass * klass)
{
parent_class = g_type_class_peek_parent (klass);
klass->fundamental_object_class.copy = (TestFundamentalObjectCopyFunction) _test_fundamental_sub_object_copy;
klass->fundamental_object_class.finalize =
(TestFundamentalObjectFinalizeFunction) test_fundamental_sub_object_finalize;
}
static void
test_fundamental_sub_object_init(TestFundamentalSubObject *object)
{
}
TestFundamentalSubObject *
test_fundamental_sub_object_new (const char * data)
{
TestFundamentalSubObject *object;
object = (TestFundamentalSubObject *) g_type_create_instance (test_fundamental_sub_object_get_type());
object->data = g_strdup(data);
return object;
}
/**
* test_callback:
......
......@@ -334,6 +334,61 @@ TestSubObj* test_sub_obj_new (void);
void test_sub_obj_unset_bare (TestSubObj *obj);
int test_sub_obj_instance_method (TestSubObj *obj);
/* fundamental object */
#define TEST_TYPE_FUNDAMENTAL_OBJECT (test_fundamental_object_get_type())
#define TEST_IS_FUNDAMENTAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FUNDAMENTAL_OBJECT))
#define TEST_IS_FUNDAMENTAL_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_FUNDAMENTAL_OBJECT))
#define TEST_FUNDAMENTAL_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_FUNDAMENTAL_OBJECT, TestFundamentalObjectClass))
#define TEST_FUNDAMENTAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FUNDAMENTAL_OBJECT, TestFundamentalObject))
#define TEST_FUNDAMENTAL_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_FUNDAMENTAL_OBJECT, TestFundamentalObjectClass))
#define TEST_FUNDAMENTAL_OBJECT_CAST(obj) ((TestFundamentalObject*)(obj))
typedef struct _TestFundamentalObject TestFundamentalObject;
typedef struct _TestFundamentalObjectClass TestFundamentalObjectClass;
typedef TestFundamentalObject * (*TestFundamentalObjectCopyFunction) (const TestFundamentalObject *obj);
typedef void (*TestFundamentalObjectFinalizeFunction) (TestFundamentalObject *obj);
struct _TestFundamentalObject {
GTypeInstance instance;
gint refcount;
guint flags;
};
struct _TestFundamentalObjectClass {
GTypeClass type_class;
TestFundamentalObjectCopyFunction copy;
TestFundamentalObjectFinalizeFunction finalize;
};
GType test_fundamental_object_get_type (void);
TestFundamentalObject* test_fundamental_object_ref (TestFundamentalObject *fundamental_object);
void test_fundamental_object_unref (TestFundamentalObject *fundamental_object);
#define TEST_VALUE_HOLDS_FUNDAMENTAL_OBJECT(value) (G_VALUE_HOLDS(value, TEST_TYPE_FUNDAMENTAL_OBJECT))
void test_value_set_fundamental_object (GValue *value, TestFundamentalObject *fundamental_object);
TestFundamentalObject* test_value_get_fundamental_object (const GValue *value);
typedef struct _TestFundamentalSubObject TestFundamentalSubObject;
typedef struct _TestFundamentalSubObjectClass TestFundamentalSubObjectClass;
struct _TestFundamentalSubObject
{
TestFundamentalObject fundamental_object;
char *data;
};
struct _TestFundamentalSubObjectClass {
TestFundamentalObjectClass fundamental_object_class;
};
GType test_fundamental_sub_object_get_type(void);
TestFundamentalSubObject *
test_fundamental_sub_object_new (const char *data);
/* callback */
typedef void (*TestSimpleCallback) (void);
typedef int (*TestCallback) (void);
......
......@@ -270,6 +270,56 @@ dump_enum_type (GType type, const char *symbol, GOutputStream *out)
goutput_write (out, " </enum>");
}
static void
dump_fundamental_type (GType type, const char *symbol, GOutputStream *out)
{
guint n_interfaces;
guint i;
GType *interfaces;
GString *parent_str;
GType parent;
gboolean first = TRUE;
escaped_printf (out, " <fundamental name=\"%s\" get-type=\"%s\"",
g_type_name (type), symbol);
if (G_TYPE_IS_ABSTRACT (type))
escaped_printf (out, " abstract=\"1\"");
if (G_TYPE_IS_INSTANTIATABLE (type))
escaped_printf (out, " instantiatable=\"1\"");
parent = type;
parent_str = g_string_new ("");
do
{
parent = g_type_parent (parent);
if (first)
first = FALSE;
else
g_string_append_c (parent_str, ',');
if (!g_type_name (parent))
break;
g_string_append (parent_str, g_type_name (parent));
} while (parent != G_TYPE_INVALID);
if (parent_str->len > 0)
escaped_printf (out, " parents=\"%s\"", parent_str->str);
g_string_free (parent_str, TRUE);
goutput_write (out, ">\n");
interfaces = g_type_interfaces (type, &n_interfaces);
for (i = 0; i < n_interfaces; i++)
{
GType itype = interfaces[i];
escaped_printf (out, " <implements name=\"%s\"/>\n",
g_type_name (itype));
}
goutput_write (out, " </fundamental>\n");
}
static void
dump_type (GType type, const char *symbol, GOutputStream *out)
{
......@@ -294,10 +344,7 @@ dump_type (GType type, const char *symbol, GOutputStream *out)
/* GValue, etc. Just skip them. */
break;
default:
/* Other fundamental types such as the once GStreamer and Clutter registers
* are not yet interesting from an introspection perspective and should be
* ignored
*/
dump_fundamental_type (type, symbol, out);
break;
}
}
......
......@@ -96,6 +96,29 @@ g_object_info_get_abstract (GIObjectInfo *info)
return blob->abstract != 0;
}
/**
* g_object_info_get_fundamental:
* @info: a #GIObjectInfo
*
* Obtain if the object type is of a fundamental type which is not
* G_TYPE_OBJECT. This is mostly for supporting GstMiniObject.
*
* Returns: %TRUE if the object type is a fundamental type
*/
gboolean
g_object_info_get_fundamental (GIObjectInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
ObjectBlob *blob;
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (GI_IS_OBJECT_INFO (info), FALSE);
blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->fundamental != 0;
}
/**
* g_object_info_get_type_name:
* @info: a #GIObjectInfo
......@@ -636,3 +659,229 @@ g_object_info_get_class_struct (GIObjectInfo *info)
return NULL;
}
typedef const char* (*SymbolGetter) (GIObjectInfo *info);
static void *
_get_func(GIObjectInfo *info,
SymbolGetter getter)
{
const char* symbol;
GSList *parents = NULL, *l;
GIObjectInfo *parent_info;
parent_info = info;
while (parent_info != NULL) {
parents = g_slist_prepend(parents, parent_info);
parent_info = g_object_info_get_parent(parent_info);
}
for (l = parents; l; l = l->next) {
GIObjectInfoRefFunction func;
parent_info = l->data;
symbol = getter(parent_info);
if (symbol == NULL)
continue;
if (g_typelib_symbol (((GIRealInfo *)parent_info)->typelib, symbol, (void**) &func)) {
g_slist_free(parents);
return func;
}
}
g_slist_free(parents);
return NULL;
}
/**
* g_object_info_get_ref_function:
* @info: a #GIObjectInfo
*