forked from AuroraMiddleware/gtk
selection: Support the file transfer portal
When the selection target is application/vnd.portal.files, send files through the file transfer portal.
This commit is contained in:
parent
bae6a37ed9
commit
9f81db139d
498
gtk/filetransferportal.c
Normal file
498
gtk/filetransferportal.c
Normal file
@ -0,0 +1,498 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
|
||||
#include <gio/gunixfdlist.h>
|
||||
|
||||
#ifndef O_PATH
|
||||
#define O_PATH 0
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#else
|
||||
#define HAVE_O_CLOEXEC 1
|
||||
#endif
|
||||
|
||||
#include "filetransferportalprivate.h"
|
||||
|
||||
static GDBusProxy *file_transfer_proxy = NULL;
|
||||
|
||||
typedef struct {
|
||||
GTask *task;
|
||||
char **files;
|
||||
int len;
|
||||
int start;
|
||||
} AddFileData;
|
||||
|
||||
static void
|
||||
free_add_file_data (gpointer data)
|
||||
{
|
||||
AddFileData *afd = data;
|
||||
|
||||
g_object_unref (afd->task);
|
||||
g_free (afd->files);
|
||||
g_free (afd);
|
||||
}
|
||||
|
||||
static void add_files (GDBusProxy *proxy,
|
||||
AddFileData *afd);
|
||||
|
||||
static void
|
||||
add_files_done (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GDBusProxy *proxy = G_DBUS_PROXY (object);
|
||||
AddFileData *afd = data;
|
||||
GError *error = NULL;
|
||||
GVariant *ret;
|
||||
|
||||
ret = g_dbus_proxy_call_with_unix_fd_list_finish (proxy, NULL, result, &error);
|
||||
if (ret == NULL)
|
||||
{
|
||||
g_task_return_error (afd->task, error);
|
||||
free_add_file_data (afd);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_unref (ret);
|
||||
|
||||
if (afd->start >= afd->len)
|
||||
{
|
||||
g_task_return_boolean (afd->task, TRUE);
|
||||
free_add_file_data (afd);
|
||||
return;
|
||||
}
|
||||
|
||||
add_files (proxy, afd);
|
||||
}
|
||||
|
||||
/* We call AddFiles in chunks of 16 to avoid running into
|
||||
* the per-message fd limit of the bus.
|
||||
*/
|
||||
static void
|
||||
add_files (GDBusProxy *proxy,
|
||||
AddFileData *afd)
|
||||
{
|
||||
GUnixFDList *fd_list;
|
||||
GVariantBuilder fds, options;
|
||||
int i;
|
||||
char *key;
|
||||
|
||||
g_variant_builder_init (&fds, G_VARIANT_TYPE ("ah"));
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
|
||||
for (i = 0; afd->files[afd->start + i]; i++)
|
||||
{
|
||||
int fd;
|
||||
int fd_in;
|
||||
GError *error = NULL;
|
||||
|
||||
if (i == 16)
|
||||
break;
|
||||
|
||||
fd = open (afd->files[afd->start + i], O_PATH | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
{
|
||||
g_task_return_new_error (afd->task, G_IO_ERROR, g_io_error_from_errno (errno),
|
||||
"Failed to open %s", afd->files[afd->start + i]);
|
||||
free_add_file_data (afd);
|
||||
g_object_unref (fd_list);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef HAVE_O_CLOEXEC
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
fd_in = g_unix_fd_list_append (fd_list, fd, &error);
|
||||
close (fd);
|
||||
|
||||
if (fd_in == -1)
|
||||
{
|
||||
g_task_return_error (afd->task, error);
|
||||
free_add_file_data (afd);
|
||||
g_object_unref (fd_list);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_builder_add (&fds, "h", fd_in);
|
||||
}
|
||||
|
||||
afd->start += 16;
|
||||
|
||||
key = (char *)g_object_get_data (G_OBJECT (afd->task), "key");
|
||||
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
g_dbus_proxy_call_with_unix_fd_list (proxy,
|
||||
"AddFiles",
|
||||
g_variant_new ("(saha{sv})", key, &fds, &options),
|
||||
0, -1,
|
||||
fd_list,
|
||||
NULL,
|
||||
add_files_done, afd);
|
||||
|
||||
g_object_unref (fd_list);
|
||||
}
|
||||
|
||||
static void
|
||||
start_session_done (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GDBusProxy *proxy = G_DBUS_PROXY (object);
|
||||
AddFileData *afd = data;
|
||||
GError *error = NULL;
|
||||
GVariant *ret;
|
||||
const char *key;
|
||||
|
||||
ret = g_dbus_proxy_call_finish (proxy, result, &error);
|
||||
if (ret == NULL)
|
||||
{
|
||||
g_task_return_error (afd->task, error);
|
||||
free_add_file_data (afd);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (ret, "(&s)", &key);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (afd->task), "key", g_strdup (key), g_free);
|
||||
|
||||
g_variant_unref (ret);
|
||||
|
||||
add_files (proxy, afd);
|
||||
}
|
||||
|
||||
void
|
||||
file_transfer_portal_register_files (const char **files,
|
||||
gboolean writable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GTask *task;
|
||||
AddFileData *afd;
|
||||
GVariantBuilder options;
|
||||
|
||||
task = g_task_new (NULL, NULL, callback, data);
|
||||
|
||||
if (file_transfer_proxy == NULL)
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"No portal found");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
afd = g_new (AddFileData, 1);
|
||||
afd->task = task;
|
||||
afd->files = g_strdupv ((char **)files);
|
||||
afd->len = g_strv_length (afd->files);
|
||||
afd->start = 0;
|
||||
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_builder_add (&options, "{sv}", "writable", g_variant_new_boolean (writable));
|
||||
g_variant_builder_add (&options, "{sv}", "autostop", g_variant_new_boolean (TRUE));
|
||||
|
||||
g_dbus_proxy_call (file_transfer_proxy, "StartTransfer",
|
||||
g_variant_new ("(a{sv})", &options),
|
||||
0, -1, NULL, start_session_done, afd);
|
||||
}
|
||||
|
||||
gboolean
|
||||
file_transfer_portal_register_files_finish (GAsyncResult *result,
|
||||
char **key,
|
||||
GError **error)
|
||||
{
|
||||
if (g_task_propagate_boolean (G_TASK (result), error))
|
||||
{
|
||||
*key = g_strdup (g_object_get_data (G_OBJECT (result), "key"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char *
|
||||
file_transfer_portal_register_files_sync (const char **files,
|
||||
gboolean writable,
|
||||
GError **error)
|
||||
{
|
||||
const char *value;
|
||||
char *key;
|
||||
GUnixFDList *fd_list;
|
||||
GVariantBuilder fds, options;
|
||||
int i;
|
||||
GVariant *ret;
|
||||
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
ret = g_dbus_proxy_call_sync (file_transfer_proxy,
|
||||
"StartTransfer",
|
||||
g_variant_new ("(a{sv})", &options),
|
||||
0,
|
||||
-1,
|
||||
NULL,
|
||||
error);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
g_variant_get (ret, "(&s)", &value);
|
||||
key = g_strdup (value);
|
||||
g_variant_unref (ret);
|
||||
|
||||
fd_list = NULL;
|
||||
|
||||
for (i = 0; files[i]; i++)
|
||||
{
|
||||
int fd;
|
||||
int fd_in;
|
||||
|
||||
if (fd_list == NULL)
|
||||
{
|
||||
g_variant_builder_init (&fds, G_VARIANT_TYPE ("ah"));
|
||||
fd_list = g_unix_fd_list_new ();
|
||||
}
|
||||
|
||||
fd = open (files[i], O_PATH | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR, g_io_error_from_errno (errno),
|
||||
"Failed to open %s", files[i]);
|
||||
g_variant_builder_clear (&fds);
|
||||
g_object_unref (fd_list);
|
||||
g_free (key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef HAVE_O_CLOEXEC
|
||||
fcntl (fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
fd_in = g_unix_fd_list_append (fd_list, fd, error);
|
||||
close (fd);
|
||||
|
||||
if (fd_in == -1)
|
||||
{
|
||||
g_variant_builder_clear (&fds);
|
||||
g_object_unref (fd_list);
|
||||
g_free (key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_variant_builder_add (&fds, "h", fd_in);
|
||||
|
||||
if ((i + 1) % 16 == 0 || files[i + 1] == NULL)
|
||||
{
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
ret = g_dbus_proxy_call_with_unix_fd_list_sync (file_transfer_proxy,
|
||||
"AddFiles",
|
||||
g_variant_new ("(saha{sv})",
|
||||
key,
|
||||
&fds,
|
||||
&options),
|
||||
0,
|
||||
-1,
|
||||
fd_list,
|
||||
NULL,
|
||||
NULL,
|
||||
error);
|
||||
g_clear_object (&fd_list);
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
g_free (key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_variant_unref (ret);
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void
|
||||
retrieve_files_done (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer data)
|
||||
{
|
||||
GDBusProxy *proxy = G_DBUS_PROXY (object);
|
||||
GTask *task = data;
|
||||
GError *error = NULL;
|
||||
GVariant *ret;
|
||||
char **files;
|
||||
|
||||
ret = g_dbus_proxy_call_finish (proxy, result, &error);
|
||||
if (ret == NULL)
|
||||
{
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (ret, "(^a&s)", &files);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (task), "files", g_strdupv (files), (GDestroyNotify)g_strfreev);
|
||||
|
||||
g_variant_unref (ret);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
file_transfer_portal_retrieve_files (const char *key,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
GTask *task;
|
||||
GVariantBuilder options;
|
||||
|
||||
task = g_task_new (NULL, NULL, callback, data);
|
||||
|
||||
if (file_transfer_proxy == NULL)
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"No portal found");
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
g_dbus_proxy_call (file_transfer_proxy,
|
||||
"RetrieveFiles",
|
||||
g_variant_new ("(sa{sv})", key, &options),
|
||||
0, -1, NULL,
|
||||
retrieve_files_done, task);
|
||||
}
|
||||
|
||||
gboolean
|
||||
file_transfer_portal_retrieve_files_finish (GAsyncResult *result,
|
||||
char ***files,
|
||||
GError **error)
|
||||
{
|
||||
if (g_task_propagate_boolean (G_TASK (result), error))
|
||||
{
|
||||
*files = g_strdupv (g_object_get_data (G_OBJECT (result), "files"));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
char **
|
||||
file_transfer_portal_retrieve_files_sync (const char *key,
|
||||
GError **error)
|
||||
{
|
||||
GVariantBuilder options;
|
||||
GVariant *ret;
|
||||
char **files = NULL;
|
||||
|
||||
g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
|
||||
ret = g_dbus_proxy_call_sync (file_transfer_proxy,
|
||||
"RetrieveFiles",
|
||||
g_variant_new ("(sa{sv})", key, &options),
|
||||
0, -1, NULL,
|
||||
error);
|
||||
if (ret)
|
||||
{
|
||||
const char **value;
|
||||
g_variant_get (ret, "(^a&s)", &value);
|
||||
files = g_strdupv ((char **)value);
|
||||
g_variant_unref (ret);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
static void
|
||||
connection_closed (GDBusConnection *connection,
|
||||
gboolean remote_peer_vanished,
|
||||
GError *error)
|
||||
{
|
||||
g_clear_object (&file_transfer_proxy);
|
||||
}
|
||||
|
||||
static void
|
||||
finish_registration (void)
|
||||
{
|
||||
/* Free the singleton when the connection closes, important for test */
|
||||
g_signal_connect (g_dbus_proxy_get_connection (G_DBUS_PROXY (file_transfer_proxy)),
|
||||
"closed", G_CALLBACK (connection_closed), NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
proxy_has_owner (GDBusProxy *proxy)
|
||||
{
|
||||
char *owner;
|
||||
|
||||
owner = g_dbus_proxy_get_name_owner (proxy);
|
||||
if (owner)
|
||||
{
|
||||
g_free (owner);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
file_transfer_portal_register (void)
|
||||
{
|
||||
static gboolean called;
|
||||
|
||||
if (!called)
|
||||
{
|
||||
called = TRUE;
|
||||
|
||||
file_transfer_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES
|
||||
| G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS
|
||||
| G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
||||
NULL,
|
||||
"org.freedesktop.portal.Documents",
|
||||
"/org/freedesktop/portal/documents",
|
||||
"org.freedesktop.portal.FileTransfer",
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (file_transfer_proxy && !proxy_has_owner (file_transfer_proxy))
|
||||
g_clear_object (&file_transfer_proxy);
|
||||
|
||||
if (file_transfer_proxy)
|
||||
finish_registration ();
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
file_transfer_portal_supported (void)
|
||||
{
|
||||
file_transfer_portal_register ();
|
||||
|
||||
return file_transfer_proxy != NULL;
|
||||
}
|
||||
|
||||
#endif /* G_OS_UNIX */
|
49
gtk/filetransferportalprivate.h
Normal file
49
gtk/filetransferportalprivate.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Matthias Clasen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __FILE_TRANSFER_PROTOCOL_H__
|
||||
#define __FILE_TRANSFER_PROTOCOL_H__
|
||||
|
||||
|
||||
void file_transfer_portal_register (void);
|
||||
|
||||
void file_transfer_portal_register_files (const char **files,
|
||||
gboolean writable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer data);
|
||||
gboolean file_transfer_portal_register_files_finish (GAsyncResult *result,
|
||||
char **key,
|
||||
GError **error);
|
||||
|
||||
void file_transfer_portal_retrieve_files (const char *key,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer data);
|
||||
gboolean file_transfer_portal_retrieve_files_finish (GAsyncResult *result,
|
||||
char ***files,
|
||||
GError **error);
|
||||
|
||||
|
||||
char * file_transfer_portal_register_files_sync (const char **files,
|
||||
gboolean writable,
|
||||
GError **error);
|
||||
|
||||
char ** file_transfer_portal_retrieve_files_sync (const char *key,
|
||||
GError **error);
|
||||
|
||||
gboolean file_transfer_portal_supported (void);
|
||||
|
||||
#endif
|
@ -116,6 +116,10 @@
|
||||
#include "broadway/gdkbroadway.h"
|
||||
#endif
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
#include "filetransferportalprivate.h"
|
||||
#endif
|
||||
|
||||
#undef DEBUG_SELECTION
|
||||
|
||||
/* Maximum size of a sent chunk, in bytes. Also the default size of
|
||||
@ -338,6 +342,7 @@ static GdkAtom text_plain_atom;
|
||||
static GdkAtom text_plain_utf8_atom;
|
||||
static GdkAtom text_plain_locale_atom;
|
||||
static GdkAtom text_uri_list_atom;
|
||||
static GdkAtom portal_files_atom;
|
||||
|
||||
static void
|
||||
init_atoms (void)
|
||||
@ -358,6 +363,7 @@ init_atoms (void)
|
||||
g_free (tmp);
|
||||
|
||||
text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list");
|
||||
portal_files_atom = gdk_atom_intern_static_string ("application/vnd.portal.files");
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,6 +508,10 @@ gtk_target_list_add_image_targets (GtkTargetList *list,
|
||||
* Appends the URI targets supported by #GtkSelectionData to
|
||||
* the target list. All targets are added with the same @info.
|
||||
*
|
||||
* Since 3.24.37, this includes the application/vnd.portal.files
|
||||
* target when possible, to allow sending files between sandboxed
|
||||
* apps via the FileTransfer portal.
|
||||
*
|
||||
* Since: 2.6
|
||||
**/
|
||||
void
|
||||
@ -512,7 +522,12 @@ gtk_target_list_add_uri_targets (GtkTargetList *list,
|
||||
|
||||
init_atoms ();
|
||||
|
||||
gtk_target_list_add (list, text_uri_list_atom, 0, info);
|
||||
gtk_target_list_add (list, text_uri_list_atom, 0, info);
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
if (file_transfer_portal_supported ())
|
||||
gtk_target_list_add (list, portal_files_atom, 0, info);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1835,6 +1850,9 @@ gtk_selection_data_get_pixbuf (const GtkSelectionData *selection_data)
|
||||
* Sets the contents of the selection from a list of URIs.
|
||||
* The string is converted to the form determined by
|
||||
* @selection_data->target.
|
||||
*
|
||||
* Since 3.24.37, this may involve using the FileTransfer
|
||||
* portal to send files between sandboxed apps.
|
||||
*
|
||||
* Returns: %TRUE if the selection was successfully set,
|
||||
* otherwise %FALSE.
|
||||
@ -1880,6 +1898,57 @@ gtk_selection_data_set_uris (GtkSelectionData *selection_data,
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
#ifndef G_OS_WIN32
|
||||
else if (selection_data->target == portal_files_atom &&
|
||||
file_transfer_portal_supported ())
|
||||
{
|
||||
GPtrArray *a;
|
||||
char **files;
|
||||
char *key;
|
||||
GError *error = NULL;
|
||||
|
||||
a = g_ptr_array_new ();
|
||||
|
||||
for (int i = 0; uris[i]; i++)
|
||||
{
|
||||
GFile *file;
|
||||
char *path;
|
||||
|
||||
file = g_file_new_for_uri (uris[i]);
|
||||
path = g_file_get_path (file);
|
||||
g_object_unref (file);
|
||||
|
||||
if (path == NULL)
|
||||
{
|
||||
g_ptr_array_unref (a);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_ptr_array_add (a, path);
|
||||
}
|
||||
|
||||
g_ptr_array_add (a, NULL);
|
||||
files = (char **) g_ptr_array_free (a, FALSE);
|
||||
|
||||
key = file_transfer_portal_register_files_sync ((const char **)files, TRUE, &error);
|
||||
if (key == NULL)
|
||||
{
|
||||
g_strfreev (files);
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
portal_files_atom,
|
||||
8, (guchar *)key, strlen (key));
|
||||
|
||||
g_strfreev (files);
|
||||
g_free (key);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -1890,6 +1959,9 @@ gtk_selection_data_set_uris (GtkSelectionData *selection_data,
|
||||
*
|
||||
* Gets the contents of the selection data as array of URIs.
|
||||
*
|
||||
* Since 3.24.37, this may involve using the FileTransfer
|
||||
* portal to send files between sandboxed apps.
|
||||
*
|
||||
* Returns: (array zero-terminated=1) (element-type utf8) (transfer full): if
|
||||
* the selection data contains a list of
|
||||
* URIs, a newly allocated %NULL-terminated string array
|
||||
@ -1922,6 +1994,40 @@ gtk_selection_data_get_uris (const GtkSelectionData *selection_data)
|
||||
|
||||
g_strfreev (list);
|
||||
}
|
||||
#ifndef G_OS_WIN32
|
||||
else if (selection_data->length >= 0 &&
|
||||
selection_data->type == portal_files_atom &&
|
||||
file_transfer_portal_supported ())
|
||||
{
|
||||
char *key;
|
||||
GError *error = NULL;
|
||||
char **files;
|
||||
|
||||
key = g_strndup ((char *) selection_data->data, selection_data->length);
|
||||
files = file_transfer_portal_retrieve_files_sync (key, &error);
|
||||
if (error)
|
||||
{
|
||||
g_warning ("%s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_free (key);
|
||||
|
||||
if (files)
|
||||
{
|
||||
GPtrArray *uris = g_ptr_array_new ();
|
||||
|
||||
for (int i = 0; files[i]; i++)
|
||||
{
|
||||
GFile *file = g_file_new_for_path (files[i]);
|
||||
g_ptr_array_add (uris, g_file_get_uri (file));
|
||||
g_object_unref (file);
|
||||
}
|
||||
|
||||
g_ptr_array_add (uris, NULL);
|
||||
result = (char **) g_ptr_array_free (uris, FALSE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2246,7 +2352,8 @@ gtk_targets_include_uri (GdkAtom *targets,
|
||||
|
||||
for (i = 0; i < n_targets; i++)
|
||||
{
|
||||
if (targets[i] == text_uri_list_atom)
|
||||
if (targets[i] == text_uri_list_atom ||
|
||||
targets[i] == portal_files_atom)
|
||||
{
|
||||
result = TRUE;
|
||||
break;
|
||||
|
@ -659,6 +659,10 @@ if os_unix and tracker3_enabled
|
||||
gtk_unix_sources += 'gtksearchenginetracker3.c'
|
||||
endif
|
||||
|
||||
if os_unix
|
||||
gtk_unix_sources += 'filetransferportal.c'
|
||||
endif
|
||||
|
||||
if os_unix
|
||||
gtk_sources += gtk_unix_sources
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user