diff --git a/doc/calls-docs.xml b/doc/calls-docs.xml
index 17a8658..f2e6b57 100644
--- a/doc/calls-docs.xml
+++ b/doc/calls-docs.xml
@@ -37,7 +37,6 @@
DBus interfaces
-
diff --git a/src/calls-application.c b/src/calls-application.c
index d040abc..a994ede 100644
--- a/src/calls-application.c
+++ b/src/calls-application.c
@@ -26,6 +26,7 @@
*/
#include "config.h"
+#include "calls-dbus-manager.h"
#include "calls-history-box.h"
#include "calls-new-call-box.h"
#include "calls-encryption-indicator.h"
@@ -65,6 +66,7 @@ struct _CallsApplication
CallsMainWindow *main_window;
CallsCallWindow *call_window;
CallsSettings *settings;
+ CallsDBusManager *dbus_manager;
char *uri;
};
@@ -75,6 +77,39 @@ G_DEFINE_TYPE (CallsApplication, calls_application, GTK_TYPE_APPLICATION);
static gboolean start_proper (CallsApplication *self);
+static gboolean
+calls_application_dbus_register (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error)
+{
+ CallsApplication *self = CALLS_APPLICATION (application);
+
+ G_APPLICATION_CLASS (calls_application_parent_class)->dbus_register (application,
+ connection,
+ object_path,
+ error);
+
+ self->dbus_manager = calls_dbus_manager_new ();
+ return calls_dbus_manager_register (self->dbus_manager, connection, object_path, error);
+}
+
+
+static void
+calls_application_dbus_unregister (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path)
+{
+ CallsApplication *self = CALLS_APPLICATION (application);
+
+ g_clear_object (&self->dbus_manager);
+
+ G_APPLICATION_CLASS (calls_application_parent_class)->dbus_unregister (application,
+ connection,
+ object_path);
+}
+
+
static gint
handle_local_options (GApplication *application,
GVariantDict *options)
@@ -553,6 +588,8 @@ calls_application_class_init (CallsApplicationClass *klass)
application_class->startup = startup;
application_class->activate = activate;
application_class->open = app_open;
+ application_class->dbus_register = calls_application_dbus_register;
+ application_class->dbus_unregister = calls_application_dbus_unregister;
g_type_ensure (CALLS_TYPE_ENCRYPTION_INDICATOR);
g_type_ensure (CALLS_TYPE_HISTORY_BOX);
diff --git a/src/calls-dbus-manager.c b/src/calls-dbus-manager.c
new file mode 100644
index 0000000..9bced16
--- /dev/null
+++ b/src/calls-dbus-manager.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2021 Purism SPC
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Author: Guido Günther
+ */
+
+#define G_LOG_DOMAIN "CallsDBusMmanager"
+
+#include "config.h"
+#include "calls-call.h"
+#include "calls-call-dbus.h"
+#include "calls-dbus-manager.h"
+#include "calls-manager.h"
+
+/**
+ * SECTION:calls-dbus-manager
+ * @short_description: Manages the Call DBus interface
+ * @Title: CallsCallDBusManager
+ *
+ * The #CallsCallManager is responsible for exposing the
+ * call objects on the session bus using #GDBusObjectManager.
+ *
+ * Call objects are exported like /sm/puri/Calls/ as
+ * /sm/puri/Calls/Call/1, /sm/puri/Calls/Call/2, … using
+ * org.freedesktop.DBus.ObjectManager.
+ */
+
+typedef struct _CallsDBusManager {
+ GObject parent;
+
+ GDBusObjectManagerServer *object_manager;
+
+ guint iface_num;
+ GListStore *objs;
+ char *object_path;
+} CallsDBusManager;
+
+
+G_DEFINE_TYPE (CallsDBusManager, calls_dbus_manager, G_TYPE_OBJECT);
+
+static char *
+get_obj_path (CallsDBusManager *self, guint num)
+{
+ return g_strdup_printf ("%s/Call/%u", self->object_path, num);
+}
+
+
+static CallsDBusObjectSkeleton *
+find_call (CallsDBusManager *self, CallsCall *call, int *pos)
+{
+ CallsDBusObjectSkeleton *found = NULL;
+
+ g_return_val_if_fail (CALLS_IS_CALL (call), NULL);
+
+ for (int i = 0; i >= 0; i++) {
+ g_autoptr (CallsDBusObjectSkeleton) item = g_list_model_get_item (G_LIST_MODEL (self->objs), i);
+
+ if (!item)
+ break;
+
+ if (call == g_object_get_data (G_OBJECT (item), "call")) {
+ *pos = i;
+ found = item;
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+static gboolean
+on_handle_call_accept (CallsDBusCallsCall *skeleton,
+ GDBusMethodInvocation *invocation,
+ CallsCall *call)
+{
+ g_return_val_if_fail (CALLS_DBUS_IS_CALLS_CALL (skeleton), FALSE);
+ g_return_val_if_fail (CALLS_IS_CALL (call), FALSE);
+
+ calls_call_answer (call);
+
+ calls_dbus_calls_call_complete_accept (skeleton, invocation);
+ return TRUE;
+}
+
+
+static gboolean
+on_handle_call_hangup (CallsDBusCallsCall *skeleton,
+ GDBusMethodInvocation *invocation,
+ CallsCall *call)
+{
+ g_return_val_if_fail (CALLS_DBUS_IS_CALLS_CALL (skeleton), FALSE);
+ g_return_val_if_fail (CALLS_IS_CALL (call), FALSE);
+
+ calls_call_hang_up (call);
+
+ calls_dbus_calls_call_complete_hangup (skeleton, invocation);
+ return TRUE;
+}
+
+
+static void
+call_added_cb (CallsDBusManager *self, CallsCall *call)
+{
+ g_autofree char *path = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (CallsDBusObjectSkeleton) object = NULL;
+ g_autoptr (CallsDBusCallsCall) iface = NULL;
+
+ path = get_obj_path (self, self->iface_num++);
+ object = calls_dbus_object_skeleton_new (path);
+ iface = calls_dbus_calls_call_skeleton_new ();
+ g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object),
+ G_DBUS_INTERFACE_SKELETON (iface));
+ g_object_set_data_full (G_OBJECT (object), "call", g_object_ref (call), g_object_unref);
+
+ g_object_connect (iface,
+ "object_signal::handle-accept", G_CALLBACK (on_handle_call_accept), call,
+ "object_signal::handle-hangup", G_CALLBACK (on_handle_call_hangup), call,
+ NULL);
+
+ g_object_bind_property (call, "state", iface, "state", G_BINDING_SYNC_CREATE);
+ g_object_bind_property (call, "inbound", iface, "inbound", G_BINDING_SYNC_CREATE);
+ g_object_bind_property (call, "number", iface, "id", G_BINDING_SYNC_CREATE);
+
+ /* Export with properties bound to reduce DBus traffic: */
+ g_debug ("Exporting %p at %s", call, path);
+ g_dbus_object_manager_server_export (self->object_manager, G_DBUS_OBJECT_SKELETON (object));
+
+ g_list_store_append (self->objs, g_steal_pointer (&object));
+}
+
+
+static void
+call_removed_cb (CallsDBusManager *self, CallsCall *call)
+{
+ const char *path = NULL;
+ CallsDBusObjectSkeleton *obj = NULL;
+ gint pos = -1;
+
+ g_debug ("Call %p removed", call);
+
+ obj = find_call (self, call, &pos);
+ g_return_if_fail (CALLS_DBUS_IS_OBJECT (obj));
+
+ path = g_dbus_object_get_object_path (G_DBUS_OBJECT (obj));
+ g_dbus_object_manager_server_unexport (self->object_manager, path);
+
+ g_list_store_remove (self->objs, pos);
+}
+
+
+static void
+calls_dbus_manager_constructed (GObject *object)
+{
+ g_autoptr (GList) calls = NULL;
+ GList *c;
+ CallsDBusManager *self = CALLS_DBUS_MANAGER (object);
+
+ G_OBJECT_CLASS (calls_dbus_manager_parent_class)->constructed (object);
+
+ self->objs = g_list_store_new (CALLS_DBUS_TYPE_OBJECT_SKELETON);
+
+ g_signal_connect_swapped (calls_manager_get_default (),
+ "call-add",
+ G_CALLBACK (call_added_cb),
+ self);
+
+ g_signal_connect_swapped (calls_manager_get_default (),
+ "call-remove",
+ G_CALLBACK (call_removed_cb),
+ self);
+ calls = calls_manager_get_calls (calls_manager_get_default ());
+ for (c = calls; c != NULL; c = c->next) {
+ call_added_cb (self, c->data);
+ }
+}
+
+
+static void
+calls_dbus_manager_dispose (GObject *object)
+{
+ CallsDBusManager *self = CALLS_DBUS_MANAGER (object);
+
+ if (self->objs) {
+ for (int i = 0; i >= 0; i++) {
+ const char *path;
+ g_autoptr (CallsDBusObjectSkeleton) obj = g_list_model_get_item (G_LIST_MODEL (self->objs), i);
+
+ if (!obj)
+ break;
+
+ path = g_dbus_object_get_object_path (G_DBUS_OBJECT (obj));
+ g_dbus_object_manager_server_unexport (self->object_manager, path);
+ }
+ }
+ g_clear_object (&self->objs);
+ g_clear_object (&self->object_manager);
+ g_clear_pointer (&self->object_path, g_free);
+
+ G_OBJECT_CLASS (calls_dbus_manager_parent_class)->dispose (object);
+}
+
+
+static void
+calls_dbus_manager_class_init (CallsDBusManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructed = calls_dbus_manager_constructed;
+ object_class->dispose = calls_dbus_manager_dispose;
+}
+
+
+static void
+calls_dbus_manager_init (CallsDBusManager *self)
+{
+ self->iface_num = 1;
+}
+
+
+CallsDBusManager *
+calls_dbus_manager_new (void)
+{
+ return g_object_new (CALLS_TYPE_DBUS_MANAGER, NULL);
+}
+
+
+gboolean
+calls_dbus_manager_register (CallsDBusManager *self,
+ GDBusConnection *connection,
+ const char *object_path,
+ GError **error)
+{
+ g_return_val_if_fail (CALLS_IS_DBUS_MANAGER (self), FALSE);
+
+ self->object_path = g_strdup (object_path);
+ g_debug ("Registering at %s", self->object_path);
+ self->object_manager = g_dbus_object_manager_server_new (object_path);
+ g_dbus_object_manager_server_set_connection (self->object_manager, connection);
+
+ return TRUE;
+}
diff --git a/src/calls-dbus-manager.h b/src/calls-dbus-manager.h
new file mode 100644
index 0000000..4ecb0d3
--- /dev/null
+++ b/src/calls-dbus-manager.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 Purism SPC
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * Author: Guido Günther
+ */
+
+#pragma once
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define CALLS_TYPE_DBUS_MANAGER calls_dbus_manager_get_type ()
+
+G_DECLARE_FINAL_TYPE (CallsDBusManager, calls_dbus_manager,
+ CALLS, DBUS_MANAGER, GObject)
+
+CallsDBusManager *calls_dbus_manager_new (void);
+gboolean calls_dbus_manager_register (CallsDBusManager *self,
+ GDBusConnection *connection,
+ const char *object_path,
+ GError **error);
+G_END_DECLS
diff --git a/src/dbus/meson.build b/src/dbus/meson.build
index 20084a1..64839f3 100644
--- a/src/dbus/meson.build
+++ b/src/dbus/meson.build
@@ -1,14 +1,9 @@
generated_dbus_sources = []
# DBus server protocols
-generated_dbus_sources += gnome.gdbus_codegen('calls-dbus',
- 'sm.puri.Calls.xml',
- docbook: 'calls',
- interface_prefix: 'sm.puri',
- namespace: 'CallsDBus')
-
generated_dbus_sources += gnome.gdbus_codegen('calls-call-dbus',
'sm.puri.Calls.Call.xml',
docbook: 'calls',
interface_prefix: 'sm.puri',
- namespace: 'CallsCallDBus')
+ object_manager: true,
+ namespace: 'CallsDBus')
diff --git a/src/dbus/sm.puri.Calls.Call.xml b/src/dbus/sm.puri.Calls.Call.xml
index dad19b2..78ecafb 100644
--- a/src/dbus/sm.puri.Calls.Call.xml
+++ b/src/dbus/sm.puri.Calls.Call.xml
@@ -20,17 +20,20 @@
-->
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ The Id identifying the call, e.g. a phone number
+
+
+
+
+
diff --git a/src/dbus/sm.puri.Calls.xml b/src/dbus/sm.puri.Calls.xml
deleted file mode 100644
index 3114502..0000000
--- a/src/dbus/sm.puri.Calls.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- an array of ongoing calls
-
-
-
-
- This gets a list of all Calls
- that are currently ongoing.
- Each Call is an D-Bus object path for the object that implements the
- Call interface.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/meson.build b/src/meson.build
index 7f64721..972f9cc 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -90,6 +90,7 @@ calls_generated_sources = [
calls_sources = files(['calls-message-source.c', 'calls-message-source.h',
'calls-call.c',
+ 'calls-dbus-manager.c',
'calls-ussd.c',
'calls-origin.c', 'calls-origin.h',
'calls-provider.c', 'calls-provider.h',