[Spice-commits] 5 commits - gtk/channel-main.c gtk/spice-gtk-session.c spice-common

Marc-André Lureau elmarco at kemper.freedesktop.org
Wed Nov 20 01:55:22 PST 2013


 gtk/channel-main.c      |  187 ++++++++++++++++++++++++++++++++++--------------
 gtk/spice-gtk-session.c |    9 +-
 spice-common            |    2 
 3 files changed, 142 insertions(+), 56 deletions(-)

New commits:
commit 296c8e31101b6e7a4515a7cf6a17b05ad25f7c6c
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 6 21:56:37 2013 +0100

    main: send max-clipboard to agent
    
    Send configured max-clipboard size to the agent, after receiving agent
    capabilities.
    
    See also spice-protocol patch description:
    http://lists.freedesktop.org/archives/spice-devel/2013-November/015254.html

diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 08138d6..ef2a5e5 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -170,6 +170,7 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel);
 static void file_xfer_continue_read(SpiceFileXferTask *task);
 static void file_xfer_completed(SpiceFileXferTask *task, GError *error);
 static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success);
+static void spice_main_set_max_clipboard(SpiceMainChannel *self, gint max);
 
 /* ------------------------------------------------------------------ */
 
@@ -196,6 +197,7 @@ static const char *agent_caps[] = {
     [ VD_AGENT_CAP_SPARSE_MONITORS_CONFIG ] = "sparse monitors",
     [ VD_AGENT_CAP_GUEST_LINEEND_LF    ] = "line-end lf",
     [ VD_AGENT_CAP_GUEST_LINEEND_CRLF  ] = "line-end crlf",
+    [ VD_AGENT_CAP_MAX_CLIPBOARD       ] = "max-clipboard",
 };
 #define NAME(_a, _i) ((_i) < SPICE_N_ELEMENTS(_a) ? (_a[(_i)] ?: "?") : "?")
 
@@ -288,7 +290,8 @@ static void spice_main_get_property(GObject    *object,
 static void spice_main_set_property(GObject *gobject, guint prop_id,
                                     const GValue *value, GParamSpec *pspec)
 {
-    SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(gobject)->priv;
+    SpiceMainChannel *self = SPICE_MAIN_CHANNEL(gobject);
+    SpiceMainChannelPrivate *c = self->priv;
 
     switch (prop_id) {
     case PROP_DISPLAY_DISABLE_WALLPAPER:
@@ -313,7 +316,7 @@ static void spice_main_set_property(GObject *gobject, guint prop_id,
         c->disable_display_align = g_value_get_boolean(value);
         break;
     case PROP_MAX_CLIPBOARD:
-        c->max_clipboard = g_value_get_int(value);
+        spice_main_set_max_clipboard(self, g_value_get_int(value));
         break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
@@ -1816,6 +1819,34 @@ static void file_xfer_handle_status(SpiceMainChannel *channel,
     file_xfer_completed(task, error);
 }
 
+/* any context: the message is not flushed immediately,
+   you can wakeup() the channel coroutine or send_msg_queue() */
+static void agent_max_clipboard(SpiceMainChannel *self)
+{
+    VDAgentMaxClipboard msg = { .max = spice_main_get_max_clipboard(self) };
+
+    if (!test_agent_cap(self, VD_AGENT_CAP_MAX_CLIPBOARD))
+        return;
+
+    agent_msg_queue(self, VD_AGENT_MAX_CLIPBOARD, sizeof(VDAgentMaxClipboard), &msg);
+}
+
+static void spice_main_set_max_clipboard(SpiceMainChannel *self, gint max)
+{
+    SpiceMainChannelPrivate *c;
+
+    g_return_if_fail(SPICE_IS_MAIN_CHANNEL(self));
+    g_return_if_fail(max >= -1);
+
+    c = self->priv;
+    if (max == spice_main_get_max_clipboard(self))
+        return;
+
+    c->max_clipboard = max;
+    agent_max_clipboard(self);
+    spice_channel_wakeup(SPICE_CHANNEL(self), FALSE);
+}
+
 /* coroutine context */
 static void main_agent_handle_msg(SpiceChannel *channel,
                                   VDAgentMessage *msg, gpointer payload)
@@ -1867,9 +1898,13 @@ static void main_agent_handle_msg(SpiceChannel *channel,
         if (test_agent_cap(self, VD_AGENT_CAP_DISPLAY_CONFIG) &&
             !c->agent_display_config_sent) {
             agent_display_config(self);
-            agent_send_msg_queue(self);
             c->agent_display_config_sent = true;
         }
+
+        agent_max_clipboard(self);
+
+        agent_send_msg_queue(self);
+
         break;
     }
     case VD_AGENT_CLIPBOARD:
diff --git a/spice-common b/spice-common
index 1450bb4..261d270 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit 1450bb4ddbd8ceab9192e4f84606aa5ae54c5ea6
+Subproject commit 261d270cc8e9af0915d5248df240828214ec996e
commit cf470e608e7f612d489563d52caff13aa3c68ee4
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 6 21:51:55 2013 +0100

    main: simplify usage of VD_AGENT_HAS_CAPABILITY
    
    Introduce a helper function test_agent_cap() to clear the code a
    little bit.

diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index ef60739..08138d6 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -201,6 +201,16 @@ static const char *agent_caps[] = {
 
 /* ------------------------------------------------------------------ */
 
+static gboolean test_agent_cap(SpiceMainChannel *channel, guint32 cap)
+{
+    SpiceMainChannelPrivate *c = channel->priv;
+
+    if (!c->agent_caps_received)
+        return FALSE;
+
+    return VD_AGENT_HAS_CAPABILITY(c->agent_caps, G_N_ELEMENTS(c->agent_caps), cap);
+}
+
 static void spice_main_channel_reset_capabilties(SpiceChannel *channel)
 {
     spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
@@ -1236,9 +1246,6 @@ static void agent_announce_caps(SpiceMainChannel *channel)
     free(caps);
 }
 
-#define HAS_CLIPBOARD_SELECTION(c) \
-    VD_AGENT_HAS_CAPABILITY((c)->agent_caps, G_N_ELEMENTS((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, guint selection,
@@ -1253,13 +1260,12 @@ static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
     if (!c->agent_connected)
         return;
 
-    g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
-        G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
+    g_return_if_fail(test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
 
     size = sizeof(VDAgentClipboardGrab) + sizeof(uint32_t) * ntypes;
-    if (HAS_CLIPBOARD_SELECTION(c))
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         size += 4;
-    else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+    } else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
         CHANNEL_DEBUG(channel, "Ignoring clipboard grab");
         return;
     }
@@ -1269,7 +1275,7 @@ static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
 
     grab = (VDAgentClipboardGrab *)msg;
 
-    if (HAS_CLIPBOARD_SELECTION(c)) {
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msg[0] = selection;
         grab = (VDAgentClipboardGrab *)(msg + 4);
     }
@@ -1290,17 +1296,16 @@ static void agent_clipboard_notify(SpiceMainChannel *self, guint selection,
     VDAgentClipboard *cb;
     guint8 *msg;
     size_t msgsize;
-    gint max_clipboard = spice_main_get_max_clipboard(channel);
+    gint max_clipboard = spice_main_get_max_clipboard(self);
 
     g_return_if_fail(c->agent_connected);
-    g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
-        G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
+    g_return_if_fail(test_agent_cap(self, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
     g_return_if_fail(max_clipboard == -1 || size < max_clipboard);
 
     msgsize = sizeof(VDAgentClipboard);
-    if (HAS_CLIPBOARD_SELECTION(c))
+    if (test_agent_cap(self, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msgsize += 4;
-    else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+    } else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
         CHANNEL_DEBUG(self, "Ignoring clipboard notify");
         return;
     }
@@ -1310,7 +1315,7 @@ static void agent_clipboard_notify(SpiceMainChannel *self, guint selection,
 
     cb = (VDAgentClipboard *)msg;
 
-    if (HAS_CLIPBOARD_SELECTION(c)) {
+    if (test_agent_cap(self, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msg[0] = selection;
         cb = (VDAgentClipboard *)(msg + 4);
     }
@@ -1329,14 +1334,12 @@ static void agent_clipboard_request(SpiceMainChannel *channel, guint selection,
     size_t msgsize;
 
     g_return_if_fail(c->agent_connected);
-
-    g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
-        G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
+    g_return_if_fail(test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
 
     msgsize = sizeof(VDAgentClipboardRequest);
-    if (HAS_CLIPBOARD_SELECTION(c))
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msgsize += 4;
-    else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
+    } else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
         SPICE_DEBUG("Ignoring clipboard request");
         return;
     }
@@ -1346,7 +1349,7 @@ static void agent_clipboard_request(SpiceMainChannel *channel, guint selection,
 
     request = (VDAgentClipboardRequest *)msg;
 
-    if (HAS_CLIPBOARD_SELECTION(c)) {
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msg[0] = selection;
         request = (VDAgentClipboardRequest *)(msg + 4);
     }
@@ -1365,11 +1368,9 @@ static void agent_clipboard_release(SpiceMainChannel *channel, guint selection)
     guint8 msgsize = 0;
 
     g_return_if_fail(c->agent_connected);
+    g_return_if_fail(test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
 
-    g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
-        G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
-
-    if (HAS_CLIPBOARD_SELECTION(c)) {
+    if (test_agent_cap(channel, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
         msg[0] = selection;
         msgsize += 4;
     } else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
@@ -1830,7 +1831,7 @@ static void main_agent_handle_msg(SpiceChannel *channel,
     case VD_AGENT_CLIPBOARD_REQUEST:
     case VD_AGENT_CLIPBOARD_GRAB:
     case VD_AGENT_CLIPBOARD:
-        if (VD_AGENT_HAS_CAPABILITY(c->agent_caps, G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
+        if (test_agent_cap(self, VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
             selection = *((guint8*)payload);
             payload = ((guint8*)payload) + 4;
             msg->size -= 4;
@@ -1863,7 +1864,7 @@ static void main_agent_handle_msg(SpiceChannel *channel,
         if (caps->request)
             agent_announce_caps(self);
 
-        if (VD_AGENT_HAS_CAPABILITY(caps->caps, G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_DISPLAY_CONFIG) &&
+        if (test_agent_cap(self, VD_AGENT_CAP_DISPLAY_CONFIG) &&
             !c->agent_display_config_sent) {
             agent_display_config(self);
             agent_send_msg_queue(self);
@@ -2443,12 +2444,7 @@ gboolean spice_main_agent_test_capability(SpiceMainChannel *channel, guint32 cap
 {
     g_return_val_if_fail(SPICE_IS_MAIN_CHANNEL(channel), FALSE);
 
-    SpiceMainChannelPrivate *c = channel->priv;
-
-    if (!c->agent_caps_received)
-        return FALSE;
-
-    return VD_AGENT_HAS_CAPABILITY(c->agent_caps, G_N_ELEMENTS(c->agent_caps), cap);
+    return test_agent_cap(channel, cap);
 }
 
 /**
commit fa29f4e1793f09d6456afc03e5820bd6b5024da5
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 6 21:50:14 2013 +0100

    main: use self for main channel variable
    
    This simplifies the following commit which uses even more
    SPICE_MAIN_CHANNEL macro, and makes the code unnecessarily heavy.

diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 2c02ece..ef60739 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -1283,10 +1283,10 @@ static void agent_clipboard_grab(SpiceMainChannel *channel, guint selection,
 
 /* 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, guint selection,
+static void agent_clipboard_notify(SpiceMainChannel *self, guint selection,
                                    guint32 type, const guchar *data, size_t size)
 {
-    SpiceMainChannelPrivate *c = channel->priv;
+    SpiceMainChannelPrivate *c = self->priv;
     VDAgentClipboard *cb;
     guint8 *msg;
     size_t msgsize;
@@ -1301,7 +1301,7 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
     if (HAS_CLIPBOARD_SELECTION(c))
         msgsize += 4;
     else if (selection != VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD) {
-        CHANNEL_DEBUG(channel, "Ignoring clipboard notify");
+        CHANNEL_DEBUG(self, "Ignoring clipboard notify");
         return;
     }
 
@@ -1316,7 +1316,7 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
     }
 
     cb->type = type;
-    agent_msg_queue_many(channel, VD_AGENT_CLIPBOARD, msg, msgsize, data, size, NULL);
+    agent_msg_queue_many(self, VD_AGENT_CLIPBOARD, msg, msgsize, data, size, NULL);
 }
 
 /* any context: the message is not flushed immediately,
@@ -1819,7 +1819,8 @@ static void file_xfer_handle_status(SpiceMainChannel *channel,
 static void main_agent_handle_msg(SpiceChannel *channel,
                                   VDAgentMessage *msg, gpointer payload)
 {
-    SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(channel)->priv;
+    SpiceMainChannel *self = SPICE_MAIN_CHANNEL(channel);
+    SpiceMainChannelPrivate *c = self->priv;
     guint8 selection = VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD;
 
     g_return_if_fail(msg->protocol == VD_AGENT_PROTOCOL);
@@ -1857,15 +1858,15 @@ static void main_agent_handle_msg(SpiceChannel *channel,
             VD_AGENT_SET_CAPABILITY(c->agent_caps, i);
         }
         c->agent_caps_received = true;
-        emit_main_context(channel, SPICE_MAIN_AGENT_UPDATE);
+        emit_main_context(self, SPICE_MAIN_AGENT_UPDATE);
 
         if (caps->request)
-            agent_announce_caps(SPICE_MAIN_CHANNEL(channel));
+            agent_announce_caps(self);
 
         if (VD_AGENT_HAS_CAPABILITY(caps->caps, G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_DISPLAY_CONFIG) &&
             !c->agent_display_config_sent) {
-            agent_display_config(SPICE_MAIN_CHANNEL(channel));
-            agent_send_msg_queue(SPICE_MAIN_CHANNEL(channel));
+            agent_display_config(self);
+            agent_send_msg_queue(self);
             c->agent_display_config_sent = true;
         }
         break;
@@ -1873,21 +1874,21 @@ static void main_agent_handle_msg(SpiceChannel *channel,
     case VD_AGENT_CLIPBOARD:
     {
         VDAgentClipboard *cb = payload;
-        emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION, selection,
+        emit_main_context(self, 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,
+            emit_main_context(self, 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_SELECTION_GRAB, selection,
+        emit_main_context(self, 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,
+            emit_main_context(self, SPICE_MAIN_CLIPBOARD_GRAB,
                               payload, msg->size / sizeof(uint32_t), &ret);
         break;
     }
@@ -1895,20 +1896,20 @@ static void main_agent_handle_msg(SpiceChannel *channel,
     {
         gboolean ret;
         VDAgentClipboardRequest *req = payload;
-        emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST, selection,
+        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION_REQUEST, selection,
                           req->type, &ret);
 
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
-            emit_main_context(channel, SPICE_MAIN_CLIPBOARD_REQUEST,
+            emit_main_context(self, SPICE_MAIN_CLIPBOARD_REQUEST,
                               req->type, &ret);
         break;
     }
     case VD_AGENT_CLIPBOARD_RELEASE:
     {
-        emit_main_context(channel, SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE, selection);
+        emit_main_context(self, SPICE_MAIN_CLIPBOARD_SELECTION_RELEASE, selection);
 
         if (selection == VD_AGENT_CLIPBOARD_SELECTION_CLIPBOARD)
-            emit_main_context(channel, SPICE_MAIN_CLIPBOARD_RELEASE);
+            emit_main_context(self, SPICE_MAIN_CLIPBOARD_RELEASE);
         break;
     }
     case VD_AGENT_REPLY:
@@ -1919,7 +1920,7 @@ static void main_agent_handle_msg(SpiceChannel *channel,
         break;
     }
     case VD_AGENT_FILE_XFER_STATUS:
-        file_xfer_handle_status(SPICE_MAIN_CHANNEL(channel), payload);
+        file_xfer_handle_status(self, payload);
         break;
     default:
         g_warning("unhandled agent message type: %u (%s), size %u",
commit 9f96915b4289237981f18740eda90ecf36a65bd6
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 6 20:37:23 2013 +0100

    Add SPICE_MAX_CLIPBOARD environment variable
    
    Allow to easily override default max-clipboard value with environment
    variable.

diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index d4b4416..2c02ece 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -220,12 +220,23 @@ static void spice_main_channel_init(SpiceMainChannel *channel)
     spice_main_channel_reset_capabilties(SPICE_CHANNEL(channel));
 }
 
+static gint spice_main_get_max_clipboard(SpiceMainChannel *self)
+{
+    g_return_val_if_fail(SPICE_IS_MAIN_CHANNEL(self), 0);
+
+    if (g_getenv("SPICE_MAX_CLIPBOARD"))
+        return atoi(g_getenv("SPICE_MAX_CLIPBOARD"));
+
+    return self->priv->max_clipboard;
+}
+
 static void spice_main_get_property(GObject    *object,
                                     guint       prop_id,
                                     GValue     *value,
                                     GParamSpec *pspec)
 {
-    SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(object)->priv;
+    SpiceMainChannel *self = SPICE_MAIN_CHANNEL(object);
+    SpiceMainChannelPrivate *c = self->priv;
 
     switch (prop_id) {
     case PROP_MOUSE_MODE:
@@ -256,7 +267,7 @@ static void spice_main_get_property(GObject    *object,
         g_value_set_boolean(value, c->disable_display_align);
         break;
     case PROP_MAX_CLIPBOARD:
-        g_value_set_int(value, c->max_clipboard);
+        g_value_set_int(value, spice_main_get_max_clipboard(self));
         break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
@@ -394,6 +405,18 @@ static void spice_main_channel_reset(SpiceChannel *channel, gboolean migrating)
     SPICE_CHANNEL_CLASS(spice_main_channel_parent_class)->channel_reset(channel, migrating);
 }
 
+static void spice_main_constructed(GObject *object)
+{
+    SpiceMainChannel *self = SPICE_MAIN_CHANNEL(object);
+    SpiceMainChannelPrivate *c = self->priv;
+
+    /* update default value */
+    c->max_clipboard = spice_main_get_max_clipboard(self);
+
+    if (G_OBJECT_CLASS(spice_main_channel_parent_class)->constructed)
+        G_OBJECT_CLASS(spice_main_channel_parent_class)->constructed(object);
+}
+
 static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
@@ -403,6 +426,7 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
     gobject_class->finalize     = spice_main_channel_finalize;
     gobject_class->get_property = spice_main_get_property;
     gobject_class->set_property = spice_main_set_property;
+    gobject_class->constructed  = spice_main_constructed;
 
     channel_class->handle_msg    = spice_main_handle_msg;
     channel_class->iterate_write = spice_channel_iterate_write;
@@ -1266,13 +1290,12 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
     VDAgentClipboard *cb;
     guint8 *msg;
     size_t msgsize;
+    gint max_clipboard = spice_main_get_max_clipboard(channel);
 
     g_return_if_fail(c->agent_connected);
-
     g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
         G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
-
-    g_return_if_fail(c->max_clipboard == -1 || size < c->max_clipboard);
+    g_return_if_fail(max_clipboard == -1 || size < max_clipboard);
 
     msgsize = sizeof(VDAgentClipboard);
     if (HAS_CLIPBOARD_SELECTION(c))
commit bc2139629a57b6ff4567c4194e24f58191361a2a
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Nov 6 20:14:50 2013 +0100

    Block sending clipboard data > max-clipboard
    
    Attempt to send very large clipboard data may easy cause OOM
    abort, either in  gdk - some patch are proposed to improve the situation,
    or in spice-gtk itself.
    
    Let's have a property that blocks unreasonably big clipboard data from
    being processed (by default 100mb). Users willing to send larger data
    can use the send basic drag-drop send file instead, or tweak the
    property value.

diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 24f7428..d4b4416 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -106,6 +106,7 @@ struct _SpiceMainChannelPrivate  {
     guint                       switch_host_delayed_id;
     guint                       migrate_delayed_id;
     spice_migrate               *migrate_data;
+    int                         max_clipboard;
 };
 
 struct spice_migrate {
@@ -137,6 +138,7 @@ enum {
     PROP_DISPLAY_COLOR_DEPTH,
     PROP_DISABLE_DISPLAY_POSITION,
     PROP_DISABLE_DISPLAY_ALIGN,
+    PROP_MAX_CLIPBOARD,
 };
 
 /* Signals */
@@ -253,6 +255,9 @@ static void spice_main_get_property(GObject    *object,
     case PROP_DISABLE_DISPLAY_ALIGN:
         g_value_set_boolean(value, c->disable_display_align);
         break;
+    case PROP_MAX_CLIPBOARD:
+        g_value_set_int(value, c->max_clipboard);
+        break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
 	break;
@@ -286,6 +291,9 @@ static void spice_main_set_property(GObject *gobject, guint prop_id,
     case PROP_DISABLE_DISPLAY_ALIGN:
         c->disable_display_align = g_value_get_boolean(value);
         break;
+    case PROP_MAX_CLIPBOARD:
+        c->max_clipboard = g_value_get_int(value);
+        break;
     default:
 	G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
 	break;
@@ -512,6 +520,24 @@ static void spice_main_channel_class_init(SpiceMainChannelClass *klass)
                               G_PARAM_CONSTRUCT |
                               G_PARAM_STATIC_STRINGS));
 
+    /**
+     * SpiceMainChannel:max-clipboard:
+     *
+     * Maximum size of clipboard operations in bytes (default 100MB,
+     * -1 for unlimited size);
+     *
+     * Since: 0.22
+     **/
+    g_object_class_install_property
+        (gobject_class, PROP_MAX_CLIPBOARD,
+         g_param_spec_int("max-clipboard",
+                          "max clipboard",
+                          "Maximum clipboard data size",
+                          -1, G_MAXINT, 100 * 1024 * 1024,
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT |
+                          G_PARAM_STATIC_STRINGS));
+
     /* TODO use notify instead */
     /**
      * SpiceMainChannel::main-mouse-update:
@@ -1246,6 +1272,8 @@ static void agent_clipboard_notify(SpiceMainChannel *channel, guint selection,
     g_return_if_fail(VD_AGENT_HAS_CAPABILITY(c->agent_caps,
         G_N_ELEMENTS(c->agent_caps), VD_AGENT_CAP_CLIPBOARD_BY_DEMAND));
 
+    g_return_if_fail(c->max_clipboard == -1 || size < c->max_clipboard);
+
     msgsize = sizeof(VDAgentClipboard);
     if (HAS_CLIPBOARD_SELECTION(c))
         msgsize += 4;
diff --git a/gtk/spice-gtk-session.c b/gtk/spice-gtk-session.c
index 71ed300..eab7e2f 100644
--- a/gtk/spice-gtk-session.c
+++ b/gtk/spice-gtk-session.c
@@ -748,16 +748,19 @@ static void clipboard_received_cb(GtkClipboard *clipboard,
     gchar* name;
     GdkAtom atom;
     int selection;
+    int max_clipboard;
 
     selection = get_selection_from_clipboard(s, clipboard);
     g_return_if_fail(selection != -1);
 
+    g_object_get(s->main, "max-clipboard", &max_clipboard, NULL);
     len = gtk_selection_data_get_length(selection_data);
-    if (len == -1) {
+    if (len == 0 || (max_clipboard != -1 && len > max_clipboard)) {
+        g_warning("discarded clipboard of size %d (max: %d)", len, max_clipboard);
+        return;
+    } else 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);


More information about the Spice-commits mailing list