[epiphany/mwleeds/webapp-dbus-api: 68/69] Use portals for web app install/uninstall




commit 405cc7a1e2e4bf09061341a1735011a85dc9467c
Author: Phaedrus Leeds <mwleeds protonmail com>
Date:   Tue Jan 25 20:10:44 2022 -0800

    Use portals for web app install/uninstall
    
    This makes use of the new dynamic launcher portal
    (https://github.com/flatpak/xdg-desktop-portal/pull/696) to install and
    uninstall web apps. This means we are able to support web apps now in
    Flatpak'd Epiphany. Unfortunately it's hard to test though so for
    now remove the unit tests.
    
    Disable the app manager feature under Flatpak since it's hard to
    implement (e.g. the portal doesn't provide access to installed apps'
    icons) but we don't need it since Software will be able to
    install/uninstall these web apps.

 lib/ephy-file-helpers.c                    |  16 +-
 lib/ephy-file-helpers.h                    |   2 +-
 lib/ephy-flatpak-utils.c                   |  38 +++
 lib/ephy-flatpak-utils.h                   |   1 +
 lib/ephy-web-app-utils.c                   | 164 +++++------
 lib/ephy-web-app-utils.h                   |  10 +-
 src/ephy-header-bar.c                      |   8 +-
 src/ephy-main.c                            |  18 +-
 src/ephy-shell.c                           |   4 +-
 src/meson.build                            |   3 +-
 src/resources/gtk/shortcuts-dialog.ui      |   2 +-
 src/webapp-provider/ephy-webapp-provider.c |   9 +-
 src/window-commands.c                      | 435 +++++++++++++----------------
 tests/meson.build                          |  23 +-
 14 files changed, 376 insertions(+), 357 deletions(-)
---
diff --git a/lib/ephy-file-helpers.c b/lib/ephy-file-helpers.c
index 0dab7a72c..69bfff639 100644
--- a/lib/ephy-file-helpers.c
+++ b/lib/ephy-file-helpers.c
@@ -575,19 +575,27 @@ launch_application (GAppInfo *app,
 
 /**
  * ephy_file_launch_webapp_desktop_file:
- * @filename: the path to the .desktop file of a web app
+ * @app_id: the id of a web app
  *
- * Launches the application described by the desktop file @filename.
+ * Launches the application described by the id @app_id
  *
  * Returns: %TRUE if the application launch was successful
  **/
 gboolean
-ephy_file_launch_webapp_desktop_file (const char *filename,
+ephy_file_launch_webapp_desktop_file (const char *app_id,
                                       guint32     user_time)
 {
   g_autoptr (GDesktopAppInfo) app = NULL;
+  g_autoptr (GKeyFile) key_file = NULL;
+  g_autoptr(GError) error = NULL;
 
-  app = g_desktop_app_info_new_from_filename (filename);
+  key_file = ephy_web_application_get_desktop_keyfile (app_id, &error);
+  if (key_file == NULL) {
+    g_warning ("Failed to get key file for app %s: %s", app_id, error->message);
+    return FALSE;
+  }
+
+  app = g_desktop_app_info_new_from_keyfile (key_file);
 
   return launch_application (G_APP_INFO (app), NULL, user_time);
 }
diff --git a/lib/ephy-file-helpers.h b/lib/ephy-file-helpers.h
index 16e5f0e0b..e0e716a73 100644
--- a/lib/ephy-file-helpers.h
+++ b/lib/ephy-file-helpers.h
@@ -68,7 +68,7 @@ gboolean           ephy_file_delete_dir_recursively         (const char
 char       *       ephy_sanitize_filename                   (char                  *filename);
 void               ephy_open_default_instance_window        (void);
 void               ephy_open_incognito_window               (const char            *uri);
-gboolean           ephy_file_launch_webapp_desktop_file     (const char            *filepath,
+gboolean           ephy_file_launch_webapp_desktop_file     (const char            *app_id,
                                                              guint32                user_time);
 gboolean           ephy_file_open_uri_in_default_browser    (const char            *uri,
                                                              guint32                user_time,
diff --git a/lib/ephy-flatpak-utils.c b/lib/ephy-flatpak-utils.c
index 49aca00cd..425d69e1f 100644
--- a/lib/ephy-flatpak-utils.c
+++ b/lib/ephy-flatpak-utils.c
@@ -132,3 +132,41 @@ ephy_open_uri_via_flatpak_portal (const char *uri)
 {
   ephy_open_uri (uri, FALSE);
 }
+
+gboolean
+ephy_can_install_web_apps (void)
+{
+  static gsize portal_available = 0;
+  enum {
+    LAUNCHER_PORTAL_MISSING = 1,
+    LAUNCHER_PORTAL_FOUND = 2
+  };
+
+  if (g_once_init_enter (&portal_available)) {
+    g_autoptr(GDBusProxy) proxy = NULL;
+    g_autoptr(GVariant) version = NULL;
+    g_autoptr(GVariant) version_child = NULL;
+    g_autoptr(GVariant) version_grandchild = NULL;
+
+    proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL,
+                                           "org.freedesktop.portal.Desktop",
+                                           "/org/freedesktop/portal/desktop",
+                                           "org.freedesktop.DBus.Properties",
+                                           NULL, NULL);
+    if (proxy)
+      version = g_dbus_proxy_call_sync (proxy, "Get",
+                                        g_variant_new ("(ss)", "org.freedesktop.portal.DynamicLauncher", 
"version"),
+                                        G_DBUS_CALL_FLAGS_NONE,
+                                        -1, NULL, NULL);
+    if (version) {
+      version_child = g_variant_get_child_value (version, 0);
+      version_grandchild = g_variant_get_child_value (version_child, 0);
+      g_debug ("Found version %d of the dynamic launcher portal", g_variant_get_uint32 (version_grandchild));
+      g_once_init_leave (&portal_available, LAUNCHER_PORTAL_FOUND);
+    } else {
+      g_once_init_leave (&portal_available, LAUNCHER_PORTAL_MISSING);
+    }
+  }
+
+  return portal_available == LAUNCHER_PORTAL_FOUND;
+}
diff --git a/lib/ephy-flatpak-utils.h b/lib/ephy-flatpak-utils.h
index 15b85ac9b..289663efb 100644
--- a/lib/ephy-flatpak-utils.h
+++ b/lib/ephy-flatpak-utils.h
@@ -30,3 +30,4 @@ void     ephy_open_uri_via_flatpak_portal                (const char *uri);
 
 void     ephy_open_directory_via_flatpak_portal          (const char *uri);
 
+gboolean ephy_can_install_web_apps                       (void);
diff --git a/lib/ephy-web-app-utils.c b/lib/ephy-web-app-utils.c
index 07792b2ae..1a05e1840 100644
--- a/lib/ephy-web-app-utils.c
+++ b/lib/ephy-web-app-utils.c
@@ -1,6 +1,7 @@
 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /*
  *  Copyright © 2011 Igalia S.L.
+ *  Copyright © 2022 Matthew Leeds
  *
  *  This file is part of Epiphany.
  *
@@ -33,6 +34,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
+#include <libportal-gtk3/portal-gtk3.h>
 
 /* Web apps are installed in the default data dir of the user. Every
  * app has its own profile directory. To create a web app, an ID needs
@@ -183,7 +185,7 @@ ephy_web_application_get_config_directory (const char *id)
 
 /**
  * ephy_web_application_delete:
- * @id: the identifier of the web application do delete
+ * @id: the identifier of the web application to delete
  *
  * Deletes all the data associated with a Web Application created by
  * Epiphany.
@@ -197,9 +199,8 @@ ephy_web_application_delete (const char *id)
   g_autofree char *cache_dir = NULL;
   g_autofree char *config_dir = NULL;
   g_autofree char *desktop_file = NULL;
-  g_autofree char *desktop_path = NULL;
-  g_autoptr (GFile) launcher = NULL;
   g_autoptr (GError) error = NULL;
+  XdpPortal *portal = ephy_get_portal ();
 
   g_assert (id);
 
@@ -244,16 +245,13 @@ ephy_web_application_delete (const char *id)
     return FALSE;
   }
 
-  desktop_path = g_build_filename (g_get_user_data_dir (), "applications", desktop_file, NULL);
-  if (g_file_test (desktop_path, G_FILE_TEST_IS_SYMLINK)) {
-    launcher = g_file_new_for_path (desktop_path);
-    if (!g_file_delete (launcher, NULL, &error)) {
-      g_warning ("Failed to delete %s: %s", desktop_path, error->message);
-      return FALSE;
-    }
-    LOG ("Deleted application launcher.\n");
+  if (xdp_portal_uninstall_launcher (portal, desktop_file, &error) != 0) {
+    g_warning ("Failed to uninstall desktop file using portal: %s", error->message);
+    return FALSE;
   }
 
+  LOG ("Deleted application launcher %s.\n", desktop_file);
+
   return TRUE;
 }
 
@@ -285,32 +283,27 @@ ephy_web_application_delete_by_desktop_file_id (const char *desktop_file_id)
   return ephy_web_application_delete (id);
 }
 
-static char *
+static gboolean
 create_desktop_file (const char *id,
-                     const char *name,
                      const char *address,
                      const char *profile_dir,
-                     const char *icon_path)
+                     const char *install_token)
 {
   g_autofree char *filename = NULL;
   g_autoptr (GKeyFile) file = NULL;
   g_autofree char *exec_string = NULL;
   g_autofree char *wm_class = NULL;
-  g_autofree char *data = NULL;
-  g_autofree char *desktop_file_path = NULL;
-  g_autofree char *apps_path = NULL;
-  g_autofree char *link_path = NULL;
-  g_autoptr (GFile) link = NULL;
+  g_autofree char *desktop_entry = NULL;
   g_autoptr (GError) error = NULL;
+  XdpPortal *portal = ephy_get_portal ();
 
   g_assert (profile_dir);
 
   filename = get_app_desktop_filename (id);
   if (!filename)
-    return NULL;
+    return FALSE;
 
   file = g_key_file_new ();
-  g_key_file_set_value (file, "Desktop Entry", "Name", name);
   exec_string = g_strdup_printf ("epiphany --application-mode \"--profile=%s\" %s",
                                  profile_dir,
                                  address);
@@ -320,33 +313,23 @@ create_desktop_file (const char *id,
   g_key_file_set_value (file, "Desktop Entry", "Type", "Application");
   g_key_file_set_value (file, "Desktop Entry", "Categories", "GNOME;GTK;");
 
-  if (icon_path)
-    g_key_file_set_value (file, "Desktop Entry", "Icon", icon_path);
-
   wm_class = g_strconcat (EPHY_WEB_APP_GAPPLICATION_ID_PREFIX, id, NULL);
   g_key_file_set_value (file, "Desktop Entry", "StartupWMClass", wm_class);
 
   g_key_file_set_value (file, "Desktop Entry", "X-Purism-FormFactor", "Workstation;Mobile;");
 
-  data = g_key_file_to_data (file, NULL, NULL);
-
-  desktop_file_path = g_build_filename (profile_dir, filename, NULL);
-
-  if (!g_file_set_contents (desktop_file_path, data, -1, NULL))
-    g_clear_pointer (&desktop_file_path, g_free);
+  desktop_entry = g_key_file_to_data (file, NULL, NULL);
 
-  /* Create a symlink in XDG_DATA_DIR/applications for the Shell to
-   * pick up this application. */
-  apps_path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
-  if (ephy_ensure_dir_exists (apps_path, &error)) {
-    link_path = g_build_filename (apps_path, filename, NULL);
-    link = g_file_new_for_path (link_path);
-    g_file_make_symbolic_link (link, desktop_file_path, NULL, NULL);
-  } else {
-    g_warning ("Error creating application symlink: %s", error->message);
+  if (xdp_portal_install_launcher (portal, install_token, filename,
+                                   desktop_entry, &error) != 0) {
+    g_warning ("Failed to install desktop file %s: %s", filename, error->message);
+    ephy_file_delete_dir_recursively (profile_dir, NULL);
+    return FALSE;
   }
 
-  return g_steal_pointer (&desktop_file_path);
+  LOG ("Created application launcher %s.\n", filename);
+
+  return TRUE;
 }
 
 /**
@@ -354,45 +337,35 @@ create_desktop_file (const char *id,
  * @id: the identifier for the new web application
  * @address: the address of the new web application
  * @name: the name for the new web application
- * @icon_pixbuf: the icon for the new web application as a #GdkPixbuf
- * @icon_path: the path to the icon, used instead of @icon_pixbuf
- * @install_token: the install token acquired via portal, used for
- *   non-interactive sandboxed installation
+ * @install_token: the install token acquired via portal methods
  * @options: the options for the new web application
  *
  * Creates a new Web Application for @address.
  *
- * Returns: (transfer-full): the path to the desktop file representing the new application
+ * Returns: %TRUE on success, %FALSE on failure
  **/
-char *
+gboolean
 ephy_web_application_create (const char                *id,
                              const char                *address,
-                             const char                *name,
-                             GdkPixbuf                 *icon_pixbuf,
-                             const char                *icon_path,
                              const char                *install_token,
                              EphyWebApplicationOptions  options)
 {
   g_autofree char *app_file = NULL;
   g_autofree char *profile_dir = NULL;
-  g_autofree char *desktop_file_path = NULL;
-  g_autofree char *icon_path_owned = NULL;
   int fd;
 
-  g_return_val_if_fail (!icon_pixbuf || !icon_path, NULL);
-
   /* If there's already a WebApp profile for the contents of this
    * view, do nothing. */
   profile_dir = ephy_web_application_get_profile_directory (id);
   if (g_file_test (profile_dir, G_FILE_TEST_IS_DIR)) {
     g_warning ("Profile directory %s already exists", profile_dir);
-    return NULL;
+    return FALSE;
   }
 
   /* Create the profile directory, populate it. */
   if (g_mkdir_with_parents (profile_dir, 488) == -1) {
     g_warning ("Failed to create directory %s", profile_dir);
-    return NULL;
+    return FALSE;
   }
 
   /* Skip migration for new web apps. */
@@ -403,30 +376,17 @@ ephy_web_application_create (const char                *id,
   fd = g_open (app_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
   if (fd < 0) {
     g_warning ("Failed to create .app file: %s", g_strerror (errno));
-    return NULL;
+    return FALSE;
   }
   close (fd);
 
-  /* Write the icon to a file */
-  if (icon_pixbuf) {
-    g_autoptr (GOutputStream) stream = NULL;
-    g_autoptr (GFile) image = NULL;
-
-    icon_path_owned = g_build_filename (profile_dir, EPHY_WEB_APP_ICON_NAME, NULL);
-    image = g_file_new_for_path (icon_path_owned);
-
-    stream = (GOutputStream *)g_file_create (image, 0, NULL, NULL);
-    gdk_pixbuf_save_to_stream (icon_pixbuf, stream, "png", NULL, NULL, NULL);
-  } else {
-    icon_path_owned = g_strdup (icon_path);
-  }
-
   /* Create the deskop file. */
-  desktop_file_path = create_desktop_file (id, name, address, profile_dir, icon_path_owned);
-  if (desktop_file_path)
-    ephy_web_application_initialize_settings (profile_dir, options);
+  if (!create_desktop_file (id, address, profile_dir, install_token))
+    return FALSE;
 
-  return g_steal_pointer (&desktop_file_path);
+  ephy_web_application_initialize_settings (profile_dir, options);
+
+  return TRUE;
 }
 
 char *
@@ -487,14 +447,35 @@ ephy_web_application_ensure_for_app_info (GAppInfo *app_info)
   return g_steal_pointer (&profile_dir);
 }
 
+GKeyFile *
+ephy_web_application_get_desktop_keyfile (const char  *id,
+                                          GError     **error)
+{
+  XdpPortal *portal = ephy_get_portal ();
+  g_autofree char *desktop_basename = NULL;
+  g_autofree char *contents = NULL;
+  g_autoptr (GKeyFile) key_file = NULL;
+
+  desktop_basename = get_app_desktop_filename (id);
+  contents = xdp_portal_get_desktop_entry (portal, desktop_basename, error);
+  if (contents == NULL)
+    return NULL;
+
+  key_file = g_key_file_new ();
+  if (!g_key_file_load_from_data (key_file, contents, -1, G_KEY_FILE_NONE, error))
+    return NULL;
+
+  return g_steal_pointer (&key_file);
+}
+
 void
 ephy_web_application_setup_from_profile_directory (const char *profile_directory)
 {
   const char *gapplication_id;
   const char *id;
-  g_autofree char *desktop_basename = NULL;
-  g_autofree char *desktop_filename = NULL;
+  g_autoptr (GKeyFile) desktop_keyfile = NULL;
   g_autoptr (GDesktopAppInfo) desktop_info = NULL;
+  g_autoptr (GError) error = NULL;
 
   g_assert (profile_directory != NULL);
 
@@ -510,12 +491,17 @@ ephy_web_application_setup_from_profile_directory (const char *profile_directory
     g_error ("Failed to get app ID from GApplication ID %s", gapplication_id);
 
   /* Get display name from desktop file */
-  desktop_basename = get_app_desktop_filename (id);
-  desktop_filename = g_build_filename (profile_directory, desktop_basename, NULL);
-  desktop_info = g_desktop_app_info_new_from_filename (desktop_filename);
-  if (!desktop_info)
-    g_error ("Required desktop file not present at %s", desktop_filename);
-  g_set_application_name (g_app_info_get_name (G_APP_INFO (desktop_info)));
+  desktop_keyfile = ephy_web_application_get_desktop_keyfile (id, &error);
+  if (!desktop_keyfile) {
+    g_warning ("Required desktop file not available: %s", error->message);
+    g_clear_error (&error);
+  } else {
+    desktop_info = g_desktop_app_info_new_from_keyfile (desktop_keyfile);
+    if (!desktop_info)
+      g_warning ("Failed to create GDesktopAppInfo for keyfile");
+    else
+      g_set_application_name (g_app_info_get_name (G_APP_INFO (desktop_info)));
+  }
 }
 
 void
@@ -957,3 +943,17 @@ ephy_web_application_is_system (EphyWebApplication *app)
 
   return g_settings_get_boolean (web_app_settings, EPHY_PREFS_WEB_APP_SYSTEM);
 }
+
+char *
+ephy_web_application_get_desktop_path (const char *id)
+{
+  g_autofree char *desktop_basename = NULL;
+
+  desktop_basename = get_app_desktop_filename (id);
+
+  /* Note: we can't use g_get_user_data_dir() since that's different within
+   * Flatpak. This path, which is a sym link to the real file, will not be
+   * accessible to us in that case, but it's still useful
+   */
+  return g_build_filename (".local", "share", "applications", desktop_basename, NULL);
+}
diff --git a/lib/ephy-web-app-utils.h b/lib/ephy-web-app-utils.h
index 66414b7a1..7bf736730 100644
--- a/lib/ephy-web-app-utils.h
+++ b/lib/ephy-web-app-utils.h
@@ -58,11 +58,8 @@ char               *ephy_web_application_get_app_id_from_name (const char *name)
 
 const char         *ephy_web_application_get_gapplication_id_from_profile_directory (const char 
*profile_dir);
 
-char               *ephy_web_application_create (const char                *id,
+gboolean            ephy_web_application_create (const char                *id,
                                                  const char                *address,
-                                                 const char                *name,
-                                                 GdkPixbuf                 *icon_pixbuf,
-                                                 const char                *icon_path,
                                                  const char                *install_token,
                                                  EphyWebApplicationOptions  options);
 
@@ -78,7 +75,10 @@ void                ephy_web_application_setup_from_desktop_file (GDesktopAppInf
 
 char               *ephy_web_application_get_profile_directory (const char *id);
 
-char               *ephy_web_application_get_desktop_path (EphyWebApplication *app);
+GKeyFile           *ephy_web_application_get_desktop_keyfile (const char  *id,
+                                                              GError     **error);
+
+char               *ephy_web_application_get_desktop_path (const char *id);
 
 EphyWebApplication *ephy_web_application_for_profile_directory (const char *profile_dir);
 
diff --git a/src/ephy-header-bar.c b/src/ephy-header-bar.c
index 285288189..4502e1e0b 100644
--- a/src/ephy-header-bar.c
+++ b/src/ephy-header-bar.c
@@ -311,8 +311,6 @@ ephy_header_bar_constructed (GObject *object)
   } else if (ephy_is_running_inside_sandbox ()) {
     gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "run-in-background-separator")));
     gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "run-in-background-button")));
-    gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "save-as-application-separator")));
-    gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "save-as-application-button")));
     gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "application-manager-button")));
 
     if (is_desktop_pantheon ())
@@ -322,6 +320,12 @@ ephy_header_bar_constructed (GObject *object)
     gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "run-in-background-button")));
   }
 
+  if (!ephy_can_install_web_apps ()) {
+    gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "save-as-application-separator")));
+    gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "save-as-application-button")));
+    gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "application-manager-button")));
+  }
+
   header_bar->combined_stop_reload_button = GTK_WIDGET (gtk_builder_get_object (builder, 
"combined_stop_reload_button"));
   header_bar->combined_stop_reload_image = GTK_WIDGET (gtk_builder_get_object (builder, 
"combined_stop_reload_image"));
   gtk_widget_set_tooltip_text (header_bar->combined_stop_reload_button, _(REFRESH_BUTTON_TOOLTIP));
diff --git a/src/ephy-main.c b/src/ephy-main.c
index 48b6c684b..71a72af3b 100644
--- a/src/ephy-main.c
+++ b/src/ephy-main.c
@@ -25,6 +25,7 @@
 #include "ephy-debug.h"
 #include "ephy-embed-utils.h"
 #include "ephy-file-helpers.h"
+#include "ephy-flatpak-utils.h"
 #include "ephy-profile-utils.h"
 #include "ephy-session.h"
 #include "ephy-settings.h"
@@ -292,14 +293,19 @@ main (int   argc,
 
   if (application_mode && !profile_directory) {
     if (desktop_file_basename) {
-      desktop_info = g_desktop_app_info_new (desktop_file_basename);
+      if (ephy_is_running_inside_sandbox ()) {
+        g_print ("In sandbox, no desktop file can be passed to --application-mode\n");
+        exit (1);
+      } else {
+        desktop_info = g_desktop_app_info_new (desktop_file_basename);
 
-      if (desktop_info)
-        profile_directory = ephy_web_application_ensure_for_app_info (G_APP_INFO (desktop_info));
+        if (desktop_info)
+          profile_directory = ephy_web_application_ensure_for_app_info (G_APP_INFO (desktop_info));
 
-      if (!profile_directory) {
-        g_print ("Invalid desktop file passed to --application-mode\n");
-        exit (1);
+        if (!profile_directory) {
+          g_print ("Invalid desktop file passed to --application-mode\n");
+          exit (1);
+        }
       }
     }
   }
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index d356ee168..901a6c199 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -333,9 +333,9 @@ launch_app (GSimpleAction *action,
             GVariant      *parameter,
             gpointer       user_data)
 {
-  const gchar *desktop_file = g_variant_get_string (parameter, NULL);
+  const gchar *webapp_id = g_variant_get_string (parameter, NULL);
 
-  ephy_file_launch_webapp_desktop_file (desktop_file,
+  ephy_file_launch_webapp_desktop_file (webapp_id,
                                         gtk_get_current_event_time ());
 }
 
diff --git a/src/meson.build b/src/meson.build
index 50f6710b3..778192349 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -73,7 +73,8 @@ libephymain_deps = [
   ephywidgets_dep,
   gvdb_dep,
   libarchive_dep,
-  libhandy_dep
+  libhandy_dep,
+  portal_dep
 ]
 
 libephymain_includes = include_directories(
diff --git a/src/resources/gtk/shortcuts-dialog.ui b/src/resources/gtk/shortcuts-dialog.ui
index a55a00cd1..20a864a67 100644
--- a/src/resources/gtk/shortcuts-dialog.ui
+++ b/src/resources/gtk/shortcuts-dialog.ui
@@ -284,7 +284,7 @@
               </object>
             </child>
             <child>
-              <object class="GtkShortcutsShortcut">
+              <object class="GtkShortcutsShortcut" id="app-manager-shortcut">
                 <property name="visible">True</property>
                 <property name="title" translatable="yes" context="shortcut window">Open web application 
manager</property>
                 <property name="accelerator">&lt;Shift&gt;&lt;Primary&gt;C</property>
diff --git a/src/webapp-provider/ephy-webapp-provider.c b/src/webapp-provider/ephy-webapp-provider.c
index 0044e6469..417f57305 100644
--- a/src/webapp-provider/ephy-webapp-provider.c
+++ b/src/webapp-provider/ephy-webapp-provider.c
@@ -72,7 +72,6 @@ handle_install (EphyWebAppProvider        *skeleton,
                 EphyWebAppProviderService *self)
 {
   g_autofree char *id = NULL;
-  g_autofree char *desktop_path = NULL;
 
   g_debug ("%s", G_STRFUNC);
 
@@ -102,11 +101,9 @@ handle_install (EphyWebAppProvider        *skeleton,
 
   id = ephy_web_application_get_app_id_from_name (name);
 
-  desktop_path = ephy_web_application_create (id, url, name,
-                                              NULL, NULL, /* icon_pixbuf, icon_path */
-                                              install_token,
-                                              EPHY_WEB_APPLICATION_NONE);
-  if (!desktop_path) {
+  if (!ephy_web_application_create (id, url,
+                                    install_token,
+                                    EPHY_WEB_APPLICATION_NONE)) {
     g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
                                            "Installing the web application '%s' (%s) failed", name, url);
     goto out;
diff --git a/src/window-commands.c b/src/window-commands.c
index ab629630a..a6d5414e1 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -64,6 +64,7 @@
 #include <gtk/gtk.h>
 #include <string.h>
 #include <webkit2/webkit2.h>
+#include <libportal-gtk3/portal-gtk3.h>
 
 #define DEFAULT_ICON_SIZE 192
 #define FAVICON_SIZE 16
@@ -901,9 +902,12 @@ window_cmd_show_shortcuts (GSimpleAction *action,
     builder = gtk_builder_new_from_resource ("/org/gnome/epiphany/gtk/shortcuts-dialog.ui");
     shortcuts_window = GTK_WIDGET (gtk_builder_get_object (builder, "shortcuts-dialog"));
 
-    if (ephy_is_running_inside_sandbox ())
+    if (!ephy_can_install_web_apps ())
       gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "shortcuts-web-apps-group")));
 
+    if (!ephy_can_install_web_apps () || ephy_is_running_inside_sandbox ())
+      gtk_widget_hide (GTK_WIDGET (gtk_builder_get_object (builder, "app-manager-shortcut")));
+
     if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL) {
       GtkShortcutsShortcut *shortcut;
 
@@ -1369,18 +1373,90 @@ window_cmd_open (GSimpleAction *action,
 
 typedef struct {
   EphyWebView *view;
-  GtkWidget *dialog;
-  GtkWidget *image;
-  GtkWidget *entry;
-  GtkWidget *spinner;
-  GtkWidget *box;
+  const char *display_address;
+  const char *url;
   char *icon_href;
+  char *title;
+  char *chosen_name;
+  char *app_id;
+  char *token;
+  GVariant *icon_v;
   GdkRGBA icon_rgba;
+  GdkPixbuf *framed_pixbuf;
   GCancellable *cancellable;
   EphyWebApplicationOptions webapp_options;
+  gboolean webapp_options_set;
   WebKitDownload *download;
+  EphyWindow *window;
 } EphyApplicationDialogData;
 
+static void
+session_bus_ready_cb (GObject      *source,
+                      GAsyncResult *res,
+                      gpointer      user_data)
+{
+  g_autoptr (GDBusConnection) connection = g_bus_get_finish (res, NULL);
+  g_autofree gchar *desktop_file = user_data;
+  g_autofree gchar *app_id = NULL;
+  GVariant *app;
+
+  if (!connection)
+    return;
+
+  app_id = g_path_get_basename (desktop_file);
+  app = g_variant_new_string (app_id);
+
+  g_dbus_connection_call (connection,
+                          "org.gnome.Shell",
+                          "/org/gnome/Shell",
+                          "org.gnome.Shell",
+                          "FocusApp",
+                          g_variant_new_tuple (&app, 1),
+                          NULL,
+                          G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                          -1,
+                          NULL,
+                          NULL,
+                          NULL);
+}
+
+static void
+ephy_focus_desktop_app (const char *webapp_id)
+{
+  g_autofree char *desktop_path = NULL;
+  desktop_path = ephy_web_application_get_desktop_path (webapp_id);
+  g_bus_get (G_BUS_TYPE_SESSION, NULL, session_bus_ready_cb, g_steal_pointer (&desktop_path));
+}
+
+static void download_finished_cb (WebKitDownload *download, EphyApplicationDialogData *data);
+
+static void download_failed_cb (WebKitDownload            *download,
+                                GError                    *error,
+                                EphyApplicationDialogData *data);
+
+static void
+ephy_application_dialog_data_free (EphyApplicationDialogData *data)
+{
+  if (data->download) {
+    g_signal_handlers_disconnect_by_func (data->download, download_finished_cb, data);
+    g_signal_handlers_disconnect_by_func (data->download, download_failed_cb, data);
+
+    data->download = NULL;
+  }
+
+  g_cancellable_cancel (data->cancellable);
+  g_object_unref (data->cancellable);
+  g_object_unref (data->window);
+  g_object_unref (data->framed_pixbuf);
+  g_variant_unref (data->icon_v);
+  g_free (data->icon_href);
+  g_free (data->title);
+  g_free (data->chosen_name);
+  g_free (data->token);
+  g_free (data->app_id);
+  g_free (data);
+}
+
 static void
 rounded_rectangle (cairo_t *cr,
                    gdouble  aspect,
@@ -1498,22 +1574,26 @@ frame_pixbuf (GdkPixbuf *pixbuf,
   return framed;
 }
 
+static void create_install_dialog_when_ready (EphyApplicationDialogData *data);
+
 static void
 set_image_from_favicon (EphyApplicationDialogData *data)
 {
-  GdkPixbuf *icon = NULL;
+  g_autoptr (GdkPixbuf) icon = NULL;
   cairo_surface_t *icon_surface = webkit_web_view_get_favicon (WEBKIT_WEB_VIEW (data->view));
 
   if (icon_surface)
     icon = ephy_pixbuf_get_from_surface_scaled (icon_surface, 0, 0);
 
   if (icon != NULL) {
-    GdkPixbuf *framed;
-
-    framed = frame_pixbuf (icon, NULL, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
-    g_object_unref (icon);
-    gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), framed);
-    g_object_unref (framed);
+    data->framed_pixbuf = frame_pixbuf (icon, NULL, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
+    g_assert (data->icon_v == NULL);
+    data->icon_v = g_icon_serialize (G_ICON (data->framed_pixbuf));
+    create_install_dialog_when_ready (data);
+  }
+  if (data->icon_v == NULL) {
+    g_warning ("Failed to get favicon for web app %s, giving up", data->display_address);
+    ephy_application_dialog_data_free (data);
   }
 }
 
@@ -1521,30 +1601,31 @@ static void
 set_app_icon_from_filename (EphyApplicationDialogData *data,
                             const char                *filename)
 {
-  GdkPixbuf *pixbuf;
-  GdkPixbuf *framed;
+  g_autoptr (GdkPixbuf) pixbuf = NULL;
 
   pixbuf = gdk_pixbuf_new_from_file_at_size (filename, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE, NULL);
-  if (pixbuf == NULL)
-    return;
 
-  framed = frame_pixbuf (pixbuf, &data->icon_rgba, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
-  g_object_unref (pixbuf);
-  gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), framed);
-  g_object_unref (framed);
+  if (pixbuf != NULL) {
+    data->framed_pixbuf = frame_pixbuf (pixbuf, &data->icon_rgba, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
+    g_assert (data->icon_v == NULL);
+    data->icon_v = g_icon_serialize (G_ICON (data->framed_pixbuf));
+    create_install_dialog_when_ready (data);
+  }
+  if (data->icon_v == NULL) {
+    g_warning ("Failed to get icon for web app %s, giving up", data->display_address);
+    ephy_application_dialog_data_free (data);
+    return;
+  }
 }
 
 static void
 download_finished_cb (WebKitDownload            *download,
                       EphyApplicationDialogData *data)
 {
-  char *filename;
-
-  gtk_widget_show (data->image);
+  g_autofree char *filename = NULL;
 
   filename = g_filename_from_uri (webkit_download_get_destination (download), NULL, NULL);
   set_app_icon_from_filename (data, filename);
-  g_free (filename);
 }
 
 static void
@@ -1552,8 +1633,6 @@ download_failed_cb (WebKitDownload            *download,
                     GError                    *error,
                     EphyApplicationDialogData *data)
 {
-  gtk_widget_show (data->image);
-
   g_signal_handlers_disconnect_by_func (download, download_finished_cb, data);
   /* Something happened, default to a page snapshot. */
   set_image_from_favicon (data);
@@ -1562,7 +1641,9 @@ download_failed_cb (WebKitDownload            *download,
 static void
 download_icon_and_set_image (EphyApplicationDialogData *data)
 {
-  char *destination, *destination_uri, *tmp_filename;
+  g_autofree char *destination = NULL;
+  g_autofree char *destination_uri = NULL;
+  g_autofree char *tmp_filename = NULL;
   EphyEmbedShell *shell = ephy_embed_shell_get_default ();
 
   data->download = webkit_web_context_download_uri (ephy_embed_shell_get_web_context (shell),
@@ -1578,9 +1659,6 @@ download_icon_and_set_image (EphyApplicationDialogData *data)
   destination = g_build_filename (ephy_file_tmp_dir (), tmp_filename, NULL);
   destination_uri = g_filename_to_uri (destination, NULL, NULL);
   webkit_download_set_destination (data->download, destination_uri);
-  g_free (destination);
-  g_free (destination_uri);
-  g_free (tmp_filename);
 
   g_signal_connect (data->download, "finished",
                     G_CALLBACK (download_finished_cb), data);
@@ -1596,7 +1674,7 @@ fill_default_application_image_cb (GObject      *source,
   EphyApplicationDialogData *data = user_data;
   char *uri = NULL;
   GdkRGBA color = { 0.5, 0.5, 0.5, 0.3 };
-  GError *error = NULL;
+  g_autoptr (GError) error = NULL;
 
   ephy_web_view_get_best_web_app_icon_finish (EPHY_WEB_VIEW (source), async_result, &uri, &color, &error);
 
@@ -1607,16 +1685,8 @@ fill_default_application_image_cb (GObject      *source,
   data->icon_rgba = color;
   if (data->icon_href != NULL)
     download_icon_and_set_image (data);
-  else {
-    gtk_widget_show (data->image);
+  else
     set_image_from_favicon (data);
-  }
-}
-
-static void
-fill_default_application_image (EphyApplicationDialogData *data)
-{
-  ephy_web_view_get_best_web_app_icon (data->view, data->cancellable, fill_default_application_image_cb, 
data);
 }
 
 typedef struct {
@@ -1674,7 +1744,8 @@ set_default_application_title (EphyApplicationDialogData *data,
     title = g_strdup (webkit_web_view_get_title (WEBKIT_WEB_VIEW (data->view)));
   }
 
-  gtk_entry_set_text (GTK_ENTRY (data->entry), title);
+  data->title = g_strdup (title);
+  create_install_dialog_when_ready (data);
   g_free (title);
 }
 
@@ -1684,19 +1755,15 @@ fill_default_application_title_cb (GObject      *source,
                                    gpointer      user_data)
 {
   EphyApplicationDialogData *data = user_data;
-  char *title;
-  GError *error = NULL;
+  g_autofree char *title = NULL;
+  g_autoptr(GError) error = NULL;
 
   /* Confusing: this can return NULL for no title, even when there is no error. */
   title = ephy_web_view_get_web_app_title_finish (EPHY_WEB_VIEW (source), async_result, &error);
   if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-    set_default_application_title (data, title);
-}
-
-static void
-fill_default_application_title (EphyApplicationDialogData *data)
-{
-  ephy_web_view_get_web_app_title (data->view, data->cancellable, fill_default_application_title_cb, data);
+    set_default_application_title (data, g_steal_pointer (&title));
+  else
+    ephy_application_dialog_data_free (data);
 }
 
 static void
@@ -1709,116 +1776,52 @@ fill_mobile_capable_cb (GObject      *source,
   gboolean capable;
 
   capable = ephy_web_view_get_web_app_mobile_capable_finish (EPHY_WEB_VIEW (source), async_result, &error);
-  if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+  if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
     data->webapp_options = capable ? EPHY_WEB_APPLICATION_MOBILE_CAPABLE : EPHY_WEB_APPLICATION_NONE;
-}
-
-static void
-fill_mobile_capable (EphyApplicationDialogData *data)
-{
-  ephy_web_view_get_web_app_mobile_capable (data->view, data->cancellable, fill_mobile_capable_cb, data);
-}
-
-static void
-session_bus_ready_cb (GObject      *source,
-                      GAsyncResult *res,
-                      gpointer      user_data)
-{
-  g_autoptr (GDBusConnection) connection = g_bus_get_finish (res, NULL);
-  g_autofree gchar *desktop_file = user_data;
-  g_autofree gchar *app_id = NULL;
-  GVariant *app;
-
-  if (!connection)
-    return;
-
-  app_id = g_path_get_basename (desktop_file);
-  app = g_variant_new_string (app_id);
-
-  g_dbus_connection_call (connection,
-                          "org.gnome.Shell",
-                          "/org/gnome/Shell",
-                          "org.gnome.Shell",
-                          "FocusApp",
-                          g_variant_new_tuple (&app, 1),
-                          NULL,
-                          G_DBUS_CALL_FLAGS_NO_AUTO_START,
-                          -1,
-                          NULL,
-                          NULL,
-                          NULL);
-}
-
-static void
-ephy_focus_desktop_app (const char *desktop_file)
-{
-  g_bus_get (G_BUS_TYPE_SESSION, NULL, session_bus_ready_cb, g_strdup (desktop_file));
-}
-
-static void
-ephy_application_dialog_data_free (EphyApplicationDialogData *data)
-{
-  if (data->download) {
-    g_signal_handlers_disconnect_by_func (data->download, download_finished_cb, data);
-    g_signal_handlers_disconnect_by_func (data->download, download_failed_cb, data);
-
-    data->download = NULL;
+    data->webapp_options_set = TRUE;
+    create_install_dialog_when_ready (data);
+  } else {
+    ephy_application_dialog_data_free (data);
   }
-
-  g_cancellable_cancel (data->cancellable);
-  g_object_unref (data->cancellable);
-  g_free (data->icon_href);
-  g_free (data);
 }
 
 static void
 save_as_application_proceed (EphyApplicationDialogData *data)
 {
-  const char *app_name;
-  g_autofree gchar *app_id = NULL;
-  g_autofree gchar *desktop_file = NULL;
+  g_autofree gchar *desktop_file_id = NULL;
   g_autofree char *message = NULL;
   GNotification *notification;
-
-  app_name = gtk_entry_get_text (GTK_ENTRY (data->entry));
-  app_id = ephy_web_application_get_app_id_from_name (app_name);
+  gboolean success;
 
   /* Create Web Application, including a new profile and .desktop file. */
-  desktop_file = ephy_web_application_create (app_id,
-                                              webkit_web_view_get_uri (WEBKIT_WEB_VIEW (data->view)),
-                                              app_name,
-                                              gtk_image_get_pixbuf (GTK_IMAGE (data->image)),
-                                              NULL, NULL, /* icon_path, install_token */
-                                              data->webapp_options);
-
-  if (desktop_file)
+  success = ephy_web_application_create (data->app_id,
+                                         data->url,
+                                         data->token,
+                                         data->webapp_options);
+
+  if (success)
     message = g_strdup_printf (_("The application “%s” is ready to be used"),
-                               app_name);
+                               data->chosen_name);
   else
     message = g_strdup_printf (_("The application “%s” could not be created"),
-                               app_name);
+                               data->chosen_name);
 
   notification = g_notification_new (message);
 
-  if (data->image) {
-    GdkPixbuf *pixbuf = gtk_image_get_pixbuf (GTK_IMAGE (data->image));
-
-    g_notification_set_icon (notification, G_ICON (pixbuf));
-  }
+  g_notification_set_icon (notification, G_ICON (data->framed_pixbuf));
 
-  if (desktop_file) {
+  if (success) {
     /* Translators: Desktop notification when a new web app is created. */
-    g_notification_add_button_with_target (notification, _("Launch"), "app.launch-app", "s", desktop_file);
-    g_notification_set_default_action_and_target (notification, "app.launch-app", "s", desktop_file);
+    g_notification_add_button_with_target (notification, _("Launch"), "app.launch-app", "s", data->app_id);
+    g_notification_set_default_action_and_target (notification, "app.launch-app", "s", data->app_id);
 
-    ephy_focus_desktop_app (desktop_file);
+    ephy_focus_desktop_app (data->app_id);
   }
 
   g_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_LOW);
 
-  g_application_send_notification (G_APPLICATION (g_application_get_default ()), app_name, notification);
+  g_application_send_notification (G_APPLICATION (g_application_get_default ()), data->chosen_name, 
notification);
 
-  gtk_widget_destroy (GTK_WIDGET (data->dialog));
   ephy_application_dialog_data_free (data);
 }
 
@@ -1827,50 +1830,61 @@ dialog_save_as_application_confirmation_cb (GtkDialog                 *dialog,
                                             GtkResponseType            response,
                                             EphyApplicationDialogData *data)
 {
-  const char *app_name;
-  g_autofree gchar *app_id = NULL;
-
-  app_name = gtk_entry_get_text (GTK_ENTRY (data->entry));
-  app_id = ephy_web_application_get_app_id_from_name (app_name);
-
   gtk_widget_destroy (GTK_WIDGET (dialog));
 
   if (response == GTK_RESPONSE_OK) {
-    ephy_web_application_delete (app_id);
+    ephy_web_application_delete (data->app_id);
     save_as_application_proceed (data);
+  } else {
+    ephy_application_dialog_data_free (data);
   }
 }
 
 static void
-dialog_save_as_application_response_cb (GtkDialog                 *dialog,
-                                        GtkResponseType            response,
-                                        EphyApplicationDialogData *data)
+prepare_install_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
 {
-  const char *app_name;
-  g_autofree gchar *app_id = NULL;
+  XdpPortal *portal = XDP_PORTAL (object);
+  EphyApplicationDialogData *data = user_data;
+  g_autoptr(GVariant) ret = NULL;
+  g_autoptr(GVariant) chosen_name_v = NULL;
+  g_autoptr(GVariant) token_v = NULL;
   GtkWidget *confirmation_dialog;
+  g_autoptr(GError) error = NULL;
 
-  if (response != GTK_RESPONSE_OK) {
+  ret = xdp_portal_prepare_install_launcher_finish (portal, result, &error);
+  if (ret == NULL) {
+    /* This might just mean the user canceled the operation */
+    g_warning ("Failed to install web app, PrepareInstall() failed: %s", error->message);
     ephy_application_dialog_data_free (data);
-    gtk_widget_destroy (GTK_WIDGET (dialog));
     return;
   }
 
-  app_name = gtk_entry_get_text (GTK_ENTRY (data->entry));
-  app_id = ephy_web_application_get_app_id_from_name (app_name);
+  chosen_name_v = g_variant_lookup_value (ret, "name", G_VARIANT_TYPE_STRING);
+  token_v = g_variant_lookup_value (ret, "token", G_VARIANT_TYPE_STRING);
+  if (chosen_name_v == NULL || token_v == NULL) {
+    g_warning ("Failed to install web app, PrepareInstall() returned invalid data");
+    ephy_application_dialog_data_free (data);
+    return;
+  }
+  data->chosen_name = g_strdup (g_variant_get_string (chosen_name_v, NULL));
+  data->token = g_strdup (g_variant_get_string (token_v, NULL));
 
-  if (!ephy_web_application_exists (app_id)) {
+  data->app_id = ephy_web_application_get_app_id_from_name (data->chosen_name);
+
+  if (!ephy_web_application_exists (data->app_id)) {
     save_as_application_proceed (data);
     return;
   }
 
   confirmation_dialog =
-    gtk_message_dialog_new (GTK_WINDOW (dialog),
+    gtk_message_dialog_new (GTK_WINDOW (data->window),
                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                             GTK_MESSAGE_QUESTION,
                             GTK_BUTTONS_NONE,
                             _("A web application named “%s” already exists. Do you want to replace it?"),
-                            app_name);
+                            data->chosen_name);
   gtk_dialog_add_buttons (GTK_DIALOG (confirmation_dialog),
                           _("Cancel"),
                           GTK_RESPONSE_CANCEL,
@@ -1887,6 +1901,27 @@ dialog_save_as_application_response_cb (GtkDialog                 *dialog,
   gtk_window_present (GTK_WINDOW (confirmation_dialog));
 }
 
+static void
+create_install_dialog_when_ready (EphyApplicationDialogData *data)
+{
+  XdpPortal *portal;
+  XdpParent *parent;
+
+  if (data->webapp_options_set == FALSE || data->title == NULL || data->icon_v == NULL)
+    return;
+
+  /* Create a dialog for the user to confirm */
+  portal = ephy_get_portal ();
+  parent = xdp_parent_new_gtk (GTK_WINDOW (data->window));
+  xdp_portal_prepare_install_launcher (portal, parent,
+                                       data->title, data->icon_v, "png",
+                                       XDP_LAUNCHER_WEBAPP, data->url,
+                                       TRUE, TRUE, /* editable name, icon */
+                                       data->cancellable,
+                                       prepare_install_cb,
+                                       data);
+}
+
 void
 window_cmd_save_as_application (GSimpleAction *action,
                                 GVariant      *parameter,
@@ -1894,98 +1929,24 @@ window_cmd_save_as_application (GSimpleAction *action,
 {
   EphyWindow *window = user_data;
   EphyEmbed *embed;
-  GtkWidget *dialog, *box, *image, *entry, *content_area;
-  GtkWidget *label;
-  GtkWidget *spinner;
-  EphyWebView *view;
   EphyApplicationDialogData *data;
-  GdkPixbuf *pixbuf;
-  GtkStyleContext *context;
-  char *markup;
-  char *escaped_address;
 
-  if (ephy_is_running_inside_sandbox ())
+  if (!ephy_can_install_web_apps ())
     return;
 
   embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
   g_assert (embed != NULL);
 
-  view = EPHY_WEB_VIEW (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed));
-
-  /* Show dialog with icon, title. */
-  dialog = gtk_dialog_new_with_buttons (_("Create Web Application"),
-                                        GTK_WINDOW (window),
-                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | 
GTK_DIALOG_USE_HEADER_BAR,
-                                        _("_Cancel"),
-                                        GTK_RESPONSE_CANCEL,
-                                        _("C_reate"),
-                                        GTK_RESPONSE_OK,
-                                        NULL);
-
-  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-
-  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
-  gtk_widget_set_margin_top (box, 15);
-  gtk_widget_set_margin_bottom (box, 15);
-  gtk_widget_set_margin_start (box, 15);
-  gtk_widget_set_margin_end (box, 15);
-  gtk_container_add (GTK_CONTAINER (content_area), box);
-
-  image = gtk_image_new ();
-  gtk_widget_set_vexpand (image, TRUE);
-  gtk_widget_set_no_show_all (image, TRUE);
-  gtk_widget_set_size_request (image, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
-  gtk_widget_set_margin_bottom (image, 10);
-  gtk_container_add (GTK_CONTAINER (box), image);
-  pixbuf = frame_pixbuf (NULL, NULL, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
-  gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
-  g_object_unref (pixbuf);
-
-  spinner = gtk_spinner_new ();
-  gtk_widget_set_size_request (spinner, DEFAULT_ICON_SIZE, DEFAULT_ICON_SIZE);
-  gtk_widget_set_vexpand (spinner, TRUE);
-  gtk_spinner_start (GTK_SPINNER (spinner));
-  gtk_container_add (GTK_CONTAINER (box), spinner);
-  gtk_widget_show (spinner);
-
-  entry = gtk_entry_new ();
-  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
-  gtk_box_pack_start (GTK_BOX (box), entry, FALSE, TRUE, 0);
-
-  escaped_address = g_markup_escape_text (ephy_web_view_get_display_address (view), -1);
-  markup = g_strdup_printf ("<small>%s</small>", escaped_address);
-  label = gtk_label_new (NULL);
-  gtk_label_set_markup (GTK_LABEL (label), markup);
-  gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
-  gtk_label_set_max_width_chars (GTK_LABEL (label), 40);
-  g_free (markup);
-  g_free (escaped_address);
-
-  gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
-  context = gtk_widget_get_style_context (label);
-  gtk_style_context_add_class (context, "dim-label");
-
   data = g_new0 (EphyApplicationDialogData, 1);
-  data->dialog = dialog;
-  data->view = view;
-  data->image = image;
-  data->entry = entry;
-  data->spinner = spinner;
+  data->window = g_object_ref (window);
+  data->view = EPHY_WEB_VIEW (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed));
+  data->display_address = ephy_web_view_get_display_address (data->view);
+  data->url = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (data->view));
   data->cancellable = g_cancellable_new ();
 
-  g_object_bind_property (image, "visible", spinner, "visible", G_BINDING_INVERT_BOOLEAN);
-
-  fill_default_application_image (data);
-  fill_default_application_title (data);
-  fill_mobile_capable (data);
-
-  gtk_widget_show_all (dialog);
-
-  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-  g_signal_connect (dialog, "response",
-                    G_CALLBACK (dialog_save_as_application_response_cb),
-                    data);
-  gtk_widget_show_all (dialog);
+  ephy_web_view_get_best_web_app_icon (data->view, data->cancellable, fill_default_application_image_cb, 
data);
+  ephy_web_view_get_web_app_title (data->view, data->cancellable, fill_default_application_title_cb, data);
+  ephy_web_view_get_web_app_mobile_capable (data->view, data->cancellable, fill_mobile_capable_cb, data);
 }
 
 static char *
diff --git a/tests/meson.build b/tests/meson.build
index bfee4398c..02b9df692 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -158,16 +158,19 @@ if get_option('unit_tests').enabled()
        env: envs
   )
 
-  web_app_utils_test = executable('test-ephy-web-app-utils',
-    'ephy-web-app-utils-test.c',
-    dependencies: ephymain_dep,
-    c_args: test_cargs,
-  )
-  test('Web app utils test',
-     web_app_utils_test,
-     env: envs,
-     depends: epiphany
-  )
+  # FIXME: this is difficult to test since the portal has to be available and
+  # would install into the user's XDG_DATA_HOME rather than the temp xdg_home
+  # setup by the test.
+  #web_app_utils_test = executable('test-ephy-web-app-utils',
+  #  'ephy-web-app-utils-test.c',
+  #  dependencies: ephymain_dep,
+  #  c_args: test_cargs,
+  #)
+  #test('Web app utils test',
+  #   web_app_utils_test,
+  #   env: envs,
+  #   depends: epiphany
+  #)
 
   web_view_test = executable('test-ephy-web-view',
     'ephy-web-view-test.c',


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