diff options
author | Richard Hughes <richard@hughsie.com> | 2017-04-21 10:32:33 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2017-04-21 11:05:52 +0100 |
commit | e32e245980f6f72b7f3eab6671404fbb5c78acad (patch) | |
tree | e42edeec613fd47d96d065bc84a2dc6f38f0b2a5 | |
parent | 08cb0ec129d71740c14b27f4bfd8c2fe79ad5d34 (diff) | |
download | appstream-glib-e32e245980f6f72b7f3eab6671404fbb5c78acad.tar.gz |
Add support for <launchable>
-rw-r--r-- | docs/api/appstream-glib-docs.sgml | 1 | ||||
-rw-r--r-- | libappstream-glib/Makefile.am | 5 | ||||
-rw-r--r-- | libappstream-glib/as-app.c | 157 | ||||
-rw-r--r-- | libappstream-glib/as-app.h | 12 | ||||
-rw-r--r-- | libappstream-glib/as-launchable-private.h | 48 | ||||
-rw-r--r-- | libappstream-glib/as-launchable.c | 263 | ||||
-rw-r--r-- | libappstream-glib/as-launchable.h | 82 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 91 | ||||
-rw-r--r-- | libappstream-glib/as-tag.c | 3 | ||||
-rw-r--r-- | libappstream-glib/as-tag.gperf | 1 | ||||
-rw-r--r-- | libappstream-glib/as-tag.h | 4 |
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; |