[Spice-devel] [PATCH spice-gtk 3/7] Move clipboard handling to SpiceGtkSession
Marc-André Lureau
marcandre.lureau at gmail.com
Thu Oct 6 11:49:23 PDT 2011
On Thu, Oct 6, 2011 at 8:07 PM, Hans de Goede <hdegoede at redhat.com> wrote:
> This fixes copy and paste with multi-monitor guests. There still is
> one small issue left with this patch, changing the setting for auto-clipboard
> in one spicy window, does not get reflected in the Options menu of the
> other spicy windows.
>
> This can be fixed by listening to the notify signal, this also requires
> SpiceDisplay to listen to property changes on its SpiceGtkSession and
> then do a g_object_set on itself to update its own property (and also
> emit its own notify signal.
>
> I'll write a separate patch for this.
>
> Signed-off-by: Hans de Goede <hdegoede at redhat.com>
> ---
> doc/reference/spice-gtk-sections.txt | 2 +
> gtk/map-file | 2 +
> gtk/spice-gtk-session.c | 593 +++++++++++++++++++++++++++++++++-
> gtk/spice-gtk-session.h | 2 +
> gtk/spice-widget-priv.h | 15 +-
> gtk/spice-widget.c | 465 ++-------------------------
> 6 files changed, 618 insertions(+), 461 deletions(-)
>
> diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
> index d5e8e70..56ae829 100644
> --- a/doc/reference/spice-gtk-sections.txt
> +++ b/doc/reference/spice-gtk-sections.txt
> @@ -292,6 +292,8 @@ SpiceUsbDeviceManagerPrivate
> SpiceGtkSession
> SpiceGtkSessionClass
> spice_gtk_session_get
> +spice_gtk_session_copy_to_guest
> +spice_gtk_session_paste_from_guest
> <SUBSECTION Standard>
> SPICE_GTK_SESSION
> SPICE_IS_GTK_SESSION
> diff --git a/gtk/map-file b/gtk/map-file
> index 41793a9..82440c0 100644
> --- a/gtk/map-file
> +++ b/gtk/map-file
> @@ -69,6 +69,8 @@ spice_session_open_fd;
> spice_session_verify_get_type;
> spice_gtk_session_get;
> spice_gtk_session_get_type;
> +spice_gtk_session_copy_to_guest;
> +spice_gtk_session_paste_from_guest;
> spice_set_session_option;
> spice_smartcard_channel_get_type;
> spice_smartcard_manager_get;
> diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
> index 165d91e..d3cdd7d 100644
> --- a/gtk/spice-gtk-session.c
> +++ b/gtk/spice-gtk-session.c
> @@ -16,10 +16,25 @@
> License along with this library; if not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include <gtk/gtk.h>
> +#include <spice/vd_agent.h>
> +#include "spice-common.h"
> #include "spice-gtk-session.h"
>
> +#define CLIPBOARD_LAST (VD_AGENT_CLIPBOARD_SELECTION_SECONDARY + 1)
> +
> struct _SpiceGtkSessionPrivate {
> - SpiceSession *session;
> + SpiceSession *session;
> + SpiceMainChannel *main;
> + gboolean auto_clipboard_enable;
> + GtkClipboard *clipboard;
> + GtkClipboard *clipboard_primary;
> + GtkTargetEntry *clip_targets[CLIPBOARD_LAST];
> + guint nclip_targets[CLIPBOARD_LAST];
> + gboolean clip_hasdata[CLIPBOARD_LAST];
> + gboolean clip_grabbed[CLIPBOARD_LAST];
> + gboolean clipboard_by_guest[CLIPBOARD_LAST];
> + gboolean clipboard_selfgrab_pending[CLIPBOARD_LAST];
> };
>
> /**
> @@ -51,6 +66,16 @@ struct _SpiceGtkSessionPrivate {
> */
>
> /* ------------------------------------------------------------------ */
> +/* Prototypes for private functions */
> +static void clipboard_owner_change(GtkClipboard *clipboard,
> + GdkEventOwnerChange *event,
> + gpointer user_data);
> +static void channel_new(SpiceSession *session, SpiceChannel *channel,
> + gpointer user_data);
> +static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
> + gpointer user_data);
> +
> +/* ------------------------------------------------------------------ */
> /* gobject glue */
>
> #define SPICE_GTK_SESSION_GET_PRIVATE(obj) \
> @@ -62,11 +87,21 @@ G_DEFINE_TYPE (SpiceGtkSession, spice_gtk_session, G_TYPE_OBJECT);
> enum {
> PROP_0,
> PROP_SESSION,
> + PROP_AUTO_CLIPBOARD,
> };
>
> static void spice_gtk_session_init(SpiceGtkSession *self)
> {
> - self->priv = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + SpiceGtkSessionPrivate *s;
> +
> + s = self->priv = SPICE_GTK_SESSION_GET_PRIVATE(self);
> +
> + s->clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
> + g_signal_connect(G_OBJECT(s->clipboard), "owner-change",
> + G_CALLBACK(clipboard_owner_change), self);
> + s->clipboard_primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
> + g_signal_connect(G_OBJECT(s->clipboard_primary), "owner-change",
> + G_CALLBACK(clipboard_owner_change), self);
> }
>
> static GObject *
> @@ -76,6 +111,9 @@ spice_gtk_session_constructor(GType gtype,
> {
> GObject *obj;
> SpiceGtkSession *self;
> + SpiceGtkSessionPrivate *s;
> + GList *list;
> + GList *it;
>
> {
> /* Always chain up to the parent constructor */
> @@ -85,20 +123,50 @@ spice_gtk_session_constructor(GType gtype,
> }
>
> self = SPICE_GTK_SESSION(obj);
> - if (!self->priv->session)
> + s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + if (!s->session)
> g_error("SpiceGtKSession constructed without a session");
>
> + g_signal_connect(s->session, "channel-new",
> + G_CALLBACK(channel_new), self);
> + g_signal_connect(s->session, "channel-destroy",
> + G_CALLBACK(channel_destroy), self);
> + list = spice_session_get_channels(s->session);
> + for (it = g_list_first(list); it != NULL; it = g_list_next(it)) {
> + channel_new(s->session, it->data, (gpointer*)self);
> + }
> + g_list_free(list);
> +
> return obj;
> }
>
> static void spice_gtk_session_dispose(GObject *gobject)
> {
> -#if 0
> SpiceGtkSession *self = SPICE_GTK_SESSION(gobject);
> SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> -#endif
>
> /* release stuff */
> + if (s->clipboard) {
> + g_signal_handlers_disconnect_by_func(s->clipboard,
> + G_CALLBACK(clipboard_owner_change), self);
> + s->clipboard = NULL;
> + }
> +
> + if (s->clipboard_primary) {
> + g_signal_handlers_disconnect_by_func(s->clipboard_primary,
> + G_CALLBACK(clipboard_owner_change), self);
> + s->clipboard_primary = NULL;
> + }
> +
> + if (s->session) {
> + g_signal_handlers_disconnect_by_func(s->session,
> + G_CALLBACK(channel_new),
> + self);
> + g_signal_handlers_disconnect_by_func(s->session,
> + G_CALLBACK(channel_destroy),
> + self);
> + s->session = NULL;
> + }
>
> /* Chain up to the parent class */
> if (G_OBJECT_CLASS(spice_gtk_session_parent_class)->dispose)
> @@ -107,12 +175,15 @@ static void spice_gtk_session_dispose(GObject *gobject)
>
> static void spice_gtk_session_finalize(GObject *gobject)
> {
> -#if 0
> SpiceGtkSession *self = SPICE_GTK_SESSION(gobject);
> SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> -#endif
> + int i;
>
> /* release stuff */
> + for (i = 0; i < CLIPBOARD_LAST; ++i) {
> + g_free(s->clip_targets[i]);
> + s->clip_targets[i] = NULL;
> + }
>
> /* Chain up to the parent class */
> if (G_OBJECT_CLASS(spice_gtk_session_parent_class)->finalize)
> @@ -131,6 +202,9 @@ static void spice_gtk_session_get_property(GObject *gobject,
> case PROP_SESSION:
> g_value_set_object(value, s->session);
> break;
> + case PROP_AUTO_CLIPBOARD:
> + g_value_set_boolean(value, s->auto_clipboard_enable);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
> break;
> @@ -149,6 +223,9 @@ static void spice_gtk_session_set_property(GObject *gobject,
> case PROP_SESSION:
> s->session = g_value_get_object(value);
> break;
> + case PROP_AUTO_CLIPBOARD:
> + s->auto_clipboard_enable = g_value_get_boolean(value);
> + break;
> default:
> G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
> break;
> @@ -181,6 +258,23 @@ static void spice_gtk_session_class_init(SpiceGtkSessionClass *klass)
> G_PARAM_CONSTRUCT_ONLY |
> G_PARAM_STATIC_STRINGS));
>
> + /**
> + * SpiceGtkSession:auto-clipboard:
> + *
> + * When this is true the clipboard gets automatically shared between host
> + * and guest.
> + **/
> + g_object_class_install_property
> + (gobject_class, PROP_AUTO_CLIPBOARD,
> + g_param_spec_boolean("auto-clipboard",
> + "Auto clipboard",
> + "Automatically relay clipboard changes between "
> + "host and guest.",
> + TRUE,
> + G_PARAM_READWRITE |
> + G_PARAM_CONSTRUCT |
> + G_PARAM_STATIC_STRINGS));
> +
> g_type_class_add_private(klass, sizeof(SpiceGtkSessionPrivate));
> }
>
> @@ -193,6 +287,446 @@ spice_gtk_session_spice_session_destroyed_cb(gpointer user_data,
> g_object_unref(self);
> }
>
> +/* ---------------------------------------------------------------- */
> +/* private functions (clipboard related) */
> +
> +static GtkClipboard* get_clipboard_from_selection(SpiceGtkSessionPrivate *s,
> + guint selection)
> +{
> + if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
> + return s->clipboard;
> + } else if (selection == VD_AGENT_CLIPBOARD_SELECTION_PRIMARY) {
> + return s->clipboard_primary;
> + } else {
> + g_warning("Unhandled clipboard selection: %d", selection);
> + return NULL;
> + }
> +}
> +
> +static gint get_selection_from_clipboard(SpiceGtkSessionPrivate *s,
> + GtkClipboard* cb)
> +{
> + if (cb == s->clipboard) {
> + return VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
> + } else if (cb == s->clipboard_primary) {
> + return VD_AGENT_CLIPBOARD_SELECTION_PRIMARY;
> + } else {
> + g_warning("Unhandled clipboard");
> + return -1;
> + }
> +}
> +
> +static const struct {
> + const char *xatom;
> + uint32_t vdagent;
> + uint32_t flags;
> +} atom2agent[] = {
> + {
> + .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> + .xatom = "UTF8_STRING",
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> + .xatom = "text/plain;charset=utf-8"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> + .xatom = "STRING"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> + .xatom = "TEXT"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> + .xatom = "text/plain"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_PNG,
> + .xatom = "image/png"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> + .xatom = "image/bmp"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> + .xatom = "image/x-bmp"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> + .xatom = "image/x-MS-bmp"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> + .xatom = "image/x-win-bitmap"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_TIFF,
> + .xatom = "image/tiff"
> + },{
> + .vdagent = VD_AGENT_CLIPBOARD_IMAGE_JPG,
> + .xatom = "image/jpeg"
> + }
> +};
> +
> +static void clipboard_get_targets(GtkClipboard *clipboard,
> + GdkAtom *atoms,
> + gint n_atoms,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + guint32 types[SPICE_N_ELEMENTS(atom2agent)];
> + char *name;
> + int a, m, t;
> + int selection;
> +
> + selection = get_selection_from_clipboard(s, clipboard);
> + g_return_if_fail(selection != -1);
> + g_return_if_fail(s->main != NULL);
> +
> + SPICE_DEBUG("%s:", __FUNCTION__);
> + if (spice_util_get_debug()) {
> + for (a = 0; a < n_atoms; a++) {
> + name = gdk_atom_name(atoms[a]);
> + SPICE_DEBUG(" \"%s\"", name);
> + g_free(name);
> + }
> + }
> +
> + memset(types, 0, sizeof(types));
> + for (a = 0; a < n_atoms; a++) {
> + name = gdk_atom_name(atoms[a]);
> + for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> + if (strcasecmp(name, atom2agent[m].xatom) != 0) {
> + continue;
> + }
> + /* found match */
> + for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) {
> + if (types[t] == atom2agent[m].vdagent) {
> + /* type already in list */
> + break;
> + }
> + if (types[t] == 0) {
> + /* add type to empty slot */
> + types[t] = atom2agent[m].vdagent;
> + break;
> + }
> + }
> + break;
> + }
> + g_free(name);
> + }
> + for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) {
> + if (types[t] == 0) {
> + break;
> + }
> + }
> + if (!s->clip_grabbed[selection] && t > 0) {
> + s->clip_grabbed[selection] = TRUE;
> + spice_main_clipboard_selection_grab(s->main, selection, types, t);
> + /* Sending a grab causes the agent to do an impicit release */
> + s->nclip_targets[selection] = 0;
> + }
> +}
> +
> +static void clipboard_owner_change(GtkClipboard *clipboard,
> + GdkEventOwnerChange *event,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + int selection;
> +
> + selection = get_selection_from_clipboard(s, clipboard);
> + g_return_if_fail(selection != -1);
> +
> + if (s->main == NULL)
> + return;
> +
> + if (s->clip_grabbed[selection]) {
> + s->clip_grabbed[selection] = FALSE;
> + spice_main_clipboard_selection_release(s->main, selection);
> + }
> +
> + switch (event->reason) {
> + case GDK_OWNER_CHANGE_NEW_OWNER:
> + if (s->clipboard_selfgrab_pending[selection]) {
> + s->clipboard_selfgrab_pending[selection] = FALSE;
> + break;
> + }
> + s->clipboard_by_guest[selection] = FALSE;
> + s->clip_hasdata[selection] = TRUE;
> + if (s->auto_clipboard_enable)
> + gtk_clipboard_request_targets(clipboard, clipboard_get_targets,
> + self);
> + break;
> + default:
> + s->clip_hasdata[selection] = FALSE;
> + break;
> + }
> +}
> +
> +typedef struct
> +{
> + GMainLoop *loop;
> + GtkSelectionData *selection_data;
> + guint info;
> + gulong timeout_handler;
> + guint selection;
> +} RunInfo;
> +
> +static void clipboard_got_from_guest(SpiceMainChannel *main, guint selection,
> + guint type, guchar *data, guint size,
> + gpointer user_data)
> +{
> + RunInfo *ri = user_data;
> +
> + g_return_if_fail(selection == ri->selection);
> +
> + SPICE_DEBUG("clipboard got data");
> +
> + gtk_selection_data_set(ri->selection_data,
> + gdk_atom_intern_static_string(atom2agent[ri->info].xatom),
> + 8, data, size);
> +
> + if (g_main_loop_is_running (ri->loop))
> + g_main_loop_quit (ri->loop);
> +}
> +
> +static gboolean clipboard_timeout(gpointer user_data)
> +{
> + RunInfo *ri = user_data;
> +
> + g_warning("clipboard get timed out");
> + if (g_main_loop_is_running (ri->loop))
> + g_main_loop_quit (ri->loop);
> +
> + ri->timeout_handler = 0;
> + return FALSE;
> +}
> +
> +static void clipboard_get(GtkClipboard *clipboard,
> + GtkSelectionData *selection_data,
> + guint info, gpointer user_data)
> +{
> + RunInfo ri = { NULL, };
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + gulong clipboard_handler;
> + int selection;
> +
> + SPICE_DEBUG("clipboard get");
> +
> + selection = get_selection_from_clipboard(s, clipboard);
> + g_return_if_fail(selection != -1);
> + g_return_if_fail(info < SPICE_N_ELEMENTS(atom2agent));
> + g_return_if_fail(s->main != NULL);
> +
> + ri.selection_data = selection_data;
> + ri.info = info;
> + ri.loop = g_main_loop_new(NULL, FALSE);
> + ri.selection = selection;
> +
> + clipboard_handler = g_signal_connect(s->main, "main-clipboard-selection",
> + G_CALLBACK(clipboard_got_from_guest),
> + &ri);
> + ri.timeout_handler = g_timeout_add_seconds(7, clipboard_timeout, &ri);
> + spice_main_clipboard_selection_request(s->main, selection,
> + atom2agent[info].vdagent);
> +
> + /* apparently, this is needed to avoid dead-lock, from
> + gtk_dialog_run */
> + GDK_THREADS_LEAVE();
> + g_main_loop_run(ri.loop);
> + GDK_THREADS_ENTER();
> +
> + g_main_loop_unref(ri.loop);
> + ri.loop = NULL;
> + g_signal_handler_disconnect(s->main, clipboard_handler);
> + if (ri.timeout_handler != 0)
> + g_source_remove(ri.timeout_handler);
> +}
> +
> +static void clipboard_clear(GtkClipboard *clipboard, gpointer user_data)
> +{
> + SPICE_DEBUG("clipboard_clear");
> + /* We watch for clipboard ownership changes and act on those, so we
> + don't need to do anything here */
> +}
> +
> +static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,
> + guint32* types, guint32 ntypes,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + GtkTargetEntry targets[SPICE_N_ELEMENTS(atom2agent)];
> + gboolean target_selected[SPICE_N_ELEMENTS(atom2agent)] = { FALSE, };
> + gboolean found;
> + GtkClipboard* cb;
> + int m, n, i;
> +
> + cb = get_clipboard_from_selection(s, selection);
> + g_return_val_if_fail(cb != NULL, FALSE);
> +
> + i = 0;
> + for (n = 0; n < ntypes; ++n) {
> + found = FALSE;
> + for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> + if (atom2agent[m].vdagent == types[n] && !target_selected[m]) {
> + found = TRUE;
> + g_return_val_if_fail(i < SPICE_N_ELEMENTS(atom2agent), FALSE);
> + targets[i].target = (gchar*)atom2agent[m].xatom;
> + targets[i].flags = 0;
> + targets[i].info = m;
> + target_selected[m] = TRUE;
> + i += 1;
> + }
> + }
> + if (!found) {
> + g_warning("clipboard: couldn't find a matching type for: %d",
> + types[n]);
> + }
> + }
> +
> + g_free(s->clip_targets[selection]);
> + s->nclip_targets[selection] = i;
> + s->clip_targets[selection] = g_memdup(targets, sizeof(GtkTargetEntry) * i);
> + /* Receiving a grab implies we've released our own grab */
> + s->clip_grabbed[selection] = FALSE;
> +
> + if (!s->auto_clipboard_enable || s->nclip_targets[selection] == 0)
> + goto skip_grab_clipboard;
> +
> + if (!gtk_clipboard_set_with_data(cb, targets, i, clipboard_get,
> + clipboard_clear, self)) {
> + g_warning("clipboard grab failed");
> + return FALSE;
> + }
> + s->clipboard_selfgrab_pending[selection] = TRUE;
> + s->clipboard_by_guest[selection] = TRUE;
> + s->clip_hasdata[selection] = FALSE;
> +
> +skip_grab_clipboard:
> + return TRUE;
> +}
> +
> +static void clipboard_received_cb(GtkClipboard *clipboard,
> + GtkSelectionData *selection_data,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + gint len = 0, m;
> + guint32 type = VD_AGENT_CLIPBOARD_NONE;
> + gchar* name;
> + GdkAtom atom;
> + int selection;
> +
> + selection = get_selection_from_clipboard(s, clipboard);
> + g_return_if_fail(selection != -1);
> +
> + len = gtk_selection_data_get_length(selection_data);
> + if (len == -1) {
> + SPICE_DEBUG("empty clipboard");
> + len = 0;
> + } else if (len == 0) {
> + SPICE_DEBUG("TODO: what should be done here?");
> + } else {
> + atom = gtk_selection_data_get_data_type(selection_data);
> + name = gdk_atom_name(atom);
> + for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> + if (strcasecmp(name, atom2agent[m].xatom) == 0) {
> + break;
> + }
> + }
> +
> + if (m >= SPICE_N_ELEMENTS(atom2agent)) {
> + g_warning("clipboard_received for unsupported type: %s", name);
> + } else {
> + type = atom2agent[m].vdagent;
> + }
> +
> + g_free(name);
> + }
> +
> + spice_main_clipboard_selection_notify(s->main, selection, type,
> + gtk_selection_data_get_data(selection_data), len);
> +}
> +
> +static gboolean clipboard_request(SpiceMainChannel *main, guint selection,
> + guint type, gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + GdkAtom atom;
> + GtkClipboard* cb;
> + int m;
> +
> + cb = get_clipboard_from_selection(s, selection);
> + g_return_val_if_fail(cb != NULL, FALSE);
> +
> + for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> + if (atom2agent[m].vdagent == type)
> + break;
> + }
> +
> + g_return_val_if_fail(m < SPICE_N_ELEMENTS(atom2agent), FALSE);
> +
> + atom = gdk_atom_intern_static_string(atom2agent[m].xatom);
> + gtk_clipboard_request_contents(cb, atom, clipboard_received_cb, self);
> +
> + return TRUE;
> +}
> +
> +static void clipboard_release(SpiceMainChannel *main, guint selection,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + GtkClipboard* clipboard = get_clipboard_from_selection(s, selection);
> + if (!clipboard)
> + return;
> +
> + s->nclip_targets[selection] = 0;
> +
> + if (!s->clipboard_by_guest[selection])
> + return;
> + gtk_clipboard_clear(clipboard);
> + s->clipboard_by_guest[selection] = FALSE;
> +}
> +
> +static void channel_new(SpiceSession *session, SpiceChannel *channel,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> +
> + if (SPICE_IS_MAIN_CHANNEL(channel)) {
> + s->main = SPICE_MAIN_CHANNEL(channel);
> + g_signal_connect(channel, "main-clipboard-selection-grab",
> + G_CALLBACK(clipboard_grab), self);
> + g_signal_connect(channel, "main-clipboard-selection-request",
> + G_CALLBACK(clipboard_request), self);
> + g_signal_connect(channel, "main-clipboard-selection-release",
> + G_CALLBACK(clipboard_release), self);
> + }
> +}
> +
> +static void channel_destroy(SpiceSession *session, SpiceChannel *channel,
> + gpointer user_data)
> +{
> + SpiceGtkSession *self = user_data;
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + guint i;
> +
> + if (SPICE_IS_MAIN_CHANNEL(channel)) {
> + s->main = NULL;
> + for (i = 0; i < CLIPBOARD_LAST; ++i) {
> + if (s->clipboard_by_guest[i]) {
> + GtkClipboard *cb = get_clipboard_from_selection(s, i);
> + if (cb)
> + gtk_clipboard_clear(cb);
> + s->clipboard_by_guest[i] = FALSE;
> + }
> + s->clip_grabbed[i] = FALSE;
> + s->nclip_targets[i] = 0;
> + }
> + }
> +}
> +
> /* ------------------------------------------------------------------ */
> /* public functions */
>
> @@ -228,3 +762,48 @@ SpiceGtkSession *spice_gtk_session_get(SpiceSession *session)
>
> return SPICE_GTK_SESSION(self);
> }
> +
> +/**
> + * spice_gtk_session_copy_to_guest:
> + * @self:
> + *
> + * Copy client-side clipboard to guest clipboard.
> + **/
> +void spice_gtk_session_copy_to_guest(SpiceGtkSession *self)
> +{
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
> +
> + if (s->clip_hasdata[selection] && !s->clip_grabbed[selection]) {
> + gtk_clipboard_request_targets(s->clipboard, clipboard_get_targets,
> + self);
> + }
> +}
> +
> +/**
> + * spice_gtk_session_paste_from_guest:
> + * @self:
> + *
> + * Copy guest clipboard to client-side clipboard.
> + **/
> +void spice_gtk_session_paste_from_guest(SpiceGtkSession *self)
> +{
> + SpiceGtkSessionPrivate *s = SPICE_GTK_SESSION_GET_PRIVATE(self);
> + int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
> +
> + if (s->nclip_targets[selection] == 0) {
> + g_warning("Guest clipboard is not available.");
> + return;
> + }
> +
> + if (!gtk_clipboard_set_with_data(s->clipboard,
> + s->clip_targets[selection],
> + s->nclip_targets[selection],
> + clipboard_get, clipboard_clear, self)) {
> + g_warning("Clipboard grab failed");
> + return;
> + }
> + s->clipboard_selfgrab_pending[selection] = TRUE;
> + s->clipboard_by_guest[selection] = TRUE;
> + s->clip_hasdata[selection] = FALSE;
> +}
> diff --git a/gtk/spice-gtk-session.h b/gtk/spice-gtk-session.h
> index 9c59fa2..3b4eac6 100644
> --- a/gtk/spice-gtk-session.h
> +++ b/gtk/spice-gtk-session.h
> @@ -57,6 +57,8 @@ struct _SpiceGtkSessionClass
> GType spice_gtk_session_get_type(void);
>
> SpiceGtkSession *spice_gtk_session_get(SpiceSession *session);
> +void spice_gtk_session_copy_to_guest(SpiceGtkSession *self);
> +void spice_gtk_session_paste_from_guest(SpiceGtkSession *self);
>
> G_END_DECLS
>
> diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
> index bd6dedb..f94c8c6 100644
> --- a/gtk/spice-widget-priv.h
> +++ b/gtk/spice-widget-priv.h
> @@ -36,13 +36,11 @@ G_BEGIN_DECLS
>
> #include "spice-widget.h"
> #include "spice-common.h"
> -#include <spice/vd_agent.h>
> +#include "spice-gtk-session.h"
>
> #define SPICE_DISPLAY_GET_PRIVATE(obj) \
> (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_DISPLAY, SpiceDisplayPrivate))
>
> -#define CLIPBOARD_LAST (VD_AGENT_CLIPBOARD_SELECTION_SECONDARY + 1)
> -
> struct _SpiceDisplayPrivate {
> gint channel_id;
>
> @@ -50,7 +48,6 @@ struct _SpiceDisplayPrivate {
> bool keyboard_grab_enable;
> bool mouse_grab_enable;
> bool resize_guest_enable;
> - bool auto_clipboard_enable;
> bool auto_usbredir_enable;
>
> /* state */
> @@ -77,16 +74,8 @@ struct _SpiceDisplayPrivate {
> cairo_surface_t *ximage;
> #endif
>
> - GtkClipboard *clipboard;
> - GtkClipboard *clipboard_primary;
> - GtkTargetEntry *clip_targets[CLIPBOARD_LAST];
> - guint nclip_targets[CLIPBOARD_LAST];
> - bool clip_hasdata[CLIPBOARD_LAST];
> - bool clip_grabbed[CLIPBOARD_LAST];
> - gboolean clipboard_by_guest[CLIPBOARD_LAST];
> - gboolean clipboard_selfgrab_pending[CLIPBOARD_LAST];
> -
> SpiceSession *session;
> + SpiceGtkSession *gtk_session;
> SpiceMainChannel *main;
> SpiceChannel *display;
> SpiceCursorChannel *cursor;
> diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
> index 2beea73..8b1c9ad 100644
> --- a/gtk/spice-widget.c
> +++ b/gtk/spice-widget.c
> @@ -110,8 +110,6 @@ static void try_keyboard_ungrab(SpiceDisplay *display);
> static void try_mouse_grab(GtkWidget *widget);
> static void try_mouse_ungrab(GtkWidget *widget);
> static void recalc_geometry(GtkWidget *widget, gboolean set_display);
> -static void clipboard_owner_change(GtkClipboard *clipboard,
> - GdkEventOwnerChange *event, gpointer user_data);
> static void disconnect_main(SpiceDisplay *display);
> static void disconnect_cursor(SpiceDisplay *display);
> static void disconnect_display(SpiceDisplay *display);
> @@ -129,6 +127,7 @@ static void spice_display_get_property(GObject *object,
> {
> SpiceDisplay *display = SPICE_DISPLAY(object);
> SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> + gboolean boolean;
>
> switch (prop_id) {
> case PROP_KEYBOARD_GRAB:
> @@ -141,7 +140,8 @@ static void spice_display_get_property(GObject *object,
> g_value_set_boolean(value, d->resize_guest_enable);
> break;
> case PROP_AUTO_CLIPBOARD:
> - g_value_set_boolean(value, d->auto_clipboard_enable);
> + g_object_get(d->gtk_session, "auto-clipboard", &boolean, NULL);
> + g_value_set_boolean(value, boolean);
> break;
> case PROP_AUTO_USBREDIR:
> g_value_set_boolean(value, d->auto_usbredir_enable);
> @@ -198,7 +198,8 @@ static void spice_display_set_property(GObject *object,
> }
> break;
> case PROP_AUTO_CLIPBOARD:
> - d->auto_clipboard_enable = g_value_get_boolean(value);
> + g_object_set(d->gtk_session, "auto-clipboard",
> + g_value_get_boolean(value), NULL);
> break;
> case PROP_AUTO_USBREDIR:
> d->auto_usbredir_enable = g_value_get_boolean(value);
> @@ -221,17 +222,6 @@ static void spice_display_dispose(GObject *obj)
> disconnect_display(display);
> disconnect_cursor(display);
>
> - if (d->clipboard) {
> - g_signal_handlers_disconnect_by_func(d->clipboard, G_CALLBACK(clipboard_owner_change),
> - display);
> - d->clipboard = NULL;
> - }
> -
> - if (d->clipboard_primary) {
> - g_signal_handlers_disconnect_by_func(d->clipboard_primary, G_CALLBACK(clipboard_owner_change),
> - display);
> - d->clipboard_primary = NULL;
> - }
> if (d->session) {
> g_signal_handlers_disconnect_by_func(d->session, G_CALLBACK(channel_new),
> display);
> @@ -239,6 +229,7 @@ static void spice_display_dispose(GObject *obj)
> display);
> g_object_unref(d->session);
> d->session = NULL;
> + d->gtk_session = NULL;
> }
> }
>
> @@ -246,7 +237,6 @@ static void spice_display_finalize(GObject *obj)
> {
> SpiceDisplay *display = SPICE_DISPLAY(obj);
> SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - int i;
>
> SPICE_DEBUG("Finalize spice display");
>
> @@ -257,11 +247,6 @@ static void spice_display_finalize(GObject *obj)
> g_free(d->activeseq);
> d->activeseq = NULL;
>
> - for (i = 0; i < CLIPBOARD_LAST; ++i) {
> - g_free(d->clip_targets[i]);
> - d->clip_targets[i] = NULL;
> - }
> -
> G_OBJECT_CLASS(spice_display_parent_class)->finalize(obj);
> }
>
> @@ -289,13 +274,6 @@ static void spice_display_init(SpiceDisplay *display)
> d->grabseq = spice_grab_sequence_new_from_string("Control_L+Alt_L");
> d->activeseq = g_new0(gboolean, d->grabseq->nkeysyms);
>
> - d->clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
> - g_signal_connect(G_OBJECT(d->clipboard), "owner-change",
> - G_CALLBACK(clipboard_owner_change), display);
> - d->clipboard_primary = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
> - g_signal_connect(G_OBJECT(d->clipboard_primary), "owner-change",
> - G_CALLBACK(clipboard_owner_change), display);
> -
> if (g_getenv("SPICE_DEBUG_CURSOR"))
> d->mouse_cursor = gdk_cursor_new(GDK_DOT);
> else
> @@ -1088,174 +1066,6 @@ static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *conf)
>
> /* ---------------------------------------------------------------- */
>
> -static GtkClipboard* get_clipboard_from_selection(SpiceDisplayPrivate *d, guint selection)
> -{
> - if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
> - return d->clipboard;
> - } else if (selection == VD_AGENT_CLIPBOARD_SELECTION_PRIMARY) {
> - return d->clipboard_primary;
> - } else {
> - g_warning("Unhandled clipboard selection: %d", selection);
> - return NULL;
> - }
> -}
> -
> -static gint get_selection_from_clipboard(SpiceDisplayPrivate *d, GtkClipboard* cb)
> -{
> - if (cb == d->clipboard) {
> - return VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
> - } else if (cb == d->clipboard_primary) {
> - return VD_AGENT_CLIPBOARD_SELECTION_PRIMARY;
> - } else {
> - g_warning("Unhandled clipboard");
> - return -1;
> - }
> -}
> -
> -static const struct {
> - const char *xatom;
> - uint32_t vdagent;
> - uint32_t flags;
> -} atom2agent[] = {
> - {
> - .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> - .xatom = "UTF8_STRING",
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> - .xatom = "text/plain;charset=utf-8"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> - .xatom = "STRING"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> - .xatom = "TEXT"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_UTF8_TEXT,
> - .xatom = "text/plain"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_PNG,
> - .xatom = "image/png"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> - .xatom = "image/bmp"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> - .xatom = "image/x-bmp"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> - .xatom = "image/x-MS-bmp"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_BMP,
> - .xatom = "image/x-win-bitmap"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_TIFF,
> - .xatom = "image/tiff"
> - },{
> - .vdagent = VD_AGENT_CLIPBOARD_IMAGE_JPG,
> - .xatom = "image/jpeg"
> - }
> -};
> -
> -static void clipboard_get_targets(GtkClipboard *clipboard,
> - GdkAtom *atoms,
> - gint n_atoms,
> - gpointer data)
> -{
> - SpiceDisplay *display = data;
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - guint32 types[SPICE_N_ELEMENTS(atom2agent)];
> - char *name;
> - int a, m, t;
> - int selection;
> -
> - selection = get_selection_from_clipboard(d, clipboard);
> - g_return_if_fail(selection != -1);
> -
> - SPICE_DEBUG("%s:", __FUNCTION__);
> - if (spice_util_get_debug()) {
> - for (a = 0; a < n_atoms; a++) {
> - name = gdk_atom_name(atoms[a]);
> - SPICE_DEBUG(" \"%s\"", name);
> - g_free(name);
> - }
> - }
> -
> - memset(types, 0, sizeof(types));
> - for (a = 0; a < n_atoms; a++) {
> - name = gdk_atom_name(atoms[a]);
> - for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> - if (strcasecmp(name, atom2agent[m].xatom) != 0) {
> - continue;
> - }
> - /* found match */
> - for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) {
> - if (types[t] == atom2agent[m].vdagent) {
> - /* type already in list */
> - break;
> - }
> - if (types[t] == 0) {
> - /* add type to empty slot */
> - types[t] = atom2agent[m].vdagent;
> - break;
> - }
> - }
> - break;
> - }
> - g_free(name);
> - }
> - for (t = 0; t < SPICE_N_ELEMENTS(atom2agent); t++) {
> - if (types[t] == 0) {
> - break;
> - }
> - }
> - if (!d->clip_grabbed[selection] && t > 0) {
> - d->clip_grabbed[selection] = TRUE;
> - spice_main_clipboard_selection_grab(d->main,
> - get_selection_from_clipboard(d, clipboard), types, t);
> - /* Sending a grab causes the agent to do an impicit release */
> - d->nclip_targets[selection] = 0;
> - }
> -}
> -
> -static void clipboard_owner_change(GtkClipboard *clipboard,
> - GdkEventOwnerChange *event,
> - gpointer data)
> -{
> - SpiceDisplay *display = data;
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - int selection;
> -
> - selection = get_selection_from_clipboard(d, clipboard);
> - g_return_if_fail(selection != -1);
> -
> - if (d->main == NULL)
> - return;
> -
> - if (d->clip_grabbed[selection]) {
> - d->clip_grabbed[selection] = FALSE;
> - spice_main_clipboard_selection_release(d->main,
> - get_selection_from_clipboard(d, clipboard));
> - }
> -
> - switch (event->reason) {
> - case GDK_OWNER_CHANGE_NEW_OWNER:
> - if (d->clipboard_selfgrab_pending[selection]) {
> - d->clipboard_selfgrab_pending[selection] = FALSE;
> - break;
> - }
> - d->clipboard_by_guest[selection] = FALSE;
> - d->clip_hasdata[selection] = TRUE;
> - if (d->auto_clipboard_enable)
> - gtk_clipboard_request_targets(clipboard, clipboard_get_targets, data);
> - break;
> - default:
> - d->clip_hasdata[selection] = FALSE;
> - break;
> - }
> -}
> -
> -/* ---------------------------------------------------------------- */
> -
> static void spice_display_class_init(SpiceDisplayClass *klass)
> {
> GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
> @@ -1314,6 +1124,12 @@ static void spice_display_class_init(SpiceDisplayClass *klass)
> G_PARAM_CONSTRUCT |
> G_PARAM_STATIC_STRINGS));
>
> + /**
> + * SpiceDisplay:auto-clipboard:
> + *
> + * When this is true the clipboard gets automatically shared between host
> + * and guest.
> + **/
Can you document this property as deprecated? and suggest using
spice-gtk-session instead? (there are other deprecated gtk-doc
comments) thanks
> g_object_class_install_property
> (gobject_class, PROP_AUTO_CLIPBOARD,
> g_param_spec_boolean("auto-clipboard",
> @@ -1593,18 +1409,12 @@ static void cursor_reset(SpiceCursorChannel *channel, gpointer data)
> static void disconnect_main(SpiceDisplay *display)
> {
> SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - gint i;
>
> if (d->main == NULL)
> return;
> g_signal_handlers_disconnect_by_func(d->main, G_CALLBACK(mouse_update),
> display);
> d->main = NULL;
> - for (i = 0; i < CLIPBOARD_LAST; ++i) {
> - d->clipboard_by_guest[i] = FALSE;
> - d->clip_grabbed[i] = FALSE;
> - d->nclip_targets[i] = 0;
> - }
> }
>
> static void disconnect_display(SpiceDisplay *display)
> @@ -1639,219 +1449,6 @@ static void disconnect_cursor(SpiceDisplay *display)
> d->cursor = NULL;
> }
>
> -typedef struct
> -{
> - GMainLoop *loop;
> - SpiceDisplay *display;
> - GtkSelectionData *selection_data;
> - guint info;
> - gulong timeout_handler;
> - guint selection;
> -} RunInfo;
> -
> -static void clipboard_got_from_guest(SpiceMainChannel *main, guint selection,
> - guint type, guchar *data, guint size,
> - gpointer userdata)
> -{
> - RunInfo *ri = userdata;
> -
> - g_return_if_fail(selection == ri->selection);
> -
> - SPICE_DEBUG("clipboard got data");
> -
> - gtk_selection_data_set(ri->selection_data,
> - gdk_atom_intern_static_string(atom2agent[ri->info].xatom),
> - 8, data, size);
> -
> - if (g_main_loop_is_running (ri->loop))
> - g_main_loop_quit (ri->loop);
> -}
> -
> -static gboolean clipboard_timeout(gpointer data)
> -{
> - RunInfo *ri = data;
> -
> - g_warning("clipboard get timed out");
> - if (g_main_loop_is_running (ri->loop))
> - g_main_loop_quit (ri->loop);
> -
> - ri->timeout_handler = 0;
> - return FALSE;
> -}
> -
> -static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data,
> - guint info, gpointer display)
> -{
> - RunInfo ri = { NULL, };
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - gulong clipboard_handler;
> -
> - SPICE_DEBUG("clipboard get");
> -
> - g_return_if_fail(info < SPICE_N_ELEMENTS(atom2agent));
> - g_return_if_fail(get_selection_from_clipboard(d, clipboard) != -1);
> -
> - ri.display = display;
> - ri.selection_data = selection_data;
> - ri.info = info;
> - ri.loop = g_main_loop_new(NULL, FALSE);
> - ri.selection = get_selection_from_clipboard(d, clipboard);
> -
> - clipboard_handler = g_signal_connect(d->main, "main-clipboard-selection",
> - G_CALLBACK(clipboard_got_from_guest), &ri);
> - ri.timeout_handler = g_timeout_add_seconds(7, clipboard_timeout, &ri);
> - spice_main_clipboard_selection_request(d->main, ri.selection, atom2agent[info].vdagent);
> -
> - /* apparently, this is needed to avoid dead-lock, from
> - gtk_dialog_run */
> - GDK_THREADS_LEAVE();
> - g_main_loop_run(ri.loop);
> - GDK_THREADS_ENTER();
> -
> - g_main_loop_unref(ri.loop);
> - ri.loop = NULL;
> - g_signal_handler_disconnect(d->main, clipboard_handler);
> - if (ri.timeout_handler != 0)
> - g_source_remove(ri.timeout_handler);
> -}
> -
> -static void clipboard_clear(GtkClipboard *clipboard, gpointer display)
> -{
> - SPICE_DEBUG("clipboard_clear");
> - /* We watch for clipboard ownership changes and act on those, so we
> - don't need to do anything here */
> -}
> -
> -static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,
> - guint32* types, guint32 ntypes, gpointer display)
> -{
> - int m, n, i;
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - GtkTargetEntry targets[SPICE_N_ELEMENTS(atom2agent)];
> - gboolean target_selected[SPICE_N_ELEMENTS(atom2agent)] = { FALSE, };
> - gboolean found;
> - GtkClipboard* cb;
> -
> - cb = get_clipboard_from_selection(d, selection);
> - g_return_val_if_fail(cb != NULL, FALSE);
> -
> - i = 0;
> - for (n = 0; n < ntypes; ++n) {
> - found = FALSE;
> - for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> - if (atom2agent[m].vdagent == types[n] && !target_selected[m]) {
> - found = TRUE;
> - g_return_val_if_fail(i < SPICE_N_ELEMENTS(atom2agent), FALSE);
> - targets[i].target = (gchar*)atom2agent[m].xatom;
> - targets[i].flags = 0;
> - targets[i].info = m;
> - target_selected[m] = TRUE;
> - i += 1;
> - }
> - }
> - if (!found) {
> - g_warning("clipboard: couldn't find a matching type for: %d", types[n]);
> - }
> - }
> -
> - g_free(d->clip_targets[selection]);
> - d->nclip_targets[selection] = i;
> - d->clip_targets[selection] = g_memdup(targets, sizeof(GtkTargetEntry) * i);
> - /* Receiving a grab implies we've released our own grab */
> - d->clip_grabbed[selection] = FALSE;
> -
> - if (!d->auto_clipboard_enable || d->nclip_targets[selection] == 0)
> - goto skip_grab_clipboard;
> -
> - if (!gtk_clipboard_set_with_data(cb, targets, i,
> - clipboard_get, clipboard_clear, display)) {
> - g_warning("clipboard grab failed");
> - return FALSE;
> - }
> - d->clipboard_selfgrab_pending[selection] = TRUE;
> - d->clipboard_by_guest[selection] = TRUE;
> - d->clip_hasdata[selection] = FALSE;
> -
> -skip_grab_clipboard:
> - return TRUE;
> -}
> -
> -static void clipboard_received_cb(GtkClipboard *clipboard,
> - GtkSelectionData *selection_data,
> - gpointer display)
> -{
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - gint len = 0, m;
> - guint32 type = VD_AGENT_CLIPBOARD_NONE;
> - gchar* name;
> - GdkAtom atom;
> -
> - g_return_if_fail(get_selection_from_clipboard(d, clipboard) != -1);
> -
> - len = gtk_selection_data_get_length(selection_data);
> - if (len == -1) {
> - SPICE_DEBUG("empty clipboard");
> - len = 0;
> - } else if (len == 0) {
> - SPICE_DEBUG("TODO: what should be done here?");
> - } else {
> - atom = gtk_selection_data_get_data_type(selection_data);
> - name = gdk_atom_name(atom);
> - for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> - if (strcasecmp(name, atom2agent[m].xatom) == 0) {
> - break;
> - }
> - }
> -
> - if (m >= SPICE_N_ELEMENTS(atom2agent)) {
> - g_warning("clipboard_received for unsupported type: %s", name);
> - } else {
> - type = atom2agent[m].vdagent;
> - }
> -
> - g_free(name);
> - }
> -
> - spice_main_clipboard_selection_notify(d->main, get_selection_from_clipboard(d, clipboard),
> - type, gtk_selection_data_get_data(selection_data), len);
> -}
> -
> -static gboolean clipboard_request(SpiceMainChannel *main, guint selection,
> - guint type, gpointer display)
> -{
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - int m;
> - GdkAtom atom;
> -
> - for (m = 0; m < SPICE_N_ELEMENTS(atom2agent); m++) {
> - if (atom2agent[m].vdagent == type)
> - break;
> - }
> -
> - g_return_val_if_fail(m < SPICE_N_ELEMENTS(atom2agent), FALSE);
> -
> - atom = gdk_atom_intern_static_string(atom2agent[m].xatom);
> - gtk_clipboard_request_contents(get_clipboard_from_selection(d, selection), atom,
> - clipboard_received_cb, display);
> -
> - return TRUE;
> -}
> -
> -static void clipboard_release(SpiceMainChannel *main, guint selection, gpointer data)
> -{
> - SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(data);
> - GtkClipboard* clipboard = get_clipboard_from_selection(d, selection);
> - if (!clipboard)
> - return;
> -
> - d->nclip_targets[selection] = 0;
> -
> - if (!d->clipboard_by_guest[selection])
> - return;
> - gtk_clipboard_clear(clipboard);
> - d->clipboard_by_guest[selection] = FALSE;
> -}
> -
> static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
> {
> SpiceDisplay *display = data;
> @@ -1864,14 +1461,6 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
> g_signal_connect(channel, "main-mouse-update",
> G_CALLBACK(mouse_update), display);
> mouse_update(channel, display);
> - if (id != d->channel_id)
> - return;
> - g_signal_connect(channel, "main-clipboard-selection-grab",
> - G_CALLBACK(clipboard_grab), display);
> - g_signal_connect(channel, "main-clipboard-selection-request",
> - G_CALLBACK(clipboard_request), display);
> - g_signal_connect(channel, "main-clipboard-selection-release",
> - G_CALLBACK(clipboard_release), display);
> return;
> }
>
> @@ -2008,6 +1597,7 @@ SpiceDisplay *spice_display_new(SpiceSession *session, int id)
> display = g_object_new(SPICE_TYPE_DISPLAY, NULL);
> d = SPICE_DISPLAY_GET_PRIVATE(display);
> d->session = g_object_ref(session);
> + d->gtk_session = spice_gtk_session_get(d->session);
> d->channel_id = id;
>
> g_signal_connect(session, "channel-new",
> @@ -2043,32 +1633,25 @@ void spice_display_mouse_ungrab(SpiceDisplay *display)
> void spice_display_copy_to_guest(SpiceDisplay *display)
> {
> SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
>
> - if (d->clip_hasdata[selection] && !d->clip_grabbed[selection]) {
> - gtk_clipboard_request_targets(d->clipboard, clipboard_get_targets, display);
> - }
> + g_return_if_fail(d->gtk_session != NULL);
> +
> + spice_gtk_session_copy_to_guest(d->gtk_session);
> }
>
> +/**
> + * spice_display_paste_from_guest:
> + * @display:
> + *
> + * Copy guest clipboard to client-side clipboard.
> + **/
> void spice_display_paste_from_guest(SpiceDisplay *display)
> {
> SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
> - int selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
>
> - if (d->nclip_targets[selection] == 0) {
> - g_warning("Guest clipboard is not available.");
> - return;
> - }
> + g_return_if_fail(d->gtk_session != NULL);
>
> - if (!gtk_clipboard_set_with_data(d->clipboard,
> - d->clip_targets[selection], d->nclip_targets[selection],
> - clipboard_get, clipboard_clear, display)) {
> - g_warning("Clipboard grab failed");
> - return;
> - }
> - d->clipboard_selfgrab_pending[selection] = TRUE;
> - d->clipboard_by_guest[selection] = TRUE;
> - d->clip_hasdata[selection] = FALSE;
> + spice_gtk_session_paste_from_guest(d->gtk_session);
> }
>
> /**
> --
> 1.7.6.4
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
>
ack
--
Marc-André Lureau
More information about the Spice-devel
mailing list