summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2017-04-21 10:32:33 +0100
committerRichard Hughes <richard@hughsie.com>2017-04-21 11:05:52 +0100
commite32e245980f6f72b7f3eab6671404fbb5c78acad (patch)
treee42edeec613fd47d96d065bc84a2dc6f38f0b2a5
parent08cb0ec129d71740c14b27f4bfd8c2fe79ad5d34 (diff)
downloadappstream-glib-e32e245980f6f72b7f3eab6671404fbb5c78acad.tar.gz
Add support for <launchable>
-rw-r--r--docs/api/appstream-glib-docs.sgml1
-rw-r--r--libappstream-glib/Makefile.am5
-rw-r--r--libappstream-glib/as-app.c157
-rw-r--r--libappstream-glib/as-app.h12
-rw-r--r--libappstream-glib/as-launchable-private.h48
-rw-r--r--libappstream-glib/as-launchable.c263
-rw-r--r--libappstream-glib/as-launchable.h82
-rw-r--r--libappstream-glib/as-self-test.c91
-rw-r--r--libappstream-glib/as-tag.c3
-rw-r--r--libappstream-glib/as-tag.gperf1
-rw-r--r--libappstream-glib/as-tag.h4
11 files changed, 663 insertions, 4 deletions
diff --git a/docs/api/appstream-glib-docs.sgml b/docs/api/appstream-glib-docs.sgml
index 05d72e3..1fddfd4 100644
--- a/docs/api/appstream-glib-docs.sgml
+++ b/docs/api/appstream-glib-docs.sgml
@@ -42,6 +42,7 @@
<xi:include href="xml/as-image.xml"/>
<xi:include href="xml/as-markup.xml"/>
<xi:include href="xml/as-release.xml"/>
+ <xi:include href="xml/as-launchable.xml"/>
<xi:include href="xml/as-provide.xml"/>
<xi:include href="xml/as-screenshot.xml"/>
<xi:include href="xml/as-store.xml"/>
diff --git a/libappstream-glib/Makefile.am b/libappstream-glib/Makefile.am
index 4640a00..7a5481a 100644
--- a/libappstream-glib/Makefile.am
+++ b/libappstream-glib/Makefile.am
@@ -75,6 +75,7 @@ libappstream_glib_include_HEADERS = \
as-icon.h \
as-image.h \
as-inf.h \
+ as-launchable.h \
as-markup.h \
as-node.h \
as-problem.h \
@@ -114,6 +115,8 @@ libappstream_glib_la_SOURCES = \
as-image-private.h \
as-inf.c \
as-inf.h \
+ as-launchable.c \
+ as-launchable-private.h \
as-markup.c \
as-monitor.c \
as-monitor.h \
@@ -219,6 +222,8 @@ introspection_sources = \
as-image.h \
as-inf.c \
as-inf.h \
+ as-launchable.c \
+ as-launchable.h \
as-markup.c \
as-markup.h \
as-node.c \
diff --git a/libappstream-glib/as-app.c b/libappstream-glib/as-app.c
index 67e0673..d04c8cc 100644
--- a/libappstream-glib/as-app.c
+++ b/libappstream-glib/as-app.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2014-2016 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -43,6 +43,7 @@
#include "as-enums.h"
#include "as-icon-private.h"
#include "as-node-private.h"
+#include "as-launchable-private.h"
#include "as-provide-private.h"
#include "as-release-private.h"
#include "as-ref-string.h"
@@ -82,6 +83,7 @@ typedef struct
GPtrArray *formats; /* of AsFormat */
GPtrArray *releases; /* of AsRelease */
GPtrArray *provides; /* of AsProvide */
+ GPtrArray *launchables; /* of AsLaunchable */
GPtrArray *screenshots; /* of AsScreenshot */
GPtrArray *reviews; /* of AsReview */
GPtrArray *content_ratings; /* of AsContentRating */
@@ -461,6 +463,7 @@ as_app_finalize (GObject *object)
g_ptr_array_unref (priv->architectures);
g_ptr_array_unref (priv->releases);
g_ptr_array_unref (priv->provides);
+ g_ptr_array_unref (priv->launchables);
g_ptr_array_unref (priv->screenshots);
g_ptr_array_unref (priv->reviews);
g_ptr_array_unref (priv->icons);
@@ -493,6 +496,7 @@ as_app_init (AsApp *app)
priv->addons = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->releases = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->provides = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ priv->launchables = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->screenshots = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->reviews = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->icons = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
@@ -1133,6 +1137,67 @@ as_app_get_provides (AsApp *app)
}
/**
+ * as_app_get_launchables:
+ * @app: a #AsApp instance.
+ *
+ * Gets all the launchables the application has.
+ *
+ * Returns: (element-type AsLaunchable) (transfer none): an array
+ *
+ * Since: 0.6.13
+ **/
+GPtrArray *
+as_app_get_launchables (AsApp *app)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ return priv->launchables;
+}
+
+/**
+ * as_app_get_launchable_by_kind:
+ * @app: a #AsApp instance.
+ * @kind: a #AsLaunchableKind, e.g. %AS_FORMAT_KIND_APPDATA
+ *
+ * Searches the list of launchables for a specific launchable kind.
+ *
+ * Returns: (transfer none): A #AsLaunchable, or %NULL if not found
+ *
+ * Since: 0.6.13
+ */
+AsLaunchable *
+as_app_get_launchable_by_kind (AsApp *app, AsLaunchableKind kind)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ for (guint i = 0; i < priv->launchables->len; i++) {
+ AsLaunchable *launchable = g_ptr_array_index (priv->launchables, i);
+ if (as_launchable_get_kind (launchable) == kind)
+ return launchable;
+ }
+ return NULL;
+}
+
+/**
+ * as_app_get_launchable_default:
+ * @app: a #AsApp instance.
+ *
+ * Returns the default launchable.
+ *
+ * Returns: (transfer none): A #AsLaunchable, or %NULL if not found
+ *
+ * Since: 0.6.13
+ */
+AsLaunchable *
+as_app_get_launchable_default (AsApp *app)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+ if (priv->launchables->len > 0) {
+ AsLaunchable *launchable = g_ptr_array_index (priv->launchables, 0);
+ return launchable;
+ }
+ return NULL;
+}
+
+/**
* as_app_get_screenshots:
* @app: a #AsApp instance.
*
@@ -3091,6 +3156,34 @@ as_app_add_provide (AsApp *app, AsProvide *provide)
g_ptr_array_add (priv->provides, g_object_ref (provide));
}
+/**
+ * as_app_add_launchable:
+ * @app: a #AsApp instance.
+ * @launchable: a #AsLaunchable instance.
+ *
+ * Adds a launchable to an application.
+ *
+ * Since: 0.6.13
+ **/
+void
+as_app_add_launchable (AsApp *app, AsLaunchable *launchable)
+{
+ AsAppPrivate *priv = GET_PRIVATE (app);
+
+ /* check for duplicates */
+ if (priv->trust_flags & AS_APP_TRUST_FLAG_CHECK_DUPLICATES) {
+ for (guint i = 0; i < priv->launchables->len; i++) {
+ AsLaunchable *lau = g_ptr_array_index (priv->launchables, i);
+ if (as_launchable_get_kind (lau) == as_launchable_get_kind (launchable) &&
+ g_strcmp0 (as_launchable_get_value (lau),
+ as_launchable_get_value (launchable)) == 0)
+ return;
+ }
+ }
+
+ g_ptr_array_add (priv->launchables, g_object_ref (launchable));
+}
+
static gint
as_app_sort_screenshots (gconstpointer a, gconstpointer b)
{
@@ -3884,6 +3977,17 @@ as_app_subsume_private (AsApp *app, AsApp *donor, AsAppSubsumeFlags flags)
}
}
+ /* launchables */
+ if (flags & AS_APP_SUBSUME_FLAG_LAUNCHABLES) {
+ if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 &&
+ priv->launchables->len > 0)
+ g_ptr_array_set_size (papp->launchables, 0);
+ for (i = 0; i < priv->launchables->len; i++) {
+ AsLaunchable *lau = g_ptr_array_index (priv->launchables, i);
+ as_app_add_launchable (app, lau);
+ }
+ }
+
/* icons */
if (flags & AS_APP_SUBSUME_FLAG_ICONS) {
if ((flags & AS_APP_SUBSUME_FLAG_REPLACE) > 0 &&
@@ -4099,6 +4203,20 @@ as_app_provides_sort_cb (gconstpointer a, gconstpointer b)
}
static gint
+as_app_launchables_sort_cb (gconstpointer a, gconstpointer b)
+{
+ AsLaunchable *lau1 = *((AsLaunchable **) a);
+ AsLaunchable *lau2 = *((AsLaunchable **) b);
+
+ if (as_launchable_get_kind (lau1) < as_launchable_get_kind (lau2))
+ return -1;
+ if (as_launchable_get_kind (lau1) > as_launchable_get_kind (lau2))
+ return 1;
+ return g_strcmp0 (as_launchable_get_value (lau1),
+ as_launchable_get_value (lau2));
+}
+
+static gint
as_app_icons_sort_cb (gconstpointer a, gconstpointer b)
{
AsIcon **ic1 = (AsIcon **) a;
@@ -4439,6 +4557,15 @@ as_app_node_insert (AsApp *app, GNode *parent, AsNodeContext *ctx)
}
}
+ /* <launchables> */
+ if (priv->launchables->len > 0 && as_node_context_get_version (ctx) > 0.9) {
+ g_ptr_array_sort (priv->launchables, as_app_launchables_sort_cb);
+ for (i = 0; i < priv->launchables->len; i++) {
+ AsLaunchable *launchable = g_ptr_array_index (priv->launchables, i);
+ as_launchable_node_insert (launchable, node_app, ctx);
+ }
+ }
+
/* <languages> */
if (g_hash_table_size (priv->languages) > 0)
as_app_node_insert_languages (app, node_app);
@@ -4909,6 +5036,17 @@ as_app_node_parse_child (AsApp *app, GNode *n, AsAppParseFlags flags,
}
break;
+ /* <launchables> */
+ case AS_TAG_LAUNCHABLE:
+ {
+ g_autoptr(AsLaunchable) lau = NULL;
+ lau = as_launchable_new ();
+ if (!as_launchable_node_parse (lau, n, ctx, error))
+ return FALSE;
+ as_app_add_launchable (app, lau);
+ break;
+ }
+
/* <languages> */
case AS_TAG_LANGUAGES:
if (!(flags & AS_APP_PARSE_FLAG_APPEND_DATA))
@@ -5021,6 +5159,7 @@ as_app_node_parse_full (AsApp *app, GNode *node, AsAppParseFlags flags,
g_ptr_array_set_size (priv->suggests, 0);
g_ptr_array_set_size (priv->requires, 0);
g_ptr_array_set_size (priv->content_ratings, 0);
+ g_ptr_array_set_size (priv->launchables, 0);
g_hash_table_remove_all (priv->keywords);
}
for (n = node->children; n != NULL; n = n->next) {
@@ -5032,6 +5171,22 @@ as_app_node_parse_full (AsApp *app, GNode *node, AsAppParseFlags flags,
if (as_app_get_icons(app)->len == 1)
as_app_check_for_hidpi_icons (app);
+ /* add the launchable if missing for desktop apps */
+ if (priv->launchables->len == 0 &&
+ priv->kind == AS_APP_KIND_DESKTOP &&
+ priv->id != NULL) {
+ AsLaunchable *lau = as_launchable_new ();
+ as_launchable_set_kind (lau, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ if (g_str_has_suffix (priv->id, ".desktop")) {
+ as_launchable_set_value (lau, priv->id);
+ } else {
+ g_autofree gchar *id_tmp = NULL;
+ id_tmp = g_strdup_printf ("%s.desktop", priv->id);
+ as_launchable_set_value (lau, id_tmp);
+ }
+ g_ptr_array_add (priv->launchables, lau);
+ }
+
return TRUE;
}
diff --git a/libappstream-glib/as-app.h b/libappstream-glib/as-app.h
index b66bc14..b1e3707 100644
--- a/libappstream-glib/as-app.h
+++ b/libappstream-glib/as-app.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2014-2016 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -32,6 +32,7 @@
#include "as-enums.h"
#include "as-format.h"
#include "as-icon.h"
+#include "as-launchable.h"
#include "as-provide.h"
#include "as-release.h"
#include "as-screenshot.h"
@@ -126,6 +127,7 @@ typedef enum {
* @AS_APP_SUBSUME_FLAG_PROJECT_LICENSE: Copy the project license
* @AS_APP_SUBSUME_FLAG_PROJECT_GROUP: Copy the project group
* @AS_APP_SUBSUME_FLAG_SOURCE_KIND: Copy the source kind
+ * @AS_APP_SUBSUME_FLAG_LAUNCHABLES: Copy the launchables
*
* The flags to use when subsuming applications.
**/
@@ -167,6 +169,7 @@ typedef enum {
AS_APP_SUBSUME_FLAG_PROJECT_GROUP = 1ull << 33, /* Since: 0.6.1 */
AS_APP_SUBSUME_FLAG_SOURCE_KIND = 1ull << 34, /* Since: 0.6.1 */
AS_APP_SUBSUME_FLAG_SUGGESTS = 1ull << 35, /* Since: 0.6.3 */
+ AS_APP_SUBSUME_FLAG_LAUNCHABLES = 1ull << 36, /* Since: 0.6.13 */
/*< private >*/
AS_APP_SUBSUME_FLAG_LAST,
} AsAppSubsumeFlags;
@@ -198,6 +201,7 @@ typedef enum {
AS_APP_SUBSUME_FLAG_SUGGESTS | \
AS_APP_SUBSUME_FLAG_TRANSLATIONS | \
AS_APP_SUBSUME_FLAG_SOURCE_KIND | \
+ AS_APP_SUBSUME_FLAG_LAUNCHABLES | \
AS_APP_SUBSUME_FLAG_URL)
/* deprecated name */
@@ -495,6 +499,7 @@ GPtrArray *as_app_get_pkgnames (AsApp *app);
GPtrArray *as_app_get_architectures (AsApp *app);
GPtrArray *as_app_get_releases (AsApp *app);
GPtrArray *as_app_get_provides (AsApp *app);
+GPtrArray *as_app_get_launchables (AsApp *app);
GPtrArray *as_app_get_screenshots (AsApp *app);
GPtrArray *as_app_get_reviews (AsApp *app);
GPtrArray *as_app_get_content_ratings (AsApp *app);
@@ -555,6 +560,9 @@ gboolean as_app_has_compulsory_for_desktop (AsApp *app,
const gchar *desktop);
gboolean as_app_has_quirk (AsApp *app,
AsAppQuirk quirk);
+AsLaunchable *as_app_get_launchable_default (AsApp *app);
+AsLaunchable *as_app_get_launchable_by_kind (AsApp *app,
+ AsLaunchableKind kind);
/* setters */
void as_app_set_id (AsApp *app,
@@ -626,6 +634,8 @@ void as_app_add_release (AsApp *app,
AsRelease *release);
void as_app_add_provide (AsApp *app,
AsProvide *provide);
+void as_app_add_launchable (AsApp *app,
+ AsLaunchable *launchable);
void as_app_add_screenshot (AsApp *app,
AsScreenshot *screenshot);
void as_app_add_review (AsApp *app,
diff --git a/libappstream-glib/as-launchable-private.h b/libappstream-glib/as-launchable-private.h
new file mode 100644
index 0000000..82062f7
--- /dev/null
+++ b/libappstream-glib/as-launchable-private.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 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_LAUNCHABLE_PRIVATE_H
+#define __AS_LAUNCHABLE_PRIVATE_H
+
+#include "as-launchable.h"
+#include "as-node-private.h"
+
+G_BEGIN_DECLS
+
+GNode *as_launchable_node_insert (AsLaunchable *launchable,
+ GNode *parent,
+ AsNodeContext *ctx);
+gboolean as_launchable_node_parse (AsLaunchable *launchable,
+ GNode *node,
+ AsNodeContext *ctx,
+ GError **error);
+gboolean as_launchable_node_parse_dep11 (AsLaunchable *launchable,
+ GNode *node,
+ AsNodeContext *ctx,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __AS_LAUNCHABLE_PRIVATE_H */
diff --git a/libappstream-glib/as-launchable.c b/libappstream-glib/as-launchable.c
new file mode 100644
index 0000000..98f4840
--- /dev/null
+++ b/libappstream-glib/as-launchable.c
@@ -0,0 +1,263 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
+ *
+ * Licensed under the GNU Lesser General Public License Version 2.1
+ *
+ * This desktop-id 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 desktop-id 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 desktop-id; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:as-launchable
+ * @short_description: Object representing a way to launch the application.
+ * @include: appstream-glib.h
+ * @stability: Stable
+ *
+ * Applications may be launchable using a different application ID to the
+ * component ID or may be launchable in some other way, e.g D-Bus, or using
+ * the default terminal emulator.
+ *
+ * See also: #AsApp
+ */
+
+#include "config.h"
+
+#include "as-node-private.h"
+#include "as-launchable-private.h"
+#include "as-ref-string.h"
+#include "as-utils-private.h"
+#include "as-yaml.h"
+
+typedef struct
+{
+ AsLaunchableKind kind;
+ AsRefString *value;
+} AsLaunchablePrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (AsLaunchable, as_launchable, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) (as_launchable_get_instance_private (o))
+
+static void
+as_launchable_finalize (GObject *object)
+{
+ AsLaunchable *launchable = AS_LAUNCHABLE (object);
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+
+ if (priv->value != NULL)
+ as_ref_string_unref (priv->value);
+
+ G_OBJECT_CLASS (as_launchable_parent_class)->finalize (object);
+}
+
+static void
+as_launchable_init (AsLaunchable *launchable)
+{
+}
+
+static void
+as_launchable_class_init (AsLaunchableClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = as_launchable_finalize;
+}
+
+
+/**
+ * as_launchable_kind_from_string:
+ * @kind: the string.
+ *
+ * Converts the text representation to an enumerated value.
+ *
+ * Returns: (transfer full): a #AsLaunchableKind, or %AS_LAUNCHABLE_KIND_UNKNOWN for unknown.
+ *
+ * Since: 0.6.13
+ **/
+AsLaunchableKind
+as_launchable_kind_from_string (const gchar *kind)
+{
+ if (g_strcmp0 (kind, "desktop-id") == 0)
+ return AS_LAUNCHABLE_KIND_DESKTOP_ID;
+ return AS_LAUNCHABLE_KIND_UNKNOWN;
+}
+
+/**
+ * as_launchable_kind_to_string:
+ * @kind: the #AsLaunchableKind.
+ *
+ * Converts the enumerated value to an text representation.
+ *
+ * Returns: string version of @kind
+ *
+ * Since: 0.6.13
+ **/
+const gchar *
+as_launchable_kind_to_string (AsLaunchableKind kind)
+{
+ if (kind == AS_LAUNCHABLE_KIND_DESKTOP_ID)
+ return "desktop-id";
+ return NULL;
+}
+
+/**
+ * as_launchable_get_value:
+ * @launchable: a #AsLaunchable instance.
+ *
+ * Gets the value to use for the launchable.
+ *
+ * Returns: usually a desktop ID, e.g. "gimp.desktop"
+ *
+ * Since: 0.6.13
+ **/
+const gchar *
+as_launchable_get_value (AsLaunchable *launchable)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ return priv->value;
+}
+
+/**
+ * as_launchable_get_kind:
+ * @launchable: a #AsLaunchable instance.
+ *
+ * Gets the launchable kind.
+ *
+ * Returns: the #AsLaunchableKind
+ *
+ * Since: 0.6.13
+ **/
+AsLaunchableKind
+as_launchable_get_kind (AsLaunchable *launchable)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ return priv->kind;
+}
+
+/**
+ * as_launchable_set_value:
+ * @launchable: a #AsLaunchable instance.
+ * @value: the URL.
+ *
+ * Sets the fully-qualified mirror URL to use for the launchable.
+ *
+ * Since: 0.6.13
+ **/
+void
+as_launchable_set_value (AsLaunchable *launchable, const gchar *value)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ as_ref_string_assign_safe (&priv->value, value);
+}
+
+/**
+ * as_launchable_set_kind:
+ * @launchable: a #AsLaunchable instance.
+ * @kind: the #AsLaunchableKind, e.g. %AS_LAUNCHABLE_KIND_DESKTOP_ID.
+ *
+ * Sets the launchable kind.
+ *
+ * Since: 0.6.13
+ **/
+void
+as_launchable_set_kind (AsLaunchable *launchable, AsLaunchableKind kind)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ priv->kind = kind;
+}
+
+/**
+ * as_launchable_node_insert: (skip)
+ * @launchable: a #AsLaunchable instance.
+ * @parent: the parent #GNode to use..
+ * @ctx: the #AsNodeContext
+ *
+ * Inserts the launchable into the DOM tree.
+ *
+ * Returns: (transfer none): A populated #GNode
+ *
+ * Since: 0.6.13
+ **/
+GNode *
+as_launchable_node_insert (AsLaunchable *launchable, GNode *parent, AsNodeContext *ctx)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ GNode *n = as_node_insert (parent, "launchable",
+ priv->value,
+ AS_NODE_INSERT_FLAG_NONE,
+ NULL);
+ if (priv->kind != AS_LAUNCHABLE_KIND_UNKNOWN)
+ as_node_add_attribute (n, "type", as_launchable_kind_to_string (priv->kind));
+ return n;
+}
+
+/**
+ * as_launchable_node_parse_dep11:
+ * @launchable: a #AsLaunchable 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.3.0
+ **/
+gboolean
+as_launchable_node_parse_dep11 (AsLaunchable *launchable, GNode *node,
+ AsNodeContext *ctx, GError **error)
+{
+ return TRUE;
+}
+
+/**
+ * as_launchable_node_parse:
+ * @launchable: a #AsLaunchable 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.13
+ **/
+gboolean
+as_launchable_node_parse (AsLaunchable *launchable, GNode *node,
+ AsNodeContext *ctx, GError **error)
+{
+ AsLaunchablePrivate *priv = GET_PRIVATE (launchable);
+ priv->kind = as_launchable_kind_from_string (as_node_get_attribute (node, "type"));
+ as_ref_string_assign (&priv->value, as_node_get_data_as_refstr (node));
+ return TRUE;
+}
+
+/**
+ * as_launchable_new:
+ *
+ * Creates a new #AsLaunchable.
+ *
+ * Returns: (transfer full): a #AsLaunchable
+ *
+ * Since: 0.6.13
+ **/
+AsLaunchable *
+as_launchable_new (void)
+{
+ AsLaunchable *launchable;
+ launchable = g_object_new (AS_TYPE_LAUNCHABLE, NULL);
+ return AS_LAUNCHABLE (launchable);
+}
diff --git a/libappstream-glib/as-launchable.h b/libappstream-glib/as-launchable.h
new file mode 100644
index 0000000..800cf89
--- /dev/null
+++ b/libappstream-glib/as-launchable.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 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_LAUNCHABLE_H
+#define __AS_LAUNCHABLE_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define AS_TYPE_LAUNCHABLE (as_launchable_get_type ())
+G_DECLARE_DERIVABLE_TYPE (AsLaunchable, as_launchable, AS, LAUNCHABLE, GObject)
+
+struct _AsLaunchableClass
+{
+ 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);
+};
+
+/**
+ * AsLaunchableKind:
+ * @AS_LAUNCHABLE_KIND_UNKNOWN: Type invalid or not known
+ * @AS_LAUNCHABLE_KIND_DESKTOP_ID: A desktop ID
+ *
+ * The launchable type.
+ **/
+typedef enum {
+ AS_LAUNCHABLE_KIND_UNKNOWN,
+ AS_LAUNCHABLE_KIND_DESKTOP_ID, /* Since: 0.6.13 */
+ /*< private >*/
+ AS_LAUNCHABLE_KIND_LAST
+} AsLaunchableKind;
+
+AsLaunchable *as_launchable_new (void);
+
+/* helpers */
+AsLaunchableKind as_launchable_kind_from_string (const gchar *kind);
+const gchar *as_launchable_kind_to_string (AsLaunchableKind kind);
+
+/* getters */
+const gchar *as_launchable_get_value (AsLaunchable *launchable);
+AsLaunchableKind as_launchable_get_kind (AsLaunchable *launchable);
+
+/* setters */
+void as_launchable_set_value (AsLaunchable *launchable,
+ const gchar *value);
+void as_launchable_set_kind (AsLaunchable *launchable,
+ AsLaunchableKind kind);
+
+G_END_DECLS
+
+#endif /* __AS_LAUNCHABLE_H */
diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c
index 782f9be..3e9a872 100644
--- a/libappstream-glib/as-self-test.c
+++ b/libappstream-glib/as-self-test.c
@@ -41,6 +41,7 @@
#include "as-monitor.h"
#include "as-node-private.h"
#include "as-problem.h"
+#include "as-launchable-private.h"
#include "as-provide-private.h"
#include "as-ref-string.h"
#include "as-release-private.h"
@@ -566,6 +567,48 @@ as_test_provide_func (void)
}
static void
+as_test_launchable_func (void)
+{
+ GError *error = NULL;
+ AsNode *n;
+ AsNode *root;
+ GString *xml;
+ const gchar *src = "<launchable type=\"desktop-id\">gnome-software.desktop</launchable>";
+ gboolean ret;
+ g_autoptr(AsNodeContext) ctx = NULL;
+ g_autoptr(AsLaunchable) launchable = NULL;
+
+ launchable = as_launchable_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, "launchable");
+ g_assert (n != NULL);
+ ctx = as_node_context_new ();
+ ret = as_launchable_node_parse (launchable, n, ctx, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ as_node_unref (root);
+
+ /* verify */
+ g_assert_cmpint (as_launchable_get_kind (launchable), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ g_assert_cmpstr (as_launchable_get_value (launchable), ==, "gnome-software.desktop");
+
+ /* back to node */
+ root = as_node_new ();
+ as_node_context_set_version (ctx, 0.4);
+ n = as_launchable_node_insert (launchable, root, ctx);
+ xml = as_node_to_xml (n, AS_NODE_TO_XML_FLAG_NONE);
+ 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_release_appstream_func (void)
{
AsChecksum *csum;
@@ -1591,6 +1634,7 @@ as_test_app_func (void)
AsIcon *ic;
AsBundle *bu;
AsRelease *rel;
+ AsLaunchable *lau;
GError *error = NULL;
AsNode *n;
AsNode *root;
@@ -1666,6 +1710,7 @@ as_test_app_func (void)
"<dbus type=\"session\">org.gnome.Software</dbus>\n"
"<dbus type=\"system\">org.gnome.Software2</dbus>\n"
"</provides>\n"
+ "<launchable type=\"desktop-id\">gnome-software.desktop</launchable>\n"
"<languages>\n"
"<lang percentage=\"90\">en_GB</lang>\n"
"<lang>pl</lang>\n"
@@ -1707,6 +1752,7 @@ as_test_app_func (void)
g_assert_cmpint (as_app_get_priority (app), ==, -4);
g_assert_cmpint (as_app_get_screenshots(app)->len, ==, 2);
g_assert_cmpint (as_app_get_releases(app)->len, ==, 2);
+ g_assert_cmpint (as_app_get_launchables(app)->len, ==, 1);
g_assert_cmpint (as_app_get_provides(app)->len, ==, 3);
g_assert_cmpint (as_app_get_kudos(app)->len, ==, 1);
g_assert_cmpint (as_app_get_permissions(app)->len, ==, 1);
@@ -1742,6 +1788,12 @@ as_test_app_func (void)
g_assert_cmpint (as_bundle_get_kind (bu), ==, AS_BUNDLE_KIND_FLATPAK);
g_assert_cmpstr (as_bundle_get_id (bu), ==, "app/org.gnome.Software/x86_64/master");
+ /* check launchable */
+ lau = as_app_get_launchable_by_kind (app, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ g_assert (lau != NULL);
+ g_assert_cmpint (as_launchable_get_kind (lau), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ g_assert_cmpstr (as_launchable_get_value (lau), ==, "gnome-software.desktop");
+
/* check we can get a specific icon */
ic = as_app_get_icon_for_size (app, 999, 999);
g_assert (ic == NULL);
@@ -1771,6 +1823,43 @@ as_test_app_func (void)
}
static void
+as_test_app_launchable_fallback_func (void)
+{
+ AsLaunchable *lau;
+ AsNode *n;
+ gboolean ret;
+ const gchar *src =
+ "<component type=\"desktop\">\n"
+ "<id>org.gnome.Software</id>\n"
+ "</component>\n";
+ g_autoptr(AsApp) app = NULL;
+ g_autoptr(AsNodeContext) ctx = NULL;
+ g_autoptr(AsNode) root = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = as_app_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, "component");
+ g_assert (n != NULL);
+ ctx = as_node_context_new ();
+ ret = as_app_node_parse (app, n, ctx, &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ /* verify */
+ g_assert_cmpstr (as_app_get_id (app), ==, "org.gnome.Software");
+ g_assert_cmpint (as_app_get_launchables(app)->len, ==, 1);
+ lau = as_app_get_launchable_by_kind (app, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ g_assert (lau != NULL);
+ g_assert_cmpint (as_launchable_get_kind (lau), ==, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ g_assert_cmpstr (as_launchable_get_value (lau), ==, "org.gnome.Software.desktop");
+}
+
+static void
as_test_app_validate_check (GPtrArray *array,
AsProblemKind kind,
const gchar *message)
@@ -5304,6 +5393,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/utils{locale-compat}", as_test_utils_locale_compat_func);
g_test_add_func ("/AppStream/utils{string-replace}", as_test_utils_string_replace_func);
g_test_add_func ("/AppStream/tag", as_test_tag_func);
+ g_test_add_func ("/AppStream/launchable", as_test_launchable_func);
g_test_add_func ("/AppStream/provide", as_test_provide_func);
g_test_add_func ("/AppStream/require", as_test_require_func);
g_test_add_func ("/AppStream/checksum", as_test_checksum_func);
@@ -5323,6 +5413,7 @@ main (int argc, char **argv)
g_test_add_func ("/AppStream/image{alpha}", as_test_image_alpha_func);
g_test_add_func ("/AppStream/screenshot", as_test_screenshot_func);
g_test_add_func ("/AppStream/app", as_test_app_func);
+ g_test_add_func ("/AppStream/app{launchable:fallback}", as_test_app_launchable_fallback_func);
g_test_add_func ("/AppStream/app{builder:gettext}", as_test_app_builder_gettext_func);
g_test_add_func ("/AppStream/app{builder:gettext-nodomain}", as_test_app_builder_gettext_nodomain_func);
g_test_add_func ("/AppStream/app{builder:qt}", as_test_app_builder_qt_func);
diff --git a/libappstream-glib/as-tag.c b/libappstream-glib/as-tag.c
index 3929791..d089f68 100644
--- a/libappstream-glib/as-tag.c
+++ b/libappstream-glib/as-tag.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2014-2016 Richard Hughes <richard@hughsie.com>
+ * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com>
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -190,6 +190,7 @@ as_tag_to_string (AsTag tag)
"suggests",
"requires",
"custom",
+ "launchable",
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 f002ee0..b090d49 100644
--- a/libappstream-glib/as-tag.gperf
+++ b/libappstream-glib/as-tag.gperf
@@ -66,3 +66,4 @@ reviewer_id, AS_TAG_REVIEWER_ID
suggests, AS_TAG_SUGGESTS
requires, AS_TAG_REQUIRES
custom, AS_TAG_CUSTOM
+launchable, AS_TAG_LAUNCHABLE
diff --git a/libappstream-glib/as-tag.h b/libappstream-glib/as-tag.h
index 2fa91e6..adb7c79 100644
--- a/libappstream-glib/as-tag.h
+++ b/libappstream-glib/as-tag.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2014-2016 Richard Hughes <richard@hughsie.com`
+ * Copyright (C) 2014-2017 Richard Hughes <richard@hughsie.com`
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
@@ -91,6 +91,7 @@ G_BEGIN_DECLS
* @AS_TAG_SUGGESTS: `suggests`
* @AS_TAG_REQUIRES: `requires`
* @AS_TAG_CUSTOM: `custom`
+ * @AS_TAG_LAUNCHABLE: `launchable`
*
* The tag type.
**/
@@ -154,6 +155,7 @@ typedef enum {
AS_TAG_SUGGESTS, /* Since: 0.6.1 */
AS_TAG_REQUIRES, /* Since: 0.6.7 */
AS_TAG_CUSTOM, /* Since: 0.6.8 */
+ AS_TAG_LAUNCHABLE, /* Since: 0.6.13 */
/*< private >*/
AS_TAG_LAST
} AsTag;