EggDBus Reference Manual | ||||
---|---|---|---|---|
Top | Description | Object Hierarchy | Properties |
Synopsis
EggDBusStructure; #define EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST(instance, signature, c_type) #define EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE(instance, signature, c_type) EggDBusStructure * egg_dbus_structure_new (const gchar *signature, GValue *elements); guint egg_dbus_structure_get_num_elements (EggDBusStructure *structure); void egg_dbus_structure_get_element (EggDBusStructure *structure, guint first_structure_element_number, ...); void egg_dbus_structure_get_element_valist (EggDBusStructure *structure, guint first_structure_element_number, va_list var_args); void egg_dbus_structure_get_element_as_gvalue (EggDBusStructure *structure, guint element_number, GValue *value); void egg_dbus_structure_set_element (EggDBusStructure *structure, guint first_structure_element_number, ...); void egg_dbus_structure_set_element_valist (EggDBusStructure *structure, guint first_structure_element_number, va_list var_args); void egg_dbus_structure_set_element_as_gvalue (EggDBusStructure *structure, guint element_number, const GValue *value); const gchar * egg_dbus_structure_get_signature (EggDBusStructure *structure); const gchar * egg_dbus_structure_get_signature_for_element (EggDBusStructure *structure, guint element_number); void egg_dbus_structure_print (EggDBusStructure *structure, guint indent);
Properties
"elemement-signatures" GStrv* : Read "elements" gpointer : Write / Construct Only "num-elemements" gint : Read "signature" gchar* : Read / Write / Construct Only
Description
Instances of EggDBusStructure represents D-Bus structures. Typically, this class isn't used directly, subclasses are used instead.
A structure in D-Bus is a container type with a fixed type signature containing a fixed number of elements. Unlike most programming languages, elements in a D-Bus structure does not have identifiers or names. Neither does the structure itself have a name. For example, in C, consider these two data types:
typedef struct { gint x; gint y; } Point; typedef struct { gint first; gint second; } Pair;
In C, Point
and Pair
are distinct types
and cannot be used interchangeably without type punning. In the D-Bus protocol, however,
it is not possible to make a distinction between serialized instance of Point
and Pair
– both have the signature (ii)
.
In EggDBus, it is possible to declare structures using D-Bus introspection XML. For example consider the following D-Bus introspection XML:
<annotation name="org.gtk.EggDBus.DeclareStruct" value="Point"> <annotation name="org.gtk.EggDBus.Struct.Member" value="i:x"> <annotation name="org.gtk.EggDBus.DocString" value="The X coordinate"/> </annotation> <annotation name="org.gtk.EggDBus.Struct.Member" value="i:y"> <annotation name="org.gtk.EggDBus.DocString" value="The Y coordinate"/> </annotation> </annotation> <annotation name="org.gtk.EggDBus.DeclareStruct" value="Pair"> <annotation name="org.gtk.EggDBus.Struct.Member" value="i:first"> <annotation name="org.gtk.EggDBus.DocString" value="The first element"/> </annotation> <annotation name="org.gtk.EggDBus.Struct.Member" value="i:second"> <annotation name="org.gtk.EggDBus.DocString" value="The second element"/> </annotation> </annotation> <annotation name="org.gtk.EggDBus.DeclareStruct" value="DescribedPair"> <annotation name="org.gtk.EggDBus.Struct.Member" value="s:desc"> <annotation name="org.gtk.EggDBus.DocString" value="A description of the described pair"/> </annotation> <annotation name="org.gtk.EggDBus.Struct.Member" value="(ii):pair"> <annotation name="org.gtk.EggDBus.DocString" value="The pair being described"/> <annotation name="org.gtk.EggDBus.StructType" value="Pair"/> </annotation> </annotation>
These declarations makes eggdbus-binding-tool(1) generate (using
--namespace Test
) three EggDBusStructure derived classes:
TestPoint, TestPair and TestDescribedPair.
Note that these generated classes are using the EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST()
and EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE()
macros for type casting and type checking.
This means that it's legal to use TestPoint and TestPair interchangeably but it's not
legal to cast e.g. an instance of type TestDescribedPoint to e.g. TestPoint:
TestPoint *point; TestPair *pair; TestDescribedPoint *described_point; point = test_point_new (3, 4); /* legal, TestPoint and TestPair are structurally equivalent types */ pair = TEST_PAIR (point); /* both of these assertions are true */ g_assert (test_pair_get_first (pair) == 3); g_assert (test_pair_get_second (pair) == 4); /* true assertion, TestDescribedPoint and TestPoint are not structurally equivalent types */ g_assert (!TEST_IS_DESCRIBED_POINT (point)); /* will issue a warning */ described_point = TEST_DESCRIBED_POINT (point); /* cleanup */ g_object_unref (point);
It is possible to supply structure wrapper types yourself if you want more a more sophisticated API than just raw getters and setters. This is often desirable when using future-proofed (to keep ABI compatibility) D-Bus structures that uses e.g. hash tables to store the values.
User defined structure wrapper types has to be declared in the D-Bus introspection XML:
<annotation name="org.gtk.EggDBus.DeclareStruct" value="Subject"> <annotation name="org.gtk.EggDBus.Struct.Signature" value="(sa{sv})"/> </annotation>
such that they can be referenced by name from methods; e.g.
<method name="GetMostPowerfulSubject"> <arg name="most_powerful_subject" direction="out" type="(sa{sv})"> <annotation name="org.gtk.EggDBus.StructType" value="Subject"/> </arg> </method>
This annotation is needed to properly disambiguate that the D-Bus signature (sa{sv})
really refers to a Subject
structure and not any other random D-Bus structure that
happens to have the same signature.
Declaring and implementing the Subject
structure wrapper type is
straightforward; first the header file:
/* * Copyright (C) 2008 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * Author: David Zeuthen <davidz@redhat.com> */ #ifndef __TEST_SUBJECT_H #define __TEST_SUBJECT_H #include <glib-object.h> #include <gio/gio.h> #include "testbindingstypes.h" G_BEGIN_DECLS #define TEST_TYPE_SUBJECT (test_subject_get_type()) #define TEST_SUBJECT(o) (EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST (o, "(sa{sv})", TestSubject)) #define TEST_SUBJECT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TEST_TYPE_SUBJECT, TestSubjectClass)) #define TEST_SUBJECT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TEST_TYPE_SUBJECT, TestSubjectClass)) #define TEST_IS_SUBJECT(o) (EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE (o, "(sa{sv})", TestSubject)) #define TEST_IS_SUBJECT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TEST_TYPE_SUBJECT)) #if 0 typedef struct _TestSubject TestSubject; #endif typedef struct _TestSubjectClass TestSubjectClass; struct _TestSubject { EggDBusStructure parent_instance; }; struct _TestSubjectClass { EggDBusStructureClass parent_class; }; GType test_subject_get_type (void) G_GNUC_CONST; typedef enum { TEST_SUBJECT_KIND_UNKNOWN, TEST_SUBJECT_KIND_HUMAN, TEST_SUBJECT_KIND_CYLON, TEST_SUBJECT_KIND_DEITY, } TestSubjectKind; TestSubject *test_subject_new (TestSubjectKind kind, const gchar *name, const gchar *favorite_food, const gchar *favorite_color); TestSubjectKind test_subject_get_kind (TestSubject *subject); const gchar * test_subject_get_name (TestSubject *subject); const gchar * test_subject_get_favorite_food (TestSubject *subject); const gchar * test_subject_get_favorite_color (TestSubject *subject); G_END_DECLS #endif /* __TEST_SUBJECT_H */
As with automatically generated EggDBusStructure subclasses, the EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST()
and EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE()
macros must be used so structural equivalence
identification and casting works.
The implementation of the Subject
structure wrapper type looks like this:
/* * Copyright (C) 2008 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * Author: David Zeuthen <davidz@redhat.com> */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include <string.h> #include "testbindings.h" #include "testsubject.h" /** * SECTION:testsubject * @title: TestSubject * @short_description: Example of user-supplied structure wrapper * * The #TestSubject interface is a user-supplied wrapper for accessing * and creating #EggDBusStructure instances with signature (sa{sv}). */ G_DEFINE_TYPE (TestSubject, test_subject, EGG_DBUS_TYPE_STRUCTURE); static void test_subject_init (TestSubject *instance) { } static void test_subject_class_init (TestSubjectClass *klass) { } /** * test_subject_new: * @kind: A TestSubjectKind. * @name: Name of subject. * @favorite_food: The favorite food of the subject. * @favorite_color: The favorite color of the subject. * * Constructs a new #TestSubject. * * Returns: A #TestSubject. */ TestSubject * test_subject_new (TestSubjectKind kind, const gchar *name, const gchar *favorite_food, const gchar *favorite_color) { GValue *values; const gchar *kind_str; EggDBusHashMap *properties; switch (kind) { case TEST_SUBJECT_KIND_HUMAN: kind_str = "human"; break; case TEST_SUBJECT_KIND_CYLON: kind_str = "cylon"; break; case TEST_SUBJECT_KIND_DEITY: kind_str = "deity"; break; default: g_warning ("Unknown kind passed"); return NULL; } properties = egg_dbus_hash_map_new (G_TYPE_STRING, (GDestroyNotify) g_free, EGG_DBUS_TYPE_VARIANT, (GDestroyNotify) g_object_unref); egg_dbus_hash_map_insert (properties, g_strdup ("name"), egg_dbus_variant_new_for_string (name)); egg_dbus_hash_map_insert (properties, g_strdup ("favorite-food"), egg_dbus_variant_new_for_string (favorite_food)); egg_dbus_hash_map_insert (properties, g_strdup ("favorite-color"), egg_dbus_variant_new_for_string (favorite_color)); values = g_new0 (GValue, 2); g_value_init (&(values[0]), G_TYPE_STRING); g_value_set_string (&(values[0]), kind_str); g_value_init (&(values[1]), EGG_DBUS_TYPE_HASH_MAP); g_value_take_object (&(values[1]), properties); return TEST_SUBJECT (g_object_new (TEST_TYPE_SUBJECT, "signature", "(sa{sv})", /* Note: the superclass steals the 'values' parameter */ "elements", values, NULL)); } /** * test_subject_get_kind: * @subject: A #TestSubject. * * Gets the kind of @subject. * * Returns: A #TestSubjectKind. */ TestSubjectKind test_subject_get_kind (TestSubject *subject) { const gchar *kind_str; TestSubjectKind kind; g_return_val_if_fail (TEST_IS_SUBJECT (subject), TEST_SUBJECT_KIND_UNKNOWN); egg_dbus_structure_get_element (EGG_DBUS_STRUCTURE (subject), 0, &kind_str, -1); if (strcmp (kind_str, "human") == 0) kind = TEST_SUBJECT_KIND_HUMAN; else if (strcmp (kind_str, "cylon") == 0) kind = TEST_SUBJECT_KIND_CYLON; else if (strcmp (kind_str, "deity") == 0) kind = TEST_SUBJECT_KIND_DEITY; else { g_warning ("unknown kind str '%s'", kind_str); kind = TEST_SUBJECT_KIND_UNKNOWN; } return kind; } /** * test_subject_get_name: * @subject: A #TestSubject. * * Gets name of @subject. * * Returns: Name of @subject. **/ const gchar * test_subject_get_name (TestSubject *subject) { EggDBusHashMap *value; EggDBusVariant *variant; const gchar *result; g_return_val_if_fail (TEST_IS_SUBJECT (subject), NULL); egg_dbus_structure_get_element (EGG_DBUS_STRUCTURE (subject), 1, &value, -1); variant = egg_dbus_hash_map_lookup (value, "name"); result = egg_dbus_variant_get_string (variant); return result; } /** * test_subject_get_favorite_food: * @subject: A #TestSubject. * * Gets favorite food of @subject. * * Returns: Favorite food of @subject. **/ const gchar * test_subject_get_favorite_food (TestSubject *subject) { EggDBusHashMap *value; EggDBusVariant *variant; const gchar *result; g_return_val_if_fail (TEST_IS_SUBJECT (subject), NULL); egg_dbus_structure_get_element (EGG_DBUS_STRUCTURE (subject), 1, &value, -1); variant = egg_dbus_hash_map_lookup (value, "favorite-food"); result = egg_dbus_variant_get_string (variant); return result; } /** * test_subject_get_favorite_color: * @subject: A #TestSubject. * * Gets favorite color of @subject. * * Returns: Favorite color of @subject. **/ const gchar * test_subject_get_favorite_color (TestSubject *subject) { EggDBusHashMap *value; EggDBusVariant *variant; const gchar *result; g_return_val_if_fail (TEST_IS_SUBJECT (subject), NULL); egg_dbus_structure_get_element (EGG_DBUS_STRUCTURE (subject), 1, &value, -1); variant = egg_dbus_hash_map_lookup (value, "favorite-color"); result = egg_dbus_variant_get_string (variant); return result; }
It is important, for structural equivalence identification and casting to work, that implementations
only use EggDBusStructure API to construct, store, set and get the element values. While this
constraint makes the implementation slightly more convoluted, it allows extending the TestSubject type
(adding new kinds like Cyborg
and properties like mood
) without
breaking the D-Bus ABI.
Details
EggDBusStructure
typedef struct _EggDBusStructure EggDBusStructure;
The EggDBusStructure structure is an opaque structure and should never be accessed directly.
EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST()
#define EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_CAST(instance, signature, c_type) ((c_type *) egg_dbus_structure_type_check_instance_cast (instance, signature, G_STRINGIFY (c_type)))
Checks that instance
is a EggDBusStructure with signature
and issues a
warning if this is not the case. Returns instance
casted to a pointer
to c_type
.
This macro should only be used in implementations of subclasses of EggDBusStructure.
|
A EggDBusStructure instance. |
|
A D-Bus signature. |
|
A corresponding C type for signature .
|
Returns : |
A pointer to c_type .
|
EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE()
#define EGG_DBUS_STRUCTURE_TYPE_CHECK_INSTANCE_TYPE(instance, signature, c_type) (egg_dbus_structure_type_check_instance_type (instance, signature, G_STRINGIFY (c_type)))
Checks if instance
is a EggDBusStructure with signature
.
This macro should only be used in implementations of subclasses of EggDBusStructure.
|
A EggDBusStructure instance. |
|
A D-Bus signature. |
|
A corresponding C type for signature .
|
Returns : |
TRUE only if instance is a EggDBusStructure with signature .
|
egg_dbus_structure_new ()
EggDBusStructure * egg_dbus_structure_new (const gchar *signature, GValue *elements);
egg_dbus_structure_get_num_elements ()
guint egg_dbus_structure_get_num_elements (EggDBusStructure *structure);
egg_dbus_structure_get_element ()
void egg_dbus_structure_get_element (EggDBusStructure *structure, guint first_structure_element_number, ...);
Gets element values in a EggDBusStructure. The returned values
should not be freed; structure
owns the reference.
|
A EggDBusStructure. |
|
Element number to get. |
|
Return location for the first element, followed optionally by more element number / return location pairs, followed by -1. |
egg_dbus_structure_get_element_valist ()
void egg_dbus_structure_get_element_valist (EggDBusStructure *structure, guint first_structure_element_number, va_list var_args);
Like egg_dbus_structure_get_element()
but intended for use by language
bindings.
|
A EggDBusStructure. |
|
Element number. |
|
Return location for the first element, followed optionally by more element number / return location pairs, followed by -1. |
egg_dbus_structure_get_element_as_gvalue ()
void egg_dbus_structure_get_element_as_gvalue (EggDBusStructure *structure, guint element_number, GValue *value);
Sets value
to the contents of the value of element_number
. This
will also initalize value
so it needs to be uninitialized
(e.g. set to zeroes). Unlike egg_dbus_structure_get_element()
, note
that the value is copied; use g_value_unset()
to free it.
|
A EggDBusStructure. |
|
Element number. |
|
Return location for GValue. |
egg_dbus_structure_set_element ()
void egg_dbus_structure_set_element (EggDBusStructure *structure, guint first_structure_element_number, ...);
Sets element values in a EggDBusStructure. Similar to g_object_set()
.
|
A EggDBusStructure. |
|
Element number to set. |
|
First element to set, followed optionally by more element number / return location pairs, followed by -1. |
egg_dbus_structure_set_element_valist ()
void egg_dbus_structure_set_element_valist (EggDBusStructure *structure, guint first_structure_element_number, va_list var_args);
Like egg_dbus_structure_set_element()
but intended for use by language
bindings.
|
A EggDBusStructure. |
|
Element number. |
|
First element to set, followed optionally by more element number / element pairs, followed by -1. |
egg_dbus_structure_set_element_as_gvalue ()
void egg_dbus_structure_set_element_as_gvalue (EggDBusStructure *structure, guint element_number, const GValue *value);
Sets value
to the contents of the value of element_number
. This
will also initalize value
so it needs to be uninitialized
(e.g. set to zeroes).
|
A EggDBusStructure. |
|
Element number. |
|
Return location for GValue. |
egg_dbus_structure_get_signature ()
const gchar * egg_dbus_structure_get_signature (EggDBusStructure *structure);
egg_dbus_structure_get_signature_for_element ()
const gchar * egg_dbus_structure_get_signature_for_element (EggDBusStructure *structure, guint element_number);
egg_dbus_structure_print ()
void egg_dbus_structure_print (EggDBusStructure *structure, guint indent);
Property Details
The "elemement-signatures"
property
"elemement-signatures" GStrv* : Read
The signatures of the elements of the structure.
The "elements"
property
"elements" gpointer : Write / Construct Only
The elements of the structure as an array of GValue. Takes ownership.
The "num-elemements"
property
"num-elemements" gint : Read
The number of elements in the structure.
Allowed values: >= 0
Default value: 0
The "signature"
property
"signature" gchar* : Read / Write / Construct Only
The signature of the structure.
Default value: NULL