summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2016-07-08 16:41:25 +0100
committerRichard Hughes <richard@hughsie.com>2016-08-11 10:13:10 +0100
commit435ad105aa8c8b73f8d981aae6a25a89db423796 (patch)
treebb4f29ef61d82bdc81fbc5de8ceb1ec73aa569bb
parent6956a72b8fc4f13ec6f10539a3c0047568854c22 (diff)
downloadappstream-glib-435ad105aa8c8b73f8d981aae6a25a89db423796.tar.gz
Add support for application suggestions
-rw-r--r--libappstream-glib/Makefile.am5
-rw-r--r--libappstream-glib/appstream-glib.h1
-rw-r--r--libappstream-glib/as-app.c71
-rw-r--r--libappstream-glib/as-app.h4
-rw-r--r--libappstream-glib/as-self-test.c54
-rw-r--r--libappstream-glib/as-suggest-private.h48
-rw-r--r--libappstream-glib/as-suggest.c285
-rw-r--r--libappstream-glib/as-suggest.h84
-rw-r--r--libappstream-glib/as-tag.c1
-rw-r--r--libappstream-glib/as-tag.gperf1
-rw-r--r--libappstream-glib/as-tag.h2
11 files changed, 556 insertions, 0 deletions
diff --git a/libappstream-glib/Makefile.am b/libappstream-glib/Makefile.am
index 8f6bb7c..826d935 100644
--- a/libappstream-glib/Makefile.am
+++ b/libappstream-glib/Makefile.am
@@ -86,6 +86,7 @@ libappstream_glib_include_HEADERS = \
as-review.h \
as-screenshot.h \
as-store.h \
+ as-suggest.h \
as-tag.h \
as-translation.h \
as-utils.h \
@@ -134,6 +135,8 @@ libappstream_glib_la_SOURCES = \
as-stemmer.c \
as-stemmer.h \
as-store.c \
+ as-suggest.c \
+ as-suggest-private.h \
as-tag.c \
as-translation.c \
as-translation-private.h \
@@ -227,6 +230,8 @@ introspection_sources = \
as-screenshot.h \
as-store.c \
as-store.h \
+ as-suggest.c \
+ as-suggest.h \
as-tag.c \
as-tag.h \
as-translation.c \
diff --git a/libappstream-glib/appstream-glib.h b/libappstream-glib/appstream-glib.h
index 55962dd..785affb 100644
--- a/libappstream-glib/appstream-glib.h
+++ b/libappstream-glib/appstream-glib.h
@@ -42,6 +42,7 @@
#include <as-review.h>
#include <as-screenshot.h>
#include <as-store.h>
+#include <as-suggest.h>
#include <as-tag.h>
#include <as-translation.h>
#include <as-version.h>
diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c
index d8d1668..177a66a 100644
--- a/libappstream-glib/as-app.c
+++ b/libappstream-glib/as-app.c
@@ -50,6 +50,7 @@
#include "as-stemmer.h"
#include "as-tag.h"
#include "as-translation-private.h"
+#include "as-suggest-private.h"
#include "as-utils-private.h"
#include "as-yaml.h"
@@ -84,6 +85,7 @@ typedef struct
GPtrArray *icons; /* of AsIcon */
GPtrArray *bundles; /* of AsBundle */
GPtrArray *translations; /* of AsTranslation */
+ GPtrArray *suggests; /* of AsSuggest */
GPtrArray *vetos; /* of string */
AsAppSourceKind source_kind;
AsAppScope scope;
@@ -485,6 +487,7 @@ as_app_finalize (GObject *object)
g_ptr_array_unref (priv->icons);
g_ptr_array_unref (priv->bundles);
g_ptr_array_unref (priv->translations);
+ g_ptr_array_unref (priv->suggests);
g_ptr_array_unref (priv->vetos);
G_OBJECT_CLASS (as_app_parent_class)->finalize (object);
@@ -514,6 +517,7 @@ as_app_init (AsApp *app)
priv->icons = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->bundles = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->translations = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ priv->suggests = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->vetos = g_ptr_array_new_with_free_func (g_free);
priv->comments = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
@@ -1172,6 +1176,23 @@ as_app_get_translations (AsApp *app)
}
/**
+ * as_app_get_suggests:
+ * @app: a #AsApp instance.
+ *
+ * Gets any suggests the application has defined.
+ *
+ * Returns: (element-type AsSuggest) (transfer none): an array
+ *
+ * Since: 0.6.1
+ **/
+GPtrArray *
+as_app_get_suggests (AsApp *app)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ return priv->suggests;
+}
+
+/**
* as_app_get_names:
* @app: a #AsApp instance.
*
@@ -3083,6 +3104,22 @@ as_app_add_translation (AsApp *app, AsTranslation *translation)
}
/**
+ * as_app_add_suggest:
+ * @app: a #AsApp instance.
+ * @suggest: a #AsSuggest instance.
+ *
+ * Adds a suggest to an application.
+ *
+ * Since: 0.6.1
+ **/
+void
+as_app_add_suggest (AsApp *app, AsSuggest *suggest)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ g_ptr_array_add (priv->suggests, g_object_ref (suggest));
+}
+
+/**
* as_app_add_pkgname:
* @app: a #AsApp instance.
* @pkgname: the package name.
@@ -3439,6 +3476,12 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags)
}
}
+ /* suggests */
+ for (i = 0; i < priv->suggests->len; i++) {
+ AsSuggest *suggest = g_ptr_array_index (priv->suggests, i);
+ as_app_add_suggest (app, suggest);
+ }
+
/* releases */
if (flags & AS_APP_SUBSUME_FLAG_RELEASES) {
for (i = 0; i < priv->releases->len; i++) {
@@ -3865,6 +3908,12 @@ as_app_node_insert (AsApp *app, GNode *parent, AsNodeContext *ctx)
as_translation_node_insert (bu, node_app, ctx);
}
+ /* <suggests> */
+ for (i = 0; i < priv->suggests->len; i++) {
+ AsSuggest *suggest = g_ptr_array_index (priv->suggests, i);
+ as_suggest_node_insert (suggest, node_app, ctx);
+ }
+
/* <name> */
as_node_insert_localized (node_app, "name",
priv->names,
@@ -4133,6 +4182,17 @@ as_app_node_parse_child (AsApp *app, GNode *n, AsAppParseFlags flags,
break;
}
+ /* <suggests> */
+ case AS_TAG_SUGGESTS:
+ {
+ g_autoptr(AsSuggest) ic = NULL;
+ ic = as_suggest_new ();
+ if (!as_suggest_node_parse (ic, n, ctx, error))
+ return FALSE;
+ as_app_add_suggest (app, ic);
+ break;
+ }
+
/* <name> */
case AS_TAG_NAME:
taken = as_node_fix_locale (as_node_get_attribute (n, "xml:lang"));
@@ -4576,6 +4636,7 @@ as_app_node_parse_full (AsApp *app, GNode *node, AsAppParseFlags flags,
g_ptr_array_set_size (priv->icons, 0);
g_ptr_array_set_size (priv->bundles, 0);
g_ptr_array_set_size (priv->translations, 0);
+ g_ptr_array_set_size (priv->suggests, 0);
g_ptr_array_set_size (priv->content_ratings, 0);
g_hash_table_remove_all (priv->keywords);
}
@@ -4809,6 +4870,16 @@ as_app_node_parse_dep11 (AsApp *app, GNode *node,
}
continue;
}
+ if (g_strcmp0 (tmp, "Suggests") == 0) {
+ for (c = n->children; c != NULL; c = c->next) {
+ g_autoptr(AsSuggest) bu = NULL;
+ bu = as_suggest_new ();
+ if (!as_suggest_node_parse_dep11 (bu, c, ctx, error))
+ return FALSE;
+ as_app_add_suggest (app, bu);
+ }
+ continue;
+ }
if (g_strcmp0 (tmp, "Url") == 0) {
for (c = n->children; c != NULL; c = c->next) {
if (g_strcmp0 (as_yaml_node_get_key (c), "homepage") == 0) {
diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h
index ddc75fd..c11ea23 100644
--- a/libappstream-glib/as-app.h
+++ b/libappstream-glib/as-app.h
@@ -35,6 +35,7 @@
#include "as-release.h"
#include "as-screenshot.h"
#include "as-review.h"
+#include "as-suggest.h"
#include "as-content-rating.h"
#include "as-translation.h"
@@ -451,6 +452,7 @@ GPtrArray *as_app_get_content_ratings (AsApp *app);
GPtrArray *as_app_get_icons (AsApp *app);
GPtrArray *as_app_get_bundles (AsApp *app);
GPtrArray *as_app_get_translations (AsApp *app);
+GPtrArray *as_app_get_suggests (AsApp *app);
GHashTable *as_app_get_names (AsApp *app);
GHashTable *as_app_get_comments (AsApp *app);
GHashTable *as_app_get_developer_names (AsApp *app);
@@ -580,6 +582,8 @@ void as_app_add_bundle (AsApp *app,
AsBundle *bundle);
void as_app_add_translation (AsApp *app,
AsTranslation *translation);
+void as_app_add_suggest (AsApp *app,
+ AsSuggest *suggest);
void as_app_add_language (AsApp *app,
gint percentage,
const gchar *locale);
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 6ec5abd..e824de4 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -43,6 +43,7 @@
#include "as-problem.h"
#include "as-provide-private.h"
#include "as-release-private.h"
+#include "as-suggest-private.h"
#include "as-screenshot-private.h"
#include "as-store.h"
#include "as-tag.h"
@@ -1173,6 +1174,7 @@ as_test_image_func (void)
g_assert (ret);
}
+
static void
as_test_review_func (void)
{
@@ -1236,6 +1238,53 @@ as_test_review_func (void)
}
static void
+as_test_suggest_func (void)
+{
+ GError *error = NULL;
+ AsNode *n;
+ AsNode *root;
+ GString *xml;
+ const gchar *src =
+ "<suggests type=\"upstream\">\n"
+ "<id>gimp.desktop</id>\n"
+ "<id>mypaint.desktop</id>\n"
+ "</suggests>\n";
+ gboolean ret;
+ g_autofree AsNodeContext *ctx = NULL;
+ g_autoptr(AsSuggest) suggest = NULL;
+ g_autoptr(GdkPixbuf) pixbuf = NULL;
+
+ suggest = as_suggest_new ();
+
+ /* to object */
+ root = as_node_from_xml (src, 0, &error);
+ g_assert_no_error (error);
+ g_assert (root != NULL);
+ n = as_node_find (root, "suggests");
+ g_assert (n != NULL);
+ ctx = as_node_context_new ();
+ ret = as_suggest_node_parse (suggest, n, ctx, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ as_node_unref (root);
+
+ /* verify */
+ g_assert_cmpint (as_suggest_get_kind (suggest), ==, AS_SUGGEST_KIND_UPSTREAM);
+ g_assert_cmpint (as_suggest_get_ids(suggest)->len, ==, 2);
+
+ /* back to node */
+ root = as_node_new ();
+ as_node_context_set_version (ctx, 0.4);
+ n = as_suggest_node_insert (suggest, root, ctx);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_FORMAT_MULTILINE);
+ ret = as_test_compare_lines (xml->str, src, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_string_free (xml, TRUE);
+ as_node_unref (root);
+}
+
+static void
as_test_bundle_func (void)
{
GError *error = NULL;
@@ -1452,6 +1501,10 @@ as_test_app_func (void)
"<source_pkgname>gnome-software-src</source_pkgname>\n"
"<bundle type=\"flatpak\">app/org.gnome.Software/x86_64/master</bundle>\n"
"<translation type=\"gettext\">gnome-software</translation>\n"
+ "<suggests type=\"upstream\">\n"
+ "<id>gimp.desktop</id>\n"
+ "<id>mypaint.desktop</id>\n"
+ "</suggests>\n"
"<name>Software</name>\n"
"<name xml:lang=\"pl\">Oprogramowanie</name>\n"
"<summary>Application manager</summary>\n"
@@ -5164,6 +5217,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/bundle", as_test_bundle_func);
g_test_add_func ("/AppStream/review", as_test_review_func);
g_test_add_func ("/AppStream/translation", as_test_translation_func);
+ g_test_add_func ("/AppStream/suggest", as_test_suggest_func);
g_test_add_func ("/AppStream/image", as_test_image_func);
g_test_add_func ("/AppStream/image{resize}", as_test_image_resize_func);
g_test_add_func ("/AppStream/image{alpha}", as_test_image_alpha_func);
diff --git a/libappstream-glib/as-suggest-private.h b/libappstream-glib/as-suggest-private.h
new file mode 100644
index 0000000..ed2aa76
--- /dev/null
+++ b/libappstream-glib/as-suggest-private.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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
+ */
+
+#if !defined (__APPSTREAM_GLIB_PRIVATE_H) && !defined (AS_COMPILATION)
+#error "Only <appstream-glib.h> can be included directly."
+#endif
+
+#ifndef __AS_SUGGEST_PRIVATE_H
+#define __AS_SUGGEST_PRIVATE_H
+
+#include "as-suggest.h"
+#include "as-node-private.h"
+
+G_BEGIN_DECLS
+
+GNode *as_suggest_node_insert (AsSuggest *suggest,
+ GNode *parent,
+ AsNodeContext *ctx);
+gboolean as_suggest_node_parse (AsSuggest *suggest,
+ GNode *node,
+ AsNodeContext *ctx,
+ GError **error);
+gboolean as_suggest_node_parse_dep11 (AsSuggest *suggest,
+ GNode *node,
+ AsNodeContext *ctx,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __AS_SUGGEST_PRIVATE_H */
diff --git a/libappstream-glib/as-suggest.c b/libappstream-glib/as-suggest.c
new file mode 100644
index 0000000..d244557
--- /dev/null
+++ b/libappstream-glib/as-suggest.c
@@ -0,0 +1,285 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014-2016 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:as-suggest
+ * @short_description: Object representing a single suggest used in a screenshot.
+ * @include: appstream-glib.h
+ * @stability: Stable
+ *
+ * Screenshot may have multiple versions of an suggest in different resolutions
+ * or aspect ratios. This object allows access to the location and size of a
+ * single suggest.
+ *
+ * See also: #AsScreenshot
+ */
+
+#include "config.h"
+
+#include "as-suggest-private.h"
+#include "as-node-private.h"
+#include "as-utils-private.h"
+
+typedef struct
+{
+ AsSuggestKind kind;
+ GPtrArray *ids; /* utf8 */
+} AsSuggestPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AsSuggest, as_suggest, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) (as_suggest_get_instance_private (o))
+
+static void
+as_suggest_finalize (GObject *object)
+{
+ AsSuggest *suggest = AS_SUGGEST (object);
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+
+ g_ptr_array_unref (priv->ids);
+
+ G_OBJECT_CLASS (as_suggest_parent_class)->finalize (object);
+}
+
+static void
+as_suggest_init (AsSuggest *suggest)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ priv->ids = g_ptr_array_new_with_free_func (g_free);
+}
+
+static void
+as_suggest_class_init (AsSuggestClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = as_suggest_finalize;
+}
+
+
+/**
+ * as_suggest_kind_from_string:
+ * @kind: the string.
+ *
+ * Converts the text representation to an enumerated value.
+ *
+ * Returns: (transfer full): a #AsSuggestKind, or %AS_SUGGEST_KIND_UNKNOWN for unknown.
+ *
+ * Since: 0.6.1
+ **/
+AsSuggestKind
+as_suggest_kind_from_string (const gchar *kind)
+{
+ if (g_strcmp0 (kind, "upstream") == 0)
+ return AS_SUGGEST_KIND_UPSTREAM;
+ if (g_strcmp0 (kind, "heuristic") == 0)
+ return AS_SUGGEST_KIND_HEURISTIC;
+ return AS_SUGGEST_KIND_UNKNOWN;
+}
+
+/**
+ * as_suggest_kind_to_string:
+ * @kind: the #AsSuggestKind.
+ *
+ * Converts the enumerated value to an text representation.
+ *
+ * Returns: string version of @kind
+ *
+ * Since: 0.6.1
+ **/
+const gchar *
+as_suggest_kind_to_string (AsSuggestKind kind)
+{
+ if (kind == AS_SUGGEST_KIND_UPSTREAM)
+ return "upstream";
+ if (kind == AS_SUGGEST_KIND_HEURISTIC)
+ return "heuristic";
+ return NULL;
+}
+
+/**
+ * as_suggest_get_ids:
+ * @suggest: a #AsSuggest instance.
+ *
+ * Gets the suggest ids if set.
+ *
+ * Returns: (transfer none): the #GPtrArray, or %NULL
+ *
+ * Since: 0.6.1
+ **/
+GPtrArray *
+as_suggest_get_ids (AsSuggest *suggest)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ return priv->ids;
+}
+
+/**
+ * as_suggest_get_kind:
+ * @suggest: a #AsSuggest instance.
+ *
+ * Gets the suggest kind.
+ *
+ * Returns: the #AsSuggestKind
+ *
+ * Since: 0.6.1
+ **/
+AsSuggestKind
+as_suggest_get_kind (AsSuggest *suggest)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ return priv->kind;
+}
+
+/**
+ * as_suggest_set_kind:
+ * @suggest: a #AsSuggest instance.
+ * @kind: the #AsSuggestKind, e.g. %AS_SUGGEST_KIND_UPSTREAM.
+ *
+ * Sets the suggest kind.
+ *
+ * Since: 0.6.1
+ **/
+void
+as_suggest_set_kind (AsSuggest *suggest, AsSuggestKind kind)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ priv->kind = kind;
+}
+
+/**
+ * as_suggest_add_id:
+ * @suggest: a #AsSuggest instance.
+ * @ids: the #GPtrArray, or %NULL
+ *
+ * Add a the suggest application ID.
+ *
+ * Since: 0.6.1
+ **/
+void
+as_suggest_add_id (AsSuggest *suggest, const gchar *id)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ g_ptr_array_add (priv->ids, g_strdup (id));
+}
+
+/**
+ * as_suggest_node_insert: (skip)
+ * @suggest: a #AsSuggest instance.
+ * @parent: the parent #GNode to use..
+ * @ctx: the #AsNodeContext
+ *
+ * Inserts the suggest into the DOM tree.
+ *
+ * Returns: (transfer none): A populated #GNode
+ *
+ * Since: 0.6.1
+ **/
+GNode *
+as_suggest_node_insert (AsSuggest *suggest, GNode *parent, AsNodeContext *ctx)
+{
+ AsSuggestPrivate *priv = GET_PRIVATE (suggest);
+ GNode *n;
+ guint i;
+
+ n = as_node_insert (parent, "suggests", NULL,
+ AS_NODE_INSERT_FLAG_NONE,
+ NULL);
+ if (priv->kind != AS_SUGGEST_KIND_UNKNOWN) {
+ as_node_add_attribute (n,
+ "type",
+ as_suggest_kind_to_string (priv->kind));
+ }
+ for (i = 0; i < priv->ids->len; i++) {
+ const gchar *id = g_ptr_array_index (priv->ids, i);
+ as_node_insert (n, "id", id,
+ AS_NODE_INSERT_FLAG_NONE,
+ NULL);
+ }
+ return n;
+}
+
+/**
+ * as_suggest_node_parse:
+ * @suggest: a #AsSuggest instance.
+ * @node: a #GNode.
+ * @ctx: a #AsNodeContext.
+ * @error: A #GError or %NULL.
+ *
+ * Populates the object from a DOM node.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.6.1
+ **/
+gboolean
+as_suggest_node_parse (AsSuggest *suggest, GNode *node,
+ AsNodeContext *ctx, GError **error)
+{
+ AsNode *c;
+ const gchar *tmp;
+
+ tmp = as_node_get_attribute (node, "type");
+ if (tmp != NULL)
+ as_suggest_set_kind (suggest, as_suggest_kind_from_string (tmp));
+ for (c = node->children; c != NULL; c = c->next) {
+ if (as_node_get_tag (c) == AS_TAG_ID)
+ as_suggest_add_id (suggest, as_node_get_data (c));
+ }
+ return TRUE;
+}
+
+/**
+ * as_suggest_node_parse_dep11:
+ * @suggest: a #AsSuggest instance.
+ * @node: a #GNode.
+ * @ctx: a #AsNodeContext.
+ * @error: A #GError or %NULL.
+ *
+ * Populates the object from a DEP-11 node.
+ *
+ * Returns: %TRUE for success
+ *
+ * Since: 0.6.1
+ **/
+gboolean
+as_suggest_node_parse_dep11 (AsSuggest *im, GNode *node,
+ AsNodeContext *ctx, GError **error)
+{
+ return TRUE;
+}
+
+/**
+ * as_suggest_new:
+ *
+ * Creates a new #AsSuggest.
+ *
+ * Returns: (transfer full): a #AsSuggest
+ *
+ * Since: 0.6.1
+ **/
+AsSuggest *
+as_suggest_new (void)
+{
+ AsSuggest *suggest;
+ suggest = g_object_new (AS_TYPE_SUGGEST, NULL);
+ return AS_SUGGEST (suggest);
+}
+
diff --git a/libappstream-glib/as-suggest.h b/libappstream-glib/as-suggest.h
new file mode 100644
index 0000000..ddae4c8
--- /dev/null
+++ b/libappstream-glib/as-suggest.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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
+ */
+
+#if !defined (__APPSTREAM_GLIB_H) && !defined (AS_COMPILATION)
+#error "Only <appstream-glib.h> can be included directly."
+#endif
+
+#ifndef __AS_SUGGEST_H
+#define __AS_SUGGEST_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define AS_TYPE_SUGGEST (as_suggest_get_type ())
+G_DECLARE_DERIVABLE_TYPE (AsSuggest, as_suggest, AS, SUGGEST, GObject)
+
+struct _AsSuggestClass
+{
+ GObjectClass parent_class;
+ /*< private >*/
+ void (*_as_reserved1) (void);
+ void (*_as_reserved2) (void);
+ void (*_as_reserved3) (void);
+ void (*_as_reserved4) (void);
+ void (*_as_reserved5) (void);
+ void (*_as_reserved6) (void);
+ void (*_as_reserved7) (void);
+ void (*_as_reserved8) (void);
+};
+
+/**
+ * AsSuggestKind:
+ * @AS_SUGGEST_KIND_UNKNOWN: Type invalid or not known
+ * @AS_SUGGEST_KIND_UPSTREAM: Upstream-specified suggestion
+ * @AS_SUGGEST_KIND_HEURISTIC: Suggestion from a heuristic
+ *
+ * The suggest type.
+ **/
+typedef enum {
+ AS_SUGGEST_KIND_UNKNOWN,
+ AS_SUGGEST_KIND_UPSTREAM,
+ AS_SUGGEST_KIND_HEURISTIC,
+ /*< private >*/
+ AS_SUGGEST_KIND_LAST
+} AsSuggestKind;
+
+AsSuggest *as_suggest_new (void);
+
+/* helpers */
+AsSuggestKind as_suggest_kind_from_string (const gchar *kind);
+const gchar *as_suggest_kind_to_string (AsSuggestKind kind);
+
+/* getters */
+AsSuggestKind as_suggest_get_kind (AsSuggest *suggest);
+GPtrArray *as_suggest_get_ids (AsSuggest *suggest);
+
+/* setters */
+void as_suggest_set_kind (AsSuggest *suggest,
+ AsSuggestKind kind);
+void as_suggest_add_id (AsSuggest *suggest,
+ const gchar *id);
+
+G_END_DECLS
+
+#endif /* __AS_SUGGEST_H */
diff --git a/libappstream-glib/as-tag.c b/libappstream-glib/as-tag.c
index 56192c8..7d83d83 100644
--- a/libappstream-glib/as-tag.c
+++ b/libappstream-glib/as-tag.c
@@ -199,6 +199,7 @@ as_tag_to_string (AsTag tag)
"review",
"reviewer_name",
"reviewer_id",
+ "suggests",
NULL };
if (tag > AS_TAG_LAST)
tag = AS_TAG_LAST;
diff --git a/libappstream-glib/as-tag.gperf b/libappstream-glib/as-tag.gperf
index a6455c1..9004b5e 100644
--- a/libappstream-glib/as-tag.gperf
+++ b/libappstream-glib/as-tag.gperf
@@ -63,3 +63,4 @@ reviews, AS_TAG_REVIEWS
review, AS_TAG_REVIEW
reviewer_name, AS_TAG_REVIEWER_NAME
reviewer_id, AS_TAG_REVIEWER_ID
+suggests, AS_TAG_SUGGESTS
diff --git a/libappstream-glib/as-tag.h b/libappstream-glib/as-tag.h
index 3ceb884..a8f4d17 100644
--- a/libappstream-glib/as-tag.h
+++ b/libappstream-glib/as-tag.h
@@ -88,6 +88,7 @@ G_BEGIN_DECLS
* @AS_TAG_REVIEW: `review`
* @AS_TAG_REVIEWER_NAME: `reviewer_name`
* @AS_TAG_REVIEWER_ID: `reviewer_id`
+ * @AS_TAG_SUGGESTS: `suggests`
*
* The tag type.
**/
@@ -148,6 +149,7 @@ typedef enum {
AS_TAG_REVIEW, /* Since: 0.6.1 */
AS_TAG_REVIEWER_NAME, /* Since: 0.6.1 */
AS_TAG_REVIEWER_ID, /* Since: 0.6.1 */
+ AS_TAG_SUGGESTS, /* Since: 0.6.1 */
/*< private >*/
AS_TAG_LAST
} AsTag;