diff options
-rw-r--r-- | docs/reference/gi-sections.txt | 1 | ||||
-rw-r--r-- | gir/Everything-1.0-expected.gir | 23 | ||||
-rw-r--r-- | gir/GIMarshallingTests-1.0-expected.gir | 5 | ||||
-rw-r--r-- | gir/everything.c | 65 | ||||
-rw-r--r-- | gir/everything.h | 2 | ||||
-rw-r--r-- | girepository/gipropertyinfo.c | 27 | ||||
-rw-r--r-- | girepository/gipropertyinfo.h | 1 | ||||
-rw-r--r-- | girepository/girnode.c | 2 | ||||
-rw-r--r-- | girepository/girnode.h | 2 | ||||
-rw-r--r-- | girepository/girparser.c | 42 | ||||
-rw-r--r-- | girepository/girwriter.c | 52 | ||||
-rw-r--r-- | girepository/gitypelib-internal.h | 20 | ||||
-rw-r--r-- | girepository/gitypes.h | 30 | ||||
-rw-r--r-- | giscanner/annotationparser.py | 15 | ||||
-rw-r--r-- | giscanner/ast.py | 6 | ||||
-rw-r--r-- | giscanner/girwriter.py | 1 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.gir | 6 | ||||
-rw-r--r-- | tests/scanner/annotation-1.0-expected.tgir | 4 | ||||
-rw-r--r-- | tests/scanner/foo-1.0-expected.gir | 5 | ||||
-rw-r--r-- | tests/scanner/foo-1.0-expected.tgir | 2 |
20 files changed, 254 insertions, 57 deletions
diff --git a/docs/reference/gi-sections.txt b/docs/reference/gi-sections.txt index 5f8f46c3..6080f9fc 100644 --- a/docs/reference/gi-sections.txt +++ b/docs/reference/gi-sections.txt @@ -108,6 +108,7 @@ g_signal_info_true_stops_emit GIPropertyInfo g_property_info_get_flags g_property_info_get_type +g_property_info_get_ownership_transfer </SECTION> <SECTION> diff --git a/gir/Everything-1.0-expected.gir b/gir/Everything-1.0-expected.gir index e2373ba2..ec7c5205 100644 --- a/gir/Everything-1.0-expected.gir +++ b/gir/Everything-1.0-expected.gir @@ -361,12 +361,23 @@ case."> </parameter> </parameters> </method> - <property name="bare" writable="1"> + <property name="bare" writable="1" transfer-ownership="none"> <type name="GObject.Object" c:type="GObject"/> </property> - <property name="boxed" writable="1"> + <property name="boxed" writable="1" transfer-ownership="none"> <type name="TestBoxed" c:type="TestBoxed"/> </property> + <property name="hash-table" writable="1" transfer-ownership="container"> + <type name="GLib.HashTable" c:type="GHashTable"> + <type name="utf8"/> + <type name="int8"/> + </type> + </property> + <property name="list" writable="1" transfer-ownership="none"> + <type name="GLib.List" c:type="gpointer"> + <type name="utf8"/> + </type> + </property> <field name="parent_instance"> <type name="GObject.Object" c:type="GObject"/> </field> @@ -376,6 +387,12 @@ case."> <field name="boxed"> <type name="TestBoxed" c:type="TestBoxed*"/> </field> + <field name="hash_table"> + <type name="GLib.HashTable" c:type="GHashTable*"/> + </field> + <field name="list"> + <type name="GLib.List" c:type="GList*"/> + </field> <glib:signal name="test"> <return-value transfer-ownership="full"> <type name="none" c:type="void"/> @@ -605,7 +622,7 @@ case."> </parameter> </parameters> </method> - <property name="testbool" writable="1"> + <property name="testbool" writable="1" transfer-ownership="none"> <type name="boolean" c:type="gboolean"/> </property> <field name="parent_instance"> diff --git a/gir/GIMarshallingTests-1.0-expected.gir b/gir/GIMarshallingTests-1.0-expected.gir index 0ed461ba..49367c28 100644 --- a/gir/GIMarshallingTests-1.0-expected.gir +++ b/gir/GIMarshallingTests-1.0-expected.gir @@ -324,7 +324,10 @@ and/or use gtk-doc annotations. --> </parameter> </parameters> </method> - <property name="int" writable="1" construct="1"> + <property name="int" + writable="1" + construct="1" + transfer-ownership="none"> <type name="int" c:type="gint"/> </property> <field name="parent_instance"> diff --git a/gir/everything.c b/gir/everything.c index 389d9a32..f8baada6 100644 --- a/gir/everything.c +++ b/gir/everything.c @@ -1524,7 +1524,9 @@ G_DEFINE_TYPE(TestObj, test_obj, G_TYPE_OBJECT); enum { PROP_TEST_OBJ_BARE = 1, - PROP_TEST_OBJ_BOXED + PROP_TEST_OBJ_BOXED, + PROP_TEST_OBJ_HASH_TABLE, + PROP_TEST_OBJ_LIST, }; static void @@ -1534,6 +1536,7 @@ test_obj_set_property (GObject *object, GParamSpec *pspec) { TestObj *self = TEST_OBJECT (object); + GList *list; switch (property_id) { @@ -1546,7 +1549,25 @@ test_obj_set_property (GObject *object, test_boxed_free (self->boxed); self->boxed = g_value_dup_boxed (value); break; - + + case PROP_TEST_OBJ_HASH_TABLE: + if (self->hash_table) + g_hash_table_unref (self->hash_table); + self->hash_table = g_hash_table_ref (g_value_get_boxed (value)); + break; + + case PROP_TEST_OBJ_LIST: + if (self->list != NULL) + { + for (list = self->list; list != NULL; list = g_list_next (list)) + g_free (list->data); + g_list_free (self->list); + } + self->list = NULL; + for (list = g_value_get_pointer (value); list != NULL; list = g_list_next (list)) + self->list = g_list_append (self->list, g_strdup (list->data)); + break; + default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -1571,6 +1592,16 @@ test_obj_get_property (GObject *object, case PROP_TEST_OBJ_BOXED: g_value_set_boxed (value, self->boxed); break; + + case PROP_TEST_OBJ_HASH_TABLE: + if (self->hash_table != NULL) + g_hash_table_ref (self->hash_table); + g_value_set_boxed (value, self->hash_table); + break; + + case PROP_TEST_OBJ_LIST: + g_value_set_pointer (value, self->list); + break; default: /* We don't have any other property... */ @@ -1660,6 +1691,35 @@ test_obj_class_init (TestObjClass *klass) g_object_class_install_property (gobject_class, PROP_TEST_OBJ_BOXED, pspec); + + /** + * TestObj:hash-table: + * + * Type: GLib.HashTable<utf8,int8> + * Transfer: container + */ + pspec = g_param_spec_boxed ("hash-table", + "GHashTable property", + "A contained GHashTable", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_HASH_TABLE, + pspec); + + /** + * TestObj:list: + * + * Type: GLib.List<utf8> + * Transfer: none + */ + pspec = g_param_spec_pointer ("list", + "GList property", + "A contained GList", + G_PARAM_READWRITE); + g_object_class_install_property (gobject_class, + PROP_TEST_OBJ_LIST, + pspec); klass->matrix = test_obj_default_matrix; } @@ -1669,6 +1729,7 @@ test_obj_init (TestObj *obj) { obj->bare = NULL; obj->boxed = NULL; + obj->hash_table = NULL; } TestObj * diff --git a/gir/everything.h b/gir/everything.h index 509e1c09..3f89e226 100644 --- a/gir/everything.h +++ b/gir/everything.h @@ -268,6 +268,8 @@ struct _TestObj GObject *bare; TestBoxed *boxed; + GHashTable *hash_table; + GList *list; }; struct _TestObjClass diff --git a/girepository/gipropertyinfo.c b/girepository/gipropertyinfo.c index 705a80bf..224709d2 100644 --- a/girepository/gipropertyinfo.c +++ b/girepository/gipropertyinfo.c @@ -57,3 +57,30 @@ g_property_info_get_type (GIPropertyInfo *info) return _g_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + G_STRUCT_OFFSET (PropertyBlob, type)); } +/** + * g_property_info_get_ownership_transfer: + * @info: a #GIPropertyInfo + * + * Obtain the ownership transfer for this property. See #GITransfer for more + * information about transfer values. + * + * Returns: the transfer + */ +GITransfer +g_property_info_get_ownership_transfer (GIPropertyInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + PropertyBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), -1); + + blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->transfer_ownership) + return GI_TRANSFER_EVERYTHING; + else if (blob->transfer_container_ownership) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} diff --git a/girepository/gipropertyinfo.h b/girepository/gipropertyinfo.h index 168b88cc..487389cb 100644 --- a/girepository/gipropertyinfo.h +++ b/girepository/gipropertyinfo.h @@ -35,6 +35,7 @@ G_BEGIN_DECLS GParamFlags g_property_info_get_flags (GIPropertyInfo *info); GITypeInfo * g_property_info_get_type (GIPropertyInfo *info); +GITransfer g_property_info_get_ownership_transfer (GIPropertyInfo *info); G_END_DECLS diff --git a/girepository/girnode.c b/girepository/girnode.c index db029989..0f5223fa 100644 --- a/girepository/girnode.c +++ b/girepository/girnode.c @@ -1648,6 +1648,8 @@ g_ir_node_build_typelib (GIrNode *node, blob->writable = prop->writable; blob->construct = prop->construct; blob->construct_only = prop->construct_only; + blob->transfer_ownership = prop->transfer; + blob->transfer_container_ownership = prop->shallow_transfer; blob->reserved = 0; g_ir_node_build_typelib ((GIrNode *)prop->type, diff --git a/girepository/girnode.h b/girepository/girnode.h index 8c7b14eb..038a53d7 100644 --- a/girepository/girnode.h +++ b/girepository/girnode.h @@ -178,6 +178,8 @@ struct _GIrNodeProperty gboolean writable; gboolean construct; gboolean construct_only; + gboolean transfer; + gboolean shallow_transfer; GIrNodeType *type; }; diff --git a/girepository/girparser.c b/girepository/girparser.c index bda72e12..65f038ce 100644 --- a/girepository/girparser.c +++ b/girepository/girparser.c @@ -841,6 +841,44 @@ start_function (GMarkupParseContext *context, } static void +parse_property_transfer (GIrNodeProperty *property, + const gchar *transfer, + ParseContext *ctx) +{ + if (transfer == NULL) + { + GIrNodeInterface *iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + + g_warning ("required attribute 'transfer-ownership' for property '%s' in " + "type '%s.%s'", property->node.name, ctx->namespace, + iface->node.name); + } + else if (strcmp (transfer, "none") == 0) + { + property->transfer = FALSE; + property->shallow_transfer = FALSE; + } + else if (strcmp (transfer, "container") == 0) + { + property->transfer = FALSE; + property->shallow_transfer = TRUE; + } + else if (strcmp (transfer, "full") == 0) + { + property->transfer = TRUE; + property->shallow_transfer = FALSE; + } + else + { + GIrNodeInterface *iface = (GIrNodeInterface *)CURRENT_NODE (ctx); + + g_warning ("Unknown transfer-ownership value: '%s' for property '%s' in " + "type '%s.%s'", transfer, property->node.name, ctx->namespace, + iface->node.name); + } +} + +static void parse_param_transfer (GIrNodeParam *param, const gchar *transfer, const gchar *name) { if (transfer == NULL) @@ -1237,12 +1275,14 @@ start_property (GMarkupParseContext *context, const gchar *writable; const gchar *construct; const gchar *construct_only; + const gchar *transfer; name = find_attribute ("name", attribute_names, attribute_values); readable = find_attribute ("readable", attribute_names, attribute_values); writable = find_attribute ("writable", attribute_names, attribute_values); construct = find_attribute ("construct", attribute_names, attribute_values); construct_only = find_attribute ("construct-only", attribute_names, attribute_values); + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); if (name == NULL) MISSING_ATTRIBUTE (context, error, element_name, "name"); @@ -1274,6 +1314,8 @@ start_property (GMarkupParseContext *context, else property->construct_only = FALSE; + parse_property_transfer (property, transfer, ctx); + iface = (GIrNodeInterface *)CURRENT_NODE (ctx); iface->members = g_list_append (iface->members, property); diff --git a/girepository/girwriter.c b/girepository/girwriter.c index 6fa892db..ca68f57b 100644 --- a/girepository/girwriter.c +++ b/girepository/girwriter.c @@ -187,6 +187,26 @@ write_type_name_attribute (const gchar *namespace, xml_printf (file, "\""); } + static void +write_ownership_transfer (GITransfer transfer, + Xml *file) +{ + switch (transfer) + { + case GI_TRANSFER_NOTHING: + xml_printf (file, " transfer-ownership=\"none\""); + break; + case GI_TRANSFER_CONTAINER: + xml_printf (file, " transfer-ownership=\"container\""); + break; + case GI_TRANSFER_EVERYTHING: + xml_printf (file, " transfer-ownership=\"full\""); + break; + default: + g_assert_not_reached (); + } +} + static void write_type_info (const gchar *namespace, GITypeInfo *info, @@ -443,20 +463,7 @@ write_callable_info (const gchar *namespace, xml_start_element (file, "return-value"); - switch (g_callable_info_get_caller_owns (info)) - { - case GI_TRANSFER_NOTHING: - xml_printf (file, " transfer-ownership=\"none\""); - break; - case GI_TRANSFER_CONTAINER: - xml_printf (file, " transfer-ownership=\"container\""); - break; - case GI_TRANSFER_EVERYTHING: - xml_printf (file, " transfer-ownership=\"full\""); - break; - default: - g_assert_not_reached (); - } + write_ownership_transfer (g_callable_info_get_caller_owns (info), file); if (g_callable_info_may_return_null (info)) xml_printf (file, " allow-none=\"1\""); @@ -477,20 +484,7 @@ write_callable_info (const gchar *namespace, xml_printf (file, " name=\"%s\"", g_base_info_get_name ((GIBaseInfo *) arg)); - switch (g_arg_info_get_ownership_transfer (arg)) - { - case GI_TRANSFER_NOTHING: - xml_printf (file, " transfer-ownership=\"none\""); - break; - case GI_TRANSFER_CONTAINER: - xml_printf (file, " transfer-ownership=\"container\""); - break; - case GI_TRANSFER_EVERYTHING: - xml_printf (file, " transfer-ownership=\"full\""); - break; - default: - g_assert_not_reached (); - } + write_ownership_transfer (g_arg_info_get_ownership_transfer (arg), file); switch (g_arg_info_get_direction (arg)) { @@ -968,6 +962,8 @@ write_property_info (const gchar *namespace, if (flags & G_PARAM_CONSTRUCT_ONLY) xml_printf (file, " construct-only=\"1\""); + write_ownership_transfer (g_property_info_get_ownership_transfer (info), file); + write_attributes (file, (GIBaseInfo*) info); type = g_property_info_get_type (info); diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 0524efa1..bb920ac6 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -815,17 +815,25 @@ typedef struct { * @writable: * @construct: * @construct_only: The ParamFlags used when registering the property. + * @transfer_ownership: When writing, the type containing the property takes + * ownership of the value. When reading, the returned value needs to be released + * by the caller. + * @transfer_container_ownership: For container types indicates that the + * ownership of the container, but not of its contents, is transferred. This is + * typically the case when reading lists of statically allocated things. * @type: Describes the type of the property. */ typedef struct { guint32 name; - guint32 deprecated : 1; - guint32 readable : 1; - guint32 writable : 1; - guint32 construct : 1; - guint32 construct_only : 1; - guint32 reserved :27; + guint32 deprecated : 1; + guint32 readable : 1; + guint32 writable : 1; + guint32 construct : 1; + guint32 construct_only : 1; + guint32 transfer_ownership : 1; + guint32 transfer_container_ownership : 1; + guint32 reserved :25; guint32 reserved2; diff --git a/girepository/gitypes.h b/girepository/gitypes.h index 78becaef..5ef64ca1 100644 --- a/girepository/gitypes.h +++ b/girepository/gitypes.h @@ -241,13 +241,29 @@ typedef enum /** * GITransfer: - * @GI_TRANSFER_NOTHING: transfer nothing to the caller - * @GI_TRANSFER_CONTAINER: transfer the container (eg list, array, - * hashtable), but no the contents to the caller. - * @GI_TRANSFER_EVERYTHING: transfer everything to the caller. - * - * Represent the transfer ownership information of a #GICallableInfo or - * a #GIArgInfo. + * @GI_TRANSFER_NOTHING: transfer nothing from the callee (function or the type + * instance the property belongs to) to the caller. The callee retains the + * ownership of the transfer and the caller doesn't need to do anything to free + * up the resources of this transfer. + * @GI_TRANSFER_CONTAINER: transfer the container (list, array, hash table) from + * the callee to the caller. The callee retains the ownership of the individual + * items in the container and the caller has to free up the container resources + * (g_list_free()/g_hash_table_destroy() etc) of this transfer. + * @GI_TRANSFER_EVERYTHING: transfer everything, eg the container and its + * contents from the callee to the caller. This is the case when the callee + * creates a copy of all the data it returns. The caller is responsible for + * cleaning up the container and item resources of this transfer. + * + * The transfer is the exchange of data between two parts, from the callee to + * the caller. The callee is either a function/method/signal or an + * object/interface where a property is defined. The caller is the side + * accessing a property or calling a function. + * #GITransfer specifies who's responsible for freeing the resources after the + * ownership transfer is complete. In case of a containing type such as a list, + * an array or a hash table the container itself is specified differently from + * the items within the container itself. Each container is freed differently, + * check the documentation for the types themselves for information on how to + * free them. */ typedef enum { GI_TRANSFER_NOTHING, diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py index d632174c..d5cc7f63 100644 --- a/giscanner/annotationparser.py +++ b/giscanner/annotationparser.py @@ -24,8 +24,8 @@ import re import sys from .ast import (Array, Bitfield, Callback, Class, Enum, Field, Function, - Interface, List, Map, Parameter, Record, Return, Type, Union, - Varargs, + Interface, List, Map, Parameter, Property, Record, Return, + Type, Union, Varargs, default_array_types, BASIC_GIR_TYPES, PARAM_DIRECTION_INOUT, @@ -53,6 +53,7 @@ TAG_RETURNS_ALT = 'return value' TAG_ATTRIBUTES = 'attributes' TAG_RENAME_TO = 'rename to' TAG_TYPE = 'type' +TAG_TRANSFER = 'transfer' # Options - annotations for parameters and return values OPT_ALLOW_NONE = 'allow-none' @@ -418,6 +419,14 @@ class AnnotationApplier(object): self._parse_node_common(prop, block) if block: prop.doc = block.comment + + transfer_tag = self._get_tag(block, TAG_TRANSFER) + if transfer_tag is not None: + options = {OPT_TRANSFER: Option(transfer_tag.value)} + else: + options = {} + prop.transfer = self._extract_transfer(parent, prop, options) + type_tag = self._get_tag(block, TAG_TYPE) if type_tag: prop.type = self._resolve(type_tag.value, prop.type) @@ -946,5 +955,7 @@ class AnnotationApplier(object): return PARAM_TRANSFER_FULL elif isinstance(node, Field): return PARAM_TRANSFER_NONE + elif isinstance(node, Property): + return PARAM_TRANSFER_NONE else: raise AssertionError(node) diff --git a/giscanner/ast.py b/giscanner/ast.py index 902a3f6f..0e9f112d 100644 --- a/giscanner/ast.py +++ b/giscanner/ast.py @@ -521,12 +521,12 @@ class Constant(Node): self.name, self.type, self.value) -class Property(Node): +class Property(TypeContainer): def __init__(self, name, type_name, readable, writable, - construct, construct_only, ctype=None): - Node.__init__(self, name) + construct, construct_only, ctype=None, transfer=None): self.type = Type(type_name, ctype) + TypeContainer.__init__(self, name, self.type, transfer) self.readable = readable self.writable = writable self.construct = construct diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py index 48791b11..7fe5bad1 100644 --- a/giscanner/girwriter.py +++ b/giscanner/girwriter.py @@ -400,6 +400,7 @@ and/or use gtk-doc annotations. ''') attrs.append(('construct', '1')) if prop.construct_only: attrs.append(('construct-only', '1')) + attrs.append(('transfer-ownership', prop.transfer)) if prop.doc: attrs.append(('doc', prop.doc)) with self.tagcontext('property', attrs): diff --git a/tests/scanner/annotation-1.0-expected.gir b/tests/scanner/annotation-1.0-expected.gir index 3191e39d..ff8e0e19 100644 --- a/tests/scanner/annotation-1.0-expected.gir +++ b/tests/scanner/annotation-1.0-expected.gir @@ -484,7 +484,10 @@ type."> <type name="none" c:type="void"/> </return-value> </method> - <property name="function-property" writable="1" construct="1"> + <property name="function-property" + writable="1" + construct="1" + transfer-ownership="none"> <type name="Callback" c:type="gpointer"/> </property> <property name="string-property" @@ -493,6 +496,7 @@ type."> deprecated-version="1.2" writable="1" construct="1" + transfer-ownership="none" doc="This is a property which is a string"> <type name="utf8" c:type="gchararray"/> </property> diff --git a/tests/scanner/annotation-1.0-expected.tgir b/tests/scanner/annotation-1.0-expected.tgir index 4f74b27c..ba56be6e 100644 --- a/tests/scanner/annotation-1.0-expected.tgir +++ b/tests/scanner/annotation-1.0-expected.tgir @@ -356,10 +356,10 @@ <type name="none"/> </return-value> </method> - <property name="function-property" writable="1" construct="1"> + <property name="function-property" writable="1" construct="1" transfer-ownership="none"> <type name="Callback"/> </property> - <property name="string-property" writable="1" construct="1"> + <property name="string-property" writable="1" construct="1" transfer-ownership="none"> <type name="utf8"/> </property> <glib:signal name="doc-empty-arg-parsing" when="LAST"> diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir index 20eb437e..e2fd2d92 100644 --- a/tests/scanner/foo-1.0-expected.gir +++ b/tests/scanner/foo-1.0-expected.gir @@ -449,7 +449,10 @@ uses a C sugar return type."> </parameter> </parameters> </method> - <property name="string" writable="1" construct="1"> + <property name="string" + writable="1" + construct="1" + transfer-ownership="none"> <type name="utf8" c:type="gchararray"/> </property> <field name="parent_instance"> diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir index d46a318b..f71201f2 100644 --- a/tests/scanner/foo-1.0-expected.tgir +++ b/tests/scanner/foo-1.0-expected.tgir @@ -333,7 +333,7 @@ </parameter> </parameters> </method> - <property name="string" writable="1" construct="1"> + <property name="string" writable="1" construct="1" transfer-ownership="none"> <type name="utf8"/> </property> <glib:signal name="signal" when="LAST"> |