Пример #1
1
void
gs_app_notify_installed (GsApp *app)
{
	_cleanup_free_ gchar *summary = NULL;
	_cleanup_object_unref_ GNotification *n = NULL;

	/* TRANSLATORS: this is the summary of a notification that an application
	 * has been successfully installed */
	summary = g_strdup_printf (_("%s is now installed"), gs_app_get_name (app));
	n = g_notification_new (summary);
	if (gs_app_get_id_kind (app) == AS_ID_KIND_DESKTOP) {
		/* TRANSLATORS: this is button that opens the newly installed application */
		g_notification_add_button_with_target (n, _("Launch"),
						       "app.launch", "s",
						       gs_app_get_id (app));
	}
	g_notification_set_default_action_and_target  (n, "app.details", "(ss)",
						       gs_app_get_id (app), "");
	g_application_send_notification (g_application_get_default (), "installed", n);
}
Пример #2
0
static gboolean
app_state_changed_idle (gpointer user_data)
{
	GsFeatureTile *tile = GS_FEATURE_TILE (user_data);
	AtkObject *accessible;
	g_autofree gchar *name = NULL;

	accessible = gtk_widget_get_accessible (GTK_WIDGET (tile));

	switch (gs_app_get_state (tile->app)) {
	case AS_APP_STATE_INSTALLED:
	case AS_APP_STATE_INSTALLING:
	case AS_APP_STATE_REMOVING:
	case AS_APP_STATE_UPDATABLE:
	case AS_APP_STATE_UPDATABLE_LIVE:
		name = g_strdup_printf ("%s (%s)",
					gs_app_get_name (tile->app),
					_("Installed"));
		break;
	case AS_APP_STATE_AVAILABLE:
	default:
		name = g_strdup (gs_app_get_name (tile->app));
		break;
	}

	if (GTK_IS_ACCESSIBLE (accessible)) {
		atk_object_set_name (accessible, name);
		atk_object_set_description (accessible, gs_app_get_summary (tile->app));
	}

	g_object_unref (tile);
	return G_SOURCE_REMOVE;
}
Пример #3
0
static gint
gs_editor_flow_box_sort_cb (GtkFlowBoxChild *row1, GtkFlowBoxChild *row2, gpointer user_data)
{
	GsAppTile *tile1 = GS_APP_TILE (gtk_bin_get_child (GTK_BIN (row1)));
	GsAppTile *tile2 = GS_APP_TILE (gtk_bin_get_child (GTK_BIN (row2)));
	return g_strcmp0 (gs_app_get_name (gs_app_tile_get_app (tile1)),
			  gs_app_get_name (gs_app_tile_get_app (tile2)));
}
Пример #4
0
/**
 * gs_app_row_get_description:
 *
 * Return value: PangoMarkup
 **/
static GString *
gs_app_row_get_description (GsAppRow *app_row)
{
	GsAppRowPrivate *priv = gs_app_row_get_instance_private (app_row);
	const gchar *tmp = NULL;

	/* convert the markdown update description into PangoMarkup */
	if (priv->show_update &&
	    (gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE ||
	     gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE_LIVE)) {
		tmp = gs_app_get_update_details (priv->app);
		if (tmp != NULL && tmp[0] != '\0')
			return g_string_new (tmp);
	}

	/* if missing summary is set, return it without escaping in order to
	 * correctly show hyperlinks */
	if (gs_app_get_state (priv->app) == AS_APP_STATE_UNAVAILABLE) {
		tmp = gs_app_get_summary_missing (priv->app);
		if (tmp != NULL && tmp[0] != '\0')
			return g_string_new (tmp);
	}

	/* try all these things in order */
	if (tmp == NULL || (tmp != NULL && tmp[0] == '\0'))
		tmp = gs_app_get_description (priv->app);
	if (tmp == NULL || (tmp != NULL && tmp[0] == '\0'))
		tmp = gs_app_get_summary (priv->app);
	if (tmp == NULL || (tmp != NULL && tmp[0] == '\0'))
		tmp = gs_app_get_name (priv->app);
	if (tmp == NULL)
		return NULL;
	return g_string_new (tmp);
}
Пример #5
0
void
gs_popular_tile_set_app (GsPopularTile *tile, GsApp *app)
{
	g_return_if_fail (GS_IS_POPULAR_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;

	if (gs_app_get_rating (tile->app) >= 0) {
		gtk_widget_set_visible (tile->stars, TRUE);
		gs_star_widget_set_rating (GS_STAR_WIDGET (tile->stars),
					   gs_app_get_rating (tile->app));
	} else {
		gtk_widget_set_visible (tile->stars, FALSE);
	}
	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);

	/* perhaps set custom css */
	gs_utils_widget_set_custom_css (app, GTK_WIDGET (tile),
					"GnomeSoftware::PopularTile-css");

	gs_image_set_from_pixbuf (GTK_IMAGE (tile->image), gs_app_get_pixbuf (tile->app));

	gtk_label_set_label (GTK_LABEL (tile->label), gs_app_get_name (app));
}
Пример #6
0
static gboolean
app_state_changed_idle (gpointer user_data)
{
	GsPopularTile *tile = GS_POPULAR_TILE (user_data);
	AtkObject *accessible;
	GtkWidget *label;
	gboolean installed;
	g_autofree gchar *name = NULL;

	accessible = gtk_widget_get_accessible (GTK_WIDGET (tile));

	label = gtk_bin_get_child (GTK_BIN (tile->eventbox));
	switch (gs_app_get_state (tile->app)) {
	case AS_APP_STATE_INSTALLED:
	case AS_APP_STATE_INSTALLING:
	case AS_APP_STATE_REMOVING:
	case AS_APP_STATE_UPDATABLE:
	case AS_APP_STATE_UPDATABLE_LIVE:
		installed = TRUE;
		name = g_strdup_printf ("%s (%s)",
					gs_app_get_name (tile->app),
					_("Installed"));
		/* TRANSLATORS: this is the small blue label on the tile
		 * that tells the user the application is installed */
		gtk_label_set_label (GTK_LABEL (label), _("Installed"));
		break;
	case AS_APP_STATE_AVAILABLE:
	default:
		installed = FALSE;
		name = g_strdup (gs_app_get_name (tile->app));
		break;
	}

	gtk_widget_set_visible (tile->eventbox, installed);

	if (GTK_IS_ACCESSIBLE (accessible)) {
		atk_object_set_name (accessible, name);
		atk_object_set_description (accessible, gs_app_get_summary (tile->app));
	}

	g_object_unref (tile);
	return G_SOURCE_REMOVE;
}
Пример #7
0
static void
gs_page_needs_user_action (GsPageHelper *helper, AsScreenshot *ss)
{
	GtkWidget *content_area;
	GtkWidget *dialog;
	GtkWidget *ssimg;
	g_autofree gchar *escaped = NULL;
	GsPagePrivate *priv = gs_page_get_instance_private (helper->page);

	dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell),
					 GTK_DIALOG_MODAL |
					 GTK_DIALOG_USE_HEADER_BAR,
					 GTK_MESSAGE_INFO,
					 GTK_BUTTONS_CANCEL,
					 /* TRANSLATORS: this is a prompt message, and
					  * '%s' is an application summary, e.g. 'GNOME Clocks' */
					 _("Prepare %s"),
					 gs_app_get_name (helper->app));
	escaped = g_markup_escape_text (as_screenshot_get_caption (ss, NULL), -1);
	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
						    "%s", escaped);

	/* this will be enabled when the device is in the right mode */
	helper->button_install = gtk_dialog_add_button (GTK_DIALOG (dialog),
							/* TRANSLATORS: update the fw */
							_("Install"),
							GTK_RESPONSE_OK);
	helper->notify_quirk_id =
		g_signal_connect (helper->app, "notify::quirk",
				  G_CALLBACK (gs_page_notify_quirk_cb),
				  helper);
	gtk_widget_set_sensitive (helper->button_install, FALSE);

	/* load screenshot */
	helper->soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT,
							      gs_user_agent (), NULL);
	ssimg = gs_screenshot_image_new (helper->soup_session);
	gs_screenshot_image_set_screenshot (GS_SCREENSHOT_IMAGE (ssimg), ss);
	gs_screenshot_image_set_size (GS_SCREENSHOT_IMAGE (ssimg), 400, 225);
	gs_screenshot_image_load_async (GS_SCREENSHOT_IMAGE (ssimg),
					helper->cancellable);
	gtk_widget_set_margin_start (ssimg, 24);
	gtk_widget_set_margin_end (ssimg, 24);
	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
	gtk_container_add (GTK_CONTAINER (content_area), ssimg);
	gtk_container_child_set (GTK_CONTAINER (content_area), ssimg, "pack-type", GTK_PACK_END, NULL);

	/* handle this async */
	g_signal_connect (dialog, "response",
			  G_CALLBACK (gs_page_update_app_response_cb), helper);
	gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog));
}
Пример #8
0
static gchar *
get_app_sort_key (GsApp *app)
{
	GString *key;

	key = g_string_sized_new (64);

	/* Sections:
	 * 1. offline integrated firmware
	 * 2. offline os updates (OS-update, apps, runtimes, addons, other)
	 * 3. online apps (apps, runtimes, addons, other)
	 * 4. online device firmware */
	g_string_append_printf (key, "%u:", gs_update_list_get_app_section (app));

	/* sort apps by kind */
	switch (gs_app_get_kind (app)) {
	case AS_APP_KIND_OS_UPDATE:
		g_string_append (key, "1:");
		break;
	case AS_APP_KIND_DESKTOP:
		g_string_append (key, "2:");
		break;
	case AS_APP_KIND_WEB_APP:
		g_string_append (key, "3:");
		break;
	case AS_APP_KIND_RUNTIME:
		g_string_append (key, "4:");
		break;
	case AS_APP_KIND_ADDON:
		g_string_append (key, "5:");
		break;
	case AS_APP_KIND_CODEC:
		g_string_append (key, "6:");
		break;
	case AS_APP_KIND_FONT:
		g_string_append (key, "6:");
		break;
	case AS_APP_KIND_INPUT_METHOD:
		g_string_append (key, "7:");
		break;
	case AS_APP_KIND_SHELL_EXTENSION:
		g_string_append (key, "8:");
		break;
	default:
		g_string_append (key, "9:");
		break;
	}

	/* finally, sort by short name */
	g_string_append (key, gs_app_get_name (app));
	return g_string_free (key, FALSE);
}
Пример #9
0
/**
 * gs_app_notify_failed_modal:
 **/
void
gs_app_notify_failed_modal (GsApp *app,
			    GtkWindow *parent_window,
			    GsPluginLoaderAction action,
			    const GError *error)
{
	GtkWidget *dialog;
	const gchar *title;
	_cleanup_free_ gchar *msg = NULL;

	title = _("Sorry, this did not work");
	switch (action) {
	case GS_PLUGIN_LOADER_ACTION_INSTALL:
		/* TRANSLATORS: this is when the install fails */
		msg = g_strdup_printf (_("Installation of %s failed."),
				       gs_app_get_name (app));
		break;
	case GS_PLUGIN_LOADER_ACTION_REMOVE:
		/* TRANSLATORS: this is when the remove fails */
		msg = g_strdup_printf (_("Removal of %s failed."),
				       gs_app_get_name (app));
		break;
	default:
		g_assert_not_reached ();
		break;
	}
	dialog = gtk_message_dialog_new (parent_window,
					 GTK_DIALOG_MODAL |
					 GTK_DIALOG_DESTROY_WITH_PARENT,
					 GTK_MESSAGE_ERROR,
					 GTK_BUTTONS_CLOSE,
					 "%s", title);
	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
						  "%s", msg);
	g_signal_connect (dialog, "response",
			  G_CALLBACK (gtk_widget_destroy), NULL);
	gtk_window_present (GTK_WINDOW (dialog));
}
Пример #10
0
void
gs_app_tile_set_app (GsAppTile *tile, GsApp *app)
{
	GsAppTilePrivate *priv;
	const gchar *summary;

	g_return_if_fail (GS_IS_APP_TILE (tile));
	g_return_if_fail (GS_IS_APP (app) || app == NULL);

	priv = gs_app_tile_get_instance_private (tile);

	gtk_image_clear (GTK_IMAGE (priv->image));
	gtk_image_set_pixel_size (GTK_IMAGE (priv->image), 64);

	if (priv->app)
		g_signal_handlers_disconnect_by_func (priv->app, app_state_changed, tile);

	g_clear_object (&priv->app);
	if (!app)
		return;
	priv->app = g_object_ref (app);
	if (gs_app_get_rating_kind (priv->app) == GS_APP_RATING_KIND_USER) {
		gs_star_widget_set_rating (GS_STAR_WIDGET (priv->stars),
					   GS_APP_RATING_KIND_USER,
					   gs_app_get_rating (priv->app));
	} else {
		gs_star_widget_set_rating (GS_STAR_WIDGET (priv->stars),
					   GS_APP_RATING_KIND_KUDOS,
					   gs_app_get_kudos_percentage (priv->app));
	}

	gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "content");

	g_signal_connect (priv->app, "notify::state",
			  G_CALLBACK (app_state_changed), tile);
	app_state_changed (priv->app, NULL, tile);

	gs_image_set_from_pixbuf (GTK_IMAGE (priv->image), gs_app_get_pixbuf (app));
	gtk_label_set_label (GTK_LABEL (priv->name), gs_app_get_name (app));
	summary = gs_app_get_summary (app);
	gtk_label_set_label (GTK_LABEL (priv->summary), summary);
	gtk_widget_set_visible (priv->summary, summary && summary[0]);
}
Пример #11
0
/**
 * gs_plugin_refine:
 */
gboolean
gs_plugin_refine (GsPlugin *plugin,
		  GList **list,
		  GsPluginRefineFlags flags,
		  GCancellable *cancellable,
		  GError **error)
{
	GsApp *app;
	GList *l;

	for (l = *list; l != NULL; l = l->next) {
		app = GS_APP (l->data);
		if (gs_app_get_name (app) == NULL) {
			if (g_strcmp0 (gs_app_get_id (app), "gnome-boxes") == 0) {
				gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "Boxes");
				gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "A simple GNOME 3 application to access remote or virtual systems");
			}
		}
	}
	return TRUE;
}
Пример #12
0
static gchar *
get_app_sort_key (GsApp *app)
{
	GString *key;

	key = g_string_sized_new (64);

	/* sort by kind */
	switch (gs_app_get_kind (app)) {
	case AS_APP_KIND_OS_UPDATE:
		g_string_append (key, "1:");
		break;
	default:
		g_string_append (key, "2:");
		break;
	}

	/* sort desktop files, then addons */
	switch (gs_app_get_kind (app)) {
	case AS_APP_KIND_FIRMWARE:
		g_string_append (key, "1:");
		break;
	case AS_APP_KIND_DESKTOP:
		g_string_append (key, "2:");
		break;
	default:
		g_string_append (key, "3:");
		break;
	}

	/* sort by install date */
	g_string_append_printf (key, "%09" G_GUINT64_FORMAT ":",
				G_MAXUINT64 - gs_app_get_install_date (app));

	/* finally, sort by short name */
	g_string_append (key, gs_app_get_name (app));
	return g_string_free (key, FALSE);
}
Пример #13
0
/**
 * gs_plugin_refine_app:
 */
static gboolean
gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GError **error)
{
	g_autofree gchar *fn = NULL;
	g_autofree gchar *hash = NULL;
	g_autofree gchar *id_nonfull = NULL;

	id_nonfull = _gs_app_get_id_nonfull (app);
	hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1);
	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;
	}
	gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
	return TRUE;
}
Пример #14
0
static GsApp *
gs_plugin_fwupd_new_app (GsPlugin *plugin, FwupdDevice *dev, GError **error)
{
	FwupdRelease *rel = fwupd_device_get_release_default (dev);
	GPtrArray *checksums;
	const gchar *update_uri;
	g_autofree gchar *basename = NULL;
	g_autofree gchar *filename_cache = NULL;
	g_autoptr(GFile) file = NULL;
	g_autoptr(GsApp) app = NULL;

	/* update unsupported */
	app = gs_plugin_fwupd_new_app_from_device (plugin, dev);
	if (gs_app_get_state (app) != AS_APP_STATE_UPDATABLE_LIVE) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "%s [%s] cannot be updated",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* some missing */
	if (gs_app_get_id (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No id for firmware");
		return NULL;
	}
	if (gs_app_get_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	if (gs_app_get_update_version (app) == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NOT_SUPPORTED,
			     "fwupd: No update-version! for %s!", gs_app_get_id (app));
		return NULL;
	}
	checksums = fwupd_release_get_checksums (rel);
	if (checksums->len == 0) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_NO_SECURITY,
			     "%s [%s] (%s) has no checksums, ignoring as unsafe",
			     gs_app_get_name (app),
			     gs_app_get_id (app),
			     gs_app_get_update_version (app));
		return NULL;
	}
	update_uri = fwupd_release_get_uri (rel);
	if (update_uri == NULL) {
		g_set_error (error,
			     GS_PLUGIN_ERROR,
			     GS_PLUGIN_ERROR_INVALID_FORMAT,
			     "no location available for %s [%s]",
			     gs_app_get_name (app), gs_app_get_id (app));
		return NULL;
	}

	/* does the firmware already exist in the cache? */
	basename = g_path_get_basename (update_uri);
	filename_cache = gs_utils_get_cache_filename ("fwupd",
						      basename,
						      GS_UTILS_CACHE_FLAG_NONE,
						      error);
	if (filename_cache == NULL)
		return NULL;

	/* delete the file if the checksum does not match */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS)) {
		const gchar *checksum_tmp = NULL;
		g_autofree gchar *checksum = NULL;

		/* we can migrate to something better than SHA1 when the LVFS
		 * starts producing metadata with multiple hash types */
		checksum_tmp = fwupd_checksum_get_by_kind (checksums,
							   G_CHECKSUM_SHA1);
		if (checksum_tmp == NULL) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "No valid checksum for %s",
				     filename_cache);
		}
		checksum = gs_plugin_fwupd_get_file_checksum (filename_cache,
							      G_CHECKSUM_SHA1,
							      error);
		if (checksum == NULL)
			return NULL;
		if (g_strcmp0 (checksum_tmp, checksum) != 0) {
			g_set_error (error,
				     GS_PLUGIN_ERROR,
				     GS_PLUGIN_ERROR_INVALID_FORMAT,
				     "%s does not match checksum, expected %s got %s",
				     filename_cache, checksum_tmp, checksum);
			g_unlink (filename_cache);
			return NULL;
		}
	}

	/* already downloaded, so overwrite */
	if (g_file_test (filename_cache, G_FILE_TEST_EXISTS))
		gs_app_set_size_download (app, 0);

	/* actually add the application */
	file = g_file_new_for_path (filename_cache);
	gs_app_set_local_file (app, file);
	return g_steal_pointer (&app);
}
Пример #15
0
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);
}
Пример #16
0
void
gs_page_remove_app (GsPage *page, GsApp *app, GCancellable *cancellable)
{
	GsPagePrivate *priv = gs_page_get_instance_private (page);
	GsPageHelper *helper;
	GtkWidget *dialog;
	g_autofree gchar *message = NULL;
	g_autofree gchar *title = NULL;

	/* pending install */
	helper = g_slice_new0 (GsPageHelper);
	helper->action = GS_PLUGIN_ACTION_REMOVE;
	helper->app = g_object_ref (app);
	helper->page = g_object_ref (page);
	helper->cancellable = g_object_ref (cancellable);
	if (gs_app_get_state (app) == AS_APP_STATE_QUEUED_FOR_INSTALL) {
		g_debug ("remove %s", gs_app_get_id (app));
		gs_plugin_loader_app_action_async (priv->plugin_loader,
		                                   app,
		                                   GS_PLUGIN_ACTION_REMOVE,
		                                   GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY,
		                                   helper->cancellable,
		                                   gs_page_app_removed_cb,
		                                   helper);
		return;
	}

	/* use different name and summary */
	switch (gs_app_get_kind (app)) {
	case AS_APP_KIND_SOURCE:
		/* TRANSLATORS: this is a prompt message, and '%s' is an
		 * source name, e.g. 'GNOME Nightly' */
		title = g_strdup_printf (_("Are you sure you want to remove "
					   "the %s source?"),
					 gs_app_get_name (app));
		/* TRANSLATORS: longer dialog text */
		message = g_strdup_printf (_("All applications from %s will be "
					     "removed, and you will have to "
					     "re-install the source to use them again."),
					   gs_app_get_name (app));
		break;
	default:
		/* TRANSLATORS: this is a prompt message, and '%s' is an
		 * application summary, e.g. 'GNOME Clocks' */
		title = g_strdup_printf (_("Are you sure you want to remove %s?"),
					 gs_app_get_name (app));
		/* TRANSLATORS: longer dialog text */
		message = g_strdup_printf (_("%s will be removed, and you will "
					     "have to install it to use it again."),
					   gs_app_get_name (app));
		break;
	}

	/* ask for confirmation */
	dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell),
	                                 GTK_DIALOG_MODAL,
	                                 GTK_MESSAGE_QUESTION,
	                                 GTK_BUTTONS_CANCEL,
	                                 "%s", title);
	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
						  "%s", message);

	/* TRANSLATORS: this is button text to remove the application */
	gtk_dialog_add_button (GTK_DIALOG (dialog), _("Remove"), GTK_RESPONSE_OK);

	/* handle this async */
	g_signal_connect (dialog, "response",
			  G_CALLBACK (gs_page_remove_app_response_cb), helper);
	gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog));
}
Пример #17
0
void
gs_page_install_app (GsPage *page,
		     GsApp *app,
		     GsShellInteraction interaction,
		     GCancellable *cancellable)
{
	GsPagePrivate *priv = gs_page_get_instance_private (page);
	GsPageHelper *helper;

	/* probably non-free */
	if (gs_app_get_state (app) == AS_APP_STATE_UNAVAILABLE) {
		GtkResponseType response;

		response = gs_app_notify_unavailable (app, gs_shell_get_window (priv->shell));
		if (response != GTK_RESPONSE_OK)
			return;
	}

	helper = g_slice_new0 (GsPageHelper);
	helper->action = GS_PLUGIN_ACTION_INSTALL;
	helper->app = g_object_ref (app);
	helper->page = g_object_ref (page);
	helper->cancellable = g_object_ref (cancellable);
	helper->interaction = interaction;

	/* need to purchase first */
	if (gs_app_get_state (app) == AS_APP_STATE_PURCHASABLE) {
		GtkWidget *dialog;
		g_autofree gchar *title = NULL;
		g_autofree gchar *message = NULL;
		g_autofree gchar *price_text = NULL;

		/* TRANSLATORS: this is a prompt message, and '%s' is an
		 * application summary, e.g. 'GNOME Clocks' */
		title = g_strdup_printf (_("Are you sure you want to purchase %s?"),
					 gs_app_get_name (app));
		price_text = gs_price_to_string (gs_app_get_price (app));
		/* TRANSLATORS: longer dialog text */
		message = g_strdup_printf (_("%s will be installed, and you will "
					     "be charged %s."),
					   gs_app_get_name (app), price_text);

		dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell),
						 GTK_DIALOG_MODAL,
						 GTK_MESSAGE_QUESTION,
						 GTK_BUTTONS_CANCEL,
						 "%s", title);
		gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
							  "%s", message);

		/* TRANSLATORS: this is button text to purchase the application */
		gtk_dialog_add_button (GTK_DIALOG (dialog), _("Purchase"), GTK_RESPONSE_OK);

		/* handle this async */
		g_signal_connect (dialog, "response",
				  G_CALLBACK (gs_page_install_purchase_response_cb), helper);
		gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog));
	} else {
		g_autoptr(GsPluginJob) plugin_job = NULL;

		plugin_job = gs_plugin_job_newv (helper->action,
						 "interactive", TRUE,
						 "app", helper->app,
						 NULL);
		gs_plugin_loader_job_process_async (priv->plugin_loader,
						    plugin_job,
						    helper->cancellable,
						    gs_page_app_installed_cb,
						    helper);
	}
}
Пример #18
0
void
gs_app_row_refresh (GsAppRow *app_row)
{
	GsAppRowPrivate *priv = gs_app_row_get_instance_private (app_row);
	GtkStyleContext *context;
	GString *str = NULL;
	const gchar *tmp;
	gboolean missing_search_result;
	guint64 installed_size;

	if (priv->app == NULL)
		return;

	/* is this a missing search result from the extras page? */
	missing_search_result = (gs_app_get_state (priv->app) == AS_APP_STATE_UNAVAILABLE &&
	                         gs_app_get_url (priv->app, AS_URL_KIND_MISSING) != NULL);

	/* do a fill bar for the current progress */
	switch (gs_app_get_state (priv->app)) {
	case AS_APP_STATE_INSTALLING:
		gs_progress_button_set_progress (GS_PROGRESS_BUTTON (priv->button),
		                                 gs_app_get_progress (priv->app));
		gs_progress_button_set_show_progress (GS_PROGRESS_BUTTON (priv->button), TRUE);
		break;
	default:
		gs_progress_button_set_show_progress (GS_PROGRESS_BUTTON (priv->button), FALSE);
		break;
	}

	/* join the description lines */
	str = gs_app_row_get_description (app_row);
	if (str != NULL) {
		as_utils_string_replace (str, "\n", " ");
		gtk_label_set_label (GTK_LABEL (priv->description_label), str->str);
		g_string_free (str, TRUE);
	} else {
		gtk_label_set_text (GTK_LABEL (priv->description_label), NULL);
	}

	/* add warning */
	if (gs_app_has_quirk (priv->app, AS_APP_QUIRK_REMOVABLE_HARDWARE)) {
		gtk_label_set_text (GTK_LABEL (priv->label_warning),
				    /* TRANSLATORS: during the update the device
				     * will restart into a special update-only mode */
				    _("Device cannot be used during update."));
		gtk_widget_show (priv->label_warning);
	}

	/* where did this app come from */
	if (priv->show_source) {
		tmp = gs_app_get_origin_hostname (priv->app);
		if (tmp != NULL) {
			g_autofree gchar *origin_tmp = NULL;
			/* TRANSLATORS: this refers to where the app came from */
			origin_tmp = g_strdup_printf ("%s: %s", _("Source"), tmp);
			gtk_label_set_label (GTK_LABEL (priv->label_origin), origin_tmp);
		}
		gtk_widget_set_visible (priv->label_origin, tmp != NULL);
	} else {
		gtk_widget_set_visible (priv->label_origin, FALSE);
	}

	/* installed tag */
	if (!priv->show_buttons) {
		switch (gs_app_get_state (priv->app)) {
		case AS_APP_STATE_UPDATABLE:
		case AS_APP_STATE_UPDATABLE_LIVE:
		case AS_APP_STATE_INSTALLED:
			gtk_widget_set_visible (priv->label_installed, TRUE);
			break;
		default:
			gtk_widget_set_visible (priv->label_installed, FALSE);
			break;
		}
	} else {
		gtk_widget_set_visible (priv->label_installed, FALSE);
	}

	/* name */
	if (g_strcmp0 (gs_app_get_branch (priv->app), "master") == 0) {
		g_autofree gchar *name = NULL;
		/* TRANSLATORS: not translated to match what flatpak does */
		name = g_strdup_printf ("%s (Nightly)",
					gs_app_get_name (priv->app));
		gtk_label_set_label (GTK_LABEL (priv->name_label), name);
	} else {
		gtk_label_set_label (GTK_LABEL (priv->name_label),
				     gs_app_get_name (priv->app));
	}
	if (priv->show_update &&
	    (gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE ||
	     gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE_LIVE)) {
		g_autofree gchar *verstr = NULL;
		verstr = gs_app_row_format_version_update (priv->app);
		gtk_label_set_label (GTK_LABEL (priv->version_label), verstr);
		gtk_widget_set_visible (priv->version_label, verstr != NULL);
		gtk_widget_hide (priv->star);
	} else {
		gtk_widget_hide (priv->version_label);
		if (missing_search_result || gs_app_get_rating (priv->app) <= 0) {
			gtk_widget_hide (priv->star);
		} else {
			gtk_widget_show (priv->star);
			gtk_widget_set_sensitive (priv->star, FALSE);
			gs_star_widget_set_rating (GS_STAR_WIDGET (priv->star),
						   gs_app_get_rating (priv->app));
		}
		gtk_label_set_label (GTK_LABEL (priv->version_label),
				     gs_app_get_version_ui (priv->app));
	}

	/* folders */
	if (priv->show_folders &&
	    gs_utils_is_current_desktop ("GNOME") &&
	    g_settings_get_boolean (priv->settings, "show-folder-management")) {
		g_autoptr(GsFolders) folders = NULL;
		const gchar *folder;
		folders = gs_folders_get ();
		folder = gs_folders_get_app_folder (folders,
						    gs_app_get_id (priv->app),
						    gs_app_get_categories (priv->app));
		if (folder != NULL)
			folder = gs_folders_get_folder_name (folders, folder);
		gtk_label_set_label (GTK_LABEL (priv->folder_label), folder);
		gtk_widget_set_visible (priv->folder_label, folder != NULL);
	} else {
		gtk_widget_hide (priv->folder_label);
	}

	/* pixbuf */
	if (gs_app_get_pixbuf (priv->app) != NULL)
		gs_image_set_from_pixbuf (GTK_IMAGE (priv->image),
					  gs_app_get_pixbuf (priv->app));

	context = gtk_widget_get_style_context (priv->image);
	if (missing_search_result)
		gtk_style_context_add_class (context, "dimmer-label");
	else
		gtk_style_context_remove_class (context, "dimmer-label");

	/* pending label */
	switch (gs_app_get_state (priv->app)) {
	case AS_APP_STATE_QUEUED_FOR_INSTALL:
		gtk_widget_set_visible (priv->label, TRUE);
		gtk_label_set_label (GTK_LABEL (priv->label), _("Pending"));
		break;
	default:
		gtk_widget_set_visible (priv->label, FALSE);
		break;
	}

	/* spinner */
	switch (gs_app_get_state (priv->app)) {
	case AS_APP_STATE_REMOVING:
		gtk_spinner_start (GTK_SPINNER (priv->spinner));
		gtk_widget_set_visible (priv->spinner, TRUE);
		break;
	default:
		gtk_widget_set_visible (priv->spinner, FALSE);
		break;
	}

	/* button */
	gs_app_row_refresh_button (app_row, missing_search_result);

	/* hide buttons in the update list, unless the app is live updatable */
	switch (gs_app_get_state (priv->app)) {
	case AS_APP_STATE_UPDATABLE_LIVE:
	case AS_APP_STATE_INSTALLING:
		gtk_widget_set_visible (priv->button_box, TRUE);
		break;
	default:
		gtk_widget_set_visible (priv->button_box, !priv->show_update);
		break;
	}

	/* checkbox */
	if (priv->selectable) {
		if (gs_app_get_kind (priv->app) == AS_APP_KIND_DESKTOP ||
		    gs_app_get_kind (priv->app) == AS_APP_KIND_RUNTIME ||
		    gs_app_get_kind (priv->app) == AS_APP_KIND_WEB_APP)
			gtk_widget_set_visible (priv->checkbox, TRUE);
	} else {
		gtk_widget_set_visible (priv->checkbox, FALSE);
	}

	installed_size = gs_app_get_size_installed (priv->app);
	if (priv->show_installed_size &&
	    installed_size != GS_APP_SIZE_UNKNOWABLE && installed_size != 0) {
		g_autofree gchar *size = NULL;
		size = g_format_size (installed_size);
		gtk_label_set_label (GTK_LABEL (priv->label_app_size), size);
		gtk_widget_show (priv->label_app_size);
	} else {
		gtk_widget_hide (priv->label_app_size);
	}
}
Пример #19
0
/**
 * gs_plugin_app_install:
 */
gboolean
gs_plugin_app_install (GsPlugin *plugin, GsApp *app,
		       GCancellable *cancellable, GError **error)
{
	AsIcon *icon;
	gboolean ret = TRUE;
	gsize kf_length;
	g_autoptr(GError) error_local = NULL;
	g_autofree gchar *app_desktop = NULL;
	g_autofree gchar *epi_desktop = NULL;
	g_autofree gchar *epi_dir = NULL;
	g_autofree gchar *epi_icon = NULL;
	g_autofree gchar *exec = NULL;
	g_autofree gchar *hash = NULL;
	g_autofree gchar *id_nonfull = NULL;
	g_autofree gchar *kf_data = NULL;
	g_autofree gchar *wmclass = NULL;
	g_autoptr(GKeyFile) kf = NULL;
	g_autoptr(GFile) symlink_desktop = NULL;
	g_autoptr(GFile) symlink_icon = NULL;

	/* only process web apps */
	if (gs_app_get_id_kind (app) != AS_ID_KIND_WEB_APP)
		return TRUE;

	/* 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;
		}
	}

	/* 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,
			       G_KEY_FILE_DESKTOP_KEY_NAME,
			       gs_app_get_name (app));
	g_key_file_set_string (kf,
			       G_KEY_FILE_DESKTOP_GROUP,
			       G_KEY_FILE_DESKTOP_KEY_COMMENT,
			       gs_app_get_summary (app));
	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,
			       exec);
	g_key_file_set_boolean (kf,
				G_KEY_FILE_DESKTOP_GROUP,
				G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY,
				TRUE);
	g_key_file_set_boolean (kf,
				G_KEY_FILE_DESKTOP_GROUP,
				G_KEY_FILE_DESKTOP_KEY_TERMINAL,
				FALSE);
	g_key_file_set_boolean (kf,
				G_KEY_FILE_DESKTOP_GROUP,
				G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
				FALSE);
	g_key_file_set_string (kf,
			       G_KEY_FILE_DESKTOP_GROUP,
			       G_KEY_FILE_DESKTOP_KEY_TYPE,
			       G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
	g_key_file_set_string (kf,
			       G_KEY_FILE_DESKTOP_GROUP,
			       G_KEY_FILE_DESKTOP_KEY_ICON,
			       epi_icon);
	g_key_file_set_string (kf,
			       G_KEY_FILE_DESKTOP_GROUP,
			       G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS,
			       wmclass);

	/* save keyfile */
	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_build_filename (g_get_user_data_dir (),
	                                "applications",
	                                gs_app_get_id (app),
	                                NULL);
	symlink_desktop = g_file_new_for_path (app_desktop);
	ret = g_file_make_symbolic_link (symlink_desktop,
					 epi_desktop,
					 NULL,
					 error);
	if (!ret)
		return FALSE;

	/* update state */
	gs_app_set_state (app, AS_APP_STATE_INSTALLING);
	gs_app_set_state (app, AS_APP_STATE_INSTALLED);
	return TRUE;
}
Пример #20
0
/**
 * gs_app_notify_unavailable:
 **/
GtkResponseType
gs_app_notify_unavailable (GsApp *app, GtkWindow *parent)
{
	GsAppLicenceHint hint = GS_APP_LICENCE_FREE;
	GtkResponseType response;
	GtkWidget *dialog;
	const gchar *licence;
	gboolean already_enabled = FALSE;	/* FIXME */
	guint i;
	struct {
		const gchar	*str;
		GsAppLicenceHint hint;
	} keywords[] = {
		{ "NonFree",		GS_APP_LICENCE_NONFREE },
		{ "PatentConcern",	GS_APP_LICENCE_PATENT_CONCERN },
		{ "Proprietary",	GS_APP_LICENCE_NONFREE },
		{ NULL, 0 }
	};
	_cleanup_free_ gchar *origin_url = NULL;
	_cleanup_object_unref_ GSettings *settings = NULL;
	_cleanup_string_free_ GString *body = NULL;
	_cleanup_string_free_ GString *title = NULL;

	/* this is very crude */
	licence = gs_app_get_licence (app);
	if (licence != NULL) {
		for (i = 0; keywords[i].str != NULL; i++) {
			if (g_strstr_len (licence, -1, keywords[i].str) != NULL)
				hint |= keywords[i].hint;
		}
	} else {
		/* use the worst-case assumption */
		hint = GS_APP_LICENCE_NONFREE | GS_APP_LICENCE_PATENT_CONCERN;
	}

	/* check if the user has already dismissed */
	settings = g_settings_new ("org.gnome.software");
	if (!g_settings_get_boolean (settings, "prompt-for-nonfree"))
		return GTK_RESPONSE_OK;

	title = g_string_new ("");
	if (already_enabled) {
		g_string_append_printf (title, "<b>%s</b>",
					/* TRANSLATORS: window title */
					_("Install Third-Party Software?"));
	} else {
		g_string_append_printf (title, "<b>%s</b>",
					/* TRANSLATORS: window title */
					_("Enable Third-Party Software Source?"));
	}
	dialog = gtk_message_dialog_new (parent,
					 GTK_DIALOG_MODAL,
					 GTK_MESSAGE_QUESTION,
					 GTK_BUTTONS_CANCEL,
					 NULL);
	gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), title->str);

	/* FIXME: get the URL somehow... */
	origin_url = g_strdup_printf ("<a href=\"\">%s>/a>", gs_app_get_origin (app));
	body = g_string_new ("");
	if (hint & GS_APP_LICENCE_NONFREE) {
		g_string_append_printf (body,
					/* TRANSLATORS: the replacements are as follows:
					 * 1. Application name, e.g. "Firefox"
					 * 2. Software source name, e.g. fedora-optional
					 */
					_("%s is not <a href=\"https://en.wikipedia.org/wiki/Free_and_open-source_software\">"
					  "free and open source software</a>, "
					  "and is provided by “%s”."),
					gs_app_get_name (app),
					origin_url);
	} else {
		g_string_append_printf (body,
					/* TRANSLATORS: the replacements are as follows:
					 * 1. Application name, e.g. "Firefox"
					 * 2. Software source name, e.g. fedora-optional */
					_("%s is provided by “%s”."),
					gs_app_get_name (app),
					origin_url);
	}

	/* tell the use what needs to be done */
	if (!already_enabled) {
		g_string_append (body, " ");
		g_string_append (body,
				/* TRANSLATORS: a software source is a repo */
				_("This software source must be "
				  "enabled to continue installation."));
	}

	/* be aware of patent clauses */
	if (hint & GS_APP_LICENCE_PATENT_CONCERN) {
		g_string_append (body, "\n\n");
		if (gs_app_get_id_kind (app) != AS_ID_KIND_CODEC) {
			g_string_append_printf (body,
						/* TRANSLATORS: Laws are geographical, urgh... */
						_("It may be illegal to install "
						  "or use %s in some countries."),
						gs_app_get_name (app));
		} else {
			g_string_append (body,
					/* TRANSLATORS: Laws are geographical, urgh... */
					_("It may be illegal to install or use "
					  "this codec in some countries."));
		}
	}

	gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", body->str);
	/* TRANSLATORS: this is button text to not ask about non-free content again */
	if (0) gtk_dialog_add_button (GTK_DIALOG (dialog), _("Don't Warn Again"), GTK_RESPONSE_YES);
	if (already_enabled) {
		gtk_dialog_add_button (GTK_DIALOG (dialog),
				       /* TRANSLATORS: button text */
				       _("Install"),
				       GTK_RESPONSE_OK);
	} else {
		gtk_dialog_add_button (GTK_DIALOG (dialog),
				       /* TRANSLATORS: button text */
				       _("Enable and Install"),
				       GTK_RESPONSE_OK);
	}
	response = gtk_dialog_run (GTK_DIALOG (dialog));
	if (response == GTK_RESPONSE_YES) {
		response = GTK_RESPONSE_OK;
		g_settings_set_boolean (settings, "prompt-for-nonfree", FALSE);
	}
	gtk_widget_destroy (dialog);
	return response;
}