[gnome-software/wip/hughsie/xdg-app: 3/3] Add initial xdg-app support



commit 1199488029f2cd5d90763701f95a35ca82d70545
Author: Richard Hughes <richard hughsie com>
Date:   Mon Feb 2 10:41:53 2015 +0000

    Add initial xdg-app support

 configure.ac                       |   17 ++
 src/gs-cmd.c                       |   12 +-
 src/gs-plugin-loader-sync.c        |   48 +++++
 src/gs-plugin-loader-sync.h        |    4 +
 src/gs-plugin-loader.c             |  109 ++++++++++
 src/gs-plugin-loader.h             |    8 +
 src/gs-plugin.h                    |    8 +
 src/plugins/Makefile.am            |   12 +
 src/plugins/gs-plugin-appstream.c  |    2 +
 src/plugins/gs-plugin-packagekit.c |    3 +
 src/plugins/gs-plugin-xdg-app.c    |  412 ++++++++++++++++++++++++++++++++++++
 11 files changed, 634 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 2c30e6f..2db39c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -104,6 +104,22 @@ AS_IF([test "x$enable_firmware" != "xno"], [
     have_firmware=no
 ])
 
+# xdg-app
+AC_ARG_ENABLE(xdg-app,
+              [AS_HELP_STRING([--enable-xdg-app],
+                              [enable xdg-app support [default=auto]])],,
+              enable_xdg_app=maybe)
+
+AS_IF([test "x$enable_xdg_app" != "xno"], [
+    PKG_CHECK_MODULES(XDG_APP,
+                      [xdg-app],
+                      [have_xdg_app=yes],
+                      [have_xdg_app=no])
+], [
+    have_xdg_app=no
+])
+AM_CONDITIONAL(HAVE_XDG_APP, test "$have_xdg_app" != no)
+
 AS_IF([test "x$have_firmware" = "xyes"], [
     AC_DEFINE(HAVE_FIRMWARE,1,[Build firmware support])
 ], [
@@ -182,5 +198,6 @@ echo "
         cppflags:                  ${CPPFLAGS}
         Dogtail:                   ${enable_dogtail}
         Firmware support:          ${have_firmware}
+        XDG-APP support:           ${have_xdg_app}
 "
 
diff --git a/src/gs-cmd.c b/src/gs-cmd.c
index a23d0ef..3e013d4 100644
--- a/src/gs-cmd.c
+++ b/src/gs-cmd.c
@@ -298,6 +298,16 @@ main (int argc, char **argv)
                                break;
                }
                gs_plugin_add_app (&list, app);
+       } else if (argc == 3 && g_strcmp0 (argv[1], "launch") == 0) {
+               app = gs_app_new (argv[2]);
+               for (i = 0; i < repeat; i++) {
+                       ret = gs_plugin_loader_app_launch (plugin_loader,
+                                                          app,
+                                                          NULL,
+                                                          &error);
+                       if (!ret)
+                               break;
+               }
        } else if (argc == 3 && g_strcmp0 (argv[1], "filename-to-app") == 0) {
                app = gs_plugin_loader_filename_to_app (plugin_loader,
                                                        argv[2],
@@ -417,7 +427,7 @@ main (int argc, char **argv)
                                     "Did not recognise option, use 'installed', "
                                     "'updates', 'popular', 'get-categories', "
                                     "'get-category-apps', 'filename-to-app', "
-                                    "'sources', 'refresh' or 'search'");
+                                    "'sources', 'refresh', 'launch' or 'search'");
        }
        if (!ret) {
                g_print ("Failed: %s\n", error->message);
diff --git a/src/gs-plugin-loader-sync.c b/src/gs-plugin-loader-sync.c
index 254b8b9..f50fc9b 100644
--- a/src/gs-plugin-loader-sync.c
+++ b/src/gs-plugin-loader-sync.c
@@ -515,6 +515,54 @@ gs_plugin_loader_app_refine (GsPluginLoader *plugin_loader,
 }
 
 /**
+ * gs_plugin_loader_app_launch_finish_sync:
+ **/
+static void
+gs_plugin_loader_app_launch_finish_sync (GsPluginLoader *plugin_loader,
+                                        GAsyncResult *res,
+                                        GsPluginLoaderHelper *helper)
+{
+       helper->ret = gs_plugin_loader_app_launch_finish (plugin_loader,
+                                                         res,
+                                                         helper->error);
+       g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_app_launch:
+ **/
+gboolean
+gs_plugin_loader_app_launch (GsPluginLoader *plugin_loader,
+                            GsApp *app,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       GsPluginLoaderHelper helper;
+
+       /* create temp object */
+       helper.context = g_main_context_new ();
+       helper.loop = g_main_loop_new (helper.context, FALSE);
+       helper.error = error;
+
+       g_main_context_push_thread_default (helper.context);
+
+       /* run async method */
+       gs_plugin_loader_app_launch_async (plugin_loader,
+                                          app,
+                                          cancellable,
+                                          (GAsyncReadyCallback) gs_plugin_loader_app_launch_finish_sync,
+                                          &helper);
+       g_main_loop_run (helper.loop);
+
+       g_main_context_pop_thread_default (helper.context);
+
+       g_main_loop_unref (helper.loop);
+       g_main_context_unref (helper.context);
+
+       return helper.ret;
+}
+
+/**
  * gs_plugin_loader_app_action_finish_sync:
  **/
 static void
diff --git a/src/gs-plugin-loader-sync.h b/src/gs-plugin-loader-sync.h
index b1b88ec..90d65c0 100644
--- a/src/gs-plugin-loader-sync.h
+++ b/src/gs-plugin-loader-sync.h
@@ -71,6 +71,10 @@ gboolean      gs_plugin_loader_app_refine            (GsPluginLoader *plugin_loader,
                                                         GsPluginRefineFlags flags,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
+gboolean        gs_plugin_loader_app_launch            (GsPluginLoader *plugin_loader,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
 gboolean        gs_plugin_loader_app_action            (GsPluginLoader *plugin_loader,
                                                         GsApp          *app,
                                                         GsPluginLoaderAction action,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 0c3cdb8..eb2ce6a 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -346,6 +346,37 @@ out:
 }
 
 /**
+ * gs_plugin_loader_run_launch:
+ **/
+static gboolean
+gs_plugin_loader_run_launch (GsPluginLoader *plugin_loader,
+                            GsApp *app,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
+       GsPluginLaunchFunc plugin_func = NULL;
+       GsPlugin *plugin;
+       gboolean ret = TRUE;
+       guint i;
+
+       /* run each plugin */
+       for (i = 0; i < priv->plugins->len; i++) {
+               plugin = g_ptr_array_index (priv->plugins, i);
+               if (!plugin->enabled)
+                       continue;
+               if (!g_module_symbol (plugin->module,
+                                     "gs_plugin_launch",
+                                     (gpointer *) &plugin_func))
+                       continue;
+               ret = plugin_func (plugin, app, cancellable, error);
+               if (!ret)
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/**
  * gs_plugin_loader_run_results_plugin:
  **/
 static gboolean
@@ -2304,6 +2335,84 @@ gs_plugin_loader_app_refine_finish (GsPluginLoader *plugin_loader,
 
 /******************************************************************************/
 
+/**
+ * gs_plugin_loader_app_launch_thread_cb:
+ **/
+static void
+gs_plugin_loader_app_launch_thread_cb (GTask *task,
+                                      gpointer object,
+                                      gpointer task_data,
+                                      GCancellable *cancellable)
+{
+       GError *error = NULL;
+       GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) task_data;
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+       gboolean ret;
+
+       ret = gs_plugin_loader_run_launch (plugin_loader,
+                                          state->app,
+                                          cancellable,
+                                          &error);
+       if (!ret) {
+               g_task_return_error (task, error);
+               return;
+       }
+
+       /* success */
+       g_task_return_boolean (task, TRUE);
+}
+
+/**
+ * gs_plugin_loader_app_launch_async:
+ *
+ * This method calls all plugins that implement the gs_plugin_launch()
+ * function.
+ **/
+void
+gs_plugin_loader_app_launch_async (GsPluginLoader *plugin_loader,
+                                  GsApp *app,
+                                  GCancellable *cancellable,
+                                  GAsyncReadyCallback callback,
+                                  gpointer user_data)
+{
+       GsPluginLoaderAsyncState *state;
+       g_autoptr(GTask) task = NULL;
+
+       g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+       g_return_if_fail (GS_IS_APP (app));
+       g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+       /* save state */
+       state = g_slice_new0 (GsPluginLoaderAsyncState);
+       state->app = g_object_ref (app);
+
+       /* run in a thread */
+       task = g_task_new (plugin_loader, cancellable, callback, user_data);
+       g_task_set_task_data (task, state, (GDestroyNotify) gs_plugin_loader_free_async_state);
+       g_task_set_return_on_cancel (task, TRUE);
+       g_task_run_in_thread (task, gs_plugin_loader_app_launch_thread_cb);
+}
+
+/**
+ * gs_plugin_loader_app_launch_finish:
+ *
+ * Return value: success
+ **/
+gboolean
+gs_plugin_loader_app_launch_finish (GsPluginLoader *plugin_loader,
+                                   GAsyncResult *res,
+                                   GError **error)
+{
+       g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), FALSE);
+       g_return_val_if_fail (G_IS_TASK (res), FALSE);
+       g_return_val_if_fail (g_task_is_valid (res, plugin_loader), FALSE);
+       g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+       return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+/******************************************************************************/
+
 static gboolean
 emit_pending_apps_idle (gpointer loader)
 {
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index dd034f1..133760c 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -198,6 +198,14 @@ void                gs_plugin_loader_app_refine_async      (GsPluginLoader 
*plugin_loader,
 gboolean        gs_plugin_loader_app_refine_finish     (GsPluginLoader *plugin_loader,
                                                         GAsyncResult   *res,
                                                         GError         **error);
+void            gs_plugin_loader_app_launch_async      (GsPluginLoader *plugin_loader,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer        user_data);
+gboolean        gs_plugin_loader_app_launch_finish     (GsPluginLoader *plugin_loader,
+                                                        GAsyncResult   *res,
+                                                        GError         **error);
 void            gs_plugin_loader_app_action_async      (GsPluginLoader *plugin_loader,
                                                         GsApp          *app,
                                                         GsPluginLoaderAction a,
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index ebb8a26..09c86ec 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -142,6 +142,10 @@ typedef gboolean    (*GsPluginRefineFunc)          (GsPlugin       *plugin,
                                                         GsPluginRefineFlags flags,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
+typedef gboolean        (*GsPluginLaunchFunc)          (GsPlugin       *plugin,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
 typedef gboolean        (*GsPluginRefreshFunc  )       (GsPlugin       *plugin,
                                                         guint           cache_age,
                                                         GsPluginRefreshFlags flags,
@@ -240,6 +244,10 @@ gboolean    gs_plugin_refine                       (GsPlugin       *plugin,
                                                         GsPluginRefineFlags flags,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
+gboolean        gs_plugin_launch                       (GsPlugin       *plugin,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
 gboolean        gs_plugin_app_install                  (GsPlugin       *plugin,
                                                         GsApp          *app,
                                                         GCancellable   *cancellable,
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 756e194..d9ce48a 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -11,6 +11,7 @@ AM_CPPFLAGS =                                         \
        $(SQLITE_CFLAGS)                                \
        $(FWUPD_CFLAGS)                                 \
        $(LIMBA_CFLAGS)                                 \
+       $(XDG_APP_CFLAGS)                               \
        -DBINDIR=\"$(bindir)\"                          \
        -DDATADIR=\"$(datadir)\"                        \
        -DGS_MODULESETDIR=\"$(datadir)/gnome-software/modulesets.d\" \
@@ -50,6 +51,10 @@ if HAVE_FIRMWARE
 plugin_LTLIBRARIES += libgs_plugin_fwupd.la
 endif
 
+if HAVE_XDG_APP
+plugin_LTLIBRARIES += libgs_plugin_xdg_app.la
+endif
+
 if HAVE_LIMBA
 plugin_LTLIBRARIES += libgs_plugin_limba.la
 endif
@@ -102,6 +107,13 @@ libgs_plugin_limba_la_LDFLAGS = -module -avoid-version
 libgs_plugin_limba_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 endif
 
+if HAVE_XDG_APP
+libgs_plugin_xdg_app_la_SOURCES = gs-plugin-xdg-app.c
+libgs_plugin_xdg_app_la_LIBADD = $(GS_PLUGIN_LIBS) $(XDG_APP_LIBS)
+libgs_plugin_xdg_app_la_LDFLAGS = -module -avoid-version
+libgs_plugin_xdg_app_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+endif
+
 libgs_plugin_moduleset_la_SOURCES =                    \
        gs-moduleset.c                                  \
        gs-moduleset.h                                  \
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index 84593b4..8890437 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -98,6 +98,8 @@ gs_plugin_initialize (GsPlugin *plugin)
            gs_plugin_check_distro_id (plugin, "ubuntu")) {
                plugin->use_pkg_descriptions = TRUE;
        }
+
+gs_plugin_set_enabled(plugin, FALSE);
 }
 
 /**
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index 48841f5..541b6e9 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -54,6 +54,9 @@ gs_plugin_initialize (GsPlugin *plugin)
        pk_client_set_background (PK_CLIENT (plugin->priv->task), FALSE);
        pk_client_set_interactive (PK_CLIENT (plugin->priv->task), FALSE);
        pk_client_set_cache_age (PK_CLIENT (plugin->priv->task), G_MAXUINT);
+
+gs_plugin_set_enabled(plugin, FALSE);
+
 }
 
 /**
diff --git a/src/plugins/gs-plugin-xdg-app.c b/src/plugins/gs-plugin-xdg-app.c
new file mode 100644
index 0000000..01203cb
--- /dev/null
+++ b/src/plugins/gs-plugin-xdg-app.c
@@ -0,0 +1,412 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2015 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Notes:
+ *
+ * All GsApp's created have management-plugin set to XgdApp
+ * Some GsApp's created have have XgdApp::type of app or runtime
+ * The GsApp:origin is the remote name, e.g. test-repo
+ *
+ * Some outstanding notes:
+ *
+ * - Why xdg_app_installation_list_installed_refs() not return a GPtrArray?
+ * - How can I get the AppStream metadata using libxdgapp?
+ * - Where is the privaledge elevation helper?
+ * - Is there a faster way to get the installed apps and frameworks at the same time?
+ * - How do I get the list of updates using libxdg-app, e.g. like "xdg-app --user --updates repo-contents 
test-repo" used to work
+ * - How do I do download-not-apply when on network?
+ * - How do I do I know when an update needs network access?
+ */
+
+#include <config.h>
+
+#include <xdg-app.h>
+
+#include <gs-plugin.h>
+
+struct GsPluginPrivate {
+       XdgAppInstallation      *installation;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+       return "xdg-app";
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+       /* create private area */
+       plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+
+       /* FIXME: this should default to system-wide, but we need a permissions
+        * helper to elevate privs */
+       plugin->priv->installation = xdg_app_installation_new_user ();
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+       g_object_unref (plugin->priv->installation);
+}
+
+/**
+ * gs_plugin_add_search:
+ */
+gboolean
+gs_plugin_add_search (GsPlugin *plugin,
+                     gchar **values,
+                     GList **list,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       return TRUE;
+}
+
+/**
+ * gs_plugin_xdg_app_create_installed:
+ */
+static GsApp *
+gs_plugin_xdg_app_create_installed (XdgAppInstalledRef *app_ref)
+{
+       g_autoptr(GsApp) app = NULL;
+
+       g_return_val_if_fail (app_ref != NULL, NULL);
+
+       /*
+        * Only show the current application in GNOME Software
+        * 
+        * You can have multiple versions/branches of a particular app-id
+        * installed but only one of them is "current" where this means:
+        *  1) the default to launch unless you specify a version
+        *  2) The one that gets its exported files exported
+        */
+       if (!xdg_app_installed_ref_get_current (app_ref))
+               return NULL;
+
+       /* create new object */
+       app = gs_app_new (xdg_app_ref_get_name (XDG_APP_REF(app_ref)));
+       gs_app_set_management_plugin (app, "XgdApp");
+       gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+       gs_app_set_kind (app, GS_APP_KIND_NORMAL);
+       gs_app_set_id_kind (app, AS_ID_KIND_DESKTOP);
+       gs_app_set_version (app, xdg_app_ref_get_version (XDG_APP_REF(app_ref)));
+       gs_app_set_origin (app, xdg_app_installed_ref_get_origin (app_ref));
+
+       switch (xdg_app_ref_get_kind (XDG_APP_REF(app_ref))) {
+       case XDG_APP_REF_KIND_APP:
+               gs_app_set_metadata (app, "XgdApp::type", "app");
+               break;
+       case XDG_APP_REF_KIND_RUNTIME:
+               gs_app_set_metadata (app, "XgdApp::type", "runtime");
+               break;
+       default:
+               return NULL;
+       }
+
+       /* we need this for uninstalling */
+       gs_app_set_metadata (app, "XgdApp::arch", xdg_app_ref_get_arch (XDG_APP_REF(app_ref)));
+
+       // read AppData from here: xdg_app_installed_ref_get_deploy_dir (app_ref)
+       // xdg_app_ref_get_commit (XDG_APP_REF(app_ref)),
+
+       //FIXME need to refine using AppData/AppStream
+       gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "GNOME Builder");
+       gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "GNOME BUILDER");
+       gs_app_set_pixbuf (app, gdk_pixbuf_new_from_file 
("/usr/share/icons/hicolor/48x48/apps/gnome-boxes.png", NULL));
+
+       return g_object_ref (app);
+}
+
+/**
+ * gs_plugin_add_installed:
+ */
+gboolean
+gs_plugin_add_installed (GsPlugin *plugin,
+                        GList **list,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       XdgAppInstalledRef **apps;
+       XdgAppInstalledRef **runtimes;
+       guint i;
+
+       /* get apps */
+       apps = xdg_app_installation_list_installed_refs (plugin->priv->installation,
+                                                        XDG_APP_REF_KIND_APP,
+                                                        cancellable, error);
+       if (apps == NULL)
+               return FALSE;
+       for (i = 0; apps[i] != NULL; i++) {
+               g_autoptr(GsApp) app = NULL;
+               app = gs_plugin_xdg_app_create_installed (apps[i]);
+               if (app == NULL)
+                       continue;
+               gs_plugin_add_app (list, app);
+       }
+
+       /* get runtimes */
+       runtimes = xdg_app_installation_list_installed_refs (plugin->priv->installation,
+                                                            XDG_APP_REF_KIND_RUNTIME,
+                                                            cancellable, error);
+       if (runtimes == NULL)
+               return FALSE;
+       for (i = 0; runtimes[i] != NULL; i++) {
+               g_autoptr(GsApp) app = NULL;
+               app = gs_plugin_xdg_app_create_installed (runtimes[i]);
+               if (app == NULL)
+                       continue;
+               gs_plugin_add_app (list, app);
+       }
+
+       return TRUE;
+}
+
+/**
+ * gs_plugin_add_sources:
+ */
+gboolean
+gs_plugin_add_sources (GsPlugin *plugin,
+                      GList **list,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       XdgAppRemote **remotes;
+       guint i;
+
+       remotes = xdg_app_installation_list_remotes (plugin->priv->installation,
+                                                    cancellable,
+                                                    error);
+       if (remotes == NULL)
+               return FALSE;
+       for (i = 0; remotes[i] != NULL; i++) {
+               g_autoptr(GsApp) app = NULL;
+               app = gs_app_new (xdg_app_remote_get_name (remotes[i]));
+               gs_app_set_management_plugin (app, "XgdApp");
+               gs_app_set_kind (app, GS_APP_KIND_SOURCE);
+               gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+               gs_app_set_name (app,
+                                GS_APP_QUALITY_LOWEST,
+                                xdg_app_remote_get_name (remotes[i]));
+               gs_app_set_summary (app,
+                                   GS_APP_QUALITY_LOWEST,
+                                   xdg_app_remote_get_title (remotes[i]));
+               gs_app_set_url (app,
+                               AS_URL_KIND_HOMEPAGE,
+                               xdg_app_remote_get_url (remotes[i]));
+               gs_plugin_add_app (list, app);
+       }
+       return TRUE;
+}
+
+/**
+ * gs_plugin_add_updates:
+ */
+gboolean
+gs_plugin_add_updates (GsPlugin *plugin,
+                      GList **list,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       return TRUE;
+}
+
+/**
+ * gs_plugin_refine_item:
+ */
+static gboolean
+gs_plugin_refine_item (GsPlugin *plugin, GsApp *app, GError **error)
+{
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+               return TRUE;
+       return TRUE;
+}
+
+/**
+ * gs_plugin_refine:
+ */
+gboolean
+gs_plugin_refine (GsPlugin *plugin,
+                 GList **list,
+                 GsPluginRefineFlags flags,
+                 GCancellable *cancellable,
+                 GError **error)
+{
+       GList *l;
+       GsApp *app;
+
+       for (l = *list; l != NULL; l = l->next) {
+               app = GS_APP (l->data);
+               if (!gs_plugin_refine_item (plugin, app, error))
+                       return FALSE;
+       }
+       return TRUE;
+}
+
+/**
+ * gs_plugin_launch:
+ */
+gboolean
+gs_plugin_launch (GsPlugin *plugin,
+                 GsApp *app,
+                 GCancellable *cancellable,
+                 GError **error)
+{
+       const gchar *version = NULL;
+       g_autoptr(XdgAppInstalledRef) xapp = NULL;
+
+       version = gs_app_get_version (app);
+       if (version == NULL)
+               version = "master";
+       xapp = xdg_app_installation_get_installed_ref (plugin->priv->installation,
+                                                      XDG_APP_REF_KIND_APP,
+                                                      gs_app_get_id (app),
+                                                      NULL,
+                                                      version,
+                                                      cancellable,
+                                                      error);
+       if (xapp == NULL)
+               return FALSE;
+       return xdg_app_installed_ref_launch (xapp, cancellable, error);
+}
+
+typedef struct {
+       GsApp           *app;
+       GsPlugin        *plugin;
+} GsPluginHelper;
+
+/**
+ * gs_plugin_xdg_app_progress_cb:
+ */
+static void
+gs_plugin_xdg_app_progress_cb (const gchar *status,
+                              guint progress,
+                              gboolean estimating,
+                              gpointer user_data)
+{
+       GsPluginHelper *helper = (GsPluginHelper *) user_data;
+       gs_plugin_progress_update (helper->plugin, helper->app, progress);
+}
+
+/**
+ * gs_plugin_app_remove:
+ */
+gboolean
+gs_plugin_app_remove (GsPlugin *plugin,
+                     GsApp *app,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       GsPluginHelper helper;
+
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+               return TRUE;
+
+       /* use helper: FIXME: new()&ref? */
+       helper.app = app;
+       helper.plugin = plugin;
+
+       /* remove */
+       return xdg_app_installation_uninstall (plugin->priv->installation,
+                                              XDG_APP_REF_KIND_APP,
+                                              gs_app_get_id (app),
+                                              gs_app_get_metadata_item (app, "XgdApp::arch"),
+                                              gs_app_get_version (app),
+                                              gs_plugin_xdg_app_progress_cb, &helper,
+                                              cancellable, error);
+}
+
+/**
+ * gs_plugin_app_install:
+ */
+gboolean
+gs_plugin_app_install (GsPlugin *plugin,
+                      GsApp *app,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       GsPluginHelper helper;
+       g_autoptr(XdgAppInstalledRef) xapp = NULL;
+
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+               return TRUE;
+
+       /* use helper: FIXME: new()&ref? */
+       helper.app = app;
+       helper.plugin = plugin;
+
+       /* install */
+       xapp = xdg_app_installation_install (plugin->priv->installation,
+                                            gs_app_get_origin (app),
+                                            XDG_APP_REF_KIND_APP,
+                                            gs_app_get_id (app),
+                                            gs_app_get_metadata_item (app, "XgdApp::arch"),
+                                            gs_app_get_version (app),
+                                            gs_plugin_xdg_app_progress_cb, &helper,
+                                            cancellable, error);
+       return xapp != NULL;
+}
+
+/**
+ * gs_plugin_app_update:
+ *
+ * This is only called when updating device firmware live.
+ */
+gboolean
+gs_plugin_app_update (GsPlugin *plugin,
+                     GsApp *app,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       GsPluginHelper helper;
+       g_autoptr(XdgAppInstalledRef) xapp = NULL;
+
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+               return TRUE;
+
+       /* use helper: FIXME: new()&ref? */
+       helper.app = app;
+       helper.plugin = plugin;
+
+       /* install */
+       xapp = xdg_app_installation_update (plugin->priv->installation,
+                                           XDG_APP_REF_KIND_APP,
+                                           gs_app_get_id (app),
+                                           gs_app_get_metadata_item (app, "XgdApp::arch"),
+                                           gs_app_get_version (app),
+                                           gs_plugin_xdg_app_progress_cb, &helper,
+                                           cancellable, error);
+       return xapp != NULL;
+}


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