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); }