From 6f93b48ef44b27e50e12b0e0958a5eb25a20f0f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Fri, 2 Apr 2021 09:52:14 +0200 Subject: [PATCH] Expose call objects on DBus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This exports call objects on the session bus: $ gdbus monitor --session -d sm.puri.Calls … /sm/puri/Calls: org.freedesktop.DBus.ObjectManager.InterfacesAdded (objectpath '/sm/puri/Calls/Call/1', {'sm.puri.Calls.Call': {'Inbound': , 'State': , 'Id': <''>, 'Party': <''>}}) /sm/puri/Calls/Call/1: org.freedesktop.DBus.Properties.PropertiesChanged ('sm.puri.Calls.Call', {'Id': <'0987654321'>, 'Inbound': , 'State': }, @as []) /sm/puri/Calls: org.freedesktop.DBus.ObjectManager.InterfacesRemoved (objectpath '/sm/puri/Calls/Call/1', ['sm.puri.Calls.Call']) $ gdbus call --session --dest sm.puri.Calls --object-path /sm/puri/Calls/Call/1 --method sm.puri.Calls.Call.Hangup Currenty hangup and accept methods are implemented as well as exposing the current call state. --- doc/calls-docs.xml | 1 - src/calls-application.c | 37 +++++ src/calls-dbus-manager.c | 245 ++++++++++++++++++++++++++++++++ src/calls-dbus-manager.h | 26 ++++ src/dbus/meson.build | 9 +- src/dbus/sm.puri.Calls.Call.xml | 25 ++-- src/dbus/sm.puri.Calls.xml | 53 ------- src/meson.build | 1 + 8 files changed, 325 insertions(+), 72 deletions(-) create mode 100644 src/calls-dbus-manager.c create mode 100644 src/calls-dbus-manager.h delete mode 100644 src/dbus/sm.puri.Calls.xml 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',