/** * as_icon_node_parse_dep11: * @icon: a #AsIcon instance. * @node: a #GNode. * @ctx: a #AsNodeContext. * @error: A #GError or %NULL. * * Populates the object from a DEP-11 node. * * Returns: %TRUE for success * * Since: 0.3.1 **/ gboolean as_icon_node_parse_dep11 (AsIcon *icon, GNode *node, AsNodeContext *ctx, GError **error) { GNode *n; AsIconPrivate *priv = GET_PRIVATE (icon); for (n = node->children; n != NULL; n = n->next) { const gchar *key; guint size; key = as_yaml_node_get_key (n); if (g_strcmp0 (key, "width") == 0) { size = as_yaml_node_get_value_as_uint (n); if (size == G_MAXUINT) size = 64; priv->width = size; } else if (g_strcmp0 (key, "height") == 0) { size = as_yaml_node_get_value_as_uint (n); if (size == G_MAXUINT) size = 64; priv->height = size; } else { if (priv->kind == AS_ICON_KIND_REMOTE) { if (g_strcmp0 (key, "url") == 0) { const gchar *media_baseurl; media_baseurl = as_node_context_get_media_base_url (ctx); if (media_baseurl == NULL) { /* no baseurl, we can just set the value as URL */ as_icon_set_url (icon, as_yaml_node_get_value (n)); } else { /* handle the media baseurl */ g_autofree gchar *url = NULL; url = g_build_filename (media_baseurl, as_yaml_node_get_value (n), NULL); as_icon_set_url (icon, url); } } } else { if (g_strcmp0 (key, "name") == 0) { const gchar *icon_name; icon_name = as_yaml_node_get_value (n); if (g_str_has_prefix (icon_name, "/")) as_icon_set_filename (icon, icon_name); else as_icon_set_name (icon, icon_name); } } } } return TRUE; }
static gboolean load_desktop_icon (GsApp *app, SnapdSnap *snap) { GPtrArray *apps; guint i; apps = snapd_snap_get_apps (snap); for (i = 0; i < apps->len; i++) { SnapdApp *snap_app = apps->pdata[i]; const gchar *desktop_file_path; g_autoptr(GKeyFile) desktop_file = NULL; g_autoptr(GError) error = NULL; g_autofree gchar *icon_value = NULL; g_autoptr(AsIcon) icon = NULL; desktop_file_path = snapd_app_get_desktop_file (snap_app); if (desktop_file_path == NULL) continue; desktop_file = g_key_file_new (); if (!g_key_file_load_from_file (desktop_file, desktop_file_path, G_KEY_FILE_NONE, &error)) { g_warning ("Failed to load desktop file %s: %s", desktop_file_path, error->message); continue; } icon_value = g_key_file_get_string (desktop_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, &error); if (icon_value == NULL) { g_warning ("Failed to get desktop file icon %s: %s", desktop_file_path, error->message); continue; } icon = as_icon_new (); if (g_str_has_prefix (icon_value, "/")) { as_icon_set_kind (icon, AS_ICON_KIND_LOCAL); as_icon_set_filename (icon, icon_value); } else { as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, icon_value); } gs_app_add_icon (app, icon); return TRUE; } return FALSE; }
static AsIcon * as_app_desktop_create_icon (AsApp *app, const gchar *name, AsAppParseFlags flags) { AsIcon *icon = as_icon_new (); gchar *dot; g_autofree gchar *name_fixed = NULL; /* local */ if (g_path_is_absolute (name)) { as_icon_set_kind (icon, AS_ICON_KIND_LOCAL); as_icon_set_filename (icon, name); return icon; } /* work around a common mistake in desktop files */ name_fixed = g_strdup (name); dot = g_strstr_len (name_fixed, -1, "."); if (dot != NULL && (g_strcmp0 (dot, ".png") == 0 || g_strcmp0 (dot, ".xpm") == 0 || g_strcmp0 (dot, ".svg") == 0)) { *dot = '\0'; } /* stock */ if (as_utils_is_stock_icon_name (name_fixed)) { as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, name_fixed); return icon; } /* stock, but kinda sneaky */ if ((flags & AS_APP_PARSE_FLAG_USE_FALLBACKS) > 0 && _as_utils_is_stock_icon_name_fallback (name_fixed)) { as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, name_fixed); return icon; } /* just use default of UNKNOWN */ as_icon_set_name (icon, name_fixed); return icon; }
static GsApp * gs_plugin_fwupd_new_app_from_device_raw (GsPlugin *plugin, FwupdDevice *device) { GPtrArray *icons; g_autofree gchar *id = NULL; g_autoptr(GsApp) app = NULL; /* create a GsApp based on the device, not the release */ id = gs_plugin_fwupd_build_device_id (device); app = gs_app_new (id); gs_app_set_kind (app, AS_APP_KIND_FIRMWARE); gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM); gs_app_set_state (app, AS_APP_STATE_INSTALLED); gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); gs_app_set_version (app, fwupd_device_get_version (device)); gs_app_set_name (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_name (device)); gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_summary (device)); gs_app_set_description (app, GS_APP_QUALITY_LOWEST, fwupd_device_get_description (device)); gs_app_set_origin (app, fwupd_device_get_vendor (device)); gs_fwupd_app_set_device_id (app, fwupd_device_get_id (device)); gs_app_set_management_plugin (app, "fwupd"); /* create icon */ icons = fwupd_device_get_icons (device); for (guint j = 0; j < icons->len; j++) { const gchar *icon = g_ptr_array_index (icons, j); g_autoptr(AsIcon) icon_tmp = as_icon_new (); if (g_str_has_prefix (icon, "/")) { as_icon_set_kind (icon_tmp, AS_ICON_KIND_LOCAL); as_icon_set_filename (icon_tmp, icon); } else { as_icon_set_kind (icon_tmp, AS_ICON_KIND_STOCK); as_icon_set_name (icon_tmp, icon); } gs_app_add_icon (app, icon_tmp); } return g_steal_pointer (&app); }
/** * gs_refine_item_pixbuf: */ static void gs_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AsApp *item) { AsIcon *icon; gboolean ret; g_autoptr(GError) error = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *cachedir = NULL; icon = as_app_get_icon_default (item); switch (as_icon_get_kind (icon)) { case AS_ICON_KIND_REMOTE: gs_app_set_icon (app, icon); if (as_icon_get_filename (icon) == NULL) { cachedir = gs_utils_get_cachedir ("icons", NULL); fn = g_build_filename (cachedir, as_icon_get_name (icon), NULL); as_icon_set_filename (icon, fn); as_icon_set_prefix (icon, cachedir); } 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); return; } } break; case AS_ICON_KIND_STOCK: 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); /* load */ ret = gs_app_load_icon (app, plugin->scale, &error); if (!ret) { 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); return; } break; case AS_ICON_KIND_CACHED: if (plugin->scale == 2) icon = as_app_get_icon_for_size (item, 128, 128); if (icon == NULL) icon = as_app_get_icon_for_size (item, 64, 64); if (icon == NULL) { g_warning ("failed to find cached icon %s", as_icon_get_name (icon)); return; } if (!as_icon_load (icon, AS_ICON_LOAD_FLAG_SEARCH_SIZE, &error)) { g_warning ("failed to load cached icon %s: %s", as_icon_get_name (icon), error->message); return; } gs_app_set_pixbuf (app, as_icon_get_pixbuf (icon)); break; default: g_warning ("icon kind unknown for %s", as_app_get_id (item)); break; } }
/** * as_icon_node_parse: * @icon: a #AsIcon instance. * @node: a #GNode. * @ctx: a #AsNodeContext. * @error: A #GError or %NULL. * * Populates the object from a DOM node. * * Returns: %TRUE for success * * Since: 0.3.1 **/ gboolean as_icon_node_parse (AsIcon *icon, GNode *node, AsNodeContext *ctx, GError **error) { AsIconPrivate *priv = GET_PRIVATE (icon); const gchar *tmp; guint size; gboolean prepend_size = TRUE; tmp = as_node_get_attribute (node, "type"); as_icon_set_kind (icon, as_icon_kind_from_string (tmp)); switch (priv->kind) { case AS_ICON_KIND_EMBEDDED: if (!as_icon_node_parse_embedded (icon, node, error)) return FALSE; break; default: /* preserve the URL for remote icons */ tmp = as_node_get_data (node); if (tmp == NULL) { g_set_error (error, AS_ICON_ERROR, AS_ICON_ERROR_FAILED, "no data for icon of type %s", as_icon_kind_to_string (priv->kind)); return FALSE; } if (priv->kind == AS_ICON_KIND_REMOTE) as_icon_set_url (icon, tmp); else if (priv->kind == AS_ICON_KIND_LOCAL) as_icon_set_filename (icon, tmp); /* store the name without any prefix */ if (g_strstr_len (tmp, -1, "/") == NULL) { as_icon_set_name (icon, tmp); } else { g_autofree gchar *basename = NULL; basename = g_path_get_basename (tmp); as_icon_set_name (icon, basename); } /* width is optional, assume 64px if missing */ size = as_node_get_attribute_as_uint (node, "width"); if (size == G_MAXUINT) { size = 64; prepend_size = FALSE; } priv->width = size; /* height is optional, assume 64px if missing */ size = as_node_get_attribute_as_uint (node, "height"); if (size == G_MAXUINT) { size = 64; prepend_size = FALSE; } priv->height = size; /* only use the size if the metadata has width and height */ if (prepend_size) { g_free (priv->prefix_private); priv->prefix_private = g_strdup_printf ("%s/%ux%u", priv->prefix, priv->width, priv->height); } break; } return TRUE; }
static gboolean gs_plugin_steam_download_icon (GsPlugin *plugin, AsApp *app, const gchar *uri, GError **error) { gsize data_len; g_autofree gchar *cache_basename = NULL; g_autofree gchar *cache_fn = NULL; g_autofree gchar *cache_png = NULL; g_autofree gchar *data = NULL; g_autoptr(AsIcon) icon = NULL; g_autoptr(GdkPixbuf) pb = NULL; /* download icons from the cdn */ cache_basename = g_path_get_basename (uri); cache_fn = gs_utils_get_cache_filename ("steam", cache_basename, GS_UTILS_CACHE_FLAG_NONE, error); if (cache_fn == NULL) return FALSE; if (g_file_test (cache_fn, G_FILE_TEST_EXISTS)) { if (!g_file_get_contents (cache_fn, &data, &data_len, error)) { gs_utils_error_convert_gio (error); return FALSE; } } else { if (!gs_mkdir_parent (cache_fn, error)) return FALSE; if (!gs_plugin_download_file (plugin, NULL, /* GsApp */ uri, cache_fn, NULL, /* GCancellable */ error)) return FALSE; } /* load the icon as large as possible */ pb = gdk_pixbuf_new_from_file (cache_fn, error); if (pb == NULL) { gs_utils_error_convert_gdk_pixbuf (error); return FALSE; } /* too small? */ if (gdk_pixbuf_get_width (pb) < 48 || gdk_pixbuf_get_height (pb) < 48) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "icon is too small %ix%i", gdk_pixbuf_get_width (pb), gdk_pixbuf_get_height (pb)); return FALSE; } /* save to cache */ memcpy (cache_basename + 40, ".png\0", 5); cache_png = gs_utils_get_cache_filename ("steam", cache_basename, GS_UTILS_CACHE_FLAG_WRITEABLE, error); if (cache_png == NULL) return FALSE; if (!gdk_pixbuf_save (pb, cache_png, "png", error, NULL)) { gs_utils_error_convert_gdk_pixbuf (error); return FALSE; } /* add an icon */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_LOCAL); as_icon_set_filename (icon, cache_png); as_app_add_icon (app, icon); return TRUE; }
/** * as_app_parse_file_key: **/ static gboolean as_app_parse_file_key (AsApp *app, GKeyFile *kf, const gchar *key, AsAppParseFlags flags, GError **error) { gchar *dot = NULL; guint i; guint j; g_autofree gchar *locale = NULL; g_autofree gchar *tmp = NULL; g_auto(GStrv) list = NULL; /* NoDisplay */ if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY) == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && strcasecmp (tmp, "True") == 0) as_app_add_veto (app, "NoDisplay=true"); /* Type */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_TYPE) == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (g_strcmp0 (tmp, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0) { g_set_error_literal (error, AS_APP_ERROR, AS_APP_ERROR_INVALID_TYPE, "not an application"); return FALSE; } /* Icon */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_ICON) == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && tmp[0] != '\0') { g_autoptr(AsIcon) icon = NULL; icon = as_icon_new (); if (g_path_is_absolute (tmp)) { as_icon_set_filename (icon, tmp); } else { /* work around a common mistake in desktop files */ dot = g_strstr_len (tmp, -1, "."); if (dot != NULL && (g_strcmp0 (dot, ".png") == 0 || g_strcmp0 (dot, ".xpm") == 0 || g_strcmp0 (dot, ".svg") == 0)) { *dot = '\0'; } } as_icon_set_name (icon, tmp); if (as_utils_is_stock_icon_name (tmp)) { as_icon_set_name (icon, tmp); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); } else if ((flags & AS_APP_PARSE_FLAG_USE_FALLBACKS) > 0 && _as_utils_is_stock_icon_name_fallback (tmp)) { as_icon_set_name (icon, tmp); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); } else { as_icon_set_kind (icon, AS_ICON_KIND_LOCAL); } as_app_add_icon (app, icon); } /* Categories */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_CATEGORIES) == 0) { list = g_key_file_get_string_list (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL); for (i = 0; list[i] != NULL; i++) { /* not a standard category */ if (g_str_has_prefix (list[i], "X-")) continue; /* check the category is valid */ if (!as_utils_is_category_id (list[i])) continue; /* ignore some useless keys */ if (g_strcmp0 (list[i], "GTK") == 0) continue; if (g_strcmp0 (list[i], "Qt") == 0) continue; if (g_strcmp0 (list[i], "KDE") == 0) continue; if (g_strcmp0 (list[i], "GNOME") == 0) continue; as_app_add_category (app, list[i]); } } else if (g_strcmp0 (key, "Keywords") == 0) { list = g_key_file_get_string_list (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL); for (i = 0; list[i] != NULL; i++) { g_auto(GStrv) kw_split = NULL; kw_split = g_strsplit (list[i], ",", -1); for (j = 0; kw_split[j] != NULL; j++) { if (kw_split[j][0] == '\0') continue; as_app_add_keyword (app, "C", kw_split[j]); } } } else if (g_str_has_prefix (key, "Keywords")) { locale = as_app_desktop_key_get_locale (key); list = g_key_file_get_locale_string_list (kf, G_KEY_FILE_DESKTOP_GROUP, key, locale, NULL, NULL); for (i = 0; list[i] != NULL; i++) { g_auto(GStrv) kw_split = NULL; kw_split = g_strsplit (list[i], ",", -1); for (j = 0; kw_split[j] != NULL; j++) { if (kw_split[j][0] == '\0') continue; as_app_add_keyword (app, locale, kw_split[j]); } } } else if (g_strcmp0 (key, "MimeType") == 0) { list = g_key_file_get_string_list (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL); for (i = 0; list[i] != NULL; i++) as_app_add_mimetype (app, list[i]); } else if (g_strcmp0 (key, "X-AppInstall-Package") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_add_pkgname (app, tmp); /* OnlyShowIn */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN) == 0) { /* if an app has only one entry, it's that desktop */ list = g_key_file_get_string_list (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL, NULL); if (g_strv_length (list) == 1) as_app_set_project_group (app, list[0]); /* Name */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_NAME) == 0 || g_strcmp0 (key, "_Name") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_name (app, "C", tmp); /* Name[] */ } else if (g_str_has_prefix (key, G_KEY_FILE_DESKTOP_KEY_NAME)) { locale = as_app_desktop_key_get_locale (key); tmp = g_key_file_get_locale_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, locale, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_name (app, locale, tmp); /* Comment */ } else if (g_strcmp0 (key, G_KEY_FILE_DESKTOP_KEY_COMMENT) == 0 || g_strcmp0 (key, "_Comment") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_comment (app, "C", tmp); /* Comment[] */ } else if (g_str_has_prefix (key, G_KEY_FILE_DESKTOP_KEY_COMMENT)) { locale = as_app_desktop_key_get_locale (key); tmp = g_key_file_get_locale_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, locale, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_comment (app, locale, tmp); /* non-standard */ } else if (g_strcmp0 (key, "X-Ubuntu-Software-Center-Name") == 0) { tmp = g_key_file_get_string (kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_name (app, "C", tmp); } else if (g_str_has_prefix (key, "X-Ubuntu-Software-Center-Name")) { locale = as_app_desktop_key_get_locale (key); tmp = g_key_file_get_locale_string (kf, G_KEY_FILE_DESKTOP_GROUP, "X-Ubuntu-Software-Center-Name", locale, NULL); if (tmp != NULL && tmp[0] != '\0') as_app_set_name (app, locale, tmp); } return TRUE; }
gboolean gs_plugin_add_distro_upgrades (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); gsize len; guint i; g_autofree gchar *data = NULL; g_autoptr(GPtrArray) distros = NULL; g_autoptr(GSettings) settings = NULL; /* just ensure there is any data, no matter how old */ if (!gs_plugin_fedora_distro_upgrades_refresh (plugin, G_MAXUINT, cancellable, error)) return FALSE; /* get cached file */ if (!g_file_get_contents (priv->cachefn, &data, &len, error)) { gs_utils_error_convert_gio (error); return FALSE; } /* parse data */ settings = g_settings_new ("org.gnome.software"); distros = parse_pkgdb_collections_data (data, (gssize) len, error); if (distros == NULL) return FALSE; g_ptr_array_sort (distros, sort_distros_cb); for (i = 0; i < distros->len; i++) { DistroInfo *distro_info = g_ptr_array_index (distros, i); g_autofree gchar *app_id = NULL; g_autofree gchar *app_version = NULL; g_autofree gchar *background = NULL; g_autofree gchar *cache_key = NULL; g_autofree gchar *url = NULL; g_autofree gchar *css = NULL; g_autoptr(GsApp) app = NULL; g_autoptr(AsIcon) ic = NULL; /* only interested in upgrades to the same distro */ if (g_strcmp0 (distro_info->name, priv->os_name) != 0) continue; /* only interested in newer versions, but not more than N+2 */ if (distro_info->version <= priv->os_version || distro_info->version > priv->os_version + 2) continue; /* only interested in non-devel distros */ if (!g_settings_get_boolean (settings, "show-upgrade-prerelease")) { if (distro_info->status == DISTRO_STATUS_DEVEL) continue; } /* search in the cache */ cache_key = g_strdup_printf ("release-%u", distro_info->version); app = gs_plugin_cache_lookup (plugin, cache_key); if (app != NULL) { gs_app_list_add (list, app); continue; } app_id = g_strdup_printf ("org.fedoraproject.release-%u.upgrade", distro_info->version); app_version = g_strdup_printf ("%u", distro_info->version); /* icon from disk */ ic = as_icon_new (); as_icon_set_kind (ic, AS_ICON_KIND_LOCAL); as_icon_set_filename (ic, "/usr/share/pixmaps/fedora-logo-sprite.png"); /* create */ app = gs_app_new (app_id); gs_app_set_kind (app, AS_APP_KIND_OS_UPGRADE); gs_app_set_state (app, AS_APP_STATE_AVAILABLE); gs_app_set_name (app, GS_APP_QUALITY_LOWEST, distro_info->name); gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, /* TRANSLATORS: this is a title for Fedora distro upgrades */ _("A major upgrade, with new features and added polish.")); gs_app_set_description (app, GS_APP_QUALITY_LOWEST, "Fedora Workstation is a polished, " "easy to use operating system for " "laptop and desktop computers, with a " "complete set of tools for developers " "and makers of all kinds."); gs_app_set_version (app, app_version); gs_app_set_size_installed (app, 1024 * 1024 * 1024); /* estimate */ gs_app_set_size_download (app, 256 * 1024 * 1024); /* estimate */ gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free"); gs_app_add_quirk (app, AS_APP_QUIRK_NEEDS_REBOOT); gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE); gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE); gs_app_set_origin_ui (app, distro_info->name); gs_app_add_icon (app, ic); gs_app_set_management_plugin (app, "packagekit"); /* show a Fedora magazine article for the release */ url = g_strdup_printf ("https://fedoramagazine.org/whats-new-fedora-%u-workstation", distro_info->version); gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, url); /* use a fancy background */ background = get_upgrade_css_background (distro_info->version); css = g_strdup_printf ("background: %s;" "background-position: center;" "background-size: cover;", background); gs_app_set_metadata (app, "GnomeSoftware::UpgradeBanner-css", css); gs_app_list_add (list, app); /* save in the cache */ gs_plugin_cache_add (plugin, cache_key, app); } return TRUE; }