From: Matthias Clasen Date: Sun, 5 Feb 2023 07:49:21 +0000 (+0100) Subject: Use a Gtk prefix for dbus-generated code X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~7^2~30^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=190d8ef8ff63f9014b595f8b47c9142eddbca34c;p=gtk4.git Use a Gtk prefix for dbus-generated code Copying this file from GIO without renaming it was not the greatest idea in retrospect. Fixes: #5572 --- diff --git a/gtk/gopenuriportal.c b/gtk/gopenuriportal.c deleted file mode 100644 index bc3211eb3d..0000000000 --- a/gtk/gopenuriportal.c +++ /dev/null @@ -1,519 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright 2017 Red Hat, Inc. - * - * SPDX-License-Identifier: LGPL-2.1-or-later - * - * 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.1 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 . - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "gopenuriportal.h" -#include "xdp-dbus.h" -#include "gtkwindowprivate.h" -#include "gtkprivate.h" -#include "gtkdialogerror.h" - -#ifdef G_OS_UNIX -#include -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#else -#define HAVE_O_CLOEXEC 1 -#endif - - -static GXdpOpenURI *openuri; - -static gboolean -init_openuri_portal (void) -{ - static gsize openuri_inited = 0; - - if (g_once_init_enter (&openuri_inited)) - { - GError *error = NULL; - GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); - - if (connection != NULL) - { - openuri = gxdp_open_uri_proxy_new_sync (connection, 0, - PORTAL_BUS_NAME, - PORTAL_OBJECT_PATH, - NULL, &error); - if (openuri == NULL) - { - g_warning ("Cannot create OpenURI portal proxy: %s", error->message); - g_error_free (error); - } - - g_object_unref (connection); - } - else - { - g_warning ("Cannot connect to session bus when initializing OpenURI portal: %s", - error->message); - g_error_free (error); - } - - g_once_init_leave (&openuri_inited, 1); - } - - return openuri != NULL; -} - -gboolean -g_openuri_portal_is_available (void) -{ - return init_openuri_portal (); -} - -enum { - XDG_DESKTOP_PORTAL_SUCCESS = 0, - XDG_DESKTOP_PORTAL_CANCELLED = 1, - XDG_DESKTOP_PORTAL_FAILED = 2 -}; - -enum { - OPEN_URI = 0, - OPEN_FILE = 1, - OPEN_FOLDER = 2 -}; - -typedef struct { - GtkWindow *parent; - GFile *file; - char *uri; - gboolean open_folder; - GDBusConnection *connection; - GCancellable *cancellable; - GTask *task; - char *handle; - guint signal_id; - glong cancel_handler; - int call; -} OpenUriData; - -static void -open_uri_data_free (OpenUriData *data) -{ - if (data->signal_id) - g_dbus_connection_signal_unsubscribe (data->connection, data->signal_id); - g_clear_object (&data->connection); - if (data->cancel_handler) - g_signal_handler_disconnect (data->cancellable, data->cancel_handler); - if (data->parent) - gtk_window_unexport_handle (data->parent); - g_clear_object (&data->parent); - g_clear_object (&data->file); - g_free (data->uri); - g_clear_object (&data->cancellable); - g_clear_object (&data->task); - g_free (data->handle); - g_free (data); -} - -static void -response_received (GDBusConnection *connection, - const char *sender_name, - const char *object_path, - const char *interface_name, - const char *signal_name, - GVariant *parameters, - gpointer user_data) -{ - GTask *task = user_data; - guint32 response; - - g_variant_get (parameters, "(u@a{sv})", &response, NULL); - - switch (response) - { - case XDG_DESKTOP_PORTAL_SUCCESS: - g_task_return_boolean (task, TRUE); - break; - case XDG_DESKTOP_PORTAL_CANCELLED: - g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED, "The portal dialog was dismissed by the user"); - break; - case XDG_DESKTOP_PORTAL_FAILED: - default: - g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, "The application launch failed"); - break; - } - - g_object_unref (task); -} - -static void -open_call_done (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GXdpOpenURI *portal = GXDP_OPEN_URI (source); - GTask *task = user_data; - OpenUriData *data = g_task_get_task_data (task); - GError *error = NULL; - gboolean res; - char *path = NULL; - - switch (data->call) - { - case OPEN_FILE: - res = gxdp_open_uri_call_open_file_finish (portal, &path, NULL, result, &error); - break; - case OPEN_FOLDER: - res = gxdp_open_uri_call_open_directory_finish (portal, &path, NULL, result, &error); - break; - case OPEN_URI: - res = gxdp_open_uri_call_open_uri_finish (portal, &path, result, &error); - break; - default: - g_assert_not_reached (); - break; - } - - if (!res) - { - g_free (path); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - if (g_strcmp0 (data->handle, path) != 0) - { - g_dbus_connection_signal_unsubscribe (data->connection, data->signal_id); - - data->signal_id = g_dbus_connection_signal_subscribe (data->connection, - PORTAL_BUS_NAME, - PORTAL_REQUEST_INTERFACE, - "Response", - path, - NULL, - G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, - response_received, - task, - NULL); - g_free (data->handle); - data->handle = g_strdup (path); - } - - g_free (path); -} - -static void -send_close (OpenUriData *data) -{ - GDBusMessage *message; - GError *error = NULL; - - message = g_dbus_message_new_method_call (PORTAL_BUS_NAME, - PORTAL_OBJECT_PATH, - PORTAL_REQUEST_INTERFACE, - "Close"); - g_dbus_message_set_body (message, g_variant_new ("(o)", data->handle)); - - if (!g_dbus_connection_send_message (data->connection, - message, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - NULL, &error)) - { - g_warning ("unable to send Close message: %s", error->message); - g_error_free (error); - } - - g_object_unref (message); -} - -static void -canceled (GCancellable *cancellable, - GTask *task) -{ - OpenUriData *data = g_task_get_task_data (task); - - send_close (data); - - g_task_return_new_error (task, - GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, - "The OpenURI portal call was cancelled by the application"); - g_object_unref (task); -} - -static void -open_uri (OpenUriData *data, - const char *parent_window, - const char *activation_token, - GAsyncReadyCallback callback) -{ - GFile *file = data->file; - gboolean open_folder = data->open_folder; - GTask *task; - GVariant *opts = NULL; - int i; - GDBusConnection *connection; - GVariantBuilder opt_builder; - char *token; - char *sender; - - connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri)); - data->connection = g_object_ref (connection); - - task = g_task_new (NULL, NULL, callback, data); - g_task_set_check_cancellable (task, FALSE); - g_task_set_task_data (task, data, NULL); - if (data->cancellable) - data->cancel_handler = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (canceled), task); - - token = g_strdup_printf ("gtk%d", g_random_int_range (0, G_MAXINT)); - sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1); - for (i = 0; sender[i]; i++) - if (sender[i] == '.') - sender[i] = '_'; - - data->handle = g_strdup_printf ("/org/freedesktop/portal/desktop/request/%s/%s", sender, token); - g_free (sender); - - data->signal_id = g_dbus_connection_signal_subscribe (connection, - PORTAL_BUS_NAME, - PORTAL_REQUEST_INTERFACE, - "Response", - data->handle, - NULL, - G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, - response_received, - task, - NULL); - - g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token)); - g_free (token); - - if (activation_token) - g_variant_builder_add (&opt_builder, "{sv}", "activation_token", g_variant_new_string (activation_token)); - - opts = g_variant_builder_end (&opt_builder); - - if (file && g_file_is_native (file)) - { - const char *path = NULL; - GUnixFDList *fd_list = NULL; - int fd, fd_id, errsv; - - path = g_file_peek_path (file); - fd = g_open (path, O_RDONLY | O_CLOEXEC); - errsv = errno; - if (fd == -1) - { - g_task_return_new_error (task, - G_IO_ERROR, g_io_error_from_errno (errsv), - "Failed to open file"); - g_object_unref (task); - return; - } - -#ifndef HAVE_O_CLOEXEC - fcntl (fd, F_SETFD, FD_CLOEXEC); -#endif - fd_list = g_unix_fd_list_new_from_array (&fd, 1); - fd = -1; - fd_id = 0; - - if (open_folder) - { - data->call = OPEN_FOLDER; - gxdp_open_uri_call_open_directory (openuri, - parent_window ? parent_window : "", - g_variant_new ("h", fd_id), - opts, - fd_list, - NULL, - open_call_done, - task); - } - else - { - data->call = OPEN_FILE; - gxdp_open_uri_call_open_file (openuri, - parent_window ? parent_window : "", - g_variant_new ("h", fd_id), - opts, - fd_list, - NULL, - open_call_done, - task); - } - - g_object_unref (fd_list); - } - else - { - char *uri = NULL; - - if (file) - uri = g_file_get_uri (file); - - data->call = OPEN_URI; - gxdp_open_uri_call_open_uri (openuri, - parent_window ? parent_window : "", - uri ? uri : data->uri, - opts, - NULL, - open_call_done, - task); - g_free (uri); - } -} - -static void -open_uri_done (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - OpenUriData *data = user_data; - GError *error = NULL; - - if (!g_task_propagate_boolean (G_TASK (result), &error)) - { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - { - g_error_free (error); - g_task_return_new_error (data->task, - GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, - "The operation was cancelled by the application"); - } - else - g_task_return_error (data->task, error); - } - else - g_task_return_boolean (data->task, TRUE); - - open_uri_data_free (data); -} - -static void -window_handle_exported (GtkWindow *window, - const char *handle, - gpointer user_data) -{ - OpenUriData *data = user_data; - GdkDisplay *display; - GAppLaunchContext *context; - char *activation_token = NULL; - - if (window) - display = gtk_widget_get_display (GTK_WIDGET (window)); - else - display = gdk_display_get_default (); - - /* FIXME - * Call the vfunc directly since g_app_launch_context_get_startup_notify_id - * has NULL checks. - * - * We should have a more direct way to do this. - */ - context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display)); - activation_token = G_APP_LAUNCH_CONTEXT_GET_CLASS (context)->get_startup_notify_id (context, NULL, NULL); - g_object_unref (context); - - open_uri (data, handle, activation_token, open_uri_done); - - g_free (activation_token); -} - -void -g_openuri_portal_open_async (GFile *file, - gboolean open_folder, - GtkWindow *parent, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - OpenUriData *data; - - if (!init_openuri_portal ()) - { - g_task_report_new_error (NULL, callback, user_data, NULL, - GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, - "The OpenURI portal is not available"); - return; - } - - data = g_new0 (OpenUriData, 1); - data->parent = parent ? g_object_ref (parent) : NULL; - data->file = g_object_ref (file); - data->open_folder = open_folder; - data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - data->task = g_task_new (parent, cancellable, callback, user_data); - g_task_set_check_cancellable (data->task, FALSE); - g_task_set_source_tag (data->task, g_openuri_portal_open_async); - - if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data)) - window_handle_exported (parent, NULL, data); -} - -gboolean -g_openuri_portal_open_finish (GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_async, FALSE); - - return g_task_propagate_boolean (G_TASK (result), error); -} - -void -g_openuri_portal_open_uri_async (const char *uri, - GtkWindow *parent, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - OpenUriData *data; - - if (!init_openuri_portal ()) - { - g_task_report_new_error (NULL, callback, user_data, NULL, - GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, - "The OpenURI portal is not available"); - return; - } - - data = g_new0 (OpenUriData, 1); - data->parent = parent ? g_object_ref (parent) : NULL; - data->uri = g_strdup (uri); - data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - data->task = g_task_new (parent, cancellable, callback, user_data); - g_task_set_check_cancellable (data->task, FALSE); - g_task_set_source_tag (data->task, g_openuri_portal_open_uri_async); - - if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data)) - window_handle_exported (parent, NULL, data); -} - -gboolean -g_openuri_portal_open_uri_finish (GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == g_openuri_portal_open_uri_async, FALSE); - - return g_task_propagate_boolean (G_TASK (result), error); -} diff --git a/gtk/gopenuriportal.h b/gtk/gopenuriportal.h deleted file mode 100644 index 047a9f3896..0000000000 --- a/gtk/gopenuriportal.h +++ /dev/null @@ -1,52 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright 2017 Red Hat, Inc. - * - * SPDX-License-Identifier: LGPL-2.1-or-later - * - * 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.1 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 . - */ - -#ifndef __G_OPEN_URI_PORTAL_H__ - -#include "gtkwindow.h" -#include -#include - -G_BEGIN_DECLS - -gboolean g_openuri_portal_is_available (void); - -void g_openuri_portal_open_async (GFile *file, - gboolean open_folder, - GtkWindow *window, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean g_openuri_portal_open_finish (GAsyncResult *result, - GError **error); - -void g_openuri_portal_open_uri_async (const char *uri, - GtkWindow *window, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean g_openuri_portal_open_uri_finish (GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c index b6382ccdba..775c40554f 100644 --- a/gtk/gtkfilechooserwidget.c +++ b/gtk/gtkfilechooserwidget.c @@ -96,7 +96,7 @@ #include "gtkexpression.h" #ifndef G_OS_WIN32 -#include "gopenuriportal.h" +#include "gtkopenuriportal.h" #endif #include diff --git a/gtk/gtkfilelauncher.c b/gtk/gtkfilelauncher.c index 6e4f840876..a4c7fc5379 100644 --- a/gtk/gtkfilelauncher.c +++ b/gtk/gtkfilelauncher.c @@ -22,7 +22,7 @@ #include "gtkfilelauncher.h" #include "gtkdialogerror.h" -#include "gopenuriportal.h" +#include "gtkopenuriportal.h" #include "deprecated/gtkshow.h" #include @@ -219,7 +219,7 @@ open_done (GObject *source, GTask *task = G_TASK (data); GError *error = NULL; - if (!g_openuri_portal_open_finish (result, &error)) + if (!gtk_openuri_portal_open_finish (result, &error)) g_task_return_error (task, error); else g_task_return_boolean (task, TRUE); @@ -367,9 +367,9 @@ gtk_file_launcher_launch (GtkFileLauncher *self, } #ifndef G_OS_WIN32 - if (g_openuri_portal_is_available ()) + if (gtk_openuri_portal_is_available ()) { - g_openuri_portal_open_async (self->file, FALSE, parent, cancellable, open_done, task); + gtk_openuri_portal_open_async (self->file, FALSE, parent, cancellable, open_done, task); } else #endif @@ -461,9 +461,9 @@ gtk_file_launcher_open_containing_folder (GtkFileLauncher *self, } #ifndef G_OS_WIN32 - if (g_openuri_portal_is_available ()) + if (gtk_openuri_portal_is_available ()) { - g_openuri_portal_open_async (self->file, TRUE, parent, cancellable, open_done, task); + gtk_openuri_portal_open_async (self->file, TRUE, parent, cancellable, open_done, task); } else #endif diff --git a/gtk/gtkopenuriportal.c b/gtk/gtkopenuriportal.c new file mode 100644 index 0000000000..10001cacf4 --- /dev/null +++ b/gtk/gtkopenuriportal.c @@ -0,0 +1,519 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright 2017 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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 . + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "gtkopenuriportal.h" +#include "xdp-dbus.h" +#include "gtkwindowprivate.h" +#include "gtkprivate.h" +#include "gtkdialogerror.h" + +#ifdef G_OS_UNIX +#include +#endif + +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#else +#define HAVE_O_CLOEXEC 1 +#endif + + +static GtkXdpOpenURI *openuri; + +static gboolean +init_openuri_portal (void) +{ + static gsize openuri_inited = 0; + + if (g_once_init_enter (&openuri_inited)) + { + GError *error = NULL; + GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + + if (connection != NULL) + { + openuri = gtk_xdp_open_uri_proxy_new_sync (connection, 0, + PORTAL_BUS_NAME, + PORTAL_OBJECT_PATH, + NULL, &error); + if (openuri == NULL) + { + g_warning ("Cannot create OpenURI portal proxy: %s", error->message); + g_error_free (error); + } + + g_object_unref (connection); + } + else + { + g_warning ("Cannot connect to session bus when initializing OpenURI portal: %s", + error->message); + g_error_free (error); + } + + g_once_init_leave (&openuri_inited, 1); + } + + return openuri != NULL; +} + +gboolean +gtk_openuri_portal_is_available (void) +{ + return init_openuri_portal (); +} + +enum { + XDG_DESKTOP_PORTAL_SUCCESS = 0, + XDG_DESKTOP_PORTAL_CANCELLED = 1, + XDG_DESKTOP_PORTAL_FAILED = 2 +}; + +enum { + OPEN_URI = 0, + OPEN_FILE = 1, + OPEN_FOLDER = 2 +}; + +typedef struct { + GtkWindow *parent; + GFile *file; + char *uri; + gboolean open_folder; + GDBusConnection *connection; + GCancellable *cancellable; + GTask *task; + char *handle; + guint signal_id; + glong cancel_handler; + int call; +} OpenUriData; + +static void +open_uri_data_free (OpenUriData *data) +{ + if (data->signal_id) + g_dbus_connection_signal_unsubscribe (data->connection, data->signal_id); + g_clear_object (&data->connection); + if (data->cancel_handler) + g_signal_handler_disconnect (data->cancellable, data->cancel_handler); + if (data->parent) + gtk_window_unexport_handle (data->parent); + g_clear_object (&data->parent); + g_clear_object (&data->file); + g_free (data->uri); + g_clear_object (&data->cancellable); + g_clear_object (&data->task); + g_free (data->handle); + g_free (data); +} + +static void +response_received (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + GTask *task = user_data; + guint32 response; + + g_variant_get (parameters, "(u@a{sv})", &response, NULL); + + switch (response) + { + case XDG_DESKTOP_PORTAL_SUCCESS: + g_task_return_boolean (task, TRUE); + break; + case XDG_DESKTOP_PORTAL_CANCELLED: + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_DISMISSED, "The portal dialog was dismissed by the user"); + break; + case XDG_DESKTOP_PORTAL_FAILED: + default: + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, "The application launch failed"); + break; + } + + g_object_unref (task); +} + +static void +open_call_done (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GtkXdpOpenURI *portal = GTK_XDP_OPEN_URI (source); + GTask *task = user_data; + OpenUriData *data = g_task_get_task_data (task); + GError *error = NULL; + gboolean res; + char *path = NULL; + + switch (data->call) + { + case OPEN_FILE: + res = gtk_xdp_open_uri_call_open_file_finish (portal, &path, NULL, result, &error); + break; + case OPEN_FOLDER: + res = gtk_xdp_open_uri_call_open_directory_finish (portal, &path, NULL, result, &error); + break; + case OPEN_URI: + res = gtk_xdp_open_uri_call_open_uri_finish (portal, &path, result, &error); + break; + default: + g_assert_not_reached (); + break; + } + + if (!res) + { + g_free (path); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (g_strcmp0 (data->handle, path) != 0) + { + g_dbus_connection_signal_unsubscribe (data->connection, data->signal_id); + + data->signal_id = g_dbus_connection_signal_subscribe (data->connection, + PORTAL_BUS_NAME, + PORTAL_REQUEST_INTERFACE, + "Response", + path, + NULL, + G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, + response_received, + task, + NULL); + g_free (data->handle); + data->handle = g_strdup (path); + } + + g_free (path); +} + +static void +send_close (OpenUriData *data) +{ + GDBusMessage *message; + GError *error = NULL; + + message = g_dbus_message_new_method_call (PORTAL_BUS_NAME, + PORTAL_OBJECT_PATH, + PORTAL_REQUEST_INTERFACE, + "Close"); + g_dbus_message_set_body (message, g_variant_new ("(o)", data->handle)); + + if (!g_dbus_connection_send_message (data->connection, + message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, &error)) + { + g_warning ("unable to send Close message: %s", error->message); + g_error_free (error); + } + + g_object_unref (message); +} + +static void +canceled (GCancellable *cancellable, + GTask *task) +{ + OpenUriData *data = g_task_get_task_data (task); + + send_close (data); + + g_task_return_new_error (task, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, + "The OpenURI portal call was cancelled by the application"); + g_object_unref (task); +} + +static void +open_uri (OpenUriData *data, + const char *parent_window, + const char *activation_token, + GAsyncReadyCallback callback) +{ + GFile *file = data->file; + gboolean open_folder = data->open_folder; + GTask *task; + GVariant *opts = NULL; + int i; + GDBusConnection *connection; + GVariantBuilder opt_builder; + char *token; + char *sender; + + connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri)); + data->connection = g_object_ref (connection); + + task = g_task_new (NULL, NULL, callback, data); + g_task_set_check_cancellable (task, FALSE); + g_task_set_task_data (task, data, NULL); + if (data->cancellable) + data->cancel_handler = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (canceled), task); + + token = g_strdup_printf ("gtk%d", g_random_int_range (0, G_MAXINT)); + sender = g_strdup (g_dbus_connection_get_unique_name (connection) + 1); + for (i = 0; sender[i]; i++) + if (sender[i] == '.') + sender[i] = '_'; + + data->handle = g_strdup_printf ("/org/freedesktop/portal/desktop/request/%s/%s", sender, token); + g_free (sender); + + data->signal_id = g_dbus_connection_signal_subscribe (connection, + PORTAL_BUS_NAME, + PORTAL_REQUEST_INTERFACE, + "Response", + data->handle, + NULL, + G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, + response_received, + task, + NULL); + + g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&opt_builder, "{sv}", "handle_token", g_variant_new_string (token)); + g_free (token); + + if (activation_token) + g_variant_builder_add (&opt_builder, "{sv}", "activation_token", g_variant_new_string (activation_token)); + + opts = g_variant_builder_end (&opt_builder); + + if (file && g_file_is_native (file)) + { + const char *path = NULL; + GUnixFDList *fd_list = NULL; + int fd, fd_id, errsv; + + path = g_file_peek_path (file); + fd = g_open (path, O_RDONLY | O_CLOEXEC); + errsv = errno; + if (fd == -1) + { + g_task_return_new_error (task, + G_IO_ERROR, g_io_error_from_errno (errsv), + "Failed to open file"); + g_object_unref (task); + return; + } + +#ifndef HAVE_O_CLOEXEC + fcntl (fd, F_SETFD, FD_CLOEXEC); +#endif + fd_list = g_unix_fd_list_new_from_array (&fd, 1); + fd = -1; + fd_id = 0; + + if (open_folder) + { + data->call = OPEN_FOLDER; + gtk_xdp_open_uri_call_open_directory (openuri, + parent_window ? parent_window : "", + g_variant_new ("h", fd_id), + opts, + fd_list, + NULL, + open_call_done, + task); + } + else + { + data->call = OPEN_FILE; + gtk_xdp_open_uri_call_open_file (openuri, + parent_window ? parent_window : "", + g_variant_new ("h", fd_id), + opts, + fd_list, + NULL, + open_call_done, + task); + } + + g_object_unref (fd_list); + } + else + { + char *uri = NULL; + + if (file) + uri = g_file_get_uri (file); + + data->call = OPEN_URI; + gtk_xdp_open_uri_call_open_uri (openuri, + parent_window ? parent_window : "", + uri ? uri : data->uri, + opts, + NULL, + open_call_done, + task); + g_free (uri); + } +} + +static void +open_uri_done (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + OpenUriData *data = user_data; + GError *error = NULL; + + if (!g_task_propagate_boolean (G_TASK (result), &error)) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + g_error_free (error); + g_task_return_new_error (data->task, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, + "The operation was cancelled by the application"); + } + else + g_task_return_error (data->task, error); + } + else + g_task_return_boolean (data->task, TRUE); + + open_uri_data_free (data); +} + +static void +window_handle_exported (GtkWindow *window, + const char *handle, + gpointer user_data) +{ + OpenUriData *data = user_data; + GdkDisplay *display; + GAppLaunchContext *context; + char *activation_token = NULL; + + if (window) + display = gtk_widget_get_display (GTK_WIDGET (window)); + else + display = gdk_display_get_default (); + + /* FIXME + * Call the vfunc directly since g_app_launch_context_get_startup_notify_id + * has NULL checks. + * + * We should have a more direct way to do this. + */ + context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display)); + activation_token = G_APP_LAUNCH_CONTEXT_GET_CLASS (context)->get_startup_notify_id (context, NULL, NULL); + g_object_unref (context); + + open_uri (data, handle, activation_token, open_uri_done); + + g_free (activation_token); +} + +void +gtk_openuri_portal_open_async (GFile *file, + gboolean open_folder, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OpenUriData *data; + + if (!init_openuri_portal ()) + { + g_task_report_new_error (NULL, callback, user_data, NULL, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, + "The OpenURI portal is not available"); + return; + } + + data = g_new0 (OpenUriData, 1); + data->parent = parent ? g_object_ref (parent) : NULL; + data->file = g_object_ref (file); + data->open_folder = open_folder; + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + data->task = g_task_new (parent, cancellable, callback, user_data); + g_task_set_check_cancellable (data->task, FALSE); + g_task_set_source_tag (data->task, gtk_openuri_portal_open_async); + + if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data)) + window_handle_exported (parent, NULL, data); +} + +gboolean +gtk_openuri_portal_open_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_openuri_portal_open_async, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +void +gtk_openuri_portal_open_uri_async (const char *uri, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + OpenUriData *data; + + if (!init_openuri_portal ()) + { + g_task_report_new_error (NULL, callback, user_data, NULL, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, + "The OpenURI portal is not available"); + return; + } + + data = g_new0 (OpenUriData, 1); + data->parent = parent ? g_object_ref (parent) : NULL; + data->uri = g_strdup (uri); + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + data->task = g_task_new (parent, cancellable, callback, user_data); + g_task_set_check_cancellable (data->task, FALSE); + g_task_set_source_tag (data->task, gtk_openuri_portal_open_uri_async); + + if (!parent || !gtk_window_export_handle (parent, window_handle_exported, data)) + window_handle_exported (parent, NULL, data); +} + +gboolean +gtk_openuri_portal_open_uri_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_openuri_portal_open_uri_async, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} diff --git a/gtk/gtkopenuriportal.h b/gtk/gtkopenuriportal.h new file mode 100644 index 0000000000..9d7d0fca37 --- /dev/null +++ b/gtk/gtkopenuriportal.h @@ -0,0 +1,52 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright 2017 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * 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.1 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 . + */ + +#ifndef __G_OPEN_URI_PORTAL_H__ + +#include "gtkwindow.h" +#include +#include + +G_BEGIN_DECLS + +gboolean gtk_openuri_portal_is_available (void); + +void gtk_openuri_portal_open_async (GFile *file, + gboolean open_folder, + GtkWindow *window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gtk_openuri_portal_open_finish (GAsyncResult *result, + GError **error); + +void gtk_openuri_portal_open_uri_async (const char *uri, + GtkWindow *window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean gtk_openuri_portal_open_uri_finish (GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif diff --git a/gtk/gtkurilauncher.c b/gtk/gtkurilauncher.c index cf705651ea..bf6e2e260b 100644 --- a/gtk/gtkurilauncher.c +++ b/gtk/gtkurilauncher.c @@ -22,7 +22,7 @@ #include "gtkurilauncher.h" #include "gtkdialogerror.h" -#include "gopenuriportal.h" +#include "gtkopenuriportal.h" #include "deprecated/gtkshow.h" #include @@ -221,7 +221,7 @@ open_done (GObject *source, GTask *task = G_TASK (data); GError *error = NULL; - if (!g_openuri_portal_open_uri_finish (result, &error)) + if (!gtk_openuri_portal_open_uri_finish (result, &error)) g_task_return_error (task, error); else g_task_return_boolean (task, TRUE); @@ -300,8 +300,8 @@ gtk_uri_launcher_launch (GtkUriLauncher *self, } #ifndef G_OS_WIN32 - if (g_openuri_portal_is_available ()) - g_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task); + if (gtk_openuri_portal_is_available ()) + gtk_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task); else #endif G_GNUC_BEGIN_IGNORE_DEPRECATIONS diff --git a/gtk/meson.build b/gtk/meson.build index 22fe7fb816..82ad8eff7a 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -758,7 +758,7 @@ if not (x11_enabled or win32_enabled) endif if not os_win32 - gtk_sources += ['gopenuriportal.c', ] + gtk_sources += ['gtkopenuriportal.c', ] endif gen_gtk_gresources_xml = find_program('gen-gtk-gresources-xml.py') @@ -991,7 +991,7 @@ else xdp_dbus_generated = gnome.gdbus_codegen('xdp-dbus', sources : 'org.freedesktop.portal.OpenURI.xml', interface_prefix : 'org.freedesktop.portal.', - namespace : 'GXdp', + namespace : 'GtkXdp', ) endif