summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Borges <felipeborges@gnome.org>2020-03-27 13:20:40 +0100
committerFelipe Borges <felipeborges@gnome.org>2020-04-14 12:39:21 +0200
commit8fe488d7b7fb5736be35bd5d3757296403a77157 (patch)
tree855226d2ef9783e23b0f04a5f5757df849645f2d
parent76d578666ff804a9f2c821051ffe9b6966f3dfb0 (diff)
downloadeog-use-gtk-appchooser-dialog.tar.gz
EogWindow: Use Portals for "Open With" when possibleuse-gtk-appchooser-dialog
If we detect that Eog is running inside a Flatpak container, we can use the OpenURI Portal[0] to open an AppChooser dialog for the user to pick an appliation. [0] https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.OpenURI Fixes #98
-rw-r--r--src/eog-util.c180
-rw-r--r--src/eog-util.h6
-rw-r--r--src/eog-window.c32
3 files changed, 208 insertions, 10 deletions
diff --git a/src/eog-util.c b/src/eog-util.c
index a6828a58..3e253dc9 100644
--- a/src/eog-util.c
+++ b/src/eog-util.c
@@ -22,6 +22,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/* For O_PATH */
+#define _GNU_SOURCE
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -37,12 +40,16 @@
#include "eog-debug.h"
#include <errno.h>
+#include <fcntl.h>
#include <string.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <gtk/gtk.h>
#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
#include <glib/gi18n.h>
+#include <sys/stat.h>
+#include <sys/types.h>
void
eog_util_show_help (const gchar *section, GtkWindow *parent)
@@ -503,3 +510,176 @@ eog_util_show_file_in_filemanager (GFile *file, GtkWindow *toplevel)
if (!done)
_eog_util_show_file_in_filemanager_fallback (file, toplevel);
}
+
+/* Portal */
+
+gboolean
+eog_util_is_running_inside_flatpak (void)
+{
+ return g_file_test ("/.flatpak-info", G_FILE_TEST_EXISTS);
+}
+
+static void
+response_cb (GDBusConnection *connection, const char *sender_name, const char *object_path, const char *interface_name, const char *signal_name, GVariant *parameters, gpointer user_data)
+{
+ GFile *file = G_FILE (user_data);
+ guint32 response;
+ guint signal_id;
+
+ signal_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (file), "signal-id"));
+ g_dbus_connection_signal_unsubscribe (connection, signal_id);
+
+ g_variant_get (parameters, "(u@a{sv})", &response, NULL);
+ if (response == 0) {
+ g_debug ("Opening file");
+ } else if (response == 1) {
+ g_debug ("User cancelled opening file");
+ } else {
+ g_warning ("Failed to open file via portal");
+ }
+}
+
+static void
+open_file_complete_cb (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GDBusProxy *proxy = G_DBUS_PROXY (source);
+ GFile *file = G_FILE (user_data);
+ GVariant *return_value = NULL;
+ const char *handle;
+ char *object_path = NULL;
+ GError *error = NULL;
+
+ return_value = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, NULL, result, &error);
+ if (!return_value) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to open file via portal: %s", error->message);
+
+ goto out;
+ }
+
+ g_variant_get (return_value, "(o)", &object_path);
+ handle = (const char *)g_object_get_data (G_OBJECT (file), "handle");
+ if (strcmp (handle, object_path) != 0) {
+ GDBusConnection *connection;
+ guint signal_id;
+
+ connection = g_dbus_proxy_get_connection (proxy);
+ signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (file), "signal-id"));
+ g_dbus_connection_signal_unsubscribe (connection, signal_id);
+
+ signal_id = g_dbus_connection_signal_subscribe (connection,
+ "org.freedesktop.portal.Desktop",
+ "org.freedesktop.portal.Request",
+ "Response",
+ handle,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
+ response_cb,
+ file,
+ NULL);
+ g_object_set_data (G_OBJECT (file), "signal-id", GUINT_TO_POINTER (signal_id));
+ }
+
+out:
+ if (return_value)
+ g_variant_unref (return_value);
+ if (object_path)
+ g_free (object_path);
+}
+
+static void
+open_with_flatpak_portal_cb (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ GVariantBuilder builder;
+ GUnixFDList *fd_list;
+ GFile *file;
+ GDBusProxy *proxy;
+ GDBusConnection *connection;
+ GError *error = NULL;
+ guint signal_id;
+ char *sender, *token, *handle;
+ int fd;
+
+ file = G_FILE (user_data);
+ fd = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (file), "fd"));
+
+ proxy = g_dbus_proxy_new_for_bus_finish (result, &error);
+ if (!proxy) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to create D-Bus proxy for OpenURI portal: %s", error->message);
+
+ close (fd);
+ return;
+ }
+
+ connection = g_dbus_proxy_get_connection (proxy);
+ sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1);
+ for (guint i = 0; sender[i] != '\0'; i++) {
+ if (sender[i] == '.') {
+ sender[i] = '_';
+ }
+ }
+
+ token = g_strdup_printf ("eog%u", g_random_int ());
+ handle = g_strdup_printf ("/org/freedesktop/portal/desktop/request/%s/%s", sender, token);
+
+ g_object_set_data_full (G_OBJECT (file), "handle", handle, g_free);
+ g_free (sender);
+
+ signal_id = g_dbus_connection_signal_subscribe (connection,
+ "org.freedesktop.portal.Desktop",
+ "org.freedesktop.portal.Request",
+ "Response",
+ handle,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
+ response_cb,
+ file,
+ NULL);
+ g_object_set_data (G_OBJECT (file), "signal-id", GUINT_TO_POINTER (signal_id));
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+ g_variant_builder_add (&builder, "{sv}", "handle_token", g_variant_new_string (token));
+ g_variant_builder_add (&builder, "{sv}", "ask", g_variant_new ("b", TRUE));
+ g_free (token);
+
+ fd_list = g_unix_fd_list_new_from_array (&fd, 1);
+ g_dbus_proxy_call_with_unix_fd_list (proxy,
+ "OpenFile",
+ g_variant_new ("(s@h@a{sv})",
+ "",
+ g_variant_new ("h", 0),
+ g_variant_builder_end (&builder)),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ fd_list,
+ NULL,
+ open_file_complete_cb,
+ file);
+ g_object_unref (fd_list);
+}
+
+void
+eog_util_open_file_with_flatpak_portal (GFile *file)
+{
+ const gchar *path;
+ int fd;
+
+ path = g_file_get_path (file);
+ fd = open (path, O_PATH | O_CLOEXEC);
+ if (fd == -1) {
+ g_warning ("Failed to open %s: %s", path, g_strerror (errno));
+ return;
+ }
+
+ g_object_set_data (G_OBJECT (file), "fd", GINT_TO_POINTER (fd));
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+ NULL,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.OpenURI",
+ NULL,
+ open_with_flatpak_portal_cb,
+ file);
+}
diff --git a/src/eog-util.h b/src/eog-util.h
index 9f2ad4c1..d328e1f9 100644
--- a/src/eog-util.h
+++ b/src/eog-util.h
@@ -69,6 +69,12 @@ G_GNUC_INTERNAL
void eog_util_show_file_in_filemanager (GFile *file,
GtkWindow *toplevel);
+G_GNUC_INTERNAL
+gboolean eog_util_is_running_inside_flatpak (void);
+
+G_GNUC_INTERNAL
+void eog_util_open_file_with_flatpak_portal (GFile *file);
+
G_END_DECLS
#endif /* __EOG_UTIL_H__ */
diff --git a/src/eog-window.c b/src/eog-window.c
index e84a2b91..75d7c138 100644
--- a/src/eog-window.c
+++ b/src/eog-window.c
@@ -1065,28 +1065,21 @@ app_chooser_dialog_response_cb (GtkDialog *dialog,
g_list_free (files);
g_object_unref (file);
+
out:
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
-eog_window_action_open_with (GSimpleAction *action,
- GVariant *parameter,
- gpointer user_data)
+eog_window_open_file_chooser_dialog (EogWindow *window)
{
- EogWindow *window;
GtkWidget *dialog;
GFileInfo *file_info;
GFile *file;
const gchar *mime_type = NULL;
- g_return_if_fail (EOG_IS_WINDOW (user_data));
- window = EOG_WINDOW (user_data);
-
file = eog_image_get_file (window->priv->image);
- file_info = g_file_query_info (file,
- G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
- 0, NULL, NULL);
+ file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, 0, NULL, NULL);
mime_type = g_content_type_get_mime_type (
g_file_info_get_content_type (file_info));
g_object_unref (file_info);
@@ -1106,6 +1099,25 @@ eog_window_action_open_with (GSimpleAction *action,
}
static void
+eog_window_action_open_with (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ EogWindow *window;
+
+ g_return_if_fail (EOG_IS_WINDOW (user_data));
+ window = EOG_WINDOW (user_data);
+
+ if (eog_util_is_running_inside_flatpak ()) {
+ GFile *file = eog_image_get_file (window->priv->image);
+
+ eog_util_open_file_with_flatpak_portal (file);
+ } else {
+ eog_window_open_file_chooser_dialog (window);
+ }
+}
+
+static void
eog_window_clear_load_job (EogWindow *window)
{
EogWindowPrivate *priv = window->priv;