Hi, On Wed, Sep 9, 2020 at 5:50 PM GitLab Mirror < gitlab-mir...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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ů <jja...@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ů <jja...@redhat.com> > Acked-by: Frediano Ziglio <fzig...@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-comm...@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/spice-commits > -- Marc-André Lureau
_______________________________________________ Spice-devel mailing list Spice-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/spice-devel