Commit 460c0c6c authored by Bob Ham's avatar Bob Ham
Browse files

Turn providers into plugins courtesy of libpeas

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.
parent b6cd5a3f
......@@ -9,6 +9,7 @@ Build-Depends:
modemmanager-dev,
libmm-glib-dev,
libgsound-dev,
libpeas-dev,
meson,
pkg-config,
# to run the tests
......
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 )
......@@ -19,11 +19,17 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
project('call', 'c',
project(
'calls',
'c',
version: '0.0.0',
license: 'GPLv3+',
meson_version: '>= 0.42.0',
default_options: [ 'warning_level=1', 'buildtype=debugoptimized', 'c_std=gnu11' ],
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')
......@@ -27,6 +27,9 @@
#include "calls-provider.h"
#include "calls-dummy-origin.h"
#include <libpeas/peas.h>
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,
#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 */
[Plugin]
Module=dummy
Name=Dummy
Description=Dummy calls provider
Authors=Bob Ham <rah@settrans.net>
Copyright=Copyright (C) 2018 Purism SPC
Website=@PACKAGE_URL_RAW@
#
# 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 <http://www.gnu.org/licenses/>.
#
# Author: Bob Ham <bob.ham@puri.sm>
#
# 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
)
subdir('mm')
subdir('dummy')
subdir('ofono')
......@@ -29,6 +29,7 @@
#include "calls-origin.h"
#include <libmm-glib.h>
#include <libpeas/peas.h>
#include <glib/gi18n.h>
struct _CallsMMProvider
......@@ -48,12 +49,14 @@ 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,
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 (CALLS_TYPE_PROVIDER,
G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_PROVIDER,
calls_mm_provider_provider_interface_init))
enum {
PROP_0,
PROP_STATUS,
......@@ -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);
}
......@@ -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__ */
#
# 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 <http://www.gnu.org/licenses/>.
#
# Author: Bob Ham <bob.ham@puri.sm>
#
# 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
)
[Plugin]
Module=mm
Name=ModemManager
Description=ModemManager calls provider
Authors=Bob Ham <rah@settrans.net>
Copyright=Copyright (C) 2018 Purism SPC
Website=@PACKAGE_URL_RAW@
......@@ -32,6 +32,8 @@
#include <libgdbofono/gdbo-modem.h>
#include <glib/gi18n.h>
#include <libpeas/peas.h>
struct _CallsOfonoProvider
{
......@@ -47,22 +49,18 @@ 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,
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 (CALLS_TYPE_PROVIDER,
G_IMPLEMENT_INTERFACE_DYNAMIC (CALLS_TYPE_PROVIDER,
calls_ofono_provider_provider_interface_init))
enum {
PROP_0,
PROP_CONNECTION,
PROP_LAST_PROP,
};
static GParamSpec *props[PROP_LAST_PROP];
static const gchar *
get_name (CallsProvider *iface)
......@@ -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,