[gnome-software/961-gsapp-state-not-updated-after-repository-enable-disable] GsApp: State not updated after repository enable/disable



commit 0934ef673a35d520e552377acc9dd5f72d0a2f9c
Author: Milan Crha <mcrha redhat com>
Date:   Tue Feb 2 07:51:28 2021 +0100

    GsApp: State not updated after repository enable/disable
    
    Let the other plugins know that a repository was enabled/disabled,
    thus they can refresh their cache accordingly.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/961

 lib/gs-plugin-loader.c                    | 13 ++++
 lib/gs-plugin.c                           | 99 +++++++++++++++++++++++++++++++
 lib/gs-plugin.h                           |  9 ++-
 plugins/core/gs-plugin-appstream.c        |  3 +
 plugins/flatpak/gs-flatpak.c              |  6 ++
 plugins/fwupd/gs-plugin-fwupd.c           |  3 +
 plugins/packagekit/gs-plugin-packagekit.c | 10 ++++
 plugins/rpm-ostree/gs-plugin-rpm-ostree.c |  2 +
 src/gs-application.c                      | 19 ++++++
 9 files changed, 163 insertions(+), 1 deletion(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index b951cdc70..7f9d00f62 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -2181,6 +2181,16 @@ gs_plugin_loader_reload_cb (GsPlugin *plugin,
                                       g_object_ref (plugin_loader));
 }
 
+static void
+gs_plugin_loader_repository_changed_cb (GsPlugin *plugin,
+                                       GsApp *repository,
+                                       GsPluginLoader *plugin_loader)
+{
+       g_signal_emit_by_name (g_application_get_default (),
+               "repository-changed",
+               repository);
+}
+
 static void
 gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
                              const gchar *filename)
@@ -2213,6 +2223,9 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
        g_signal_connect (plugin, "allow-updates",
                          G_CALLBACK (gs_plugin_loader_allow_updates_cb),
                          plugin_loader);
+       g_signal_connect (plugin, "repository-changed",
+                         G_CALLBACK (gs_plugin_loader_repository_changed_cb),
+                         plugin_loader);
        gs_plugin_set_soup_session (plugin, priv->soup_session);
        gs_plugin_set_locale (plugin, priv->locale);
        gs_plugin_set_language (plugin, priv->language);
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index cf1d788df..de22bbf9b 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -90,6 +90,7 @@ enum {
        SIGNAL_REPORT_EVENT,
        SIGNAL_ALLOW_UPDATES,
        SIGNAL_BASIC_AUTH_START,
+       SIGNAL_REPOSITORY_CHANGED,
        SIGNAL_LAST
 };
 
@@ -2028,6 +2029,13 @@ gs_plugin_class_init (GsPluginClass *klass)
                              G_STRUCT_OFFSET (GsPluginClass, basic_auth_start),
                              NULL, NULL, g_cclosure_marshal_generic,
                              G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER);
+
+       signals [SIGNAL_REPOSITORY_CHANGED] =
+               g_signal_new ("repository-changed",
+                             G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (GsPluginClass, repository_changed),
+                             NULL, NULL, g_cclosure_marshal_generic,
+                             G_TYPE_NONE, 1, GS_TYPE_APP);
 }
 
 static void
@@ -2069,3 +2077,94 @@ gs_plugin_new (void)
        plugin = g_object_new (GS_TYPE_PLUGIN, NULL);
        return plugin;
 }
+
+typedef struct {
+       GsPlugin *plugin;
+       GsApp    *repository;
+} GsPluginRepositoryChangedHelper;
+
+static gboolean
+gs_plugin_repository_changed_cb (gpointer user_data)
+{
+       GsPluginRepositoryChangedHelper *helper = user_data;
+       g_signal_emit (helper->plugin,
+                      signals[SIGNAL_REPOSITORY_CHANGED], 0,
+                      helper->repository);
+       g_clear_object (&helper->repository);
+       g_clear_object (&helper->plugin);
+       g_slice_free (GsPluginRepositoryChangedHelper, helper);
+       return FALSE;
+}
+
+/**
+ * gs_plugin_repository_changed:
+ * @plugin: a #GsPlugin
+ * @repository: a #GsApp representing the repository
+ *
+ * Emit the "repository-changed" signal in the main thread.
+ *
+ * Since: 40
+ **/
+void
+gs_plugin_repository_changed (GsPlugin *plugin,
+                             GsApp *repository)
+{
+       GsPluginRepositoryChangedHelper *helper;
+       g_autoptr(GSource) idle_source = NULL;
+
+       g_return_if_fail (GS_IS_PLUGIN (plugin));
+       g_return_if_fail (GS_IS_APP (repository));
+
+       helper = g_slice_new0 (GsPluginRepositoryChangedHelper);
+       helper->plugin = g_object_ref (plugin);
+       helper->repository = g_object_ref (repository);
+
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (idle_source, gs_plugin_repository_changed_cb, helper, NULL);
+       g_source_attach (idle_source, NULL);
+}
+
+/**
+ * gs_plugin_update_cache_state_for_repository:
+ * @plugin: a #GsPlugin
+ * @repository: a #GsApp representing a repository, which changed
+ *
+ * Update state of the all cached #GsApp instances related
+ * to the @repository.
+ *
+ * Since: 40
+ **/
+void
+gs_plugin_update_cache_state_for_repository (GsPlugin *plugin,
+                                            GsApp *repository)
+{
+       GsPluginPrivate *priv;
+       GHashTableIter iter;
+       g_autoptr(GMutexLocker) locker = NULL;
+       gpointer value;
+       const gchar *repo_id;
+       GsAppState repo_state;
+
+       g_return_if_fail (GS_IS_PLUGIN (plugin));
+       g_return_if_fail (GS_IS_APP (repository));
+
+       priv = gs_plugin_get_instance_private (plugin);
+       repo_id = gs_app_get_id (repository);
+       repo_state = gs_app_get_state (repository);
+
+       locker = g_mutex_locker_new (&priv->cache_mutex);
+
+       g_hash_table_iter_init (&iter, priv->cache);
+       while (g_hash_table_iter_next (&iter, NULL, &value)) {
+               GsApp *app = value;
+               GsAppState app_state = gs_app_get_state (app);
+
+               if (((app_state == GS_APP_STATE_AVAILABLE &&
+                   repo_state != GS_APP_STATE_INSTALLED) ||
+                   (app_state == GS_APP_STATE_UNAVAILABLE &&
+                   repo_state == GS_APP_STATE_INSTALLED)) &&
+                   g_strcmp0 (gs_app_get_origin (app), repo_id) == 0) {
+                       gs_app_set_state (app, repo_state == GS_APP_STATE_INSTALLED ? GS_APP_STATE_AVAILABLE 
: GS_APP_STATE_UNAVAILABLE);
+               }
+       }
+}
diff --git a/lib/gs-plugin.h b/lib/gs-plugin.h
index e2119317d..288126c75 100644
--- a/lib/gs-plugin.h
+++ b/lib/gs-plugin.h
@@ -44,7 +44,9 @@ struct _GsPluginClass
                                                         const gchar    *realm,
                                                         GCallback       callback,
                                                         gpointer        user_data);
-       gpointer                 padding[25];
+       void                    (*repository_changed)   (GsPlugin       *plugin,
+                                                        GsApp          *repository);
+       gpointer                 padding[24];
 };
 
 typedef struct GsPluginData    GsPluginData;
@@ -128,5 +130,10 @@ void                gs_plugin_basic_auth_start             (GsPlugin       *plugin,
                                                         const gchar    *realm,
                                                         GCallback       callback,
                                                         gpointer        user_data);
+void           gs_plugin_repository_changed            (GsPlugin       *plugin,
+                                                        GsApp          *repository);
+void           gs_plugin_update_cache_state_for_repository
+                                                       (GsPlugin *plugin,
+                                                        GsApp *repository);
 
 G_END_DECLS
diff --git a/plugins/core/gs-plugin-appstream.c b/plugins/core/gs-plugin-appstream.c
index f8fa1864e..06e639018 100644
--- a/plugins/core/gs-plugin-appstream.c
+++ b/plugins/core/gs-plugin-appstream.c
@@ -46,6 +46,9 @@ gs_plugin_initialize (GsPlugin *plugin)
 
        /* require settings */
        priv->settings = g_settings_new ("org.gnome.software");
+
+       g_signal_connect_object (g_application_get_default (), "repository-changed",
+               G_CALLBACK (gs_plugin_update_cache_state_for_repository), plugin, G_CONNECT_SWAPPED);
 }
 
 void
diff --git a/plugins/flatpak/gs-flatpak.c b/plugins/flatpak/gs-flatpak.c
index c528fb5d0..e13e2590d 100644
--- a/plugins/flatpak/gs-flatpak.c
+++ b/plugins/flatpak/gs-flatpak.c
@@ -1474,6 +1474,9 @@ gs_flatpak_app_install_source (GsFlatpak *self, GsApp *app,
 
        /* success */
        gs_app_set_state (app, GS_APP_STATE_INSTALLED);
+
+       gs_plugin_repository_changed (self->plugin, app);
+
        return TRUE;
 }
 
@@ -2917,6 +2920,9 @@ gs_flatpak_app_remove_source (GsFlatpak *self,
        g_rw_lock_reader_unlock (&self->silo_lock);
 
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
+
+       gs_plugin_repository_changed (self->plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/fwupd/gs-plugin-fwupd.c b/plugins/fwupd/gs-plugin-fwupd.c
index 2a99d9957..ff2a71754 100644
--- a/plugins/fwupd/gs-plugin-fwupd.c
+++ b/plugins/fwupd/gs-plugin-fwupd.c
@@ -947,6 +947,9 @@ gs_plugin_fwupd_modify_source (GsPlugin *plugin, GsApp *app, gboolean enabled,
        }
        gs_app_set_state (app, enabled ?
                          GS_APP_STATE_INSTALLED : GS_APP_STATE_AVAILABLE);
+
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index 7f158ed25..5c4f8f64c 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -181,6 +181,7 @@ gs_plugin_app_origin_repo_enable (GsPlugin *plugin,
 {
        GsPluginData *priv = gs_plugin_get_data (plugin);
        g_autoptr(GsPackagekitHelper) helper = gs_packagekit_helper_new (plugin);
+       g_autoptr(GsApp) repo_app = NULL;
        g_autoptr(PkResults) results = NULL;
        g_autoptr(PkError) error_code = NULL;
        const gchar *repo_id;
@@ -219,6 +220,11 @@ gs_plugin_app_origin_repo_enable (GsPlugin *plugin,
         * UNAVAILABLE state to AVAILABLE */
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       /* Construct a simple fake GsApp for the repository, used only by the signal handler */
+       repo_app = gs_app_new (repo_id);
+       gs_app_set_state (repo_app, GS_APP_STATE_INSTALLED);
+       gs_plugin_repository_changed (plugin, repo_app);
+
        return TRUE;
 }
 
@@ -260,6 +266,8 @@ gs_plugin_repo_enable (GsPlugin *plugin,
        /* state is known */
        gs_app_set_state (app, GS_APP_STATE_INSTALLED);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
@@ -500,6 +508,8 @@ gs_plugin_repo_disable (GsPlugin *plugin,
        /* state is known */
        gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
index 38c3d9906..0d26dfad6 100644
--- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
@@ -1112,6 +1112,8 @@ gs_plugin_repo_enable (GsPlugin *plugin,
        else
                gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
 
+       gs_plugin_repository_changed (plugin, app);
+
        return TRUE;
 }
 
diff --git a/src/gs-application.c b/src/gs-application.c
index 92dd3cd67..c6fce42e2 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -59,6 +59,7 @@ G_DEFINE_TYPE (GsApplication, gs_application, GTK_TYPE_APPLICATION);
 
 enum {
        INSTALL_RESOURCES_DONE,
+       REPOSITORY_CHANGED,
        LAST_SIGNAL
 };
 
@@ -1188,6 +1189,24 @@ gs_application_class_init (GsApplicationClass *class)
                NULL,
                G_TYPE_NONE, 2,
                G_TYPE_STRING, G_TYPE_ERROR);
+
+       /**
+        * GsApplication::repository-changed:
+        * @repository: a #GsApp of the repository
+        *
+        * Emitted when the repository changed, usually when it is enabled or disabled.
+        *
+        * Since: 40
+        */
+       signals[REPOSITORY_CHANGED] = g_signal_new (
+               "repository-changed",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_ACTION | G_SIGNAL_NO_RECURSE,
+               0,
+               NULL, NULL,
+               NULL,
+               G_TYPE_NONE, 1,
+               GS_TYPE_APP);
 }
 
 GsApplication *


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]