[gnome-software/mwleeds/pwa-plugin: 3/3] Fix epiphany self test




commit 41e62c5085fcaa7174a851965719eef98b327cd1
Author: Phaedrus Leeds <mwleeds protonmail com>
Date:   Fri Feb 25 20:39:52 2022 -0800

    Fix epiphany self test
    
    Use libglib-testing to mock responses from the portal and WebAppProvider
    D-Bus services, and test the epiphany plugin's ability to list installed
    apps.

 .gitlab-ci.yml                                     |   2 +-
 .gitlab-ci/fedora.Dockerfile                       |   1 +
 plugins/epiphany/gs-plugin-epiphany.c              |  38 ++-
 plugins/epiphany/gs-self-test.c                    | 223 +++++++++++---
 plugins/epiphany/meson.build                       |  25 ++
 .../org.freedesktop.portal.DynamicLauncher.xml     | 332 +++++++++++++++++++++
 subprojects/libglib-testing.wrap                   |   2 +-
 7 files changed, 558 insertions(+), 65 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index daf689856..65d9f2ab8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -20,7 +20,7 @@ variables:
 
 fedora-x86_64:
   extends: .build
-  image: registry.gitlab.gnome.org/gnome/gnome-software/fedora:v9
+  image: registry.gitlab.gnome.org/gnome/gnome-software/fedora:v10
   stage: build
   except:
     - tags
diff --git a/.gitlab-ci/fedora.Dockerfile b/.gitlab-ci/fedora.Dockerfile
index 08813fd7c..beea19a90 100644
--- a/.gitlab-ci/fedora.Dockerfile
+++ b/.gitlab-ci/fedora.Dockerfile
@@ -33,6 +33,7 @@ RUN dnf -y install \
     libcurl-devel \
     libdnf-devel \
     libepoxy-devel \
+    libglib-testing-devel \
     libgudev-devel \
     libjpeg-turbo-devel \
     liboauth-devel \
diff --git a/plugins/epiphany/gs-plugin-epiphany.c b/plugins/epiphany/gs-plugin-epiphany.c
index 58e139a23..9472b11b8 100644
--- a/plugins/epiphany/gs-plugin-epiphany.c
+++ b/plugins/epiphany/gs-plugin-epiphany.c
@@ -15,6 +15,7 @@
 
 #include "gs-epiphany-generated.h"
 #include "gs-plugin-epiphany.h"
+#include "gs-plugin-private.h"
 
 /*
  * SECTION:
@@ -157,19 +158,23 @@ setup_thread_cb (GTask        *task,
        g_autofree gchar *name_owner = NULL;
        g_autoptr(GError) local_error = NULL;
        g_autoptr(GVariant) version = NULL;
+       GDBusConnection *connection;
 
        assert_in_worker (self);
 
+       connection = gs_plugin_get_session_bus_connection (GS_PLUGIN (self));
+       g_assert (connection != NULL);
+
        /* Check that the proxy exists (and is owned; it should auto-start) so
         * we can disable the plugin for systems which don’t have new enough
         * Epiphany.
         */
-       self->epiphany_proxy = gs_ephy_web_app_provider_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
-                                                                               G_DBUS_PROXY_FLAGS_NONE,
-                                                                               
"org.gnome.Epiphany.WebAppProvider",
-                                                                               
"/org/gnome/Epiphany/WebAppProvider",
-                                                                               g_task_get_cancellable (task),
-                                                                               &local_error);
+       self->epiphany_proxy = gs_ephy_web_app_provider_proxy_new_sync (connection,
+                                                                       G_DBUS_PROXY_FLAGS_NONE,
+                                                                       "org.gnome.Epiphany.WebAppProvider",
+                                                                       "/org/gnome/Epiphany/WebAppProvider",
+                                                                       g_task_get_cancellable (task),
+                                                                       &local_error);
        if (self->epiphany_proxy == NULL) {
                gs_epiphany_error_convert (&local_error);
                g_task_return_error (task, g_steal_pointer (&local_error));
@@ -184,14 +189,14 @@ setup_thread_cb (GTask        *task,
        }
 
        /* Check if the dynamic launcher portal is available and disable otherwise */
-       self->launcher_portal_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
-                                                                    
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
-                                                                    NULL,
-                                                                    "org.freedesktop.portal.Desktop",
-                                                                    "/org/freedesktop/portal/desktop",
-                                                                    "org.freedesktop.portal.DynamicLauncher",
-                                                                    g_task_get_cancellable (task),
-                                                                    &local_error);
+       self->launcher_portal_proxy = g_dbus_proxy_new_sync (connection,
+                                                            G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
+                                                            NULL,
+                                                            "org.freedesktop.portal.Desktop",
+                                                            "/org/freedesktop/portal/desktop",
+                                                            "org.freedesktop.portal.DynamicLauncher",
+                                                            g_task_get_cancellable (task),
+                                                            &local_error);
        if (self->launcher_portal_proxy == NULL) {
                gs_epiphany_error_convert (&local_error);
                g_task_return_error (task, g_steal_pointer (&local_error));
@@ -456,8 +461,9 @@ list_installed_apps_thread_cb (GTask        *task,
                g_debug ("%s: Working on installed web app %s", G_STRFUNC, desktop_file_id);
 
                desktop_info = g_desktop_app_info_new (desktop_file_id);
+
                if (desktop_info == NULL) {
-                       g_warning ("Epiphany returned a non-existent desktop ID %s", desktop_file_id);
+                       g_warning ("Epiphany returned a non-existent or invalid desktop ID %s", 
desktop_file_id);
                        continue;
                }
 
@@ -514,6 +520,8 @@ list_installed_apps_thread_cb (GTask        *task,
                        const char *x;
                        guint64 size = 0;
 
+                       g_debug ("%s: finding size for icon %s", G_STRFUNC, icon_path);
+
                        g_clear_object (&file_info);
                        file_info = g_file_query_info (icon_file,
                                                       G_FILE_ATTRIBUTE_STANDARD_SIZE,
diff --git a/plugins/epiphany/gs-self-test.c b/plugins/epiphany/gs-self-test.c
index 4bea3e740..49d468bbf 100644
--- a/plugins/epiphany/gs-self-test.c
+++ b/plugins/epiphany/gs-self-test.c
@@ -12,34 +12,175 @@
 #include "gnome-software-private.h"
 
 #include "gs-test.h"
+#include "gs-dynamic-launcher-portal-iface.h"
+#include "gs-epiphany-generated.h"
+
+#include <libglib-testing/dbus-queue.h>
+
+/* This is run in a worker thread */
+static void
+epiphany_and_portal_mock_server_cb (GtDBusQueue *queue,
+                                   gpointer     user_data)
+{
+       {
+               g_autoptr(GDBusMethodInvocation) invocation = NULL;
+               g_autoptr(GVariant) properties_variant = NULL;
+               const char *property_interface;
+               invocation = gt_dbus_queue_assert_pop_message (queue,
+                                                              "/org/gnome/Epiphany/WebAppProvider",
+                                                              "org.freedesktop.DBus.Properties",
+                                                              "GetAll", "(&s)",
+                                                              &property_interface);
+               g_assert_cmpstr (property_interface, ==, "org.gnome.Epiphany.WebAppProvider");
+               properties_variant = g_variant_new_parsed ("({'Version': <@u 1>},)");
+               g_dbus_method_invocation_return_value (invocation, g_steal_pointer (&properties_variant));
+       }
+       {
+               g_autoptr(GDBusMethodInvocation) invocation = NULL;
+               g_autoptr(GVariant) properties_variant = NULL;
+               const char *property_interface, *props_dict;
+               invocation = gt_dbus_queue_assert_pop_message (queue,
+                                                              "/org/freedesktop/portal/desktop",
+                                                              "org.freedesktop.DBus.Properties",
+                                                              "GetAll", "(&s)",
+                                                              &property_interface);
+               g_assert_cmpstr (property_interface, ==, "org.freedesktop.portal.DynamicLauncher");
+               props_dict = "({'version': <@u 1>,'SupportedLauncherTypes': <@u 3>},)";
+               properties_variant = g_variant_new_parsed (props_dict);
+               g_dbus_method_invocation_return_value (invocation, g_steal_pointer (&properties_variant));
+       }
+       {
+               g_autoptr(GDBusMethodInvocation) invocation = NULL;
+               const char *installed_apps[] = 
{"org.gnome.Epiphany.WebApp_e9d0e1e4b0a10856aa3b38d9eb4375de4070d043.desktop", NULL};
+               invocation = gt_dbus_queue_assert_pop_message (queue,
+                                                              "/org/gnome/Epiphany/WebAppProvider",
+                                                              "org.gnome.Epiphany.WebAppProvider",
+                                                              "GetInstalledApps", "()", NULL);
+               g_dbus_method_invocation_return_value (invocation, g_variant_new ("(^as)", installed_apps));
+       }
+}
+
+static GtDBusQueue *
+bus_set_up (void)
+{
+       g_autoptr(GError) local_error = NULL;
+       g_autoptr(GtDBusQueue) queue = NULL;
+
+       queue = gt_dbus_queue_new ();
+
+       gt_dbus_queue_connect (queue, &local_error);
+       g_assert_no_error (local_error);
+
+       gt_dbus_queue_own_name (queue, "org.freedesktop.portal.Desktop");
+
+       gt_dbus_queue_export_object (queue,
+                                    "/org/freedesktop/portal/desktop",
+                                    (GDBusInterfaceInfo *) 
&org_freedesktop_portal_dynamic_launcher_interface,
+                                    &local_error);
+       g_assert_no_error (local_error);
+
+       gt_dbus_queue_own_name (queue, "org.gnome.Epiphany.WebAppProvider");
+
+       gt_dbus_queue_export_object (queue,
+                                    "/org/gnome/Epiphany/WebAppProvider",
+                                    gs_ephy_web_app_provider_interface_info (),
+                                    &local_error);
+       g_assert_no_error (local_error);
+
+       gt_dbus_queue_set_server_func (queue, epiphany_and_portal_mock_server_cb,
+                                      NULL);
+
+       return g_steal_pointer (&queue);
+}
 
 static void
 gs_plugins_epiphany_func (GsPluginLoader *plugin_loader)
 {
-       gboolean ret;
+       g_assert_true (gs_plugin_loader_get_enabled (plugin_loader, "epiphany"));
+}
+
+static char *
+create_fake_desktop_file (const char *app_id)
+{
+       g_autofree char *contents = NULL;
        g_autoptr(GError) error = NULL;
-       g_autoptr(GsApp) app = NULL;
+       g_autofree char *desktop_path = NULL;
+       g_autofree char *icon_path = NULL;
+
+       /* Use an icon we already have locally */
+       icon_path = gs_test_get_filename (TESTDATADIR, "icons/hicolor/scalable/org.gnome.Software.svg");
+       g_assert (icon_path != NULL);
+
+       /* Use true instead of epiphany in Exec and TryExec; otherwise
+        * g_desktop_app_info_new() in the plugin code will look for an
+        * epiphany binary and fail.
+        */
+       contents = g_strdup_printf ("[Desktop Entry]\n"
+               "Name=Pinafore\n"
+               "Exec=true --application-mode \"--profile=/home/nobody/.local/share/%s\" 
https://pinafore.social/\n";
+               "StartupNotify=true\n"
+               "Terminal=false\n"
+               "Type=Application\n"
+               "Categories=GNOME;GTK;\n"
+               "Icon=%s\n"
+               "StartupWMClass=%s\n"
+               "X-Purism-FormFactor=Workstation;Mobile;\n"
+               "TryExec=true\n",
+               app_id, icon_path, app_id);
+
+       desktop_path = g_strconcat (g_get_user_data_dir (), G_DIR_SEPARATOR_S,
+                                   "applications", G_DIR_SEPARATOR_S,
+                                   app_id, ".desktop", NULL);
+
+       g_debug ("Creating a fake desktop file at path: %s", desktop_path);
+       gs_mkdir_parent (desktop_path, &error);
+       g_assert_no_error (error);
+       g_file_set_contents (desktop_path, contents, -1, &error);
+       g_assert_no_error (error);
+
+       return g_steal_pointer (&desktop_path);
+}
+
+static void
+gs_plugins_epiphany_installed_func (GsPluginLoader *plugin_loader)
+{
        g_autoptr(GsPluginJob) plugin_job = NULL;
-       GsPlugin *plugin;
-
-       /* no epiphany, abort */
-       if (!gs_plugin_loader_get_enabled (plugin_loader, "epiphany"))
-               return;
-
-       /* a webapp with a local icon */
-       app = gs_app_new ("app.squoosh.webapp.desktop");
-       gs_app_set_kind (app, AS_COMPONENT_KIND_WEB_APP);
-       plugin = gs_plugin_loader_find_plugin (plugin_loader, "epiphany");
-       gs_app_set_management_plugin (app, plugin);
-       plugin_job = gs_plugin_job_refine_new_for_app (app,
-                                                      GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON);
-       ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
+       g_autoptr(GError) error = NULL;
+       g_autoptr(GIcon) icon = NULL;
+       g_autoptr(GsAppList) list = NULL;
+       GsApp *app;
+       const char *app_id = "org.gnome.Epiphany.WebApp_e9d0e1e4b0a10856aa3b38d9eb4375de4070d043";
+       g_autofree char *app_id_desktop = NULL;
+       g_autofree char *desktop_path = NULL;
+       g_autofree char *origin_ui = NULL;
+
+       app_id_desktop = g_strdup_printf ("%s.desktop", app_id);
+       desktop_path = create_fake_desktop_file (app_id);
+
+       plugin_job = gs_plugin_job_list_installed_apps_new (GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN,
+                                                           0, GS_PLUGIN_JOB_DEDUPE_FLAGS_DEFAULT,
+                                                           GS_PLUGIN_LIST_INSTALLED_APPS_FLAGS_NONE);
+       list = gs_plugin_loader_job_process (plugin_loader, plugin_job, NULL, &error);
        gs_test_flush_main_context ();
        g_assert_no_error (error);
-       g_assert_true (ret);
+       g_assert_nonnull (list);
+
+       g_assert_cmpint (gs_app_list_length (list), ==, 1);
+       app = gs_app_list_index (list, 0);
+       g_assert_cmpstr (gs_app_get_id (app), ==, app_id_desktop);
+       g_assert_cmpint (gs_app_get_kind (app), ==, AS_COMPONENT_KIND_WEB_APP);
+       g_assert_cmpint (gs_app_get_scope (app), ==, AS_COMPONENT_SCOPE_USER);
+       g_assert_cmpint (gs_app_get_state (app), ==, GS_APP_STATE_INSTALLED);
+       g_assert_cmpstr (gs_app_get_name (app), ==, "Pinafore");
+       g_assert_cmpstr (gs_app_get_summary (app), ==, "pinafore.social");
+       g_assert_cmpstr (gs_app_get_origin (app), ==, "gnome-web");
+       origin_ui = gs_app_get_origin_ui (app);
+       g_assert_cmpstr (origin_ui, ==, "GNOME Web");
+       icon = gs_app_get_icon_for_size (app, 4096, 1, NULL);
+       g_assert_nonnull (icon);
+       g_clear_object (&icon);
 
-       g_assert_cmpint (gs_app_get_state (app), ==, GS_APP_STATE_AVAILABLE);
-       g_assert_nonnull (gs_app_get_icons (app));
+       gs_utils_unlink (desktop_path, NULL);
 }
 
 int
@@ -50,43 +191,24 @@ main (int argc, char **argv)
        g_autofree gchar *xml = NULL;
        g_autoptr(GError) error = NULL;
        g_autoptr(GsPluginLoader) plugin_loader = NULL;
+       g_autoptr(GtDBusQueue) queue = NULL;
+       int res;
        const gchar *allowlist[] = {
-               "appstream",
                "epiphany",
                "icons",
                NULL
        };
 
-       g_test_init (&argc, &argv, NULL);
-       g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+       gs_test_init (&argc, &argv);
        g_setenv ("GS_XMLB_VERBOSE", "1", TRUE);
 
-       /* Use an icon we already have locally */
-       fn = gs_test_get_filename (TESTDATADIR, "icons/hicolor/scalable/org.gnome.Software.svg");
-       g_assert (fn != NULL);
-       xml = g_strdup_printf ("<?xml version=\"1.0\"?>\n"
-               "<components version=\"0.14\">\n"
-               "  <component type=\"webapp\">\n"
-               "    <id>app.squoosh.webapp.desktop</id>\n"
-               "    <metadata_license>CC0-1.0</metadata_license>\n"
-               "    <project_license>Apache-2.0</project_license>\n"
-               "    <name>Squoosh</name>\n"
-               "    <summary>Compress and compare images with different codecs, right in your 
browser</summary>\n"
-               "    <launchable type=\"url\">https://squoosh.app/</launchable>\n"
-               "    <icon type=\"remote\">file://%s</icon>\n"
-               "    <categories>\n"
-               "      <category>Utility</category>\n"
-               "    </categories>\n"
-               "    <pkgname>test</pkgname>\n"
-               "  </component>\n"
-               "  <info>\n"
-               "    <scope>user</scope>\n"
-               "  </info>\n"
-               "</components>\n", fn);
-       g_setenv ("GS_SELF_TEST_APPSTREAM_XML", xml, TRUE);
+       /* Set up mock D-Bus services for the Epiphany WebAppProvider and the
+        * DynamicLauncher portal
+        */
+       queue = bus_set_up ();
 
        /* we can only load this once per process */
-       plugin_loader = gs_plugin_loader_new ();
+       plugin_loader = gs_plugin_loader_new (gt_dbus_queue_get_client_connection (queue), NULL);
        gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR);
        gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR_CORE);
        ret = gs_plugin_loader_setup (plugin_loader,
@@ -98,9 +220,14 @@ main (int argc, char **argv)
        g_assert_true (ret);
 
        /* plugin tests go here */
-       g_test_add_data_func ("/gnome-software/plugins/epiphany",
+       g_test_add_data_func ("/gnome-software/plugins/epiphany/enabled",
                              plugin_loader,
                              (GTestDataFunc) gs_plugins_epiphany_func);
+       g_test_add_data_func ("/gnome-software/plugins/epiphany/installed",
+                             plugin_loader,
+                             (GTestDataFunc) gs_plugins_epiphany_installed_func);
 
-       return g_test_run ();
+       res = g_test_run ();
+       gt_dbus_queue_disconnect (queue, TRUE);
+       return res;
 }
diff --git a/plugins/epiphany/meson.build b/plugins/epiphany/meson.build
index 61457b3ff..1ae98eb6f 100644
--- a/plugins/epiphany/meson.build
+++ b/plugins/epiphany/meson.build
@@ -37,6 +37,27 @@ i18n.merge_file(
 )
 
 if get_option('tests')
+  # The DynamicLauncher interface xml comes from:
+  # https://github.com/flatpak/xdg-desktop-portal/blob/main/data/org.freedesktop.portal.DynamicLauncher.xml
+  gdbus_codegen = find_program('gdbus-codegen')
+  dynamic_launcher_portal_iface_h = custom_target(
+    'gs-dynamic-launcher-portal-iface.h',
+    input: ['org.freedesktop.portal.DynamicLauncher.xml'],
+    output: ['gs-dynamic-launcher-portal-iface.h'],
+    command: [gdbus_codegen,
+              '--interface-info-header',
+              '--output', '@OUTPUT@',
+              '@INPUT@'],
+  )
+  dynamic_launcher_portal_iface_c = custom_target(
+    'gs-dynamic-launcher-portal-iface.c',
+    input: ['org.freedesktop.portal.DynamicLauncher.xml'],
+    output: ['gs-dynamic-launcher-portal-iface.c'],
+    command: [gdbus_codegen,
+              '--interface-info-body',
+              '--output', '@OUTPUT@',
+              '@INPUT@'],
+  )
   cargs += ['-DLOCALPLUGINDIR="' + meson.current_build_dir() + '"']
   cargs += ['-DLOCALPLUGINDIR_CORE="' + meson.current_build_dir() + '/../core"']
   cargs += ['-DTESTDATADIR="' + join_paths(meson.current_source_dir(), '..', '..', 'data') + '"']
@@ -45,6 +66,9 @@ if get_option('tests')
     compiled_schemas,
     sources : [
       'gs-self-test.c',
+      dynamic_launcher_portal_iface_c,
+      dynamic_launcher_portal_iface_h,
+      epiphany_generated,
     ],
     include_directories : [
       include_directories('../..'),
@@ -52,6 +76,7 @@ if get_option('tests')
     ],
     dependencies : [
       plugin_libs,
+      dependency('glib-testing-0', fallback: ['libglib-testing', 'libglib_testing_dep']),
     ],
     link_with : [
       libgnomesoftware,
diff --git a/plugins/epiphany/org.freedesktop.portal.DynamicLauncher.xml 
b/plugins/epiphany/org.freedesktop.portal.DynamicLauncher.xml
new file mode 100644
index 000000000..65aa90e1f
--- /dev/null
+++ b/plugins/epiphany/org.freedesktop.portal.DynamicLauncher.xml
@@ -0,0 +1,332 @@
+<?xml version="1.0"?>
+<!--
+ Copyright (C) 2021 Matthew Leeds
+
+ 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 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, see <http://www.gnu.org/licenses/>.
+
+ Author: Matthew Leeds <mwleeds protonmail com>
+-->
+
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd";>
+  <!--
+      org.freedesktop.portal.DynamicLauncher:
+      @short_description: Portal for installing application launchers onto the
+        desktop
+
+      The DynamicLauncher portal allows sandboxed (or unsandboxed) applications
+      to install launchers (.desktop files) which have an icon associated with them
+      and which execute a command in the application. The desktop environment
+      would display the launcher to the user in its menu of installed applications.
+      For example this can be used by a sandboxed browser to install web app
+      launchers. The portal also allows apps to uninstall the launchers, launch
+      them, and read the desktop file and icon data for them.
+
+      The standard way to install a launcher is to use the PrepareInstall() method
+      which results in a dialog being presented to the user so they can confirm
+      they want to install the launcher. Then, the token returned by PrepareInstall()
+      would be passed to the Install() method to complete the installation.
+
+      However, in the rare circumstance that an unsandboxed process such as a
+      system component needs to install a launcher without user interaction, this
+      can be accomplished by using the RequestInstallToken() method and passing
+      the acquired token to Install().
+
+      This documentation describes version 1 of this interface.
+  -->
+  <interface name="org.freedesktop.portal.DynamicLauncher">
+    <!--
+        Install:
+        @token: Token proving authorization of the installation
+        @desktop_file_id: The .desktop file name to be used
+        @desktop_entry: The text of the Desktop Entry file to be installed, see below
+        @options: Vardict with optional further information
+
+        Installs a .desktop launcher and icon into appropriate directories to
+        allow the desktop environment to find them. Please note that this method
+        overwrites any existing launcher with the same id. If you want to
+        present the user with a confirmation dialog in that case, you can check
+        for it using the GetDesktopEntry() method and clean up any state from
+        the previous launcher if you want.
+
+        @token must be a token that was returned by a previous
+        org.freedesktop.portal.DynamicLauncher.PrepareInstall() or
+        org.freedesktop.portal.DynamicLauncher.RequestInstallToken() call.
+        The token can only be used once and is valid for up to five minutes.
+
+        The icon and name used for the launcher will be the ones from the previous
+        org.freedesktop.portal.DynamicLauncher.PrepareInstall() or
+        org.freedesktop.portal.DynamicLauncher.RequestInstallToken() call.
+
+        The @desktop_file_id must have ".desktop" as a suffix. Except in the
+        special case when the calling process has no associated app ID,
+        @desktop_file_id must have the app ID followed by a period as a prefix,
+        regardless of whether the calling process is sandboxed or unsandboxed.
+
+        The @desktop_entry should be a valid desktop entry file beginning with
+        "[Desktop Entry]", except it should not include Name= or Icon= entries
+        (if present, these will be overwritten by the portal implementation).
+        The Exec= entry will be rewritten to call the sandboxed application e.g.
+        via "flatpak run", if the application is sandboxed.
+
+        It is recommended to include a TryExec= line with either a binary name
+        or an absolute path. The launcher will be deleted if the TryExec binary
+        cannot be found on session start.
+
+        The @options vardict currently has no supported entries.
+    -->
+    <method name="Install">
+      <arg type="s" name="token" direction="in"/>
+      <arg type="s" name="desktop_file_id" direction="in"/>
+      <arg type="s" name="desktop_entry" direction="in"/>
+      <arg type="a{sv}" name="options" direction="in"/>
+    </method>
+    <!--
+        PrepareInstall:
+        @parent_window: Identifier for the application window, see <link linkend="parent_window">Common 
Conventions</link>
+        @name: The default name for the launcher
+        @icon_v: A #GBytesIcon icon as returned by g_icon_serialize(). Must be
+          a png or jpeg no larger than 512x512, or an svg
+        @options: Vardict with optional further information
+        @handle: Object path for the #org.freedesktop.portal.Request object representing this call
+
+        Presents a dialog to the user to allow them to see the icon, potentially
+        change the name, and confirm installation of the launcher.
+
+        Supported keys in the @options vardict:
+        <variablelist>
+          <varlistentry>
+            <term>handle_token s</term>
+            <listitem><para>
+              A string that will be used as the last element of the @handle. Must be a valid
+              object path element. See the #org.freedesktop.portal.Request documentation for
+              more information about the @handle.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>modal b</term>
+            <listitem><para>
+              Whether to make the dialog modal. Defaults to yes.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>launcher_type u</term>
+            <listitem><para>
+              The type of launcher being created. For supported values see the
+              SupportedLauncherTypes property. Defaults to "Application".
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>target s</term>
+            <listitem><para>
+              For a launcher of type "Webapp", this is the URL of the web app
+              being installed. This is displayed in the user-facing dialog.
+              For other launcher types, this is not needed.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>editable_name b</term>
+            <listitem><para>
+              If true, the user will be able to edit the name of the launcher.
+              Defaults to true.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>editable_icon b</term>
+            <listitem><para>
+              If true, the user will be able to edit the icon of the launcher,
+              if the implementation supports this. Defaults to false.
+            </para></listitem>
+          </varlistentry>
+        </variablelist>
+
+        The following results get returned via the #org.freedesktop.portal.Request::Response signal:
+        <variablelist>
+          <varlistentry>
+            <term>name s</term>
+            <listitem><para>
+              The name chosen by the user for the launcher.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term>token s</term>
+            <listitem><para>
+              Token that can be passed to a subsequent org.freedesktop.portal.DynamicLauncher.Install() call 
to
+              complete the installation without another dialog.
+            </para></listitem>
+          </varlistentry>
+        </variablelist>
+    -->
+    <method name="PrepareInstall">
+      <arg type="s" name="parent_window" direction="in"/>
+      <arg type="s" name="name" direction="in"/>
+      <arg type="v" name="icon_v" direction="in"/>
+      <arg type="a{sv}" name="options" direction="in"/>
+      <arg type="o" name="handle" direction="out"/>
+    </method>
+    <!--
+        RequestInstallToken:
+        @name: The name that will be used in the desktop file
+        @icon_v: A #GBytesIcon icon as returned by g_icon_serialize(). Must be
+          a png or jpeg no larger than 512x512, or an svg
+        @options: Vardict with optional further information
+        @token: the token to be used with the Install() method
+
+        This method is intended for use only by specific components that
+        have their application ID allowlisted in the portal backend (e.g. GNOME
+        Software and KDE Discover). It is otherwise not guaranteed to work.
+
+        The token returned by this method can be used to avoid the need for a
+        confirmation dialog; the token can be passed to the Install() method
+        just as if it were acquired via the PrepareInstall() method.
+
+        The @options vardict currently has no supported entries.
+    -->
+    <method name="RequestInstallToken">
+      <arg type="s" name="name" direction="in"/>
+      <arg type="v" name="icon_v" direction="in"/>
+      <arg type="a{sv}" name="options" direction="in"/>
+      <arg type="s" name="token" direction="out"/>
+    </method>
+    <!--
+        Uninstall:
+        @desktop_file_id: The .desktop file name
+        @options: Vardict with optional further information
+
+        This method deletes the desktop file and corresponding icon from the
+        appropriate directories to remove the launcher referred to by
+        @desktop_file_id.
+
+        The @desktop_file_id must have ".desktop" as a suffix. Except in the
+        special case when the calling process has no associated app ID,
+        @desktop_file_id must have the app ID followed by a period as a prefix,
+        regardless of whether the calling process is sandboxed or unsandboxed.
+
+        For example, Epiphany, which has the app ID "org.gnome.Epiphany"
+        in stable builds, might use a @desktop_file_id like
+        "org.gnome.Epiphany.WebApp_e9d0e1e4b0a10856aa3b38d9eb4375de4070d043.desktop"
+        In that example the desktop file would exist at the path
+        
"~/.local/share/xdg-desktop-portal/applications/org.gnome.Epiphany.WebApp_e9d0e1e4b0a10856aa3b38d9eb4375de4070d043.desktop"
+        with a sym link in "~/.local/share/applications/".
+        The checksum at the end of the file name is an implementation detail in
+        Epiphany and not required by the portal.
+
+        This method is intended to be called by the application that created the
+        launcher, e.g. a web browser, so it can clean up associated data as part
+        of the uninstallation. Consequently, the proper way for a software center
+        to remove a launcher is by using the APIs provided by the application
+        that installed it. For example, for GNOME Software to remove web
+        launchers created by Epiphany, it would use the
+        org.gnome.Epiphany.WebAppProvider D-Bus interface.
+
+        Please note that this method call will fail if the specified launcher
+        already does not exist.
+
+        The @options vardict currently has no supported entries.
+    -->
+    <method name="Uninstall">
+      <arg type="s" name="desktop_file_id" direction="in"/>
+      <arg type="a{sv}" name="options" direction="in"/>
+    </method>
+    <!--
+        GetDesktopEntry:
+        @desktop_file_id: The .desktop file name
+        @contents: the contents of the named .desktop file
+
+        This function returns the contents of a desktop file with the name
+        @desktop_file_id in @contents.
+
+        The @desktop_file_id must have ".desktop" as a suffix. Except in the
+        special case when the calling process has no associated app ID,
+        @desktop_file_id must have the app ID followed by a period as a prefix.
+
+        This method only works for desktop files that were created by the
+        dynamic launcher portal.
+    -->
+    <method name="GetDesktopEntry">
+      <arg type="s" name="desktop_file_id" direction="in"/>
+      <arg type="s" name="contents" direction="out"/>
+    </method>
+    <!--
+        GetIcon:
+        @desktop_file_id: The .desktop file name
+        @icon_v: the icon as a serialized #GBytesIcon
+        @icon_format: one of "png", "jpeg", "svg"
+        @icon_size: the width and height in pixels of the icon
+
+        This function returns the contents of the icon specified in the "Icon"
+        key of the desktop file with the name @desktop_file_id in @icon_v. The
+        icon #GVariant can be passed to g_icon_deserialize() to reconstruct the
+        #GIcon.
+
+        The @desktop_file_id must have ".desktop" as a suffix. Except in the
+        special case when the calling process has no associated app ID,
+        @desktop_file_id must have the app ID followed by a period as a prefix.
+
+        The format and size of the icon are returned in @icon_format and
+        @icon_size. For svg icons, @icon_size is currently always set to 4096,
+        but don't depend on that as it may change in the future.
+
+        This method only works for desktop files that were created by the
+        dynamic launcher portal.
+    -->
+    <method name="GetIcon">
+      <arg type="s" name="desktop_file_id" direction="in"/>
+      <arg type="v" name="icon_v" direction="out"/>
+      <arg type="s" name="icon_format" direction="out"/>
+      <arg type="u" name="icon_size" direction="out"/>
+    </method>
+    <!--
+        Launch:
+        @desktop_file_id: The .desktop file name
+        @options: Vardict with optional further onformation
+
+        This function launches the app specified by @desktop_file_id.
+
+        The @desktop_file_id must have ".desktop" as a suffix. Except in the
+        special case when the calling process has no associated app ID,
+        @desktop_file_id must have the app ID followed by a period as a prefix.
+
+        This method only works for desktop files that were created by the
+        dynamic launcher portal.
+
+        Supported keys in the @options vardict include:
+        <variablelist>
+          <varlistentry>
+            <term>activation_token s</term>
+            <listitem><para>
+              A token that can be used to activate the chosen application.
+            </para><para>
+              The activation_token option was introduced in version 1 of the interface.
+            </para></listitem>
+          </varlistentry>
+        </variablelist>
+    -->
+    <method name="Launch">
+      <arg type="s" name="desktop_file_id" direction="in"/>
+      <arg type="a{sv}" name="options" direction="in"/>
+    </method>
+    <!--
+        SupportedLauncherTypes:
+
+        A bitmask of available launcher types. Currently defined types are:
+
+        <simplelist>
+          <member>1: Application. A launcher that represents an application.</member>
+          <member>2: Webapp. A launcher that represents a web app.</member>
+        </simplelist>
+    -->
+    <property name="SupportedLauncherTypes" type="u" access="read"/>
+    <property name="version" type="u" access="read"/>
+  </interface>
+</node>
diff --git a/subprojects/libglib-testing.wrap b/subprojects/libglib-testing.wrap
index ffb33614b..e3c06f2e8 100644
--- a/subprojects/libglib-testing.wrap
+++ b/subprojects/libglib-testing.wrap
@@ -1,5 +1,5 @@
 [wrap-git]
 directory = libglib-testing
 url = https://gitlab.gnome.org/pwithnall/libglib-testing.git
-revision = 0.1.0
+revision = 0.1.1
 depth = 1


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