From 460c0c6c3d1666e80af268a4a49d37a8887acba1 Mon Sep 17 00:00:00 2001 From: Bob Ham Date: Fri, 23 Nov 2018 14:34:41 +0000 Subject: [PATCH] Turn providers into plugins courtesy of libpeas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an initial, static implementation of plugins. The CallsApplication has a plugin name which can be changed with a new --provider command line option. This plugin name is used to instantiate the appropriate plugin when the application is activated. From then on, the plugin cannot change. In future, we can expand this support to include loading multiple plugins at once, configurable through some UI. This will have far-reaching implications though, and complicate things like enumerating the provider hierarchy. There is also no practical benefit right now; the mm and ofono plugins can't be used at the same time because ModemManager and oFono don't play nice together, and the whole raison d'ĂȘtre of the dummy plugin is undermined if you can make use of one of the others. So for now, we just implement one static plugin. --- debian/control | 1 + libgdbofono/meson.build | 19 -- meson.build | 35 +- {src => plugins/dummy}/calls-dummy-call.c | 0 {src => plugins/dummy}/calls-dummy-call.h | 0 {src => plugins/dummy}/calls-dummy-origin.c | 0 {src => plugins/dummy}/calls-dummy-origin.h | 0 {src => plugins/dummy}/calls-dummy-provider.c | 69 +++- {src => plugins/dummy}/calls-dummy-provider.h | 0 plugins/dummy/dummy.plugin.in | 7 + plugins/dummy/meson.build | 56 ++++ plugins/meson.build | 3 + {src => plugins/mm}/calls-mm-call.c | 0 {src => plugins/mm}/calls-mm-call.h | 0 {src => plugins/mm}/calls-mm-origin.c | 0 {src => plugins/mm}/calls-mm-origin.h | 0 {src => plugins/mm}/calls-mm-provider.c | 28 +- {src => plugins/mm}/calls-mm-provider.h | 2 - plugins/mm/meson.build | 56 ++++ plugins/mm/mm.plugin.in | 7 + {src => plugins/ofono}/calls-ofono-call.c | 0 {src => plugins/ofono}/calls-ofono-call.h | 0 {src => plugins/ofono}/calls-ofono-origin.c | 0 {src => plugins/ofono}/calls-ofono-origin.h | 0 {src => plugins/ofono}/calls-ofono-provider.c | 102 +++--- {src => plugins/ofono}/calls-ofono-provider.h | 2 - .../ofono/libgdbofono}/call.xml | 0 .../ofono/libgdbofono}/dbus-introspect.sh | 0 .../ofono/libgdbofono}/manager.xml | 0 plugins/ofono/libgdbofono/meson.build | 51 +++ .../ofono/libgdbofono}/modem-full.xml | 0 .../ofono/libgdbofono}/modem.xml | 0 plugins/ofono/meson.build | 60 ++++ plugins/ofono/ofono.plugin.in | 7 + src/calls-application.c | 299 +++++++++++++++--- src/meson.build | 30 +- tests/meson.build | 10 +- tests/setup-origin.h | 2 +- tests/test-provider.c | 7 +- 39 files changed, 672 insertions(+), 181 deletions(-) delete mode 100644 libgdbofono/meson.build rename {src => plugins/dummy}/calls-dummy-call.c (100%) rename {src => plugins/dummy}/calls-dummy-call.h (100%) rename {src => plugins/dummy}/calls-dummy-origin.c (100%) rename {src => plugins/dummy}/calls-dummy-origin.h (100%) rename {src => plugins/dummy}/calls-dummy-provider.c (66%) rename {src => plugins/dummy}/calls-dummy-provider.h (100%) create mode 100644 plugins/dummy/dummy.plugin.in create mode 100644 plugins/dummy/meson.build create mode 100644 plugins/meson.build rename {src => plugins/mm}/calls-mm-call.c (100%) rename {src => plugins/mm}/calls-mm-call.h (100%) rename {src => plugins/mm}/calls-mm-origin.c (100%) rename {src => plugins/mm}/calls-mm-origin.h (100%) rename {src => plugins/mm}/calls-mm-provider.c (93%) rename {src => plugins/mm}/calls-mm-provider.h (96%) create mode 100644 plugins/mm/meson.build create mode 100644 plugins/mm/mm.plugin.in rename {src => plugins/ofono}/calls-ofono-call.c (100%) rename {src => plugins/ofono}/calls-ofono-call.h (100%) rename {src => plugins/ofono}/calls-ofono-origin.c (100%) rename {src => plugins/ofono}/calls-ofono-origin.h (100%) rename {src => plugins/ofono}/calls-ofono-provider.c (86%) rename {src => plugins/ofono}/calls-ofono-provider.h (93%) rename {libgdbofono => plugins/ofono/libgdbofono}/call.xml (100%) rename {libgdbofono => plugins/ofono/libgdbofono}/dbus-introspect.sh (100%) rename {libgdbofono => plugins/ofono/libgdbofono}/manager.xml (100%) create mode 100644 plugins/ofono/libgdbofono/meson.build rename {libgdbofono => plugins/ofono/libgdbofono}/modem-full.xml (100%) rename {libgdbofono => plugins/ofono/libgdbofono}/modem.xml (100%) create mode 100644 plugins/ofono/meson.build create mode 100644 plugins/ofono/ofono.plugin.in diff --git a/debian/control b/debian/control index fe6c6bf..b3f3bac 100644 --- a/debian/control +++ b/debian/control @@ -9,6 +9,7 @@ Build-Depends: modemmanager-dev, libmm-glib-dev, libgsound-dev, + libpeas-dev, meson, pkg-config, # to run the tests diff --git a/libgdbofono/meson.build b/libgdbofono/meson.build deleted file mode 100644 index 44eac5d..0000000 --- a/libgdbofono/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -gnome = import('gnome') -dbus_interfaces = ['manager', 'modem', 'call'] - -gdbus_src = [] -foreach iface: dbus_interfaces - gdbus_src += gnome.gdbus_codegen('gdbo-' + iface, - iface + '.xml', - interface_prefix: 'org.ofono.', - namespace: 'GDBO') -endforeach - -deps = [ dependency('gio-2.0'), - dependency('gio-unix-2.0'), - ] - -gdbofono_lib = static_library('gdbofono', - gdbus_src, - include_directories : include_directories('..'), - dependencies : deps ) diff --git a/meson.build b/meson.build index 4932b31..9e9a5cd 100644 --- a/meson.build +++ b/meson.build @@ -19,11 +19,17 @@ # SPDX-License-Identifier: GPL-3.0-or-later # -project('call', 'c', - version: '0.0.0', - license: 'GPLv3+', - meson_version: '>= 0.42.0', - default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ], +project( + 'calls', + 'c', + version: '0.0.0', + license: 'GPLv3+', + meson_version: '>= 0.46.0', + default_options: [ + 'warning_level=1', + 'buildtype=debugoptimized', + 'c_std=gnu11' + ] ) calls_id = 'sm.puri.Calls' @@ -31,9 +37,26 @@ calls_homepage = 'https://source.puri.sm/Librem5/calls' calls_name = meson.project_name() calls_version = meson.project_version() -subdir('libgdbofono') +top_include = include_directories('.') + +prefix = get_option('prefix') +libdir = get_option('libdir') +localedir = get_option('localedir') +full_localedir = join_paths(prefix, localedir) +full_calls_plugin_libdir = join_paths(prefix, libdir, calls_name, 'plugins') + +config_data = configuration_data() +config_data.set_quoted('APP_ID', calls_id) +config_data.set_quoted('GETTEXT_PACKAGE', calls_name) +config_data.set_quoted('LOCALEDIR', full_localedir) +config_data.set_quoted('PLUGIN_LIBDIR', full_calls_plugin_libdir) +config_data.set_quoted('PACKAGE_URL', calls_homepage) +config_data.set_quoted('PACKAGE_VERSION', calls_version) +config_data.set('PACKAGE_URL_RAW', calls_homepage) + subdir('po') subdir('src') +subdir('plugins') subdir('doc') subdir('data') subdir('tests') diff --git a/src/calls-dummy-call.c b/plugins/dummy/calls-dummy-call.c similarity index 100% rename from src/calls-dummy-call.c rename to plugins/dummy/calls-dummy-call.c diff --git a/src/calls-dummy-call.h b/plugins/dummy/calls-dummy-call.h similarity index 100% rename from src/calls-dummy-call.h rename to plugins/dummy/calls-dummy-call.h diff --git a/src/calls-dummy-origin.c b/plugins/dummy/calls-dummy-origin.c similarity index 100% rename from src/calls-dummy-origin.c rename to plugins/dummy/calls-dummy-origin.c diff --git a/src/calls-dummy-origin.h b/plugins/dummy/calls-dummy-origin.h similarity index 100% rename from src/calls-dummy-origin.h rename to plugins/dummy/calls-dummy-origin.h diff --git a/src/calls-dummy-provider.c b/plugins/dummy/calls-dummy-provider.c similarity index 66% rename from src/calls-dummy-provider.c rename to plugins/dummy/calls-dummy-provider.c index 890d468..cce29ef 100644 --- a/src/calls-dummy-provider.c +++ b/plugins/dummy/calls-dummy-provider.c @@ -27,6 +27,9 @@ #include "calls-provider.h" #include "calls-dummy-origin.h" +#include + + struct _CallsDummyProvider { GObject parent_instance; @@ -37,12 +40,26 @@ struct _CallsDummyProvider static void calls_dummy_provider_message_source_interface_init (CallsProviderInterface *iface); static void calls_dummy_provider_provider_interface_init (CallsProviderInterface *iface); -G_DEFINE_TYPE_WITH_CODE (CallsDummyProvider, calls_dummy_provider, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, - calls_dummy_provider_message_source_interface_init) - G_IMPLEMENT_INTERFACE (CALLS_TYPE_PROVIDER, - calls_dummy_provider_provider_interface_init)) +#ifdef FOR_TESTING + +G_DEFINE_TYPE_WITH_CODE +(CallsDummyProvider, calls_dummy_provider, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, + calls_dummy_provider_message_source_interface_init) + G_IMPLEMENT_INTERFACE (CALLS_TYPE_PROVIDER, + calls_dummy_provider_provider_interface_init)) + +#else + +G_DEFINE_DYNAMIC_TYPE_EXTENDED +(CallsDummyProvider, calls_dummy_provider, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_MESSAGE_SOURCE, + calls_dummy_provider_message_source_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_PROVIDER, + calls_dummy_provider_provider_interface_init)) + +#endif /* FOR_TESTING */ enum { PROP_0, @@ -65,10 +82,15 @@ get_origins (CallsProvider *iface) } -CallsDummyProvider * -calls_dummy_provider_new () +static void +constructed (GObject *object) { - return g_object_new (CALLS_TYPE_DUMMY_PROVIDER, NULL); + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + CallsDummyProvider *self = CALLS_DUMMY_PROVIDER (object); + + calls_dummy_provider_add_origin (self, "Dummy origin"); + + parent_class->constructed (object); } @@ -108,8 +130,9 @@ calls_dummy_provider_class_init (CallsDummyProviderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->dispose = dispose; + object_class->constructed = constructed; object_class->get_property = get_property; + object_class->dispose = dispose; g_object_class_override_property (object_class, PROP_STATUS, "status"); } @@ -142,3 +165,31 @@ calls_dummy_provider_add_origin (CallsDummyProvider *self, self->origins = g_list_append (self->origins, calls_dummy_origin_new (name)); } + + +CallsDummyProvider * +calls_dummy_provider_new () +{ + return g_object_new (CALLS_TYPE_DUMMY_PROVIDER, NULL); +} + + +#ifndef FOR_TESTING + +static void +calls_dummy_provider_class_finalize (CallsDummyProviderClass *klass) +{ +} + + +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) +{ + calls_dummy_provider_register_type (G_TYPE_MODULE (module)); + + peas_object_module_register_extension_type (module, + CALLS_TYPE_PROVIDER, + CALLS_TYPE_DUMMY_PROVIDER); +} + +#endif /* FOR_TESTING */ diff --git a/src/calls-dummy-provider.h b/plugins/dummy/calls-dummy-provider.h similarity index 100% rename from src/calls-dummy-provider.h rename to plugins/dummy/calls-dummy-provider.h diff --git a/plugins/dummy/dummy.plugin.in b/plugins/dummy/dummy.plugin.in new file mode 100644 index 0000000..57d3952 --- /dev/null +++ b/plugins/dummy/dummy.plugin.in @@ -0,0 +1,7 @@ +[Plugin] +Module=dummy +Name=Dummy +Description=Dummy calls provider +Authors=Bob Ham +Copyright=Copyright (C) 2018 Purism SPC +Website=@PACKAGE_URL_RAW@ diff --git a/plugins/dummy/meson.build b/plugins/dummy/meson.build new file mode 100644 index 0000000..2ae87f8 --- /dev/null +++ b/plugins/dummy/meson.build @@ -0,0 +1,56 @@ +# +# Copyright (C) 2018 Purism SPC +# +# This file is part of Calls. +# +# Calls is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Calls 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Calls. If not, see . +# +# Author: Bob Ham +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +dummy_include = include_directories('.') + +dummy_install_dir = join_paths(full_calls_plugin_libdir, 'dummy') + +dummy_plugin = configure_file( + input: 'dummy.plugin.in', + output: 'dummy.plugin', + configuration: config_data, + install_dir: dummy_install_dir +) + +dummy_deps = [ + dependency('gobject-2.0'), + dependency('gtk+-3.0'), + dependency('libpeas-1.0'), +] + +dummy_sources = files( + [ + 'calls-dummy-call.c', 'calls-dummy-call.h', + 'calls-dummy-origin.c', 'calls-dummy-origin.h', + 'calls-dummy-provider.c', 'calls-dummy-provider.h' + ] +) + +shared_module( + 'dummy', + dummy_sources, + dependencies: dummy_deps, + include_directories: src_include, + install: true, + install_dir: dummy_install_dir +) diff --git a/plugins/meson.build b/plugins/meson.build new file mode 100644 index 0000000..d41741b --- /dev/null +++ b/plugins/meson.build @@ -0,0 +1,3 @@ +subdir('mm') +subdir('dummy') +subdir('ofono') diff --git a/src/calls-mm-call.c b/plugins/mm/calls-mm-call.c similarity index 100% rename from src/calls-mm-call.c rename to plugins/mm/calls-mm-call.c diff --git a/src/calls-mm-call.h b/plugins/mm/calls-mm-call.h similarity index 100% rename from src/calls-mm-call.h rename to plugins/mm/calls-mm-call.h diff --git a/src/calls-mm-origin.c b/plugins/mm/calls-mm-origin.c similarity index 100% rename from src/calls-mm-origin.c rename to plugins/mm/calls-mm-origin.c diff --git a/src/calls-mm-origin.h b/plugins/mm/calls-mm-origin.h similarity index 100% rename from src/calls-mm-origin.h rename to plugins/mm/calls-mm-origin.h diff --git a/src/calls-mm-provider.c b/plugins/mm/calls-mm-provider.c similarity index 93% rename from src/calls-mm-provider.c rename to plugins/mm/calls-mm-provider.c index 39623be..db18150 100644 --- a/src/calls-mm-provider.c +++ b/plugins/mm/calls-mm-provider.c @@ -29,6 +29,7 @@ #include "calls-origin.h" #include +#include #include struct _CallsMMProvider @@ -48,11 +49,13 @@ struct _CallsMMProvider static void calls_mm_provider_message_source_interface_init (CallsProviderInterface *iface); static void calls_mm_provider_provider_interface_init (CallsProviderInterface *iface); -G_DEFINE_TYPE_WITH_CODE (CallsMMProvider, calls_mm_provider, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, - calls_mm_provider_message_source_interface_init) - G_IMPLEMENT_INTERFACE (CALLS_TYPE_PROVIDER, - calls_mm_provider_provider_interface_init)) +G_DEFINE_DYNAMIC_TYPE_EXTENDED +(CallsMMProvider, calls_mm_provider, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_MESSAGE_SOURCE, + calls_mm_provider_message_source_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_PROVIDER, + calls_mm_provider_provider_interface_init)) + enum { PROP_0, @@ -436,6 +439,11 @@ calls_mm_provider_class_init (CallsMMProviderClass *klass) } +static void +calls_mm_provider_class_finalize (CallsMMProviderClass *klass) +{ +} + static void calls_mm_provider_message_source_interface_init (CallsProviderInterface *iface) { @@ -459,8 +467,12 @@ calls_mm_provider_init (CallsMMProvider *self) } -CallsMMProvider * -calls_mm_provider_new () +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) { - return g_object_new (CALLS_TYPE_MM_PROVIDER, NULL); + calls_mm_provider_register_type (G_TYPE_MODULE (module)); + + peas_object_module_register_extension_type (module, + CALLS_TYPE_PROVIDER, + CALLS_TYPE_MM_PROVIDER); } diff --git a/src/calls-mm-provider.h b/plugins/mm/calls-mm-provider.h similarity index 96% rename from src/calls-mm-provider.h rename to plugins/mm/calls-mm-provider.h index 538fcc3..12d871a 100644 --- a/src/calls-mm-provider.h +++ b/plugins/mm/calls-mm-provider.h @@ -34,8 +34,6 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (CallsMMProvider, calls_mm_provider, CALLS, MM_PROVIDER, GObject); -CallsMMProvider *calls_mm_provider_new (); - G_END_DECLS #endif /* CALLS_MM_PROVIDER_H__ */ diff --git a/plugins/mm/meson.build b/plugins/mm/meson.build new file mode 100644 index 0000000..37d588c --- /dev/null +++ b/plugins/mm/meson.build @@ -0,0 +1,56 @@ +# +# Copyright (C) 2018 Purism SPC +# +# This file is part of Calls. +# +# Calls is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Calls 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Calls. If not, see . +# +# Author: Bob Ham +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +mm_install_dir = join_paths(full_calls_plugin_libdir, 'mm') + +mm_plugin = configure_file( + input: 'mm.plugin.in', + output: 'mm.plugin', + configuration: config_data, + install_dir: mm_install_dir +) + +mm_deps = [ + dependency('gobject-2.0'), + dependency('gtk+-3.0'), + dependency('ModemManager'), + dependency('mm-glib'), + dependency('libpeas-1.0'), +] + +mm_sources = files( + [ + 'calls-mm-call.c', 'calls-mm-call.h', + 'calls-mm-origin.c', 'calls-mm-origin.h', + 'calls-mm-provider.c', 'calls-mm-provider.h' + ] +) + +shared_module( + 'mm', + mm_sources, + dependencies: mm_deps, + include_directories: src_include, + install: true, + install_dir: mm_install_dir +) diff --git a/plugins/mm/mm.plugin.in b/plugins/mm/mm.plugin.in new file mode 100644 index 0000000..1a1a724 --- /dev/null +++ b/plugins/mm/mm.plugin.in @@ -0,0 +1,7 @@ +[Plugin] +Module=mm +Name=ModemManager +Description=ModemManager calls provider +Authors=Bob Ham +Copyright=Copyright (C) 2018 Purism SPC +Website=@PACKAGE_URL_RAW@ diff --git a/src/calls-ofono-call.c b/plugins/ofono/calls-ofono-call.c similarity index 100% rename from src/calls-ofono-call.c rename to plugins/ofono/calls-ofono-call.c diff --git a/src/calls-ofono-call.h b/plugins/ofono/calls-ofono-call.h similarity index 100% rename from src/calls-ofono-call.h rename to plugins/ofono/calls-ofono-call.h diff --git a/src/calls-ofono-origin.c b/plugins/ofono/calls-ofono-origin.c similarity index 100% rename from src/calls-ofono-origin.c rename to plugins/ofono/calls-ofono-origin.c diff --git a/src/calls-ofono-origin.h b/plugins/ofono/calls-ofono-origin.h similarity index 100% rename from src/calls-ofono-origin.h rename to plugins/ofono/calls-ofono-origin.h diff --git a/src/calls-ofono-provider.c b/plugins/ofono/calls-ofono-provider.c similarity index 86% rename from src/calls-ofono-provider.c rename to plugins/ofono/calls-ofono-provider.c index 6971b4b..383fb64 100644 --- a/src/calls-ofono-provider.c +++ b/plugins/ofono/calls-ofono-provider.c @@ -32,6 +32,8 @@ #include #include +#include + struct _CallsOfonoProvider { @@ -47,21 +49,17 @@ struct _CallsOfonoProvider GHashTable *origins; }; + static void calls_ofono_provider_message_source_interface_init (CallsProviderInterface *iface); static void calls_ofono_provider_provider_interface_init (CallsProviderInterface *iface); -G_DEFINE_TYPE_WITH_CODE (CallsOfonoProvider, calls_ofono_provider, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, - calls_ofono_provider_message_source_interface_init) - G_IMPLEMENT_INTERFACE (CALLS_TYPE_PROVIDER, - calls_ofono_provider_provider_interface_init)) -enum { - PROP_0, - PROP_CONNECTION, - PROP_LAST_PROP, -}; -static GParamSpec *props[PROP_LAST_PROP]; +G_DEFINE_DYNAMIC_TYPE_EXTENDED +(CallsOfonoProvider, calls_ofono_provider, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_MESSAGE_SOURCE, + calls_ofono_provider_message_source_interface_init) + G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_PROVIDER, + calls_ofono_provider_provider_interface_init)) static const gchar * @@ -70,6 +68,7 @@ get_name (CallsProvider *iface) return "oFono"; } + static void add_origin_to_list (const gchar *path, CallsOfonoOrigin *origin, @@ -78,6 +77,7 @@ add_origin_to_list (const gchar *path, *list = g_list_prepend (*list, origin); } + static GList * get_origins (CallsProvider *iface) { @@ -90,36 +90,6 @@ get_origins (CallsProvider *iface) return g_list_reverse (list); } -CallsOfonoProvider * -calls_ofono_provider_new (GDBusConnection *connection) -{ - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); - - return g_object_new (CALLS_TYPE_OFONO_PROVIDER, - "connection", connection, - NULL); -} - - -static void -set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - CallsOfonoProvider *self = CALLS_OFONO_PROVIDER (object); - - switch (property_id) { - case PROP_CONNECTION: - g_set_object (&self->connection, - g_value_get_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} static void add_origin (CallsOfonoProvider *self, @@ -137,6 +107,7 @@ add_origin (CallsOfonoProvider *self, "origin-added", origin); } + static void remove_origin (CallsOfonoProvider *self, const gchar *path, @@ -151,6 +122,7 @@ remove_origin (CallsOfonoProvider *self, g_object_unref (origin); } + static gboolean object_array_includes (GVariantIter *iter, const gchar *needle) @@ -170,6 +142,7 @@ object_array_includes (GVariantIter *iter, return found; } + static void modem_check_ifaces (CallsOfonoProvider *self, GDBOModem *modem, @@ -199,6 +172,7 @@ modem_check_ifaces (CallsOfonoProvider *self, } } + static void modem_property_changed_cb (GDBOModem *modem, const gchar *name, @@ -220,6 +194,7 @@ modem_property_changed_cb (GDBOModem *modem, modem_check_ifaces (self, modem, modem_name, value); } + struct CallsModemProxyNewData { CallsOfonoProvider *self; @@ -227,6 +202,7 @@ struct CallsModemProxyNewData GVariant *ifaces; }; + static void modem_proxy_new_cb (GDBusConnection *connection, GAsyncResult *res, @@ -274,6 +250,7 @@ modem_proxy_new_cb (GDBusConnection *connection, g_debug ("Modem `%s' added", path); } + static gchar * modem_properties_get_name (GVariant *properties) { @@ -297,6 +274,7 @@ modem_properties_get_name (GVariant *properties) return NULL; } + static void modem_added_cb (GDBOManager *manager, const gchar *path, @@ -336,6 +314,7 @@ modem_added_cb (GDBOManager *manager, g_debug ("Modem `%s' addition in progress", path); } + static void modem_removed_cb (GDBOManager *manager, const gchar *path, @@ -405,6 +384,13 @@ constructed (GObject *object) CallsOfonoProvider *self = CALLS_OFONO_PROVIDER (object); GError *error = NULL; + self->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!self->connection) + { + g_error ("Error creating D-Bus connection: %s", + error->message); + } + self->manager = gdbo_manager_proxy_new_sync (self->connection, G_DBUS_PROXY_FLAGS_NONE, @@ -416,7 +402,6 @@ constructed (GObject *object) { g_error ("Error creating ModemManager object manager proxy: %s", error->message); - return; } g_signal_connect (self->manager, "modem-added", @@ -440,14 +425,13 @@ dispose (GObject *object) GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); CallsOfonoProvider *self = CALLS_OFONO_PROVIDER (object); - // FIXME - g_clear_object (&self->manager); g_clear_object (&self->connection); parent_class->dispose (object); } + static void finalize (GObject *object) { @@ -466,26 +450,24 @@ calls_ofono_provider_class_init (CallsOfonoProviderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; object_class->finalize = finalize; - - props[PROP_CONNECTION] = - g_param_spec_object ("connection", - _("Connection"), - _("The D-Bus connection to use for communication with oFono"), - G_TYPE_DBUS_CONNECTION, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY); - - g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } + +static void +calls_ofono_provider_class_finalize (CallsOfonoProviderClass *klass) +{ +} + + static void calls_ofono_provider_message_source_interface_init (CallsProviderInterface *iface) { } + static void calls_ofono_provider_provider_interface_init (CallsProviderInterface *iface) { @@ -493,6 +475,7 @@ calls_ofono_provider_provider_interface_init (CallsProviderInterface *iface) iface->get_origins = get_origins; } + static void calls_ofono_provider_init (CallsOfonoProvider *self) { @@ -501,3 +484,14 @@ calls_ofono_provider_init (CallsOfonoProvider *self) self->origins = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } + + +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) +{ + calls_ofono_provider_register_type (G_TYPE_MODULE (module)); + + peas_object_module_register_extension_type (module, + CALLS_TYPE_PROVIDER, + CALLS_TYPE_OFONO_PROVIDER); +} diff --git a/src/calls-ofono-provider.h b/plugins/ofono/calls-ofono-provider.h similarity index 93% rename from src/calls-ofono-provider.h rename to plugins/ofono/calls-ofono-provider.h index ccca1e6..aa8f768 100644 --- a/src/calls-ofono-provider.h +++ b/plugins/ofono/calls-ofono-provider.h @@ -34,8 +34,6 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (CallsOfonoProvider, calls_ofono_provider, CALLS, OFONO_PROVIDER, GObject); -CallsOfonoProvider *calls_ofono_provider_new (GDBusConnection *connection); - G_END_DECLS #endif /* CALLS_OFONO_PROVIDER_H__ */ diff --git a/libgdbofono/call.xml b/plugins/ofono/libgdbofono/call.xml similarity index 100% rename from libgdbofono/call.xml rename to plugins/ofono/libgdbofono/call.xml diff --git a/libgdbofono/dbus-introspect.sh b/plugins/ofono/libgdbofono/dbus-introspect.sh similarity index 100% rename from libgdbofono/dbus-introspect.sh rename to plugins/ofono/libgdbofono/dbus-introspect.sh diff --git a/libgdbofono/manager.xml b/plugins/ofono/libgdbofono/manager.xml similarity index 100% rename from libgdbofono/manager.xml rename to plugins/ofono/libgdbofono/manager.xml diff --git a/plugins/ofono/libgdbofono/meson.build b/plugins/ofono/libgdbofono/meson.build new file mode 100644 index 0000000..04d632d --- /dev/null +++ b/plugins/ofono/libgdbofono/meson.build @@ -0,0 +1,51 @@ +# +# Copyright (C) 2018 Purism SPC +# +# This file is part of Calls. +# +# Calls is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Calls 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Calls. If not, see . +# +# Author: Bob Ham +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + + +gnome = import('gnome') +dbus_interfaces = ['manager', 'modem', 'call'] + +gdbofono_src = [] +gdbofono_headers = [] +foreach iface: dbus_interfaces + src = gnome.gdbus_codegen( + 'gdbo-' + iface, + iface + '.xml', + interface_prefix: 'org.ofono.', + namespace: 'GDBO' + ) + gdbofono_src += src + gdbofono_headers += src[1] +endforeach + +gdbofono_deps = [ + dependency('gio-2.0'), + dependency('gio-unix-2.0'), +] + +gdbofono_lib = static_library( + 'gdbofono', + gdbofono_src, + include_directories: top_include, + dependencies: gdbofono_deps +) diff --git a/libgdbofono/modem-full.xml b/plugins/ofono/libgdbofono/modem-full.xml similarity index 100% rename from libgdbofono/modem-full.xml rename to plugins/ofono/libgdbofono/modem-full.xml diff --git a/libgdbofono/modem.xml b/plugins/ofono/libgdbofono/modem.xml similarity index 100% rename from libgdbofono/modem.xml rename to plugins/ofono/libgdbofono/modem.xml diff --git a/plugins/ofono/meson.build b/plugins/ofono/meson.build new file mode 100644 index 0000000..fb08127 --- /dev/null +++ b/plugins/ofono/meson.build @@ -0,0 +1,60 @@ +# +# Copyright (C) 2018 Purism SPC +# +# This file is part of Calls. +# +# Calls is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Calls 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 +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Calls. If not, see . +# +# Author: Bob Ham +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +subdir('libgdbofono') + +ofono_install_dir = join_paths(full_calls_plugin_libdir, 'ofono') + +ofono_plugin = configure_file( + input: 'ofono.plugin.in', + output: 'ofono.plugin', + configuration: config_data, + install_dir: ofono_install_dir +) + +ofono_deps = [ + dependency('gobject-2.0'), + dependency('gtk+-3.0'), + dependency('libpeas-1.0'), +] + +ofono_sources = files( + [ + 'calls-ofono-call.c', 'calls-ofono-call.h', + 'calls-ofono-origin.c', 'calls-ofono-origin.h', + 'calls-ofono-provider.c', 'calls-ofono-provider.h' + ] +) + +shared_module( + 'ofono', + ofono_sources, gdbofono_headers, + dependencies: ofono_deps, + include_directories: [ + src_include, + include_directories('.') + ], + link_with: gdbofono_lib, + install: true, + install_dir: ofono_install_dir +) diff --git a/plugins/ofono/ofono.plugin.in b/plugins/ofono/ofono.plugin.in new file mode 100644 index 0000000..eff681f --- /dev/null +++ b/plugins/ofono/ofono.plugin.in @@ -0,0 +1,7 @@ +[Plugin] +Module=ofono +Name=oFono +Description=oFono calls provider +Authors=Bob Ham +Copyright=Copyright (C) 2018 Purism SPC +Website=@PACKAGE_URL_RAW@ diff --git a/src/calls-application.c b/src/calls-application.c index 594eb7f..d1c6f62 100644 --- a/src/calls-application.c +++ b/src/calls-application.c @@ -25,23 +25,23 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -#include - -#define HANDY_USE_UNSTABLE_API -#include - #include "config.h" #include "calls-new-call-header-bar.h" #include "calls-history-header-bar.h" #include "calls-history-box.h" #include "calls-new-call-box.h" #include "calls-encryption-indicator.h" -#include "calls-mm-provider.h" #include "calls-ringer.h" #include "calls-call-window.h" #include "calls-main-window.h" #include "calls-application.h" +#define HANDY_USE_UNSTABLE_API +#include + +#include +#include + /** * SECTION: calls-application * @title: CallsApplication @@ -49,10 +49,13 @@ * @include: "calls-application.h" */ +#define DEFAULT_PROVIDER_PLUGIN "mm" + struct _CallsApplication { GtkApplication parent_instance; + GString *provider_name; CallsProvider *provider; CallsRinger *ringer; }; @@ -60,6 +63,217 @@ struct _CallsApplication G_DEFINE_TYPE (CallsApplication, calls_application, GTK_TYPE_APPLICATION) +static gint +handle_local_options (GApplication *application, + GVariantDict *options) +{ + gboolean ok; + g_autoptr(GError) error = NULL; + const gchar *name; + + g_debug ("Registering application"); + ok = g_application_register (application, NULL, &error); + if (!ok) + { + g_error ("Error registering application: %s", + error->message); + } + + ok = g_variant_dict_lookup (options, "provider", "&s", &name); + if (ok) + { + g_action_group_activate_action (G_ACTION_GROUP (application), + "set-provider-name", + g_variant_new_string (name)); + } + + return -1; // Continue processing signal +} + + +static void +set_provider_name_action (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + CallsApplication *self = CALLS_APPLICATION (user_data); + const gchar *name; + + name = g_variant_get_string (parameter, NULL); + g_return_if_fail (name != NULL); + + if (self->provider) + { + g_warning ("Cannot set provider name to `%s'" + " because provider is already created", + name); + return; + } + + g_string_assign (self->provider_name, name); + + g_debug ("Provider name set to `%s'", + self->provider_name->str); +} + + +static const GActionEntry actions[] = +{ + { "set-provider-name", set_provider_name_action, "s" }, +}; + + +static void +startup (GApplication *application) +{ + G_APPLICATION_CLASS (calls_application_parent_class)->startup (application); + + g_set_prgname (APP_ID); + g_set_application_name (_("Calls")); + + g_action_map_add_action_entries (G_ACTION_MAP (application), + actions, + G_N_ELEMENTS (actions), + application); +} + + +static void +load_provider_plugin (CallsApplication *self) +{ + const gchar * const name = self->provider_name->str; + PeasEngine *plugins; + PeasPluginInfo *info; + PeasExtension *extension; + + g_assert (self->provider == NULL); + + // Add Calls search path and rescan + plugins = peas_engine_get_default (); + peas_engine_add_search_path (plugins, PLUGIN_LIBDIR, PLUGIN_LIBDIR); + g_debug ("Scanning for plugins in `%s'", PLUGIN_LIBDIR); + + // Find the plugin + info = peas_engine_get_plugin_info (plugins, name); + if (!info) + { + g_critical ("Could not find plugin `%s'", name); + return; + } + + // Possibly load the plugin + if (!peas_plugin_info_is_loaded (info)) + { + g_autoptr(GError) error = NULL; + + peas_engine_load_plugin (plugins, info); + + if (!peas_plugin_info_is_available (info, &error)) + { + if (error) + { + g_critical ("Error loading plugin `%s': %s", + name, error->message); + } + else + { + g_critical ("Could not load plugin `%s'", name); + } + + return; + } + + g_debug ("Loaded plugin `%s'", name); + } + + // Check the plugin provides CallsProvider + if (!peas_engine_provides_extension + (plugins, info, CALLS_TYPE_PROVIDER)) + { + g_critical ("Plugin `%s' does not have a provider extension", + name); + return; + } + + // Get the extension + extension = peas_engine_create_extensionv + (plugins, info, CALLS_TYPE_PROVIDER, 0, NULL); + if (!extension) + { + g_critical ("Could not create provider from plugin `%s'", + name); + return; + } + + g_debug ("Created provider from plugin `%s'", name); + self->provider = CALLS_PROVIDER (extension); +} + + +static void +activate (GApplication *application) +{ + GtkApplication *gtk_app; + GtkWindow *window; + + g_assert (GTK_IS_APPLICATION (application)); + gtk_app = GTK_APPLICATION (application); + + window = gtk_application_get_active_window (gtk_app); + + if (window == NULL) + { + CallsApplication *self = CALLS_APPLICATION (application); + + // Later we will make provider loading/unloaded a dynamic + // process but that will have far-reaching consequences and is + // of no use immediately so for now, we just load one provider + // at startup. We can't put this in the actual startup() method + // though, because we need to be able to set the provider name + // from the command line and we use actions to do that, which + // depend on the application already being started up. + if (!self->provider) + { + load_provider_plugin (self); + if (!self->provider) + { + g_application_quit (application); + return; + } + + self->ringer = calls_ringer_new (self->provider); + g_assert (self->ringer != NULL); + } + + /* + * We don't track the memory created. Ideally, we might have to. + * But we assume that the application is closed by closing the + * window. In that case, GTK+ frees the resources right. + */ + window = GTK_WINDOW (calls_main_window_new (gtk_app, self->provider)); + calls_call_window_new (gtk_app, self->provider); + } + + gtk_window_present (window); +} + + +static void +constructed (GObject *object) +{ + GObjectClass *parent_class = g_type_class_peek (GTK_TYPE_APPLICATION); + CallsApplication *self = CALLS_APPLICATION (object); + GSimpleActionGroup *action_group; + + action_group = g_simple_action_group_new (); + g_action_map_add_action_entries (G_ACTION_MAP (action_group), + actions, G_N_ELEMENTS (actions), self); + g_object_unref (action_group); + + parent_class->constructed (object); +} + + static void dispose (GObject *object) { @@ -68,51 +282,20 @@ dispose (GObject *object) g_clear_object (&self->ringer); g_clear_object (&self->provider); + G_OBJECT_CLASS (calls_application_parent_class)->dispose (object); +} + + +static void +finalize (GObject *object) +{ + CallsApplication *self = (CallsApplication *)object; + + g_string_free (self->provider_name, TRUE); + G_OBJECT_CLASS (calls_application_parent_class)->finalize (object); } -static void -startup (GApplication *application) -{ - CallsApplication *self = (CallsApplication *)application; - g_autoptr(GError) error = NULL; - - G_APPLICATION_CLASS (calls_application_parent_class)->startup (application); - - g_set_prgname (APP_ID); - g_set_application_name (_("Calls")); - - self->provider = CALLS_PROVIDER (calls_mm_provider_new ()); - g_assert (self->provider != NULL); - - self->ringer = calls_ringer_new (self->provider); - g_assert (self->ringer != NULL); -} - -static void -activate (GApplication *application) -{ - CallsApplication *self = (CallsApplication *)application; - GtkApplication *app = (GtkApplication *)application; - GtkWindow *window; - - g_assert (GTK_IS_APPLICATION (app)); - - window = gtk_application_get_active_window (app); - - if (window == NULL) - { - /* - * We don't track the memory created. Ideally, we might have to. - * But we assume that the application is closed by closing the - * window. In that case, GTK+ frees the resources right. - */ - window = GTK_WINDOW (calls_main_window_new (app, self->provider)); - calls_call_window_new (app, self->provider); - } - - gtk_window_present (window); -} static void calls_application_class_init (CallsApplicationClass *klass) @@ -120,8 +303,11 @@ calls_application_class_init (CallsApplicationClass *klass) GApplicationClass *application_class = G_APPLICATION_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->constructed = constructed; object_class->dispose = dispose; + object_class->finalize = finalize; + application_class->handle_local_options = handle_local_options; application_class->startup = startup; application_class->activate = activate; @@ -133,11 +319,28 @@ calls_application_class_init (CallsApplicationClass *klass) g_type_ensure (HDY_TYPE_DIALER); } + static void calls_application_init (CallsApplication *self) { + const GOptionEntry options[] = { + { + "provider", 'p', G_OPTION_FLAG_NONE, + G_OPTION_ARG_STRING, NULL, + _("The name of the plugin to use for the call Provider"), + _("PLUGIN") + }, + { + NULL + } + }; + + g_application_add_main_option_entries (G_APPLICATION (self), options); + + self->provider_name = g_string_new (DEFAULT_PROVIDER_PLUGIN); } + CallsApplication * calls_application_new (void) { diff --git a/src/meson.build b/src/meson.build index 63cdb2e..1e109a2 100644 --- a/src/meson.build +++ b/src/meson.build @@ -23,12 +23,13 @@ gnome = import('gnome') +src_include = include_directories('.') + calls_deps = [ dependency('gobject-2.0'), dependency('gtk+-3.0'), dependency('libhandy-0.0'), - dependency('ModemManager'), - dependency('mm-glib'), dependency('gsound'), + dependency('libpeas-1.0'), ] calls_sources = files(['calls-message-source.c', 'calls-message-source.h', @@ -37,12 +38,6 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h', 'calls-provider.c', 'calls-provider.h', 'calls-enumerate-params.c', 'calls-enumerate-params.h', 'calls-enumerate.c', 'calls-enumerate.h', - 'calls-ofono-call.c', 'calls-ofono-call.h', - 'calls-ofono-origin.c', 'calls-ofono-origin.h', - 'calls-ofono-provider.c', 'calls-ofono-provider.h', - 'calls-mm-call.c', 'calls-mm-call.h', - 'calls-mm-origin.c', 'calls-mm-origin.h', - 'calls-mm-provider.c', 'calls-mm-provider.h', 'calls-party.c', 'calls-party.h', 'calls-call-data.c', 'calls-call-data.h', 'calls-call-holder.c', 'calls-call-holder.h', @@ -60,23 +55,12 @@ calls_sources = files(['calls-message-source.c', 'calls-message-source.h', 'util.c', 'util.h', ]) -calls_dummy_sources = files(['calls-dummy-call.c', 'calls-dummy-call.h', - 'calls-dummy-origin.c', 'calls-dummy-origin.h', - 'calls-dummy-provider.c', 'calls-dummy-provider.h', - ]) - -prefix = get_option('prefix') -config_data = configuration_data() -config_data.set_quoted('APP_ID', calls_id) -config_data.set_quoted('GETTEXT_PACKAGE', calls_name) -config_data.set_quoted('LOCALEDIR', join_paths(prefix, get_option('localedir'))) -config_data.set_quoted('PACKAGE_URL', calls_homepage) -config_data.set_quoted('PACKAGE_VERSION', calls_version) -config_data.set_quoted('VCS_TAG', '@VCS_TAG@') +calls_config_data = config_data +calls_config_data.set_quoted('VCS_TAG', '@VCS_TAG@') config_h_in = configure_file( output: 'config.h.in', - configuration: config_data + configuration: calls_config_data ) config_h = vcs_tag( @@ -99,6 +83,6 @@ calls_resources = gnome.compile_resources( executable('calls', calls_sources, calls_enum_sources, calls_resources, 'main.c', dependencies : calls_deps, - link_with : gdbofono_lib, + export_dynamic : true, include_directories : include_directories('..'), install : true) diff --git a/tests/meson.build b/tests/meson.build index b5e71a1..97ea786 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -11,6 +11,7 @@ test_env = [ test_cflags = [ '-fPIE', + '-DFOR_TESTING' ] test_link_args = [ @@ -38,13 +39,16 @@ foreach test : tests 'common.h' ] t = executable(name, test_sources, - calls_sources, calls_dummy_sources, calls_enum_sources, calls_resources, + calls_sources, dummy_sources, calls_enum_sources, calls_resources, c_args : test_cflags, link_args: test_link_args, link_with : gdbofono_lib, dependencies: calls_deps, - include_directories : include_directories('..', - join_paths('..', 'src')), + include_directories : [ + top_include, + src_include, + dummy_include + ] ) test(name, t, env: test_env) endforeach diff --git a/tests/setup-origin.h b/tests/setup-origin.h index 7edb5df..acd5885 100644 --- a/tests/setup-origin.h +++ b/tests/setup-origin.h @@ -7,7 +7,7 @@ #include "setup-provider.h" #include "calls-dummy-origin.h" -#define TEST_ORIGIN_NAME "Test origin" +#define TEST_ORIGIN_NAME "Dummy origin" #define TEST_CALL_NUMBER "0123456789" diff --git a/tests/test-provider.c b/tests/test-provider.c index 9dbc3e9..6c16ae7 100644 --- a/tests/test-provider.c +++ b/tests/test-provider.c @@ -43,14 +43,9 @@ test_dummy_provider_origins (ProviderFixture *fixture, { GList *origins; - calls_dummy_provider_add_origin (fixture->dummy_provider, - "Test origin 1"); - calls_dummy_provider_add_origin (fixture->dummy_provider, - "Test origin 2"); - origins = calls_provider_get_origins (CALLS_PROVIDER (fixture->dummy_provider)); - g_assert_cmpuint (g_list_length (origins), ==, 2); + g_assert_cmpuint (g_list_length (origins), ==, 1); g_list_free (origins); }