[gnome-software] Move the launch action to the plugin loader
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Move the launch action to the plugin loader
- Date: Tue, 22 Dec 2015 09:12:16 +0000 (UTC)
commit 15b6e5d07cc75003321b570e35c7353ca1049499
Author: Richard Hughes <richard hughsie com>
Date: Tue Dec 22 09:05:42 2015 +0000
Move the launch action to the plugin loader
This allows to handle different kinds of application in the future (e.g. for
xdg-apps) and possibly also allows us to handle web-apps in a smarter way.
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/gs-shell-details.c | 40 +++++++-------
src/plugins/gs-plugin-epiphany.c | 42 ++++++++++++++
src/plugins/gs-plugin-packagekit.c | 42 ++++++++++++++
9 files changed, 292 insertions(+), 21 deletions(-)
---
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 5d13889..d938d27 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -348,6 +348,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
@@ -2306,6 +2337,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 0c9ae09..aa30144 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -143,6 +143,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,
@@ -241,6 +245,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/gs-shell-details.c b/src/gs-shell-details.c
index 2c2c57f..da20d1b 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -24,7 +24,6 @@
#include <string.h>
#include <glib/gi18n.h>
-#include <gio/gdesktopappinfo.h>
#include <appstream-glib.h>
#include "gs-utils.h"
@@ -1201,31 +1200,32 @@ gs_shell_details_addon_selected_cb (GsAppAddonRow *row,
}
/**
- * gs_shell_details_app_launch_button_cb:
+ * gs_shell_details_filename_to_app_cb:
**/
static void
-gs_shell_details_app_launch_button_cb (GtkWidget *widget, GsShellDetails *self)
+gs_shell_details_app_launch_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
- GdkDisplay *display;
- const gchar *desktop_id;
+ GsShellDetails *self = GS_SHELL_DETAILS (user_data);
g_autoptr(GError) error = NULL;
- g_autoptr(GAppInfo) appinfo = NULL;
- g_autoptr(GAppLaunchContext) context = NULL;
-
- desktop_id = gs_app_get_id (self->app);
- if (desktop_id == NULL) {
- g_warning ("no such desktop file: %s", desktop_id);
+ if (!gs_plugin_loader_app_launch_finish (self->plugin_loader, res, &error)) {
+ g_warning ("failed to launch GsApp: %s", error->message);
return;
}
- appinfo = G_APP_INFO (g_desktop_app_info_new (desktop_id));
- if (appinfo == NULL) {
- g_warning ("no such desktop file: %s", desktop_id);
- return;
- }
- display = gdk_display_get_default ();
- context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display));
- if (!g_app_info_launch (appinfo, NULL, context, &error))
- g_warning ("launching %s failed: %s", desktop_id, error->message);
+}
+
+/**
+ * gs_shell_details_app_launch_button_cb:
+ **/
+static void
+gs_shell_details_app_launch_button_cb (GtkWidget *widget, GsShellDetails *self)
+{
+ gs_plugin_loader_app_launch_async (self->plugin_loader,
+ self->app,
+ self->cancellable,
+ gs_shell_details_app_launch_cb,
+ self);
}
/**
diff --git a/src/plugins/gs-plugin-epiphany.c b/src/plugins/gs-plugin-epiphany.c
index 1d32afb..c711efb 100644
--- a/src/plugins/gs-plugin-epiphany.c
+++ b/src/plugins/gs-plugin-epiphany.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <glib/gi18n.h>
+#include <gio/gdesktopappinfo.h>
#include <libsoup/soup.h>
#include <gs-plugin.h>
@@ -295,3 +296,44 @@ gs_plugin_refine (GsPlugin *plugin,
}
return TRUE;
}
+
+/**
+ * gs_plugin_launch:
+ */
+gboolean
+gs_plugin_launch (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GdkDisplay *display;
+ const gchar *desktop_id;
+ g_autoptr(GAppInfo) appinfo = NULL;
+ g_autoptr(GAppLaunchContext) context = NULL;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "Epiphany") != 0)
+ return TRUE;
+
+ desktop_id = gs_app_get_id (app);
+ if (desktop_id == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no such desktop file: %s",
+ desktop_id);
+ return FALSE;
+ }
+ appinfo = G_APP_INFO (g_desktop_app_info_new (desktop_id));
+ if (appinfo == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no such desktop file: %s",
+ desktop_id);
+ return FALSE;
+ }
+ display = gdk_display_get_default ();
+ context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display));
+ return g_app_info_launch (appinfo, NULL, context, error);
+}
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index 48841f5..4269827 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -24,6 +24,7 @@
#define I_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE
#include <packagekit-glib2/packagekit.h>
#include <glib/gi18n.h>
+#include <gio/gdesktopappinfo.h>
#include <gs-plugin.h>
@@ -692,3 +693,44 @@ gs_plugin_add_search_what_provides (GsPlugin *plugin,
/* add results */
return gs_plugin_packagekit_add_results (plugin, list, results, error);
}
+
+/**
+ * gs_plugin_launch:
+ */
+gboolean
+gs_plugin_launch (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GdkDisplay *display;
+ const gchar *desktop_id;
+ g_autoptr(GAppInfo) appinfo = NULL;
+ g_autoptr(GAppLaunchContext) context = NULL;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "PackageKit") != 0)
+ return TRUE;
+
+ desktop_id = gs_app_get_id (app);
+ if (desktop_id == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no such desktop file: %s",
+ desktop_id);
+ return FALSE;
+ }
+ appinfo = G_APP_INFO (g_desktop_app_info_new (desktop_id));
+ if (appinfo == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no such desktop file: %s",
+ desktop_id);
+ return FALSE;
+ }
+ display = gdk_display_get_default ();
+ context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display));
+ return g_app_info_launch (appinfo, NULL, context, error);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]