[epiphany] Make web app manager work under Flatpak



commit 097e0e3fb6c71aa080112d011c58f74292508a3c
Author: Phaedrus Leeds <mwleeds protonmail com>
Date:   Wed Feb 23 15:35:34 2022 -0800

    Make web app manager work under Flatpak
    
    Make use of the GetIcon() portal method so the app manager can work
    under Flatpak.

 embed/ephy-about-handler.c           | 16 ++++++-
 lib/ephy-web-app-utils.c             | 84 ++++++++++++++++++++++++++++++++++--
 lib/ephy-web-app-utils.h             |  9 +++-
 src/ephy-header-bar.c                |  1 -
 src/preferences/prefs-general-page.c |  3 +-
 5 files changed, 105 insertions(+), 8 deletions(-)
---
diff --git a/embed/ephy-about-handler.c b/embed/ephy-about-handler.c
index 915cfca2e..cd8b1c381 100644
--- a/embed/ephy-about-handler.c
+++ b/embed/ephy-about-handler.c
@@ -264,6 +264,7 @@ handle_applications_finished_cb (EphyAboutHandler       *handler,
 
     for (p = applications; p; p = p->next) {
       EphyWebApplication *app = (EphyWebApplication *)p->data;
+      const char *icon_url;
       g_autofree char *encoded_icon_url = NULL;
       g_autofree char *encoded_name = NULL;
       g_autofree char *encoded_url = NULL;
@@ -278,6 +279,17 @@ handle_applications_finished_cb (EphyAboutHandler       *handler,
       g_date_set_time_t (date, (time_t)app->install_date_uint64);
       g_date_strftime (install_date, 127, "%x", date);
 
+      /* In the sandbox we don't have access to the host side icon file */
+      if (ephy_is_running_inside_sandbox ())
+        icon_url = app->tmp_icon_url;
+      else
+        icon_url = app->icon_url;
+
+      if (!icon_url) {
+        g_warning ("Failed to get icon url for app %s", app->id);
+        continue;
+      }
+
       /* Most of these fields are at least semi-trusted. The app ID was chosen
        * by ephy so it's safe. The icon URL could be changed by the user to
        * something else after web app creation, though, so better not fully
@@ -285,7 +297,7 @@ handle_applications_finished_cb (EphyAboutHandler       *handler,
        * anything at all, so those need to be encoded for sure. Install date
        * should be fine because it's constructed by Epiphany.
        */
-      encoded_icon_url = ephy_encode_for_html_attribute (app->icon_url);
+      encoded_icon_url = ephy_encode_for_html_attribute (icon_url);
       encoded_name = ephy_encode_for_html_entity (app->name);
       encoded_url = ephy_encode_for_html_entity (app->url);
       g_string_append_printf (data_str,
@@ -586,7 +598,7 @@ ephy_about_handler_handle_request (EphyAboutHandler       *handler,
     handled = ephy_about_handler_handle_memory (handler, request);
   else if (!g_strcmp0 (path, "epiphany"))
     handled = ephy_about_handler_handle_epiphany (handler, request);
-  else if (!g_strcmp0 (path, "applications") && !ephy_is_running_inside_sandbox ())
+  else if (!g_strcmp0 (path, "applications"))
     handled = ephy_about_handler_handle_applications (handler, request);
   else if (!g_strcmp0 (path, "newtab"))
     handled = ephy_about_handler_handle_newtab (handler, request);
diff --git a/lib/ephy-web-app-utils.c b/lib/ephy-web-app-utils.c
index 1b4bcb758..0f70dbfcd 100644
--- a/lib/ephy-web-app-utils.c
+++ b/lib/ephy-web-app-utils.c
@@ -36,6 +36,7 @@
 #include <fcntl.h>
 #include <libportal-gtk3/portal-gtk3.h>
 #include <glib/gi18n.h>
+#include <gio/gunixoutputstream.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
@@ -564,14 +565,84 @@ ephy_web_application_free (EphyWebApplication *app)
   g_free (app->id);
   g_free (app->name);
   g_free (app->icon_url);
+  g_free (app->tmp_icon_url);
   g_free (app->url);
   g_free (app->desktop_file);
   g_free (app->desktop_path);
   g_free (app);
 }
 
+static char *
+ephy_web_application_get_tmp_icon_path (const char  *desktop_path,
+                                        GError     **error)
+{
+  XdpPortal *portal = ephy_get_portal ();
+  g_autoptr (GVariant) icon_v = NULL;
+  g_autofree char *icon_format = NULL;
+  g_autofree char *desktop_basename = NULL;
+  g_autofree char *tmp_file_name = NULL;
+  g_autofree char *tmp_file_path = NULL;
+  g_autoptr (GIcon) icon = NULL;
+  g_autoptr (GOutputStream) stream = NULL;
+  GBytes *bytes;
+  gconstpointer bytes_data;
+  gsize bytes_len;
+  int fd;
+
+  g_return_val_if_fail (desktop_path != NULL, NULL);
+
+  /* This function is only useful inside the sandbox since the icon file on the
+   * host is inaccessible in that case.
+   */
+  g_assert (ephy_is_running_inside_sandbox ());
+
+  desktop_basename = g_path_get_basename (desktop_path);
+  icon_v = xdp_portal_dynamic_launcher_get_icon (portal, desktop_basename, &icon_format, NULL, error);
+  if (!icon_v)
+    return NULL;
+
+  tmp_file_name = ephy_file_tmp_filename (".ephy-webapp-icon-XXXXXX", icon_format);
+  tmp_file_path = g_build_filename (ephy_file_tmp_dir (), tmp_file_name, NULL);
+
+  icon = g_icon_deserialize (icon_v);
+  if (!icon) {
+    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+                         "Icon deserialization failed");
+    return NULL;
+  }
+
+  if (!G_IS_BYTES_ICON (icon)) {
+    g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
+                 "Unexpected icon type: %s", G_OBJECT_TYPE_NAME (icon));
+    return NULL;
+  }
+
+  bytes = g_bytes_icon_get_bytes (G_BYTES_ICON (icon));
+  fd = g_open (tmp_file_path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+  if (fd == -1) {
+    g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
+                 "Failed to create tmpfile ā€˜%sā€™: %s",
+                 tmp_file_path, g_strerror (errno));
+    return NULL;
+  }
+
+  stream = g_unix_output_stream_new (fd, TRUE);
+  /* Use write_all() instead of write_bytes() so we don't have to worry about
+   * partial writes (https://gitlab.gnome.org/GNOME/glib/-/issues/570).
+   */
+  bytes_data = g_bytes_get_data (bytes, &bytes_len);
+  if (!g_output_stream_write_all (stream, bytes_data, bytes_len, NULL, NULL, error))
+    return NULL;
+
+  if (!g_output_stream_close (stream, NULL, error))
+    return NULL;
+
+  return g_steal_pointer (&tmp_file_path);
+}
+
 EphyWebApplication *
-ephy_web_application_for_profile_directory (const char *profile_dir)
+ephy_web_application_for_profile_directory (const char            *profile_dir,
+                                            EphyWebAppNeedTmpIcon  need_tmp_icon)
 {
   g_autoptr (EphyWebApplication) app = NULL;
   const char *id;
@@ -603,6 +674,12 @@ ephy_web_application_for_profile_directory (const char *profile_dir)
     app->name = g_key_file_get_string (key_file, "Desktop Entry", "Name", NULL);
     app->icon_url = g_key_file_get_string (key_file, "Desktop Entry", "Icon", NULL);
 
+    if (ephy_is_running_inside_sandbox () && need_tmp_icon == EPHY_WEB_APP_NEED_TMP_ICON) {
+      app->tmp_icon_url = ephy_web_application_get_tmp_icon_path (app->desktop_path, &error);
+      if (!app->tmp_icon_url)
+        g_warning ("Failed to get tmp icon path for app %s: %s", app->id, error->message);
+    }
+
     exec = g_key_file_get_string (key_file, "Desktop Entry", "Exec", NULL);
     if (g_shell_parse_argv (exec, &argc, &argv, NULL))
       app->url = g_strdup (argv[argc - 1]);
@@ -682,7 +759,7 @@ ephy_web_application_get_application_list (void)
       g_autofree char *profile_dir = NULL;
 
       profile_dir = g_build_filename (parent_directory_path, name, NULL);
-      app = ephy_web_application_for_profile_directory (profile_dir);
+      app = ephy_web_application_for_profile_directory (profile_dir, EPHY_WEB_APP_NEED_TMP_ICON);
       if (app) {
         g_autofree char *app_file = g_build_filename (profile_dir, ".app", NULL);
         if (g_file_test (app_file, G_FILE_TEST_EXISTS))
@@ -844,7 +921,8 @@ urls_have_same_origin (const char *a_url,
 gboolean
 ephy_web_application_is_uri_allowed (const char *uri)
 {
-  g_autoptr (EphyWebApplication) webapp = ephy_web_application_for_profile_directory (ephy_profile_dir ());
+  g_autoptr (EphyWebApplication) webapp = ephy_web_application_for_profile_directory (ephy_profile_dir (),
+                                                                                      
EPHY_WEB_APP_NO_TMP_ICON);
   const char *scheme;
   g_auto (GStrv) urls = NULL;
   guint i;
diff --git a/lib/ephy-web-app-utils.h b/lib/ephy-web-app-utils.h
index 5b3993fea..3870d63a8 100644
--- a/lib/ephy-web-app-utils.h
+++ b/lib/ephy-web-app-utils.h
@@ -30,6 +30,7 @@ typedef struct {
   char *id;
   char *name;
   char *icon_url;
+  char *tmp_icon_url;
   char *url;
   char *desktop_file; /* only used for legacy apps */
   char *desktop_path;
@@ -57,6 +58,11 @@ typedef enum {
   EPHY_WEB_APP_NOT_FOUND,
 } EphyWebAppFound;
 
+typedef enum {
+  EPHY_WEB_APP_NEED_TMP_ICON,
+  EPHY_WEB_APP_NO_TMP_ICON, /* avoid sync I/O, don't initialize app->tmp_icon_path */
+} EphyWebAppNeedTmpIcon;
+
 #define EPHY_WEB_APP_ICON_NAME "app-icon.png"
 
 char               *ephy_web_application_get_app_id_from_name (const char *name);
@@ -93,7 +99,8 @@ GKeyFile           *ephy_web_application_get_desktop_keyfile (const char  *id,
 
 char               *ephy_web_application_get_desktop_path (const char *id);
 
-EphyWebApplication *ephy_web_application_for_profile_directory (const char *profile_dir);
+EphyWebApplication *ephy_web_application_for_profile_directory (const char            *profile_dir,
+                                                                EphyWebAppNeedTmpIcon  need_tmp_icon);
 
 void                ephy_web_application_free (EphyWebApplication *app);
 
diff --git a/src/ephy-header-bar.c b/src/ephy-header-bar.c
index b03635adf..d6132ba8b 100644
--- a/src/ephy-header-bar.c
+++ b/src/ephy-header-bar.c
@@ -276,7 +276,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, "application-manager-button")));
 
     if (is_desktop_pantheon ())
       gtk_widget_destroy (GTK_WIDGET (gtk_builder_get_object (builder, "help-button")));
diff --git a/src/preferences/prefs-general-page.c b/src/preferences/prefs-general-page.c
index 6ef42f92b..297201850 100644
--- a/src/preferences/prefs-general-page.c
+++ b/src/preferences/prefs-general-page.c
@@ -1176,7 +1176,8 @@ setup_general_page (PrefsGeneralPage *general_page)
   /* ======================================================================== */
   if (ephy_embed_shell_get_mode (ephy_embed_shell_get_default ()) == EPHY_EMBED_SHELL_MODE_APPLICATION &&
       !ephy_is_running_inside_sandbox ()) {
-    general_page->webapp = ephy_web_application_for_profile_directory (ephy_profile_dir ());
+    general_page->webapp = ephy_web_application_for_profile_directory (ephy_profile_dir (),
+                                                                       EPHY_WEB_APP_NO_TMP_ICON);
     g_assert (general_page->webapp);
 
     if (!g_settings_get_boolean (EPHY_SETTINGS_WEB_APP, EPHY_PREFS_WEB_APP_SYSTEM)) {


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