gboolean gs_plugin_app_install (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(SnapdClient) client = NULL; SnapdInstallFlags flags = SNAPD_INSTALL_FLAGS_NONE; /* We can only install apps we know of */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; client = get_client (plugin, error); if (client == NULL) return FALSE; gs_app_set_state (app, AS_APP_STATE_INSTALLING); if (g_strcmp0 (gs_app_get_metadata_item (app, "snap::confinement"), "classic") == 0) flags |= SNAPD_INSTALL_FLAGS_CLASSIC; if (!snapd_client_install2_sync (client, flags, gs_app_get_metadata_item (app, "snap::name"), NULL, NULL, progress_cb, app, cancellable, error)) { gs_app_set_state_recover (app); snapd_error_convert (error); return FALSE; } gs_app_set_state (app, AS_APP_STATE_INSTALLED); return TRUE; }
gboolean gs_plugin_app_remove (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(SnapdClient) client = NULL; /* We can only remove apps we know of */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; client = get_client (plugin, error); if (client == NULL) return FALSE; gs_app_set_state (app, AS_APP_STATE_REMOVING); if (!snapd_client_remove_sync (client, gs_app_get_metadata_item (app, "snap::name"), progress_cb, app, cancellable, error)) { gs_app_set_state_recover (app); snapd_error_convert (error); return FALSE; } gs_app_set_state (app, AS_APP_STATE_AVAILABLE); return TRUE; }
/** * gs_plugin_refine_item_metadata: */ static gboolean gs_plugin_refine_item_metadata (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { g_autoptr(XdgAppRef) xref = NULL; /* already set */ if (gs_app_get_metadata_item (app, "xdg-app::kind") != NULL) return TRUE; /* AppStream sets the source to appname/arch/branch, if this isn't set * we can't break out the fields */ if (gs_app_get_source_default (app) == NULL) { g_warning ("no source set by appstream for %s", gs_plugin_get_name (plugin)); return TRUE; } /* parse the ref */ xref = xdg_app_ref_parse (gs_app_get_source_default (app), error); if (xref == NULL) { g_prefix_error (error, "failed to parse '%s': ", gs_app_get_source_default (app)); return FALSE; } gs_plugin_xdg_app_set_metadata (app, xref); /* success */ return TRUE; }
gboolean gs_plugin_launch (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { const gchar *launch_name; g_autofree gchar *binary_name = NULL; GAppInfoCreateFlags flags = G_APP_INFO_CREATE_NONE; g_autoptr(GAppInfo) info = NULL; /* We can only launch apps we know of */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; launch_name = gs_app_get_metadata_item (app, "snap::launch-name"); if (!launch_name) return TRUE; if (g_strcmp0 (launch_name, gs_app_get_id (app)) == 0) binary_name = g_strdup_printf ("/snap/bin/%s", launch_name); else binary_name = g_strdup_printf ("/snap/bin/%s.%s", gs_app_get_id (app), launch_name); if (!is_graphical (app, cancellable)) flags |= G_APP_INFO_CREATE_NEEDS_TERMINAL; info = g_app_info_create_from_commandline (binary_name, NULL, flags, error); if (info == NULL) return FALSE; return g_app_info_launch (info, NULL, NULL, error); }
static gboolean gs_plugin_fwupd_modify_source (GsPlugin *plugin, GsApp *app, gboolean enabled, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); const gchar *remote_id = gs_app_get_metadata_item (app, "fwupd::remote-id"); if (remote_id == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "not enough data for fwupd %s", gs_app_get_unique_id (app)); return FALSE; } gs_app_set_state (app, enabled ? AS_APP_STATE_INSTALLING : AS_APP_STATE_REMOVING); if (!fwupd_client_modify_remote (priv->client, remote_id, "Enabled", enabled ? "true" : "false", cancellable, error)) { gs_app_set_state_recover (app); return FALSE; } gs_app_set_state (app, enabled ? AS_APP_STATE_INSTALLED : AS_APP_STATE_AVAILABLE); return TRUE; }
static gboolean load_snap_icon (GsApp *app, SnapdClient *client, SnapdSnap *snap, GCancellable *cancellable) { const gchar *icon_url; g_autoptr(SnapdIcon) icon = NULL; g_autoptr(GInputStream) input_stream = NULL; g_autoptr(GdkPixbuf) pixbuf = NULL; g_autoptr(GError) error = NULL; icon_url = snapd_snap_get_icon (snap); if (icon_url == NULL || strcmp (icon_url, "") == 0) return FALSE; icon = snapd_client_get_icon_sync (client, gs_app_get_metadata_item (app, "snap::name"), cancellable, &error); if (icon == NULL) { g_warning ("Failed to load snap icon: %s", error->message); return FALSE; } input_stream = g_memory_input_stream_new_from_bytes (snapd_icon_get_data (icon)); pixbuf = gdk_pixbuf_new_from_stream_at_scale (input_stream, 64, 64, TRUE, cancellable, &error); if (pixbuf == NULL) { g_warning ("Failed to decode snap icon %s: %s", icon_url, error->message); return FALSE; } gs_app_set_pixbuf (app, pixbuf); return TRUE; }
// Check if an app is graphical by checking if it uses a known GUI interface. // This doesn't necessarily mean that every binary uses this interfaces, but is probably true. // https://bugs.launchpad.net/bugs/1595023 static gboolean is_graphical (GsPlugin *plugin, GsApp *app, GCancellable *cancellable) { g_autoptr(SnapdClient) client = NULL; g_autoptr(GPtrArray) plugs = NULL; guint i; g_autoptr(GError) error = NULL; client = get_client (plugin, &error); if (client == NULL) return FALSE; if (!snapd_client_get_interfaces_sync (client, &plugs, NULL, cancellable, &error)) { g_warning ("Failed to check interfaces: %s", error->message); return FALSE; } for (i = 0; i < plugs->len; i++) { SnapdPlug *plug = plugs->pdata[i]; const gchar *interface; // Only looks at the plugs for this snap if (g_strcmp0 (snapd_plug_get_snap (plug), gs_app_get_metadata_item (app, "snap::name")) != 0) continue; interface = snapd_plug_get_interface (plug); if (interface == NULL) continue; if (g_strcmp0 (interface, "unity7") == 0 || g_strcmp0 (interface, "x11") == 0 || g_strcmp0 (interface, "mir") == 0) return TRUE; } return FALSE; }
static gboolean gs_plugin_fwupd_install (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); const gchar *device_id; FwupdInstallFlags install_flags = 0; GFile *local_file; g_autofree gchar *filename = NULL; /* not set */ local_file = gs_app_get_local_file (app); if (local_file == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "not enough data for fwupd %s", filename); return FALSE; } /* file does not yet exist */ filename = g_file_get_path (local_file); if (!g_file_query_exists (local_file, cancellable)) { const gchar *uri = gs_fwupd_app_get_update_uri (app); gs_app_set_state (app, AS_APP_STATE_INSTALLING); if (!gs_plugin_download_file (plugin, app, uri, filename, cancellable, error)) return FALSE; } /* limit to single device? */ device_id = gs_fwupd_app_get_device_id (app); if (device_id == NULL) device_id = FWUPD_DEVICE_ID_ANY; /* set the last object */ g_set_object (&priv->app_current, app); /* only offline supported */ if (gs_app_get_metadata_item (app, "fwupd::OnlyOffline") != NULL) install_flags |= FWUPD_INSTALL_FLAG_OFFLINE; gs_app_set_state (app, AS_APP_STATE_INSTALLING); if (!fwupd_client_install (priv->client, device_id, filename, install_flags, cancellable, error)) { gs_plugin_fwupd_error_convert (error); gs_app_set_state_recover (app); return FALSE; } /* delete the file from the cache */ gs_app_set_state (app, AS_APP_STATE_INSTALLED); return g_file_delete (local_file, cancellable, error); }
/** * gs_app_get_xdgapp_kind: */ static XdgAppRefKind gs_app_get_xdgapp_kind (GsApp *app) { const gchar *kind = gs_app_get_metadata_item (app, "xdg-app::kind"); if (g_strcmp0 (kind, "app") == 0) return XDG_APP_REF_KIND_APP; if (g_strcmp0 (kind, "runtime") == 0) return XDG_APP_REF_KIND_RUNTIME; g_warning ("unknown xdg-app kind: %s", kind); return XDG_APP_REF_KIND_APP; }
gboolean gs_plugin_launch (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { const gchar *launch_name; const gchar *launch_desktop; g_autoptr(GAppInfo) info = NULL; /* We can only launch apps we know of */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; launch_name = gs_app_get_metadata_item (app, "snap::launch-name"); launch_desktop = gs_app_get_metadata_item (app, "snap::launch-desktop"); if (!launch_name) return TRUE; if (launch_desktop) { info = (GAppInfo *)g_desktop_app_info_new_from_filename (launch_desktop); } else { g_autofree gchar *commandline = NULL; GAppInfoCreateFlags flags = G_APP_INFO_CREATE_NONE; if (g_strcmp0 (launch_name, gs_app_get_metadata_item (app, "snap::name")) == 0) commandline = g_strdup_printf ("snap run %s", launch_name); else commandline = g_strdup_printf ("snap run %s.%s", gs_app_get_metadata_item (app, "snap::name"), launch_name); if (!is_graphical (plugin, app, cancellable)) flags |= G_APP_INFO_CREATE_NEEDS_TERMINAL; info = g_app_info_create_from_commandline (commandline, NULL, flags, error); } if (info == NULL) return FALSE; return g_app_info_launch (info, NULL, NULL, error); }
static gboolean load_icon (GsPlugin *plugin, SnapdClient *client, GsApp *app, const gchar *id, SnapdSnap *local_snap, SnapdSnap *store_snap, GCancellable *cancellable) { if (local_snap != NULL) { if (load_snap_icon (app, client, local_snap, cancellable)) return TRUE; if (load_desktop_icon (app, local_snap)) return TRUE; } if (store_snap == NULL) store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL); if (store_snap != NULL) return load_store_icon (app, store_snap); return FALSE; }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { const gchar *key = "GnomeSoftware::FeatureTile-css"; guint i; for (i = 0; myapps[i].id != NULL; i++) { if (g_strcmp0 (gs_app_get_id (app), myapps[i].id) != 0) continue; if (gs_app_get_metadata_item (app, key) != NULL) continue; gs_app_set_metadata (app, key, myapps[i].css); } return TRUE; }
gboolean gs_plugin_launch (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { const gchar *gameid; g_autofree gchar *cmdline = NULL; /* only process this app if was created by this plugin */ if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) return TRUE; /* this is async as steam is a different process: FIXME: use D-Bus */ gameid = gs_app_get_metadata_item (app, "X-Steam-GameID"); cmdline = g_strdup_printf ("steam steam://run/%s", gameid); if (!g_spawn_command_line_sync (cmdline, NULL, NULL, NULL, error)) { gs_utils_error_convert_gio (error); return FALSE; } return TRUE; }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { const gchar *keys[] = { "GnomeSoftware::AppTile-css", "GnomeSoftware::FeatureTile-css", "GnomeSoftware::UpgradeBanner-css", NULL }; /* rewrite URIs */ for (guint i = 0; keys[i] != NULL; i++) { const gchar *css = gs_app_get_metadata_item (app, keys[i]); if (css != NULL) { g_autofree gchar *css_new = NULL; g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin)); gs_app_set_summary_missing (app_dl, /* TRANSLATORS: status text when downloading */ _("Downloading featured images…")); css_new = gs_plugin_download_rewrite_resource (plugin, app, css, cancellable, error); if (css_new == NULL) return FALSE; if (g_strcmp0 (css, css_new) != 0) { gs_app_set_metadata (app, keys[i], NULL); gs_app_set_metadata (app, keys[i], css_new); } } } return TRUE; }
gboolean gs_plugin_review_submit (GsPlugin *plugin, GsApp *app, AsReview *review, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); g_autofree gchar *data = NULL; g_autofree gchar *uri = NULL; g_autofree gchar *version = NULL; g_autoptr(JsonBuilder) builder = NULL; g_autoptr(JsonGenerator) json_generator = NULL; g_autoptr(JsonNode) json_root = NULL; /* save as we don't re-request the review from the server */ as_review_set_reviewer_name (review, g_get_real_name ()); as_review_add_metadata (review, "app_id", gs_app_get_id (app)); as_review_add_metadata (review, "user_skey", gs_app_get_metadata_item (app, "ODRS::user_skey")); /* create object with review data */ builder = json_builder_new (); json_builder_begin_object (builder); json_builder_set_member_name (builder, "user_hash"); json_builder_add_string_value (builder, priv->user_hash); json_builder_set_member_name (builder, "user_skey"); json_builder_add_string_value (builder, as_review_get_metadata_item (review, "user_skey")); json_builder_set_member_name (builder, "app_id"); json_builder_add_string_value (builder, as_review_get_metadata_item (review, "app_id")); json_builder_set_member_name (builder, "locale"); json_builder_add_string_value (builder, gs_plugin_get_locale (plugin)); json_builder_set_member_name (builder, "distro"); json_builder_add_string_value (builder, priv->distro); json_builder_set_member_name (builder, "version"); version = gs_plugin_odrs_sanitize_version (as_review_get_version (review)); json_builder_add_string_value (builder, version); json_builder_set_member_name (builder, "user_display"); json_builder_add_string_value (builder, as_review_get_reviewer_name (review)); json_builder_set_member_name (builder, "summary"); json_builder_add_string_value (builder, as_review_get_summary (review)); json_builder_set_member_name (builder, "description"); json_builder_add_string_value (builder, as_review_get_description (review)); json_builder_set_member_name (builder, "rating"); json_builder_add_int_value (builder, as_review_get_rating (review)); json_builder_end_object (builder); /* export as a string */ json_root = json_builder_get_root (builder); json_generator = json_generator_new (); json_generator_set_pretty (json_generator, TRUE); json_generator_set_root (json_generator, json_root); data = json_generator_to_data (json_generator, NULL); /* clear cache */ if (!gs_plugin_odrs_invalidate_cache (review, error)) return FALSE; /* POST */ uri = g_strdup_printf ("%s/submit", priv->review_server); return gs_plugin_odrs_json_post (gs_plugin_get_soup_session (plugin), uri, data, error); }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { const gchar *gameid; const gchar *tmp; g_autofree gchar *manifest_basename = NULL; g_autofree gchar *fn = NULL; g_autoptr(GHashTable) manifest = NULL; /* check is us */ gameid = gs_app_get_metadata_item (app, "X-Steam-GameID"); if (gameid == NULL) return TRUE; /* is this true? */ gs_app_set_kind (app, AS_ID_KIND_DESKTOP); /* no way of knowing */ if (gs_app_get_size_download (app) == 0) gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE); /* hardcoded */ if (gs_app_get_origin_hostname (app) == NULL) gs_app_set_origin_hostname (app, "steampowered.com"); /* size */ tmp = gs_app_get_metadata_item (app, "X-Steam-Size"); if (tmp != NULL) { guint64 sz; sz = g_ascii_strtoull (tmp, NULL, 10); if (sz > 0) gs_app_set_size_installed (app, sz); } /* check manifest */ manifest_basename = g_strdup_printf ("appmanifest_%s.acf", gameid); fn = g_build_filename (g_get_user_data_dir (), "Steam", "steamapps", manifest_basename, NULL); if (!g_file_test (fn, G_FILE_TEST_EXISTS)) { /* can never have been installed */ gs_app_set_state (app, AS_APP_STATE_AVAILABLE); return TRUE; } manifest = gs_plugin_steam_load_app_manifest (fn, error); if (manifest == NULL) return FALSE; /* this is better than the download size */ tmp = g_hash_table_lookup (manifest, "SizeOnDisk"); if (tmp != NULL) { guint64 sz; sz = g_ascii_strtoull (tmp, NULL, 10); if (sz > 0) gs_app_set_size_installed (app, sz); } /* set state */ tmp = g_hash_table_lookup (manifest, "StateFlags"); if (tmp != NULL) { guint64 state_flags; /* set state */ state_flags = g_ascii_strtoull (tmp, NULL, 10); if (state_flags & GS_STEAM_STATE_FLAG_DOWNLOADING || state_flags & GS_STEAM_STATE_FLAG_PREALLOCATING || state_flags & GS_STEAM_STATE_FLAG_ADDING_FILES || state_flags & GS_STEAM_STATE_FLAG_COMMITTING || state_flags & GS_STEAM_STATE_FLAG_STAGING) gs_app_set_state (app, AS_APP_STATE_INSTALLING); else if (state_flags & GS_STEAM_STATE_FLAG_UNINSTALLING) gs_app_set_state (app, AS_APP_STATE_REMOVING); else if (state_flags & GS_STEAM_STATE_FLAG_FULLY_INSTALLED) gs_app_set_state (app, AS_APP_STATE_INSTALLED); else if (state_flags & GS_STEAM_STATE_FLAG_UNINSTALLED) gs_app_set_state (app, AS_APP_STATE_AVAILABLE); } /* set install date */ tmp = g_hash_table_lookup (manifest, "LastUpdated"); if (tmp != NULL) { guint64 ts; ts = g_ascii_strtoull (tmp, NULL, 10); if (ts > 0) gs_app_set_install_date (app, ts); } return TRUE; }
/** * gs_plugin_refine_app: */ gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { Header h; const gchar *fn; gint rc; g_auto(rpmdbMatchIterator) mi = NULL; g_auto(rpmts) ts = NULL; /* not required */ if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_LICENSE) == 0 && (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) == 0) return TRUE; /* no need to run the plugin */ if (gs_app_get_source_default (app) != NULL && gs_app_get_source_id_default (app) != NULL) return TRUE; /* open db readonly */ ts = rpmtsCreate(); rpmtsSetRootDir (ts, NULL); rc = rpmtsOpenDB (ts, O_RDONLY); if (rc != 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Failed to open rpmdb: %i", rc); return FALSE; } /* look for a specific file */ fn = gs_app_get_metadata_item (app, "appstream::source-file"); if (fn == NULL) return TRUE; if (!g_str_has_prefix (fn, "/usr")) return TRUE; mi = rpmtsInitIterator (ts, RPMDBI_INSTFILENAMES, fn, 0); if (mi == NULL) { g_debug ("rpm: no search results for %s", fn); return TRUE; } /* on rpm-ostree this package cannot be removed 'live' */ gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY); /* process any results */ g_debug ("rpm: querying for %s with %s", gs_app_get_id (app), fn); while ((h = rpmdbNextIterator (mi)) != NULL) { guint64 epoch; const gchar *name; const gchar *version; const gchar *arch; const gchar *release; const gchar *license; /* add default source */ name = headerGetString (h, RPMTAG_NAME); if (gs_app_get_source_default (app) == NULL) { g_debug ("rpm: setting source to %s", name); gs_app_add_source (app, name); } /* set size */ if (gs_app_get_size_download (app) == 0) gs_app_set_size_download (app, 0); if (gs_app_get_size_installed (app) == 0) { guint64 tmp; tmp = headerGetNumber (h, RPMTAG_SIZE); gs_app_set_size_installed (app, tmp); } /* set license */ license = headerGetString (h, RPMTAG_LICENSE); if (gs_app_get_license (app) == NULL && license != NULL) { g_autofree gchar *tmp = NULL; tmp = as_utils_license_to_spdx (license); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, tmp); } /* add version */ version = headerGetString (h, RPMTAG_VERSION); if (gs_app_get_version (app) == NULL) { g_debug ("rpm: setting version to %s", version); gs_app_set_version (app, version); } /* add source-id */ if (gs_app_get_source_id_default (app) == NULL) { g_autofree gchar *tmp = NULL; release = headerGetString (h, RPMTAG_RELEASE); arch = headerGetString (h, RPMTAG_ARCH); epoch = headerGetNumber (h, RPMTAG_EPOCH); if (epoch > 0) { tmp = g_strdup_printf ("%s;%" G_GUINT64_FORMAT ":%s-%s;%s;installed", name, epoch, version, release, arch); } else { tmp = g_strdup_printf ("%s;%s-%s;%s;installed", name, version, release, arch); } g_debug ("rpm: setting source-id to %s", tmp); gs_app_add_source_id (app, tmp); } } return TRUE; }
/** * gs_appstream_refine_app: */ gboolean gs_appstream_refine_app (GsPlugin *plugin, GsApp *app, AsApp *item, GError **error) { AsRelease *rel; GHashTable *urls; GPtrArray *pkgnames; GPtrArray *kudos; const gchar *tmp; guint i; /* set the kind to be more precise */ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN || gs_app_get_kind (app) == AS_APP_KIND_GENERIC) { gs_app_set_kind (app, as_app_get_kind (item)); } /* is installed already */ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN) { switch (as_app_get_source_kind (item)) { case AS_APP_SOURCE_KIND_APPDATA: case AS_APP_SOURCE_KIND_DESKTOP: gs_app_set_kind (app, AS_APP_KIND_DESKTOP); gs_app_set_state (app, AS_APP_STATE_INSTALLED); break; case AS_APP_SOURCE_KIND_METAINFO: gs_app_set_state (app, AS_APP_STATE_INSTALLED); break; case AS_APP_SOURCE_KIND_APPSTREAM: gs_app_set_state (app, as_app_get_state (item)); break; default: break; } } /* set management plugin automatically */ gs_refine_item_management_plugin (app, item); /* set id */ if (as_app_get_id (item) != NULL && gs_app_get_id (app) == NULL) gs_app_set_id (app, as_app_get_id (item)); /* set name */ tmp = as_app_get_name (item, NULL); if (tmp != NULL) { if (g_str_has_prefix (tmp, "(Nightly) ")) { tmp += 10; if (gs_app_get_metadata_item (app, "X-XdgApp-Tags") == NULL) gs_app_set_metadata (app, "X-XdgApp-Tags", "nightly"); } gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, tmp); } /* set summary */ tmp = as_app_get_comment (item, NULL); if (tmp != NULL) { gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, tmp); } /* add urls */ urls = as_app_get_urls (item); if (g_hash_table_size (urls) > 0 && gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) { GList *l; g_autoptr(GList) keys = NULL; keys = g_hash_table_get_keys (urls); for (l = keys; l != NULL; l = l->next) { gs_app_set_url (app, as_url_kind_from_string (l->data), g_hash_table_lookup (urls, l->data)); } } /* set licence */ if (as_app_get_project_license (item) != NULL && gs_app_get_license (app) == NULL) gs_app_set_license (app, GS_APP_QUALITY_HIGHEST, as_app_get_project_license (item)); /* set keywords */ if (as_app_get_keywords (item, NULL) != NULL && gs_app_get_keywords (app) == NULL) { gs_app_set_keywords (app, as_app_get_keywords (item, NULL)); gs_app_add_kudo (app, GS_APP_KUDO_HAS_KEYWORDS); } /* set origin */ if (as_app_get_origin (item) != NULL && gs_app_get_origin (app) == NULL) { gs_app_set_origin (app, as_app_get_origin (item)); } /* set description */ tmp = as_app_get_description (item, NULL); if (tmp != NULL) { g_autofree gchar *from_xml = NULL; from_xml = as_markup_convert_simple (tmp, error); if (from_xml == NULL) { g_prefix_error (error, "trying to parse '%s': ", tmp); return FALSE; } gs_app_set_description (app, GS_APP_QUALITY_HIGHEST, from_xml); } /* set icon */ if (as_app_get_icon_default (item) != NULL && gs_app_get_pixbuf (app) == NULL) gs_refine_item_pixbuf (plugin, app, item); /* set categories */ if (as_app_get_categories (item) != NULL && gs_app_get_categories (app)->len == 0) gs_app_set_categories (app, as_app_get_categories (item)); /* set project group */ if (as_app_get_project_group (item) != NULL && gs_app_get_project_group (app) == NULL) gs_app_set_project_group (app, as_app_get_project_group (item)); /* this is a core application for the desktop and cannot be removed */ if (_as_app_has_compulsory_for_desktop (item, "GNOME") && gs_app_get_kind (app) == AS_APP_KIND_DESKTOP) gs_app_add_quirk (app, AS_APP_QUIRK_COMPULSORY); /* set id kind */ if (gs_app_get_kind (app) == AS_APP_KIND_UNKNOWN) gs_app_set_kind (app, as_app_get_kind (item)); /* copy all the metadata */ gs_appstream_copy_metadata (app, item); /* set package names */ pkgnames = as_app_get_pkgnames (item); if (pkgnames->len > 0 && gs_app_get_sources(app)->len == 0) gs_app_set_sources (app, pkgnames); /* set addons */ gs_appstream_refine_add_addons (plugin, app, item); /* set screenshots */ gs_appstream_refine_add_screenshots (app, item); /* are the screenshots perfect */ if (gs_appstream_are_screenshots_perfect (item)) gs_app_add_kudo (app, GS_APP_KUDO_PERFECT_SCREENSHOTS); /* was this application released recently */ if (gs_appstream_is_recent_release (item)) gs_app_add_kudo (app, GS_APP_KUDO_RECENT_RELEASE); /* add kudos */ if (as_app_get_language (item, plugin->locale) > 50) gs_app_add_kudo (app, GS_APP_KUDO_MY_LANGUAGE); /* add new-style kudos */ kudos = as_app_get_kudos (item); for (i = 0; i < kudos->len; i++) { tmp = g_ptr_array_index (kudos, i); switch (as_kudo_kind_from_string (tmp)) { case AS_KUDO_KIND_SEARCH_PROVIDER: gs_app_add_kudo (app, GS_APP_KUDO_SEARCH_PROVIDER); break; case AS_KUDO_KIND_USER_DOCS: gs_app_add_kudo (app, GS_APP_KUDO_INSTALLS_USER_DOCS); break; case AS_KUDO_KIND_APP_MENU: gs_app_add_kudo (app, GS_APP_KUDO_USES_APP_MENU); break; case AS_KUDO_KIND_MODERN_TOOLKIT: gs_app_add_kudo (app, GS_APP_KUDO_MODERN_TOOLKIT); break; case AS_KUDO_KIND_NOTIFICATIONS: gs_app_add_kudo (app, GS_APP_KUDO_USES_NOTIFICATIONS); break; case AS_KUDO_KIND_HIGH_CONTRAST: gs_app_add_kudo (app, GS_APP_KUDO_HIGH_CONTRAST); break; case AS_KUDO_KIND_HI_DPI_ICON: gs_app_add_kudo (app, GS_APP_KUDO_HI_DPI_ICON); break; default: g_debug ("no idea how to handle kudo '%s'", tmp); break; } } /* is there any update information */ rel = as_app_get_release_default (item); if (rel != NULL) { tmp = as_release_get_description (rel, NULL); if (tmp != NULL) { g_autofree gchar *desc = NULL; desc = as_markup_convert (tmp, AS_MARKUP_CONVERT_FORMAT_MARKDOWN, error); if (desc == NULL) return FALSE; gs_app_set_update_details (app, desc); } gs_app_set_update_urgency (app, as_release_get_urgency (rel)); gs_app_set_update_version (app, as_release_get_version (rel)); } return TRUE; }
gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GsPluginData *priv = gs_plugin_get_data (plugin); g_autoptr(SnapdClient) client = NULL; const gchar *name; g_autoptr(SnapdSnap) local_snap = NULL; g_autoptr(SnapdSnap) store_snap = NULL; SnapdSnap *snap; const gchar *developer_name; g_autofree gchar *description = NULL; /* not us */ if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0) return TRUE; client = get_client (plugin, error); if (client == NULL) return FALSE; /* get information from local snaps and store */ local_snap = snapd_client_get_snap_sync (client, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL); if (local_snap == NULL || (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) != 0) store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), cancellable, NULL); if (local_snap == NULL && store_snap == NULL) return TRUE; if (local_snap != NULL) gs_app_set_state (app, AS_APP_STATE_INSTALLED); else gs_app_set_state (app, AS_APP_STATE_AVAILABLE); /* use store information for basic metadata over local information */ snap = store_snap != NULL ? store_snap : local_snap; name = snapd_snap_get_title (snap); if (name == NULL || g_strcmp0 (name, "") == 0) name = snapd_snap_get_name (snap); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, name); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_summary (snap)); description = gs_plugin_snap_get_description_safe (snap); if (description != NULL) gs_app_set_description (app, GS_APP_QUALITY_NORMAL, description); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, snapd_snap_get_license (snap)); developer_name = snapd_snap_get_publisher_display_name (snap); if (developer_name == NULL) developer_name = snapd_snap_get_publisher_username (snap); gs_app_set_developer_name (app, developer_name); if (snapd_snap_get_publisher_validation (snap) == SNAPD_PUBLISHER_VALIDATION_VERIFIED) gs_app_add_quirk (app, GS_APP_QUIRK_DEVELOPER_VERIFIED); snap = local_snap != NULL ? local_snap : store_snap; gs_app_set_version (app, snapd_snap_get_version (snap)); switch (snapd_snap_get_snap_type (snap)) { case SNAPD_SNAP_TYPE_APP: gs_app_set_kind (app, AS_APP_KIND_DESKTOP); break; case SNAPD_SNAP_TYPE_KERNEL: case SNAPD_SNAP_TYPE_GADGET: case SNAPD_SNAP_TYPE_OS: gs_app_set_kind (app, AS_APP_KIND_RUNTIME); break; default: case SNAPD_SNAP_TYPE_UNKNOWN: gs_app_set_kind (app, AS_APP_KIND_UNKNOWN); break; } /* add information specific to installed snaps */ if (local_snap != NULL) { SnapdApp *snap_app; GDateTime *install_date; install_date = snapd_snap_get_install_date (local_snap); gs_app_set_size_installed (app, snapd_snap_get_installed_size (local_snap)); gs_app_set_install_date (app, install_date != NULL ? g_date_time_to_unix (install_date) : GS_APP_INSTALL_DATE_UNKNOWN); snap_app = get_primary_app (local_snap); if (snap_app != NULL) { gs_app_set_metadata (app, "snap::launch-name", snapd_app_get_name (snap_app)); gs_app_set_metadata (app, "snap::launch-desktop", snapd_app_get_desktop_file (snap_app)); } else { gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); } } /* add information specific to store snaps */ if (store_snap != NULL) { gs_app_set_origin (app, priv->store_name); gs_app_set_size_download (app, snapd_snap_get_download_size (store_snap)); if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS && gs_app_get_screenshots (app)->len == 0) refine_screenshots (app, store_snap); } /* load icon if requested */ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON && gs_app_get_pixbuf (app) == NULL) load_icon (plugin, client, app, gs_app_get_metadata_item (app, "snap::name"), local_snap, store_snap, cancellable); return TRUE; }
void gs_feature_tile_set_app (GsFeatureTile *tile, GsApp *app) { const gchar *background; const gchar *stroke_color; const gchar *text_color; const gchar *text_shadow; g_autoptr(GString) data = NULL; g_return_if_fail (GS_IS_FEATURE_TILE (tile)); g_return_if_fail (GS_IS_APP (app) || app == NULL); if (tile->app) g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile); g_set_object (&tile->app, app); if (!app) return; gtk_stack_set_visible_child_name (GTK_STACK (tile->stack), "content"); g_signal_connect (tile->app, "notify::state", G_CALLBACK (app_state_changed), tile); app_state_changed (tile->app, NULL, tile); gtk_label_set_label (GTK_LABEL (tile->title), gs_app_get_name (app)); gtk_label_set_label (GTK_LABEL (tile->subtitle), gs_app_get_summary (app)); /* check the app has the featured data */ text_color = gs_app_get_metadata_item (app, "Featured::text-color"); if (text_color == NULL) { g_autofree gchar *tmp = NULL; tmp = gs_app_to_string (app); g_warning ("%s has no featured data: %s", gs_app_get_id (app), tmp); return; } background = gs_app_get_metadata_item (app, "Featured::background"); stroke_color = gs_app_get_metadata_item (app, "Featured::stroke-color"); text_shadow = gs_app_get_metadata_item (app, "Featured::text-shadow"); data = g_string_sized_new (1024); g_string_append (data, ".featured-tile {\n"); g_string_append_printf (data, " border-color: %s;\n", stroke_color); if (text_shadow != NULL) g_string_append_printf (data, " text-shadow: %s;\n", text_shadow); g_string_append_printf (data, " color: %s;\n", text_color); g_string_append (data, " -GtkWidget-focus-padding: 0;\n"); g_string_append_printf (data, " outline-color: alpha(%s, 0.75);\n", text_color); g_string_append (data, " outline-style: dashed;\n"); g_string_append (data, " outline-offset: 2px;\n"); g_string_append_printf (data, " background: %s;\n", background); g_string_append (data, "}\n"); g_string_append (data, ".featured-tile:hover {\n"); g_string_append (data, " background: linear-gradient(to bottom,\n"); g_string_append (data, " alpha(#fff,0.16),\n"); g_string_append_printf (data, " alpha(#aaa,0.16)), %s;\n", background); g_string_append (data, "}\n"); gtk_css_provider_load_from_data (tile->provider, data->str, -1, NULL); }