[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-commits/attachments/20200909/a7b6a85b/attachment-0001.htm>


More information about the Spice-commits mailing list