[gnome-software] Add screenshots to each application if specified in the AppStream metadata



commit ae7544bf74b38141e65d32a8242d279b799a0224
Author: Richard Hughes <richard hughsie com>
Date:   Fri Oct 4 13:22:00 2013 +0100

    Add screenshots to each application if specified in the AppStream metadata

 src/Makefile.am                   |    2 +
 src/gs-app.c                      |   54 ++++------
 src/gs-app.h                      |    8 +-
 src/gs-screenshot.c               |  195 +++++++++++++++++++++++++++++++++++++
 src/gs-screenshot.h               |   68 +++++++++++++
 src/plugins/gs-plugin-appstream.c |   53 ++++++++++
 6 files changed, 345 insertions(+), 35 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 81e4a2e..a45dd21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -59,6 +59,8 @@ gnome_software_SOURCES =                              \
        gs-plugin.h                                     \
        gs-profile.c                                    \
        gs-profile.h                                    \
+       gs-screenshot.c                                 \
+       gs-screenshot.h                                 \
        gs-shell.c                                      \
        gs-shell.h                                      \
        gs-shell-details.c                              \
diff --git a/src/gs-app.c b/src/gs-app.c
index c1f68f5..e23b04d 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -60,7 +60,7 @@ struct GsAppPrivate
        gchar                   *version;
        gchar                   *summary;
        gchar                   *description;
-       gchar                   *screenshot;
+       GPtrArray               *screenshots;
        gchar                   *url;
        gchar                   *update_version;
        gchar                   *update_details;
@@ -84,7 +84,6 @@ enum {
        PROP_SUMMARY,
        PROP_DESCRIPTION,
        PROP_URL,
-       PROP_SCREENSHOT,
        PROP_RATING,
        PROP_KIND,
        PROP_STATE,
@@ -160,11 +159,13 @@ gs_app_state_to_string (GsAppState state)
 gchar *
 gs_app_to_string (GsApp *app)
 {
-       const gchar *tmp;
        GList *keys;
        GList *l;
-       GsAppPrivate *priv = app->priv;
        GString *str;
+       GsAppPrivate *priv = app->priv;
+       GsScreenshot *ss;
+       const gchar *tmp;
+       guint i;
 
        str = g_string_new ("GsApp:\n");
        g_string_append_printf (str, "\tkind:\t%s\n",
@@ -181,8 +182,11 @@ gs_app_to_string (GsApp *app)
                g_string_append_printf (str, "\tsummary:\t%s\n", priv->summary);
        if (priv->description != NULL)
                g_string_append_printf (str, "\tdescription:\t%lu\n", strlen (priv->description));
-       if (priv->screenshot != NULL)
-               g_string_append_printf (str, "\tscreenshot:\t%s\n", priv->screenshot);
+       for (i = 0; i < priv->screenshots->len; i++) {
+               ss = g_ptr_array_index (priv->screenshots, i);
+               g_string_append_printf (str, "\tscreenshot-%02i:\t%s\n",
+                                       i, gs_screenshot_get_url (ss, G_MAXUINT, G_MAXUINT));
+       }
        if (priv->url != NULL)
                g_string_append_printf (str, "\turl:\t%s\n", priv->url);
        if (priv->rating != -1)
@@ -655,24 +659,23 @@ gs_app_set_url (GsApp *app, const gchar *url)
 }
 
 /**
- * gs_app_get_screenshot:
+ * gs_app_add_screenshot:
  */
-const gchar *
-gs_app_get_screenshot (GsApp *app)
+void
+gs_app_add_screenshot (GsApp *app, GsScreenshot *screenshot)
 {
-       g_return_val_if_fail (GS_IS_APP (app), NULL);
-       return app->priv->screenshot;
+       g_return_if_fail (GS_IS_APP (app));
+       g_ptr_array_add (app->priv->screenshots, g_object_ref (screenshot));
 }
 
 /**
- * gs_app_set_screenshot:
+ * gs_app_get_screenshots:
  */
-void
-gs_app_set_screenshot (GsApp *app, const gchar *screenshot)
+GPtrArray *
+gs_app_get_screenshots (GsApp *app)
 {
-       g_return_if_fail (GS_IS_APP (app));
-       g_free (app->priv->screenshot);
-       app->priv->screenshot = g_strdup (screenshot);
+       g_return_val_if_fail (GS_IS_APP (app), NULL);
+       return app->priv->screenshots;
 }
 
 /**
@@ -865,9 +868,6 @@ gs_app_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *
        case PROP_URL:
                g_value_set_string (value, priv->url);
                break;
-       case PROP_SCREENSHOT:
-               g_value_set_string (value, priv->screenshot);
-               break;
        case PROP_RATING:
                g_value_set_uint (value, priv->rating);
                break;
@@ -913,9 +913,6 @@ gs_app_set_property (GObject *object, guint prop_id, const GValue *value, GParam
        case PROP_URL:
                gs_app_set_url (app, g_value_get_string (value));
                break;
-       case PROP_SCREENSHOT:
-               gs_app_set_screenshot (app, g_value_get_string (value));
-               break;
        case PROP_RATING:
                gs_app_set_rating (app, g_value_get_int (value));
                break;
@@ -990,14 +987,6 @@ gs_app_class_init (GsAppClass *klass)
        g_object_class_install_property (object_class, PROP_URL, pspec);
 
        /**
-        * GsApp:screenshot:
-        */
-       pspec = g_param_spec_string ("screenshot", NULL, NULL,
-                                    NULL,
-                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
-       g_object_class_install_property (object_class, PROP_SCREENSHOT, pspec);
-
-       /**
         * GsApp:rating:
         */
        pspec = g_param_spec_int ("rating", NULL, NULL,
@@ -1050,6 +1039,7 @@ gs_app_init (GsApp *app)
        app->priv->rating = -1;
        app->priv->related = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->priv->history = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+       app->priv->screenshots = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
        app->priv->metadata = g_hash_table_new_full (g_str_hash,
                                                     g_str_equal,
                                                     g_free,
@@ -1074,7 +1064,7 @@ gs_app_finalize (GObject *object)
        g_free (priv->version);
        g_free (priv->summary);
        g_free (priv->description);
-       g_free (priv->screenshot);
+       g_ptr_array_unref (priv->screenshots);
        g_free (priv->update_version);
        g_free (priv->update_details);
        g_free (priv->management_plugin);
diff --git a/src/gs-app.h b/src/gs-app.h
index 04f5bd8..24a5587 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -25,6 +25,8 @@
 #include <glib-object.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
+#include "gs-screenshot.h"
+
 G_BEGIN_DECLS
 
 #define GS_TYPE_APP            (gs_app_get_type ())
@@ -113,9 +115,9 @@ void                 gs_app_set_description         (GsApp          *app,
 const gchar    *gs_app_get_url                 (GsApp          *app);
 void            gs_app_set_url                 (GsApp          *app,
                                                 const gchar    *url);
-const gchar    *gs_app_get_screenshot          (GsApp          *app);
-void            gs_app_set_screenshot          (GsApp          *app,
-                                                const gchar    *screenshot);
+GPtrArray      *gs_app_get_screenshots         (GsApp          *app);
+void            gs_app_add_screenshot          (GsApp          *app,
+                                                GsScreenshot   *screenshot);
 const gchar    *gs_app_get_update_version      (GsApp          *app);
 void            gs_app_set_update_version      (GsApp          *app,
                                                 const gchar    *update_version);
diff --git a/src/gs-screenshot.c b/src/gs-screenshot.c
new file mode 100644
index 0000000..989a99f
--- /dev/null
+++ b/src/gs-screenshot.c
@@ -0,0 +1,195 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013 Matthias Clasen <mclasen redhat 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 "gs-screenshot.h"
+
+static void    gs_screenshot_finalize  (GObject        *object);
+
+#define GS_SCREENSHOT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_SCREENSHOT, 
GsScreenshotPrivate))
+
+struct GsScreenshotPrivate
+{
+       GPtrArray               *array;
+       gboolean                 is_default;
+};
+
+typedef struct {
+       gchar                   *url;
+       guint                    width;
+       guint                    height;
+} GsScreenshotItem;
+
+G_DEFINE_TYPE (GsScreenshot, gs_screenshot, G_TYPE_OBJECT)
+
+/**
+ * gs_screenshot_item_free:
+ **/
+static void
+gs_screenshot_item_free (GsScreenshotItem *item)
+{
+       g_free (item->url);
+       g_slice_free (GsScreenshotItem, item);
+}
+
+/**
+ * gs_screenshot_get_is_default:
+ **/
+gboolean
+gs_screenshot_get_is_default (GsScreenshot *screenshot)
+{
+       g_return_val_if_fail (GS_IS_SCREENSHOT (screenshot), FALSE);
+       return screenshot->priv->is_default;
+}
+
+/**
+ * gs_screenshot_set_is_default:
+ **/
+void
+gs_screenshot_set_is_default (GsScreenshot *screenshot, gboolean is_default)
+{
+       g_return_if_fail (GS_IS_SCREENSHOT (screenshot));
+       screenshot->priv->is_default = is_default;
+}
+
+/**
+ * gs_screenshot_get_item:
+ **/
+static GsScreenshotItem *
+gs_screenshot_get_item (GsScreenshot *screenshot, guint width, guint height)
+{
+       GsScreenshotItem *item;
+       guint i;
+
+       g_return_val_if_fail (GS_IS_SCREENSHOT (screenshot), NULL);
+
+       for (i = 0; i < screenshot->priv->array->len; i++) {
+               item = g_ptr_array_index (screenshot->priv->array, i);
+               if ((item->width == width || width == G_MAXUINT) &&
+                   (item->height == height || height == G_MAXUINT))
+                       return item;
+       }
+
+       return NULL;
+}
+
+/**
+ * gs_screenshot_add_image:
+ **/
+void
+gs_screenshot_add_image (GsScreenshot *screenshot,
+                        const gchar *url,
+                        guint width,
+                        guint height)
+{
+       GsScreenshotItem *item;
+
+       g_return_if_fail (GS_IS_SCREENSHOT (screenshot));
+       g_return_if_fail (url != NULL);
+       g_return_if_fail (width > 0);
+       g_return_if_fail (height > 0);
+
+       /* check if already exists */
+       item = gs_screenshot_get_item (screenshot, width, height);
+       if (item != NULL) {
+               g_warning ("replaced URL %s with %s for %ux%u",
+                          item->url, url, width, height);
+               g_free (item->url);
+               item->url = g_strdup (url);
+       } else {
+               item = g_slice_new0 (GsScreenshotItem);
+               item->url = g_strdup (url);
+               item->width = width;
+               item->height = height;
+               g_ptr_array_add (screenshot->priv->array, item);
+       }
+}
+
+/**
+ * gs_screenshot_get_url:
+ **/
+const gchar *
+gs_screenshot_get_url (GsScreenshot *screenshot, guint width, guint height)
+{
+       GsScreenshotItem *item;
+
+       g_return_val_if_fail (GS_IS_SCREENSHOT (screenshot), NULL);
+       g_return_val_if_fail (width > 0, NULL);
+       g_return_val_if_fail (height > 0, NULL);
+
+       item = gs_screenshot_get_item (screenshot, width, height);
+       if (item == NULL)
+               return NULL;
+
+       return item->url;
+}
+
+/**
+ * gs_screenshot_class_init:
+ **/
+static void
+gs_screenshot_class_init (GsScreenshotClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       object_class->finalize = gs_screenshot_finalize;
+       g_type_class_add_private (klass, sizeof (GsScreenshotPrivate));
+}
+
+/**
+ * gs_screenshot_init:
+ **/
+static void
+gs_screenshot_init (GsScreenshot *screenshot)
+{
+       screenshot->priv = GS_SCREENSHOT_GET_PRIVATE (screenshot);
+       screenshot->priv->array = g_ptr_array_new_with_free_func ((GDestroyNotify) gs_screenshot_item_free);
+}
+
+/**
+ * gs_screenshot_finalize:
+ **/
+static void
+gs_screenshot_finalize (GObject *object)
+{
+       GsScreenshot *screenshot = GS_SCREENSHOT (object);
+       GsScreenshotPrivate *priv = screenshot->priv;
+
+       g_ptr_array_unref (priv->array);
+
+       G_OBJECT_CLASS (gs_screenshot_parent_class)->finalize (object);
+}
+
+/**
+ * gs_screenshot_new:
+ **/
+GsScreenshot *
+gs_screenshot_new (void)
+{
+       GsScreenshot *screenshot;
+       screenshot = g_object_new (GS_TYPE_SCREENSHOT, NULL);
+       return GS_SCREENSHOT (screenshot);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-screenshot.h b/src/gs-screenshot.h
new file mode 100644
index 0000000..f253f62
--- /dev/null
+++ b/src/gs-screenshot.h
@@ -0,0 +1,68 @@
+/* -*- 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_SCREENSHOT_H
+#define __GS_SCREENSHOT_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SCREENSHOT             (gs_screenshot_get_type ())
+#define GS_SCREENSHOT(o)               (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SCREENSHOT, GsScreenshot))
+#define GS_SCREENSHOT_CLASS(k)         (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_SCREENSHOT, GsScreenshotClass))
+#define GS_IS_SCREENSHOT(o)            (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SCREENSHOT))
+#define GS_IS_SCREENSHOT_CLASS(k)      (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_SCREENSHOT))
+#define GS_SCREENSHOT_GET_CLASS(o)     (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_SCREENSHOT, 
GsScreenshotClass))
+
+typedef struct GsScreenshotPrivate GsScreenshotPrivate;
+
+typedef struct
+{
+        GObject                 parent;
+        GsScreenshotPrivate    *priv;
+} GsScreenshot;
+
+typedef struct
+{
+       GObjectClass             parent_class;
+} GsScreenshotClass;
+
+GType           gs_screenshot_get_type         (void);
+
+GsScreenshot   *gs_screenshot_new              (void);
+
+gboolean        gs_screenshot_get_is_default   (GsScreenshot           *screenshot);
+void            gs_screenshot_set_is_default   (GsScreenshot           *screenshot,
+                                                gboolean                is_default);
+void            gs_screenshot_add_image        (GsScreenshot           *screenshot,
+                                                const gchar            *url,
+                                                guint                   width,
+                                                guint                   height);
+const gchar    *gs_screenshot_get_url          (GsScreenshot           *screenshot,
+                                                guint                   width,
+                                                guint                   height);
+
+G_END_DECLS
+
+#endif /* __GS_SCREENSHOT_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index b51c5c8..a1e5b6e 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -364,6 +364,56 @@ gs_plugin_refine_item_pixbuf (GsPlugin *plugin, GsApp *app, AppstreamApp *item)
 }
 
 /**
+ * gs_plugin_refine_add_screenshots:
+ */
+static void
+gs_plugin_refine_add_screenshots (GsApp *app, AppstreamApp *item)
+{
+       AppstreamImage *im;
+       AppstreamScreenshot *ss;
+       AppstreamScreenshotKind ss_kind;
+       GPtrArray *images_as;
+       GPtrArray *screenshots_as;
+       GsScreenshot *screenshot;
+       guint i;
+       guint j;
+
+       /* do we have any to add */
+       screenshots_as = appstream_app_get_screenshots (item);
+       if (screenshots_as->len == 0)
+               return;
+
+       /* does the app already have some */
+       if (gs_app_get_screenshots(app)->len > 0)
+               return;
+
+       /* add any we know */
+       for (i = 0; i < screenshots_as->len; i++) {
+               ss = g_ptr_array_index (screenshots_as, i);
+               images_as = appstream_screenshot_get_images (ss);
+               if (images_as->len == 0)
+                       continue;
+               ss_kind = appstream_screenshot_get_kind (ss);
+               if (ss_kind == APPSTREAM_SCREENSHOT_KIND_UNKNOWN)
+                       continue;
+
+               /* create a new application screenshot and add each image */
+               screenshot = gs_screenshot_new ();
+               gs_screenshot_set_is_default (screenshot,
+                                             ss_kind == APPSTREAM_SCREENSHOT_KIND_DEFAULT);
+               for (j = 0; j < images_as->len; j++) {
+                       im = g_ptr_array_index (images_as, j);
+                       gs_screenshot_add_image (screenshot,
+                                                appstream_image_get_url (im),
+                                                appstream_image_get_width (im),
+                                                appstream_image_get_height (im));
+               }
+               gs_app_add_screenshot (app, screenshot);
+               g_object_unref (screenshot);
+       }
+}
+
+/**
  * gs_plugin_refine_item:
  */
 static gboolean
@@ -412,6 +462,9 @@ gs_plugin_refine_item (GsPlugin *plugin,
        if (appstream_app_get_pkgname (item) != NULL && gs_app_get_source (app) == NULL)
                gs_app_set_source (app, appstream_app_get_pkgname (item));
 
+       /* set screenshots */
+       gs_plugin_refine_add_screenshots (app, item);
+
        return ret;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]