[gnome-software/1801-flatpak-is-launched-while-displaying-a-native-app] gs-plugin: Add helper function gs_plugin_app_launch_filtered()
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/1801-flatpak-is-launched-while-displaying-a-native-app] gs-plugin: Add helper function gs_plugin_app_launch_filtered()
- Date: Thu, 23 Jun 2022 08:42:45 +0000 (UTC)
commit 912d9af9f44c7b92c3d8cc8fb1e4de705df9234d
Author: Milan Crha <mcrha redhat com>
Date: Thu Jun 23 10:38:28 2022 +0200
gs-plugin: Add helper function gs_plugin_app_launch_filtered()
It can be used to pick which .desktop file should be used to launch
an application. It helps to pick the right format when an application
is installed by multiple repos/remotes, like as an RPM and as a Flatpak.
lib/gs-plugin.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/gs-plugin.h | 24 +++++++++++
2 files changed, 149 insertions(+)
---
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index 2fe17134a..c059ade99 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -892,6 +892,131 @@ gs_plugin_app_launch (GsPlugin *plugin, GsApp *app, GError **error)
return TRUE;
}
+static GDesktopAppInfo *
+check_directory_for_desktop_file (GsPlugin *plugin,
+ GsApp *app,
+ GsPluginPickDesktopFileCallback cb,
+ gpointer user_data,
+ const gchar *desktop_id,
+ const gchar *data_dir)
+{
+ g_autofree gchar *filename = NULL;
+ g_autoptr(GKeyFile) key_file = NULL;
+
+ filename = g_build_filename (data_dir, "applications", desktop_id, NULL);
+ key_file = g_key_file_new ();
+
+ if (g_key_file_load_from_file (key_file, filename, G_KEY_FILE_KEEP_TRANSLATIONS, NULL) &&
+ cb (plugin, app, filename, key_file)) {
+ g_autoptr(GDesktopAppInfo) appinfo = NULL;
+ appinfo = g_desktop_app_info_new_from_keyfile (key_file);
+ if (appinfo != NULL)
+ return g_steal_pointer (&appinfo);
+ g_debug ("Failed to load '%s' as a GDesktopAppInfo", filename);
+ return NULL;
+ }
+
+ if (!g_str_has_suffix (desktop_id, ".desktop")) {
+ g_autofree gchar *desktop_filename = g_strconcat (filename, ".desktop", NULL);
+ if (g_key_file_load_from_file (key_file, desktop_filename, G_KEY_FILE_KEEP_TRANSLATIONS,
NULL) &&
+ cb (plugin, app, desktop_filename, key_file)) {
+ g_autoptr(GDesktopAppInfo) appinfo = NULL;
+ appinfo = g_desktop_app_info_new_from_keyfile (key_file);
+ if (appinfo != NULL)
+ return g_steal_pointer (&appinfo);
+ g_debug ("Failed to load '%s' as a GDesktopAppInfo", desktop_filename);
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * gs_plugin_app_launch_filtered:
+ * @plugin: a #GsPlugin
+ * @app: a #GsApp to launch
+ * @cb: a callback to pick the correct .desktop file
+ * @user_data: (closure cb) (scope call): user data for the @cb
+ * @error: a #GError, or %NULL
+ *
+ * Launches application @app, using the .desktop file picked by the @cb.
+ * This can help in case multiple versions of the @app are installed
+ * in the system (like a Flatpak and RPM versions).
+ *
+ * Returns: %TRUE on success
+ *
+ * Since: 43
+ **/
+gboolean
+gs_plugin_app_launch_filtered (GsPlugin *plugin,
+ GsApp *app,
+ GsPluginPickDesktopFileCallback cb,
+ gpointer user_data,
+ GError **error)
+{
+ const gchar *desktop_id;
+ g_autoptr(GDesktopAppInfo) appinfo = NULL;
+
+ g_return_val_if_fail (GS_IS_PLUGIN (plugin), FALSE);
+ g_return_val_if_fail (GS_IS_APP (app), FALSE);
+ g_return_val_if_fail (cb != NULL, FALSE);
+
+ desktop_id = gs_app_get_launchable (app, AS_LAUNCHABLE_KIND_DESKTOP_ID);
+ if (desktop_id == NULL)
+ desktop_id = gs_app_get_id (app);
+ if (desktop_id == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no desktop file for app: %s",
+ gs_app_get_name (app));
+ return FALSE;
+ }
+
+ /* First, the configs. Highest priority: the user's ~/.config */
+ appinfo = check_directory_for_desktop_file (plugin, app, cb, user_data, desktop_id,
g_get_user_config_dir ());
+
+ if (appinfo == NULL) {
+ /* Next, the system configs (/etc/xdg, and so on). */
+ const gchar * const *dirs;
+ dirs = g_get_system_config_dirs ();
+ for (guint i = 0; dirs[i] && appinfo == NULL; i++) {
+ appinfo = check_directory_for_desktop_file (plugin, app, cb, user_data, desktop_id,
dirs[i]);
+ }
+ }
+
+ if (appinfo == NULL) {
+ /* Now the data. Highest priority: the user's ~/.local/share/applications */
+ appinfo = check_directory_for_desktop_file (plugin, app, cb, user_data, desktop_id,
g_get_user_data_dir ());
+ }
+
+ if (appinfo == NULL) {
+ /* Following that, XDG_DATA_DIRS/applications, in order */
+ const gchar * const *dirs;
+ dirs = g_get_system_data_dirs ();
+ for (guint i = 0; dirs[i] && appinfo == NULL; i++) {
+ appinfo = check_directory_for_desktop_file (plugin, app, cb, user_data, desktop_id,
dirs[i]);
+ }
+ }
+
+ if (appinfo == NULL) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "no appropriate desktop file found: %s",
+ desktop_id);
+ return FALSE;
+ }
+
+ g_idle_add_full (G_PRIORITY_DEFAULT,
+ gs_plugin_app_launch_cb,
+ g_object_ref (appinfo),
+ (GDestroyNotify) g_object_unref);
+
+ return TRUE;
+}
+
static void
weak_ref_free (GWeakRef *weak)
{
diff --git a/lib/gs-plugin.h b/lib/gs-plugin.h
index 709819799..412b2e734 100644
--- a/lib/gs-plugin.h
+++ b/lib/gs-plugin.h
@@ -208,6 +208,30 @@ void gs_plugin_status_update (GsPlugin *plugin,
gboolean gs_plugin_app_launch (GsPlugin *plugin,
GsApp *app,
GError **error);
+typedef gboolean (* GsPluginPickDesktopFileCallback) (GsPlugin *plugin,
+ GsApp *app,
+ const gchar *filename,
+ GKeyFile *key_file);
+/**
+ * GsPluginPickDesktopFileCallback:
+ * @plugin: a #GsPlugin
+ * @app: a #GsApp
+ * @filename: a .desktop file name
+ * @key_file: a #GKeyFile with @filename loaded
+ *
+ * A callback used by gs_plugin_app_launch_filtered() to filter which
+ * of the candidate .desktop files should be used to launch the @app.
+ *
+ * Returns: %TRUE, when the @key_file should be used, %FALSE to continue
+ * searching.
+ *
+ * Since: 43
+ **/
+gboolean gs_plugin_app_launch_filtered (GsPlugin *plugin,
+ GsApp *app,
+ GsPluginPickDesktopFileCallback cb,
+ gpointer user_data,
+ GError **error);
void gs_plugin_updates_changed (GsPlugin *plugin);
void gs_plugin_reload (GsPlugin *plugin);
const gchar *gs_plugin_status_to_string (GsPluginStatus status);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]