[gnome-software] Load all local, remote and stock icons in the 'icons' plugin



commit 25433ed5dda49ef8520292b0c4a9203f5b33ffd1
Author: Richard Hughes <richard hughsie com>
Date:   Tue May 10 16:36:29 2016 +0100

    Load all local, remote and stock icons in the 'icons' plugin
    
    Before this change we were loading icons both in GsApp instances (with static
    mutexes for the icon cache, ewww), in the plugin loader and also in the icons
    plugin depending on the AsAppKind.
    
    This change makes all the icon loading happen in one place.

 src/gs-app.c                   |  176 +++-------------------------------------
 src/gs-app.h                   |    3 -
 src/gs-plugin-loader.c         |   54 ++++++++++++-
 src/gs-plugin.h                |    2 +
 src/gs-self-test.c             |    2 +-
 src/gs-shell-category.c        |    2 +-
 src/gs-shell-details.c         |    3 +-
 src/gs-shell-extras.c          |    6 +-
 src/gs-shell-installed.c       |    2 +-
 src/gs-shell-moderate.c        |    2 +-
 src/gs-shell-search-provider.c |    2 +-
 src/gs-shell-search.c          |    2 +-
 src/gs-shell-updates.c         |    2 +-
 src/plugins/gs-appstream.c     |    6 +-
 src/plugins/gs-plugin-icons.c  |  132 +++++++++++++++++++++++++++---
 15 files changed, 196 insertions(+), 200 deletions(-)
---
diff --git a/src/gs-app.c b/src/gs-app.c
index cce2154..bbef000 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -96,7 +96,6 @@ struct _GsApp
        AsAppState               state_recover;
        guint                    progress;
        GHashTable              *metadata;
-       GdkPixbuf               *pixbuf;
        GPtrArray               *addons; /* of GsApp */
        GHashTable              *addons_hash; /* of "id" */
        GPtrArray               *related; /* of GsApp */
@@ -220,6 +219,8 @@ gs_app_to_string (GsApp *app)
        if (app->icon != NULL) {
                gs_app_kv_lpad (str, "icon-kind",
                                as_icon_kind_to_string (as_icon_get_kind (app->icon)));
+               gs_app_kv_printf (str, "icon-pixbuf", "%p",
+                                 as_icon_get_pixbuf (app->icon));
                if (as_icon_get_name (app->icon) != NULL)
                        gs_app_kv_lpad (str, "icon-name",
                                        as_icon_get_name (app->icon));
@@ -308,8 +309,6 @@ gs_app_to_string (GsApp *app)
        }
        if (app->reviews != NULL)
                gs_app_kv_printf (str, "reviews", "%i", app->reviews->len);
-       if (app->pixbuf != NULL)
-               gs_app_kv_printf (str, "pixbuf", "%p", app->pixbuf);
        if (app->install_date != 0) {
                gs_app_kv_printf (str, "install-date", "%"
                                  G_GUINT64_FORMAT "",
@@ -959,55 +958,6 @@ gs_app_set_project_group (GsApp *app, const gchar *project_group)
 }
 
 /**
- * gs_app_is_addon_id_kind
- **/
-static gboolean
-gs_app_is_addon_id_kind (GsApp *app)
-{
-       AsAppKind kind;
-       kind = gs_app_get_kind (app);
-       if (kind == AS_APP_KIND_DESKTOP)
-               return FALSE;
-       if (kind == AS_APP_KIND_WEB_APP)
-               return FALSE;
-       return TRUE;
-}
-
-static GtkIconTheme    *icon_theme_singleton;
-static GMutex           icon_theme_lock;
-static GHashTable      *icon_theme_paths;
-
-/**
- * icon_theme_get:
- */
-static GtkIconTheme *
-icon_theme_get (void)
-{
-       if (icon_theme_singleton == NULL)
-               icon_theme_singleton = gtk_icon_theme_new ();
-
-       return icon_theme_singleton;
-}
-
-/**
- * icon_theme_add_path:
- */
-static void
-icon_theme_add_path (const gchar *path)
-{
-       if (path == NULL)
-               return;
-
-       if (icon_theme_paths == NULL)
-               icon_theme_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
-       if (!g_hash_table_contains (icon_theme_paths, path)) {
-               gtk_icon_theme_prepend_search_path (icon_theme_get (), path);
-               g_hash_table_add (icon_theme_paths, g_strdup (path));
-       }
-}
-
-/**
  * gs_app_get_pixbuf:
  * @app: a #GsApp
  *
@@ -1018,56 +968,10 @@ icon_theme_add_path (const gchar *path)
 GdkPixbuf *
 gs_app_get_pixbuf (GsApp *app)
 {
-       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&icon_theme_lock);
-
        g_return_val_if_fail (GS_IS_APP (app), NULL);
-
-       /* has an icon */
-       if (app->pixbuf == NULL &&
-           app->icon != NULL &&
-           as_icon_get_kind (app->icon) == AS_ICON_KIND_STOCK) {
-               app->pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                             as_icon_get_name (app->icon), 64,
-                                                             GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                             GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                             NULL);
-
-       } else if (app->pixbuf == NULL && gs_app_get_state (app) == AS_APP_STATE_AVAILABLE_LOCAL) {
-               const gchar *icon_name;
-               if (gs_app_get_kind (app) == AS_APP_KIND_SOURCE)
-                       icon_name = "x-package-repository";
-               else if (gs_app_is_addon_id_kind (app))
-                       icon_name = "application-x-addon";
-               else
-                       icon_name = "application-x-executable";
-               app->pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                             icon_name, 96,
-                                                             GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                             GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                             NULL);
-
-       } else if (app->pixbuf == NULL && gs_app_get_kind (app) == AS_APP_KIND_GENERIC) {
-               app->pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                             "application-x-addon-symbolic", 64,
-                                                             GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                             GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                             NULL);
-       } else if (app->pixbuf == NULL && gs_app_get_kind (app) == AS_APP_KIND_OS_UPDATE) {
-               app->pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                             "software-update-available-symbolic", 64,
-                                                             GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                             GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                             NULL);
-       } else if (app->pixbuf == NULL &&
-                  gs_app_get_state (app) == AS_APP_STATE_UNAVAILABLE) {
-               app->pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                             "dialog-question-symbolic", 16,
-                                                             GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                             GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                             NULL);
-       }
-
-       return app->pixbuf;
+       if (app->icon == NULL)
+               return NULL;
+       return as_icon_get_pixbuf (app->icon);
 }
 
 /**
@@ -1160,69 +1064,6 @@ gs_app_set_runtime (GsApp *app, GsApp *runtime)
 }
 
 /**
- * gs_app_load_icon:
- * @app: a #GsApp
- * @scale: a window scale factor, e.g. 2 for HiDPI displays
- * @error: a #GError, or %NULL
- *
- * Loads an icon to a pixbuf for the application.
- *
- * Returns: %TRUE for success
- **/
-gboolean
-gs_app_load_icon (GsApp *app, gint scale, GError **error)
-{
-       AsIcon *icon;
-       g_autoptr(GdkPixbuf) pixbuf = NULL;
-
-       g_return_val_if_fail (GS_IS_APP (app), FALSE);
-       g_return_val_if_fail (app->icon != NULL, FALSE);
-
-       /* either load from the theme or from a file */
-       icon = gs_app_get_icon (app);
-       switch (as_icon_get_kind (icon)) {
-       case AS_ICON_KIND_LOCAL:
-               if (as_icon_get_filename (icon) == NULL) {
-                       g_set_error (error,
-                                    GS_PLUGIN_ERROR,
-                                    GS_PLUGIN_ERROR_FAILED,
-                                    "%s icon has no filename",
-                                    as_icon_get_name (icon));
-                       return FALSE;
-               }
-               pixbuf = gdk_pixbuf_new_from_file_at_size (as_icon_get_filename (icon),
-                                                          64 * scale,
-                                                          64 * scale,
-                                                          error);
-               break;
-       case AS_ICON_KIND_STOCK:
-       {
-               g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&icon_theme_lock);
-
-               icon_theme_add_path (as_icon_get_prefix (icon));
-               pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
-                                                  as_icon_get_name (icon),
-                                                  64 * scale,
-                                                  GTK_ICON_LOOKUP_USE_BUILTIN |
-                                                  GTK_ICON_LOOKUP_FORCE_SIZE,
-                                                  error);
-               break;
-       }
-       default:
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "%s icon cannot be loaded",
-                            as_icon_kind_to_string (as_icon_get_kind (icon)));
-               break;
-       }
-       if (pixbuf == NULL)
-               return FALSE;
-       gs_app_set_pixbuf (app, pixbuf);
-       return TRUE;
-}
-
-/**
  * gs_app_set_pixbuf:
  * @app: a #GsApp
  * @pixbuf: a #GdkPixbuf, or %NULL
@@ -1233,7 +1074,11 @@ void
 gs_app_set_pixbuf (GsApp *app, GdkPixbuf *pixbuf)
 {
        g_return_if_fail (GS_IS_APP (app));
-       g_set_object (&app->pixbuf, pixbuf);
+       if (app->icon == NULL) {
+               g_warning ("trying to set pixbuf on %s with no icon", app->id);
+               return;
+       }
+       as_icon_set_pixbuf (app->icon, pixbuf);
 }
 
 typedef enum {
@@ -2797,7 +2642,6 @@ gs_app_dispose (GObject *object)
 
        g_clear_object (&app->icon);
        g_clear_object (&app->runtime);
-       g_clear_object (&app->pixbuf);
 
        g_clear_pointer (&app->addons, g_ptr_array_unref);
        g_clear_pointer (&app->history, g_ptr_array_unref);
diff --git a/src/gs-app.h b/src/gs-app.h
index 6348e7d..d9eac28 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -210,9 +210,6 @@ void                 gs_app_set_local_file          (GsApp          *app,
 GsApp          *gs_app_get_runtime             (GsApp          *app);
 void            gs_app_set_runtime             (GsApp          *app,
                                                 GsApp          *runtime);
-gboolean        gs_app_load_icon               (GsApp          *app,
-                                                gint            scale,
-                                                GError         **error);
 const gchar    *gs_app_get_metadata_item       (GsApp          *app,
                                                 const gchar    *key);
 void            gs_app_set_metadata            (GsApp          *app,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 3813e70..b9ca0e7 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -432,6 +432,8 @@ out:
        return ret;
 }
 
+static GList *gs_plugin_loader_add_os_update_item (GList *list);
+
 /**
  * gs_plugin_loader_run_results:
  **/
@@ -515,6 +517,19 @@ gs_plugin_loader_run_results (GsPluginLoader *plugin_loader,
        if (!ret)
                goto out;
 
+       /* coalesce all packages down into one os-update */
+       if (g_strcmp0 (function_name, "gs_plugin_add_updates") == 0) {
+               list = gs_plugin_loader_add_os_update_item (list);
+               ret = gs_plugin_loader_run_refine (plugin_loader,
+                                                  function_name,
+                                                  &list,
+                                                  GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+                                                  cancellable,
+                                                  error);
+               if (!ret)
+                       goto out;
+       }
+
        /* filter package list */
        gs_app_list_filter_duplicates (&list);
 
@@ -872,6 +887,7 @@ gs_plugin_loader_add_os_update_item (GList *list)
        GsApp *app_tmp;
        g_autoptr(GError) error = NULL;
        g_autoptr(GdkPixbuf) pixbuf = NULL;
+       g_autoptr(AsIcon) ic = NULL;
 
        /* do we have any packages left that are not apps? */
        for (l = list; l != NULL; l = l->next) {
@@ -886,6 +902,7 @@ gs_plugin_loader_add_os_update_item (GList *list)
 
        /* create new meta object */
        app_os = gs_app_new ("os-update.virtual");
+       gs_app_set_management_plugin (app_os, "");
        gs_app_set_kind (app_os, AS_APP_KIND_OS_UPDATE);
        gs_app_set_state (app_os, AS_APP_STATE_UPDATABLE_LIVE);
        gs_app_set_name (app_os,
@@ -907,6 +924,10 @@ gs_plugin_loader_add_os_update_item (GList *list)
                        continue;
                gs_app_add_related (app_os, app_tmp);
        }
+       ic = as_icon_new ();
+       as_icon_set_kind (ic, AS_ICON_KIND_STOCK);
+       as_icon_set_name (ic, "software-update-available-symbolic");
+       gs_app_set_icon (app_os, ic);
 
        return g_list_prepend (list, app_os);
 }
@@ -942,9 +963,6 @@ gs_plugin_loader_get_updates_thread_cb (GTask *task,
        /* filter package list */
        gs_app_list_filter_duplicates (&state->list);
 
-       /* coalesce all packages down into one os-update */
-       state->list = gs_plugin_loader_add_os_update_item (state->list);
-
        /* remove any packages that are not proper applications or
         * OS updates */
        gs_app_list_filter (&state->list, gs_plugin_loader_app_is_valid, state);
@@ -2548,6 +2566,10 @@ gs_plugin_loader_app_refine_async (GsPluginLoader *plugin_loader,
        state->app = g_object_ref (app);
        state->flags = flags;
 
+       /* enforce this */
+       if (state->flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS)
+               state->flags |= GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON;
+
        /* run in a thread */
        task = g_task_new (plugin_loader, cancellable, callback, user_data);
        g_task_set_task_data (task, state, (GDestroyNotify) gs_plugin_loader_free_async_state);
@@ -3971,6 +3993,32 @@ gs_plugin_loader_file_to_app_thread_cb (GTask *task,
                return;
        }
 
+       /* check the apps have an icon set */
+       for (l = state->list; l != NULL; l = l->next) {
+               GsApp *app = GS_APP (l->data);
+               if (gs_app_get_icon (app) == NULL) {
+                       g_autoptr(AsIcon) ic = as_icon_new ();
+                       as_icon_set_kind (ic, AS_ICON_KIND_STOCK);
+                       if (gs_app_get_kind (app) == AS_APP_KIND_SOURCE)
+                               as_icon_set_name (ic, "x-package-repository");
+                       else
+                               as_icon_set_name (ic, "application-x-executable");
+                       gs_app_set_icon (app, ic);
+               }
+       }
+
+       /* run refine() on each one again to pick up any icons */
+       ret = gs_plugin_loader_run_refine (plugin_loader,
+                                          function_name,
+                                          &state->list,
+                                          GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
+                                          cancellable,
+                                          &error);
+       if (!ret) {
+               g_task_return_error (task, error);
+               return;
+       }
+
        /* success */
        if (g_list_length (state->list) != 1) {
                g_task_return_new_error (task,
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 5a71f65..6e78451 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -142,6 +142,7 @@ typedef enum {
  * @GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEWS:            Require user-reviews
  * @GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS:     Require user-ratings
  * @GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS:         Require the key colors
+ * @GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON:               Require the icon to be loaded
  *
  * The refine flags.
  **/
@@ -168,6 +169,7 @@ typedef enum {
        GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEWS          = 1 << 18,
        GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS   = 1 << 19,
        GS_PLUGIN_REFINE_FLAGS_REQUIRE_KEY_COLORS       = 1 << 20,
+       GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON             = 1 << 21,
        /*< private >*/
        GS_PLUGIN_REFINE_FLAGS_LAST
 } GsPluginRefineFlags;
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 5600b1d..1726a68 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -442,7 +442,7 @@ gs_plugin_loader_webapps_func (GsPluginLoader *plugin_loader)
        app = gs_app_new ("arachne.desktop");
        gs_app_set_kind (app, AS_APP_KIND_WEB_APP);
        ret = gs_plugin_loader_app_refine (plugin_loader, app,
-                                          GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+                                          GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
                                           NULL,
                                           &error);
        g_assert_no_error (error);
diff --git a/src/gs-shell-category.c b/src/gs-shell-category.c
index b6ca31e..7701891 100644
--- a/src/gs-shell-category.c
+++ b/src/gs-shell-category.c
@@ -153,7 +153,7 @@ gs_shell_category_populate_filtered (GsShellCategory *self, GsCategory *subcateg
 
        gs_plugin_loader_get_category_apps_async (self->plugin_loader,
                                                  subcategory,
-                                                 GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                 GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                  GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
                                                  GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING,
                                                  self->cancellable,
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index f46ddf9..b1dc7e4 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -1437,7 +1437,7 @@ gs_shell_details_set_filename (GsShellDetails *self, const gchar *filename)
        file = g_file_new_for_path (filename);
        gs_plugin_loader_file_to_app_async (self->plugin_loader,
                                            file,
-                                           GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                           GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING |
                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS |
                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEWS,
@@ -1453,6 +1453,7 @@ static void
 gs_shell_details_load (GsShellDetails *self)
 {
        gs_plugin_loader_app_refine_async (self->plugin_loader, self->app,
+                                          GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                           GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE |
                                           GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE |
                                           GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING |
diff --git a/src/gs-shell-extras.c b/src/gs-shell-extras.c
index 0c8b576..1ab8ab9 100644
--- a/src/gs-shell-extras.c
+++ b/src/gs-shell-extras.c
@@ -693,7 +693,7 @@ gs_shell_extras_load (GsShellExtras *self, GPtrArray *array_search_data)
                        g_debug ("searching filename: '%s'", search_data->search_filename);
                        gs_plugin_loader_search_files_async (self->plugin_loader,
                                                             search_data->search_filename,
-                                                            GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                             GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING |
                                                             GS_PLUGIN_REFINE_FLAGS_ALLOW_PACKAGES,
                                                             self->search_cancellable,
@@ -705,7 +705,7 @@ gs_shell_extras_load (GsShellExtras *self, GPtrArray *array_search_data)
                        file = g_file_new_for_path (search_data->package_filename);
                        gs_plugin_loader_file_to_app_async (self->plugin_loader,
                                                            file,
-                                                           GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                           GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_RATING |
                                                            GS_PLUGIN_REFINE_FLAGS_ALLOW_PACKAGES,
                                                            self->search_cancellable,
@@ -715,7 +715,7 @@ gs_shell_extras_load (GsShellExtras *self, GPtrArray *array_search_data)
                        g_debug ("searching what provides: '%s'", search_data->search);
                        gs_plugin_loader_search_what_provides_async (self->plugin_loader,
                                                                     search_data->search,
-                                                                    GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                                    GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                                     GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
                                                                     GS_PLUGIN_REFINE_FLAGS_REQUIRE_HISTORY |
                                                                     
GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
diff --git a/src/gs-shell-installed.c b/src/gs-shell-installed.c
index 8016370..92bc7c2 100644
--- a/src/gs-shell-installed.c
+++ b/src/gs-shell-installed.c
@@ -232,7 +232,7 @@ gs_shell_installed_load (GsShellInstalled *self)
 
        /* get popular apps */
        gs_plugin_loader_get_installed_async (self->plugin_loader,
-                                             GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                             GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                              GS_PLUGIN_REFINE_FLAGS_REQUIRE_HISTORY |
                                              GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
                                              GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
diff --git a/src/gs-shell-moderate.c b/src/gs-shell-moderate.c
index 227f23f..482cb90 100644
--- a/src/gs-shell-moderate.c
+++ b/src/gs-shell-moderate.c
@@ -185,7 +185,7 @@ gs_shell_moderate_load (GsShellModerate *self)
 
        /* get unvoted reviews as apps */
        gs_plugin_loader_get_unvoted_reviews_async (self->plugin_loader,
-                                                   GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                   GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                    GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
                                                    GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
                                                    GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE |
diff --git a/src/gs-shell-search-provider.c b/src/gs-shell-search-provider.c
index 4666e06..fb44ed4 100644
--- a/src/gs-shell-search-provider.c
+++ b/src/gs-shell-search-provider.c
@@ -193,7 +193,7 @@ handle_get_result_metas (GsShellSearchProvider2     *skeleton,
                /* find the application with this ID */
                app = gs_plugin_loader_get_app_by_id (self->plugin_loader,
                                                      results[i],
-                                                     GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                                     GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                                      GS_PLUGIN_REFINE_FLAGS_REQUIRE_DESCRIPTION,
                                                      NULL,
                                                      &error);
diff --git a/src/gs-shell-search.c b/src/gs-shell-search.c
index 0d2d3cb..5062dc1 100644
--- a/src/gs-shell-search.c
+++ b/src/gs-shell-search.c
@@ -160,7 +160,7 @@ gs_shell_search_load (GsShellSearch *self)
        /* search for apps */
        gs_plugin_loader_search_async (self->plugin_loader,
                                       self->value,
-                                      GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+                                      GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION |
                                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE |
                                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_HISTORY |
diff --git a/src/gs-shell-updates.c b/src/gs-shell-updates.c
index d1a8c09..167abcf 100644
--- a/src/gs-shell-updates.c
+++ b/src/gs-shell-updates.c
@@ -591,7 +591,7 @@ gs_shell_updates_load (GsShellUpdates *self)
        if (self->in_flight > 0)
                return;
        gs_container_remove_all (GTK_CONTAINER (self->list_box_updates));
-       refine_flags = GS_PLUGIN_REFINE_FLAGS_DEFAULT |
+       refine_flags = GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON |
                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_DETAILS |
                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_PROVENANCE |
                       GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION;
diff --git a/src/plugins/gs-appstream.c b/src/plugins/gs-appstream.c
index bf16afc..763e283 100644
--- a/src/plugins/gs-appstream.c
+++ b/src/plugins/gs-appstream.c
@@ -39,9 +39,9 @@ gs_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item)
        g_autofree gchar *cachedir = NULL;
 
        icon = as_app_get_icon_default (item);
+       gs_app_set_icon (app, icon);
        switch (as_icon_get_kind (icon)) {
        case AS_ICON_KIND_REMOTE:
-               gs_app_set_icon (app, icon);
                if (as_icon_get_filename (icon) == NULL) {
                        fn = gs_utils_get_cache_filename ("icons",
                                                          as_icon_get_name (icon),
@@ -53,14 +53,12 @@ gs_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item)
                }
                break;
        case AS_ICON_KIND_STOCK:
+               break;
        case AS_ICON_KIND_LOCAL:
-               gs_app_set_icon (app, icon);
-
                /* does not exist, so try to find using the icon theme */
                if (as_icon_get_kind (icon) == AS_ICON_KIND_LOCAL &&
                    as_icon_get_filename (icon) == NULL)
                        as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
-
                break;
        case AS_ICON_KIND_CACHED:
                if (gs_plugin_get_scale (plugin) == 2)
diff --git a/src/plugins/gs-plugin-icons.c b/src/plugins/gs-plugin-icons.c
index 0c34179..05f58c0 100644
--- a/src/plugins/gs-plugin-icons.c
+++ b/src/plugins/gs-plugin-icons.c
@@ -30,10 +30,40 @@
  * SECTION:
  * Loads remote icons and converts them into local cached ones.
  *
- * It is provided so that each plugin handling REMOTE icons does not
+ * It is provided so that each plugin handling icons does not
  * have to handle the download and caching functionality.
  */
 
+struct GsPluginData {
+       GtkIconTheme            *icon_theme;
+       GMutex                   icon_theme_lock;
+       GHashTable              *icon_theme_paths;
+};
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+       GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
+       priv->icon_theme = gtk_icon_theme_new ();
+       priv->icon_theme_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+       g_mutex_init (&priv->icon_theme_lock);
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       g_object_unref (priv->icon_theme);
+       g_hash_table_unref (priv->icon_theme_paths);
+       g_mutex_clear (&priv->icon_theme_lock);
+}
+
 /**
  * gs_plugin_order_after:
  */
@@ -100,6 +130,82 @@ gs_plugin_icons_download (GsPlugin *plugin, const gchar *uri, const gchar *filen
 }
 
 /**
+ * gs_plugin_icons_load_local:
+ */
+static gboolean
+gs_plugin_icons_load_local (GsPlugin *plugin, GsApp *app, GError **error)
+{
+       AsIcon *icon;
+       g_autoptr(GdkPixbuf) pixbuf = NULL;
+
+       icon = gs_app_get_icon (app);
+       if (as_icon_get_filename (icon) == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "%s icon has no filename",
+                            gs_app_get_id (app));
+               return FALSE;
+       }
+       pixbuf = gdk_pixbuf_new_from_file_at_size (as_icon_get_filename (icon),
+                                                  64 * gs_plugin_get_scale (plugin),
+                                                  64 * gs_plugin_get_scale (plugin),
+                                                  error);
+       if (pixbuf == NULL)
+               return FALSE;
+       gs_app_set_pixbuf (app, pixbuf);
+       return TRUE;
+}
+
+/**
+ * gs_plugin_icons_add_theme_path:
+ */
+static void
+gs_plugin_icons_add_theme_path (GsPlugin *plugin, const gchar *path)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       if (path == NULL)
+               return;
+       if (!g_hash_table_contains (priv->icon_theme_paths, path)) {
+               gtk_icon_theme_prepend_search_path (priv->icon_theme, path);
+               g_hash_table_add (priv->icon_theme_paths, g_strdup (path));
+       }
+}
+
+/**
+ * gs_plugin_icons_load_stock:
+ */
+static gboolean
+gs_plugin_icons_load_stock (GsPlugin *plugin, GsApp *app, GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       AsIcon *icon;
+       g_autoptr(GdkPixbuf) pixbuf = NULL;
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->icon_theme_lock);
+
+       icon = gs_app_get_icon (app);
+       if (as_icon_get_name (icon) == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "%s icon has no name",
+                            gs_app_get_id (app));
+               return FALSE;
+       }
+       gs_plugin_icons_add_theme_path (plugin, as_icon_get_prefix (icon));
+       pixbuf = gtk_icon_theme_load_icon (priv->icon_theme,
+                                          as_icon_get_name (icon),
+                                          64 * gs_plugin_get_scale (plugin),
+                                          GTK_ICON_LOOKUP_USE_BUILTIN |
+                                          GTK_ICON_LOOKUP_FORCE_SIZE,
+                                          error);
+       if (pixbuf == NULL)
+               return FALSE;
+       gs_app_set_pixbuf (app, pixbuf);
+       return TRUE;
+}
+
+/**
  * gs_plugin_refine_app:
  */
 gboolean
@@ -113,6 +219,10 @@ gs_plugin_refine_app (GsPlugin *plugin,
        const gchar *fn;
        gchar *found;
 
+       /* not required */
+       if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON) == 0)
+               return TRUE;
+
        /* invalid */
        if (gs_app_get_pixbuf (app) != NULL)
                return TRUE;
@@ -120,15 +230,13 @@ gs_plugin_refine_app (GsPlugin *plugin,
        if (ic == NULL)
                return TRUE;
 
-       /* handle LOCAL and STOCK */
-       if (as_icon_get_kind (ic) == AS_ICON_KIND_LOCAL ||
-           as_icon_get_kind (ic) == AS_ICON_KIND_STOCK) {
-               return gs_app_load_icon (app,
-                                        gs_plugin_get_scale (plugin),
-                                        error);
-       }
+       /* handle different icon types */
+       if (as_icon_get_kind (ic) == AS_ICON_KIND_LOCAL)
+               return gs_plugin_icons_load_local (plugin, app, error);
+       if (as_icon_get_kind (ic) == AS_ICON_KIND_STOCK)
+               return gs_plugin_icons_load_stock (plugin, app, error);
 
-       /* not applicable */
+       /* not applicable for remote */
        if (as_icon_get_url (ic) == NULL)
                return TRUE;
        if (as_icon_get_filename (ic) == NULL)
@@ -138,9 +246,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
        if (g_str_has_prefix (as_icon_get_url (ic), "file://")) {
                as_icon_set_filename (ic, as_icon_get_url (ic) + 7);
                as_icon_set_kind (ic, AS_ICON_KIND_LOCAL);
-               return gs_app_load_icon (app,
-                                        gs_plugin_get_scale (plugin),
-                                        error);
+               return gs_plugin_icons_load_local (plugin, app, error);
        }
 
        /* convert filename from jpg to png */
@@ -155,5 +261,5 @@ gs_plugin_refine_app (GsPlugin *plugin,
        if (!gs_plugin_icons_download (plugin, as_icon_get_url (ic), fn, error))
                return FALSE;
        as_icon_set_kind (ic, AS_ICON_KIND_LOCAL);
-       return gs_app_load_icon (app, gs_plugin_get_scale (plugin), error);
+       return gs_plugin_icons_load_local (plugin, app, error);
 }


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