static void clipboard_got_from_guest(SpiceMainChannel *main, guint selection, guint type, const guchar *data, guint size, gpointer user_data) { RunInfo *ri = user_data; SpiceGtkSessionPrivate *s = ri->self->priv; gchar *conv = NULL; g_return_if_fail(selection == ri->selection); SPICE_DEBUG("clipboard got data"); if (atom2agent[ri->info].vdagent == VD_AGENT_CLIPBOARD_UTF8_TEXT) { /* on windows, gtk+ would already convert to LF endings, but not on unix */ if (spice_main_agent_test_capability(s->main, VD_AGENT_CAP_GUEST_LINEEND_CRLF)) { GError *err = NULL; conv = spice_dos2unix((gchar*)data, size, &err); if (err) { g_warning("Failed to convert text line ending: %s", err->message); g_clear_error(&err); goto end; } size = strlen(conv); } gtk_selection_data_set_text(ri->selection_data, conv ?: (gchar*)data, size); } else {
static void clipboard_owner_change(GtkClipboard *clipboard, GdkEventOwnerChange *event, gpointer user_data) { g_return_if_fail(SPICE_IS_GTK_SESSION(user_data)); SpiceGtkSession *self = user_data; SpiceGtkSessionPrivate *s = self->priv; 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; if (spice_main_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) spice_main_clipboard_selection_release(s->main, selection); } switch (event->reason) { case GDK_OWNER_CHANGE_NEW_OWNER: if (gtk_clipboard_get_owner(clipboard) == G_OBJECT(self)) break; s->clipboard_by_guest[selection] = FALSE; s->clip_hasdata[selection] = TRUE; if (s->auto_clipboard_enable && !read_only(self)) gtk_clipboard_request_targets(clipboard, clipboard_get_targets, weak_ref(G_OBJECT(self))); break; default: s->clip_hasdata[selection] = FALSE; break; } }
static void clipboard_get_targets(GtkClipboard *clipboard, GdkAtom *atoms, gint n_atoms, gpointer user_data) { WeakRef *weakref = user_data; SpiceGtkSession *self = (SpiceGtkSession*)weakref->object; weak_unref(weakref); if (self == NULL) return; g_return_if_fail(SPICE_IS_GTK_SESSION(self)); SpiceGtkSessionPrivate *s = self->priv; guint32 types[SPICE_N_ELEMENTS(atom2agent)]; char *name; int a, m, t; int selection; if (s->main == NULL) return; selection = get_selection_from_clipboard(s, 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 (!s->clip_grabbed[selection] && t > 0) { s->clip_grabbed[selection] = TRUE; if (spice_main_agent_test_capability(s->main, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND)) 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; } }
gboolean clipboard_requestFromGuest(SpiceMainChannel *main, guint selection, guint type, gpointer user_data) { SPICE_DEBUG("CB: clipboard_requestFromGuest()"); if (!enableClipboardToGuest) { SPICE_DEBUG("CB: enableClipboardToGuest set to false. Doing nothing."); return TRUE; } SpiceDisplay *display; SpiceDisplayPrivate *d; if (clipboardOwner != CB_OWNER_HOST) { SPICE_DEBUG("We do NOT have clipboard grabbed, so we won't send it."); return FALSE; } display = global_display(); if (global_display() == NULL) { return FALSE; } d = SPICE_DISPLAY_GET_PRIVATE(display); if (d->main == NULL) { return FALSE; } //TODO check values as spice-gtk-session. gchar *data = (gchar *) hostClipboard; SPICE_DEBUG("CB: hostClipboard 0x%x\n", hostClipboard); if (hostClipboard != NULL) { SPICE_DEBUG("CB: hostClipboard contains %s\n", hostClipboard); } if (data == NULL ) { SPICE_DEBUG("CB: No supported Clipboard format available\n"); return FALSE; } /* Transform format (line ending, etc) before sending */ gint len = 0; gpointer conv = NULL; /* Our clipboard is not GTK but windows. So we positively have CRLF as line break. But it is our (client program) responsability to give the guest the format it wants. */ if (spice_main_agent_test_capability(d->main, VD_AGENT_CAP_GUEST_LINEEND_CRLF)) { SPICE_DEBUG("CB: Host to Guest, changing line ending\n"); len = strnlen(data, CB_SIZE); conv = spice_unix2dos((gchar*)data, len); SPICE_DEBUG("CB: Host to Guest, changing line ending: OK\n"); len = strnlen(conv, CB_SIZE); } else { len = strnlen((const char *)data, CB_SIZE); } spice_main_clipboard_selection_notify(d->main, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD, VD_AGENT_CLIPBOARD_UTF8_TEXT, conv ? conv : data, len); onError: g_free(conv); return FALSE; }