[Spice-devel] [Spice-commits] 6 commits - meson.build src/map-file src/spice-glib-sym-file src/spice-gtk-session.c src/spice-session.c src/spice-session.h src/spice-session-priv.h
Marc-André Lureau
marcandre.lureau at gmail.com
Wed Sep 9 14:03:55 UTC 2020
Hi,
On Wed, Sep 9, 2020 at 5:50 PM GitLab Mirror <
gitlab-mirror at kemper.freedesktop.org> wrote:
> meson.build | 13 -
> src/map-file | 1
> src/spice-glib-sym-file | 1
> src/spice-gtk-session.c | 399
> +++++++++++++++++++++++++++++++++++++++++++++++
> src/spice-session-priv.h | 1
> src/spice-session.c | 30 +++
> src/spice-session.h | 5
> 7 files changed, 443 insertions(+), 7 deletions(-)
>
> New commits:
> commit f33d589d747f4f7ee6a1241c344ca611a36e9c71
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Fri May 29 17:59:38 2020 +0200
>
> clipboard: enable copying files to guest using webdav
>
> When an app advertises the "text/uri-list" target, the user
> probably wants to copy/move files. Spice-gtk then sends
> a grab message to the vdagent advertising the
> VD_AGENT_CLIPBOARD_FILE_LIST type.
>
> Vdagent can then request clipboard data in this type.
>
> Spice-gtk tries to talk to the app that owns the clipboard
> in its native format in order to determine the preferred
> file operation (copy X move).
>
> For GNOME Nautilus, that's simply "UTF8_TEXT",
> for KDE Dolphin, "application/x-kde-cutselection".
>
> Otherwise the generic "text/uri-list" is used that does not
> provide any additional information.
>
> Once the uri list is obtained from the app, spice-gtk
> creates a unique virtual dir in the ".spice-clipboard"
> directory that is designated for this purpose.
>
> Each file is attached inside this virtual dir using
> phodav_virtual_dir_attach_real_child(), see phodav API
> for details.
>
> A list of paths in the phodav server is then sent to vdagent,
> as specified in the spice-protocol.
> Such path can for example look like this:
> /.spice-clipboard/b8f0249c-082a-4da9-9a38-2de3237a66f0/file
>
> It is up to the vdagent to ensure that the spice shared folder
> is accessible and to set the clipboard data in a format that
> other apps understand.
>
> This requires new phodav with PhodavVirtualDir API.
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/meson.build b/meson.build
> index 7ade460..e43139e 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -33,7 +33,7 @@ spice_glib_deps = []
> spice_gtk_deps = []
> spice_wayland_deps = []
> spice_acl_deps = []
> -spice_protocol_version = '0.14.2'
> +spice_protocol_version = '0.14.3'
>
> #
> # Set up subprojects
> diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
> index 5e6be4a..dfbd8fa 100644
> --- a/src/spice-gtk-session.c
> +++ b/src/spice-gtk-session.c
> @@ -34,6 +34,10 @@
> #endif
> #endif
>
> +#ifdef HAVE_PHODAV_VIRTUAL
> +#include <libphodav/phodav.h>
> +#endif
> +
> #include <gtk/gtk.h>
> #include <spice/vd_agent.h>
> #include "desktop-integration.h"
> @@ -61,6 +65,8 @@ struct _SpiceGtkSessionPrivate {
> gboolean clip_grabbed[CLIPBOARD_LAST];
> gboolean clipboard_by_guest[CLIPBOARD_LAST];
> guint clipboard_release_delay[CLIPBOARD_LAST];
> + /* TODO: maybe add a way of restoring this? */
> + GHashTable *cb_shared_files;
> /* auto-usbredir related */
> gboolean auto_usbredir_enable;
> int auto_usbredir_reqs;
> @@ -191,6 +197,12 @@ static void spice_gtk_session_init(SpiceGtkSession
> *self)
>
> s = self->priv = spice_gtk_session_get_instance_private(self);
>
> + s->cb_shared_files =
> + g_hash_table_new_full(g_file_hash,
> + (GEqualFunc)g_file_equal,
> + g_object_unref, /* unref GFile */
> + g_free /* free gchar * */
> + );
> s->clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
> g_signal_connect(G_OBJECT(s->clipboard), "owner-change",
> G_CALLBACK(clipboard_owner_change), self);
> @@ -252,6 +264,7 @@ static void spice_gtk_session_dispose(GObject *gobject)
> self);
> s->session = NULL;
> }
> + g_clear_pointer(&s->cb_shared_files, g_hash_table_destroy);
>
> /* Chain up to the parent class */
> if (G_OBJECT_CLASS(spice_gtk_session_parent_class)->dispose)
> @@ -544,6 +557,9 @@ static const struct {
> },{
> .vdagent = VD_AGENT_CLIPBOARD_IMAGE_JPG,
> .xatom = "image/jpeg"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_FILE_LIST,
> + .xatom = "text/uri-list"
> }
> };
>
> @@ -660,6 +676,18 @@ static void clipboard_get_targets(GtkClipboard
> *clipboard,
> continue;
> }
>
> + if (atom2agent[m].vdagent == VD_AGENT_CLIPBOARD_FILE_LIST) {
> +#ifdef HAVE_PHODAV_VIRTUAL
> + if (!clipboard_get_open_webdav(s->session)) {
> + SPICE_DEBUG("Received %s target, but the clipboard
> webdav channel "
> + "isn't available, skipping",
> atom2agent[m].xatom);
> + break;
> + }
> +#else
> + break;
> +#endif
> + }
> +
> /* check if type is already in list */
> for (t = 0; t < num_types; t++) {
> if (types[t] == atom2agent[m].vdagent) {
> @@ -1037,6 +1065,318 @@ notify_agent:
> g_free(conv);
> }
>
> +#ifdef HAVE_PHODAV_VIRTUAL
> +/* returns path to @file under @root in clipboard phodav server, or NULL
> on error */
> +static gchar *clipboard_webdav_share_file(PhodavVirtualDir *root, GFile
> *file)
> +{
> + gchar *uuid;
> + PhodavVirtualDir *dir;
> + GError *err = NULL;
> +
> + /* separate directory is created for each file,
> + * as we want to preserve the original filename and avoid conflicts */
> + for (guint i = 0; i < 8; i++) {
> + uuid = g_uuid_string_random();
> + gchar *dir_path =
> g_strdup_printf(SPICE_WEBDAV_CLIPBOARD_FOLDER_PATH "/%s", uuid);
> + dir = phodav_virtual_dir_new_dir(root, dir_path, &err);
> + g_free(dir_path);
> + if (!err) {
> + break;
> + }
> + g_clear_pointer(&uuid, g_free);
> + if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
> + g_warning("failed to create phodav virtual dir: %s",
> err->message);
> + g_error_free(err);
> + return NULL;
> + }
> + g_clear_error(&err);
> + }
> +
> + if (!dir) {
> + g_warning("failed to create phodav virtual dir: all attempts
> failed");
> + return NULL;
> + }
> +
> + phodav_virtual_dir_attach_real_child(dir, file);
> + g_object_unref(dir);
> +
> + gchar *base = g_file_get_basename(file);
> + gchar *path = g_strdup_printf(SPICE_WEBDAV_CLIPBOARD_FOLDER_PATH
> "/%s/%s", uuid, base);
> + g_free(uuid);
> + g_free(base);
> +
> + return path;
> +}
> +
> +/* join all strings in @strv into a new char array,
> + * including all terminating NULL-chars */
> +static gchar *strv_concat(gchar **strv, gsize *size_out)
> +{
> + gchar **str_p, *arr, *curr;
> +
> + g_return_val_if_fail(strv && size_out, NULL);
> +
> + for (str_p = strv, *size_out = 0; *str_p != NULL; str_p++) {
> + *size_out += strlen(*str_p) + 1;
> + }
> +
> + arr = g_malloc(*size_out);
> +
> + for (str_p = strv, curr = arr; *str_p != NULL; str_p++) {
> + curr = g_stpcpy(curr, *str_p) + 1;
> + }
> +
> + return arr;
> +}
> +
> +/* if not done alreay, share all files in @uris using the webdav server
> + * and return a new buffer with VD_AGENT_CLIPBOARD_FILE_LIST data */
> +static gchar *strv_uris_transform_to_data(SpiceGtkSessionPrivate *s,
> + gchar **uris, gsize *size_out, GdkDragAction action)
> +{
> + SpiceWebdavChannel *webdav;
> + PhodavServer *phodav;
> + PhodavVirtualDir *root;
> +
> + gchar **uri_ptr, *path, **paths, *data;
> + GFile *file;
> + guint n;
> +
> + *size_out = 0;
> +
> + if (!uris || g_strv_length(uris) < 1) {
> + return NULL;
> + }
> +
> + webdav = clipboard_get_open_webdav(s->session);
> + if (!webdav) {
> + SPICE_DEBUG("Received uris, but no webdav channel");
> + return NULL;
> + }
> +
> + phodav = spice_session_get_webdav_server(s->session);
> + g_object_get(phodav, "root-file", &root, NULL);
> +
> + paths = g_new0(gchar *, g_strv_length(uris) + 2);
> +
> + paths[0] = action == GDK_ACTION_MOVE ? "cut" : "copy";
> + n = 1;
> +
> + for (uri_ptr = uris; *uri_ptr != NULL; uri_ptr++) {
> + file = g_file_new_for_uri(*uri_ptr);
> +
> + /* clipboard data is usually requested multiple times for no
> obvious reasons
> + * (clipboar managers to blame?), we don't want to create
> multiple dirs for the same file */
> + path = g_hash_table_lookup(s->cb_shared_files, file);
> + if (path) {
> + SPICE_DEBUG("found %s with path %s", *uri_ptr, path);
> + g_object_unref(file);
> + } else {
> + path = clipboard_webdav_share_file(root, file);
> + g_return_val_if_fail(path != NULL, NULL);
> + SPICE_DEBUG("publishing %s under %s", *uri_ptr, path);
> + /* file and path gets freed once the hash table gets
> destroyed */
> + g_hash_table_insert(s->cb_shared_files, file, path);
> + }
> + paths[n] = path;
> + n++;
> + }
> +
> + g_object_unref(root);
> + data = strv_concat(paths, size_out);
> + g_free(paths);
> +
> + return data;
> +}
> +
> +static GdkAtom a_gnome, a_mate, a_nautilus, a_uri_list, a_kde_cut;
> +
> +static void init_uris_atoms()
> +{
> + if (a_gnome != GDK_NONE) {
> + return;
> + }
> + a_gnome =
> gdk_atom_intern_static_string("x-special/gnome-copied-files");
> + a_mate = gdk_atom_intern_static_string("x-special/mate-copied-files");
> + a_nautilus = gdk_atom_intern_static_string("UTF8_STRING");
> + a_uri_list = gdk_atom_intern_static_string("text/uri-list");
> + a_kde_cut =
> gdk_atom_intern_static_string("application/x-kde-cutselection");
> +}
> +
> +static GdkAtom clipboard_select_uris_atom(SpiceGtkSessionPrivate *s,
> guint selection)
> +{
> + init_uris_atoms();
> + if (clipboard_find_atom(s, selection, a_gnome)) {
> + return a_gnome;
> + }
> + if (clipboard_find_atom(s, selection, a_mate)) {
> + return a_mate;
> + }
> + if (clipboard_find_atom(s, selection, a_nautilus)) {
> + return a_nautilus;
> + }
> + return clipboard_find_atom(s, selection, a_uri_list);
> +}
> +
> +/* common handler for "x-special/gnome-copied-files" and
> "x-special/mate-copied-files" */
> +static gchar
> *x_special_copied_files_transform_to_data(SpiceGtkSessionPrivate *s,
> + GtkSelectionData *selection_data, gsize *size_out)
> +{
> + const gchar *text;
> + gchar **lines, *data = NULL;
> + GdkDragAction action;
> +
> + *size_out = 0;
> +
> + text = (gchar *)gtk_selection_data_get_data(selection_data);
> + if (!text) {
> + return NULL;
> + }
> + lines = g_strsplit(text, "\n", -1);
> + if (g_strv_length(lines) < 2) {
> + goto err;
> + }
> +
> + if (!g_strcmp0(lines[0], "cut")) {
> + action = GDK_ACTION_MOVE;
> + } else if (!g_strcmp0(lines[0], "copy")) {
> + action = GDK_ACTION_COPY;
> + } else {
> + goto err;
> + }
> +
> + data = strv_uris_transform_to_data(s, &lines[1], size_out, action);
> +err:
> + g_strfreev(lines);
> + return data;
> +}
> +
> +/* used with newer Nautilus */
> +static gchar *nautilus_uris_transform_to_data(SpiceGtkSessionPrivate *s,
> + GtkSelectionData *selection_data, gsize *size_out, gboolean
> *retry_out)
> +{
> + gchar **lines, *text, *data = NULL;
> + guint n_lines;
> + GdkDragAction action;
> +
> + *size_out = 0;
> +
> + text = (gchar *)gtk_selection_data_get_text(selection_data);
> + if (!text) {
> + return NULL;
> + }
> + lines = g_strsplit(text, "\n", -1);
> + g_free(text);
> + n_lines = g_strv_length(lines);
> +
> + if (n_lines < 4) {
> + *retry_out = TRUE;
> + goto err;
> + }
> +
> + if (g_strcmp0(lines[0], "x-special/nautilus-clipboard")) {
> + *retry_out = TRUE;
> + goto err;
> + }
> +
> + if (!g_strcmp0(lines[1], "cut")) {
> + action = GDK_ACTION_MOVE;
> + } else if (!g_strcmp0(lines[1], "copy")) {
> + action = GDK_ACTION_COPY;
> + } else {
> + goto err;
> + }
> +
> + /* the list of uris must end with \n,
> + * so there must be an empty string after the split */
> + if (g_strcmp0(lines[n_lines-1], "")) {
> + goto err;
> + }
> + g_clear_pointer(&lines[n_lines-1], g_free);
> +
> + data = strv_uris_transform_to_data(s, &lines[2], size_out, action);
> +err:
> + g_strfreev(lines);
> + return data;
> +}
> +
> +static GdkDragAction kde_get_clipboard_action(SpiceGtkSessionPrivate *s,
> GtkClipboard *clipboard)
> +{
> + GtkSelectionData *selection_data;
> + GdkDragAction action;
> + const guchar *data;
> +
> + /* this uses another GMainLoop, basically the same mechanism
> + * as we use in clipboard_get(), so it doesn't block */
> + selection_data = gtk_clipboard_wait_for_contents(clipboard,
> a_kde_cut);
> + data = gtk_selection_data_get_data(selection_data);
> + if (data && data[0] == '1') {
> + action = GDK_ACTION_MOVE;
> + } else {
> + action = GDK_ACTION_COPY;
> + }
> + gtk_selection_data_free(selection_data);
> +
> + return action;
> +}
> +
> +static void clipboard_received_uri_contents_cb(GtkClipboard *clipboard,
> + GtkSelectionData
> *selection_data,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = free_weak_ref(user_data);
> + SpiceGtkSessionPrivate *s;
> + guint selection;
> +
> + if (!self) {
> + return;
> + }
> + s = self->priv;
> +
> + selection = get_selection_from_clipboard(s, clipboard);
> + g_return_if_fail(selection != -1);
> +
> + init_uris_atoms();
> + GdkAtom type = gtk_selection_data_get_data_type(selection_data);
> + gchar *data;
> + gsize len;
> +
> + if (type == a_gnome || type == a_mate) {
> + /* used by old Nautilus + many other file managers */
> + data = x_special_copied_files_transform_to_data(s,
> selection_data, &len);
> + } else if (type == a_nautilus) {
> + gboolean retry = FALSE;
> + data = nautilus_uris_transform_to_data(s, selection_data, &len,
> &retry);
> +
> + if (retry && clipboard_find_atom(s, selection, a_uri_list) !=
> GDK_NONE) {
> + /* it's not Nautilus, so we give it one more try with the
> generic uri-list target */
> + gtk_clipboard_request_contents(clipboard, a_uri_list,
> + clipboard_received_uri_contents_cb, get_weak_ref(self));
> + return;
> + }
> + } else if (type == a_uri_list) {
> + GdkDragAction action = GDK_ACTION_COPY;
> + gchar **uris = gtk_selection_data_get_uris(selection_data);
> +
> + /* KDE uses a separate atom to distinguish between copy and move
> operation */
> + if (clipboard_find_atom(s, selection, a_kde_cut) != GDK_NONE) {
> + action = kde_get_clipboard_action(s, clipboard);
> + }
> +
> + data = strv_uris_transform_to_data(s, uris, &len, action);
> + g_strfreev(uris);
> + } else {
> + g_warning("received uris in unsupported type");
> + data = NULL;
> + len = 0;
> + }
> +
> + spice_main_channel_clipboard_selection_notify(s->main, selection,
> + VD_AGENT_CLIPBOARD_FILE_LIST, (guchar *)data, len);
> + g_free(data);
> +}
> +#endif
> +
> static void clipboard_received_cb(GtkClipboard *clipboard,
> GtkSelectionData *selection_data,
> gpointer user_data)
> @@ -1111,6 +1451,17 @@ static gboolean clipboard_request(SpiceMainChannel
> *main, guint selection,
> if (type == VD_AGENT_CLIPBOARD_UTF8_TEXT) {
> gtk_clipboard_request_text(cb, clipboard_received_text_cb,
> get_weak_ref(self));
> + } else if (type == VD_AGENT_CLIPBOARD_FILE_LIST) {
> +#ifdef HAVE_PHODAV_VIRTUAL
> + atom = clipboard_select_uris_atom(s, selection);
> + if (atom == GDK_NONE) {
> + return FALSE;
> + }
> + gtk_clipboard_request_contents(cb, atom,
> + clipboard_received_uri_contents_cb, get_weak_ref(self));
> +#else
> + return FALSE;
> +#endif
> } else {
> for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> if (atom2agent[m].vdagent == type)
> diff --git a/src/spice-session.c b/src/spice-session.c
> index f0ac891..8831bc5 100644
> --- a/src/spice-session.c
> +++ b/src/spice-session.c
> @@ -2666,6 +2666,17 @@ static void
> spice_session_set_shared_dir(SpiceSession *session, const gchar *dir
>
> g_free(s->shared_dir);
> s->shared_dir = g_strdup(dir);
> +
> +#ifdef HAVE_PHODAV_VIRTUAL
> + if (s->webdav == NULL) {
> + return;
> + }
> +
> + PhodavVirtualDir *root;
> + g_object_get(s->webdav, "root-file", &root, NULL);
> + phodav_virtual_dir_root_set_real(root, s->shared_dir);
> + g_object_unref(root);
> +#endif
> }
>
> G_GNUC_INTERNAL
> @@ -2807,21 +2818,39 @@ PhodavServer*
> spice_session_get_webdav_server(SpiceSession *session)
> static GMutex mutex;
>
> const gchar *shared_dir = spice_session_get_shared_dir(session);
> + /* with HAVE_PHODAV_VIRTUAL, PhodavServer must be created even if
> shared_dir is NULL */
> +#ifndef HAVE_PHODAV_VIRTUAL
> if (shared_dir == NULL) {
> SPICE_DEBUG("No shared dir set, not creating webdav server");
> return NULL;
> }
> +#endif
>
> g_mutex_lock(&mutex);
>
> if (priv->webdav == NULL) {
> +#ifdef HAVE_PHODAV_VIRTUAL
> + PhodavVirtualDir *root = phodav_virtual_dir_new_root();
> + priv->webdav = phodav_server_new_for_root_file(G_FILE(root));
> +
> + phodav_virtual_dir_root_set_real(root, shared_dir);
> +
> + g_object_unref(phodav_virtual_dir_new_dir(root,
> SPICE_WEBDAV_CLIPBOARD_FOLDER_PATH, NULL));
> + g_object_unref(root);
> +#else
> priv->webdav = phodav_server_new(shared_dir);
> +#endif
> +
> g_object_bind_property(session, "share-dir-ro",
> priv->webdav, "read-only",
>
> G_BINDING_SYNC_CREATE|G_BINDING_BIDIRECTIONAL);
> +
> + /* with HAVE_PHODAV_VIRTUAL, the update is done in
> spice_session_set_shared_dir() */
> +#ifndef HAVE_PHODAV_VIRTUAL
> g_object_bind_property(session, "shared-dir",
> priv->webdav, "root",
>
> G_BINDING_SYNC_CREATE|G_BINDING_BIDIRECTIONAL);
> +#endif
> }
>
> g_mutex_unlock(&mutex);
> diff --git a/src/spice-session.h b/src/spice-session.h
> index 9436be8..665d2f3 100644
> --- a/src/spice-session.h
> +++ b/src/spice-session.h
> @@ -36,6 +36,8 @@ G_BEGIN_DECLS
> #define SPICE_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
> SPICE_TYPE_SESSION))
> #define SPICE_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
> SPICE_TYPE_SESSION, SpiceSessionClass))
>
> +#define SPICE_WEBDAV_CLIPBOARD_FOLDER_PATH "/.spice-clipboard"
> +
> typedef struct _PhodavServer PhodavServer;
>
> /**
> commit 996bfb48dc5d1d17bb56b4936f79d8705bcd5c48
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Tue Jun 30 15:15:39 2020 +0200
>
> spice-gtk-session: cache atoms
>
> At the moment, spice-gtk only sends a grab message to the vdagent
> based on the retrieved atoms.
>
> With the upcoming changes, spice-gtk will have to know which
> targets were advertised outside of clipboard_get_targets() callback.
>
> We could use gtk_clipboard_wait_for_targets() or
> gtk_clipboard_wait_is_*_available(), but the targets are not cached
> by GTK+ on wayland for some reason. So let's cache them in spice-gtk
> to avoid having to talk to the clipboard owner.
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
> index 2b86616..5e6be4a 100644
> --- a/src/spice-gtk-session.c
> +++ b/src/spice-gtk-session.c
> @@ -55,6 +55,8 @@ struct _SpiceGtkSessionPrivate {
> GtkClipboard *clipboard_primary;
> GtkTargetEntry *clip_targets[CLIPBOARD_LAST];
> guint nclip_targets[CLIPBOARD_LAST];
> + GdkAtom *atoms[CLIPBOARD_LAST];
> + guint n_atoms[CLIPBOARD_LAST];
> gboolean clip_hasdata[CLIPBOARD_LAST];
> gboolean clip_grabbed[CLIPBOARD_LAST];
> gboolean clipboard_by_guest[CLIPBOARD_LAST];
> @@ -284,6 +286,8 @@ static void spice_gtk_session_finalize(GObject
> *gobject)
> for (i = 0; i < CLIPBOARD_LAST; ++i) {
> g_clear_pointer(&s->clip_targets[i], g_free);
> clipboard_release_delay_remove(self, i, true);
> + g_clear_pointer(&s->atoms[i], g_free);
> + s->n_atoms[i] = 0;
> }
>
> /* Chain up to the parent class */
> @@ -589,6 +593,16 @@ static SpiceWebdavChannel
> *clipboard_get_open_webdav(SpiceSession *session)
> g_list_free(list);
> return open ? SPICE_WEBDAV_CHANNEL(channel) : NULL;
> }
> +
> +static GdkAtom clipboard_find_atom(SpiceGtkSessionPrivate *s, guint
> selection, GdkAtom a)
> +{
> + for (int i = 0; i < s->n_atoms[selection]; i++) {
> + if (s->atoms[selection][i] == a) {
> + return a;
> + }
> + }
> + return GDK_NONE;
> +}
> #endif
>
> static void clipboard_get_targets(GtkClipboard *clipboard,
> @@ -622,6 +636,11 @@ static void clipboard_get_targets(GtkClipboard
> *clipboard,
> selection = get_selection_from_clipboard(s, clipboard);
> g_return_if_fail(selection != -1);
>
> + /* GTK+ does seem to cache atoms, but not for Wayland */
> + g_free(s->atoms[selection]);
> + s->atoms[selection] = g_memdup(atoms, n_atoms * sizeof(GdkAtom));
> + s->n_atoms[selection] = n_atoms;
> +
> if (s->clip_grabbed[selection]) {
> SPICE_DEBUG("Clipboard is already grabbed, re-grab: %d atoms",
> n_atoms);
> }
> @@ -705,6 +724,9 @@ static void clipboard_owner_change(GtkClipboard
> *clipboard,
> return;
> }
>
> + g_clear_pointer(&s->atoms[selection], g_free);
> + s->n_atoms[selection] = 0;
> +
> if (event->reason != GDK_OWNER_CHANGE_NEW_OWNER) {
> if (s->clip_grabbed[selection]) {
> /* grab was sent to the agent, so release it */
> commit 852b847c868a199b5127644ca689f8a7d70fbda1
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Fri May 29 17:57:51 2020 +0200
>
> spice-gtk-session: add clipboard_get_open_webdav()
>
> File copy&paste functionality will only be enabled when there is an
> open
> webdav channel.
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
> index 48058c7..2b86616 100644
> --- a/src/spice-gtk-session.c
> +++ b/src/spice-gtk-session.c
> @@ -565,6 +565,32 @@ static gpointer free_weak_ref(gpointer data)
> return object;
> }
>
> +#ifdef HAVE_PHODAV_VIRTUAL
> +static SpiceWebdavChannel *clipboard_get_open_webdav(SpiceSession
> *session)
> +{
> + GList *list, *l;
> + SpiceChannel *channel = NULL;
> + gboolean open = FALSE;
> +
> + g_return_val_if_fail(session != NULL, NULL);
> +
> + list = spice_session_get_channels(session);
> + for (l = g_list_first(list); l != NULL; l = g_list_next(l)) {
> + channel = l->data;
> +
> + if (!SPICE_IS_WEBDAV_CHANNEL(channel)) {
> + continue;
> + }
> +
> + g_object_get(channel, "port-opened", &open, NULL);
> + break;
> + }
> +
> + g_list_free(list);
> + return open ? SPICE_WEBDAV_CHANNEL(channel) : NULL;
> +}
> +#endif
> +
> static void clipboard_get_targets(GtkClipboard *clipboard,
> GdkAtom *atoms,
> gint n_atoms,
> commit c1b5433815e5cd7683671d33a0d579b7b185efe8
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Mon Jun 29 19:40:25 2020 +0200
>
> build: require GLib 2.52+
>
> This adds g_uuid_string_random()
> which is necessary for the following file copy&paste
> functionality.
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/meson.build b/meson.build
> index 1c4e9d9..7ade460 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -89,7 +89,7 @@ endforeach
> #
> # check for mandatory dependencies
> #
> -glib_version = '2.46'
> +glib_version = '2.52'
> glib_version_info = '>= @0@'.format(glib_version)
> pixman_version = '>= 0.17.7'
>
> commit 979b752b24d6f8d7089a23760fd5adda18f0e7ed
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Sat May 23 13:40:39 2020 +0200
>
> build: define HAVE_PHODAV_VIRTUAL if phodav >= 2.5
>
> Phodav 2.5 brings PhodavVirtualDir API needed for the
> file copy and paste functionality.
>
> If the library version is not sufficient, this new feature
> will be disabled, but the standard shared folders can still
> be used.
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/meson.build b/meson.build
> index 6bbb4a8..1c4e9d9 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -177,14 +177,17 @@ endif
>
> # webdav
> spice_gtk_has_phodav = false
> -d = dependency('libphodav-2.0', required: get_option('webdav'))
> -if d.found()
> - spice_glib_deps += d
> +phodav_dep = dependency('libphodav-2.0', required: get_option('webdav'))
> +if phodav_dep.found()
> + spice_glib_deps += phodav_dep
> d = dependency('libsoup-2.4', version : '>= 2.49.91', required:
> get_option('webdav'))
> if d.found()
> spice_glib_deps += d
> spice_gtk_config_data.set('USE_PHODAV', '1')
> spice_gtk_has_phodav = true
> + if phodav_dep.version().version_compare('>= 2.5')
> + spice_gtk_config_data.set('HAVE_PHODAV_VIRTUAL', '1')
> + endif
> endif
> endif
>
> commit 4b9092b96b8da946ff3d17922b0fcf225c5dc81f
> Author: Jakub Janků <jjanku at redhat.com>
> Date: Sat May 23 16:28:52 2020 +0200
>
> session: make spice_session_get_webdav_server() public
>
> It will be necessary to access the webdav server from
> spice-gtk-session.c
> which isn't compiled with spice-session-priv.h, so make
> spice_session_get_webdav_server() public.
>
I haven't looked at the whole series. Wouldn't it make sense to make it a
read-only property instead?
>
> Signed-off-by: Jakub Janků <jjanku at redhat.com>
> Acked-by: Frediano Ziglio <fziglio at redhat.com>
>
> diff --git a/src/map-file b/src/map-file
> index acdd38f..86f371d 100644
> --- a/src/map-file
> +++ b/src/map-file
> @@ -144,6 +144,7 @@ spice_session_new;
> spice_session_open_fd;
> spice_session_verify_get_type;
> spice_set_session_option;
> +spice_session_get_webdav_server;
> spice_smartcard_channel_get_type;
> spice_smartcard_manager_get;
> spice_smartcard_manager_get_readers;
> diff --git a/src/spice-glib-sym-file b/src/spice-glib-sym-file
> index 72e6ef0..effcd09 100644
> --- a/src/spice-glib-sym-file
> +++ b/src/spice-glib-sym-file
> @@ -123,6 +123,7 @@ spice_session_new
> spice_session_open_fd
> spice_session_verify_get_type
> spice_set_session_option
> +spice_session_get_webdav_server
> spice_smartcard_channel_get_type
> spice_smartcard_manager_get
> spice_smartcard_manager_get_readers
> diff --git a/src/spice-session-priv.h b/src/spice-session-priv.h
> index b4919a4..5b52f8d 100644
> --- a/src/spice-session-priv.h
> +++ b/src/spice-session-priv.h
> @@ -87,7 +87,6 @@ gboolean
> spice_session_get_smartcard_enabled(SpiceSession *session);
> gboolean spice_session_get_usbredir_enabled(SpiceSession *session);
> gboolean spice_session_get_gl_scanout_enabled(SpiceSession *session);
>
> -PhodavServer *spice_session_get_webdav_server(SpiceSession *session);
> guint spice_session_get_n_display_channels(SpiceSession *session);
> gboolean spice_session_set_migration_session(SpiceSession *session,
> SpiceSession *mig_session);
> SpiceAudio *spice_audio_get(SpiceSession *session, GMainContext *context);
> diff --git a/src/spice-session.c b/src/spice-session.c
> index 6915736..f0ac891 100644
> --- a/src/spice-session.c
> +++ b/src/spice-session.c
> @@ -2796,7 +2796,6 @@ gboolean
> spice_session_get_smartcard_enabled(SpiceSession *session)
> return session->priv->smartcard;
> }
>
> -G_GNUC_INTERNAL
> PhodavServer* spice_session_get_webdav_server(SpiceSession *session)
> {
> SpiceSessionPrivate *priv;
> diff --git a/src/spice-session.h b/src/spice-session.h
> index ed01c01..9436be8 100644
> --- a/src/spice-session.h
> +++ b/src/spice-session.h
> @@ -36,6 +36,8 @@ G_BEGIN_DECLS
> #define SPICE_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
> SPICE_TYPE_SESSION))
> #define SPICE_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
> SPICE_TYPE_SESSION, SpiceSessionClass))
>
> +typedef struct _PhodavServer PhodavServer;
> +
> /**
> * SpiceSessionVerify:
> * @SPICE_SESSION_VERIFY_PUBKEY: verify certificate public key matching
> @@ -113,6 +115,7 @@ gboolean spice_session_has_channel_type(SpiceSession
> *session, gint type);
> gboolean spice_session_get_read_only(SpiceSession *session);
> SpiceURI *spice_session_get_proxy_uri(SpiceSession *session);
> gboolean spice_session_is_for_migration(SpiceSession *session);
> +PhodavServer *spice_session_get_webdav_server(SpiceSession *session);
>
> G_END_DECLS
>
> _______________________________________________
> Spice-commits mailing list
> Spice-commits at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-commits
>
--
Marc-André Lureau
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20200909/a7b6a85b/attachment-0001.htm>
More information about the Spice-devel
mailing list