[gnome-software] Split up gs-utils into two source files for sanity
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Split up gs-utils into two source files for sanity
- Date: Tue, 10 May 2016 07:53:11 +0000 (UTC)
commit 7c59ca10fda0fed12d0bb8fbd4e087424c449dcf
Author: Richard Hughes <richard hughsie com>
Date: Tue May 10 08:43:23 2016 +0100
Split up gs-utils into two source files for sanity
gs-common.h is designed to be used by the frontend, gs-utils.h is designed to
be used by plugins.
po/POTFILES.in | 2 +-
src/Makefile.am | 4 +
src/gs-app-row.c | 2 +-
src/gs-app-tile.c | 2 +-
src/gs-app.c | 1 +
src/gs-common.c | 750 +++++++++++++++++++++++++++++++++++++++++++++
src/gs-common.h | 71 +++++
src/gs-feature-tile.c | 2 +-
src/gs-history-dialog.c | 2 +-
src/gs-page.c | 2 +-
src/gs-plugin-loader.c | 2 +-
src/gs-popular-tile.c | 2 +-
src/gs-screenshot-image.c | 3 +-
src/gs-shell-category.c | 2 +-
src/gs-shell-details.c | 4 +-
src/gs-shell-extras.c | 2 +-
src/gs-shell-installed.c | 2 +-
src/gs-shell-moderate.c | 2 +-
src/gs-shell-overview.c | 2 +-
src/gs-shell-search.c | 2 +-
src/gs-shell-updates.c | 2 +-
src/gs-shell.c | 2 +-
src/gs-sources-dialog.c | 2 +-
src/gs-update-dialog.c | 2 +-
src/gs-upgrade-banner.c | 2 +-
src/gs-utils.c | 719 -------------------------------------------
src/gs-utils.h | 47 +---
27 files changed, 855 insertions(+), 782 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0f37728..8bd9c8b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -54,7 +54,7 @@ src/gs-update-list.c
src/gs-update-monitor.c
src/gs-upgrade-banner.c
[type: gettext/glade]src/gs-upgrade-banner.ui
-src/gs-utils.c
+src/gs-common.c
[type: gettext/glade]src/gs-menus.ui
src/org.gnome.Software.desktop.in
src/plugins/menu-spec-common.c
diff --git a/src/Makefile.am b/src/Makefile.am
index d7766d6..f2441ad 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -91,6 +91,7 @@ gnome_software_cmd_SOURCES = \
gs-app-list.c \
gs-review.c \
gs-cmd.c \
+ gs-common.c \
gs-debug.c \
gs-utils.c \
gs-os-release.c \
@@ -122,6 +123,8 @@ gnome_software_SOURCES = \
gs-app-list.h \
gs-category.c \
gs-category.h \
+ gs-common.c \
+ gs-common.h \
gs-debug.c \
gs-debug.h \
gs-app-addon-row.c \
@@ -300,6 +303,7 @@ gs_self_test_SOURCES = \
gs-app.c \
gs-app-list.c \
gs-category.c \
+ gs-common.c \
gs-os-release.c \
gs-plugin-loader-sync.c \
gs-plugin-loader.c \
diff --git a/src/gs-app-row.c b/src/gs-app-row.c
index 49a1fa4..28784e9 100644
--- a/src/gs-app-row.c
+++ b/src/gs-app-row.c
@@ -28,7 +28,7 @@
#include "gs-app-row.h"
#include "gs-star-widget.h"
#include "gs-progress-button.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-folders.h"
typedef struct
diff --git a/src/gs-app-tile.c b/src/gs-app-tile.c
index 5aefdfc..091e643 100644
--- a/src/gs-app-tile.c
+++ b/src/gs-app-tile.c
@@ -26,7 +26,7 @@
#include "gs-app-tile.h"
#include "gs-star-widget.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsAppTile
{
diff --git a/src/gs-app.c b/src/gs-app.c
index 99e7abf..2710c86 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -48,6 +48,7 @@
#include <glib/gi18n.h>
#include "gs-app.h"
+#include "gs-plugin.h"
#include "gs-utils.h"
struct _GsApp
diff --git a/src/gs-common.c b/src/gs-common.c
new file mode 100644
index 0000000..8253fba
--- /dev/null
+++ b/src/gs-common.c
@@ -0,0 +1,750 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013-2015 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"
+
+#include <glib/gi18n.h>
+#include <gio/gdesktopappinfo.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#include "gs-app.h"
+#include "gs-common.h"
+#include "gs-plugin.h"
+
+#define SPINNER_DELAY 500
+
+static gboolean
+fade_in (gpointer data)
+{
+ GtkWidget *spinner = data;
+ gdouble opacity;
+
+ opacity = gtk_widget_get_opacity (spinner);
+ opacity = opacity + 0.1;
+ gtk_widget_set_opacity (spinner, opacity);
+
+ if (opacity >= 1.0) {
+ g_object_steal_data (G_OBJECT (spinner), "fade-timeout");
+ return G_SOURCE_REMOVE;
+ }
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+remove_source (gpointer data)
+{
+ g_source_remove (GPOINTER_TO_UINT (data));
+}
+
+static gboolean
+start_spinning (gpointer data)
+{
+ GtkWidget *spinner = data;
+ guint id;
+
+ gtk_widget_set_opacity (spinner, 0);
+ gtk_spinner_start (GTK_SPINNER (spinner));
+ id = g_timeout_add (100, fade_in, spinner);
+ g_object_set_data_full (G_OBJECT (spinner), "fade-timeout",
+ GUINT_TO_POINTER (id), remove_source);
+
+ /* don't try to remove this source in the future */
+ g_object_steal_data (G_OBJECT (spinner), "start-timeout");
+ return G_SOURCE_REMOVE;
+}
+
+void
+gs_stop_spinner (GtkSpinner *spinner)
+{
+ g_object_set_data (G_OBJECT (spinner), "start-timeout", NULL);
+ gtk_spinner_stop (spinner);
+}
+
+void
+gs_start_spinner (GtkSpinner *spinner)
+{
+ gboolean active;
+ guint id;
+
+ /* Don't do anything if it's already spinning */
+ g_object_get (spinner, "active", &active, NULL);
+ if (active || g_object_get_data (G_OBJECT (spinner), "start-timeout") != NULL)
+ return;
+
+ gtk_widget_set_opacity (GTK_WIDGET (spinner), 0);
+ id = g_timeout_add (SPINNER_DELAY, start_spinning, spinner);
+ g_object_set_data_full (G_OBJECT (spinner), "start-timeout",
+ GUINT_TO_POINTER (id), remove_source);
+}
+
+static void
+remove_all_cb (GtkWidget *widget, gpointer user_data)
+{
+ GtkContainer *container = GTK_CONTAINER (user_data);
+ gtk_container_remove (container, widget);
+}
+
+void
+gs_container_remove_all (GtkContainer *container)
+{
+ gtk_container_foreach (container, remove_all_cb, container);
+}
+
+static void
+grab_focus (GtkWidget *widget)
+{
+ g_signal_handlers_disconnect_by_func (widget, grab_focus, NULL);
+ gtk_widget_grab_focus (widget);
+}
+
+void
+gs_grab_focus_when_mapped (GtkWidget *widget)
+{
+ if (gtk_widget_get_mapped (widget))
+ gtk_widget_grab_focus (widget);
+ else
+ g_signal_connect_after (widget, "map",
+ G_CALLBACK (grab_focus), NULL);
+}
+
+void
+gs_app_notify_installed (GsApp *app)
+{
+ g_autofree gchar *summary = NULL;
+ g_autoptr(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_kind (app) == AS_APP_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);
+}
+
+/**
+ * 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;
+ gboolean show_detailed_error;
+ g_autoptr(GString) msg = NULL;
+
+ /* TRANSLATORS: install or removed failed */
+ title = _("Sorry, this did not work");
+
+ /* say what we tried to do */
+ msg = g_string_new ("");
+ switch (action) {
+ case GS_PLUGIN_LOADER_ACTION_INSTALL:
+ /* TRANSLATORS: this is when the install fails */
+ g_string_append_printf (msg, _("Installation of %s failed."),
+ gs_app_get_name (app));
+ break;
+ case GS_PLUGIN_LOADER_ACTION_REMOVE:
+ /* TRANSLATORS: this is when the remove fails */
+ g_string_append_printf (msg, _("Removal of %s failed."),
+ gs_app_get_name (app));
+ break;
+ case GS_PLUGIN_LOADER_ACTION_UPGRADE_DOWNLOAD:
+ /* TRANSLATORS: this is when the upgrade download fails */
+ g_string_append_printf (msg, _("Upgrade to %s failed."),
+ gs_app_get_name (app));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ g_string_append (msg, " ");
+
+ /* give details about the error */
+ switch (error->code) {
+ case GS_PLUGIN_ERROR_NO_NETWORK:
+ /* TRANSLATORS: the package manager needed to download
+ * something with no network available */
+ g_string_append (msg, _("Internet access was required but wasn’t available."));
+ g_string_append (msg, " ");
+ /* TRANSLATORS: plug in the network cable... */
+ g_string_append (msg, _("Please make sure that you have internet access and try again."));
+ show_detailed_error = FALSE;
+ break;
+ case GS_PLUGIN_ERROR_NO_SPACE:
+ /* TRANSLATORS: we ran out of disk space */
+ g_string_append (msg, _("There wasn’t enough disk space."));
+ g_string_append (msg, " ");
+ /* TRANSLATORS: delete some stuff! */
+ g_string_append (msg, _("Please free up some space and try again."));
+ show_detailed_error = FALSE;
+ break;
+ default:
+ /* TRANSLATORS: we didn't handle the error type */
+ g_string_append (msg, _("If the problem persists, contact your software provider."));
+ show_detailed_error = TRUE;
+ }
+
+ dialog = gtk_message_dialog_new (parent_window,
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_USE_HEADER_BAR |
+ 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->str);
+
+ /* detailed error in an expander */
+ if (show_detailed_error) {
+ GtkWidget *vbox;
+ GtkWidget *expander;
+ GtkWidget *scrolled_window;
+ GtkWidget *label;
+
+ vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ /* TRANSLATORS: this is an expander title */
+ expander = gtk_expander_new (_("Show Details"));
+ gtk_widget_set_margin_start (expander, 36);
+ gtk_widget_set_margin_end (expander, 36);
+ scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (expander), scrolled_window);
+ label = gtk_label_new (error->message);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_container_add (GTK_CONTAINER (scrolled_window), label);
+ gtk_box_pack_end (GTK_BOX (vbox), expander, FALSE, TRUE, 4);
+ gtk_widget_show_all (expander);
+
+ }
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+typedef enum {
+ GS_APP_LICENSE_FREE = 0,
+ GS_APP_LICENSE_NONFREE = 1,
+ GS_APP_LICENSE_PATENT_CONCERN = 2
+} GsAppLicenseHint;
+
+/**
+ * gs_app_notify_unavailable:
+ **/
+GtkResponseType
+gs_app_notify_unavailable (GsApp *app, GtkWindow *parent)
+{
+ GsAppLicenseHint hint = GS_APP_LICENSE_FREE;
+ GtkResponseType response;
+ GtkWidget *dialog;
+ const gchar *license;
+ gboolean already_enabled = FALSE; /* FIXME */
+ guint i;
+ struct {
+ const gchar *str;
+ GsAppLicenseHint hint;
+ } keywords[] = {
+ { "NonFree", GS_APP_LICENSE_NONFREE },
+ { "PatentConcern", GS_APP_LICENSE_PATENT_CONCERN },
+ { "Proprietary", GS_APP_LICENSE_NONFREE },
+ { NULL, 0 }
+ };
+ g_autofree gchar *origin_url = NULL;
+ g_autoptr(GSettings) settings = NULL;
+ g_autoptr(GString) body = NULL;
+ g_autoptr(GString) title = NULL;
+
+ /* this is very crude */
+ license = gs_app_get_license (app);
+ if (license != NULL) {
+ for (i = 0; keywords[i].str != NULL; i++) {
+ if (g_strstr_len (license, -1, keywords[i].str) != NULL)
+ hint |= keywords[i].hint;
+ }
+ } else {
+ /* use the worst-case assumption */
+ hint = GS_APP_LICENSE_NONFREE | GS_APP_LICENSE_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_LICENSE_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_LICENSE_PATENT_CONCERN) {
+ g_string_append (body, "\n\n");
+ if (gs_app_get_kind (app) != AS_APP_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;
+}
+
+void
+gs_app_show_url (GsApp *app, AsUrlKind kind)
+{
+ const gchar *url;
+ g_autoptr(GError) error = NULL;
+
+ url = gs_app_get_url (app, kind);
+ if (!gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error))
+ g_warning ("spawn of '%s' failed", url);
+}
+
+/**
+ * gs_image_set_from_pixbuf_with_scale:
+ **/
+void
+gs_image_set_from_pixbuf_with_scale (GtkImage *image, const GdkPixbuf *pixbuf, gint scale)
+{
+ cairo_surface_t *surface;
+ surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
+ gtk_image_set_from_surface (image, surface);
+ cairo_surface_destroy (surface);
+}
+
+/**
+ * gs_image_set_from_pixbuf:
+ **/
+void
+gs_image_set_from_pixbuf (GtkImage *image, const GdkPixbuf *pixbuf)
+{
+ gint scale;
+ scale = gdk_pixbuf_get_width (pixbuf) / 64;
+ gs_image_set_from_pixbuf_with_scale (image, pixbuf, scale);
+}
+
+#if AS_CHECK_VERSION(0,5,12)
+/**
+ * gs_utils_get_content_rating:
+ *
+ * Note: These are strings marked for translation for comment.
+ * This functionality is not currently used.
+ **/
+const gchar *
+gs_utils_get_content_rating (void)
+{
+ struct {
+ const gchar *id;
+ AsContentRatingValue value;
+ const gchar *desc;
+ } content_rating_oars[] = {
+ { "violence-cartoon", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating violence-cartoon", "None") },
+ { "violence-cartoon", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Cartoon characters in unsafe situations") },
+ { "violence-cartoon", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Cartoon characters in aggressive conflict") },
+ { "violence-cartoon", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Graphic violence involving cartoon characters") },
+ { "violence-fantasy", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating violence-fantasy", "None") },
+ { "violence-fantasy", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Characters in unsafe situations easily distinguishable from reality") },
+ { "violence-fantasy", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Characters in aggressive conflict easily distinguishable from reality") },
+ { "violence-fantasy", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Graphic violence easily distinguishable from reality") },
+ { "violence-realistic", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating violence-realistic", "None") },
+ { "violence-realistic", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Mild realistic characters in unsafe situations") },
+ { "violence-realistic", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Depictions of realistic characters in aggressive conflict") },
+ { "violence-realistic", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Graphic violence involving realistic characters") },
+ { "violence-bloodshed", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating violence-bloodshed", "None") },
+ { "violence-bloodshed", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Unrealistic bloodshed") },
+ { "violence-bloodshed", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Realistic bloodshed") },
+ { "violence-bloodshed", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Depictions of bloodshed and the mutilation of body parts") },
+ { "violence-sexual", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating violence-sexual", "None") },
+ { "violence-sexual", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Rape or other violent sexual behavior") },
+ { "drugs-alcohol", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating drugs-alcohol", "None") },
+ { "drugs-alcohol", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("References to alcoholic beverages") },
+ { "drugs-alcohol", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Use of alcoholic beverages") },
+ { "drugs-narcotics", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating drugs-narcotics", "None") },
+ { "drugs-narcotics", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("References to illicit drugs") },
+ { "drugs-narcotics", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Use of illicit drugs") },
+ { "drugs-tobacco", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("References to tobacco products") },
+ { "drugs-tobacco", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Use of tobacco products") },
+ { "sex-nudity", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating sex-nudity", "None") },
+ { "sex-nudity", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Brief artistic nudity") },
+ { "sex-nudity", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Prolonged nudity") },
+ { "sex-themes", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating sex-themes", "None") },
+ { "sex-themes", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Provocative references or depictions") },
+ { "sex-themes", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Sexual references or depictions") },
+ { "sex-themes", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Graphic sexual behavior") },
+ { "language-profanity", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating language-profanity", "None") },
+ { "language-profanity", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Mild or infrequent use of profanity") },
+ { "language-profanity", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Moderate use of profanity") },
+ { "language-profanity", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Strong or frequent use of profanity") },
+ { "language-humor", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating language-humor", "None") },
+ { "language-humor", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Slapstick humor") },
+ { "language-humor", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Vulgar or bathroom humor") },
+ { "language-humor", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Mature or sexual humor") },
+ { "language-discrimination", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating language-discrimination", "None") },
+ { "language-discrimination", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Negativity towards a specific group of people") },
+ { "language-discrimination", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Discrimation designed to cause emotional harm") },
+ { "language-discrimination", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Explicit discrimination based on gender, sexuality, race or religion") },
+ { "money-advertising", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating money-advertising", "None") },
+ { "money-advertising", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Product placement") },
+ { "money-advertising", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Explicit references to specific brands or trademarked products") },
+ { "money-advertising", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Players are encouraged to purchase specific real-world items") },
+ { "money-gambling", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating money-gambling", "None") },
+ { "money-gambling", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Gambling on random events using tokens or credits") },
+ { "money-gambling", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Gambling using \"play\" money") },
+ { "money-gambling", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Gambling using real money") },
+ { "money-purchasing", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating money-purchasing", "None") },
+ { "money-purchasing", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Ability to spend real money in-game") },
+ { "social-chat", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating social-chat", "None") },
+ { "social-chat", AS_CONTENT_RATING_VALUE_MILD,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Player-to-player game interactions without chat functionality") },
+ { "social-chat", AS_CONTENT_RATING_VALUE_MODERATE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Player-to-player preset interactions without chat functionality") },
+ { "social-chat", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Uncontrolled chat functionality between players") },
+ { "social-audio", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating social-audio", "None") },
+ { "social-audio", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Uncontrolled audio or video chat functionality between players") },
+ { "social-contacts", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating social-contacts", "None") },
+ { "social-contacts", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Sharing social network usernames or email addresses") },
+ { "social-info", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating social-info", "None") },
+ { "social-info", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Sharing user information with 3rd parties") },
+ { "social-location", AS_CONTENT_RATING_VALUE_NONE,
+ /* TRANSLATORS: content rating description */
+ C_("content rating social-location", "None") },
+ { "social-location", AS_CONTENT_RATING_VALUE_INTENSE,
+ /* TRANSLATORS: content rating description: comments welcome */
+ _("Sharing physical location to other users") },
+ { NULL, 0, NULL } };
+ return content_rating_oars[0].desc;
+}
+#endif
+
+/**
+ * gs_utils_is_current_desktop:
+ */
+gboolean
+gs_utils_is_current_desktop (const gchar *name)
+{
+ const gchar *tmp;
+ g_auto(GStrv) names = NULL;
+ tmp = g_getenv ("XDG_CURRENT_DESKTOP");
+ if (tmp == NULL)
+ return FALSE;
+ names = g_strsplit (tmp, ":", -1);
+ return g_strv_contains ((const gchar * const *) names, name);
+}
+
+/**
+ * gs_utils_widget_css_parsing_error_cb:
+ */
+static void
+gs_utils_widget_css_parsing_error_cb (GtkCssProvider *provider,
+ GtkCssSection *section,
+ GError *error,
+ gpointer user_data)
+{
+ g_warning ("CSS parse error %i:%i: %s",
+ gtk_css_section_get_start_line (section),
+ gtk_css_section_get_start_position (section),
+ error->message);
+}
+
+/**
+ * gs_utils_widget_set_custom_css:
+ **/
+void
+gs_utils_widget_set_custom_css (GsApp *app, GtkWidget *widget, const gchar *metadata_css)
+{
+ GPtrArray *key_colors;
+ GString *str = g_string_sized_new (1024);
+ GString *css_str = g_string_new ("");
+ GtkStyleContext *context;
+ const gchar *css;
+ guint i;
+ g_autofree gchar *class_name = NULL;
+ g_autoptr(GtkCssProvider) provider = NULL;
+
+ g_return_if_fail (GS_IS_APP (app));
+
+ /* invalid */
+ css = gs_app_get_metadata_item (app, metadata_css);
+ if (css == NULL)
+ return;
+
+ /* replace any key colors */
+ css_str = g_string_new (css);
+ key_colors = gs_app_get_key_colors (app);
+ for (i = 0; i < key_colors->len; i++) {
+ GdkRGBA *color = g_ptr_array_index (key_colors, 1);
+ g_autofree gchar *key = NULL;
+ g_autofree gchar *value = NULL;
+ key = g_strdup_printf ("@keycolor-%02i@", i);
+ value = g_strdup_printf ("rgb(%.0f,%.0f,%.0f)",
+ color->red,
+ color->green,
+ color->blue);
+ as_utils_string_replace (css_str, key, value);
+ }
+
+ /* make into a proper CSS class */
+ class_name = g_strdup_printf ("themed-widget_%p", widget);
+ g_string_append_printf (str, ".%s {\n", class_name);
+ g_string_append_printf (str, "%s\n", css_str->str);
+ g_string_append (str, "}");
+
+ g_string_append_printf (str, ".%s:hover {\n", class_name);
+ g_string_append (str, " opacity: 0.9;\n");
+ g_string_append (str, "}\n");
+
+ g_debug ("using custom CSS %s", str->str);
+
+ /* set the custom CSS class */
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_add_class (context, class_name);
+
+ /* set up custom provider and store on the widget */
+ provider = gtk_css_provider_new ();
+ g_signal_connect (provider, "parsing-error",
+ G_CALLBACK (gs_utils_widget_css_parsing_error_cb), NULL);
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ GTK_STYLE_PROVIDER (provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ gtk_css_provider_load_from_data (provider, str->str, -1, NULL);
+ g_object_set_data_full (G_OBJECT (widget),
+ "GnomeSoftware::provider",
+ g_object_ref (provider),
+ g_object_unref);
+}
+
+const gchar *
+gs_user_agent (void)
+{
+ return PACKAGE_NAME "/" PACKAGE_VERSION;
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-common.h b/src/gs-common.h
new file mode 100644
index 0000000..6e7ea92
--- /dev/null
+++ b/src/gs-common.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef __GS_COMMON_H
+#define __GS_COMMON_H
+
+#include <gio/gdesktopappinfo.h>
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+void gs_start_spinner (GtkSpinner *spinner);
+void gs_stop_spinner (GtkSpinner *spinner);
+void gs_container_remove_all (GtkContainer *container);
+void gs_grab_focus_when_mapped (GtkWidget *widget);
+
+void gs_app_notify_installed (GsApp *app);
+void gs_app_notify_failed_modal (GsApp *app,
+ GtkWindow *parent_window,
+ GsPluginLoaderAction action,
+ const GError *error);
+GtkResponseType
+ gs_app_notify_unavailable (GsApp *app,
+ GtkWindow *parent);
+void gs_app_show_url (GsApp *app,
+ AsUrlKind kind);
+
+void gs_image_set_from_pixbuf_with_scale (GtkImage *image,
+ const GdkPixbuf *pixbuf,
+ gint scale);
+void gs_image_set_from_pixbuf (GtkImage *image,
+ const GdkPixbuf *pixbuf);
+
+#if AS_CHECK_VERSION(0,5,12)
+const gchar *gs_utils_get_content_rating (void);
+#endif
+
+const gchar *gs_user_agent (void);
+gboolean gs_utils_is_current_desktop (const gchar *name);
+void gs_utils_widget_set_custom_css (GsApp *app,
+ GtkWidget *widget,
+ const gchar *metadata_css);
+gboolean gs_utils_strv_fnmatch (gchar **strv,
+ const gchar *str);
+
+G_END_DECLS
+
+#endif /* __GS_COMMON_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-feature-tile.c b/src/gs-feature-tile.c
index 77a122c..cba49e4 100644
--- a/src/gs-feature-tile.c
+++ b/src/gs-feature-tile.c
@@ -25,7 +25,7 @@
#include <gtk/gtk.h>
#include "gs-feature-tile.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsFeatureTile
{
diff --git a/src/gs-history-dialog.c b/src/gs-history-dialog.c
index 194c1e6..287dbd1 100644
--- a/src/gs-history-dialog.c
+++ b/src/gs-history-dialog.c
@@ -26,7 +26,7 @@
#include <gtk/gtk.h>
#include "gs-history-dialog.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsHistoryDialog
{
diff --git a/src/gs-page.c b/src/gs-page.c
index 5e8d2dc..49e4e30 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -27,7 +27,7 @@
#include "gs-app.h"
#include "gs-page.h"
#include "gs-shell.h"
-#include "gs-utils.h"
+#include "gs-common.h"
typedef struct
{
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 7b8f2c2..d96ba25 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -28,7 +28,7 @@
#include "gs-plugin-loader.h"
#include "gs-plugin.h"
#include "gs-plugin-private.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#define GS_PLUGIN_LOADER_UPDATES_CHANGED_DELAY 3 /* s */
diff --git a/src/gs-popular-tile.c b/src/gs-popular-tile.c
index 2fcdb24..cec0bc9 100644
--- a/src/gs-popular-tile.c
+++ b/src/gs-popular-tile.c
@@ -26,7 +26,7 @@
#include "gs-popular-tile.h"
#include "gs-star-widget.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsPopularTile
{
diff --git a/src/gs-screenshot-image.c b/src/gs-screenshot-image.c
index 5966645..8d17636 100644
--- a/src/gs-screenshot-image.c
+++ b/src/gs-screenshot-image.c
@@ -24,13 +24,14 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
+#include <gnome-software.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-bg.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include "gs-screenshot-image.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsScreenshotImage
{
diff --git a/src/gs-shell-category.c b/src/gs-shell-category.c
index bc3e445..b6ca31e 100644
--- a/src/gs-shell-category.c
+++ b/src/gs-shell-category.c
@@ -25,7 +25,7 @@
#include <string.h>
#include <glib/gi18n.h>
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-app-tile.h"
#include "gs-shell-category.h"
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 945982f..4c9cc82 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -24,9 +24,9 @@
#include <string.h>
#include <glib/gi18n.h>
-#include <appstream-glib.h>
+#include <gnome-software.h>
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-shell-details.h"
#include "gs-app-addon-row.h"
diff --git a/src/gs-shell-extras.c b/src/gs-shell-extras.c
index 9c36dce..0c8b576 100644
--- a/src/gs-shell-extras.c
+++ b/src/gs-shell-extras.c
@@ -27,7 +27,7 @@
#include "gs-app-row.h"
#include "gs-language.h"
#include "gs-shell.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-vendor.h"
#include <glib/gi18n.h>
diff --git a/src/gs-shell-installed.c b/src/gs-shell-installed.c
index 39a2e81..8016370 100644
--- a/src/gs-shell-installed.c
+++ b/src/gs-shell-installed.c
@@ -29,7 +29,7 @@
#include "gs-shell.h"
#include "gs-shell-installed.h"
#include "gs-app.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-app-row.h"
#include "gs-app-folder-dialog.h"
#include "gs-folders.h"
diff --git a/src/gs-shell-moderate.c b/src/gs-shell-moderate.c
index 414b704..227f23f 100644
--- a/src/gs-shell-moderate.c
+++ b/src/gs-shell-moderate.c
@@ -30,7 +30,7 @@
#include "gs-review-row.h"
#include "gs-shell.h"
#include "gs-shell-moderate.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsShellModerate
{
diff --git a/src/gs-shell-overview.c b/src/gs-shell-overview.c
index bd35014..2f91112 100644
--- a/src/gs-shell-overview.c
+++ b/src/gs-shell-overview.c
@@ -30,7 +30,7 @@
#include "gs-popular-tile.h"
#include "gs-feature-tile.h"
#include "gs-category-tile.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#define N_TILES 8
diff --git a/src/gs-shell-search.c b/src/gs-shell-search.c
index a3ef887..0d2d3cb 100644
--- a/src/gs-shell-search.c
+++ b/src/gs-shell-search.c
@@ -27,7 +27,7 @@
#include "gs-shell-search.h"
#include "gs-shell.h"
#include "gs-app.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-app-row.h"
struct _GsShellSearch
diff --git a/src/gs-shell-updates.c b/src/gs-shell-updates.c
index 80cc6cc..d1a8c09 100644
--- a/src/gs-shell-updates.c
+++ b/src/gs-shell-updates.c
@@ -26,7 +26,7 @@
#include "gs-shell.h"
#include "gs-shell-updates.h"
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-app.h"
#include "gs-app-row.h"
#include "gs-update-dialog.h"
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 474401b..09b1b07 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -25,7 +25,7 @@
#include <string.h>
#include <glib/gi18n.h>
-#include "gs-utils.h"
+#include "gs-common.h"
#include "gs-shell.h"
#include "gs-shell-details.h"
#include "gs-shell-installed.h"
diff --git a/src/gs-sources-dialog.c b/src/gs-sources-dialog.c
index b78dd81..adc71c4 100644
--- a/src/gs-sources-dialog.c
+++ b/src/gs-sources-dialog.c
@@ -28,7 +28,7 @@
#include "gs-sources-dialog.h"
#include "gs-os-release.h"
#include "gs-sources-dialog-row.h"
-#include "gs-utils.h"
+#include "gs-common.h"
struct _GsSourcesDialog
{
diff --git a/src/gs-update-dialog.c b/src/gs-update-dialog.c
index 45bae7d..3f75cb9 100644
--- a/src/gs-update-dialog.c
+++ b/src/gs-update-dialog.c
@@ -27,7 +27,7 @@
#include "gs-update-dialog.h"
#include "gs-app-row.h"
#include "gs-update-list.h"
-#include "gs-utils.h"
+#include "gs-common.h"
typedef struct {
gchar *title;
diff --git a/src/gs-upgrade-banner.c b/src/gs-upgrade-banner.c
index 5772352..699c6a9 100644
--- a/src/gs-upgrade-banner.c
+++ b/src/gs-upgrade-banner.c
@@ -27,7 +27,7 @@
#include <stdlib.h>
#include "gs-upgrade-banner.h"
-#include "gs-utils.h"
+#include "gs-common.h"
typedef struct
{
diff --git a/src/gs-utils.c b/src/gs-utils.c
index 977f183..3b4200f 100644
--- a/src/gs-utils.c
+++ b/src/gs-utils.c
@@ -21,8 +21,6 @@
#include "config.h"
-#include <glib/gi18n.h>
-#include <gio/gdesktopappinfo.h>
#include <errno.h>
#include <fnmatch.h>
@@ -34,376 +32,6 @@
#include "gs-utils.h"
#include "gs-plugin.h"
-#define SPINNER_DELAY 500
-
-static gboolean
-fade_in (gpointer data)
-{
- GtkWidget *spinner = data;
- gdouble opacity;
-
- opacity = gtk_widget_get_opacity (spinner);
- opacity = opacity + 0.1;
- gtk_widget_set_opacity (spinner, opacity);
-
- if (opacity >= 1.0) {
- g_object_steal_data (G_OBJECT (spinner), "fade-timeout");
- return G_SOURCE_REMOVE;
- }
- return G_SOURCE_CONTINUE;
-}
-
-static void
-remove_source (gpointer data)
-{
- g_source_remove (GPOINTER_TO_UINT (data));
-}
-
-static gboolean
-start_spinning (gpointer data)
-{
- GtkWidget *spinner = data;
- guint id;
-
- gtk_widget_set_opacity (spinner, 0);
- gtk_spinner_start (GTK_SPINNER (spinner));
- id = g_timeout_add (100, fade_in, spinner);
- g_object_set_data_full (G_OBJECT (spinner), "fade-timeout",
- GUINT_TO_POINTER (id), remove_source);
-
- /* don't try to remove this source in the future */
- g_object_steal_data (G_OBJECT (spinner), "start-timeout");
- return G_SOURCE_REMOVE;
-}
-
-void
-gs_stop_spinner (GtkSpinner *spinner)
-{
- g_object_set_data (G_OBJECT (spinner), "start-timeout", NULL);
- gtk_spinner_stop (spinner);
-}
-
-void
-gs_start_spinner (GtkSpinner *spinner)
-{
- gboolean active;
- guint id;
-
- /* Don't do anything if it's already spinning */
- g_object_get (spinner, "active", &active, NULL);
- if (active || g_object_get_data (G_OBJECT (spinner), "start-timeout") != NULL)
- return;
-
- gtk_widget_set_opacity (GTK_WIDGET (spinner), 0);
- id = g_timeout_add (SPINNER_DELAY, start_spinning, spinner);
- g_object_set_data_full (G_OBJECT (spinner), "start-timeout",
- GUINT_TO_POINTER (id), remove_source);
-}
-
-static void
-remove_all_cb (GtkWidget *widget, gpointer user_data)
-{
- GtkContainer *container = GTK_CONTAINER (user_data);
- gtk_container_remove (container, widget);
-}
-
-void
-gs_container_remove_all (GtkContainer *container)
-{
- gtk_container_foreach (container, remove_all_cb, container);
-}
-
-static void
-grab_focus (GtkWidget *widget)
-{
- g_signal_handlers_disconnect_by_func (widget, grab_focus, NULL);
- gtk_widget_grab_focus (widget);
-}
-
-void
-gs_grab_focus_when_mapped (GtkWidget *widget)
-{
- if (gtk_widget_get_mapped (widget))
- gtk_widget_grab_focus (widget);
- else
- g_signal_connect_after (widget, "map",
- G_CALLBACK (grab_focus), NULL);
-}
-
-void
-gs_app_notify_installed (GsApp *app)
-{
- g_autofree gchar *summary = NULL;
- g_autoptr(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_kind (app) == AS_APP_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);
-}
-
-/**
- * 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;
- gboolean show_detailed_error;
- g_autoptr(GString) msg = NULL;
-
- /* TRANSLATORS: install or removed failed */
- title = _("Sorry, this did not work");
-
- /* say what we tried to do */
- msg = g_string_new ("");
- switch (action) {
- case GS_PLUGIN_LOADER_ACTION_INSTALL:
- /* TRANSLATORS: this is when the install fails */
- g_string_append_printf (msg, _("Installation of %s failed."),
- gs_app_get_name (app));
- break;
- case GS_PLUGIN_LOADER_ACTION_REMOVE:
- /* TRANSLATORS: this is when the remove fails */
- g_string_append_printf (msg, _("Removal of %s failed."),
- gs_app_get_name (app));
- break;
- case GS_PLUGIN_LOADER_ACTION_UPGRADE_DOWNLOAD:
- /* TRANSLATORS: this is when the upgrade download fails */
- g_string_append_printf (msg, _("Upgrade to %s failed."),
- gs_app_get_name (app));
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- g_string_append (msg, " ");
-
- /* give details about the error */
- switch (error->code) {
- case GS_PLUGIN_ERROR_NO_NETWORK:
- /* TRANSLATORS: the package manager needed to download
- * something with no network available */
- g_string_append (msg, _("Internet access was required but wasn’t available."));
- g_string_append (msg, " ");
- /* TRANSLATORS: plug in the network cable... */
- g_string_append (msg, _("Please make sure that you have internet access and try again."));
- show_detailed_error = FALSE;
- break;
- case GS_PLUGIN_ERROR_NO_SPACE:
- /* TRANSLATORS: we ran out of disk space */
- g_string_append (msg, _("There wasn’t enough disk space."));
- g_string_append (msg, " ");
- /* TRANSLATORS: delete some stuff! */
- g_string_append (msg, _("Please free up some space and try again."));
- show_detailed_error = FALSE;
- break;
- default:
- /* TRANSLATORS: we didn't handle the error type */
- g_string_append (msg, _("If the problem persists, contact your software provider."));
- show_detailed_error = TRUE;
- }
-
- dialog = gtk_message_dialog_new (parent_window,
- GTK_DIALOG_MODAL |
- GTK_DIALOG_USE_HEADER_BAR |
- 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->str);
-
- /* detailed error in an expander */
- if (show_detailed_error) {
- GtkWidget *vbox;
- GtkWidget *expander;
- GtkWidget *scrolled_window;
- GtkWidget *label;
-
- vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
- /* TRANSLATORS: this is an expander title */
- expander = gtk_expander_new (_("Show Details"));
- gtk_widget_set_margin_start (expander, 36);
- gtk_widget_set_margin_end (expander, 36);
- scrolled_window = gtk_scrolled_window_new (NULL, NULL);
- gtk_container_add (GTK_CONTAINER (expander), scrolled_window);
- label = gtk_label_new (error->message);
- gtk_label_set_selectable (GTK_LABEL (label), TRUE);
- gtk_container_add (GTK_CONTAINER (scrolled_window), label);
- gtk_box_pack_end (GTK_BOX (vbox), expander, FALSE, TRUE, 4);
- gtk_widget_show_all (expander);
-
- }
-
- g_signal_connect (dialog, "response",
- G_CALLBACK (gtk_widget_destroy), NULL);
- gtk_window_present (GTK_WINDOW (dialog));
-}
-
-typedef enum {
- GS_APP_LICENSE_FREE = 0,
- GS_APP_LICENSE_NONFREE = 1,
- GS_APP_LICENSE_PATENT_CONCERN = 2
-} GsAppLicenseHint;
-
-/**
- * gs_app_notify_unavailable:
- **/
-GtkResponseType
-gs_app_notify_unavailable (GsApp *app, GtkWindow *parent)
-{
- GsAppLicenseHint hint = GS_APP_LICENSE_FREE;
- GtkResponseType response;
- GtkWidget *dialog;
- const gchar *license;
- gboolean already_enabled = FALSE; /* FIXME */
- guint i;
- struct {
- const gchar *str;
- GsAppLicenseHint hint;
- } keywords[] = {
- { "NonFree", GS_APP_LICENSE_NONFREE },
- { "PatentConcern", GS_APP_LICENSE_PATENT_CONCERN },
- { "Proprietary", GS_APP_LICENSE_NONFREE },
- { NULL, 0 }
- };
- g_autofree gchar *origin_url = NULL;
- g_autoptr(GSettings) settings = NULL;
- g_autoptr(GString) body = NULL;
- g_autoptr(GString) title = NULL;
-
- /* this is very crude */
- license = gs_app_get_license (app);
- if (license != NULL) {
- for (i = 0; keywords[i].str != NULL; i++) {
- if (g_strstr_len (license, -1, keywords[i].str) != NULL)
- hint |= keywords[i].hint;
- }
- } else {
- /* use the worst-case assumption */
- hint = GS_APP_LICENSE_NONFREE | GS_APP_LICENSE_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_LICENSE_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_LICENSE_PATENT_CONCERN) {
- g_string_append (body, "\n\n");
- if (gs_app_get_kind (app) != AS_APP_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;
-}
-
-void
-gs_app_show_url (GsApp *app, AsUrlKind kind)
-{
- const gchar *url;
- g_autoptr(GError) error = NULL;
-
- url = gs_app_get_url (app, kind);
- if (!gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error))
- g_warning ("spawn of '%s' failed", url);
-}
-
/**
* gs_mkdir_parent:
**/
@@ -425,29 +53,6 @@ gs_mkdir_parent (const gchar *path, GError **error)
}
/**
- * gs_image_set_from_pixbuf_with_scale:
- **/
-void
-gs_image_set_from_pixbuf_with_scale (GtkImage *image, const GdkPixbuf *pixbuf, gint scale)
-{
- cairo_surface_t *surface;
- surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
- gtk_image_set_from_surface (image, surface);
- cairo_surface_destroy (surface);
-}
-
-/**
- * gs_image_set_from_pixbuf:
- **/
-void
-gs_image_set_from_pixbuf (GtkImage *image, const GdkPixbuf *pixbuf)
-{
- gint scale;
- scale = gdk_pixbuf_get_width (pixbuf) / 64;
- gs_image_set_from_pixbuf_with_scale (image, pixbuf, scale);
-}
-
-/**
* gs_utils_get_file_age:
*
* Returns: The time in seconds since the file was modified
@@ -473,12 +78,6 @@ gs_utils_get_file_age (GFile *file)
return now - mtime;
}
-const gchar *
-gs_user_agent (void)
-{
- return PACKAGE_NAME "/" PACKAGE_VERSION;
-}
-
/**
* gs_utils_get_cache_filename:
*
@@ -588,227 +187,6 @@ gs_utils_get_permission (const gchar *id)
#endif
}
-#if AS_CHECK_VERSION(0,5,12)
-/**
- * gs_utils_get_content_rating:
- *
- * Note: These are strings marked for translation for comment.
- * This functionality is not currently used.
- **/
-const gchar *
-gs_utils_get_content_rating (void)
-{
- struct {
- const gchar *id;
- AsContentRatingValue value;
- const gchar *desc;
- } content_rating_oars[] = {
- { "violence-cartoon", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating violence-cartoon", "None") },
- { "violence-cartoon", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Cartoon characters in unsafe situations") },
- { "violence-cartoon", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Cartoon characters in aggressive conflict") },
- { "violence-cartoon", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Graphic violence involving cartoon characters") },
- { "violence-fantasy", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating violence-fantasy", "None") },
- { "violence-fantasy", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Characters in unsafe situations easily distinguishable from reality") },
- { "violence-fantasy", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Characters in aggressive conflict easily distinguishable from reality") },
- { "violence-fantasy", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Graphic violence easily distinguishable from reality") },
- { "violence-realistic", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating violence-realistic", "None") },
- { "violence-realistic", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Mild realistic characters in unsafe situations") },
- { "violence-realistic", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Depictions of realistic characters in aggressive conflict") },
- { "violence-realistic", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Graphic violence involving realistic characters") },
- { "violence-bloodshed", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating violence-bloodshed", "None") },
- { "violence-bloodshed", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Unrealistic bloodshed") },
- { "violence-bloodshed", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Realistic bloodshed") },
- { "violence-bloodshed", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Depictions of bloodshed and the mutilation of body parts") },
- { "violence-sexual", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating violence-sexual", "None") },
- { "violence-sexual", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Rape or other violent sexual behavior") },
- { "drugs-alcohol", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating drugs-alcohol", "None") },
- { "drugs-alcohol", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("References to alcoholic beverages") },
- { "drugs-alcohol", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Use of alcoholic beverages") },
- { "drugs-narcotics", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating drugs-narcotics", "None") },
- { "drugs-narcotics", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("References to illicit drugs") },
- { "drugs-narcotics", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Use of illicit drugs") },
- { "drugs-tobacco", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("References to tobacco products") },
- { "drugs-tobacco", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Use of tobacco products") },
- { "sex-nudity", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating sex-nudity", "None") },
- { "sex-nudity", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Brief artistic nudity") },
- { "sex-nudity", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Prolonged nudity") },
- { "sex-themes", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating sex-themes", "None") },
- { "sex-themes", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Provocative references or depictions") },
- { "sex-themes", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Sexual references or depictions") },
- { "sex-themes", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Graphic sexual behavior") },
- { "language-profanity", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating language-profanity", "None") },
- { "language-profanity", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Mild or infrequent use of profanity") },
- { "language-profanity", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Moderate use of profanity") },
- { "language-profanity", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Strong or frequent use of profanity") },
- { "language-humor", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating language-humor", "None") },
- { "language-humor", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Slapstick humor") },
- { "language-humor", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Vulgar or bathroom humor") },
- { "language-humor", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Mature or sexual humor") },
- { "language-discrimination", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating language-discrimination", "None") },
- { "language-discrimination", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Negativity towards a specific group of people") },
- { "language-discrimination", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Discrimation designed to cause emotional harm") },
- { "language-discrimination", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Explicit discrimination based on gender, sexuality, race or religion") },
- { "money-advertising", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating money-advertising", "None") },
- { "money-advertising", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Product placement") },
- { "money-advertising", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Explicit references to specific brands or trademarked products") },
- { "money-advertising", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Players are encouraged to purchase specific real-world items") },
- { "money-gambling", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating money-gambling", "None") },
- { "money-gambling", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Gambling on random events using tokens or credits") },
- { "money-gambling", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Gambling using \"play\" money") },
- { "money-gambling", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Gambling using real money") },
- { "money-purchasing", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating money-purchasing", "None") },
- { "money-purchasing", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Ability to spend real money in-game") },
- { "social-chat", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating social-chat", "None") },
- { "social-chat", AS_CONTENT_RATING_VALUE_MILD,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Player-to-player game interactions without chat functionality") },
- { "social-chat", AS_CONTENT_RATING_VALUE_MODERATE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Player-to-player preset interactions without chat functionality") },
- { "social-chat", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Uncontrolled chat functionality between players") },
- { "social-audio", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating social-audio", "None") },
- { "social-audio", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Uncontrolled audio or video chat functionality between players") },
- { "social-contacts", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating social-contacts", "None") },
- { "social-contacts", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Sharing social network usernames or email addresses") },
- { "social-info", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating social-info", "None") },
- { "social-info", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Sharing user information with 3rd parties") },
- { "social-location", AS_CONTENT_RATING_VALUE_NONE,
- /* TRANSLATORS: content rating description */
- C_("content rating social-location", "None") },
- { "social-location", AS_CONTENT_RATING_VALUE_INTENSE,
- /* TRANSLATORS: content rating description: comments welcome */
- _("Sharing physical location to other users") },
- { NULL, 0, NULL } };
- return content_rating_oars[0].desc;
-}
-#endif
-
/**
* gs_utils_get_content_type:
*/
@@ -835,103 +213,6 @@ gs_utils_get_content_type (GFile *file,
}
/**
- * gs_utils_is_current_desktop:
- */
-gboolean
-gs_utils_is_current_desktop (const gchar *name)
-{
- const gchar *tmp;
- g_auto(GStrv) names = NULL;
- tmp = g_getenv ("XDG_CURRENT_DESKTOP");
- if (tmp == NULL)
- return FALSE;
- names = g_strsplit (tmp, ":", -1);
- return g_strv_contains ((const gchar * const *) names, name);
-}
-
-/**
- * gs_utils_widget_css_parsing_error_cb:
- */
-static void
-gs_utils_widget_css_parsing_error_cb (GtkCssProvider *provider,
- GtkCssSection *section,
- GError *error,
- gpointer user_data)
-{
- g_warning ("CSS parse error %i:%i: %s",
- gtk_css_section_get_start_line (section),
- gtk_css_section_get_start_position (section),
- error->message);
-}
-
-/**
- * gs_utils_widget_set_custom_css:
- **/
-void
-gs_utils_widget_set_custom_css (GsApp *app, GtkWidget *widget, const gchar *metadata_css)
-{
- GPtrArray *key_colors;
- GString *str = g_string_sized_new (1024);
- GString *css_str = g_string_new ("");
- GtkStyleContext *context;
- const gchar *css;
- guint i;
- g_autofree gchar *class_name = NULL;
- g_autoptr(GtkCssProvider) provider = NULL;
-
- g_return_if_fail (GS_IS_APP (app));
-
- /* invalid */
- css = gs_app_get_metadata_item (app, metadata_css);
- if (css == NULL)
- return;
-
- /* replace any key colors */
- css_str = g_string_new (css);
- key_colors = gs_app_get_key_colors (app);
- for (i = 0; i < key_colors->len; i++) {
- GdkRGBA *color = g_ptr_array_index (key_colors, 1);
- g_autofree gchar *key = NULL;
- g_autofree gchar *value = NULL;
- key = g_strdup_printf ("@keycolor-%02i@", i);
- value = g_strdup_printf ("rgb(%.0f,%.0f,%.0f)",
- color->red,
- color->green,
- color->blue);
- as_utils_string_replace (css_str, key, value);
- }
-
- /* make into a proper CSS class */
- class_name = g_strdup_printf ("themed-widget_%p", widget);
- g_string_append_printf (str, ".%s {\n", class_name);
- g_string_append_printf (str, "%s\n", css_str->str);
- g_string_append (str, "}");
-
- g_string_append_printf (str, ".%s:hover {\n", class_name);
- g_string_append (str, " opacity: 0.9;\n");
- g_string_append (str, "}\n");
-
- g_debug ("using custom CSS %s", str->str);
-
- /* set the custom CSS class */
- context = gtk_widget_get_style_context (widget);
- gtk_style_context_add_class (context, class_name);
-
- /* set up custom provider and store on the widget */
- provider = gtk_css_provider_new ();
- g_signal_connect (provider, "parsing-error",
- G_CALLBACK (gs_utils_widget_css_parsing_error_cb), NULL);
- gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
- GTK_STYLE_PROVIDER (provider),
- GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- gtk_css_provider_load_from_data (provider, str->str, -1, NULL);
- g_object_set_data_full (G_OBJECT (widget),
- "GnomeSoftware::provider",
- g_object_ref (provider),
- g_object_unref);
-}
-
-/**
* gs_utils_strv_fnmatch:
*/
gboolean
diff --git a/src/gs-utils.h b/src/gs-utils.h
index 828a90b..9596006 100644
--- a/src/gs-utils.h
+++ b/src/gs-utils.h
@@ -26,7 +26,6 @@
#include <gtk/gtk.h>
#include "gs-app.h"
-#include "gs-plugin-loader.h"
G_BEGIN_DECLS
@@ -36,54 +35,20 @@ typedef enum {
GS_UTILS_CACHE_FLAG_LAST
} GsUtilsCacheFlags;
-void gs_start_spinner (GtkSpinner *spinner);
-void gs_stop_spinner (GtkSpinner *spinner);
-void gs_container_remove_all (GtkContainer *container);
-void gs_grab_focus_when_mapped (GtkWidget *widget);
-
-guint gs_utils_get_file_age (GFile *file);
-gchar *gs_utils_get_content_type (GFile *file,
- GCancellable *cancellable,
- GError **error);
-
-void gs_app_notify_installed (GsApp *app);
-void gs_app_notify_failed_modal (GsApp *app,
- GtkWindow *parent_window,
- GsPluginLoaderAction action,
- const GError *error);
-GtkResponseType
- gs_app_notify_unavailable (GsApp *app,
- GtkWindow *parent);
-void gs_app_show_url (GsApp *app,
- AsUrlKind kind);
-
-gboolean gs_mkdir_parent (const gchar *path,
- GError **error);
-
-void gs_image_set_from_pixbuf_with_scale (GtkImage *image,
- const GdkPixbuf *pixbuf,
- gint scale);
-void gs_image_set_from_pixbuf (GtkImage *image,
- const GdkPixbuf *pixbuf);
-const gchar *gs_user_agent (void);
-
+guint gs_utils_get_file_age (GFile *file);
+gchar *gs_utils_get_content_type (GFile *file,
+ GCancellable *cancellable,
+ GError **error);
+gboolean gs_mkdir_parent (const gchar *path,
+ GError **error);
gchar *gs_utils_get_cache_filename (const gchar *kind,
const gchar *basename,
GsUtilsCacheFlags flags,
GError **error);
gchar *gs_utils_get_user_hash (GError **error);
GPermission *gs_utils_get_permission (const gchar *id);
-#if AS_CHECK_VERSION(0,5,12)
-const gchar *gs_utils_get_content_rating (void);
-#endif
-
-gboolean gs_utils_is_current_desktop (const gchar *name);
-void gs_utils_widget_set_custom_css (GsApp *app,
- GtkWidget *widget,
- const gchar *metadata_css);
gboolean gs_utils_strv_fnmatch (gchar **strv,
const gchar *str);
-
GDesktopAppInfo *gs_utils_get_desktop_app_info (const gchar *id);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]