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

@@ -55,8 +55,6 @@ static GParamSpec *props[PROP_LAST_PROP];
enum {
SIGNAL_ORIGIN_ADD,
SIGNAL_ORIGIN_REMOVE,
SIGNAL_CALL_ADD,
SIGNAL_CALL_REMOVE,
/* TODO: currently this event isn't emitted since the plugins don't give use
@@ -205,7 +203,6 @@ add_origin (CallsManager *self, CallsOrigin *origin, CallsProvider *provider)
calls_origin_foreach_call(origin, (CallsOriginForeachCallFunc)add_call, self);
set_state (self, CALLS_MANAGER_STATE_READY);
g_signal_emit (self, signals[SIGNAL_ORIGIN_ADD], 0, origin);
}
static void
@@ -217,7 +214,7 @@ remove_call_cb (gpointer self, CallsCall *call, CallsOrigin *origin)
static void
remove_origin (CallsManager *self, CallsOrigin *origin, CallsProvider *provider)
{
g_autoptr (GList) origins = NULL;
GListModel *origins;
g_return_if_fail (CALLS_IS_ORIGIN (origin));
@@ -229,10 +226,8 @@ remove_origin (CallsManager *self, CallsOrigin *origin, CallsProvider *provider)
calls_manager_set_default_origin (self, NULL);
origins = calls_manager_get_origins (self);
if (origins == NULL)
set_state (self, CALLS_MANAGER_STATE_NO_ORIGIN);
g_signal_emit (self, signals[SIGNAL_ORIGIN_REMOVE], 0, origin);
if (!origins || g_list_model_get_n_items (origins) == 0)
set_state (self, CALLS_MANAGER_STATE_NO_ORIGIN);
}
static void
@@ -240,29 +235,59 @@ remove_provider (CallsManager *self)
{
PeasEngine *engine = peas_engine_get_default ();
PeasPluginInfo *plugin = peas_engine_get_plugin_info (engine, self->provider_name);
g_autoptr (GList) origins = NULL;
GList *o;
GListModel *origins;
guint n_items;
g_debug ("Remove provider: %s", calls_provider_get_name (self->provider));
g_signal_handlers_disconnect_by_data (self->provider, self);
origins = calls_provider_get_origins (self->provider);
g_signal_handlers_disconnect_by_data (origins, self);
n_items = g_list_model_get_n_items (origins);
for (o = origins; o != NULL; o = o->next)
for (guint i = 0; i < n_items; i++)
{
remove_origin (self, o->data, self->provider);
g_autoptr(CallsOrigin) origin = NULL;
origin = g_list_model_get_item (origins, i);
remove_origin (self, origin, self->provider);
}
g_clear_pointer (&self->provider_name, g_free);
peas_engine_unload_plugin (engine, plugin);
g_clear_object (&self->provider);
set_state (self, CALLS_MANAGER_STATE_NO_PROVIDER);
}
static void
origin_items_changed_cb (CallsManager *self)
{
GListModel *origins;
guint n_items;
g_assert (CALLS_IS_MANAGER (self));
origins = calls_provider_get_origins (self->provider);
n_items = g_list_model_get_n_items (origins);
if (n_items)
set_state (self, CALLS_MANAGER_STATE_READY);
else
set_state (self, CALLS_MANAGER_STATE_NO_ORIGIN);
for (guint i = 0; i < n_items; i++)
{
g_autoptr(CallsOrigin) origin = NULL;
origin = g_list_model_get_item (origins, i);
add_origin (self, origin, self->provider);
}
}
static void
add_provider (CallsManager *self, const gchar *name)
{
g_autoptr (GList) origins = NULL;
GList *o;
GListModel *origins;
/* We could eventually enable more then one provider, but for now let's use
only one */
@@ -279,17 +304,17 @@ add_provider (CallsManager *self, const gchar *name)
return;
}
set_state (self, CALLS_MANAGER_STATE_NO_ORIGIN);
if (g_strcmp0 (name, "dummy") == 0)
set_state (self, CALLS_MANAGER_STATE_READY);
else
set_state (self, CALLS_MANAGER_STATE_NO_ORIGIN);
origins = calls_provider_get_origins (self->provider);
g_signal_connect_swapped (self->provider, "origin-added", G_CALLBACK (add_origin), self);
g_signal_connect_swapped (self->provider, "origin-removed", G_CALLBACK (remove_origin), self);
for (o = origins; o != NULL; o = o->next)
{
add_origin (self, o->data, self->provider);
}
g_signal_connect_object (origins, "items-changed",
G_CALLBACK (origin_items_changed_cb), self,
G_CONNECT_SWAPPED);
origin_items_changed_cb (self);
self->provider_name = g_strdup (name);
}
@@ -366,26 +391,6 @@ calls_manager_class_init (CallsManagerClass *klass)
object_class->set_property = calls_manager_set_property;
object_class->finalize = calls_manager_finalize;
signals[SIGNAL_ORIGIN_ADD] =
g_signal_new ("origin-add",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL, NULL,
G_TYPE_NONE,
1,
CALLS_TYPE_ORIGIN);
signals[SIGNAL_ORIGIN_REMOVE] =
g_signal_new ("origin-remove",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL, NULL,
G_TYPE_NONE,
1,
CALLS_TYPE_ORIGIN);
signals[SIGNAL_CALL_ADD] =
g_signal_new ("call-add",
G_TYPE_FROM_CLASS (klass),
@@ -548,7 +553,7 @@ calls_manager_get_state (CallsManager *self)
return self->state;
}
GList *
GListModel *
calls_manager_get_origins (CallsManager *self)
{
g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL);
@@ -562,16 +567,23 @@ calls_manager_get_origins (CallsManager *self)
GList *
calls_manager_get_calls (CallsManager *self)
{
g_autoptr (GList) origins = NULL;
GListModel *origins = NULL;
g_autoptr (GList) calls = NULL;
GList *o;
guint n_items = 0;
g_return_val_if_fail (CALLS_IS_MANAGER (self), NULL);
origins = calls_manager_get_origins (self);
if (origins)
n_items = g_list_model_get_n_items (origins);
for (o = origins; o != NULL; o = o->next)
calls = g_list_concat (calls, calls_origin_get_calls (o->data));
for (guint i = 0; i < n_items; i++)
{
g_autoptr(CallsOrigin) origin = NULL;
origin = g_list_model_get_item (origins, i);
calls = g_list_concat (calls, calls_origin_get_calls (origin));
}
return g_steal_pointer (&calls);
}

View File

@@ -54,7 +54,7 @@ void calls_manager_set_provider (CallsManager *self,
const gchar *name);
CallsProvider *calls_manager_get_real_provider (CallsManager *self);
CallsManagerState calls_manager_get_state (CallsManager *self);
GList *calls_manager_get_origins (CallsManager *self);
GListModel *calls_manager_get_origins (CallsManager *self);
GList *calls_manager_get_calls (CallsManager *self);
void calls_manager_dial (CallsManager *self,
CallsOrigin *origin,

View File

@@ -35,8 +35,8 @@ struct _CallsNewCallBox
{
GtkBox parent_instance;
GtkListStore *origin_store;
GtkComboBox *origin_box;
GtkListBox *origin_list_box;
HdyComboRow *origin_list;
GtkButton *backspace;
HdyKeypad *keypad;
GtkButton *dial;
@@ -48,30 +48,20 @@ struct _CallsNewCallBox
G_DEFINE_TYPE (CallsNewCallBox, calls_new_call_box, GTK_TYPE_BOX);
enum {
ORIGIN_STORE_COLUMN_NAME,
ORIGIN_STORE_COLUMN_ORIGIN
};
static CallsOrigin *
get_origin (CallsNewCallBox *self)
{
GtkTreeIter iter;
gboolean ok;
CallsOrigin *origin;
g_autoptr(CallsOrigin) origin = NULL;
GListModel *model;
int index = -1;
ok = gtk_combo_box_get_active_iter (self->origin_box, &iter);
if (!ok)
{
return NULL;
}
model = hdy_combo_row_get_model (self->origin_list);
gtk_tree_model_get (GTK_TREE_MODEL (self->origin_store),
&iter,
ORIGIN_STORE_COLUMN_ORIGIN, &origin,
-1);
g_assert (CALLS_IS_ORIGIN (origin));
if (model)
index = hdy_combo_row_get_selected_index (self->origin_list);
if (model && index >= 0)
origin = g_list_model_get_item (model, index);
return origin;
}
@@ -170,120 +160,70 @@ dial_queued (CallsNewCallBox *self)
g_list_foreach (self->dial_queue,
(GFunc)dial_queued_cb,
origin);
g_object_unref (origin);
clear_dial_queue (self);
}
void
update_origin_box (CallsNewCallBox *self)
char *
get_origin_name (gpointer item,
gpointer user_data)
{
GtkTreeModel *origin_store = GTK_TREE_MODEL (self->origin_store);
GtkTreeIter iter;
g_assert (CALLS_IS_ORIGIN (item));
if (!gtk_tree_model_get_iter_first (origin_store, &iter))
{
gtk_widget_hide (GTK_WIDGET (self->origin_box));
gtk_widget_set_sensitive (GTK_WIDGET (self->dial), FALSE);
return;
}
return g_strdup (calls_origin_get_name (item));
}
/* We know there is at least one origin. */
static void
origin_count_changed_cb (CallsNewCallBox *self)
{
GListModel *origins;
guint n_items = 0;
gtk_widget_set_sensitive (GTK_WIDGET (self->dial), TRUE);
g_assert (CALLS_IS_NEW_CALL_BOX (self));
if (!gtk_tree_model_iter_next (origin_store, &iter))
{
gtk_combo_box_set_active (self->origin_box, 0);
gtk_widget_hide (GTK_WIDGET (self->origin_box));
}
origins = calls_manager_get_origins (calls_manager_get_default ());
n_items = g_list_model_get_n_items (origins);
gtk_widget_set_visible (GTK_WIDGET (self->origin_list_box), n_items > 1);
gtk_widget_set_sensitive (GTK_WIDGET (self->dial), n_items > 0);
if (n_items)
hdy_combo_row_bind_name_model (self->origin_list, origins,
get_origin_name, self, NULL);
else
{
/* We know there are multiple origins. */
hdy_combo_row_bind_name_model (self->origin_list,
NULL, NULL, NULL, NULL);
if (gtk_combo_box_get_active (self->origin_box) < 0)
{
gtk_combo_box_set_active (self->origin_box, 0);
}
/* We know there are multiple origins and one is selected. */
gtk_widget_show (GTK_WIDGET (self->origin_box));
}
if (n_items)
hdy_combo_row_set_selected_index (self->origin_list, 0);
dial_queued (self);
}
static void
add_origin (CallsNewCallBox *self, CallsOrigin *origin)
provider_changed_cb (CallsNewCallBox *self)
{
GtkTreeIter iter;
GListModel *origins;
gtk_list_store_append (self->origin_store, &iter);
gtk_list_store_set (self->origin_store, &iter,
ORIGIN_STORE_COLUMN_NAME, calls_origin_get_name (origin),
ORIGIN_STORE_COLUMN_ORIGIN, G_OBJECT (origin),
-1);
g_assert (CALLS_IS_NEW_CALL_BOX (self));
update_origin_box (self);
origins = calls_manager_get_origins (calls_manager_get_default ());
g_signal_connect_object (origins, "items-changed",
G_CALLBACK (origin_count_changed_cb), self,
G_CONNECT_SWAPPED);
}
static void
remove_origin (CallsNewCallBox *self, CallsOrigin *origin)
{
GtkTreeIter iter;
gboolean ok;
ok = calls_list_store_find (self->origin_store, origin,
ORIGIN_STORE_COLUMN_ORIGIN, &iter);
g_return_if_fail (ok);
gtk_list_store_remove (self->origin_store, &iter);
update_origin_box (self);
}
static void
remove_origins (CallsNewCallBox *self)
{
GtkTreeModel *model = GTK_TREE_MODEL (self->origin_store);
GtkTreeIter iter;
while (gtk_tree_model_get_iter_first (model, &iter))
{
gtk_list_store_remove (self->origin_store, &iter);
}
}
static void
calls_new_call_box_init (CallsNewCallBox *self)
{
g_autoptr (GList) origins = NULL;
GList *o;
gtk_widget_init_template (GTK_WIDGET (self));
g_signal_connect_swapped (calls_manager_get_default (),
"origin-add",
G_CALLBACK (add_origin),
"notify::provider",
G_CALLBACK (provider_changed_cb),
self);
g_signal_connect_swapped (calls_manager_get_default (),
"origin-remove",
G_CALLBACK (remove_origin),
self);
origins = calls_manager_get_origins (calls_manager_get_default ());
for (o = origins; o != NULL; o = o->next) {
add_origin (self, o->data);
}
update_origin_box (self);
provider_changed_cb (self);
}
@@ -294,11 +234,6 @@ dispose (GObject *object)
clear_dial_queue (self);
if (self->origin_store)
{
remove_origins (self);
}
if (self->long_press_back_gesture != NULL)
g_object_unref (self->long_press_back_gesture);
@@ -315,8 +250,8 @@ calls_new_call_box_class_init (CallsNewCallBoxClass *klass)
object_class->dispose = dispose;
gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/calls/ui/new-call-box.ui");
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, origin_store);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, origin_box);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, origin_list_box);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, origin_list);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, backspace);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, long_press_back_gesture);
gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, keypad);
@@ -354,7 +289,6 @@ calls_new_call_box_dial (CallsNewCallBox *self,
}
calls_origin_dial (origin, target);
g_object_unref (origin);
}
void

View File

@@ -58,13 +58,6 @@ enum {
static GParamSpec *props[PROP_LAST_PROP];
enum {
SIGNAL_ORIGIN_ADDED,
SIGNAL_ORIGIN_REMOVED,
SIGNAL_LAST_SIGNAL,
};
static guint signals [SIGNAL_LAST_SIGNAL];
static void
calls_provider_get_property (GObject *object,
guint prop_id,
@@ -99,20 +92,6 @@ calls_provider_class_init (CallsProviderClass *klass)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
signals[SIGNAL_ORIGIN_ADDED] =
g_signal_new ("origin-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, CALLS_TYPE_ORIGIN);
signals[SIGNAL_ORIGIN_REMOVED] =
g_signal_new ("origin-removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, CALLS_TYPE_ORIGIN);
}
static void
@@ -151,10 +130,9 @@ calls_provider_get_status (CallsProvider *self)
*
* Get the list of #CallsOrigin interfaces offered by this provider.
*
* Returns: A newly-allocated GList of objects implementing
* #CallsOrigin or NULL if there was an error.
* Returns: (transfer none): A #GListModel of origins
*/
GList *
GListModel *
calls_provider_get_origins (CallsProvider *self)
{
g_return_val_if_fail (CALLS_IS_PROVIDER (self), NULL);

View File

@@ -46,13 +46,13 @@ struct _CallsProviderClass
const char *(*get_name) (CallsProvider *self);
const char *(*get_status) (CallsProvider *self);
GList *(*get_origins) (CallsProvider *self);
GListModel *(*get_origins) (CallsProvider *self);
};
const char *calls_provider_get_name (CallsProvider *self);
const char *calls_provider_get_status (CallsProvider *self);
GList *calls_provider_get_origins (CallsProvider *self);
GListModel *calls_provider_get_origins (CallsProvider *self);
G_END_DECLS

View File

@@ -21,26 +21,19 @@
<property name="orientation">vertical</property>
<property name="valign">center</property>
<property name="visible">True</property>
<child>
<object class="GtkComboBox" id="origin_box">
<property name="can_focus">False</property>
<property name="model">origin_store</property>
<property name="id_column">0</property>
<property name="margin_bottom">8</property>
<property name="no_show_all">True</property>
<object class="GtkListBox" id="origin_list_box">
<property name="visible">True</property>
<property name="selection-mode">none</property>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
<object class="HdyComboRow" id="origin_list">
<property name="visible">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>