summaryrefslogtreecommitdiff
path: root/libappstream-builder/asb-app.c
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2014-06-17 11:52:49 +0100
committerRichard Hughes <richard@hughsie.com>2014-06-17 12:01:32 +0100
commit1284b3fa0addf21070c6d9ce697623a04862cdde (patch)
treea9ecf1b4d984e41e56179ebd6453288dd712843e /libappstream-builder/asb-app.c
parent0ec1dd10ee2281d4f6e102e4e8da8365332540b1 (diff)
downloadappstream-glib-1284b3fa0addf21070c6d9ce697623a04862cdde.tar.gz
Add libappstream-builder from the createrepo_as project
Diffstat (limited to 'libappstream-builder/asb-app.c')
-rw-r--r--libappstream-builder/asb-app.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/libappstream-builder/asb-app.c b/libappstream-builder/asb-app.c
new file mode 100644
index 0000000..2f8fd7b
--- /dev/null
+++ b/libappstream-builder/asb-app.c
@@ -0,0 +1,494 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:asb-app
+ * @short_description: Application object.
+ * @stability: Unstable
+ *
+ * This is an application object that wraps AsApp and provides further features.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <appstream-glib.h>
+
+#include "asb-app.h"
+#include "as-cleanup.h"
+
+typedef struct _AsbAppPrivate AsbAppPrivate;
+struct _AsbAppPrivate
+{
+ GPtrArray *vetos;
+ GPtrArray *requires_appdata;
+ GdkPixbuf *pixbuf;
+ AsbPackage *pkg;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (AsbApp, asb_app, AS_TYPE_APP)
+
+#define GET_PRIVATE(o) (asb_app_get_instance_private (o))
+
+/**
+ * asb_app_finalize:
+ **/
+static void
+asb_app_finalize (GObject *object)
+{
+ AsbApp *app = ASB_APP (object);
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+
+ g_ptr_array_unref (priv->vetos);
+ g_ptr_array_unref (priv->requires_appdata);
+ if (priv->pixbuf != NULL)
+ g_object_unref (priv->pixbuf);
+ if (priv->pkg != NULL)
+ g_object_unref (priv->pkg);
+
+ G_OBJECT_CLASS (asb_app_parent_class)->finalize (object);
+}
+
+/**
+ * asb_app_init:
+ **/
+static void
+asb_app_init (AsbApp *app)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ priv->vetos = g_ptr_array_new_with_free_func (g_free);
+ priv->requires_appdata = g_ptr_array_new_with_free_func (g_free);
+}
+
+/**
+ * asb_app_class_init:
+ **/
+static void
+asb_app_class_init (AsbAppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = asb_app_finalize;
+}
+
+/**
+ * asb_app_to_xml:
+ * @app: A #AsbApp
+ *
+ * Converts the application to it's XML representation.
+ *
+ * Returns: allocated string
+ *
+ * Since: 0.1.0
+ **/
+gchar *
+asb_app_to_xml (AsbApp *app)
+{
+ GString *str;
+ _cleanup_object_unref_ AsStore *store;
+
+ store = as_store_new ();
+ as_store_add_app (store, AS_APP (app));
+ str = as_store_to_xml (store,
+ AS_NODE_TO_XML_FLAG_FORMAT_INDENT |
+ AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
+ return g_string_free (str, FALSE);
+}
+
+/**
+ * asb_app_add_veto:
+ * @app: A #AsbApp
+ * @fmt: format string
+ * @...: varargs
+ *
+ * Adds a reason to not include the application.
+ *
+ * Since: 0.1.0
+ **/
+void
+asb_app_add_veto (AsbApp *app, const gchar *fmt, ...)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ gchar *tmp;
+ va_list args;
+ va_start (args, fmt);
+ tmp = g_strdup_vprintf (fmt, args);
+ va_end (args);
+ g_ptr_array_add (priv->vetos, tmp);
+}
+
+/**
+ * asb_app_add_requires_appdata:
+ * @app: A #AsbApp
+ * @fmt: format string
+ * @...: varargs
+ *
+ * Adds a reason that AppData is required.
+ *
+ * Since: 0.1.0
+ **/
+void
+asb_app_add_requires_appdata (AsbApp *app, const gchar *fmt, ...)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ gchar *tmp;
+ va_list args;
+ va_start (args, fmt);
+ tmp = g_strdup_vprintf (fmt, args);
+ va_end (args);
+ g_ptr_array_add (priv->requires_appdata, tmp);
+}
+
+/**
+ * asb_app_set_requires_appdata:
+ * @app: A #AsbApp
+ * @requires_appdata: boolean
+ *
+ * Sets (or clears) the requirement for AppData.
+ *
+ * Since: 0.1.0
+ **/
+void
+asb_app_set_requires_appdata (AsbApp *app, gboolean requires_appdata)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ if (requires_appdata) {
+ g_ptr_array_add (priv->requires_appdata, NULL);
+ } else {
+ g_ptr_array_set_size (priv->requires_appdata, 0);
+ }
+}
+
+/**
+ * asb_app_set_pixbuf:
+ * @app: A #AsbApp
+ * @pixbuf: a #GdkPixbuf
+ *
+ * Sets the icon for the application.
+ *
+ * Since: 0.1.0
+ **/
+void
+asb_app_set_pixbuf (AsbApp *app, GdkPixbuf *pixbuf)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ if (priv->pixbuf != NULL)
+ g_object_ref (priv->pixbuf);
+ priv->pixbuf = g_object_ref (pixbuf);
+
+ /* does the icon not have an alpha channel */
+ if (!gdk_pixbuf_get_has_alpha (priv->pixbuf)) {
+ asb_package_log (priv->pkg,
+ ASB_PACKAGE_LOG_LEVEL_WARNING,
+ "icon does not have an alpha channel");
+ }
+}
+
+/**
+ * asb_app_get_requires_appdata:
+ * @app: A #AsbApp
+ *
+ * Gets if AppData is still required for the application.
+ *
+ * Returns: (transfer none) (element-type utf8): A list of reasons
+ *
+ * Since: 0.1.0
+ **/
+GPtrArray *
+asb_app_get_requires_appdata (AsbApp *app)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ return priv->requires_appdata;
+}
+
+/**
+ * asb_app_get_vetos:
+ * @app: A #AsbApp
+ *
+ * Gets the list of vetos.
+ *
+ * Returns: (transfer none) (element-type utf8): A list of vetos
+ *
+ * Since: 0.1.0
+ **/
+GPtrArray *
+asb_app_get_vetos (AsbApp *app)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ return priv->vetos;
+}
+
+/**
+ * asb_app_get_package:
+ * @app: A #AsbApp
+ *
+ * Gets the package that backs the application.
+ *
+ * Returns: (transfer none): package
+ *
+ * Since: 0.1.0
+ **/
+AsbPackage *
+asb_app_get_package (AsbApp *app)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ return priv->pkg;
+}
+
+/**
+ * asb_app_save_resources_image:
+ **/
+static gboolean
+asb_app_save_resources_image (AsbApp *app,
+ AsImage *image,
+ GError **error)
+{
+ const gchar *output_dir;
+ gboolean ret = TRUE;
+ _cleanup_free_ gchar *filename = NULL;
+ _cleanup_free_ gchar *size_str;
+
+ /* treat source images differently */
+ if (as_image_get_kind (image) == AS_IMAGE_KIND_SOURCE) {
+ size_str = g_strdup ("source");
+ } else {
+ size_str = g_strdup_printf ("%ix%i",
+ as_image_get_width (image),
+ as_image_get_height (image));
+ }
+
+ /* does screenshot already exist */
+ output_dir = asb_package_get_config (asb_app_get_package (app), "OutputDir");
+ filename = g_build_filename (output_dir,
+ "screenshots",
+ size_str,
+ as_image_get_basename (image),
+ NULL);
+ if (g_file_test (filename, G_FILE_TEST_EXISTS)) {
+ asb_package_log (asb_app_get_package (app),
+ ASB_PACKAGE_LOG_LEVEL_DEBUG,
+ "%s screenshot already exists", size_str);
+ return TRUE;
+ }
+
+ /* thumbnails will already be 16:9 */
+ ret = as_image_save_filename (image,
+ filename,
+ 0, 0,
+ AS_IMAGE_SAVE_FLAG_NONE,
+ error);
+ if (!ret)
+ return FALSE;
+
+ /* set new AppStream compatible screenshot name */
+ asb_package_log (asb_app_get_package (app),
+ ASB_PACKAGE_LOG_LEVEL_DEBUG,
+ "saved %s screenshot", size_str);
+ return TRUE;
+
+}
+
+/**
+ * asb_app_save_resources_screenshot:
+ **/
+static gboolean
+asb_app_save_resources_screenshot (AsbApp *app,
+ AsScreenshot *screenshot,
+ GError **error)
+{
+ AsImage *im;
+ GPtrArray *images;
+ guint i;
+
+ images = as_screenshot_get_images (screenshot);
+ for (i = 0; i < images->len; i++) {
+ im = g_ptr_array_index (images, i);
+ if (!asb_app_save_resources_image (app, im, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * asb_app_save_resources:
+ * @app: A #AsbApp
+ * @error: A #GError or %NULL
+ *
+ * Saves to disk any resources set for the application.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+asb_app_save_resources (AsbApp *app, GError **error)
+{
+ AsbAppPrivate *priv = GET_PRIVATE (app);
+ AsScreenshot *ss;
+ guint i;
+ GPtrArray *screenshots;
+
+ /* any non-stock icon set */
+ if (priv->pixbuf != NULL) {
+ const gchar *tmpdir;
+ _cleanup_free_ gchar *filename = NULL;
+
+ tmpdir = asb_package_get_config (priv->pkg, "TempDir");
+ filename = g_build_filename (tmpdir,
+ "icons",
+ as_app_get_icon (AS_APP (app)),
+ NULL);
+ if (!gdk_pixbuf_save (priv->pixbuf, filename, "png", error, NULL))
+ return FALSE;
+
+ /* set new AppStream compatible icon name */
+ asb_package_log (priv->pkg,
+ ASB_PACKAGE_LOG_LEVEL_DEBUG,
+ "Saved icon %s", filename);
+ }
+
+ /* save any screenshots */
+ screenshots = as_app_get_screenshots (AS_APP (app));
+ for (i = 0; i < screenshots->len; i++) {
+ ss = g_ptr_array_index (screenshots, i);
+ if (!asb_app_save_resources_screenshot (app, ss, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * asb_app_add_screenshot_source:
+ * @app: A #AsbApp
+ * @filename: filename to the source image
+ * @error: A #GError or %NULL
+ *
+ * Adds a screenshot from a previously saved image.
+ *
+ * Returns: %TRUE for success, %FALSE otherwise
+ *
+ * Since: 0.1.0
+ **/
+gboolean
+asb_app_add_screenshot_source (AsbApp *app, const gchar *filename, GError **error)
+{
+ gboolean is_default;
+ guint sizes[] = { 624, 351, 112, 63, 752, 423, 0 };
+ const gchar *mirror_uri;
+ guint i;
+ _cleanup_free_ gchar *basename = NULL;
+ _cleanup_object_unref_ AsImage *im_src;
+ _cleanup_object_unref_ AsScreenshot *ss = NULL;
+
+ im_src = as_image_new ();
+ if (!as_image_load_filename (im_src, filename, error))
+ return FALSE;
+
+ /* is the aspect ratio of the source perfectly 16:9 */
+ if ((as_image_get_width (im_src) / 16) * 9 !=
+ as_image_get_height (im_src)) {
+ asb_package_log (asb_app_get_package (app),
+ ASB_PACKAGE_LOG_LEVEL_WARNING,
+ "%s is not in 16:9 aspect ratio",
+ filename);
+ }
+
+ ss = as_screenshot_new ();
+ is_default = as_app_get_screenshots(AS_APP(app))->len == 0;
+ as_screenshot_set_kind (ss, is_default ? AS_SCREENSHOT_KIND_DEFAULT :
+ AS_SCREENSHOT_KIND_NORMAL);
+
+ /* include the app-id in the basename */
+ basename = g_strdup_printf ("%s-%s.png",
+ as_app_get_id (AS_APP (app)),
+ as_image_get_md5 (im_src));
+ as_image_set_basename (im_src, basename);
+
+ /* only fonts have full sized screenshots */
+ mirror_uri = asb_package_get_config (asb_app_get_package (app), "MirrorURI");
+ if (as_app_get_id_kind (AS_APP (app)) == AS_ID_KIND_FONT) {
+ _cleanup_free_ gchar *url_tmp;
+ url_tmp = g_build_filename (mirror_uri,
+ "source",
+ basename,
+ NULL);
+ as_image_set_url (im_src, url_tmp, -1);
+ as_image_set_kind (im_src, AS_IMAGE_KIND_SOURCE);
+ as_screenshot_add_image (ss, im_src);
+ } else {
+ for (i = 0; sizes[i] != 0; i += 2) {
+ _cleanup_free_ gchar *size_str;
+ _cleanup_free_ gchar *url_tmp;
+ _cleanup_object_unref_ AsImage *im_tmp;
+ _cleanup_object_unref_ GdkPixbuf *pixbuf;
+
+ size_str = g_strdup_printf ("%ix%i",
+ sizes[i],
+ sizes[i+1]);
+ url_tmp = g_build_filename (mirror_uri,
+ size_str,
+ basename,
+ NULL);
+ pixbuf = as_image_save_pixbuf (im_src,
+ sizes[i],
+ sizes[i+1],
+ AS_IMAGE_SAVE_FLAG_PAD_16_9);
+ im_tmp = as_image_new ();
+ as_image_set_width (im_tmp, sizes[i]);
+ as_image_set_height (im_tmp, sizes[i+1]);
+ as_image_set_url (im_tmp, url_tmp, -1);
+ as_image_set_pixbuf (im_tmp, pixbuf);
+ as_image_set_kind (im_tmp, AS_IMAGE_KIND_THUMBNAIL);
+ as_image_set_basename (im_tmp, basename);
+ as_screenshot_add_image (ss, im_tmp);
+ }
+ }
+ as_app_add_screenshot (AS_APP (app), ss);
+ return TRUE;
+}
+
+/**
+ * asb_app_new:
+ * @pkg: A #AsbPackage
+ * @id_full: The ID for the package
+ *
+ * Creates a new application object.
+ *
+ * Returns: a #AsbApp
+ *
+ * Since: 0.1.0
+ **/
+AsbApp *
+asb_app_new (AsbPackage *pkg, const gchar *id_full)
+{
+ AsbApp *app;
+ AsbAppPrivate *priv;
+
+ app = g_object_new (ASB_TYPE_APP, NULL);
+ priv = GET_PRIVATE (app);
+ if (pkg != NULL) {
+ priv->pkg = g_object_ref (pkg);
+ as_app_add_pkgname (AS_APP (app),
+ asb_package_get_name (pkg), -1);
+ }
+ if (id_full != NULL)
+ as_app_set_id_full (AS_APP (app), id_full, -1);
+ return ASB_APP (app);
+}