D-Bus

By default, integration exists for D-Bus to connect to a bus, own a name, and perform method calls, asynchronously.

See dex_bus_get(), dex_bus_own_name_on_connection(), dex_dbus_connection_call(), dex_dbus_connection_call_with_unix_fd_list(), dex_dbus_connection_send_message_with_reply() and dex_dbus_connection_close().

Enabling GDBus codegen

Integration with GDBus based codegen can be enabled, by calling gdbus-codegen with --extension-path=path/to/dex-gdbus-codegen-extension.py. The installed file path can be queried via pkgconf --variable=gdbus_codegen_extension libdex-1:

libdex_dep = dependency('libdex-1')

ext = libdex_dep.get_pkgconfig_variable('gdbus_codegen_extension')
dbus_ping_pong = gnome.gdbus_codegen(
  'dex-dbus-ping-pong',
  sources: ['org.example.PingPong.xml'],
  interface_prefix: 'org.example',
  namespace: 'DexDbus',
  extra_args: [f'--extension-path=@ext@'],
)

Proxy Futures

With the GDBus codegen enabled, for every proxy, a ${name}_new_future function is generated in addition to the sync and async/finish variants. The returned future resolves into the proxy object.

  g_autoptr(DexDbusPingPong) *pp = NULL;
  pp = dex_await_object (dex_dbus_ping_pong_proxy_new_future (connection,
                                                              G_DBUS_PROXY_FLAGS_NONE,
                                                              "org.example.PingPong",
                                                              "/org/example/pingpong"),
                         &error);

For every method, a ${name}_call_${method}_future function is generated in addition to the sync and async/finish variants. The returned future resolves into the boxed type ${Name}${Method}Result which contains the results of the call.

  g_autoptr(DexDbusPingPongPingResult) result = NULL;

  result = dex_await_boxed (dex_dbus_ping_pong_call_ping_future (pp, "ping"), &error);
  g_assert (result);
  g_print ("%s\n", result->pong);

For every signal, a ${name}_wait_${signal}_future function is generated. The future gets resolved when the signal got emitted, and the future resolves into the boxed type ${Name}${Signal}Signal which contains the results of the signal emission.

  g_autoptr(DexDbusPingPongReloadingSignal) signal = NULL;

  signal = dex_await_boxed (dex_dbus_ping_pong_wait_reloading_future (pp), &error);
  g_assert (signal);
  g_print ("%s\n", signal->active);

For every Dex.DBusInterfaceSkeleton, a corresponding ${Name}SignalMonitor class is generated. Objects of the class will listen to the specified signals, and a call to `${Name}SignalMonitor::next${signal} returns a future that will resolve either immediately when a signal was emitted previously, or when the next signal arrives. This can be useful when it is important to not miss signal emissions.

  g_autoptr(DexDbusPingPongSignalMonitor) signal_monitor =
    dex_dbus_ping_pong_signal_monitor_new (pp, DEX_DBUS_PING_PONG_SIGNAL_RELOADING);

  signal = dex_await_boxed (dex_dbus_ping_pong_signal_monitor_next_reloading (signal_monitor), &error);
  g_assert (signal);
  g_print ("%s\n", signal->active);

InterfaceSkeleton Fiber Dispatching

With the GDBus codegen enabled, all generated ${Name}Skeletons that application code derives from to implement a service derive from DexDBusInterfaceSkeleton instead of directly from GDBusInterfaceSkeleton. This allows application code to enable handling method invocations in fibers, by setting DEX_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_FIBER with dex_dbus_interface_skeleton_set_flags().

static gboolean
handle_ping (DexDbusPingPong       *object,
             GDBusMethodInvocation *invocation,
             const char            *ping)
{
  g_print ("service: %s\n", ping);

  dex_await (dex_timeout_new_seconds (1), NULL);
  dex_dbus_ping_pong_complete_ping (object, invocation, "pong");

  return G_DBUS_METHOD_INVOCATION_HANDLED;
}

static void
dex_dbus_ping_pong_iface_init (DexDbusPingPongIface *iface)
{
  iface->handle_ping = handle_ping;
}

static DexPingPong *
get_ping_pong (void)
{
  g_autoptr(DexPingPong) pp = NULL;
  pp = g_object_new (DEX_TYPE_PING_PONG, NULL);
  dex_dbus_interface_skeleton_set_flags (DEX_DBUS_INTERFACE_SKELETON (pp),
                                         DEX_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_FIBER);
  return g_steal_pointer (&pp);
}