provider: Use GListModel to track origins

And adapt to changes

It's easier to track changes if we are using GListModel than
a GList.  Also, eventually we shall have multiple providers,
and we can use GtkFlattenListModel to merge multiple origins
without manually managing pointers ourself.

Since several widgets has APIs to handle GListModels, it will
also help us create widgets from GListModels easily.
This commit is contained in:
Mohammed Sadiq
2021-02-15 11:04:34 +05:30
parent b5645c4cca
commit eda460ac15
16 changed files with 274 additions and 366 deletions

View File

@@ -35,7 +35,7 @@ struct _CallsDummyProvider
{
CallsProvider parent_instance;
GList *origins;
GListStore *origins;
};
static void calls_dummy_provider_message_source_interface_init (CallsMessageSourceInterface *iface);
@@ -61,13 +61,15 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED
static gboolean
usr1_handler (CallsDummyProvider *self)
{
CallsDummyOrigin *origin;
GListModel *model;
g_autoptr(CallsDummyOrigin) origin = NULL;
g_return_val_if_fail (self->origins != NULL, FALSE);
model = G_LIST_MODEL (self->origins);
g_return_val_if_fail (g_list_model_get_n_items (model) > 0, FALSE);
g_debug ("Received SIGUSR1, adding new incoming call");
origin = CALLS_DUMMY_ORIGIN (self->origins->data);
origin = g_list_model_get_item (model, 0);
calls_dummy_origin_create_inbound (origin, "0987654321");
return TRUE;
@@ -85,12 +87,12 @@ calls_dummy_provider_get_status (CallsProvider *provider)
return "Normal";
}
static GList *
static GListModel *
calls_dummy_provider_get_origins (CallsProvider *provider)
{
CallsDummyProvider *self = CALLS_DUMMY_PROVIDER (provider);
return g_list_copy (self->origins);
return G_LIST_MODEL (self->origins);
}
static void
@@ -111,19 +113,10 @@ constructed (GObject *object)
static void
dispose (GObject *object)
{
gpointer origin;
GList *next;
CallsDummyProvider *self = CALLS_DUMMY_PROVIDER (object);
while (self->origins != NULL) {
origin = self->origins->data;
next = self->origins->next;
g_list_free_1 (self->origins);
self->origins = next;
g_signal_emit_by_name (self, "origin-removed", origin);
g_object_unref (origin);
}
g_list_store_remove_all (self->origins);
g_clear_object (&self->origins);
G_OBJECT_CLASS (calls_dummy_provider_parent_class)->dispose (object);
}
@@ -153,6 +146,7 @@ calls_dummy_provider_message_source_interface_init (CallsMessageSourceInterface
static void
calls_dummy_provider_init (CallsDummyProvider *self)
{
self->origins = g_list_store_new (CALLS_TYPE_DUMMY_ORIGIN);
}
@@ -161,9 +155,7 @@ calls_dummy_provider_add_origin (CallsDummyProvider *self,
const gchar *name)
{
CallsDummyOrigin *origin = calls_dummy_origin_new (name);
self->origins = g_list_append (self->origins, origin);
g_signal_emit_by_name (CALLS_PROVIDER (self), "origin-added", CALLS_ORIGIN (origin));
g_list_store_append (self->origins, origin);
}

View File

@@ -869,3 +869,18 @@ calls_mm_origin_new (MMObject *mm_obj)
"mm-object", mm_obj,
NULL);
}
gboolean
calls_mm_origin_matches (CallsMMOrigin *self,
MMObject *mm_obj)
{
g_return_val_if_fail (CALLS_IS_MM_ORIGIN (self), FALSE);
g_return_val_if_fail (MM_IS_OBJECT (mm_obj), FALSE);
if (self->mm_obj)
return g_strcmp0 (mm_object_get_path (mm_obj),
mm_object_get_path (self->mm_obj)) == 0;
return FALSE;
}

View File

@@ -35,6 +35,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (CallsMMOrigin, calls_mm_origin, CALLS, MM_ORIGIN, GObject);
CallsMMOrigin *calls_mm_origin_new (MMObject *modem);
gboolean calls_mm_origin_matches (CallsMMOrigin *self,
MMObject *modem);
G_END_DECLS

View File

@@ -42,8 +42,8 @@ struct _CallsMMProvider
guint watch_id;
/** ModemManager object proxy */
MMManager *mm;
/** Map of D-Bus object paths to origins */
GHashTable *origins;
/* A list of CallsOrigins */
GListStore *origins;
};
static void calls_mm_provider_message_source_interface_init (CallsMessageSourceInterface *iface);
@@ -78,7 +78,7 @@ update_status (CallsMMProvider *self)
{
s = _("ModemManager unavailable");
}
else if (g_hash_table_size (self->origins) == 0)
else if (g_list_model_get_n_items (G_LIST_MODEL (self->origins)) == 0)
{
s = _("No voice-capable modem available");
}
@@ -91,6 +91,32 @@ update_status (CallsMMProvider *self)
}
gboolean
mm_provider_contains (CallsMMProvider *self,
MMObject *mm_obj)
{
GListModel *model;
guint n_items;
g_assert (CALLS_IS_MM_PROVIDER (self));
g_assert (MM_OBJECT (mm_obj));
model = G_LIST_MODEL (self->origins);
n_items = g_list_model_get_n_items (model);
for (guint i = 0; i < n_items; i++)
{
g_autoptr(CallsMMOrigin) origin = NULL;
origin = g_list_model_get_item (model, i);
if (calls_mm_origin_matches (origin, mm_obj))
return TRUE;
}
return FALSE;
}
static void
add_origin (CallsMMProvider *self,
GDBusObject *object)
@@ -99,8 +125,9 @@ add_origin (CallsMMProvider *self,
CallsMMOrigin *origin;
const gchar *path;
mm_obj = MM_OBJECT (object);
path = g_dbus_object_get_object_path (object);
if (g_hash_table_contains (self->origins, path))
if (mm_provider_contains (self, mm_obj))
{
g_warning ("New voice interface on existing"
" origin with path `%s'", path);
@@ -111,16 +138,10 @@ add_origin (CallsMMProvider *self,
path);
g_assert (MM_IS_OBJECT (object));
mm_obj = MM_OBJECT (object);
origin = calls_mm_origin_new (mm_obj);
g_list_store_append (self->origins, origin);
g_hash_table_insert (self->origins,
mm_object_dup_path (mm_obj),
origin);
g_signal_emit_by_name (CALLS_PROVIDER (self),
"origin-added", origin);
update_status (self);
}
@@ -151,24 +172,25 @@ remove_modem_object (CallsMMProvider *self,
const gchar *path,
GDBusObject *object)
{
gpointer *origin;
GListModel *model;
guint n_items;
origin = g_hash_table_lookup (self->origins, path);
if (!origin)
{
return;
}
model = G_LIST_MODEL (self->origins);
n_items = g_list_model_get_n_items (model);
g_assert (CALLS_IS_ORIGIN (origin));
for (guint i = 0; i < n_items; i++) {
g_autoptr (CallsMMOrigin) origin = NULL;
g_object_ref (origin);
g_hash_table_remove (self->origins, path);
origin = g_list_model_get_item (model, i);
g_signal_emit_by_name (CALLS_PROVIDER (self),
"origin-removed", CALLS_ORIGIN (origin));
g_object_unref (origin);
if (calls_mm_origin_matches (origin, MM_OBJECT (object)))
{
g_list_store_remove (self->origins, i);
update_status (self);
update_status (self);
break;
}
}
}
@@ -299,35 +321,13 @@ mm_appeared_cb (GDBusConnection *connection,
}
static void
clear_dbus (CallsMMProvider *self)
{
GList *paths, *node;
gpointer origin;
paths = g_hash_table_get_keys (self->origins);
for (node = paths; node != NULL; node = node->next)
{
g_hash_table_steal_extended (self->origins, node->data, NULL, &origin);
g_signal_emit_by_name (CALLS_PROVIDER (self),
"origin-removed", CALLS_ORIGIN (origin));
g_object_unref (origin);
}
g_list_free_full (paths, g_free);
g_clear_object (&self->mm);
}
void
mm_vanished_cb (GDBusConnection *connection,
const gchar *name,
CallsMMProvider *self)
{
g_debug ("ModemManager vanished from D-Bus");
clear_dbus (self);
g_list_store_remove_all (self->origins);
update_status (self);
}
@@ -346,12 +346,12 @@ calls_mm_provider_get_status (CallsProvider *provider)
return self->status;
}
static GList *
static GListModel *
calls_mm_provider_get_origins (CallsProvider *provider)
{
CallsMMProvider *self = CALLS_MM_PROVIDER (provider);
return g_hash_table_get_values (self->origins);
return G_LIST_MODEL (self->origins);
}
static void
@@ -384,7 +384,7 @@ dispose (GObject *object)
self->watch_id = 0;
}
clear_dbus (self);
g_list_store_remove_all (self->origins);
G_OBJECT_CLASS (calls_mm_provider_parent_class)->dispose (object);
}
@@ -395,7 +395,7 @@ finalize (GObject *object)
{
CallsMMProvider *self = CALLS_MM_PROVIDER (object);
g_hash_table_unref (self->origins);
g_object_unref (self->origins);
g_free (self->status);
G_OBJECT_CLASS (calls_mm_provider_parent_class)->finalize (object);
@@ -433,8 +433,7 @@ static void
calls_mm_provider_init (CallsMMProvider *self)
{
self->status = g_strdup (_("Initialised"));
self->origins = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
self->origins = g_list_store_new (CALLS_TYPE_MM_ORIGIN);
}

View File

@@ -110,6 +110,18 @@ calls_ofono_origin_new (GDBOModem *modem)
NULL);
}
gboolean
calls_ofono_origin_matches (CallsOfonoOrigin *self,
const char *path)
{
g_return_val_if_fail (CALLS_IS_OFONO_ORIGIN (self), FALSE);
g_return_val_if_fail (path, FALSE);
if (!self->modem)
return FALSE;
return g_strcmp0 (g_dbus_proxy_get_object_path (G_DBUS_PROXY (self->modem)), path) == 0;
}
static void
set_property (GObject *object,

View File

@@ -36,6 +36,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (CallsOfonoOrigin, calls_ofono_origin, CALLS, OFONO_ORIGIN, GObject);
CallsOfonoOrigin *calls_ofono_origin_new (GDBOModem *modem);
gboolean calls_ofono_origin_matches (CallsOfonoOrigin *self,
const char *path);
G_END_DECLS

View File

@@ -45,8 +45,8 @@ struct _CallsOfonoProvider
GDBOManager *manager;
/** Map of D-Bus object paths to a struct CallsModemData */
GHashTable *modems;
/** Map of D-Bus object paths to Origins */
GHashTable *origins;
/* A list of CallsOrigins */
GListStore *origins;
};
@@ -59,47 +59,37 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED
calls_ofono_provider_message_source_interface_init))
static void
add_origin_to_list (const gchar *path,
CallsOfonoOrigin *origin,
GList **list)
gboolean
ofono_find_origin_index (CallsOfonoProvider *self,
const char *path,
guint *index)
{
*list = g_list_prepend (*list, origin);
GListModel *model;
guint n_items;
g_assert (CALLS_IS_OFONO_PROVIDER (self));
model = G_LIST_MODEL (self->origins);
n_items = g_list_model_get_n_items (model);
for (guint i = 0; i < n_items; i++)
{
g_autoptr(CallsOfonoOrigin) origin = NULL;
origin = g_list_model_get_item (model, i);
if (calls_ofono_origin_matches (origin, path))
{
if (index)
*index = i;
return TRUE;
}
}
return FALSE;
}
static void
add_origin (CallsOfonoProvider *self,
const gchar *path,
GDBOModem *modem)
{
CallsOfonoOrigin *origin;
g_debug ("Adding oFono Origin with path `%s'", path);
origin = calls_ofono_origin_new (modem);
g_hash_table_insert (self->origins, g_strdup(path), origin);
g_signal_emit_by_name (CALLS_PROVIDER (self),
"origin-added", origin);
}
static void
remove_origin (CallsOfonoProvider *self,
const gchar *path,
CallsOfonoOrigin *origin)
{
g_debug ("Removing oFono Origin with path `%s'", path);
g_signal_emit_by_name (CALLS_PROVIDER (self),
"origin-removed", origin);
g_hash_table_remove (self->origins, path);
g_object_unref (origin);
}
static gboolean
object_array_includes (GVariantIter *iter,
const gchar *needle)
@@ -129,7 +119,8 @@ modem_check_ifaces (CallsOfonoProvider *self,
gboolean voice;
GVariantIter *iter = NULL;
const gchar *path;
CallsOfonoOrigin *origin;
guint index;
gboolean has_origin;
g_variant_get (ifaces, "as", &iter);
@@ -137,15 +128,20 @@ modem_check_ifaces (CallsOfonoProvider *self,
(iter, "org.ofono.VoiceCallManager");
path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (modem));
origin = g_hash_table_lookup (self->origins, path);
if (voice && !origin)
has_origin = ofono_find_origin_index (self, path, &index);
if (voice && !has_origin)
{
add_origin (self, path, modem);
g_autoptr(CallsOfonoOrigin) origin = NULL;
g_debug ("Adding oFono Origin with path `%s'", path);
origin = calls_ofono_origin_new (modem);
g_list_store_append (self->origins, origin);
}
else if (!voice && origin)
else if (!voice && has_origin)
{
remove_origin (self, path, origin);
g_list_store_remove (self->origins, index);
}
}
@@ -297,15 +293,12 @@ modem_removed_cb (GDBOManager *manager,
const gchar *path,
CallsOfonoProvider *self)
{
CallsOfonoOrigin *origin;
guint index;
g_debug ("Removing modem `%s'", path);
origin = g_hash_table_lookup (self->origins, path);
if (origin)
{
remove_origin (self, path, origin);
}
if (ofono_find_origin_index (self, path, &index))
g_list_store_remove (self->origins, index);
g_hash_table_remove (self->modems, path);
@@ -365,16 +358,12 @@ calls_ofono_provider_get_status (CallsProvider *provider)
return "";
}
static GList *
static GListModel *
calls_ofono_provider_get_origins (CallsProvider *provider)
{
CallsOfonoProvider *self = CALLS_OFONO_PROVIDER (provider);
GList *list = NULL;
g_hash_table_foreach (self->origins,
(GHFunc)add_origin_to_list, &list);
return g_list_reverse (list);
return G_LIST_MODEL (self->origins);
}
@@ -436,7 +425,7 @@ finalize (GObject *object)
{
CallsOfonoProvider *self = CALLS_OFONO_PROVIDER (object);
g_hash_table_unref (self->origins);
g_object_unref (self->origins);
g_hash_table_unref (self->modems);
G_OBJECT_CLASS (calls_ofono_provider_parent_class)->finalize (object);
@@ -476,8 +465,7 @@ calls_ofono_provider_init (CallsOfonoProvider *self)
{
self->modems = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
self->origins = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
self->origins = g_list_store_new (CALLS_TYPE_OFONO_ORIGIN);
}