1
0
Fork 0
mirror of https://gitlab.gnome.org/GNOME/calls.git synced 2024-12-04 20:07:36 +00:00

refactor: Switch to CallsPluginManager

This commit is contained in:
Evangelos Ribeiro Tzaras 2023-05-15 10:08:55 +02:00
parent 37b208f040
commit d3e42c93cd
9 changed files with 371 additions and 589 deletions

View file

@ -32,6 +32,11 @@
#include "calls-account-provider.h" #include "calls-account-provider.h"
#include "calls-manager.h" #include "calls-manager.h"
#include "calls-in-app-notification.h" #include "calls-in-app-notification.h"
#include "calls-plugin-manager.h"
#include "calls-util.h"
#include "gtkcustomfilter.h"
#include "gtkfilterlistmodel.h"
#include <glib/gi18n-lib.h> #include <glib/gi18n-lib.h>
@ -66,11 +71,16 @@ struct _CallsAccountOverview {
GtkWindow *account_window; GtkWindow *account_window;
GtkWidget *current_account_widget; GtkWidget *current_account_widget;
/* models */
GtkFilter *account_provider_filter;
GtkFilter *account_filter;
GListModel *providers;
GListModel *accounts;
/* misc */ /* misc */
GtkEventController *key_controller; GtkEventController *key_controller;
GtkEventController *key_controller_account; GtkEventController *key_controller_account;
CallsAccountOverviewState state; CallsAccountOverviewState state;
GList *providers;
CallsInAppNotification *in_app_notification; CallsInAppNotification *in_app_notification;
}; };
@ -101,14 +111,25 @@ static void
update_state (CallsAccountOverview *self) update_state (CallsAccountOverview *self)
{ {
guint n_origins = 0; guint n_origins = 0;
guint n_providers;
g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self)); g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self));
for (GList *node = self->providers; node != NULL; node = node->next) { n_providers = g_list_model_get_n_items (self->providers);
CallsProvider *provider = CALLS_PROVIDER (node->data);
GListModel *model = calls_provider_get_origins (provider);
n_origins += g_list_model_get_n_items (model); for (guint i = 0; i < n_providers; i++) {
g_autoptr (CallsProvider) provider = g_list_model_get_item (self->providers, i);
GListModel *origins;
/* we might be in the middle of the lists being updated! */
if (!provider) {
n_providers--;
break;
}
origins = calls_provider_get_origins (provider);
n_origins += g_list_model_get_n_items (origins);
} }
if (n_origins > 0) if (n_origins > 0)
@ -116,6 +137,8 @@ update_state (CallsAccountOverview *self)
else else
self->state = SHOW_INTRO; self->state = SHOW_INTRO;
gtk_widget_set_sensitive (self->add_btn, n_providers > 0);
update_visibility (self); update_visibility (self);
} }
@ -145,18 +168,20 @@ on_account_row_activated (GtkListBox *box,
GtkListBoxRow *row, GtkListBoxRow *row,
CallsAccountOverview *self) CallsAccountOverview *self)
{ {
CallsAccountProvider *provider;
CallsAccount *account = NULL; CallsAccount *account = NULL;
CallsAccountRow *acc_row; CallsAccountRow *acc_row;
CallsAccountProvider *provider;
GtkWidget *widget; GtkWidget *widget;
g_assert (GTK_IS_LIST_BOX_ROW (row) ); g_assert (GTK_IS_LIST_BOX_ROW (row) );
g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self)); g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self));
g_assert (g_list_model_get_n_items (self->providers) > 0);
if (row == self->add_row) { if (row == self->add_row) {
/* TODO this needs changing if we ever have multiple account providers */ /* TODO this needs changing if we ever have multiple account providers */
provider = CALLS_ACCOUNT_PROVIDER (self->providers->data); provider = g_list_model_get_item (self->providers, 0);
widget = calls_account_provider_get_account_widget (provider); widget = calls_account_provider_get_account_widget (provider);
g_object_unref (provider);
} else if (CALLS_IS_ACCOUNT_ROW (row)) { } else if (CALLS_IS_ACCOUNT_ROW (row)) {
acc_row = CALLS_ACCOUNT_ROW (row); acc_row = CALLS_ACCOUNT_ROW (row);
@ -215,84 +240,72 @@ on_account_message (CallsAccount *account,
static void static void
update_account_list (CallsAccountOverview *self) on_accounts_changed (GListModel *accounts,
guint position,
guint removed,
guint added,
CallsAccountOverview *self)
{ {
gboolean removed_all = FALSE; guint n_providers = g_list_model_get_n_items (self->providers);
g_assert (CALLS_IS_ACCOUNT_OVERVIEW (self)); for (guint i = removed; i > 0; i--) {
GtkListBoxRow *row =
gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->overview), position + i - 1);
/* TODO rework with GTK4 FlattenListModel (to flatten a GListModel of GListModels) gtk_container_remove (GTK_CONTAINER (self->overview), GTK_WIDGET (row));
* in particular we could then connect to the items-changed signal of the flattened list.
* Always rebuilding the account list is not particularly efficient, but since
* we're not constantly doing this it's fine for now.
*/
while (!removed_all) {
GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (self->overview), 0);
if (row == NULL || row == GTK_LIST_BOX_ROW (self->add_row))
removed_all = TRUE;
else
gtk_container_remove (GTK_CONTAINER (self->overview), GTK_WIDGET (row));
} }
for (GList *node = self->providers; node != NULL; node = node->next) { for (guint i = 0; i < added; i++) {
CallsAccountProvider *provider = CALLS_ACCOUNT_PROVIDER (node->data); g_autoptr (CallsAccount) account =
GListModel *model = calls_provider_get_origins (CALLS_PROVIDER (provider)); CALLS_ACCOUNT (g_list_model_get_item (accounts, position + i));
guint n_origins = g_list_model_get_n_items (model); CallsAccountProvider *provider = NULL;
CallsAccountRow *account_row;
for (guint i = 0; i < n_origins; i++) { /* which provider does this account belong to? */
g_autoptr (CallsAccount) account = CALLS_ACCOUNT (g_list_model_get_item (model, i)); for (guint j = 0; j < n_providers; j++) {
CallsAccountRow *account_row = calls_account_row_new (provider, account); g_autoptr (CallsProvider) candidate = g_list_model_get_item (self->providers, j);
g_signal_handlers_disconnect_by_data (account, self); if (calls_find_in_model (calls_provider_get_origins (candidate), account, NULL)) {
g_signal_connect_object (account, "message", provider = CALLS_ACCOUNT_PROVIDER (candidate);
G_CALLBACK (on_account_message), break;
self, }
G_CONNECT_AFTER);
gtk_list_box_insert (GTK_LIST_BOX (self->overview),
GTK_WIDGET (account_row),
0);
} }
g_assert (CALLS_IS_ACCOUNT_PROVIDER (provider));
account_row = calls_account_row_new (provider, account);
g_signal_connect_object (account, "message",
G_CALLBACK (on_account_message),
self,
0);
gtk_list_box_insert (GTK_LIST_BOX (self->overview),
GTK_WIDGET (account_row),
position + i);
} }
update_state (self); update_state (self);
} }
static void static void
on_providers_changed (CallsAccountOverview *self) on_providers_changed (GListModel *providers,
guint position,
guint removed,
guint added,
CallsAccountOverview *self)
{ {
GList *providers; for (guint i = 0; i < added; i++) {
g_autoptr (CallsProvider) provider =
g_list_model_get_item (providers, position + i);
g_clear_pointer (&self->providers, g_list_free); g_signal_connect_swapped (provider, "widget-edit-done",
providers = calls_manager_get_providers (calls_manager_get_default ()); G_CALLBACK (gtk_widget_hide), self->account_window);
for (GList *node = providers; node != NULL; node = node->next) {
CallsProvider *provider = node->data;
if (CALLS_IS_ACCOUNT_PROVIDER (provider)) {
self->providers = g_list_append (self->providers, provider);
g_signal_connect_object (calls_provider_get_origins (provider),
"items-changed",
G_CALLBACK (update_account_list),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (provider,
"widget-edit-done",
G_CALLBACK (gtk_widget_hide),
self->account_window,
G_CONNECT_SWAPPED);
}
} }
/* Clear any acccount widgets, because they might've gone stale */ /* Clear any acccount widgets, because they might've gone stale */
attach_account_widget (self, NULL); attach_account_widget (self, NULL);
gtk_widget_hide (GTK_WIDGET (self->account_window)); gtk_widget_hide (GTK_WIDGET (self->account_window));
update_account_list (self);
gtk_widget_set_sensitive (self->add_btn, !!self->providers);
} }
@ -316,6 +329,12 @@ calls_account_overview_dispose (GObject *object)
{ {
CallsAccountOverview *self = CALLS_ACCOUNT_OVERVIEW (object); CallsAccountOverview *self = CALLS_ACCOUNT_OVERVIEW (object);
g_clear_object (&self->providers);
g_clear_object (&self->account_provider_filter);
g_clear_object (&self->accounts);
g_clear_object (&self->account_filter);
g_clear_object (&self->key_controller); g_clear_object (&self->key_controller);
g_clear_object (&self->key_controller_account); g_clear_object (&self->key_controller_account);
@ -348,24 +367,65 @@ calls_account_overview_class_init (CallsAccountOverviewClass *klass)
} }
static gboolean
match_account_provider (gpointer item,
gpointer unused)
{
g_assert (CALLS_IS_PROVIDER (item));
return CALLS_IS_ACCOUNT_PROVIDER (item);
}
static gboolean
match_account (gpointer item,
gpointer unused)
{
g_assert (CALLS_IS_ORIGIN (item));
return CALLS_IS_ACCOUNT (item);
}
static void static void
calls_account_overview_init (CallsAccountOverview *self) calls_account_overview_init (CallsAccountOverview *self)
{ {
GListModel *all_providers =
calls_plugin_manager_get_providers (calls_plugin_manager_get_default ());
GListModel *all_origins =
calls_manager_get_origins (calls_manager_get_default ());
gtk_widget_init_template (GTK_WIDGET (self)); gtk_widget_init_template (GTK_WIDGET (self));
g_signal_connect_swapped (calls_manager_get_default (), self->account_provider_filter = gtk_custom_filter_new (match_account_provider, NULL, NULL);
"providers-changed", self->providers =
G_CALLBACK (on_providers_changed), G_LIST_MODEL (gtk_filter_list_model_new (all_providers,
self); self->account_provider_filter));
on_providers_changed (self);
g_signal_connect (self->providers,
"items-changed",
G_CALLBACK (on_providers_changed),
self);
on_providers_changed (self->providers,
0, 0, g_list_model_get_n_items (self->providers),
self);
self->account_filter = gtk_custom_filter_new (match_account, NULL, NULL);
self->accounts =
G_LIST_MODEL (gtk_filter_list_model_new (all_origins,
self->account_filter));
g_signal_connect_object (self->accounts,
"items-changed",
G_CALLBACK (on_accounts_changed),
self,
G_CONNECT_AFTER);
on_accounts_changed (self->accounts, 0, 0, g_list_model_get_n_items (self->accounts), self);
gtk_list_box_insert (GTK_LIST_BOX (self->overview), gtk_list_box_insert (GTK_LIST_BOX (self->overview),
GTK_WIDGET (self->add_row), GTK_WIDGET (self->add_row),
-1); -1);
gtk_window_set_transient_for (self->account_window, GTK_WINDOW (self)); gtk_window_set_transient_for (self->account_window, GTK_WINDOW (self));
update_state (self);
self->key_controller = gtk_event_controller_key_new (GTK_WIDGET (self)); self->key_controller = gtk_event_controller_key_new (GTK_WIDGET (self));
g_signal_connect (self->key_controller, g_signal_connect (self->key_controller,
"key-pressed", "key-pressed",

View file

@ -39,6 +39,7 @@
#include "calls-message-source.h" #include "calls-message-source.h"
#include "calls-new-call-box.h" #include "calls-new-call-box.h"
#include "calls-notifier.h" #include "calls-notifier.h"
#include "calls-plugin-manager.h"
#include "calls-record-store.h" #include "calls-record-store.h"
#include "calls-ringer.h" #include "calls-ringer.h"
#include "version.h" #include "version.h"
@ -73,6 +74,8 @@ struct _CallsApplication {
guint id_sigint; guint id_sigint;
gboolean shutdown; gboolean shutdown;
gboolean db_done; gboolean db_done;
CallsPluginManager *plugin_manager;
CallsSettings *settings;
}; };
G_DEFINE_TYPE (CallsApplication, calls_application, GTK_TYPE_APPLICATION); G_DEFINE_TYPE (CallsApplication, calls_application, GTK_TYPE_APPLICATION);
@ -155,60 +158,76 @@ calls_application_dbus_unregister (GApplication *application,
static void static void
set_provider_names_action (GSimpleAction *action, set_plugin_names_action (GSimpleAction *action,
GVariant *parameter, GVariant *parameter,
gpointer user_data) gpointer user_data)
{ {
CallsManager *manager;
g_autofree const char **names = NULL; g_autofree const char **names = NULL;
g_autofree const char **loaded = NULL; g_autofree const char **loaded = NULL;
CallsApplication *self = user_data;
gsize length; gsize length;
guint length_loaded; guint length_loaded;
g_assert (CALLS_IS_APPLICATION (self));
names = g_variant_get_strv (parameter, &length); names = g_variant_get_strv (parameter, &length);
g_return_if_fail (names && *names); g_return_if_fail (names && *names);
manager = calls_manager_get_default (); loaded = calls_plugin_manager_get_plugin_names (self->plugin_manager, &length_loaded);
loaded = calls_manager_get_provider_names (manager, &length_loaded);
/* remove unwanted providers */ /* remove unwanted plugins */
for (guint i = 0; i < length_loaded; i++) { for (guint i = 0; i < length_loaded; i++) {
g_autofree char *provider = g_strdup (loaded[i]); g_autofree char *plugin = g_strdup (loaded[i]);
if (!g_strv_contains (names, provider))
calls_manager_remove_provider (manager, provider); if (!g_strv_contains (names, plugin)) {
g_autoptr (GError) error = NULL;
gboolean ok = calls_plugin_manager_unload_plugin (self->plugin_manager, plugin, &error);
g_debug ("Unloading plugin `%s' %ssuccessful", plugin, ok ? "" : "un");
if (!ok)
g_warning ("Plugin '%s' not unloaded: %s", plugin, error->message);
}
} }
for (guint i = 0; i < length; i++) { for (guint i = 0; i < length; i++) {
g_autoptr (GError) error = NULL;
const char *name = names[i]; const char *name = names[i];
gboolean ok;
if (calls_manager_has_provider (manager, name)) if (calls_plugin_manager_has_plugin (self->plugin_manager, name))
continue; continue;
g_debug ("Loading provider `%s'", name); ok = calls_plugin_manager_load_plugin (self->plugin_manager, name, &error);
calls_manager_add_provider (manager, name); g_debug ("Loading plugin `%s' %ssuccessful", name, ok ? "" : "un");
if (!ok)
g_warning ("Plugin '%s' not loaded: %s", name, error->message);
} }
} }
static void static void
set_default_providers_action (GSimpleAction *action, set_default_plugins_action (GSimpleAction *action,
GVariant *parameter, GVariant *parameter,
gpointer user_data) gpointer user_data)
{ {
CallsManager *manager = calls_manager_get_default (); CallsApplication *self = CALLS_APPLICATION (user_data);
CallsSettings *settings = calls_manager_get_settings (manager);
g_auto (GStrv) plugins = NULL; g_auto (GStrv) plugins = NULL;
/** /**
* Only add default providers when there are none added yet, * Only add default providers when there are none added yet,
* This makes sure we're not resetting explicitly set providers * This makes sure we're not resetting explicitly set providers
*/ */
if (calls_manager_has_any_provider (manager)) if (calls_plugin_manager_has_any_plugins (self->plugin_manager))
return; return;
plugins = calls_settings_get_autoload_plugins (settings); plugins = calls_settings_get_autoload_plugins (self->settings);
for (guint i = 0; plugins[i] != NULL; i++) { for (guint i = 0; plugins[i] != NULL; i++) {
calls_manager_add_provider (manager, plugins[i]); g_autoptr (GError) error = NULL;
g_debug ("Loading default provider %s", plugins[i]);
if (!calls_plugin_manager_load_plugin (self->plugin_manager, plugins[i], &error))
g_warning ("Could not load plugin '%s': %s", plugins[i], error->message);
} }
} }
@ -417,8 +436,8 @@ manager_state_changed_cb (GApplication *application)
static const GActionEntry actions[] = static const GActionEntry actions[] =
{ {
{ "set-provider-names", set_provider_names_action, "as" }, { "set-plugin-names", set_plugin_names_action, "as" },
{ "set-default-providers", set_default_providers_action, NULL }, { "set-default-plugins", set_default_plugins_action, NULL },
{ "set-daemon", set_daemon_action, "b" }, { "set-daemon", set_daemon_action, "b" },
{ "dial", dial_action, "s" }, { "dial", dial_action, "s" },
{ "copy-number", copy_number, "s" }, { "copy-number", copy_number, "s" },
@ -509,7 +528,7 @@ calls_application_command_line (GApplication *application,
GVariantDict *options; GVariantDict *options;
const char *arg; const char *arg;
g_autoptr (GVariant) providers = NULL; g_autoptr (GVariant) plugins = NULL;
g_auto (GStrv) arguments = NULL; g_auto (GStrv) arguments = NULL;
gint argc; gint argc;
guint verbosity; guint verbosity;
@ -529,14 +548,14 @@ calls_application_command_line (GApplication *application,
start_proper (self); start_proper (self);
providers = g_variant_dict_lookup_value (options, "provider", G_VARIANT_TYPE_STRING_ARRAY); plugins = g_variant_dict_lookup_value (options, "plugins", G_VARIANT_TYPE_STRING_ARRAY);
if (providers) { if (plugins) {
g_action_group_activate_action (G_ACTION_GROUP (application), g_action_group_activate_action (G_ACTION_GROUP (application),
"set-provider-names", "set-plugin-names",
providers); plugins);
} else { } else {
g_action_group_activate_action (G_ACTION_GROUP (application), g_action_group_activate_action (G_ACTION_GROUP (application),
"set-default-providers", "set-default-plugins",
NULL); NULL);
} }
@ -629,6 +648,12 @@ start_proper (CallsApplication *self)
gtk_app = GTK_APPLICATION (self); gtk_app = GTK_APPLICATION (self);
self->settings = calls_settings_get_default ();
g_assert (self->settings);
self->plugin_manager = calls_plugin_manager_get_default ();
g_assert (self->plugin_manager);
self->manager = calls_manager_get_default (); self->manager = calls_manager_get_default ();
g_assert (self->manager); g_assert (self->manager);
@ -746,6 +771,8 @@ finalize (GObject *object)
g_clear_object (&self->ringer); g_clear_object (&self->ringer);
g_clear_object (&self->notifier); g_clear_object (&self->notifier);
g_clear_object (&self->manager); g_clear_object (&self->manager);
g_clear_object (&self->plugin_manager);
g_clear_object (&self->settings);
g_free (self->uri); g_free (self->uri);
@ -780,9 +807,9 @@ calls_application_init (CallsApplication *self)
{ {
const GOptionEntry options[] = { const GOptionEntry options[] = {
{ {
"provider", 'p', G_OPTION_FLAG_NONE, "plugins", 'p', G_OPTION_FLAG_NONE,
G_OPTION_ARG_STRING_ARRAY, NULL, G_OPTION_ARG_STRING_ARRAY, NULL,
_("The name of the plugin to use as a call provider"), _("The name of the plugins to load"),
_("PLUGIN") _("PLUGIN")
}, },
{ {

View file

@ -31,6 +31,7 @@
#include "calls-contacts-provider.h" #include "calls-contacts-provider.h"
#include "calls-manager.h" #include "calls-manager.h"
#include "calls-message-source.h" #include "calls-message-source.h"
#include "calls-plugin-manager.h"
#include "calls-provider.h" #include "calls-provider.h"
#include "calls-settings.h" #include "calls-settings.h"
#include "calls-ui-call-data.h" #include "calls-ui-call-data.h"
@ -39,6 +40,10 @@
#include "enum-types.h" #include "enum-types.h"
#include "gtkcustomfilter.h"
#include "gtkfilterlistmodel.h"
#include "gtkflattenlistmodel.h"
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <libpeas/peas.h> #include <libpeas/peas.h>
@ -59,12 +64,23 @@ static const char * const protocols[] = {
"sips" "sips"
}; };
static gboolean
match_origin_supports_protocol (gpointer item,
gpointer protocol)
{
g_assert (CALLS_IS_ORIGIN (item));
return calls_origin_supports_protocol (CALLS_ORIGIN (item), (char *) protocol);
}
struct _CallsManager { struct _CallsManager {
GObject parent_instance; GObject parent_instance;
GHashTable *providers;
GListStore *origins; GListStore *origins;
GtkFlattenListModel *origins_flat;
/* origins_by_protocol maps protocol names to GListStore's of suitable origins */ /* origins_by_protocol maps protocol names to GListStore's of suitable origins */
GHashTable *origins_by_protocol; GHashTable *origins_by_protocol;
/* dial_actions_by_protocol maps protocol names to GSimpleActions */ /* dial_actions_by_protocol maps protocol names to GSimpleActions */
@ -123,16 +139,17 @@ set_state_flags (CallsManager *self, CallsManagerFlags state_flags)
static void static void
update_state_flags (CallsManager *self) update_state_flags (CallsManager *self)
{ {
GHashTableIter iter;
gpointer value;
CallsManagerFlags state_flags = CALLS_MANAGER_FLAGS_UNKNOWN; CallsManagerFlags state_flags = CALLS_MANAGER_FLAGS_UNKNOWN;
GListModel *providers;
guint n_providers;
g_assert (CALLS_IS_MANAGER (self)); g_assert (CALLS_IS_MANAGER (self));
g_hash_table_iter_init (&iter, self->providers); providers = calls_plugin_manager_get_providers (calls_plugin_manager_get_default ());
while (g_hash_table_iter_next (&iter, NULL, &value)) { n_providers = g_list_model_get_n_items (providers);
CallsProvider *provider = CALLS_PROVIDER (value); for (guint i = 0; i < n_providers; i++) {
g_autoptr (CallsProvider) provider = g_list_model_get_item (providers, i);
if (calls_provider_is_modem (provider)) { if (calls_provider_is_modem (provider)) {
state_flags |= CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER; state_flags |= CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER;
@ -242,6 +259,8 @@ add_call (CallsManager *self, CallsCall *call, CallsOrigin *origin)
call_data = calls_ui_call_data_new (call, origin_id); call_data = calls_ui_call_data_new (call, origin_id);
g_hash_table_insert (self->calls, call, call_data); g_hash_table_insert (self->calls, call, call_data);
g_object_set_data (G_OBJECT (call), "call-origin", origin);
g_signal_emit (self, signals[UI_CALL_ADDDED], 0, call_data); g_signal_emit (self, signals[UI_CALL_ADDDED], 0, call_data);
} }
@ -363,8 +382,6 @@ add_origin (CallsManager *self, CallsOrigin *origin)
name = calls_origin_get_name (origin); name = calls_origin_get_name (origin);
g_debug ("Adding origin %s (%p)", name, origin); g_debug ("Adding origin %s (%p)", name, origin);
g_list_store_append (self->origins, origin);
g_signal_connect_object (origin, g_signal_connect_object (origin,
"message", "message",
G_CALLBACK (on_message), G_CALLBACK (on_message),
@ -388,238 +405,27 @@ add_origin (CallsManager *self, CallsOrigin *origin)
calls_origin_foreach_call (origin, (CallsOriginForeachCallFunc) add_call, self); calls_origin_foreach_call (origin, (CallsOriginForeachCallFunc) add_call, self);
} }
static void static void
remove_call_cb (gpointer self, CallsCall *call, CallsOrigin *origin) on_origins_changed (GListModel *model,
guint position,
guint removed,
guint added,
CallsManager *self)
{ {
remove_call (self, call, NULL, origin);
}
static void
remove_origin (CallsManager *self, CallsOrigin *origin)
{
g_autofree const char *name = NULL;
guint position;
g_assert (CALLS_IS_MANAGER (self)); g_assert (CALLS_IS_MANAGER (self));
g_assert (CALLS_IS_ORIGIN (origin)); g_assert (model == G_LIST_MODEL (self->origins_flat));
name = calls_origin_get_name (origin); for (guint i = 0; i < added; i++) {
g_debug ("Removing origin %s (%p)", name, origin); g_autoptr (CallsOrigin) origin = g_list_model_get_item (model, position + i);
g_signal_handlers_disconnect_by_data (origin, self); add_origin (self, origin);
calls_origin_foreach_call (origin, remove_call_cb, self);
if (!g_list_store_find (self->origins, origin, &position))
g_warning ("Origin %p not found in list store while trying to remove it",
origin);
else
g_list_store_remove (self->origins, position);
}
/* rebuild_origins_by_protocols() when any origins were added or removed */
static void
rebuild_origins_by_protocols (CallsManager *self)
{
GHashTableIter iter;
gpointer value;
guint n_origins;
g_assert (CALLS_IS_MANAGER (self));
/* Remove everything */
g_hash_table_iter_init (&iter, self->origins_by_protocol);
while (g_hash_table_iter_next (&iter, NULL, &value)) {
GListStore *store = G_LIST_STORE (value);
g_list_store_remove_all (store);
}
/* Iterate over all origins and check which protocols they support */
n_origins = g_list_model_get_n_items (G_LIST_MODEL (self->origins));
for (guint i = 0; i < n_origins; i++) {
g_autoptr (CallsOrigin) origin =
g_list_model_get_item (G_LIST_MODEL (self->origins), i);
for (guint j = 0; j < G_N_ELEMENTS (protocols); j++) {
GListStore *store =
G_LIST_STORE (g_hash_table_lookup (self->origins_by_protocol, protocols[j]));
g_assert (store);
if (calls_origin_supports_protocol (origin, protocols[j]))
g_list_store_append (store, origin);
}
} }
update_state_flags (self);
update_protocol_dial_actions (self); update_protocol_dial_actions (self);
} }
static void
remove_provider (CallsManager *self,
const char *name)
{
g_autoptr (CallsProvider) provider = NULL;
GListModel *origins;
guint n_items;
g_assert (CALLS_IS_MANAGER (self));
g_assert (name);
provider = g_hash_table_lookup (self->providers, name);
if (provider) {
/* Hold a ref since g_hash_table_remove () might drop the last one */
g_object_ref (provider);
} else {
g_warning ("Trying to remove provider %s which has not been found", name);
return;
}
g_debug ("Remove provider: %s", name);
g_signal_handlers_disconnect_by_data (provider, self);
origins = calls_provider_get_origins (provider);
g_signal_handlers_disconnect_by_data (origins, self);
n_items = g_list_model_get_n_items (origins);
for (guint i = 0; i < n_items; i++) {
g_autoptr (CallsOrigin) origin = NULL;
origin = g_list_model_get_item (origins, i);
remove_origin (self, origin);
}
g_hash_table_remove (self->providers, name);
calls_provider_unload_plugin (name);
rebuild_origins_by_protocols (self);
update_state_flags (self);
g_signal_emit (self, signals[PROVIDERS_CHANGED], 0);
}
static gboolean
origin_found_in_any_provider (CallsManager *self,
CallsOrigin *origin)
{
GHashTableIter iter;
gpointer value;
g_return_val_if_fail (CALLS_IS_MANAGER (self), FALSE);
g_return_val_if_fail (CALLS_IS_ORIGIN (origin), FALSE);
g_hash_table_iter_init (&iter, self->providers);
while (g_hash_table_iter_next (&iter, NULL, &value)) {
guint position;
CallsProvider *provider = CALLS_PROVIDER (value);
GListModel *origins = calls_provider_get_origins (provider);
if (origins && calls_find_in_model (origins,
origin,
&position))
return TRUE;
}
return FALSE;
}
static void
origin_items_changed_cb (GListModel *model,
guint position,
guint removed,
guint added,
CallsManager *self)
{
guint i;
CallsOrigin *origin;
guint purged = 0;
guint total_origins;
g_assert (CALLS_IS_MANAGER (self));
total_origins = g_list_model_get_n_items (G_LIST_MODEL (self->origins));
g_debug ("origins changed: pos=%d rem=%d added=%d total=%d",
position, removed, added, g_list_model_get_n_items (model));
/* Check stale/removed origins: We need to look up */
if (removed == 0)
goto skip_remove;
for (i = 0; i < total_origins - purged; i++) {
origin = g_list_model_get_item (G_LIST_MODEL (self->origins), i - purged);
if (!origin_found_in_any_provider (self, origin)) {
remove_origin (self, origin);
purged++;
}
}
/** The number of purged entries from self->origins must be equal to removed
* origins from the providers list
*/
if (purged != removed) {
g_warning ("Managed origins are not in sync anymore!");
}
skip_remove:
for (i = 0; i < added; i++) {
g_debug ("before adding: %d",
g_list_model_get_n_items (G_LIST_MODEL (self->origins)));
origin = g_list_model_get_item (model, position + i);
add_origin (self, origin); // add to list store
g_object_unref (origin);
g_debug ("after adding: %d",
g_list_model_get_n_items (G_LIST_MODEL (self->origins)));
}
rebuild_origins_by_protocols (self);
update_state_flags (self);
}
static void
add_provider (CallsManager *self, const gchar *name)
{
GListModel *origins;
CallsProvider *provider;
guint n_items;
g_assert (CALLS_IS_MANAGER (self));
g_assert (name);
if (g_hash_table_lookup (self->providers, name))
return;
provider = calls_provider_load_plugin (name);
if (provider == NULL) {
g_warning ("Could not load a plugin with name `%s'", name);
return;
}
g_hash_table_insert (self->providers, g_strdup (name), provider);
origins = calls_provider_get_origins (provider);
g_signal_connect_object (origins, "items-changed",
G_CALLBACK (origin_items_changed_cb), self,
G_CONNECT_AFTER);
n_items = g_list_model_get_n_items (origins);
origin_items_changed_cb (origins, 0, 0, n_items, self);
g_signal_emit (self, signals[PROVIDERS_CHANGED], 0);
}
static void static void
calls_manager_get_property (GObject *object, calls_manager_get_property (GObject *object,
guint property_id, guint property_id,
@ -649,7 +455,6 @@ calls_manager_finalize (GObject *object)
g_clear_object (&self->contacts_provider); g_clear_object (&self->contacts_provider);
g_clear_pointer (&self->origins_by_protocol, g_hash_table_unref); g_clear_pointer (&self->origins_by_protocol, g_hash_table_unref);
g_clear_pointer (&self->providers, g_hash_table_unref);
g_clear_pointer (&self->dial_actions_by_protocol, g_hash_table_unref); g_clear_pointer (&self->dial_actions_by_protocol, g_hash_table_unref);
G_OBJECT_CLASS (calls_manager_parent_class)->finalize (object); G_OBJECT_CLASS (calls_manager_parent_class)->finalize (object);
@ -736,36 +541,101 @@ calls_manager_class_init (CallsManagerClass *klass)
} }
static void
on_providers_changed (GListModel *model,
guint position,
guint removed,
guint added,
CallsManager *self)
{
g_autoptr (GPtrArray) origins_add = g_ptr_array_sized_new (added);
g_assert (CALLS_IS_MANAGER (self));
g_debug ("Provider changed at pos %u; removed %u; added %u",
position, removed, added);
for (guint i = 0; i < added; i++) {
g_autoptr (CallsProvider) provider =
g_list_model_get_item (model, position + i);
g_ptr_array_add (origins_add, calls_provider_get_origins (provider));
g_debug ("Adding provider %s with %u items",
calls_provider_get_name (provider),
g_list_model_get_n_items (calls_provider_get_origins (provider)));
}
g_list_store_splice (self->origins,
position,
removed,
origins_add->pdata,
added);
if (removed > 0) {
GHashTableIter calls_iter;
gpointer key;
g_hash_table_iter_init (&calls_iter, self->calls);
while (g_hash_table_iter_next (&calls_iter, &key, NULL)) {
gpointer origin = g_object_get_data (G_OBJECT (key), "call-origin");
if (!calls_find_in_model (G_LIST_MODEL (self->origins_flat), origin, NULL))
calls_call_hang_up (CALLS_CALL (key));
}
}
update_state_flags (self);
}
static void static void
calls_manager_init (CallsManager *self) calls_manager_init (CallsManager *self)
{ {
g_autoptr (GVariantType) variant_type = NULL; g_autoptr (GVariantType) variant_type = NULL;
GApplication *application; GApplication *application;
PeasEngine *peas; CallsPluginManager *plugin_manager = calls_plugin_manager_get_default ();
const gchar *dir; GListModel *providers;
g_autofree char *default_plugin_dir_provider = NULL;
self->state_flags = CALLS_MANAGER_FLAGS_UNKNOWN; self->state_flags = CALLS_MANAGER_FLAGS_UNKNOWN;
self->providers = g_hash_table_new_full (g_str_hash,
g_str_equal, self->origins = g_list_store_new (G_TYPE_LIST_MODEL); /* list of lists */
g_free, self->origins_flat = gtk_flatten_list_model_new (CALLS_TYPE_ORIGIN, G_LIST_MODEL (self->origins));
g_object_unref);
g_signal_connect_object (self->origins_flat,
"items-changed",
G_CALLBACK (on_origins_changed),
self,
0);
providers = calls_plugin_manager_get_providers (plugin_manager);
g_signal_connect_object (providers,
"items-changed",
G_CALLBACK (on_providers_changed),
self,
0); /* G_CONNECT_DEFAULT */
if (g_list_model_get_n_items (providers) > 0)
on_providers_changed (providers, 0, 0, g_list_model_get_n_items (providers), self);
self->origins_by_protocol = g_hash_table_new_full (g_str_hash, self->origins_by_protocol = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, NULL,
g_object_unref); g_object_unref);
for (guint i = 0; i < G_N_ELEMENTS (protocols); i++) { for (guint i = 0; i < G_N_ELEMENTS (protocols); i++) {
GListStore *origin_store = g_list_store_new (calls_origin_get_type ()); g_autoptr (GtkFilter) filter =
gtk_custom_filter_new (match_origin_supports_protocol, (gpointer) protocols[i], NULL);
GtkFilterListModel *f_list =
gtk_filter_list_model_new (G_LIST_MODEL (self->origins_flat), filter);
g_debug ("Adding filter list model for protocol '%s'", protocols[i]);
g_hash_table_insert (self->origins_by_protocol, g_hash_table_insert (self->origins_by_protocol,
g_strdup (protocols[i]), (gpointer) protocols[i],
origin_store); f_list);
} }
self->dial_actions_by_protocol = g_hash_table_new_full (g_str_hash, self->dial_actions_by_protocol = g_hash_table_new_full (g_str_hash,
g_str_equal, g_str_equal,
g_free, NULL,
g_object_unref); g_object_unref);
application = g_application_get_default (); application = g_application_get_default ();
@ -780,7 +650,7 @@ calls_manager_init (CallsManager *self)
self); self);
g_hash_table_insert (self->dial_actions_by_protocol, g_hash_table_insert (self->dial_actions_by_protocol,
g_strdup (protocols[i]), (gpointer) protocols[i],
g_object_ref (action)); g_object_ref (action));
/* Enable action if there are suitable origins */ /* Enable action if there are suitable origins */
@ -791,36 +661,12 @@ calls_manager_init (CallsManager *self)
g_action_map_add_action (G_ACTION_MAP (application), G_ACTION (action)); g_action_map_add_action (G_ACTION_MAP (application), G_ACTION (action));
} }
self->origins = g_list_store_new (calls_origin_get_type ());
/* This hash table only owns the value, not the key */ /* This hash table only owns the value, not the key */
self->calls = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); self->calls = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
self->settings = calls_settings_get_default (); self->settings = calls_settings_get_default ();
// Load the contacts provider /* Load the contacts provider */
self->contacts_provider = calls_contacts_provider_new (); self->contacts_provider = calls_contacts_provider_new ();
peas = peas_engine_get_default ();
dir = g_getenv ("CALLS_PLUGIN_DIR");
if (dir && dir[0] != '\0') {
g_autofree char *plugin_dir_provider = NULL;
plugin_dir_provider = g_build_filename (dir, "provider", NULL);
if (g_file_test (plugin_dir_provider, G_FILE_TEST_EXISTS)) {
g_debug ("Adding %s to plugin search path", plugin_dir_provider);
peas_engine_prepend_search_path (peas, plugin_dir_provider, NULL);
} else {
g_warning ("Not adding %s to plugin search path, because the directory doesn't exist. Check if env CALLS_PLUGIN_DIR is set correctly", plugin_dir_provider);
}
}
default_plugin_dir_provider = g_build_filename(PLUGIN_LIBDIR, "provider", NULL);
peas_engine_add_search_path (peas, default_plugin_dir_provider, NULL);
g_debug ("Scanning for plugins in `%s'", default_plugin_dir_provider);
peas_engine_rescan_plugins (peas);
} }
@ -853,55 +699,6 @@ calls_manager_get_contacts_provider (CallsManager *self)
} }
void
calls_manager_add_provider (CallsManager *self,
const char *name)
{
g_return_if_fail (CALLS_IS_MANAGER (self));
g_return_if_fail (name);
add_provider (self, name);
}
void
calls_manager_remove_provider (CallsManager *self,
const char *name)
{
g_return_if_fail (CALLS_IS_MANAGER (self));
g_return_if_fail (name);
remove_provider (self, name);
}
gboolean
calls_manager_has_provider (CallsManager *self,
const char *name)
{
g_return_val_if_fail (CALLS_IS_MANAGER (self), FALSE);
g_return_val_if_fail (name, FALSE);
return !!g_hash_table_lookup (self->providers, name);
}
gboolean
calls_manager_is_modem_provider (CallsManager *self,
const char *name)
{
CallsProvider *provider;
g_return_val_if_fail (CALLS_IS_MANAGER (self), FALSE);
g_return_val_if_fail (name, FALSE);
provider = g_hash_table_lookup (self->providers, name);
g_return_val_if_fail (provider, FALSE);
return calls_provider_is_modem (provider);
}
CallsManagerFlags CallsManagerFlags
calls_manager_get_state_flags (CallsManager *self) calls_manager_get_state_flags (CallsManager *self)
{ {
@ -916,7 +713,7 @@ calls_manager_get_origins (CallsManager *self)
{ {
g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL); g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL);
return G_LIST_MODEL (self->origins); return G_LIST_MODEL (self->origins_flat);
} }
@ -952,7 +749,7 @@ calls_manager_hang_up_all_calls (CallsManager *self)
g_return_if_fail (CALLS_IS_MANAGER (self)); g_return_if_fail (CALLS_IS_MANAGER (self));
origins = G_LIST_MODEL (self->origins); origins = G_LIST_MODEL (self->origins_flat);
n_items = g_list_model_get_n_items (origins); n_items = g_list_model_get_n_items (origins);
for (uint i = 0; i < n_items; i++) { for (uint i = 0; i < n_items; i++) {
@ -996,58 +793,6 @@ calls_manager_get_suitable_origins (CallsManager *self,
return NULL; return NULL;
} }
/**
* calls_manager_has_any_provider:
* @self: The #CallsManager
*
* Returns: %TRUE if any provider is loaded, %FALSE otherwise
*/
gboolean
calls_manager_has_any_provider (CallsManager *self)
{
g_return_val_if_fail (CALLS_IS_MANAGER (self), FALSE);
return !!g_hash_table_size (self->providers);
}
/**
* calls_manager_get_provider_names:
* @self: The #CallsManager
* @length: (optional) (out): the length of the returned array
*
* Retrieves the names of all providers loaded by @self, as an array.
*
* You should free the return value with g_free().
*
* Returns: (array length=length) (transfer container): a
* %NULL-terminated array containing the names of providers.
*/
const char **
calls_manager_get_provider_names (CallsManager *self,
guint *length)
{
g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL);
return (const char **) g_hash_table_get_keys_as_array (self->providers, length);
}
/**
* calls_manager_get_providers:
* @self: A #CallsManager
*
* Get the currently loaded providers
*
* Returns: (transfer container): A #GList of #CallsProvider.
* Use g_list_free() when done using the list.
*/
GList *
calls_manager_get_providers (CallsManager *self)
{
g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL);
return g_hash_table_get_values (self->providers);
}
CallsSettings * CallsSettings *
calls_manager_get_settings (CallsManager *self) calls_manager_get_settings (CallsManager *self)
@ -1076,10 +821,10 @@ calls_manager_get_origin_by_id (CallsManager *self,
if (STR_IS_NULL_OR_EMPTY (origin_id)) if (STR_IS_NULL_OR_EMPTY (origin_id))
return NULL; return NULL;
n_origins = g_list_model_get_n_items (G_LIST_MODEL (self->origins)); n_origins = g_list_model_get_n_items (G_LIST_MODEL (self->origins_flat));
for (uint i = 0; i < n_origins; i++) { for (uint i = 0; i < n_origins; i++) {
g_autoptr (CallsOrigin) origin = g_autoptr (CallsOrigin) origin =
g_list_model_get_item (G_LIST_MODEL (self->origins), i); g_list_model_get_item (G_LIST_MODEL (self->origins_flat), i);
g_autofree char *id = calls_origin_get_id (origin); g_autofree char *id = calls_origin_get_id (origin);
if (g_strcmp0 (id, origin_id) == 0) if (g_strcmp0 (id, origin_id) == 0)

View file

@ -51,14 +51,6 @@ CallsManager *calls_manager_new (void);
CallsManager *calls_manager_get_default (void); CallsManager *calls_manager_get_default (void);
CallsContactsProvider *calls_manager_get_contacts_provider (CallsManager *self); CallsContactsProvider *calls_manager_get_contacts_provider (CallsManager *self);
CallsSettings *calls_manager_get_settings (CallsManager *self); CallsSettings *calls_manager_get_settings (CallsManager *self);
void calls_manager_add_provider (CallsManager *self,
const char *name);
void calls_manager_remove_provider (CallsManager *self,
const char *name);
gboolean calls_manager_has_provider (CallsManager *self,
const char *name);
gboolean calls_manager_is_modem_provider (CallsManager *self,
const char *name);
CallsManagerFlags calls_manager_get_state_flags (CallsManager *self); CallsManagerFlags calls_manager_get_state_flags (CallsManager *self);
GListModel *calls_manager_get_origins (CallsManager *self); GListModel *calls_manager_get_origins (CallsManager *self);
GList *calls_manager_get_calls (CallsManager *self); GList *calls_manager_get_calls (CallsManager *self);
@ -67,9 +59,5 @@ GListModel *calls_manager_get_suitable_origins (CallsManager *sel
CallsOrigin *calls_manager_get_origin_by_id (CallsManager *self, CallsOrigin *calls_manager_get_origin_by_id (CallsManager *self,
const char *origin_id); const char *origin_id);
void calls_manager_hang_up_all_calls (CallsManager *self); void calls_manager_hang_up_all_calls (CallsManager *self);
gboolean calls_manager_has_any_provider (CallsManager *self);
const char **calls_manager_get_provider_names (CallsManager *self,
guint *length);
GList *calls_manager_get_providers (CallsManager *self);
G_END_DECLS G_END_DECLS

View file

@ -187,72 +187,6 @@ calls_provider_get_origins (CallsProvider *self)
return CALLS_PROVIDER_GET_CLASS (self)->get_origins (self); return CALLS_PROVIDER_GET_CLASS (self)->get_origins (self);
} }
/**
* calls_provider_load_plugin:
* @name: The name of the provider plugin to load
*
* Get a #CallsProvider plugin by name
*
* Returns: (transfer full): A #CallsProvider
*/
CallsProvider *
calls_provider_load_plugin (const char *name)
{
g_autoptr (GError) error = NULL;
PeasEngine *plugins;
PeasPluginInfo *info;
PeasExtension *extension;
plugins = peas_engine_get_default ();
// Find the plugin
info = peas_engine_get_plugin_info (plugins, name);
if (!info) {
g_debug ("Could not find plugin `%s'", name);
return NULL;
}
// Possibly load the plugin
if (!peas_plugin_info_is_loaded (info)) {
peas_engine_load_plugin (plugins, info);
if (!peas_plugin_info_is_available (info, &error)) {
g_debug ("Error loading plugin `%s': %s", name, error->message);
return NULL;
}
g_debug ("Loaded plugin `%s'", name);
}
// Check the plugin provides CallsProvider
if (!peas_engine_provides_extension (plugins, info, CALLS_TYPE_PROVIDER)) {
g_debug ("Plugin `%s' does not have a provider extension", name);
return NULL;
}
// Get the extension
extension = peas_engine_create_extensionv (plugins, info, CALLS_TYPE_PROVIDER, 0, NULL);
if (!extension) {
g_debug ("Could not create provider from plugin `%s'", name);
return NULL;
}
g_debug ("Created provider from plugin `%s'", name);
return CALLS_PROVIDER (extension);
}
void
calls_provider_unload_plugin (const char *name)
{
PeasEngine *engine = peas_engine_get_default ();
PeasPluginInfo *plugin = peas_engine_get_plugin_info (engine, name);
if (plugin)
peas_engine_unload_plugin (engine, plugin);
else
g_warning ("Can't unload plugin: No plugin with name %s found", name);
}
/** /**
* calls_provider_get_protocols: * calls_provider_get_protocols:
* @self: A #CallsProvider * @self: A #CallsProvider

View file

@ -53,8 +53,6 @@ struct _CallsProviderClass {
const char *calls_provider_get_name (CallsProvider *self); const char *calls_provider_get_name (CallsProvider *self);
const char *calls_provider_get_status (CallsProvider *self); const char *calls_provider_get_status (CallsProvider *self);
GListModel *calls_provider_get_origins (CallsProvider *self); GListModel *calls_provider_get_origins (CallsProvider *self);
CallsProvider *calls_provider_load_plugin (const char *name);
void calls_provider_unload_plugin (const char *name);
const char *const *calls_provider_get_protocols (CallsProvider *self); const char *const *calls_provider_get_protocols (CallsProvider *self);
gboolean calls_provider_is_modem (CallsProvider *self); gboolean calls_provider_is_modem (CallsProvider *self);
gboolean calls_provider_is_operational (CallsProvider *self); gboolean calls_provider_is_operational (CallsProvider *self);

View file

@ -52,7 +52,6 @@ t = executable('emergency-call-types', test_sources,
) )
test('emergency-call-types', t, env: test_env) test('emergency-call-types', t, env: test_env)
test_sources = [ 'test-manager.c' ] test_sources = [ 'test-manager.c' ]
t = executable('manager', test_sources, t = executable('manager', test_sources,

View file

@ -11,6 +11,7 @@
#include "calls-manager.h" #include "calls-manager.h"
#include "calls-dbus-manager.h" #include "calls-dbus-manager.h"
#include "calls-plugin-manager.h"
#include <glib-unix.h> #include <glib-unix.h>
@ -51,8 +52,10 @@ int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
g_autoptr (CallsManager) manager = NULL; g_autoptr (CallsManager) manager = NULL;
CallsDBusManager *dbus_manager = NULL; g_autoptr (CallsPluginManager) plugin_manager = NULL;
g_autoptr (GMainLoop) loop = g_main_loop_new (NULL, FALSE); g_autoptr (GMainLoop) loop = g_main_loop_new (NULL, FALSE);
g_autoptr (GError) error = NULL;
CallsDBusManager *dbus_manager = NULL;
guint bus_id; guint bus_id;
/* Setup environment */ /* Setup environment */
@ -62,9 +65,11 @@ main (int argc, char *argv[])
g_print ("Starting up DBus service\n"); g_print ("Starting up DBus service\n");
plugin_manager = calls_plugin_manager_get_default ();
manager = calls_manager_get_default (); manager = calls_manager_get_default ();
dbus_manager = calls_dbus_manager_new (); dbus_manager = calls_dbus_manager_new ();
calls_manager_add_provider (manager, "dummy"); g_assert_true (calls_plugin_manager_load_plugin (plugin_manager, "dummy", &error));
g_assert_no_error (error);
bus_id = g_bus_own_name (G_BUS_TYPE_SESSION, bus_id = g_bus_own_name (G_BUS_TYPE_SESSION,
CALLS_DBUS_NAME, CALLS_DBUS_NAME,
@ -79,7 +84,8 @@ main (int argc, char *argv[])
g_print ("Shutting down DBus service\n"); g_print ("Shutting down DBus service\n");
calls_manager_remove_provider (manager, "dummy"); g_assert_true (calls_plugin_manager_unload_plugin (plugin_manager, "dummy", &error));
g_assert_no_error (error);
/* The DBus manager unexports any objects it may still have. /* The DBus manager unexports any objects it may still have.
* Do this before releasing the DBus name ownership */ * Do this before releasing the DBus name ownership */

View file

@ -5,6 +5,8 @@
*/ */
#include "calls-manager.h" #include "calls-manager.h"
#include "calls-plugin-manager.h"
#include "calls-util.h"
#include <cui-call.h> #include <cui-call.h>
#include <glib.h> #include <glib.h>
@ -12,6 +14,7 @@
struct TestData { struct TestData {
GMainLoop *loop; GMainLoop *loop;
CallsManager *manager; CallsManager *manager;
CallsPluginManager *plugin_manager;
GListModel *origins; GListModel *origins;
GListModel *origins_tel; GListModel *origins_tel;
CallsOrigin *origin; CallsOrigin *origin;
@ -24,6 +27,7 @@ call_add_cb (CallsManager *manager,
struct TestData *data) struct TestData *data)
{ {
static guint phase = 0; static guint phase = 0;
g_autoptr (GError) error = NULL;
data->call = call; data->call = call;
switch (phase++) { switch (phase++) {
@ -33,9 +37,11 @@ call_add_cb (CallsManager *manager,
case 1: case 1:
/* Unload the provider */ /* Unload the provider */
calls_manager_remove_provider (data->manager, "dummy"); calls_plugin_manager_unload_plugin (data->plugin_manager, "dummy", &error);
g_assert_false (calls_manager_has_provider (data->manager, "dummy")); g_assert_false (calls_plugin_manager_has_plugin (data->plugin_manager, "dummy"));
g_assert_false (calls_manager_has_any_provider (data->manager)); g_assert_false (calls_plugin_manager_has_any_plugins (data->plugin_manager));
g_assert_cmpuint (g_list_model_get_n_items (calls_manager_get_origins (data->manager)),
==, 0);
break; break;
@ -72,19 +78,20 @@ call_remove_cb (CallsManager *manager,
static void static void
test_calls_manager_without_provider (void) test_calls_manager_without_provider (void)
{ {
guint no_origins;
GListModel *origins; GListModel *origins;
g_autoptr (CallsManager) manager = calls_manager_new (); CallsManager *manager = calls_manager_get_default ();
CallsPluginManager *plugin_manager = calls_plugin_manager_get_default ();
g_assert_true (CALLS_IS_MANAGER (manager)); g_assert_true (CALLS_IS_MANAGER (manager));
g_assert_true (CALLS_IS_PLUGIN_MANAGER (plugin_manager));
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN); g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN);
origins = calls_manager_get_origins (manager); origins = calls_manager_get_origins (manager);
no_origins = g_list_model_get_n_items (origins); g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
g_assert_cmpuint (no_origins, ==, 0);
g_assert_null (calls_manager_get_calls (manager)); g_assert_null (calls_manager_get_calls (manager));
g_assert_false (calls_manager_has_any_provider (manager)); g_assert_false (calls_plugin_manager_has_any_plugins (plugin_manager));
origins = calls_manager_get_suitable_origins (manager, "tel:+123456789"); origins = calls_manager_get_suitable_origins (manager, "tel:+123456789");
g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0); g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
@ -94,11 +101,16 @@ test_calls_manager_without_provider (void)
origins = calls_manager_get_suitable_origins (manager, "sips:bob@example.org"); origins = calls_manager_get_suitable_origins (manager, "sips:bob@example.org");
g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0); g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
g_assert_finalize_object (manager);
g_assert_finalize_object (plugin_manager);
} }
static void static void
test_calls_manager_dummy_provider (void) test_calls_manager_dummy_provider (void)
{ {
g_autoptr (GError) error = NULL;
CallsManager *manager; CallsManager *manager;
GListModel *origins; GListModel *origins;
GListModel *origins_tel; GListModel *origins_tel;
@ -106,7 +118,9 @@ test_calls_manager_dummy_provider (void)
struct TestData *test_data; struct TestData *test_data;
test_data = g_new0 (struct TestData, 1); test_data = g_new0 (struct TestData, 1);
test_data->manager = calls_manager_new (); test_data->manager = calls_manager_get_default ();
test_data->plugin_manager = calls_plugin_manager_get_default ();
manager = test_data->manager; manager = test_data->manager;
g_assert_true (CALLS_IS_MANAGER (manager)); g_assert_true (CALLS_IS_MANAGER (manager));
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN); g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN);
@ -117,9 +131,11 @@ test_calls_manager_dummy_provider (void)
g_assert_true (origins); g_assert_true (origins);
g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0); g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
calls_manager_add_provider (manager, "dummy"); g_assert_true (calls_plugin_manager_load_plugin (test_data->plugin_manager, "dummy", &error));
g_assert_true (calls_manager_has_any_provider (manager)); g_assert_no_error (error);
g_assert_true (calls_manager_has_provider (manager, "dummy"));
g_assert_true (calls_plugin_manager_has_any_plugins (test_data->plugin_manager));
g_assert_true (calls_plugin_manager_has_plugin (test_data->plugin_manager, "dummy"));
/* Dummy plugin fakes being a modem */ /* Dummy plugin fakes being a modem */
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, g_assert_cmpuint (calls_manager_get_state_flags (manager), ==,
CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER | CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER |
@ -134,8 +150,7 @@ test_calls_manager_dummy_provider (void)
test_data->origins_tel = calls_manager_get_suitable_origins (manager, "tel:+393422342"); test_data->origins_tel = calls_manager_get_suitable_origins (manager, "tel:+393422342");
origins_tel = test_data->origins_tel; origins_tel = test_data->origins_tel;
g_assert_true (G_IS_LIST_MODEL (origins_tel)); g_assert_true (G_IS_LIST_MODEL (origins_tel));
g_assert_true (G_IS_LIST_STORE (origins_tel)); g_assert_true (calls_find_in_model (origins_tel, test_data->origin, &position));
g_assert_true (g_list_store_find (G_LIST_STORE (origins_tel), test_data->origin, &position));
g_signal_connect (manager, "ui-call-added", G_CALLBACK (call_add_cb), test_data); g_signal_connect (manager, "ui-call-added", G_CALLBACK (call_add_cb), test_data);
g_signal_connect (manager, "ui-call-removed", G_CALLBACK (call_remove_cb), test_data); g_signal_connect (manager, "ui-call-removed", G_CALLBACK (call_remove_cb), test_data);
@ -155,22 +170,29 @@ test_calls_manager_dummy_provider (void)
g_assert_finalize_object (test_data->origin); g_assert_finalize_object (test_data->origin);
g_assert_finalize_object (test_data->manager); g_assert_finalize_object (test_data->manager);
g_assert_finalize_object (test_data->plugin_manager);
g_free (test_data); g_free (test_data);
} }
static void static void
test_calls_manager_mm_provider (void) test_calls_manager_mm_provider (void)
{ {
GListModel *origins_tel; GListModel *origins_tel;
g_autoptr (CallsManager) manager = calls_manager_new (); CallsManager *manager = calls_manager_get_default ();
CallsPluginManager *plugin_manager = calls_plugin_manager_get_default ();
g_autoptr (GError) error = NULL;
g_assert_true (CALLS_IS_MANAGER (manager)); g_assert_true (CALLS_IS_MANAGER (manager));
g_assert_true (CALLS_IS_PLUGIN_MANAGER (plugin_manager));
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN); g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN);
calls_manager_add_provider (manager, "mm"); g_assert_true (calls_plugin_manager_load_plugin (plugin_manager, "mm", &error));
g_assert_true (calls_manager_has_any_provider (manager)); g_assert_no_error (error);
g_assert_true (calls_manager_has_provider (manager, "mm")); g_assert_true (calls_plugin_manager_has_any_plugins (plugin_manager));
g_assert_true (calls_plugin_manager_has_plugin (plugin_manager, "mm"));
g_assert_cmpuint (calls_manager_get_state_flags (manager), >, CALLS_MANAGER_FLAGS_UNKNOWN); g_assert_cmpuint (calls_manager_get_state_flags (manager), >, CALLS_MANAGER_FLAGS_UNKNOWN);
@ -180,22 +202,28 @@ test_calls_manager_mm_provider (void)
g_assert_nonnull (origins_tel); g_assert_nonnull (origins_tel);
g_assert_cmpuint (g_list_model_get_n_items (origins_tel), ==, 0); g_assert_cmpuint (g_list_model_get_n_items (origins_tel), ==, 0);
calls_manager_remove_provider (manager, "mm"); g_assert_true (calls_plugin_manager_unload_plugin (plugin_manager, "mm", &error));
g_assert_no_error (error);
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN); g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_UNKNOWN);
g_assert_finalize_object (manager);
g_assert_finalize_object (plugin_manager);
} }
static void static void
test_calls_manager_multiple_providers_mm_sip (void) test_calls_manager_multiple_providers_mm_sip (void)
{ {
g_autoptr (CallsOrigin) origin_alice = NULL; CallsManager *manager = calls_manager_get_default ();
g_autoptr (CallsOrigin) origin_bob = NULL; CallsPluginManager *plugin_manager = calls_plugin_manager_get_default ();
g_autoptr (CallsManager) manager = calls_manager_new ();
GListModel *origins; GListModel *origins;
GListModel *origins_tel; GListModel *origins_tel;
GListModel *origins_sip; GListModel *origins_sip;
GListModel *origins_sips; GListModel *origins_sips;
g_autoptr (GError) error = NULL;
g_assert_true (CALLS_IS_MANAGER (manager)); g_assert_true (CALLS_IS_MANAGER (manager));
g_assert_true (CALLS_IS_PLUGIN_MANAGER (plugin_manager));
origins = calls_manager_get_origins (manager); origins = calls_manager_get_origins (manager);
g_assert_true (G_IS_LIST_MODEL (origins)); g_assert_true (G_IS_LIST_MODEL (origins));
@ -215,10 +243,7 @@ test_calls_manager_multiple_providers_mm_sip (void)
g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0); g_assert_cmpuint (g_list_model_get_n_items (origins), ==, 0);
/* First add the SIP provider, MM provider later */ /* First add the SIP provider, MM provider later */
calls_manager_add_provider (manager, "sip"); g_assert_true (calls_plugin_manager_load_plugin (plugin_manager, "sip", &error));
g_assert_true (calls_manager_has_any_provider (manager));
g_assert_true (calls_manager_has_provider (manager, "sip"));
g_assert_true (calls_manager_is_modem_provider (manager, "sip") == FALSE);
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_HAS_VOIP_PROVIDER); g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, CALLS_MANAGER_FLAGS_HAS_VOIP_PROVIDER);
/* Still no origins */ /* Still no origins */
@ -237,13 +262,13 @@ test_calls_manager_multiple_providers_mm_sip (void)
* see https://source.puri.sm/Librem5/calls/-/issues/280 * see https://source.puri.sm/Librem5/calls/-/issues/280
* and https://source.puri.sm/Librem5/calls/-/issues/178 * and https://source.puri.sm/Librem5/calls/-/issues/178
*/ */
calls_manager_add_provider (manager, "mm"); g_assert_true (calls_plugin_manager_load_plugin (plugin_manager, "mm", &error));
g_assert_true (calls_manager_has_any_provider (manager));
g_assert_true (calls_manager_has_provider (manager, "mm"));
g_assert_cmpuint (calls_manager_get_state_flags (manager), ==, g_assert_cmpuint (calls_manager_get_state_flags (manager), ==,
CALLS_MANAGER_FLAGS_HAS_VOIP_PROVIDER | CALLS_MANAGER_FLAGS_HAS_VOIP_PROVIDER |
CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER); CALLS_MANAGER_FLAGS_HAS_CELLULAR_PROVIDER);
g_assert_finalize_object (manager);
g_assert_finalize_object (plugin_manager);
} }
gint gint