[glib] Add g_value_take_variant
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add g_value_take_variant
- Date: Sat, 19 Jun 2010 18:02:52 +0000 (UTC)
commit db68f8203ab9b81e70dbada99faaf69c727f793c
Author: Christian Persch <chpe gnome org>
Date: Fri Jun 18 01:08:13 2010 +0200
Add g_value_take_variant
Turns out we do need g_value_take_variant(), so we can correctly
implement VARIANT:* marshalers.
Bug #621947.
docs/reference/gobject/gobject-sections.txt | 1 +
gobject/glib-genmarshal.c | 2 +-
gobject/gobject.symbols | 1 +
gobject/gtype.h | 7 ++
gobject/gvaluetypes.c | 39 +++++++++++++
gobject/gvaluetypes.h | 2 +
tests/gobject/accumulator.c | 81 +++++++++++++++++++++++++++
tests/gobject/testmarshal.list | 2 +-
8 files changed, 133 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 483c785..fbb4cfe 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -708,6 +708,7 @@ g_param_spec_variant
g_value_get_variant
g_value_dup_variant
g_value_set_variant
+g_value_take_variant
<SUBSECTION Private>
g_value_set_instance
diff --git a/gobject/glib-genmarshal.c b/gobject/glib-genmarshal.c
index 30e36ad..e382fdc 100644
--- a/gobject/glib-genmarshal.c
+++ b/gobject/glib-genmarshal.c
@@ -249,7 +249,7 @@ complete_out_arg (OutArgument *oarg)
{ "BOXED", "BOXED", "gpointer", "g_value_take_boxed", },
{ "POINTER", "POINTER", "gpointer", "g_value_set_pointer", },
{ "OBJECT", "OBJECT", "GObject*", "g_value_take_object", },
- { "VARIANT", "VARIANT", "GVariant*", "g_value_set_variant", },
+ { "VARIANT", "VARIANT", "GVariant*", "g_value_take_variant", },
/* deprecated: */
{ "NONE", "VOID", "void", NULL, },
{ "BOOL", "BOOLEAN", "gboolean", "g_value_set_boolean", },
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index 9b09d9e..0e3c7ee 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -299,6 +299,7 @@ g_value_get_gtype
g_value_get_variant
g_value_dup_variant
g_value_set_variant
+g_value_take_variant
#endif
#endif
diff --git a/gobject/gtype.h b/gobject/gtype.h
index d94249d..253d68e 100644
--- a/gobject/gtype.h
+++ b/gobject/gtype.h
@@ -184,6 +184,13 @@ G_BEGIN_DECLS
*
* The fundamental type corresponding to #GVariant.
*
+ * All floating #GVariant instances passed through the #GType system are
+ * consumed.
+ *
+ * Note that callbacks in closures, and signal handlers
+ * for signals of return type %G_TYPE_VARIANT, must never return floating
+ * variants.
+ *
* Note: GLib 2.24 did include a boxed type with this name. It was replaced
* with this fundamental type in 2.26.
*
diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c
index 6c54a27..1b15301 100644
--- a/gobject/gvaluetypes.c
+++ b/gobject/gvaluetypes.c
@@ -1207,6 +1207,45 @@ g_value_set_variant (GValue *value,
}
/**
+ * g_value_take_variant:
+ * @value: a valid #GValue of %G_TYPE_VARIANT
+ * @variant: a #GVariant, or %NULL
+ *
+ * Set the contents of a variant #GValue to @variant, and takes over
+ * the ownership of the caller's reference to @variant;
+ * the caller doesn't have to unref it any more (i.e. the reference
+ * count of the variant is not increased).
+ *
+ * It is a programmer error to pass a floating variant to this function.
+ * In particular this means that callbacks in closures, and signal handlers
+ * for signals of return type %G_TYPE_VARIANT, must never return floating
+ * variants.
+ *
+ * If you want the #GValue to hold its own reference to @variant, use
+ * g_value_set_variant() instead.
+ *
+ * This is an internal function introduced mainly for C marshallers.
+ *
+ * Since: 2.26
+ */
+void
+g_value_take_variant (GValue *value,
+ GVariant *variant)
+{
+ GVariant *old_variant;
+
+ g_return_if_fail (G_VALUE_HOLDS_VARIANT (value));
+ g_return_if_fail (variant == NULL || !g_variant_is_floating (variant));
+
+ old_variant = value->data[0].v_pointer;
+
+ value->data[0].v_pointer = variant;
+
+ if (old_variant)
+ g_variant_unref (old_variant);
+}
+
+/**
* g_value_get_variant:
* @value: a valid #GValue of %G_TYPE_VARIANT
*
diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h
index d5e27c9..3d3f7b6 100644
--- a/gobject/gvaluetypes.h
+++ b/gobject/gvaluetypes.h
@@ -225,6 +225,8 @@ void g_value_set_gtype (GValue *value,
GType g_value_get_gtype (const GValue *value);
void g_value_set_variant (GValue *value,
GVariant *variant);
+void g_value_take_variant (GValue *value,
+ GVariant *variant);
GVariant* g_value_get_variant (const GValue *value);
GVariant* g_value_dup_variant (const GValue *value);
diff --git a/tests/gobject/accumulator.c b/tests/gobject/accumulator.c
index 602ab11..a4aaee9 100644
--- a/tests/gobject/accumulator.c
+++ b/tests/gobject/accumulator.c
@@ -58,6 +58,8 @@ struct _TestObjectClass
gint param);
gboolean (*test_signal2) (TestObject *tobject,
gint param);
+ GVariant* (*test_signal3) (TestObject *tobject,
+ gboolean *weak_ptr);
};
static GType test_object_get_type (void);
@@ -155,11 +157,70 @@ test_object_signal2_callback_after (TestObject *tobject,
return FALSE;
}
+static gboolean
+test_signal3_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer data)
+{
+ GVariant *variant;
+
+ variant = g_value_get_variant (handler_return);
+ g_assert (!g_variant_is_floating (variant));
+
+ g_value_set_variant (return_accu, variant);
+
+ return variant == NULL;
+}
+
+/* To be notified when the variant is finalised, we construct
+ * it from data with a custom GDestroyNotify.
+ */
+
+typedef struct {
+ char *mem;
+ gsize n;
+ gboolean *weak_ptr;
+} VariantData;
+
+static void
+free_data (VariantData *data)
+{
+ *(data->weak_ptr) = TRUE;
+ g_free (data->mem);
+ g_slice_free (VariantData, data);
+}
+
+static GVariant *
+test_object_real_signal3 (TestObject *tobject,
+ gboolean *weak_ptr)
+{
+ GVariant *variant;
+ VariantData *data;
+
+ variant = g_variant_ref_sink (g_variant_new_uint32 (42));
+ data = g_slice_new (VariantData);
+ data->weak_ptr = weak_ptr;
+ data->n = g_variant_get_size (variant);
+ data->mem = g_malloc (data->n);
+ g_variant_store (variant, data->mem);
+ g_variant_unref (variant);
+
+ variant = g_variant_new_from_data (G_VARIANT_TYPE ("u"),
+ data->mem,
+ data->n,
+ TRUE,
+ (GDestroyNotify) free_data,
+ data);
+ return g_variant_ref_sink (variant);
+}
+
static void
test_object_class_init (TestObjectClass *class)
{
class->test_signal1 = test_object_real_signal1;
class->test_signal2 = test_object_real_signal2;
+ class->test_signal3 = test_object_real_signal3;
g_signal_new ("test-signal1",
G_OBJECT_CLASS_TYPE (class),
@@ -175,6 +236,13 @@ test_object_class_init (TestObjectClass *class)
g_signal_accumulator_true_handled, NULL,
test_marshal_BOOLEAN__INT,
G_TYPE_BOOLEAN, 1, G_TYPE_INT);
+ g_signal_new ("test-signal3",
+ G_OBJECT_CLASS_TYPE (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TestObjectClass, test_signal3),
+ test_signal3_accumulator, NULL,
+ test_marshal_VARIANT__POINTER,
+ G_TYPE_VARIANT, 1, G_TYPE_POINTER);
}
static DEFINE_TYPE(TestObject, test_object,
@@ -188,6 +256,8 @@ main (int argc,
TestObject *object;
gchar *string_result;
gboolean bool_result;
+ gboolean variant_finalised;
+ GVariant *variant_result;
g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
G_LOG_LEVEL_WARNING |
@@ -223,5 +293,16 @@ main (int argc,
g_signal_emit_by_name (object, "test-signal2", 4, &bool_result);
g_assert (bool_result == FALSE);
+ variant_finalised = FALSE;
+ variant_result = NULL;
+ g_signal_emit_by_name (object, "test-signal3", &variant_finalised, &variant_result);
+ g_assert (variant_result != NULL);
+ g_assert (!g_variant_is_floating (variant_result));
+
+ /* Test that variant_result had refcount 1 */
+ g_assert (!variant_finalised);
+ g_variant_unref (variant_result);
+ g_assert (variant_finalised);
+
return 0;
}
diff --git a/tests/gobject/testmarshal.list b/tests/gobject/testmarshal.list
index bed97e2..198c4f9 100644
--- a/tests/gobject/testmarshal.list
+++ b/tests/gobject/testmarshal.list
@@ -1,4 +1,4 @@
# Marshallers used in tests
BOOLEAN:INT
STRING:INT
-
+VARIANT:POINTER
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]