[gnome-software] Use an AsIcon internally to simplify a lot of complex code
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Use an AsIcon internally to simplify a lot of complex code
- Date: Thu, 11 Dec 2014 16:54:20 +0000 (UTC)
commit 0a4924dbd8ed120fbd1fec261c786217643d0860
Author: Richard Hughes <richard hughsie com>
Date: Wed Dec 10 11:49:31 2014 +0000
Use an AsIcon internally to simplify a lot of complex code
This allows us to do three things:
* Simplify the icon loading, and remove a lot of hacks and heuristics used.
* Split out a plugin to download icons, which allows us to support remote icons
for non-webapps which we'll use to good effect soon.
* Simplify the epiphany web-app integration to avoid having two places to query
application state.
src/gs-app.c | 107 ++++--
src/gs-app.h | 7 +-
src/gs-plugin-loader.c | 7 +-
src/gs-plugin.h | 1 +
src/gs-shell-details.c | 17 +-
src/gs-utils.c | 66 ----
src/gs-utils.h | 4 -
src/plugins/Makefile.am | 6 +
src/plugins/gs-plugin-appstream.c | 42 ++-
src/plugins/gs-plugin-epiphany.c | 724 ++++++++-----------------------------
src/plugins/gs-plugin-icons.c | 216 +++++++++++
11 files changed, 503 insertions(+), 694 deletions(-)
---
diff --git a/src/gs-app.c b/src/gs-app.c
index 5fd2e5a..ca21192 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -56,8 +56,7 @@ struct GsAppPrivate
gchar *id;
gchar *name;
GsAppQuality name_quality;
- gchar *icon;
- gchar *icon_path;
+ AsIcon *icon;
GPtrArray *sources;
GPtrArray *source_ids;
gchar *project_group;
@@ -213,10 +212,19 @@ gs_app_to_string (GsApp *app)
gs_app_get_kudos_percentage (app));
if (priv->name != NULL)
g_string_append_printf (str, "\tname:\t%s\n", priv->name);
- if (priv->icon != NULL)
- g_string_append_printf (str, "\ticon:\t%s\n", priv->icon);
- if (priv->icon_path != NULL)
- g_string_append_printf (str, "\ticon-path:\t%s\n", priv->icon_path);
+ if (priv->icon != NULL) {
+ g_string_append_printf (str, "\ticon-kind:\t%s\n",
+ as_icon_kind_to_string (as_icon_get_kind (priv->icon)));
+ if (as_icon_get_name (priv->icon) != NULL)
+ g_string_append_printf (str, "\ticon-name:\t%s\n",
+ as_icon_get_name (priv->icon));
+ if (as_icon_get_prefix (priv->icon) != NULL)
+ g_string_append_printf (str, "\ticon-prefix:\t%s\n",
+ as_icon_get_prefix (priv->icon));
+ if (as_icon_get_filename (priv->icon) != NULL)
+ g_string_append_printf (str, "\ticon-filename:\t%s\n",
+ as_icon_get_filename (priv->icon));
+ }
if (priv->version != NULL)
g_string_append_printf (str, "\tversion:\t%s\n", priv->version);
if (priv->version_ui != NULL)
@@ -782,7 +790,7 @@ gs_app_get_pixbuf (GsApp *app)
/**
* gs_app_get_icon:
*/
-const gchar *
+AsIcon *
gs_app_get_icon (GsApp *app)
{
g_return_val_if_fail (GS_IS_APP (app), NULL);
@@ -793,37 +801,48 @@ gs_app_get_icon (GsApp *app)
* gs_app_set_icon:
*/
void
-gs_app_set_icon (GsApp *app, const gchar *icon)
+gs_app_set_icon (GsApp *app, AsIcon *icon)
{
g_return_if_fail (GS_IS_APP (app));
- g_return_if_fail (icon != NULL);
/* save icon */
- g_free (app->priv->icon);
- app->priv->icon = g_strdup (icon);
+ g_clear_object (&app->priv->icon);
+ if (icon != NULL)
+ app->priv->icon = g_object_ref (icon);
}
+static GtkIconTheme *icon_theme_singleton;
+static GMutex icon_theme_lock;
+static GHashTable *icon_theme_paths;
+
/**
- * gs_app_get_icon_path:
+ * icon_theme_get:
*/
-const gchar *
-gs_app_get_icon_path (GsApp *app)
+static GtkIconTheme *
+icon_theme_get (void)
{
- g_return_val_if_fail (GS_IS_APP (app), NULL);
- return app->priv->icon_path;
+ if (icon_theme_singleton == NULL)
+ icon_theme_singleton = gtk_icon_theme_new ();
+
+ return icon_theme_singleton;
}
/**
- * gs_app_set_icon_path:
+ * icon_theme_add_path:
*/
-void
-gs_app_set_icon_path (GsApp *app, const gchar *icon_path)
+static void
+icon_theme_add_path (const gchar *path)
{
- g_return_if_fail (GS_IS_APP (app));
+ 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);
- /* save theme path */
- g_free (app->priv->icon_path);
- app->priv->icon_path = g_strdup (icon_path);
+ 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));
+ }
}
/**
@@ -832,6 +851,7 @@ gs_app_set_icon_path (GsApp *app, const gchar *icon_path)
gboolean
gs_app_load_icon (GsApp *app, gint scale, GError **error)
{
+ AsIcon *icon;
GdkPixbuf *pixbuf = NULL;
gboolean ret = TRUE;
@@ -839,8 +859,41 @@ gs_app_load_icon (GsApp *app, gint scale, GError **error)
g_return_val_if_fail (app->priv->icon != NULL, FALSE);
/* either load from the theme or from a file */
- pixbuf = gs_pixbuf_load (app->priv->icon, app->priv->icon_path,
- 64 * scale, error);
+ 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_mutex_lock (&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);
+ g_mutex_unlock (&icon_theme_lock);
+ 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) {
ret = FALSE;
goto out;
@@ -2045,8 +2098,6 @@ gs_app_finalize (GObject *object)
g_free (priv->id);
g_free (priv->name);
g_hash_table_unref (priv->urls);
- g_free (priv->icon);
- g_free (priv->icon_path);
g_free (priv->licence);
g_free (priv->menu_path);
g_free (priv->origin);
@@ -2069,6 +2120,8 @@ gs_app_finalize (GObject *object)
g_hash_table_unref (priv->related_hash);
g_ptr_array_unref (priv->related);
g_ptr_array_unref (priv->history);
+ if (priv->icon != NULL)
+ g_object_unref (priv->icon);
if (priv->pixbuf != NULL)
g_object_unref (priv->pixbuf);
if (priv->featured_pixbuf != NULL)
diff --git a/src/gs-app.h b/src/gs-app.h
index 4fddcbe..0d946c3 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -194,12 +194,9 @@ void gs_app_set_management_plugin (GsApp *app,
GdkPixbuf *gs_app_get_pixbuf (GsApp *app);
void gs_app_set_pixbuf (GsApp *app,
GdkPixbuf *pixbuf);
-const gchar *gs_app_get_icon (GsApp *app);
+AsIcon *gs_app_get_icon (GsApp *app);
void gs_app_set_icon (GsApp *app,
- const gchar *icon);
-const gchar *gs_app_get_icon_path (GsApp *app);
-void gs_app_set_icon_path (GsApp *app,
- const gchar *icon_path);
+ AsIcon *icon);
gboolean gs_app_load_icon (GsApp *app,
gint scale,
GError **error);
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 034451f..d66fc04 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -1515,6 +1515,7 @@ gs_plugin_loader_get_featured_finish (GsPluginLoader *plugin_loader,
static gboolean
gs_plugin_loader_convert_unavailable_app (GsApp *app, const gchar *search)
{
+ AsIcon *icon;
GPtrArray *keywords;
GString *tmp;
const gchar *keyword;
@@ -1542,9 +1543,13 @@ gs_plugin_loader_convert_unavailable_app (GsApp *app, const gchar *search)
gs_app_set_summary_missing (app, tmp->str);
gs_app_set_kind (app, GS_APP_KIND_MISSING);
gs_app_set_size (app, GS_APP_SIZE_MISSING);
- gs_app_set_icon (app, "dialog-question-symbolic");
+ icon = as_icon_new ();
+ as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
+ as_icon_set_name (icon, "dialog-question-symbolic", -1);
+ gs_app_set_icon (app, icon);
gs_app_load_icon (app, 1, NULL);
g_string_free (tmp, TRUE);
+ g_object_unref (icon);
return TRUE;
}
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 5c9399e..84ee6f4 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -29,6 +29,7 @@
#include "gs-app.h"
#include "gs-category.h"
+#include "gs-cleanup.h"
#include "gs-profile.h"
G_BEGIN_DECLS
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 92c942b..d95dd35 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -548,7 +548,11 @@ gs_shell_details_refresh_all (GsShellDetails *shell_details)
/* set the icon */
tmp = gs_app_get_metadata_item (priv->app, "DataDir::desktop-icon");
if (tmp != NULL) {
- pixbuf = gs_pixbuf_load (tmp, NULL, 96, &error);
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ tmp, 96,
+ GTK_ICON_LOOKUP_USE_BUILTIN |
+ GTK_ICON_LOOKUP_FORCE_SIZE,
+ &error);
if (pixbuf == NULL) {
g_warning ("Failed to load desktop icon: %s",
error->message);
@@ -559,11 +563,16 @@ gs_shell_details_refresh_all (GsShellDetails *shell_details)
pixbuf = gs_app_get_pixbuf (priv->app);
if (pixbuf == NULL && gs_app_get_state (priv->app) == AS_APP_STATE_AVAILABLE_LOCAL) {
if (gs_app_get_kind (priv->app) == GS_APP_KIND_SOURCE)
- pixbuf = gs_pixbuf_load ("x-package-repository", NULL, 96, NULL);
+ tmp = "x-package-repository";
else if (gs_shell_details_is_addon_id_kind (priv->app))
- pixbuf = gs_pixbuf_load ("application-x-addon", NULL, 96, NULL);
+ tmp = "application-x-addon";
else
- pixbuf = gs_pixbuf_load ("application-x-executable", NULL, 96, NULL);
+ tmp = "application-x-executable";
+ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ tmp, 96,
+ GTK_ICON_LOOKUP_USE_BUILTIN |
+ GTK_ICON_LOOKUP_FORCE_SIZE,
+ NULL);
}
if (pixbuf != NULL) {
gs_image_set_from_pixbuf (GTK_IMAGE (priv->application_details_icon), pixbuf);
diff --git a/src/gs-utils.c b/src/gs-utils.c
index 30fdd9c..01fa2d7 100644
--- a/src/gs-utils.c
+++ b/src/gs-utils.c
@@ -249,72 +249,6 @@ gs_mkdir_parent (const gchar *path, GError **error)
return ret;
}
-static GtkIconTheme *icon_theme_singleton;
-static GMutex icon_theme_lock;
-static GHashTable *icon_theme_paths;
-
-static GtkIconTheme *
-icon_theme_get (void)
-{
- if (icon_theme_singleton == NULL)
- icon_theme_singleton = gtk_icon_theme_new ();
-
- return icon_theme_singleton;
-}
-
-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_pixbuf_load:
- **/
-GdkPixbuf *
-gs_pixbuf_load (const gchar *icon_name,
- const gchar *icon_path,
- guint icon_size,
- GError **error)
-{
- GdkPixbuf *pixbuf = NULL;
-
- g_return_val_if_fail (icon_name != NULL, NULL);
- g_return_val_if_fail (icon_size > 0, NULL);
-
- if (icon_name[0] == '\0') {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Icon name not specified");
- } else if (icon_name[0] == '/') {
- pixbuf = gdk_pixbuf_new_from_file_at_size (icon_name,
- icon_size,
- icon_size,
- error);
- } else {
- g_mutex_lock (&icon_theme_lock);
- icon_theme_add_path (icon_path);
- pixbuf = gtk_icon_theme_load_icon (icon_theme_get (),
- icon_name,
- icon_size,
- GTK_ICON_LOOKUP_USE_BUILTIN |
- GTK_ICON_LOOKUP_FORCE_SIZE,
- error);
- g_mutex_unlock (&icon_theme_lock);
- }
- return pixbuf;
-}
-
static void
reboot_done (GObject *source, GAsyncResult *res, gpointer data)
{
diff --git a/src/gs-utils.h b/src/gs-utils.h
index bbc7a15..aeac877 100644
--- a/src/gs-utils.h
+++ b/src/gs-utils.h
@@ -45,10 +45,6 @@ guint gs_string_replace (GString *string,
const gchar *replace);
gboolean gs_mkdir_parent (const gchar *path,
GError **error);
-GdkPixbuf *gs_pixbuf_load (const gchar *icon_name,
- const gchar *icon_path,
- guint icon_size,
- GError **error);
void gs_reboot (GCallback reboot_failed);
void gs_image_set_from_pixbuf_with_scale (GtkImage *image,
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 9cad3e2..de60263 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -36,6 +36,7 @@ plugin_LTLIBRARIES = \
libgs_plugin_fedora_tagger_ratings.la \
libgs_plugin_fedora_tagger_usage.la \
libgs_plugin_epiphany.la \
+ libgs_plugin_icons.la \
libgs_plugin_systemd-updates.la \
libgs_plugin_packagekit-refine.la \
libgs_plugin_packagekit-refresh.la \
@@ -63,6 +64,11 @@ libgs_plugin_epiphany_la_LIBADD = $(GS_PLUGIN_LIBS) $(SOUP_LIBS)
libgs_plugin_epiphany_la_LDFLAGS = -module -avoid-version
libgs_plugin_epiphany_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+libgs_plugin_icons_la_SOURCES = gs-plugin-icons.c
+libgs_plugin_icons_la_LIBADD = $(GS_PLUGIN_LIBS) $(SOUP_LIBS)
+libgs_plugin_icons_la_LDFLAGS = -module -avoid-version
+libgs_plugin_icons_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+
libgs_plugin_self_test_la_SOURCES = gs-plugin-self-test.c
libgs_plugin_self_test_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_self_test_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index 08ea755..44984a5 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -256,22 +256,51 @@ out:
static void
gs_plugin_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item)
{
- GError *error = NULL;
AsIcon *icon;
+ GError *error = NULL;
gboolean ret;
+ gchar *fn = NULL;
+ gchar *path = NULL;
icon = as_app_get_icon_default (item);
switch (as_icon_get_kind (icon)) {
case AS_ICON_KIND_REMOTE:
- gs_app_set_icon (app, as_icon_get_name (icon));
+ gs_app_set_icon (app, icon);
+ path = g_build_filename (g_get_user_data_dir (),
+ "gnome-software",
+ "icons",
+ NULL);
+ fn = g_build_filename (path, as_icon_get_name (icon), NULL);
+ as_icon_set_filename (icon, fn);
+ as_icon_set_prefix (icon, path);
+ if (g_file_test (fn, G_FILE_TEST_EXISTS)) {
+ as_icon_set_kind (icon, AS_ICON_KIND_LOCAL);
+ ret = gs_app_load_icon (app, plugin->scale, &error);
+ if (!ret) {
+ g_warning ("failed to load icon %s: %s",
+ as_icon_get_name (icon),
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+ }
break;
case AS_ICON_KIND_STOCK:
case AS_ICON_KIND_LOCAL:
- gs_app_set_icon (app, as_icon_get_name (icon));
+ 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);
+
+ /* load */
ret = gs_app_load_icon (app, plugin->scale, &error);
if (!ret) {
- g_warning ("failed to load stock icon %s: %s",
- as_icon_get_name (icon), error->message);
+ g_warning ("failed to load %s icon %s: %s",
+ as_icon_kind_to_string (as_icon_get_kind (icon)),
+ as_icon_get_name (icon),
+ error->message);
g_error_free (error);
return;
}
@@ -298,6 +327,9 @@ gs_plugin_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item)
g_warning ("icon kind unknown for %s", as_app_get_id (item));
break;
}
+out:
+ g_free (path);
+ g_free (fn);
}
/**
diff --git a/src/plugins/gs-plugin-epiphany.c b/src/plugins/gs-plugin-epiphany.c
index ad7568f..0bce057 100644
--- a/src/plugins/gs-plugin-epiphany.c
+++ b/src/plugins/gs-plugin-epiphany.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -30,12 +30,6 @@
#include <gs-plugin.h>
#include <gs-utils.h>
-struct GsPluginPrivate {
- GList *list;
- SoupSession *session;
- gsize loaded;
-};
-
/**
* gs_plugin_get_name:
*/
@@ -51,9 +45,7 @@ gs_plugin_get_name (void)
void
gs_plugin_initialize (GsPlugin *plugin)
{
- char *epiphany;
-
- plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+ _cleanup_free_ gchar *epiphany = NULL;
/* we can only work with epiphany */
epiphany = g_find_program_in_path ("epiphany");
@@ -62,377 +54,85 @@ gs_plugin_initialize (GsPlugin *plugin)
g_debug ("disabling '%s' as epiphany does not exist",
plugin->name);
}
-
- g_free (epiphany);
-}
-
-/**
- * gs_plugin_destroy:
- */
-void
-gs_plugin_destroy (GsPlugin *plugin)
-{
- if (plugin->priv->session != NULL)
- g_object_unref (plugin->priv->session);
- gs_plugin_list_free (plugin->priv->list);
-}
-
-/**
- * gs_plugin_add_installed_file:
- */
-static gboolean
-gs_plugin_add_installed_file (GsPlugin *plugin,
- const gchar *filename,
- GsApp **app,
- GError **error)
-{
- GKeyFile *kf;
- gboolean no_display;
- gboolean ret;
- gchar *comment = NULL;
- gchar *icon = NULL;
- gchar *name = NULL;
- gchar *path;
-
- /* load keyfile */
- path = g_build_filename (g_get_user_data_dir (),
- "applications",
- filename,
- NULL);
- kf = g_key_file_new ();
- ret = g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error);
- if (!ret)
- goto out;
-
- /* check we're showing this */
- no_display = g_key_file_get_boolean (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
- NULL);
-
- /* get name */
- name = g_key_file_get_locale_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_NAME,
- NULL,
- error);
- if (name == NULL) {
- ret = FALSE;
- goto out;
- }
-
- /* get icon */
- icon = g_key_file_get_locale_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_ICON,
- NULL,
- error);
- if (icon == NULL) {
- ret = FALSE;
- goto out;
- }
-
- /* get comment */
- comment = g_key_file_get_locale_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_COMMENT,
- NULL,
- NULL);
- if (comment == NULL) {
- /* TRANSLATORS: this is when a webapp has no comment */
- comment = g_strdup_printf (_("Web app"));
- }
-
- /* create application */
- *app = gs_app_new (filename);
- gs_app_set_name (*app, GS_APP_QUALITY_NORMAL, name);
- gs_app_set_summary (*app, GS_APP_QUALITY_NORMAL, comment);
- /* TRANSLATORS: this is the licence of the web-app */
- gs_app_set_licence (*app, _("Proprietary"));
- gs_app_set_state (*app, no_display ? AS_APP_STATE_AVAILABLE :
- AS_APP_STATE_INSTALLED);
- gs_app_set_kind (*app, GS_APP_KIND_NORMAL);
- gs_app_set_id_kind (*app, AS_ID_KIND_WEB_APP);
- gs_app_add_source_id (*app, path);
- gs_app_set_icon (*app, icon);
- ret = gs_app_load_icon (*app, plugin->scale, error);
- if (!ret)
- goto out;
-out:
- g_key_file_free (kf);
- g_free (path);
- g_free (icon);
- g_free (name);
- g_free (comment);
- return ret;
}
/**
- * gs_plugin_epiphany_load_db:
+ * _gs_app_get_id_nonfull:
*/
-static gboolean
-gs_plugin_epiphany_load_db (GsPlugin *plugin, GError **error)
+static gchar *
+_gs_app_get_id_nonfull (GsApp *app)
{
- GDir *dir;
- GsApp *app = NULL;
- const gchar *filename;
- gboolean ret = TRUE;
- gchar *path;
-
- /* find any web apps */
- path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
- dir = g_dir_open (path, 0, error);
- if (dir == NULL) {
- ret = FALSE;
- goto out;
- }
- while ((filename = g_dir_read_name (dir)) != NULL) {
- if (!g_str_has_prefix (filename, "epiphany"))
- continue;
- if (!g_str_has_suffix (filename, ".desktop"))
- continue;
- ret = gs_plugin_add_installed_file (plugin,
- filename,
- &app,
- error);
- if (!ret)
- goto out;
- if (app != NULL) {
- gs_app_set_management_plugin (app, "Epiphany");
- gs_plugin_add_app (&plugin->priv->list, app);
- g_clear_object (&app);
- }
- }
-out:
- g_free (path);
- if (dir != NULL)
- g_dir_close (dir);
- return ret;
-}
-
-/**
- * gs_plugin_add_installed:
- */
-gboolean
-gs_plugin_add_installed (GsPlugin *plugin,
- GList **list,
- GCancellable *cancellable,
- GError **error)
-{
- GList *l;
- GsApp *app;
- gboolean ret = TRUE;
-
- /* already loaded */
- if (g_once_init_enter (&plugin->priv->loaded)) {
- ret = gs_plugin_epiphany_load_db (plugin, error);
- g_once_init_leave (&plugin->priv->loaded, TRUE);
- if (!ret)
- goto out;
- }
-
- /* add all installed apps */
- for (l = plugin->priv->list; l != NULL; l = l->next) {
- app = GS_APP (l->data);
- if (gs_app_get_state (app) != AS_APP_STATE_INSTALLED)
- continue;
- gs_plugin_add_app (list, app);
- }
-out:
- return ret;
-}
-
-/**
- * gs_plugin_epiphany_match_app_value:
- */
-static gboolean
-gs_plugin_epiphany_match_app_value (GsApp *app, const gchar *value)
-{
- if (strcasestr (gs_app_get_name (app), value) != NULL)
- return TRUE;
- if (strcasestr (gs_app_get_summary (app), value) != NULL)
- return TRUE;
- return FALSE;
-}
-
-/**
- * gs_plugin_epiphany_match_app:
- */
-static gboolean
-gs_plugin_epiphany_match_app (GsApp *app, gchar **values)
-{
- gboolean matches = FALSE;
- guint i;
-
- /* does the GsApp match *all* search keywords */
- for (i = 0; values[i] != NULL; i++) {
- matches = gs_plugin_epiphany_match_app_value (app, values[i]);
- if (!matches)
- break;
- }
- return matches;
-}
-
-/**
- * gs_plugin_add_search:
- */
-gboolean
-gs_plugin_add_search (GsPlugin *plugin,
- gchar **values,
- GList **list,
- GCancellable *cancellable,
- GError **error)
-{
- GList *l;
- GsApp *app;
- gboolean ret = TRUE;
-
- /* already loaded */
- if (g_once_init_enter (&plugin->priv->loaded)) {
- ret = gs_plugin_epiphany_load_db (plugin, error);
- g_once_init_leave (&plugin->priv->loaded, TRUE);
- if (!ret)
- goto out;
- }
-
- /* add any matching apps */
- for (l = plugin->priv->list; l != NULL; l = l->next) {
- if (g_cancellable_set_error_if_cancelled (cancellable, error))
- goto out;
-
- app = GS_APP (l->data);
- if (gs_plugin_epiphany_match_app (app, values))
- gs_plugin_add_app (list, app);
- }
-out:
- return ret;
-}
-
-/**
- * gs_plugin_app_set_enabled:
- */
-static gboolean
-gs_plugin_app_set_enabled (const gchar *filename, gboolean enabled, GError **error)
-{
- GKeyFile *kf;
- gboolean ret;
- gchar *data = NULL;
- gsize length;
-
- /* load file */
- kf = g_key_file_new ();
- ret = g_key_file_load_from_file (kf, filename, G_KEY_FILE_NONE, error);
- if (!ret)
- goto out;
-
- /* change value */
- g_key_file_set_boolean (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
- !enabled);
-
- /* save value */
- data = g_key_file_to_data (kf, &length, error);
- if (data == NULL) {
- ret = FALSE;
- goto out;
- }
- ret = g_file_set_contents (filename, data, length, error);
- if (!ret)
- goto out;
-out:
- g_free (data);
- g_key_file_free (kf);
- return ret;
+ gchar *id;
+ gchar *tmp;
+
+ id = g_strdup (gs_app_get_id (app));
+ tmp = g_strrstr (id, ".desktop");
+ if (tmp != NULL)
+ *tmp = '\0';
+ return id;
}
/**
* gs_plugin_app_install:
*/
gboolean
-gs_plugin_app_install (GsPlugin *plugin,
- GsApp *app,
- GCancellable *cancellable,
- GError **error)
+gs_plugin_app_install (GsPlugin *plugin, GsApp *app,
+ GCancellable *cancellable, GError **error)
{
- const gchar *filename;
- gboolean ret = TRUE;
-
- /* already loaded */
- if (g_once_init_enter (&plugin->priv->loaded)) {
- ret = gs_plugin_epiphany_load_db (plugin, error);
- g_once_init_leave (&plugin->priv->loaded, TRUE);
- if (!ret)
- goto out;
- }
-
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app), "Epiphany") != 0)
- goto out;
- filename = gs_app_get_source_id_default (app);
- if (filename == NULL)
- goto out;
- gs_app_set_state (app, AS_APP_STATE_INSTALLING);
- ret = gs_plugin_app_set_enabled (filename, TRUE, error);
- if (!ret)
- goto out;
- gs_app_set_state (app, AS_APP_STATE_INSTALLED);
-out:
- return ret;
-}
-
-/**
- * gs_plugin_app_remove:
- */
-gboolean
-gs_plugin_app_remove (GsPlugin *plugin,
- GsApp *app,
- GCancellable *cancellable,
- GError **error)
-{
- const gchar *filename;
+ AsIcon *icon;
gboolean ret = TRUE;
+ gsize kf_length;
+ _cleanup_error_free_ GError *error_local = NULL;
+ _cleanup_free_ gchar *app_desktop = NULL;
+ _cleanup_free_ gchar *epi_desktop = NULL;
+ _cleanup_free_ gchar *epi_dir = NULL;
+ _cleanup_free_ gchar *epi_icon = NULL;
+ _cleanup_free_ gchar *exec = NULL;
+ _cleanup_free_ gchar *hash = NULL;
+ _cleanup_free_ gchar *id_nonfull = NULL;
+ _cleanup_free_ gchar *kf_data = NULL;
+ _cleanup_free_ gchar *wmclass = NULL;
+ _cleanup_keyfile_unref_ GKeyFile *kf = NULL;
+ _cleanup_object_unref_ GFile *symlink_desktop = NULL;
+ _cleanup_object_unref_ GFile *symlink_icon = NULL;
+
+ /* only process web apps */
+ if (gs_app_get_id_kind (app) != AS_ID_KIND_WEB_APP)
+ return TRUE;
- /* already loaded */
- if (g_once_init_enter (&plugin->priv->loaded)) {
- ret = gs_plugin_epiphany_load_db (plugin, error);
- g_once_init_leave (&plugin->priv->loaded, TRUE);
- if (!ret)
- goto out;
+ /* create the correct directory */
+ id_nonfull = _gs_app_get_id_nonfull (app);
+ hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1);
+ epi_dir = g_strdup_printf ("%s/epiphany/app-%s-%s",
+ g_get_user_config_dir (),
+ id_nonfull,
+ hash);
+ g_mkdir_with_parents (epi_dir, 0755);
+
+ /* symlink icon */
+ epi_icon = g_build_filename (epi_dir, "app-icon.png", NULL);
+ symlink_icon = g_file_new_for_path (epi_icon);
+ icon = gs_app_get_icon (app);
+ ret = g_file_make_symbolic_link (symlink_icon,
+ as_icon_get_filename (icon),
+ NULL,
+ &error_local);
+ if (!ret) {
+ if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
+ g_debug ("ignoring icon symlink failure: %s",
+ error_local->message);
+ } else {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Can't symlink icon: %s",
+ error_local->message);
+ return FALSE;
+ }
}
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app), "Epiphany") != 0)
- goto out;
-
- filename = gs_app_get_source_id_default (app);
- if (filename == NULL)
- goto out;
- gs_app_set_state (app, AS_APP_STATE_REMOVING);
- ret = gs_plugin_app_set_enabled (filename, FALSE, error);
- if (!ret)
- goto out;
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
-out:
- return ret;
-}
-
-/**
- * gs_plugin_write_file:
- */
-static gboolean
-gs_plugin_write_file (GsApp *app, const gchar *filename, GError **error)
-{
- GKeyFile *kf;
- const gchar *url;
- gboolean enabled;
- gboolean ret;
- gchar *data;
- gchar *exec;
- gchar *profile;
- gchar *wmclass;
- gsize length;
-
+ /* add desktop file */
+ wmclass = g_strdup_printf ("%s-%s", id_nonfull, hash);
kf = g_key_file_new ();
g_key_file_set_string (kf,
G_KEY_FILE_DESKTOP_GROUP,
@@ -442,15 +142,9 @@ gs_plugin_write_file (GsApp *app, const gchar *filename, GError **error)
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_COMMENT,
gs_app_get_summary (app));
-
- url = gs_app_get_url (app, AS_URL_KIND_HOMEPAGE);
- wmclass = g_strdup_printf ("%s-%s",
- gs_app_get_id (app),
- gs_app_get_metadata_item (app, "Epiphany::hash"));
- profile = g_strdup_printf ("%s/epiphany/app-%s",
- g_get_user_config_dir (), wmclass);
- exec = g_strdup_printf ("epiphany --application-mode "
- "--profile=\"%s\" %s", profile, url);
+ exec = g_strdup_printf ("epiphany --application-mode --profile=\"%s\" %s",
+ epi_dir,
+ gs_app_get_url (app, AS_URL_KIND_HOMEPAGE));
g_key_file_set_string (kf,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_EXEC,
@@ -463,19 +157,10 @@ gs_plugin_write_file (GsApp *app, const gchar *filename, GError **error)
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_TERMINAL,
FALSE);
- switch (gs_app_get_state (app)) {
- case AS_APP_STATE_INSTALLING:
- case AS_APP_STATE_INSTALLED:
- enabled = TRUE;
- break;
- default:
- enabled = FALSE;
- break;
- }
g_key_file_set_boolean (kf,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
- !enabled);
+ FALSE);
g_key_file_set_string (kf,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_TYPE,
@@ -483,135 +168,74 @@ gs_plugin_write_file (GsApp *app, const gchar *filename, GError **error)
g_key_file_set_string (kf,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_ICON,
- gs_app_get_icon (app));
+ epi_icon);
g_key_file_set_string (kf,
G_KEY_FILE_DESKTOP_GROUP,
G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS,
wmclass);
/* save keyfile */
- data = g_key_file_to_data (kf, &length, error);
- if (data == NULL) {
- ret = FALSE;
- goto out;
- }
- ret = g_file_set_contents (filename, data, length, error);
+ kf_data = g_key_file_to_data (kf, &kf_length, error);
+ if (kf_data == NULL)
+ return FALSE;
+ epi_desktop = g_strdup_printf ("%s/%s.desktop", epi_dir, wmclass);
+ if (!g_file_set_contents (epi_desktop, kf_data, kf_length, error))
+ return FALSE;
+
+ /* symlink it to somewhere the shell will notice */
+ app_desktop = g_strdup_printf ("%s/applications/%s",
+ g_get_user_data_dir (),
+ gs_app_get_id (app));
+ symlink_desktop = g_file_new_for_path (app_desktop);
+ ret = g_file_make_symbolic_link (symlink_desktop,
+ epi_desktop,
+ NULL,
+ error);
if (!ret)
- goto out;
-out:
- g_free (data);
- g_free (profile);
- g_free (exec);
- g_free (wmclass);
- g_key_file_free (kf);
- return ret;
-}
-
-/**
- * gs_plugin_setup_networking:
- */
-static gboolean
-gs_plugin_setup_networking (GsPlugin *plugin, GError **error)
-{
- gboolean ret = TRUE;
-
- /* already set up */
- if (plugin->priv->session != NULL)
- goto out;
+ return FALSE;
- /* set up a session */
- plugin->priv->session = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT,
- "gnome-software",
- SOUP_SESSION_TIMEOUT, 5000,
- NULL);
- if (plugin->priv->session == NULL) {
- ret = FALSE;
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "%s: failed to setup networking",
- plugin->name);
- goto out;
- }
- soup_session_add_feature_by_type (plugin->priv->session,
- SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
-out:
- return ret;
+ /* update state */
+ gs_app_set_state (app, AS_APP_STATE_INSTALLING);
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ return TRUE;
}
/**
- * gs_plugin_epiphany_download:
+ * gs_plugin_app_remove:
*/
-static gboolean
-gs_plugin_epiphany_download (GsPlugin *plugin, const gchar *uri, const gchar *filename, GError **error)
+gboolean
+gs_plugin_app_remove (GsPlugin *plugin, GsApp *app,
+ GCancellable *cancellable, GError **error)
{
- GInputStream *stream = NULL;
- GdkPixbuf *pixbuf = NULL;
- GdkPixbuf *pixbuf_new = NULL;
- SoupMessage *msg = NULL;
- gboolean ret = TRUE;
- guint status_code;
-
- /* create the GET data */
- msg = soup_message_new (SOUP_METHOD_GET, uri);
- if (msg == NULL) {
- ret = FALSE;
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "%s is not a valid URL", uri);
- goto out;
- }
+ const gchar *epi_desktop;
+ _cleanup_free_ gchar *basename = NULL;
+ _cleanup_free_ gchar *app_desktop = NULL;
+ _cleanup_object_unref_ GFile *file_epi = NULL;
+ _cleanup_object_unref_ GFile *file_app = NULL;
- /* ensure networking is set up */
- ret = gs_plugin_setup_networking (plugin, error);
- if (!ret)
- goto out;
-
- /* set sync request */
- status_code = soup_session_send_message (plugin->priv->session, msg);
- if (status_code != SOUP_STATUS_OK) {
- ret = FALSE;
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Failed to download icon %s: %s",
- uri, soup_status_get_phrase (status_code));
- goto out;
- }
-
- /* we're assuming this is a 64x64 png file, resize if not */
- stream = g_memory_input_stream_new_from_data (msg->response_body->data,
- msg->response_body->length,
- NULL);
- pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
- if (pixbuf == NULL) {
- ret = FALSE;
- goto out;
- }
- if (gdk_pixbuf_get_height (pixbuf) == 64 &&
- gdk_pixbuf_get_width (pixbuf) == 64) {
- pixbuf_new = g_object_ref (pixbuf);
- } else {
- pixbuf_new = gdk_pixbuf_scale_simple (pixbuf, 64, 64,
- GDK_INTERP_BILINEAR);
- }
-
- /* write file */
- ret = gdk_pixbuf_save (pixbuf_new, filename, "png", error, NULL);
- if (!ret)
- goto out;
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "Epiphany") != 0)
+ return TRUE;
+ epi_desktop = gs_app_get_source_id_default (app);
+ if (epi_desktop == NULL)
+ return TRUE;
-out:
- if (stream != NULL)
- g_object_unref (stream);
- if (pixbuf_new != NULL)
- g_object_unref (pixbuf_new);
- if (pixbuf != NULL)
- g_object_unref (pixbuf);
- if (msg != NULL)
- g_object_unref (msg);
- return ret;
+ /* remove the epi 'config' file */
+ gs_app_set_state (app, AS_APP_STATE_REMOVING);
+ file_epi = g_file_new_for_path (epi_desktop);
+ if (!g_file_delete (file_epi, NULL, error))
+ return FALSE;
+
+ /* remove the shared desktop file */
+ basename = g_file_get_basename (file_epi);
+ app_desktop = g_strdup_printf ("%s/applications/%s",
+ g_get_user_data_dir (),
+ gs_app_get_id (app));
+ file_app = g_file_new_for_path (app_desktop);
+ if (!g_file_delete (file_app, NULL, error))
+ return FALSE;
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ return TRUE;
}
/**
@@ -620,79 +244,26 @@ out:
static gboolean
gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GError **error)
{
- gboolean ret;
- gchar *path = NULL;
- gchar *filename_icon = NULL;
- gchar *hash;
- GError *error_local = NULL;
- GFile *file = NULL;
+ _cleanup_free_ gchar *fn = NULL;
+ _cleanup_free_ gchar *hash = NULL;
+ _cleanup_free_ gchar *id_nonfull = NULL;
- /* this is not yet installed */
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
-
- /* calculate SHA1 hash of name */
+ id_nonfull = _gs_app_get_id_nonfull (app);
hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1);
- gs_app_set_metadata (app, "Epiphany::hash", hash);
-
- /* download icon if it does not exist */
- filename_icon = g_strdup_printf ("%s/epiphany/app-%s-%s/app-icon.png",
- g_get_user_config_dir (),
- gs_app_get_id (app),
- hash);
- if (!g_file_test (filename_icon, G_FILE_TEST_EXISTS)) {
- ret = gs_mkdir_parent (filename_icon, error);
- if (!ret)
- goto out;
- if (g_str_has_prefix (gs_app_get_icon (app), "/")) {
- file = g_file_new_for_path (filename_icon);
- ret = g_file_make_symbolic_link (file,
- gs_app_get_icon (app),
- NULL,
- &error_local);
- } else {
- ret = gs_plugin_epiphany_download (plugin,
- gs_app_get_icon (app),
- filename_icon,
- &error_local);
- }
- if (!ret) {
- /* this isn't a fatal error */
- gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
- gs_app_set_state (app, AS_APP_STATE_UNAVAILABLE);
- g_debug ("Failed to download %s: %s",
- gs_app_get_icon (app), error_local->message);
- g_error_free (error_local);
- ret = TRUE;
- goto out;
- }
+ fn = g_strdup_printf ("%s/epiphany/app-%s-%s/%s-%s.desktop",
+ g_get_user_config_dir (),
+ id_nonfull,
+ hash,
+ id_nonfull,
+ hash);
+ if (g_file_test (fn, G_FILE_TEST_EXISTS)) {
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ gs_app_add_source_id (app, fn);
+ gs_app_set_management_plugin (app, "Epiphany");
+ return TRUE;
}
-
- /* set local icon name */
- gs_app_set_icon (app, filename_icon);
- ret = gs_app_load_icon (app, plugin->scale, error);
- if (!ret)
- goto out;
-
- /* save file */
- path = g_build_filename (g_get_user_data_dir (),
- "applications",
- gs_app_get_id (app),
- NULL);
- ret = gs_plugin_write_file (app, path, error);
- if (!ret)
- goto out;
- gs_app_add_source_id (app, path);
-
- /* we now know about this */
- gs_plugin_add_app (&plugin->priv->list, app);
- gs_app_set_management_plugin (app, "Epiphany");
-out:
- if (file != NULL)
- g_object_unref (file);
- g_free (hash);
- g_free (path);
- g_free (filename_icon);
- return ret;
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ return TRUE;
}
/**
@@ -708,15 +279,6 @@ gs_plugin_refine (GsPlugin *plugin,
GList *l;
GsApp *app;
const gchar *tmp;
- gboolean ret = TRUE;
-
- /* already loaded */
- if (g_once_init_enter (&plugin->priv->loaded)) {
- ret = gs_plugin_epiphany_load_db (plugin, error);
- g_once_init_leave (&plugin->priv->loaded, TRUE);
- if (!ret)
- goto out;
- }
for (l = *list; l != NULL; l = l->next) {
app = GS_APP (l->data);
@@ -726,10 +288,8 @@ gs_plugin_refine (GsPlugin *plugin,
tmp = gs_app_get_source_id_default (app);
if (tmp != NULL)
continue;
- ret = gs_plugin_refine_app (plugin, app, error);
- if (!ret)
- goto out;
+ if (!gs_plugin_refine_app (plugin, app, error))
+ return FALSE;
}
-out:
- return ret;
+ return TRUE;
}
diff --git a/src/plugins/gs-plugin-icons.c b/src/plugins/gs-plugin-icons.c
new file mode 100644
index 0000000..a32ed61
--- /dev/null
+++ b/src/plugins/gs-plugin-icons.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#define _GNU_SOURCE
+#include <string.h>
+
+#include <glib/gi18n.h>
+#include <libsoup/soup.h>
+
+#include <gs-plugin.h>
+#include <gs-utils.h>
+
+struct GsPluginPrivate {
+ SoupSession *session;
+ gsize loaded;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+ return "icons";
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+}
+
+/**
+ * gs_plugin_get_deps:
+ */
+const gchar **
+gs_plugin_get_deps (GsPlugin *plugin)
+{
+ static const gchar *deps[] = {
+ "appstream", /* needs remote icons downloaded */
+ "epiphany", /* "" */
+ NULL };
+ return deps;
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+ if (plugin->priv->session != NULL)
+ g_object_unref (plugin->priv->session);
+}
+
+/**
+ * gs_plugin_setup_networking:
+ */
+static gboolean
+gs_plugin_setup_networking (GsPlugin *plugin, GError **error)
+{
+ /* already set up */
+ if (plugin->priv->session != NULL)
+ return TRUE;
+
+ /* set up a session */
+ plugin->priv->session = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT,
+ "gnome-software",
+ SOUP_SESSION_TIMEOUT, 5000,
+ NULL);
+ if (plugin->priv->session == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "%s: failed to setup networking",
+ plugin->name);
+ return FALSE;
+ }
+ soup_session_add_feature_by_type (plugin->priv->session,
+ SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
+ return TRUE;
+}
+
+/**
+ * gs_plugin_icons_download:
+ */
+static gboolean
+gs_plugin_icons_download (GsPlugin *plugin, const gchar *uri, const gchar *filename, GError **error)
+{
+ guint status_code;
+ _cleanup_object_unref_ GdkPixbuf *pixbuf_new = NULL;
+ _cleanup_object_unref_ GdkPixbuf *pixbuf = NULL;
+ _cleanup_object_unref_ GInputStream *stream = NULL;
+ _cleanup_object_unref_ SoupMessage *msg = NULL;
+
+ /* create the GET data */
+ msg = soup_message_new (SOUP_METHOD_GET, uri);
+ if (msg == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "%s is not a valid URL", uri);
+ return FALSE;
+ }
+
+ /* ensure networking is set up */
+ if (!gs_plugin_setup_networking (plugin, error))
+ return FALSE;
+
+ /* set sync request */
+ status_code = soup_session_send_message (plugin->priv->session, msg);
+ if (status_code != SOUP_STATUS_OK) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "Failed to download icon %s: %s",
+ uri, soup_status_get_phrase (status_code));
+ return FALSE;
+ }
+
+ /* we're assuming this is a 64x64 png file, resize if not */
+ stream = g_memory_input_stream_new_from_data (msg->response_body->data,
+ msg->response_body->length,
+ NULL);
+ pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
+ if (pixbuf == NULL)
+ return FALSE;
+ if (gdk_pixbuf_get_height (pixbuf) == 64 &&
+ gdk_pixbuf_get_width (pixbuf) == 64) {
+ pixbuf_new = g_object_ref (pixbuf);
+ } else {
+ pixbuf_new = gdk_pixbuf_scale_simple (pixbuf, 64, 64,
+ GDK_INTERP_BILINEAR);
+ }
+
+ /* write file */
+ return gdk_pixbuf_save (pixbuf_new, filename, "png", error, NULL);
+}
+
+/**
+ * gs_plugin_refine:
+ */
+static gboolean
+gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GError **error)
+{
+ AsIcon *ic;
+
+ /* not applicable */
+ ic = gs_app_get_icon (app);
+ if (as_icon_get_url (ic) == NULL)
+ return TRUE;
+ if (as_icon_get_filename (ic) == NULL)
+ return TRUE;
+
+ /* create runtime dir and download */
+ if (!gs_mkdir_parent (as_icon_get_prefix (ic), error))
+ return FALSE;
+ if (!gs_plugin_icons_download (plugin,
+ as_icon_get_url (ic),
+ as_icon_get_filename (ic),
+ error))
+ return FALSE;
+ as_icon_set_kind (ic, AS_ICON_KIND_LOCAL);
+ return gs_app_load_icon (app, plugin->scale, error);
+}
+
+/**
+ * gs_plugin_refine:
+ */
+gboolean
+gs_plugin_refine (GsPlugin *plugin,
+ GList **list,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GError *error_local = NULL;
+ GList *l;
+ GsApp *app;
+
+ for (l = *list; l != NULL; l = l->next) {
+ app = GS_APP (l->data);
+ if (gs_app_get_pixbuf (app) != NULL)
+ continue;
+ if (gs_app_get_icon (app) == NULL)
+ continue;
+ if (!gs_plugin_refine_app (plugin, app, &error_local)) {
+ g_warning ("ignoring: %s", error_local->message);
+ g_clear_error (&error_local);
+ }
+ }
+ return TRUE;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]