summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2011-02-18 19:42:04 +0100
committerMarc-André Lureau <marcandre.lureau@redhat.com>2011-03-01 18:49:38 +0100
commit7198a37b4dcf66411df176a7c7a340262745a921 (patch)
tree8634efbbe9307a079ee5cbd2e65edeb46033bc77
parentcc9213aad878f0c40af040af0514cf38c6009bd2 (diff)
gtk: add multiple selection clipboard sharing
-rw-r--r--gtk/Makefile.am4
-rw-r--r--gtk/channel-main.c358
-rw-r--r--gtk/channel-main.h5
-rw-r--r--gtk/map-file4
-rw-r--r--gtk/spice-client-gtk.defs42
-rw-r--r--gtk/spice-marshal.txt3
-rw-r--r--gtk/spice-widget-priv.h1
-rw-r--r--gtk/spice-widget.c74
8 files changed, 449 insertions, 42 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index bf90621..7ce8a65 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -68,7 +68,7 @@ AM_CPPFLAGS = \
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
SPICE_GTK_LDFLAGS_COMMON = \
- -version-number 1:0:0 \
+ -version-number 1:1:0 \
-no-undefined \
$(VERSION_LDFLAGS) \
$(NULL)
@@ -120,7 +120,7 @@ libspice_client_gtkinclude_HEADERS = \
$(NULL)
libspice_client_glib_2_0_la_LDFLAGS = \
- -version-number 2:0:1 \
+ -version-number 3:0:2 \
-no-undefined \
$(VERSION_LDFLAGS) \
$(NULL)
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 6121f20..ff784b9 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -106,6 +106,10 @@ enum {
SPICE_MAIN_CLIPBOARD_GRAB,
SPICE_MAIN_CLIPBOARD_REQUEST,
SPICE_MAIN_CLIPBOARD_RELEASE,
+ SPICE_MAIN_CLIPBOARD_SELECTION,
+ SPICE_MAIN_CLIPBOARD_SELECTION_GRAB,
+ SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST,
+ SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE,
SPICE_MIGRATION_STARTED,
SPICE_MAIN_LAST_SIGNAL,
};
@@ -379,7 +383,7 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
/* TODO use notify instead */
/**
- * SpiceMainChannel::main-clipboard:
+ * SpiceMainChannel::main-agent-update:
* @main: the #SpiceMainChannel that emitted the signal
*
* Notify when the %SpiceMainChannel:agent-connected or
@@ -402,6 +406,8 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
* @size: size of @data in bytes
*
* Provides guest clipboard data requested by spice_main_clipboard_request().
+ *
+ * Deprecated: 0.6: use SpiceMainChannel::main-clipboard-selection instead.
**/
signals[SPICE_MAIN_CLIPBOARD] =
g_signal_new("main-clipboard",
@@ -415,6 +421,23 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT);
/**
+ * SpiceMainChannel::main-clipboard-selection:
+ * @main: the #SpiceMainChannel that emitted the signal
+ *
+ * Since: 0.6
+ **/
+ signals[SPICE_MAIN_CLIPBOARD_SELECTION] =
+ g_signal_new("main-clipboard-selection",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__UINT_UINT_POINTER_UINT,
+ G_TYPE_NONE,
+ 4,
+ G_TYPE_UINT, G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT);
+
+ /**
* SpiceMainChannel::main-clipboard-grab:
* @main: the #SpiceMainChannel that emitted the signal
* @types: the VD_AGENT_CLIPBOARD data types
@@ -422,6 +445,8 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
*
* Inform when clipboard data is available from the guest, and for
* which @types.
+ *
+ * Deprecated: 0.6: use SpiceMainChannel::main-clipboard-selection-grab instead.
**/
signals[SPICE_MAIN_CLIPBOARD_GRAB] =
g_signal_new("main-clipboard-grab",
@@ -435,6 +460,28 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
G_TYPE_POINTER, G_TYPE_UINT);
/**
+ * SpiceMainChannel::main-clipboard-selection-grab:
+ * @main: the #SpiceMainChannel that emitted the signal
+ * @types: the VD_AGENT_CLIPBOARD data types
+ * @ntypes: the number of @types
+ *
+ * Inform when clipboard data is available from the guest, and for
+ * which @types.
+ *
+ * Since: 0.6
+ **/
+ signals[SPICE_MAIN_CLIPBOARD_SELECTION_GRAB] =
+ g_signal_new("main-clipboard-selection-grab",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_user_marshal_BOOLEAN__UINT_POINTER_UINT,
+ G_TYPE_BOOLEAN,
+ 3,
+ G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_UINT);
+
+ /**
* SpiceMainChannel::main-clipboard-request:
* @main: the #SpiceMainChannel that emitted the signal
* @types: the VD_AGENT_CLIPBOARD request type
@@ -442,6 +489,7 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
*
* Request clipbard data from the client.
*
+ * Deprecated: 0.6: use SpiceMainChannel::main-clipboard-selection-request instead.
**/
signals[SPICE_MAIN_CLIPBOARD_REQUEST] =
g_signal_new("main-clipboard-request",
@@ -455,12 +503,34 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
G_TYPE_UINT);
/**
+ * SpiceMainChannel::main-clipboard-selection-request:
+ * @main: the #SpiceMainChannel that emitted the signal
+ * @types: the VD_AGENT_CLIPBOARD request type
+ * Returns: %TRUE if the request is successful
+ *
+ * Request clipbard data from the client.
+ *
+ * Since: 0.6
+ **/
+ signals[SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST] =
+ g_signal_new("main-clipboard-selection-request",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_user_marshal_BOOLEAN__UINT_UINT,
+ G_TYPE_BOOLEAN,
+ 2,
+ G_TYPE_UINT, G_TYPE_UINT);
+
+ /**
* SpiceMainChannel::main-clipboard-release:
* @main: the #SpiceMainChannel that emitted the signal
*
* Inform when the clipboard is released from the guest, when no
* clipboard data is available from the guest.
*
+ * Deprecated: 0.6: use SpiceMainChannel::main-clipboard-selection-release instead.
**/
signals[SPICE_MAIN_CLIPBOARD_RELEASE] =
g_signal_new("main-clipboard-release",
@@ -473,6 +543,26 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
0);
/**
+ * SpiceMainChannel::main-clipboard-selection-release:
+ * @main: the #SpiceMainChannel that emitted the signal
+ *
+ * Inform when the clipboard is released from the guest, when no
+ * clipboard data is available from the guest.
+ *
+ * Since: 0.6
+ **/
+ signals[SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE] =
+ g_signal_new("main-clipboard-selection-release",
+ G_OBJECT_CLASS_TYPE(gobject_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_UINT);
+
+ /**
* SpiceMainChannel::migration-started:
* @main: the #SpiceMainChannel that emitted the signal
* @session: a migration #SpiceSession
@@ -526,6 +616,30 @@ struct SPICE_MAIN_CLIPBOARD_REQUEST {
gboolean *ret;
};
+struct SPICE_MAIN_CLIPBOARD_SELECTION {
+ guint8 selection;
+ guint type;
+ gpointer data;
+ gsize size;
+};
+
+struct SPICE_MAIN_CLIPBOARD_SELECTION_GRAB {
+ guint8 selection;
+ gpointer types;
+ gsize ntypes;
+ gboolean *ret;
+};
+
+struct SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST {
+ guint8 selection;
+ guint type;
+ gboolean *ret;
+};
+
+struct SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE {
+ guint8 selection;
+};
+
/* main context */
static void do_emit_main_context(GObject *object, int signum, gpointer params)
{
@@ -554,6 +668,30 @@ static void do_emit_main_context(GObject *object, int signum, gpointer params)
p->type, p->ret);
break;
}
+ case SPICE_MAIN_CLIPBOARD_SELECTION: {
+ struct SPICE_MAIN_CLIPBOARD_SELECTION *p = params;
+ g_signal_emit(object, signals[signum], 0,
+ p->selection, p->type, p->data, p->size);
+ break;
+ }
+ case SPICE_MAIN_CLIPBOARD_SELECTION_GRAB: {
+ struct SPICE_MAIN_CLIPBOARD_SELECTION_GRAB *p = params;
+ g_signal_emit(object, signals[signum], 0,
+ p->selection, p->types, p->ntypes, p->ret);
+ break;
+ }
+ case SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST: {
+ struct SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST *p = params;
+ g_signal_emit(object, signals[signum], 0,
+ p->selection, p->type, p->ret);
+ break;
+ }
+ case SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE: {
+ struct SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE *p = params;
+ g_signal_emit(object, signals[signum], 0,
+ p->selection);
+ break;
+ }
default:
g_warn_if_reached();
}
@@ -706,16 +844,22 @@ static void agent_announce_caps(SpiceMainChannel *channel)
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_REPLY);
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_DISPLAY_CONFIG);
VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
+ VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION);
agent_msg_queue(channel, VD_AGENT_ANNOUNCE_CAPABILITIES, size, caps);
free(caps);
}
+#define HAS_CLIPBOARD_SELECTION(c) \
+ VD_AGENT_HAS_CAPABILITY((c)->agent_caps, sizeof((c)->agent_caps), VD_AGENT_CAP_CLIPBOARD_SELECTION)
+
/* any context: the message is not flushed immediately,
you can wakeup() the channel coroutine or send_msg_queue() */
-static void agent_clipboard_grab(SpiceMainChannel *channel, guint32 *types, int ntypes)
+static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
+ guint32 *types, int ntypes)
{
spice_main_channel *c = channel->priv;
+ guint8 *msg;
VDAgentClipboardGrab *grab;
size_t size;
int i;
@@ -727,22 +871,38 @@ static void agent_clipboard_grab(SpiceMainChannel *channel, guint32 *types, int
sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
size = sizeof(VDAgentClipboardGrab) + sizeof(uint32_t) * ntypes;
- grab = spice_malloc0(size);
+ if (HAS_CLIPBOARD_SELECTION(c))
+ size += 4;
+ else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+ SPICE_DEBUG("Ignoring clipboard grab");
+ return;
+ }
+
+ msg = g_alloca(size);
+ memset(msg, 0, size);
+
+ grab = (VDAgentClipboardGrab *)msg;
+
+ if (HAS_CLIPBOARD_SELECTION(c)) {
+ msg[0] = selection;
+ grab = (VDAgentClipboardGrab *)(msg + 4);
+ }
+
for (i = 0; i < ntypes; i++) {
grab->types[i] = types[i];
}
- agent_msg_queue(channel, VD_AGENT_CLIPBOARD_GRAB, size, grab);
- free(grab);
+ agent_msg_queue(channel, VD_AGENT_CLIPBOARD_GRAB, size, msg);
}
/* any context: the message is not flushed immediately,
you can wakeup() the channel coroutine or send_msg_queue() */
-static void agent_clipboard_notify(SpiceMainChannel *channel,
+static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
guint32 type, const guchar *data, size_t size)
{
spice_main_channel *c = channel->priv;
VDAgentClipboard *cb;
+ guint8 *msg;
size_t msgsize;
g_return_if_fail(c->agent_connected);
@@ -751,43 +911,88 @@ static void agent_clipboard_notify(SpiceMainChannel *channel,
sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
msgsize = sizeof(VDAgentClipboard) + size;
- cb = spice_malloc0(msgsize);
+ if (HAS_CLIPBOARD_SELECTION(c))
+ msgsize += 4;
+ else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+ SPICE_DEBUG("Ignoring clipboard notify");
+ return;
+ }
+
+ msg = g_alloca(msgsize);
+ memset(msg, 0, msgsize);
+
+ cb = (VDAgentClipboard *)msg;
+
+ if (HAS_CLIPBOARD_SELECTION(c)) {
+ msg[0] = selection;
+ cb = (VDAgentClipboard *)(msg + 4);
+ }
+
cb->type = type;
memcpy(cb->data, data, size);
- agent_msg_queue(channel, VD_AGENT_CLIPBOARD, msgsize, cb);
- free(cb);
+ agent_msg_queue(channel, VD_AGENT_CLIPBOARD, msgsize, msg);
}
/* any context: the message is not flushed immediately,
you can wakeup() the channel coroutine or send_msg_queue() */
-static void agent_clipboard_request(SpiceMainChannel *channel, guint32 type)
+static void agent_clipboard_request(SpiceMainChannel *channel, guint selection, guint32 type)
{
spice_main_channel *c = channel->priv;
- VDAgentClipboardRequest request = { 0, };
+ VDAgentClipboardRequest *request;
+ guint8 *msg;
+ size_t msgsize;
g_return_if_fail(c->agent_connected);
g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
- request.type = type;
+ msgsize = sizeof(VDAgentClipboardRequest);
+ if (HAS_CLIPBOARD_SELECTION(c))
+ msgsize += 4;
+ else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+ SPICE_DEBUG("Ignoring clipboard request");
+ return;
+ }
+
+ msg = g_alloca(msgsize);
+ memset(msg, 0, msgsize);
+
+ request = (VDAgentClipboardRequest *)msg;
+
+ if (HAS_CLIPBOARD_SELECTION(c)) {
+ msg[0] = selection;
+ request = (VDAgentClipboardRequest *)(msg + 4);
+ }
+
+ request->type = type;
- agent_msg_queue(channel, VD_AGENT_CLIPBOARD_REQUEST, sizeof(VDAgentClipboardRequest), &request);
+ agent_msg_queue(channel, VD_AGENT_CLIPBOARD_REQUEST, msgsize, msg);
}
/* any context: the message is not flushed immediately,
you can wakeup() the channel coroutine or send_msg_queue() */
-static void agent_clipboard_release(SpiceMainChannel *channel)
+static void agent_clipboard_release(SpiceMainChannel *channel, guint selection)
{
spice_main_channel *c = channel->priv;
+ guint8 msg[4] = { 0, };
+ guint8 msgsize = 0;
g_return_if_fail(c->agent_connected);
g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
- agent_msg_queue(channel, VD_AGENT_CLIPBOARD_REQUEST, 0, NULL);
+ if (HAS_CLIPBOARD_SELECTION(c)) {
+ msg[0] = selection;
+ msgsize += 4;
+ } else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+ SPICE_DEBUG("Ignoring clipboard release");
+ return;
+ }
+
+ agent_msg_queue(channel, VD_AGENT_CLIPBOARD_RELEASE, msgsize, msg);
}
/* coroutine context */
@@ -952,6 +1157,22 @@ static void main_agent_handle_msg(SpiceChannel *channel,
VDAgentMessage *msg, gpointer payload)
{
spice_main_channel *c = SPICE_MAIN_CHANNEL(channel)->priv;
+ guint8 selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
+
+ switch (msg->type) {
+ case VD_AGENT_CLIPBOARD_RELEASE:
+ case VD_AGENT_CLIPBOARD_REQUEST:
+ case VD_AGENT_CLIPBOARD_GRAB:
+ case VD_AGENT_CLIPBOARD:
+ if (VD_AGENT_HAS_CAPABILITY(c->agent_caps, sizeof(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
+ selection = *((guint8*)payload);
+ payload = ((guint8*)payload) + 4;
+ msg->size -= 4;
+ }
+ break;
+ default:
+ break;
+ }
switch (msg->type) {
case VD_AGENT_ANNOUNCE_CAPABILITIES:
@@ -987,28 +1208,42 @@ static void main_agent_handle_msg(SpiceChannel *channel,
case VD_AGENT_CLIPBOARD:
{
VDAgentClipboard *cb = payload;
- emit_main_context(channel, SPICE_MAIN_CLIPBOARD,
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION, selection,
cb->type, cb->data, msg->size - sizeof(VDAgentClipboard));
+
+ if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD,
+ cb->type, cb->data, msg->size - sizeof(VDAgentClipboard));
break;
}
case VD_AGENT_CLIPBOARD_GRAB:
{
gboolean ret;
- emit_main_context(channel, SPICE_MAIN_CLIPBOARD_GRAB,
- payload, msg->size / sizeof(uint32_t), &ret);
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION_GRAB, selection,
+ (guint8*)payload, msg->size / sizeof(uint32_t), &ret);
+ if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_GRAB,
+ payload, msg->size / sizeof(uint32_t), &ret);
break;
}
case VD_AGENT_CLIPBOARD_REQUEST:
{
gboolean ret;
VDAgentClipboardRequest *req = payload;
- emit_main_context(channel, SPICE_MAIN_CLIPBOARD_REQUEST,
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST, selection,
req->type, &ret);
+
+ if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_REQUEST,
+ req->type, &ret);
break;
}
case VD_AGENT_CLIPBOARD_RELEASE:
{
- emit_main_context(channel, SPICE_MAIN_CLIPBOARD_RELEASE);
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE, selection);
+
+ if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
+ emit_main_context(channel, SPICE_MAIN_CLIPBOARD_RELEASE);
break;
}
case VD_AGENT_REPLY:
@@ -1414,13 +1649,32 @@ void spice_main_set_display(SpiceMainChannel *channel, int id,
* @ntypes: the number of @types
*
* Grab the guest clipboard, with #VD_AGENT_CLIPBOARD @types.
+ *
+ * Deprecated: 0.6: use spice_main_clipboard_selection_grab() instead.
**/
void spice_main_clipboard_grab(SpiceMainChannel *channel, guint32 *types, int ntypes)
{
+ spice_main_clipboard_selection_grab(channel, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD, types, ntypes);
+}
+
+/**
+ * spice_main_clipboard_selection_grab:
+ * @channel:
+ * @selection: one of the clipboard #VD_AGENT_CLIPBOARD_SELECTION_*
+ * @types: an array of #VD_AGENT_CLIPBOARD types available in the clipboard
+ * @ntypes: the number of @types
+ *
+ * Grab the guest clipboard, with #VD_AGENT_CLIPBOARD @types.
+ *
+ * Since: 0.6
+ **/
+void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint selection,
+ guint32 *types, int ntypes)
+{
g_return_if_fail(channel != NULL);
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
- agent_clipboard_grab(channel, types, ntypes);
+ agent_clipboard_grab(channel, selection, types, ntypes);
spice_channel_wakeup(SPICE_CHANNEL(channel));
}
@@ -1430,9 +1684,26 @@ void spice_main_clipboard_grab(SpiceMainChannel *channel, guint32 *types, int nt
*
* Release the clipboard (for example, when the client looses the
* clipboard grab): Inform the guest no clipboard data is available.
+ *
+ * Deprecated: 0.6: use spice_main_clipboard_selection_release() instead.
**/
void spice_main_clipboard_release(SpiceMainChannel *channel)
{
+ spice_main_clipboard_selection_release(channel, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD);
+}
+
+/**
+ * spice_main_clipboard_selection_release:
+ * @channel:
+ * @selection: one of the clipboard #VD_AGENT_CLIPBOARD_SELECTION_*
+ *
+ * Release the clipboard (for example, when the client looses the
+ * clipboard grab): Inform the guest no clipboard data is available.
+ *
+ * Since: 0.6
+ **/
+void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint selection)
+{
g_return_if_fail(channel != NULL);
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
@@ -1441,7 +1712,7 @@ void spice_main_clipboard_release(SpiceMainChannel *channel)
if (!c->agent_connected)
return;
- agent_clipboard_release(channel);
+ agent_clipboard_release(channel, selection);
spice_channel_wakeup(SPICE_CHANNEL(channel));
}
@@ -1453,14 +1724,35 @@ void spice_main_clipboard_release(SpiceMainChannel *channel)
* @size: data length in bytes
*
* Send the clipboard data to the guest.
+ *
+ * Deprecated: 0.6: use spice_main_clipboard_selection_notify() instead.
**/
void spice_main_clipboard_notify(SpiceMainChannel *channel,
guint32 type, const guchar *data, size_t size)
{
+ spice_main_clipboard_selection_notify(channel, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD,
+ type, data, size);
+}
+
+/**
+ * spice_main_clipboard_selection_notify:
+ * @channel:
+ * @selection: one of the clipboard #VD_AGENT_CLIPBOARD_SELECTION_*
+ * @type: a #VD_AGENT_CLIPBOARD type
+ * @data: clipboard data
+ * @size: data length in bytes
+ *
+ * Send the clipboard data to the guest.
+ *
+ * Since: 0.6
+ **/
+void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint selection,
+ guint32 type, const guchar *data, size_t size)
+{
g_return_if_fail(channel != NULL);
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
- agent_clipboard_notify(channel, type, data, size);
+ agent_clipboard_notify(channel, selection, type, data, size);
spice_channel_wakeup(SPICE_CHANNEL(channel));
}
@@ -1471,12 +1763,30 @@ void spice_main_clipboard_notify(SpiceMainChannel *channel,
*
* Request clipboard data of @type from the guest. The reply is sent
* through the #SpiceMainChannel::main-clipboard signal.
+ *
+ * Deprecated: 0.6: use spice_main_clipboard_selection_request() instead.
**/
void spice_main_clipboard_request(SpiceMainChannel *channel, guint32 type)
{
+ spice_main_clipboard_selection_request(channel, VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD, type);
+}
+
+/**
+ * spice_main_clipboard_selection_request:
+ * @channel:
+ * @selection: one of the clipboard #VD_AGENT_CLIPBOARD_SELECTION_*
+ * @type: a #VD_AGENT_CLIPBOARD type
+ *
+ * Request clipboard data of @type from the guest. The reply is sent
+ * through the #SpiceMainChannel::main-clipboard signal.
+ *
+ * Since: 0.6
+ **/
+void spice_main_clipboard_selection_request(SpiceMainChannel *channel, guint selection, guint32 type)
+{
g_return_if_fail(channel != NULL);
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
- agent_clipboard_request(channel, type);
+ agent_clipboard_request(channel, selection, type);
spice_channel_wakeup(SPICE_CHANNEL(channel));
}
diff --git a/gtk/channel-main.h b/gtk/channel-main.h
index 9a4f884..645de5d 100644
--- a/gtk/channel-main.h
+++ b/gtk/channel-main.h
@@ -60,6 +60,11 @@ void spice_main_clipboard_release(SpiceMainChannel *channel);
void spice_main_clipboard_notify(SpiceMainChannel *channel, guint32 type, const guchar *data, size_t size);
void spice_main_clipboard_request(SpiceMainChannel *channel, guint32 type);
+void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint selection, guint32 *types, int ntypes);
+void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint selection);
+void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint selection, guint32 type, const guchar *data, size_t size);
+void spice_main_clipboard_selection_request(SpiceMainChannel *channel, guint selection, guint32 type);
+
G_END_DECLS
#endif /* __SPICE_CLIENT_MAIN_CHANNEL_H__ */
diff --git a/gtk/map-file b/gtk/map-file
index a17ab16..0f52a53 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -44,6 +44,10 @@ spice_main_clipboard_grab;
spice_main_clipboard_notify;
spice_main_clipboard_release;
spice_main_clipboard_request;
+spice_main_clipboard_selection_grab;
+spice_main_clipboard_selection_notify;
+spice_main_clipboard_selection_release;
+spice_main_clipboard_selection_request;
spice_main_set_display;
spice_playback_channel_get_type;
spice_playback_channel_set_delay;
diff --git a/gtk/spice-client-gtk.defs b/gtk/spice-client-gtk.defs
index 7930318..fddb641 100644
--- a/gtk/spice-client-gtk.defs
+++ b/gtk/spice-client-gtk.defs
@@ -481,6 +481,48 @@
)
)
+(define-function spice_main_clipboard_selection_grab
+ (c-name "spice_main_clipboard_selection_grab")
+ (return-type "none")
+ (parameters
+ '("SpiceMainChannel*" "channel")
+ '("guint" "selection")
+ '("guint32*" "types")
+ '("int" "ntypes")
+ )
+)
+
+(define-function spice_main_clipboard_selection_release
+ (c-name "spice_main_clipboard_selection_release")
+ (return-type "none")
+ (parameters
+ '("SpiceMainChannel*" "channel")
+ '("guint" "selection")
+ )
+)
+
+(define-function spice_main_clipboard_selection_notify
+ (c-name "spice_main_clipboard_selection_notify")
+ (return-type "none")
+ (parameters
+ '("SpiceMainChannel*" "channel")
+ '("guint" "selection")
+ '("guint32" "type")
+ '("const-guchar*" "data")
+ '("size_t" "size")
+ )
+)
+
+(define-function spice_main_clipboard_selection_request
+ (c-name "spice_main_clipboard_selection_request")
+ (return-type "none")
+ (parameters
+ '("SpiceMainChannel*" "channel")
+ '("guint" "selection")
+ '("guint32" "type")
+ )
+)
+
;; From channel-display.h
diff --git a/gtk/spice-marshal.txt b/gtk/spice-marshal.txt
index 9884804..b99a5f5 100644
--- a/gtk/spice-marshal.txt
+++ b/gtk/spice-marshal.txt
@@ -7,3 +7,6 @@ VOID:POINTER,INT
BOOLEAN:POINTER,UINT
BOOLEAN:UINT
VOID:UINT,POINTER,UINT
+VOID:UINT,UINT,POINTER,UINT
+BOOLEAN:UINT,POINTER,UINT
+BOOLEAN:UINT,UINT
diff --git a/gtk/spice-widget-priv.h b/gtk/spice-widget-priv.h
index e90603a..325e897 100644
--- a/gtk/spice-widget-priv.h
+++ b/gtk/spice-widget-priv.h
@@ -73,6 +73,7 @@ struct spice_display {
#endif
GtkClipboard *clipboard;
+ GtkClipboard *clipboard_primary;
GtkTargetEntry *clip_targets;
guint nclip_targets;
bool clip_hasdata;
diff --git a/gtk/spice-widget.c b/gtk/spice-widget.c
index 72cbd9c..98920b9 100644
--- a/gtk/spice-widget.c
+++ b/gtk/spice-widget.c
@@ -254,6 +254,9 @@ static void spice_display_init(SpiceDisplay *display)
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);
@@ -976,6 +979,30 @@ static gboolean configure_event(GtkWidget *widget, GdkEventConfigure *conf)
/* ---------------------------------------------------------------- */
+static GtkClipboard* get_clipboard_from_selection(spice_display *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(spice_display *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;
@@ -1031,6 +1058,8 @@ static void clipboard_get_targets(GtkClipboard *clipboard,
char *name;
int a, m, t;
+ g_return_if_fail(get_selection_from_clipboard(d, clipboard) != -1);
+
SPICE_DEBUG("%s:", __FUNCTION__);
if (spice_util_get_debug()) {
for (a = 0; a < n_atoms; a++) {
@@ -1070,7 +1099,8 @@ static void clipboard_get_targets(GtkClipboard *clipboard,
}
if (!d->clip_grabbed && t > 0) {
d->clip_grabbed = true;
- spice_main_clipboard_grab(d->main, types, t);
+ spice_main_clipboard_selection_grab(d->main,
+ get_selection_from_clipboard(d, clipboard), types, t);
}
}
@@ -1081,12 +1111,15 @@ static void clipboard_owner_change(GtkClipboard *clipboard,
SpiceDisplay *display = data;
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
+ g_return_if_fail(get_selection_from_clipboard(d, clipboard) != -1);
+
if (d->main == NULL)
return;
if (d->clip_grabbed) {
d->clip_grabbed = false;
- spice_main_clipboard_release(d->main);
+ spice_main_clipboard_selection_release(d->main,
+ get_selection_from_clipboard(d, clipboard));
}
switch (event->reason) {
@@ -1435,7 +1468,6 @@ static void disconnect_cursor(SpiceDisplay *display)
d->cursor = NULL;
}
-
typedef struct
{
GMainLoop *loop;
@@ -1443,14 +1475,17 @@ typedef struct
GtkSelectionData *selection_data;
guint info;
gulong timeout_handler;
+ guint selection;
} RunInfo;
-static void clipboard_got_from_guest(SpiceMainChannel *main,
+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,
@@ -1483,16 +1518,18 @@ static void clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_d
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",
+ 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_request(d->main, atom2agent[info].vdagent);
+ spice_main_clipboard_selection_request(d->main, ri.selection, atom2agent[info].vdagent);
/* apparently, this is needed to avoid dead-lock, from
gtk_dialog_run */
@@ -1513,7 +1550,7 @@ static void clipboard_clear(GtkClipboard *clipboard, gpointer display)
// clipboard release ?
}
-static gboolean clipboard_grab(SpiceMainChannel *main,
+static gboolean clipboard_grab(SpiceMainChannel *main, guint selection,
guint32* types, guint32 ntypes, gpointer display)
{
int m, n, i;
@@ -1521,6 +1558,10 @@ static gboolean clipboard_grab(SpiceMainChannel *main,
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) {
@@ -1548,7 +1589,7 @@ static gboolean clipboard_grab(SpiceMainChannel *main,
if (!d->auto_clipboard_enable)
goto skip_grab_clipboard;
- if (!gtk_clipboard_set_with_data(d->clipboard, targets, i,
+ if (!gtk_clipboard_set_with_data(cb, targets, i,
clipboard_get, clipboard_clear, display)) {
g_warning("clipboard grab failed");
return FALSE;
@@ -1569,6 +1610,7 @@ static void clipboard_received_cb(GtkClipboard *clipboard,
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) {
@@ -1594,12 +1636,12 @@ static void clipboard_received_cb(GtkClipboard *clipboard,
g_free(name);
}
- spice_main_clipboard_notify(d->main,
+ 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,
- guint32 type, gpointer display)
+static gboolean clipboard_request(SpiceMainChannel *main, guint selection,
+ guint type, gpointer display)
{
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(display);
int m;
@@ -1613,13 +1655,13 @@ static gboolean clipboard_request(SpiceMainChannel *main,
g_return_val_if_fail(m < SPICE_N_ELEMENTS(atom2agent), FALSE);
atom = gdk_atom_intern_static_string(atom2agent[m].xatom);
- gtk_clipboard_request_contents(d->clipboard, atom,
+ gtk_clipboard_request_contents(get_clipboard_from_selection(d, selection), atom,
clipboard_received_cb, display);
return TRUE;
}
-static void clipboard_release(SpiceMainChannel *main, gpointer data)
+static void clipboard_release(SpiceMainChannel *main, guint selection, gpointer data)
{
spice_display *d = SPICE_DISPLAY_GET_PRIVATE(data);
@@ -1637,11 +1679,11 @@ static void channel_new(SpiceSession *s, SpiceChannel *channel, gpointer data)
d->main = SPICE_MAIN_CHANNEL(channel);
g_signal_connect(channel, "main-mouse-update",
G_CALLBACK(mouse_update), display);
- g_signal_connect(channel, "main-clipboard-grab",
+ g_signal_connect(channel, "main-clipboard-selection-grab",
G_CALLBACK(clipboard_grab), display);
- g_signal_connect(channel, "main-clipboard-request",
+ g_signal_connect(channel, "main-clipboard-selection-request",
G_CALLBACK(clipboard_request), display);
- g_signal_connect(channel, "main-clipboard-release",
+ g_signal_connect(channel, "main-clipboard-selection-release",
G_CALLBACK(clipboard_release), display);
mouse_update(channel, display);
return;