# Migrating to GDBus

## Conceptual differences

The central concepts of D-Bus are modelled in a very similar way in dbus-glib and GDBus. Both have a objects representing connections, proxies and method invocations. But there are some important differences:

- dbus-glib uses libdbus, GDBus doesn't. Instead, it relies on GIO streams as transport layer, and has its own implementation for the the D-Bus connection setup and authentication. Apart from using streams as transport, avoiding libdbus also lets GDBus avoid some thorny multithreading issues.

- dbus-glib uses the GObject type system for method arguments and return values, including a homegrown container specialization mechanism. GDBus relies uses the #GVariant type system which is explicitly designed to match D-Bus types.

- The typical way to export an object in dbus-glib involves generating glue code from XML introspection data using `dbus-binding-tool`. GDBus does not (yet?) use code generation; you are expected to embed the introspection data in your application code.

## API comparison

### dbus-glib APIs and their GDBus counterparts

dbus-glib | GDBus
--- | ---
#DBusGConnection | #GDBusConnection
#DBusGProxy | #GDBusProxy
#DBusGMethodInvocation | #GDBusMethodInvocation
dbus_g_bus_get() | g_bus_get_sync(), also see g_bus_get()
dbus_g_proxy_new_for_name() | g_dbus_proxy_new_sync() and g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()
dbus_g_proxy_add_signal() | not needed, use the generic #GDBusProxy::g-signal
dbus_g_proxy_connect_signal() | use g_signal_connect() with #GDBusProxy::g-signal
dbus_g_connection_register_g_object() | g_dbus_connection_register_object()
dbus_g_connection_unregister_g_object() | g_dbus_connection_unregister_object()
dbus_g_object_type_install_info() | introspection data is installed while registering an object, see g_dbus_connection_register_object()
dbus_g_proxy_begin_call() | g_dbus_proxy_call()
dbus_g_proxy_end_call() | g_dbus_proxy_call_finish()
dbus_g_proxy_call() | g_dbus_proxy_call_sync()
dbus_g_error_domain_register() | g_dbus_error_register_error_domain()
dbus_g_error_has_name() | no direct equivalent, see g_dbus_error_get_remote_error()
dbus_g_method_return() | g_dbus_method_invocation_return_value()
dbus_g_method_return_error() | g_dbus_method_invocation_return_error() and variants
dbus_g_method_get_sender() | g_dbus_method_invocation_get_sender()

## Owning bus names

Using dbus-glib, you typically call RequestName manually to own a name, like in the following excerpt:

      error = NULL;
      res = dbus_g_proxy_call (system_bus_proxy,
                               "RequestName",
                               &error,
                               G_TYPE_STRING, NAME_TO_CLAIM,
                               G_TYPE_UINT,   DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
                               G_TYPE_INVALID,
                               G_TYPE_UINT,   &result,
                               G_TYPE_INVALID);
      if (!res)
        {
          if (error != NULL)
            {
              g_warning ("Failed to acquire %s: %s",
                         NAME_TO_CLAIM, error->message);
              g_error_free (error);
            }
          else
            {
              g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
            }
          goto out;
        }

      if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
        {
          if (error != NULL)
            {
              g_warning ("Failed to acquire %s: %s",
                         NAME_TO_CLAIM, error->message);
              g_error_free (error);
            }
          else
            {
              g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
            }
          exit (1);
        }

      dbus_g_proxy_add_signal (system_bus_proxy, "NameLost",
                               G_TYPE_STRING, G_TYPE_INVALID);
      dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost",
                                   G_CALLBACK (on_name_lost), NULL, NULL);

      /* further setup ... */

While you can do things this way with GDBus too, using g_dbus_proxy_call_sync(), it is much nicer to use the high-level API for this:

    static void
    on_name_acquired (GDBusConnection *connection,
                      const gchar     *name,
                      gpointer         user_data)
    {
      /* further setup ... */
    }

    /* ... */

      owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
                                 NAME_TO_CLAIM,
                                 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
                                 on_bus_acquired,
                                 on_name_acquired,
                                 on_name_lost,
                                 NULL,
                                 NULL);

      g_main_loop_run (loop);

      g_bus_unown_name (owner_id);

Note that g_bus_own_name() works asynchronously and requires you to enter your mainloop to await the on_name_aquired() callback. Also note that in order to avoid race conditions (e.g. when your service is activated by a method call), you have to export your manager object before acquiring the name. The on_bus_acquired() callback is the right place to do such preparations.

## Creating proxies for well-known names

dbus-glib lets you create proxy objects for well-known names, like the following example:

      proxy = dbus_g_proxy_new_for_name (system_bus_connection,
                                         "org.freedesktop.Accounts",
                                         "/org/freedesktop/Accounts",
                                         "org.freedesktop.Accounts");

For a #DBusGProxy constructed like this, method calls will be sent to the current owner of the name, and that owner can change over time.

The same can be achieved with #GDBusProxy:

      error = NULL;
      proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
                                             G_DBUS_PROXY_FLAGS_NONE,
                                             NULL, /* GDBusInterfaceInfo */
                                             "org.freedesktop.Accounts",
                                             "/org/freedesktop/Accounts",
                                             "org.freedesktop.Accounts",
                                             NULL, /* GCancellable */
                                             &error);

For an added layer of safety, you can specify what D-Bus interface the proxy is expected to conform to by using the #GDBusInterfaceInfo type.

Additionally, #GDBusProxy loads, caches and tracks changes to the D-Bus properties on the remote object. It also sets up match rules so D-Bus signals from the remote object are delivered locally.

## Client-side GObject bindings

dbus-glib comes with `dbus-binding-tool`, which can produce somewhat nice client-side wrappers for a D-Bus interface. GDBus does not have code-generation at this point, but #GDBusProxy is designed to allow the creating of client-side wrappers by subclassing #GDBusProxy.

For an example of a #GDBusProxy-derived class that wraps a D-Bus interface in a type-safe way, see . The comparison is as follows:

### Wrapping the org.freedesktop.Accounts.User D-Bus interface in the AccountUser GObject type

D-Bus concept | GObject concept
--- | ---
AutomaticLogin property | `AccountsUser:automatic-login` GObject property C getter: accounts_user_get_automatic_login() Watch changes via the `notify::automatic-login` signal
RealName property | `AccountsUser:real-name` GObject property C getter: accounts_user_get_real_name() Watch changes via the `notify::real-name signal`
UserName property | `AccountsUser:user-name` GObject property C getter: accounts_user_get_user_name() Watch changes via the `notify::user-name` signal
Changed signal | `AccountsUser::changed` GObject signal Watch via e.g. g_signal_connect()
Frobnicate method | Use accounts_user_frobnicate() + accounts_user_frobnicate_finish() or accounts_user_frobnicate_sync() to invoke

### GDBusProxy subclass example

    FIXME: MISSING XINCLUDE CONTENT

## Exporting objects

With dbus-glib, exporting an object over D-Bus works by generating a bunch of glue code from your introspection XML with `dbus-binding-tool`. The glue code gets included in your source, and you need to call

      dbus_g_object_type_install_info (TYPE_MYOBJECT,
                                       &dbus_glib_myobject_object_info);

in your class_init() function to tell dbus-glib about your type. To actually export an instance, you call

      dbus_g_connection_register_g_object (system_bus_connection,
                                           my_object_path,
                                           G_OBJECT (my_object));

The GDBus way of exporting an object works by embedding the introspection XML in the source, creating introspection data structures from it with g_dbus_node_info_new_for_xml(), and passing that along when you register the object:

      static const gchar introspection_xml[] =
        "<node>"
        "  <interface name='org.gtk.GDBus.TestPeerInterface'>"
        "    <method name='HelloWorld'>"
        "      <arg type='s' name='greeting' direction='in'/>"
        "      <arg type='s' name='response' direction='out'/>"
        "    </method>"
        "  </interface>"
        "</node>";

      /* parse introspection data */
      introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);

      /
      id = g_dbus_connection_register_object (connection,
                                              "/org/gtk/GDBus/TestObject",
                                              "org.gtk.GDBus.TestPeerInterface",
                                              introspection_data->interfaces[0],
                                              &interface_vtable,
                                              NULL,  /* user_data */
                                              NULL,  /* user_data_free_func */
                                              NULL); /* GError** */

The actual implementation of the exported object is done by specifying a #GDBusInterfaceVTable that has method_call(), get_property() and set_property() methods. There is no direct support beyond that for exporting #GObjects, so there is quite a bit of manual work involved, as you can see in the following example.

Since the VTable methods don't have any direct #GObject support, we pass the exported object as @user_data. Also note that we have to handle the emission of the PropertiesChanged signal ourselves, by connecting to ::notify.

### Exporting a GObject

    FIXME: MISSING XINCLUDE CONTENT