## EggDBusStructure EggDBusStructure — D-Bus structures |

## 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);

## Object Hierarchy

      GObject
       +----EggDBusStructure

## 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.

`instance` : | A EggDBusStructure instance.
`signature` : | A D-Bus signature.
`c_type` : | 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.

`instance` : | A EggDBusStructure instance.
`signature` : | A D-Bus signature.
`c_type` : | 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.

`structure` : | A EggDBusStructure.
`first_structure_element_number` : | 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.

`structure` : | A EggDBusStructure.
`first_structure_element_number` : | Element number.
`var_args` : | 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.

`structure` : | A EggDBusStructure.
`element_number` : | Element number.
`value` : | 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()`.

`structure` : | A EggDBusStructure.
`first_structure_element_number` : | 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.

`structure` : | A EggDBusStructure.
`first_structure_element_number` : | Element number.
`var_args` : | 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).

`structure` : | A EggDBusStructure.
`element_number` : | Element number.
`value` : | 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