[Spice-commits] 7 commits - server/char-device.c server/char-device.h server/cursor-channel.c server/dcc.c server/dcc.h server/dcc-send.c server/display-channel.c server/display-channel.h server/red-channel-client.c server/red-channel-client.h server/red-channel-client-private.h server/red-pipe-item.c server/red-pipe-item.h server/reds.c server/red-worker.c server/stream.c

Jonathon Jongsma jjongsma at kemper.freedesktop.org
Mon Sep 19 12:49:07 UTC 2016


 server/char-device.c                |  144 +++++-------
 server/char-device.h                |    1 
 server/cursor-channel.c             |    2 
 server/dcc-send.c                   |   59 ++---
 server/dcc.c                        |   91 +++----
 server/dcc.h                        |    3 
 server/display-channel.c            |  411 +++++++++++++++++++++---------------
 server/display-channel.h            |   57 ++--
 server/red-channel-client-private.h |    3 
 server/red-channel-client.c         |   97 +++++---
 server/red-channel-client.h         |    6 
 server/red-pipe-item.c              |    1 
 server/red-pipe-item.h              |    6 
 server/red-worker.c                 |   60 +----
 server/reds.c                       |   14 -
 server/stream.c                     |   80 +++----
 16 files changed, 528 insertions(+), 507 deletions(-)

New commits:
commit 21c6da814adea145d6fe7dd40d596bc15eea3ead
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Mon Oct 5 14:22:31 2015 -0500

    Change RedCharDevicePrivate::clients to GList
    
    More Ring cleanup. At the moment, we only support a single client, so
    this is only a one-element list

diff --git a/server/char-device.c b/server/char-device.c
index a03867f..4f01d3c 100644
--- a/server/char-device.c
+++ b/server/char-device.c
@@ -32,7 +32,6 @@
 
 typedef struct RedCharDeviceClient RedCharDeviceClient;
 struct RedCharDeviceClient {
-    RingItem link;
     RedCharDevice *dev;
     RedClient *client;
     int do_flow_control;
@@ -58,8 +57,7 @@ struct RedCharDevicePrivate {
     SpiceTimer *write_to_dev_timer;
     uint64_t num_self_tokens;
 
-    Ring clients; /* list of RedCharDeviceClient */
-    uint32_t num_clients;
+    GList *clients; /* list of RedCharDeviceClient */
 
     uint64_t client_tokens_interval; /* frequency of returning tokens to the client */
     SpiceCharDeviceInstance *sin;
@@ -207,8 +205,7 @@ static void red_char_device_client_free(RedCharDevice *dev,
         dev->priv->cur_write_buf->client = NULL;
     }
 
-    dev->priv->num_clients--;
-    ring_remove(&dev_client->link);
+    dev->priv->clients = g_list_remove(dev->priv->clients, dev_client);
     free(dev_client);
 }
 
@@ -222,12 +219,11 @@ static void red_char_device_handle_client_overflow(RedCharDeviceClient *dev_clie
 static RedCharDeviceClient *red_char_device_client_find(RedCharDevice *dev,
                                                         RedClient *client)
 {
-    RingItem *item;
+    GList *item;
 
-    RING_FOREACH(item, &dev->priv->clients) {
-        RedCharDeviceClient *dev_client;
+    for (item = dev->priv->clients; item != NULL; item = item->next) {
+        RedCharDeviceClient *dev_client = item->data;
 
-        dev_client = SPICE_CONTAINEROF(item, RedCharDeviceClient, link);
         if (dev_client->client == client) {
             return dev_client;
         }
@@ -253,13 +249,11 @@ static int red_char_device_can_send_to_client(RedCharDeviceClient *dev_client)
 
 static uint64_t red_char_device_max_send_tokens(RedCharDevice *dev)
 {
-    RingItem *item;
+    GList *item;
     uint64_t max = 0;
 
-    RING_FOREACH(item, &dev->priv->clients) {
-        RedCharDeviceClient *dev_client;
-
-        dev_client = SPICE_CONTAINEROF(item, RedCharDeviceClient, link);
+    for (item = dev->priv->clients; item != NULL; item = item->next) {
+        RedCharDeviceClient *dev_client = item->data;
 
         if (!dev_client->do_flow_control) {
             max = ~0;
@@ -295,12 +289,13 @@ static void red_char_device_add_msg_to_client_queue(RedCharDeviceClient *dev_cli
 static void red_char_device_send_msg_to_clients(RedCharDevice *dev,
                                                 RedPipeItem *msg)
 {
-    RingItem *item, *next;
+    GList *l;
 
-    RING_FOREACH_SAFE(item, next, &dev->priv->clients) {
-        RedCharDeviceClient *dev_client;
+    l = dev->priv->clients;
+    while (l) {
+        GList *next = l->next;
+        RedCharDeviceClient *dev_client = l->data;
 
-        dev_client = SPICE_CONTAINEROF(item, RedCharDeviceClient, link);
         if (red_char_device_can_send_to_client(dev_client)) {
             dev_client->num_send_tokens--;
             spice_assert(g_queue_is_empty(dev_client->send_queue));
@@ -310,6 +305,7 @@ static void red_char_device_send_msg_to_clients(RedCharDevice *dev,
         } else {
             red_char_device_add_msg_to_client_queue(dev_client, msg);
         }
+        l = next;
     }
 }
 
@@ -338,7 +334,7 @@ static int red_char_device_read_from_device(RedCharDevice *dev)
      * Reading from the device only in case at least one of the clients have a free token.
      * All messages will be discarded if no client is attached to the device
      */
-    while ((max_send_tokens || ring_is_empty(&dev->priv->clients)) && dev->priv->running) {
+    while ((max_send_tokens || (dev->priv->clients == NULL)) && dev->priv->running) {
         RedPipeItem *msg;
 
         msg = red_char_device_read_one_msg_from_device(dev);
@@ -743,7 +739,7 @@ int red_char_device_client_add(RedCharDevice *dev,
     spice_assert(dev);
     spice_assert(client);
 
-    if (wait_for_migrate_data && (dev->priv->num_clients > 0 || dev->priv->active)) {
+    if (wait_for_migrate_data && (dev->priv->clients != NULL || dev->priv->active)) {
         spice_warning("can't restore device %p from migration data. The device "
                       "has already been active", dev);
         return FALSE;
@@ -757,8 +753,7 @@ int red_char_device_client_add(RedCharDevice *dev,
                                             num_client_tokens,
                                             num_send_tokens);
     dev_client->dev = dev;
-    ring_add(&dev->priv->clients, &dev_client->link);
-    dev->priv->num_clients++;
+    dev->priv->clients = g_list_prepend(dev->priv->clients, dev_client);
     /* Now that we have a client, forward any pending device data */
     red_char_device_wakeup(dev);
     return TRUE;
@@ -778,12 +773,12 @@ void red_char_device_client_remove(RedCharDevice *dev,
     }
     red_char_device_client_free(dev, dev_client);
     if (dev->priv->wait_for_migrate_data) {
-        spice_assert(dev->priv->num_clients == 0);
+        spice_assert(dev->priv->clients == NULL);
         dev->priv->wait_for_migrate_data  = FALSE;
         red_char_device_read_from_device(dev);
     }
 
-    if (dev->priv->num_clients == 0) {
+    if (dev->priv->clients == NULL) {
         spice_debug("client removed, memory pool will be freed (%"PRIu64" bytes)", dev->priv->cur_pool_size);
         write_buffers_queue_free(&dev->priv->write_bufs_pool);
         dev->priv->cur_pool_size = 0;
@@ -818,7 +813,7 @@ void red_char_device_stop(RedCharDevice *dev)
 
 void red_char_device_reset(RedCharDevice *dev)
 {
-    RingItem *client_item;
+    GList *client_item;
     RedCharDeviceWriteBuffer *buf;
 
     red_char_device_stop(dev);
@@ -829,10 +824,9 @@ void red_char_device_reset(RedCharDevice *dev)
     }
     red_char_device_write_buffer_release(dev, &dev->priv->cur_write_buf);
 
-    RING_FOREACH(client_item, &dev->priv->clients) {
-        RedCharDeviceClient *dev_client;
+    for (client_item = dev->priv->clients; client_item != NULL; client_item = client_item->next) {
+        RedCharDeviceClient *dev_client = client_item->data;
 
-        dev_client = SPICE_CONTAINEROF(client_item, RedCharDeviceClient, link);
         spice_debug("send_queue_empty %d", g_queue_is_empty(dev_client->send_queue));
         dev_client->num_send_tokens += g_queue_get_length(dev_client->send_queue);
         g_queue_foreach(dev_client->send_queue, (GFunc)red_pipe_item_unref, NULL);
@@ -886,10 +880,8 @@ void red_char_device_migrate_data_marshall(RedCharDevice *dev,
     SpiceMarshaller *m2;
 
     /* multi-clients are not supported */
-    spice_assert(dev->priv->num_clients == 1);
-    dev_client = SPICE_CONTAINEROF(ring_get_tail(&dev->priv->clients),
-                                   RedCharDeviceClient,
-                                   link);
+    spice_assert(g_list_length(dev->priv->clients) == 1);
+    dev_client = g_list_last(dev->priv->clients)->data;
     /* FIXME: if there were more than one client before the marshalling,
      * it is possible that the send_queue length > 0, and the send data
      * should be migrated as well */
@@ -941,11 +933,10 @@ int red_char_device_restore(RedCharDevice *dev,
     RedCharDeviceClient *dev_client;
     uint32_t client_tokens_window;
 
-    spice_assert(dev->priv->num_clients == 1 && dev->priv->wait_for_migrate_data);
+    spice_assert(g_list_length(dev->priv->clients) == 1 &&
+                 dev->priv->wait_for_migrate_data);
 
-    dev_client = SPICE_CONTAINEROF(ring_get_tail(&dev->priv->clients),
-                                     RedCharDeviceClient,
-                                     link);
+    dev_client = g_list_last(dev->priv->clients)->data;
     if (mig_data->version > SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION) {
         spice_error("dev %p error: migration data version %u is bigger than self %u",
                     dev, mig_data->version, SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION);
@@ -1110,11 +1101,8 @@ red_char_device_finalize(GObject *object)
     red_char_device_write_buffer_free(self->priv->cur_write_buf);
     self->priv->cur_write_buf = NULL;
 
-    while (!ring_is_empty(&self->priv->clients)) {
-        RingItem *item = ring_get_tail(&self->priv->clients);
-        RedCharDeviceClient *dev_client;
-
-        dev_client = SPICE_CONTAINEROF(item, RedCharDeviceClient, link);
+    while (self->priv->clients != NULL) {
+        RedCharDeviceClient *dev_client = self->priv->clients->data;
         red_char_device_client_free(self, dev_client);
     }
     self->priv->running = FALSE;
@@ -1182,7 +1170,6 @@ red_char_device_init(RedCharDevice *self)
 
     g_queue_init(&self->priv->write_queue);
     g_queue_init(&self->priv->write_bufs_pool);
-    ring_init(&self->priv->clients);
 
     g_signal_connect(self, "notify::sin", G_CALLBACK(red_char_device_on_sin_changed), NULL);
 }
commit 8340688c9de22db7f15c50720f7a0148d23b9877
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Fri Oct 2 15:12:22 2015 -0500

    Change RedCharDevice::write_queue to GQueue
    
    Change a couple more Rings to GQueue

diff --git a/server/char-device.c b/server/char-device.c
index 957fb26..a03867f 100644
--- a/server/char-device.c
+++ b/server/char-device.c
@@ -50,8 +50,8 @@ struct RedCharDevicePrivate {
     int active; /* has read/write been performed since the device was started */
     int wait_for_migrate_data;
 
-    Ring write_queue;
-    Ring write_bufs_pool;
+    GQueue write_queue;
+    GQueue write_bufs_pool;
     uint64_t cur_pool_size;
     RedCharDeviceWriteBuffer *cur_write_buf;
     uint8_t *cur_write_buf_pos;
@@ -150,16 +150,11 @@ static void red_char_device_write_buffer_free(RedCharDeviceWriteBuffer *buf)
     free(buf);
 }
 
-static void write_buffers_queue_free(Ring *write_queue)
+static void write_buffers_queue_free(GQueue *write_queue)
 {
-    while (!ring_is_empty(write_queue)) {
-        RingItem *item = ring_get_tail(write_queue);
-        RedCharDeviceWriteBuffer *buf;
-
-        ring_remove(item);
-        buf = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
+    RedCharDeviceWriteBuffer *buf;
+    while ((buf = g_queue_pop_tail(write_queue)))
         red_char_device_write_buffer_free(buf);
-    }
 }
 
 static void red_char_device_write_buffer_pool_add(RedCharDevice *dev,
@@ -171,7 +166,7 @@ static void red_char_device_write_buffer_pool_add(RedCharDevice *dev,
         buf->origin = WRITE_BUFFER_ORIGIN_NONE;
         buf->client = NULL;
         dev->priv->cur_pool_size += buf->buf_size;
-        ring_add(&dev->priv->write_bufs_pool, &buf->link);
+        g_queue_push_head(&dev->priv->write_bufs_pool, buf);
         return;
     }
 
@@ -182,7 +177,7 @@ static void red_char_device_write_buffer_pool_add(RedCharDevice *dev,
 static void red_char_device_client_free(RedCharDevice *dev,
                                         RedCharDeviceClient *dev_client)
 {
-    RingItem *item, *next;
+    GList *l, *next;
 
     if (dev_client->wait_for_tokens_timer) {
         reds_core_timer_remove(dev->priv->reds, dev_client->wait_for_tokens_timer);
@@ -192,16 +187,18 @@ static void red_char_device_client_free(RedCharDevice *dev,
     g_queue_free_full(dev_client->send_queue, (GDestroyNotify)red_pipe_item_unref);
 
     /* remove write buffers that are associated with the client */
-    spice_debug("write_queue_is_empty %d", ring_is_empty(&dev->priv->write_queue) && !dev->priv->cur_write_buf);
-    RING_FOREACH_SAFE(item, next, &dev->priv->write_queue) {
-        RedCharDeviceWriteBuffer *write_buf;
+    spice_debug("write_queue_is_empty %d", g_queue_is_empty(&dev->priv->write_queue) && !dev->priv->cur_write_buf);
+    l = g_queue_peek_head_link(&dev->priv->write_queue);
+    while (l) {
+        RedCharDeviceWriteBuffer *write_buf = l->data;
+        next = l->next;
 
-        write_buf = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
         if (write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT &&
             write_buf->client == dev_client->client) {
-            ring_remove(item);
+            g_queue_delete_link(&dev->priv->write_queue, l);
             red_char_device_write_buffer_pool_add(dev, write_buf);
         }
+        l = next;
     }
 
     if (dev->priv->cur_write_buf && dev->priv->cur_write_buf->origin == WRITE_BUFFER_ORIGIN_CLIENT &&
@@ -483,13 +480,10 @@ static int red_char_device_write_to_device(RedCharDevice *dev)
         uint32_t write_len;
 
         if (!dev->priv->cur_write_buf) {
-            RingItem *item = ring_get_tail(&dev->priv->write_queue);
-            if (!item) {
+            dev->priv->cur_write_buf = g_queue_pop_tail(&dev->priv->write_queue);
+            if (!dev->priv->cur_write_buf)
                 break;
-            }
-            dev->priv->cur_write_buf = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
             dev->priv->cur_write_buf_pos = dev->priv->cur_write_buf->buf;
-            ring_remove(item);
         }
 
         write_len = dev->priv->cur_write_buf->buf + dev->priv->cur_write_buf->buf_used -
@@ -519,7 +513,7 @@ static int red_char_device_write_to_device(RedCharDevice *dev)
                                       CHAR_DEVICE_WRITE_TO_TIMEOUT);
             }
         } else {
-            spice_assert(ring_is_empty(&dev->priv->write_queue));
+            spice_assert(g_queue_is_empty(&dev->priv->write_queue));
         }
         dev->priv->active = dev->priv->active || total;
     }
@@ -542,16 +536,14 @@ static RedCharDeviceWriteBuffer *__red_char_device_write_buffer_get(
     RedCharDevice *dev, RedClient *client,
     int size, int origin, int migrated_data_tokens)
 {
-    RingItem *item;
     RedCharDeviceWriteBuffer *ret;
 
     if (origin == WRITE_BUFFER_ORIGIN_SERVER && !dev->priv->num_self_tokens) {
         return NULL;
     }
 
-    if ((item = ring_get_tail(&dev->priv->write_bufs_pool))) {
-        ret = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
-        ring_remove(item);
+    ret = g_queue_pop_tail(&dev->priv->write_bufs_pool);
+    if (ret) {
         dev->priv->cur_pool_size -= ret->buf_size;
     } else {
         ret = spice_new0(RedCharDeviceWriteBuffer, 1);
@@ -594,7 +586,7 @@ static RedCharDeviceWriteBuffer *__red_char_device_write_buffer_get(
     return ret;
 error:
     dev->priv->cur_pool_size += ret->buf_size;
-    ring_add(&dev->priv->write_bufs_pool, &ret->link);
+    g_queue_push_head(&dev->priv->write_bufs_pool, ret);
     return NULL;
 }
 
@@ -643,7 +635,7 @@ void red_char_device_write_buffer_add(RedCharDevice *dev,
         return;
     }
 
-    ring_add(&dev->priv->write_queue, &write_buf->link);
+    g_queue_push_head(&dev->priv->write_queue, write_buf);
     red_char_device_write_to_device(dev);
 }
 
@@ -660,7 +652,6 @@ void red_char_device_write_buffer_release(RedCharDevice *dev,
     uint32_t buf_token_price = write_buf->token_price;
     RedClient *client = write_buf->client;
 
-    spice_assert(!ring_item_is_linked(&write_buf->link));
     if (!dev) {
         spice_printerr("no device. write buffer is freed");
         red_char_device_write_buffer_free(write_buf);
@@ -828,17 +819,12 @@ void red_char_device_stop(RedCharDevice *dev)
 void red_char_device_reset(RedCharDevice *dev)
 {
     RingItem *client_item;
+    RedCharDeviceWriteBuffer *buf;
 
     red_char_device_stop(dev);
     dev->priv->wait_for_migrate_data = FALSE;
     spice_debug("char device %p", dev);
-    while (!ring_is_empty(&dev->priv->write_queue)) {
-        RingItem *item = ring_get_tail(&dev->priv->write_queue);
-        RedCharDeviceWriteBuffer *buf;
-
-        ring_remove(item);
-        buf = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
-        /* tracking the tokens */
+    while ((buf = g_queue_pop_tail(&dev->priv->write_queue))) {
         red_char_device_write_buffer_release(dev, &buf);
     }
     red_char_device_write_buffer_release(dev, &dev->priv->cur_write_buf);
@@ -894,7 +880,7 @@ void red_char_device_migrate_data_marshall(RedCharDevice *dev,
                                            SpiceMarshaller *m)
 {
     RedCharDeviceClient *dev_client;
-    RingItem *item;
+    GList *item;
     uint32_t *write_to_dev_size_ptr;
     uint32_t *write_to_dev_tokens_ptr;
     SpiceMarshaller *m2;
@@ -932,10 +918,9 @@ void red_char_device_migrate_data_marshall(RedCharDevice *dev,
         }
     }
 
-    RING_FOREACH_REVERSED(item, &dev->priv->write_queue) {
-        RedCharDeviceWriteBuffer *write_buf;
+    for (item = g_queue_peek_tail_link(&dev->priv->write_queue); item != NULL; item = item->prev) {
+        RedCharDeviceWriteBuffer *write_buf = item->data;
 
-        write_buf = SPICE_CONTAINEROF(item, RedCharDeviceWriteBuffer, link);
         spice_marshaller_add_ref_full(m2, write_buf->buf, write_buf->buf_used,
                                       migrate_data_marshaller_write_buffer_free,
                                       red_char_device_write_buffer_ref(write_buf)
@@ -966,7 +951,7 @@ int red_char_device_restore(RedCharDevice *dev,
                     dev, mig_data->version, SPICE_MIGRATE_DATA_CHAR_DEVICE_VERSION);
         return FALSE;
     }
-    spice_assert(!dev->priv->cur_write_buf && ring_is_empty(&dev->priv->write_queue));
+    spice_assert(!dev->priv->cur_write_buf && g_queue_is_empty(&dev->priv->write_queue));
     spice_assert(mig_data->connected);
 
     client_tokens_window = dev_client->num_client_tokens; /* initial state of tokens */
@@ -1195,8 +1180,8 @@ red_char_device_init(RedCharDevice *self)
 {
     self->priv = RED_CHAR_DEVICE_PRIVATE(self);
 
-    ring_init(&self->priv->write_queue);
-    ring_init(&self->priv->write_bufs_pool);
+    g_queue_init(&self->priv->write_queue);
+    g_queue_init(&self->priv->write_bufs_pool);
     ring_init(&self->priv->clients);
 
     g_signal_connect(self, "notify::sin", G_CALLBACK(red_char_device_on_sin_changed), NULL);
diff --git a/server/char-device.h b/server/char-device.h
index 1ada763..44e9504 100644
--- a/server/char-device.h
+++ b/server/char-device.h
@@ -144,7 +144,6 @@ GType red_char_device_get_type(void) G_GNUC_CONST;
 
 /* buffer that is used for writing to the device */
 typedef struct RedCharDeviceWriteBuffer {
-    RingItem link;
     int origin;
     RedClient *client; /* The client that sent the message to the device.
                           NULL if the server created the message */
commit 039d3150ab37857a589d0bffada53a698b992745
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Thu Oct 1 15:34:41 2015 -0500

    Change Drawable->pipes from Ring to GList
    
    This improves the readability of the code and keeps things
    encapsulated better.

diff --git a/server/dcc.c b/server/dcc.c
index 27efdc6..f0a1ef8 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -49,9 +49,10 @@ static RedSurfaceCreateItem *red_surface_create_item_new(RedChannel* channel,
 int dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
 {
     RedDrawablePipeItem *dpi;
-    RingItem *dpi_link, *dpi_next;
+    GList *l;
 
-    DRAWABLE_FOREACH_DPI_SAFE(drawable, dpi_link, dpi_next, dpi) {
+    for (l = drawable->pipes; l != NULL; l = l->next) {
+        dpi = l->data;
         if (dpi->dcc == dcc) {
             return TRUE;
         }
@@ -276,9 +277,7 @@ static void red_drawable_pipe_item_free(RedPipeItem *item)
                                                  dpi_pipe_item);
     spice_assert(item->refcount == 0);
 
-    if (ring_item_is_linked(&dpi->base)) {
-        ring_remove(&dpi->base);
-    }
+    dpi->drawable->pipes = g_list_remove(dpi->drawable->pipes, dpi);
     drawable_unref(dpi->drawable);
     free(dpi);
 }
@@ -291,8 +290,7 @@ static RedDrawablePipeItem *red_drawable_pipe_item_new(DisplayChannelClient *dcc
     dpi = spice_malloc0(sizeof(*dpi));
     dpi->drawable = drawable;
     dpi->dcc = dcc;
-    ring_item_init(&dpi->base);
-    ring_add(&drawable->pipes, &dpi->base);
+    drawable->pipes = g_list_prepend(drawable->pipes, dpi);
     red_pipe_item_init_full(&dpi->dpi_pipe_item, RED_PIPE_ITEM_TYPE_DRAW,
                             red_drawable_pipe_item_free);
     drawable->refs++;
diff --git a/server/dcc.h b/server/dcc.h
index a2478b9..932e051 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -91,7 +91,6 @@ typedef struct RedImageItem {
 } RedImageItem;
 
 typedef struct RedDrawablePipeItem {
-    RingItem base;  /* link for a list of pipe items held by Drawable */
     RedPipeItem dpi_pipe_item; /* link for the client's pipe itself */
     Drawable *drawable;
     DisplayChannelClient *dcc;
diff --git a/server/display-channel.c b/server/display-channel.c
index 6e754b3..cd9c937 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -255,7 +255,7 @@ static void pipes_add_drawable(DisplayChannel *display, Drawable *drawable)
     DisplayChannelClient *dcc;
     GList *link, *next;
 
-    spice_warn_if_fail(ring_is_empty(&drawable->pipes));
+    spice_warn_if_fail(drawable->pipes == NULL);
     FOREACH_CLIENT(display, link, next, dcc) {
         dcc_prepend_drawable(dcc, drawable);
     }
@@ -265,14 +265,17 @@ static void pipes_add_drawable_after(DisplayChannel *display,
                                      Drawable *drawable, Drawable *pos_after)
 {
     RedDrawablePipeItem *dpi_pos_after;
-    RingItem *dpi_link, *dpi_next;
     DisplayChannelClient *dcc;
     int num_other_linked = 0;
+    GList *l;
+
+    for (l = pos_after->pipes; l != NULL; l = l->next) {
+        dpi_pos_after = l->data;
 
-    DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
         num_other_linked++;
         dcc_add_drawable_after(dpi_pos_after->dcc, drawable, &dpi_pos_after->dpi_pipe_item);
     }
+
     if (num_other_linked == 0) {
         pipes_add_drawable(display, drawable);
         return;
@@ -282,12 +285,15 @@ static void pipes_add_drawable_after(DisplayChannel *display,
         spice_debug("TODO: not O(n^2)");
         FOREACH_CLIENT(display, link, next, dcc) {
             int sent = 0;
-            DRAWABLE_FOREACH_DPI_SAFE(pos_after, dpi_link, dpi_next, dpi_pos_after) {
+            GList *l;
+            for (l = pos_after->pipes; l != NULL; l = l->next) {
+                dpi_pos_after = l->data;
                 if (dpi_pos_after->dcc == dcc) {
                     sent = 1;
                     break;
                 }
             }
+
             if (!sent) {
                 dcc_prepend_drawable(dcc, drawable);
             }
@@ -324,14 +330,17 @@ static void current_remove_drawable(DisplayChannel *display, Drawable *item)
 static void drawable_remove_from_pipes(Drawable *drawable)
 {
     RedDrawablePipeItem *dpi;
-    RingItem *item, *next;
+    GList *l;
 
-    RING_FOREACH_SAFE(item, next, &drawable->pipes) {
+    l = drawable->pipes;
+    while (l) {
+        GList *next = l->next;
         RedChannelClient *rcc;
 
-        dpi = SPICE_UPCAST(RedDrawablePipeItem, item);
+        dpi = l->data;
         rcc = RED_CHANNEL_CLIENT(dpi->dcc);
         red_channel_client_pipe_remove_and_release(rcc, &dpi->dpi_pipe_item);
+        l = next;
     }
 }
 
@@ -424,7 +433,7 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
         if (is_same_drawable(drawable, other_drawable)) {
 
             DisplayChannelClient *dcc;
-            RingItem *dpi_ring_item;
+            GList *dpi_item;
             GList *link, *next;
 
             other_drawable->refs++;
@@ -432,11 +441,11 @@ static int current_add_equal(DisplayChannel *display, DrawItem *item, TreeItem *
 
             /* sending the drawable to clients that already received
              * (or will receive) other_drawable */
-            dpi_ring_item = ring_get_head(&other_drawable->pipes);
+            dpi_item = g_list_first(other_drawable->pipes);
             /* dpi contains a sublist of dcc's, ordered the same */
             FOREACH_CLIENT(display, link, next, dcc) {
-                if (dpi_ring_item && dcc == SPICE_UPCAST(RedDrawablePipeItem, dpi_ring_item)->dcc) {
-                    dpi_ring_item = ring_next(&other_drawable->pipes, dpi_ring_item);
+                if (dpi_item && dcc == ((RedDrawablePipeItem *) dpi_item->data)->dcc) {
+                    dpi_item = dpi_item->next;
                 } else {
                     dcc_prepend_drawable(dcc, drawable);
                 }
@@ -1292,7 +1301,6 @@ static Drawable *display_channel_drawable_try_new(DisplayChannel *display,
     ring_item_init(&drawable->tree_item.base.siblings_link);
     drawable->tree_item.base.type = TREE_ITEM_TYPE_DRAWABLE;
     region_init(&drawable->tree_item.base.rgn);
-    ring_init(&drawable->pipes);
     glz_retention_init(&drawable->glz_retention);
     drawable->process_commands_generation = process_commands_generation;
 
@@ -1343,7 +1351,7 @@ void drawable_unref(Drawable *drawable)
         return;
 
     spice_warn_if_fail(!drawable->tree_item.shadow);
-    spice_warn_if_fail(ring_is_empty(&drawable->pipes));
+    spice_warn_if_fail(drawable->pipes == NULL);
 
     if (drawable->stream) {
         detach_stream(display, drawable->stream);
diff --git a/server/display-channel.h b/server/display-channel.h
index 2f7df55..20f299d 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -54,7 +54,7 @@ struct Drawable {
     RingItem surface_list_link;
     RingItem list_link;
     DrawItem tree_item;
-    Ring pipes;
+    GList *pipes;
     RedPipeItem *pipe_item_rest;
     uint32_t size_pipe_item_rest;
     RedDrawable *red_drawable;
@@ -80,10 +80,6 @@ struct Drawable {
 
 void drawable_unref (Drawable *drawable);
 
-#define LINK_TO_DPI(ptr) SPICE_UPCAST(RedDrawablePipeItem, (ptr))
-#define DRAWABLE_FOREACH_DPI_SAFE(drawable, link, next, dpi)            \
-    SAFE_FOREACH(link, next, drawable,  &(drawable)->pipes, dpi, LINK_TO_DPI(link))
-
 enum {
     RED_PIPE_ITEM_TYPE_DRAW = RED_PIPE_ITEM_TYPE_COMMON_LAST,
     RED_PIPE_ITEM_TYPE_IMAGE,
diff --git a/server/stream.c b/server/stream.c
index 746f1cf..49b5910 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -331,11 +331,10 @@ void detach_stream(DisplayChannel *display, Stream *stream)
 static void before_reattach_stream(DisplayChannel *display,
                                    Stream *stream, Drawable *new_frame)
 {
-    RedDrawablePipeItem *dpi;
     DisplayChannelClient *dcc;
     int index;
     StreamAgent *agent;
-    RingItem *ring_item, *next;
+    GList *dpi_link, *dpi_next;
     GList *link, *link_next;
 
     spice_return_if_fail(stream->current);
@@ -350,7 +349,9 @@ static void before_reattach_stream(DisplayChannel *display,
     }
 
     index = display_channel_get_stream_id(display, stream);
-    DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) {
+    for (dpi_link = stream->current->pipes; dpi_link; dpi_link = dpi_next) {
+        RedDrawablePipeItem *dpi = dpi_link->data;
+        dpi_next = dpi_link->next;
         dcc = dpi->dcc;
         agent = dcc_get_stream_agent(dcc, index);
 
commit a78a7d251042892182b158650291d19a85bbd6b1
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Thu Oct 1 10:39:18 2015 -0500

    RedChannelClient: store pipe items in a GQueue
    
    Instead of using a Ring (and having a ring item link in every pipe
    item), store them in a GQueue. This also necesitated changing
    RedCharDeviceVDIPort->priv->read_bufs to a GList as well.
    
    Also Optimise client pipe by passing pipe position instead of data.
    This avoids having the search the data scanning all the queue changing
    the order of these operations from O(n) to O(1).
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/cursor-channel.c b/server/cursor-channel.c
index 52c8e2d..8786ac6 100644
--- a/server/cursor-channel.c
+++ b/server/cursor-channel.c
@@ -189,8 +189,6 @@ static void cursor_pipe_item_free(RedPipeItem *base)
 
     RedCursorPipeItem *pipe_item = SPICE_UPCAST(RedCursorPipeItem, base);
 
-    spice_assert(!red_pipe_item_is_linked(&pipe_item->base));
-
     cursor_item_unref(pipe_item->cursor_item);
     free(pipe_item);
 }
diff --git a/server/dcc-send.c b/server/dcc-send.c
index 7f0d87a..1d05c68 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -176,9 +176,9 @@ static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush,
     }
 }
 
-static RedPipeItem *dcc_get_tail(DisplayChannelClient *dcc)
+static GList *dcc_get_tail(DisplayChannelClient *dcc)
 {
-    return (RedPipeItem*)ring_get_tail(red_channel_client_get_pipe(RED_CHANNEL_CLIENT(dcc)));
+    return red_channel_client_get_pipe(RED_CHANNEL_CLIENT(dcc))->tail;
 }
 
 static void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
@@ -606,17 +606,13 @@ static int pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *dc
                                                         SpiceRect *surface_areas[],
                                                         int num_surfaces)
 {
-    RedPipeItem *pipe_item;
-    Ring *pipe;
+    GList *l;
 
     spice_assert(num_surfaces);
-    pipe = red_channel_client_get_pipe(RED_CHANNEL_CLIENT(dcc));
 
-    for (pipe_item = (RedPipeItem *)ring_get_head(pipe);
-         pipe_item;
-         pipe_item = (RedPipeItem *)ring_next(pipe, &pipe_item->link))
-    {
+    for (l = red_channel_client_get_pipe(RED_CHANNEL_CLIENT(dcc))->head; l != NULL; l = l->next) {
         Drawable *drawable;
+        RedPipeItem *pipe_item = l->data;
 
         if (pipe_item->type != RED_PIPE_ITEM_TYPE_DRAW)
             continue;
@@ -695,8 +691,8 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
     int resent_surface_ids[MAX_PIPE_SIZE];
     SpiceRect resent_areas[MAX_PIPE_SIZE]; // not pointers since drawables may be released
     int num_resent;
-    RedPipeItem *pipe_item;
-    Ring *pipe;
+    GList *l;
+    GQueue *pipe;
 
     resent_surface_ids[0] = first_surface_id;
     resent_areas[0] = *first_area;
@@ -705,9 +701,8 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
     pipe = red_channel_client_get_pipe(RED_CHANNEL_CLIENT(dcc));
 
     // going from the oldest to the newest
-    for (pipe_item = (RedPipeItem *)ring_get_tail(pipe);
-         pipe_item;
-         pipe_item = (RedPipeItem *)ring_prev(pipe, &pipe_item->link)) {
+    for (l = pipe->tail; l != NULL; l = l->prev) {
+        RedPipeItem *pipe_item = l->data;
         Drawable *drawable;
         RedDrawablePipeItem *dpi;
         RedImageItem *image;
@@ -731,13 +726,13 @@ static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient
         }
 
         image = dcc_add_surface_area_image(dcc, drawable->red_drawable->surface_id,
-                                           &drawable->red_drawable->bbox, pipe_item, TRUE);
+                                           &drawable->red_drawable->bbox, l, TRUE);
         resent_surface_ids[num_resent] = drawable->red_drawable->surface_id;
         resent_areas[num_resent] = drawable->red_drawable->bbox;
         num_resent++;
 
         spice_assert(image);
-        red_channel_client_pipe_remove_and_release(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item);
+        red_channel_client_pipe_remove_and_release_pos(RED_CHANNEL_CLIENT(dcc), l);
         pipe_item = &image->base;
     }
 }
diff --git a/server/dcc.c b/server/dcc.c
index a5a1b40..27efdc6 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -67,8 +67,7 @@ int dcc_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
 int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id,
                                           int wait_if_used)
 {
-    Ring *ring;
-    RedPipeItem *item;
+    GList *l;
     int x;
     RedChannelClient *rcc;
 
@@ -77,13 +76,14 @@ int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface
        no other drawable depends on them */
 
     rcc = RED_CHANNEL_CLIENT(dcc);
-    ring = &rcc->priv->pipe;
-    item = (RedPipeItem *) ring;
-    while ((item = (RedPipeItem *)ring_next(ring, &item->link))) {
+    for (l = rcc->priv->pipe.head; l != NULL; ) {
         Drawable *drawable;
         RedDrawablePipeItem *dpi = NULL;
         int depend_found = FALSE;
+        RedPipeItem *item = l->data;
+        GList *item_pos = l;
 
+        l = l->next;
         if (item->type == RED_PIPE_ITEM_TYPE_DRAW) {
             dpi = SPICE_CONTAINEROF(item, RedDrawablePipeItem, dpi_pipe_item);
             drawable = dpi->drawable;
@@ -94,12 +94,7 @@ int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface
         }
 
         if (drawable->surface_id == surface_id) {
-            RedPipeItem *tmp_item = item;
-            item = (RedPipeItem *)ring_prev(ring, &item->link);
-            red_channel_client_pipe_remove_and_release(rcc, tmp_item);
-            if (!item) {
-                item = (RedPipeItem *)ring;
-            }
+            red_channel_client_pipe_remove_and_release_pos(rcc, item_pos);
             continue;
         }
 
@@ -112,11 +107,11 @@ int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface
 
         if (depend_found) {
             spice_debug("surface %d dependent item found %p, %p", surface_id, drawable, item);
-            if (wait_if_used) {
-                break;
-            } else {
+            if (!wait_if_used) {
                 return TRUE;
             }
+            return red_channel_client_wait_pipe_item_sent(rcc, item_pos,
+                                                          COMMON_CLIENT_TIMEOUT);
         }
     }
 
@@ -124,18 +119,11 @@ int dcc_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface
         return TRUE;
     }
 
-    if (item) {
-        return red_channel_client_wait_pipe_item_sent(RED_CHANNEL_CLIENT(dcc), item,
-                                                      COMMON_CLIENT_TIMEOUT);
-    } else {
-        /*
-         * in case that the pipe didn't contain any item that is dependent on the surface, but
-         * there is one during sending. Use a shorter timeout, since it is just one item
-         */
-        return red_channel_client_wait_outgoing_item(RED_CHANNEL_CLIENT(dcc),
-                                                     DISPLAY_CLIENT_SHORT_TIMEOUT);
-    }
-    return TRUE;
+    /*
+     * in case that the pipe didn't contain any item that is dependent on the surface, but
+     * there is one during sending. Use a shorter timeout, since it is just one item
+     */
+    return red_channel_client_wait_outgoing_item(rcc, DISPLAY_CLIENT_SHORT_TIMEOUT);
 }
 
 void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
@@ -170,7 +158,7 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
 RedImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc,
                                          int surface_id,
                                          SpiceRect *area,
-                                         RedPipeItem *pos,
+                                         GList *pipe_item_pos,
                                          int can_lossy)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
@@ -220,8 +208,8 @@ RedImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc,
         }
     }
 
-    if (pos) {
-        red_channel_client_pipe_add_after(RED_CHANNEL_CLIENT(dcc), &item->base, pos);
+    if (pipe_item_pos) {
+        red_channel_client_pipe_add_after_pos(RED_CHANNEL_CLIENT(dcc), &item->base, pipe_item_pos);
     } else {
         red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &item->base);
     }
@@ -288,7 +276,6 @@ static void red_drawable_pipe_item_free(RedPipeItem *item)
                                                  dpi_pipe_item);
     spice_assert(item->refcount == 0);
 
-    spice_warn_if_fail(!ring_item_is_linked(&item->link));
     if (ring_item_is_linked(&dpi->base)) {
         ring_remove(&dpi->base);
     }
diff --git a/server/dcc.h b/server/dcc.h
index d08e413..a2478b9 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -129,7 +129,7 @@ void                       dcc_push_surface_image                    (DisplayCha
 RedImageItem *             dcc_add_surface_area_image                (DisplayChannelClient *dcc,
                                                                       int surface_id,
                                                                       SpiceRect *area,
-                                                                      RedPipeItem *pos,
+                                                                      GList *pipe_item_pos,
                                                                       int can_lossy);
 void                       dcc_palette_cache_reset                   (DisplayChannelClient *dcc);
 void                       dcc_palette_cache_palette                 (DisplayChannelClient *dcc,
diff --git a/server/display-channel.c b/server/display-channel.c
index 61f55a6..6e754b3 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -327,11 +327,11 @@ static void drawable_remove_from_pipes(Drawable *drawable)
     RingItem *item, *next;
 
     RING_FOREACH_SAFE(item, next, &drawable->pipes) {
+        RedChannelClient *rcc;
+
         dpi = SPICE_UPCAST(RedDrawablePipeItem, item);
-        if (red_pipe_item_is_linked(&dpi->dpi_pipe_item)) {
-            red_channel_client_pipe_remove_and_release(RED_CHANNEL_CLIENT(dpi->dcc),
-                                                       &dpi->dpi_pipe_item);
-        }
+        rcc = RED_CHANNEL_CLIENT(dpi->dcc);
+        red_channel_client_pipe_remove_and_release(rcc, &dpi->dpi_pipe_item);
     }
 }
 
diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index 532bfa3..8eaa570 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -59,8 +59,7 @@ struct RedChannelClientPrivate
 
     int during_send;
     int id; // debugging purposes
-    Ring pipe;
-    uint32_t pipe_size;
+    GQueue pipe;
 
     RedChannelCapabilities remote_caps;
     int is_mini_header;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 0eed02b..50b295c 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -344,7 +344,7 @@ void red_channel_client_on_out_msg_done(void *opaque)
     } else {
         if (rcc->priv->latency_monitor.timer
             && !rcc->priv->send_data.blocked
-            && rcc->priv->pipe_size == 0) {
+            && g_queue_is_empty(&rcc->priv->pipe)) {
             /* It is possible that the socket will become idle, so we may be able to test latency */
             red_channel_client_restart_ping_timer(rcc);
         }
@@ -352,10 +352,9 @@ void red_channel_client_on_out_msg_done(void *opaque)
 
 }
 
-static void red_channel_client_pipe_remove(RedChannelClient *rcc, RedPipeItem *item)
+static gboolean red_channel_client_pipe_remove(RedChannelClient *rcc, RedPipeItem *item)
 {
-    rcc->priv->pipe_size--;
-    ring_remove(&item->link);
+    return g_queue_remove(&rcc->priv->pipe, item);
 }
 
 static void red_channel_client_set_remote_caps(RedChannelClient* rcc,
@@ -681,8 +680,7 @@ RedChannelClient *red_channel_client_create(int size, RedChannel *channel, RedCl
         goto error;
     }
 
-    ring_init(&rcc->priv->pipe);
-    rcc->priv->pipe_size = 0;
+    g_queue_init(&rcc->priv->pipe);
 
     stream->watch = channel->core->watch_add(channel->core,
                                            stream->socket,
@@ -743,7 +741,7 @@ RedChannelClient *red_channel_client_create_dummy(int size,
 
     rcc->incoming.header.data = rcc->incoming.header_buf;
     rcc->incoming.serial = 1;
-    ring_init(&rcc->priv->pipe);
+    g_queue_init(&rcc->priv->pipe);
 
     rcc->priv->dummy = TRUE;
     rcc->priv->dummy_connected = TRUE;
@@ -1039,15 +1037,11 @@ void red_channel_client_send(RedChannelClient *rcc)
 
 static inline RedPipeItem *red_channel_client_pipe_item_get(RedChannelClient *rcc)
 {
-    RedPipeItem *item;
-
     if (!rcc || rcc->priv->send_data.blocked
-             || red_channel_client_waiting_for_ack(rcc)
-             || !(item = (RedPipeItem *)ring_get_tail(&rcc->priv->pipe))) {
+             || red_channel_client_waiting_for_ack(rcc)) {
         return NULL;
     }
-    red_channel_client_pipe_remove(rcc, item);
-    return item;
+    return g_queue_pop_tail(&rcc->priv->pipe);
 }
 
 void red_channel_client_push(RedChannelClient *rcc)
@@ -1072,7 +1066,7 @@ void red_channel_client_push(RedChannelClient *rcc)
     while ((pipe_item = red_channel_client_pipe_item_get(rcc))) {
         red_channel_client_send_item(rcc, pipe_item);
     }
-    if (red_channel_client_no_item_being_sent(rcc) && ring_is_empty(&rcc->priv->pipe)
+    if (red_channel_client_no_item_being_sent(rcc) && g_queue_is_empty(&rcc->priv->pipe)
         && rcc->priv->stream->watch) {
         rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
                                                     SPICE_WATCH_EVENT_READ);
@@ -1286,7 +1280,7 @@ void red_channel_client_set_message_serial(RedChannelClient *rcc, uint64_t seria
     rcc->priv->send_data.serial = serial;
 }
 
-static inline gboolean client_pipe_add(RedChannelClient *rcc, RedPipeItem *item, RingItem *pos)
+static inline gboolean prepare_pipe_add(RedChannelClient *rcc, RedPipeItem *item)
 {
     spice_assert(rcc && item);
     if (SPICE_UNLIKELY(!red_channel_client_is_connected(rcc))) {
@@ -1294,20 +1288,21 @@ static inline gboolean client_pipe_add(RedChannelClient *rcc, RedPipeItem *item,
         red_pipe_item_unref(item);
         return FALSE;
     }
-    if (ring_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
+    if (g_queue_is_empty(&rcc->priv->pipe) && rcc->priv->stream->watch) {
         rcc->priv->channel->core->watch_update_mask(rcc->priv->stream->watch,
                                                     SPICE_WATCH_EVENT_READ |
                                                     SPICE_WATCH_EVENT_WRITE);
     }
-    rcc->priv->pipe_size++;
-    ring_add(pos, &item->link);
     return TRUE;
 }
 
 void red_channel_client_pipe_add(RedChannelClient *rcc, RedPipeItem *item)
 {
 
-    client_pipe_add(rcc, item, &rcc->priv->pipe);
+    if (!prepare_pipe_add(rcc, item)) {
+        return;
+    }
+    g_queue_push_head(&rcc->priv->pipe, item);
 }
 
 void red_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item)
@@ -1316,31 +1311,53 @@ void red_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item)
     red_channel_client_push(rcc);
 }
 
+void red_channel_client_pipe_add_after_pos(RedChannelClient *rcc,
+                                           RedPipeItem *item,
+                                           GList *pipe_item_pos)
+{
+    spice_assert(pipe_item_pos);
+    if (!prepare_pipe_add(rcc, item)) {
+        return;
+    }
+
+    g_queue_insert_after(&rcc->priv->pipe, pipe_item_pos, item);
+}
+
 void red_channel_client_pipe_add_after(RedChannelClient *rcc,
                                        RedPipeItem *item,
                                        RedPipeItem *pos)
 {
+    GList *prev;
+
     spice_assert(pos);
-    client_pipe_add(rcc, item, &pos->link);
+    prev = g_queue_find(&rcc->priv->pipe, pos);
+    g_return_if_fail(prev != NULL);
+
+    red_channel_client_pipe_add_after_pos(rcc, item, prev);
 }
 
 int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc,
                                            RedPipeItem *item)
 {
-    return ring_item_is_linked(&item->link);
+    return g_queue_find(&rcc->priv->pipe, item) != NULL;
 }
 
 void red_channel_client_pipe_add_tail(RedChannelClient *rcc,
                                       RedPipeItem *item)
 {
-    client_pipe_add(rcc, item, rcc->priv->pipe.prev);
+    if (!prepare_pipe_add(rcc, item)) {
+        return;
+    }
+    g_queue_push_tail(&rcc->priv->pipe, item);
 }
 
 void red_channel_client_pipe_add_tail_and_push(RedChannelClient *rcc, RedPipeItem *item)
 {
-    if (client_pipe_add(rcc, item, rcc->priv->pipe.prev)) {
-        red_channel_client_push(rcc);
+    if (!prepare_pipe_add(rcc, item)) {
+        return;
     }
+    g_queue_push_tail(&rcc->priv->pipe, item);
+    red_channel_client_push(rcc);
 }
 
 void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type)
@@ -1365,15 +1382,15 @@ void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type)
 gboolean red_channel_client_pipe_is_empty(RedChannelClient *rcc)
 {
     g_return_val_if_fail(rcc != NULL, TRUE);
-    return (rcc->priv->pipe_size == 0) && (ring_is_empty(&rcc->priv->pipe));
+    return g_queue_is_empty(&rcc->priv->pipe);
 }
 
 uint32_t red_channel_client_get_pipe_size(RedChannelClient *rcc)
 {
-    return rcc->priv->pipe_size;
+    return g_queue_get_length(&rcc->priv->pipe);
 }
 
-Ring* red_channel_client_get_pipe(RedChannelClient *rcc)
+GQueue* red_channel_client_get_pipe(RedChannelClient *rcc)
 {
     return &rcc->priv->pipe;
 }
@@ -1410,11 +1427,9 @@ static void red_channel_client_pipe_clear(RedChannelClient *rcc)
     if (rcc) {
         red_channel_client_clear_sent_item(rcc);
     }
-    while ((item = (RedPipeItem *)ring_get_head(&rcc->priv->pipe))) {
-        ring_remove(&item->link);
+    while ((item = g_queue_pop_head(&rcc->priv->pipe)) != NULL) {
         red_pipe_item_unref(item);
     }
-    rcc->priv->pipe_size = 0;
 }
 
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
@@ -1517,7 +1532,7 @@ static void marker_pipe_item_free(RedPipeItem *base)
 
 /* TODO: more evil sync stuff. anything with the word wait in it's name. */
 int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
-                                           RedPipeItem *item,
+                                           GList *item_pos,
                                            int64_t timeout)
 {
     uint64_t end_time;
@@ -1537,7 +1552,7 @@ int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
                             marker_pipe_item_free);
     item_in_pipe = TRUE;
     mark_item->item_in_pipe = &item_in_pipe;
-    red_channel_client_pipe_add_after(rcc, &mark_item->base, item);
+    red_channel_client_pipe_add_after_pos(rcc, &mark_item->base, item_pos);
 
     if (red_channel_client_is_blocked(rcc)) {
         red_channel_client_receive(rcc);
@@ -1545,8 +1560,8 @@ int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
     }
     red_channel_client_push(rcc);
 
-    while(item_in_pipe &&
-          (timeout == -1 || spice_get_monotonic_time_ns() < end_time)) {
+    while (item_in_pipe &&
+           (timeout == -1 || spice_get_monotonic_time_ns() < end_time)) {
         usleep(CHANNEL_BLOCKED_SLEEP_DURATION);
         red_channel_client_receive(rcc);
         red_channel_client_send(rcc);
@@ -1598,7 +1613,7 @@ int red_channel_client_wait_outgoing_item(RedChannelClient *rcc,
 
 void red_channel_client_disconnect_if_pending_send(RedChannelClient *rcc)
 {
-    if (red_channel_client_is_blocked(rcc) || rcc->priv->pipe_size > 0) {
+    if (red_channel_client_is_blocked(rcc) || !g_queue_is_empty(&rcc->priv->pipe)) {
         red_channel_client_disconnect(rcc);
     } else {
         spice_assert(red_channel_client_no_item_being_sent(rcc));
@@ -1613,7 +1628,17 @@ gboolean red_channel_client_no_item_being_sent(RedChannelClient *rcc)
 void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc,
                                                 RedPipeItem *item)
 {
-    red_channel_client_pipe_remove(rcc, item);
+    if (red_channel_client_pipe_remove(rcc, item)) {
+        red_pipe_item_unref(item);
+    }
+}
+
+void red_channel_client_pipe_remove_and_release_pos(RedChannelClient *rcc,
+                                                    GList *item_pos)
+{
+    RedPipeItem *item = item_pos->data;
+
+    g_queue_delete_link(&rcc->priv->pipe, item_pos);
     red_pipe_item_unref(item);
 }
 
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index d2f7b3e..b2386d3 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -105,8 +105,10 @@ void red_channel_client_start_connectivity_monitoring(RedChannelClient *rcc, uin
 void red_channel_client_pipe_add_push(RedChannelClient *rcc, RedPipeItem *item);
 void red_channel_client_pipe_add(RedChannelClient *rcc, RedPipeItem *item);
 void red_channel_client_pipe_add_after(RedChannelClient *rcc, RedPipeItem *item, RedPipeItem *pos);
+void red_channel_client_pipe_add_after_pos(RedChannelClient *rcc, RedPipeItem *item, GList *pos);
 int red_channel_client_pipe_item_is_linked(RedChannelClient *rcc, RedPipeItem *item);
 void red_channel_client_pipe_remove_and_release(RedChannelClient *rcc, RedPipeItem *item);
+void red_channel_client_pipe_remove_and_release_pos(RedChannelClient *rcc, GList *item_pos);
 void red_channel_client_pipe_add_tail(RedChannelClient *rcc, RedPipeItem *item);
 void red_channel_client_pipe_add_tail_and_push(RedChannelClient *rcc, RedPipeItem *item);
 /* for types that use this routine -> the pipe item should be freed */
@@ -114,7 +116,7 @@ void red_channel_client_pipe_add_type(RedChannelClient *rcc, int pipe_item_type)
 void red_channel_client_pipe_add_empty_msg(RedChannelClient *rcc, int msg_type);
 gboolean red_channel_client_pipe_is_empty(RedChannelClient *rcc);
 uint32_t red_channel_client_get_pipe_size(RedChannelClient *rcc);
-Ring* red_channel_client_get_pipe(RedChannelClient *rcc);
+GQueue* red_channel_client_get_pipe(RedChannelClient *rcc);
 gboolean red_channel_client_is_mini_header(RedChannelClient *rcc);
 
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
@@ -150,7 +152,7 @@ void red_channel_client_set_header_sub_list(RedChannelClient *rcc, uint32_t sub_
  */
 
 int red_channel_client_wait_pipe_item_sent(RedChannelClient *rcc,
-                                           RedPipeItem *item,
+                                           GList *item_pos,
                                            int64_t timeout);
 int red_channel_client_wait_outgoing_item(RedChannelClient *rcc,
                                           int64_t timeout);
diff --git a/server/red-pipe-item.c b/server/red-pipe-item.c
index 31262fa..d899610 100644
--- a/server/red-pipe-item.c
+++ b/server/red-pipe-item.c
@@ -42,7 +42,6 @@ void red_pipe_item_init_full(RedPipeItem *item,
                              gint type,
                              red_pipe_item_free_t *free_func)
 {
-    ring_item_init(&item->link);
     item->type = type;
     item->refcount = 1;
     item->free_func = free_func ? free_func : (red_pipe_item_free_t *)free;
diff --git a/server/red-pipe-item.h b/server/red-pipe-item.h
index bf13b0b..a589c68 100644
--- a/server/red-pipe-item.h
+++ b/server/red-pipe-item.h
@@ -26,7 +26,6 @@ struct RedPipeItem;
 typedef void red_pipe_item_free_t(struct RedPipeItem *item);
 
 typedef struct RedPipeItem {
-    RingItem link;
     int type;
 
     /* private */
@@ -39,11 +38,6 @@ void red_pipe_item_init_full(RedPipeItem *item, int type, red_pipe_item_free_t f
 RedPipeItem *red_pipe_item_ref(RedPipeItem *item);
 void red_pipe_item_unref(RedPipeItem *item);
 
-static inline int red_pipe_item_is_linked(RedPipeItem *item)
-{
-    return ring_item_is_linked(&item->link);
-}
-
 static inline void red_pipe_item_init(RedPipeItem *item, int type)
 {
     red_pipe_item_init_full(item, type, NULL);
diff --git a/server/reds.c b/server/reds.c
index 8e9dc7b..6244e32 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -238,7 +238,7 @@ struct RedCharDeviceVDIPortPrivate {
     AgentMsgFilter write_filter;
 
     /* read from agent */
-    Ring read_bufs;
+    GList *read_bufs;
     uint32_t read_state;
     uint32_t message_receive_len;
     uint8_t *receive_pos;
@@ -795,15 +795,15 @@ static void vdi_read_buf_init(RedVDIReadBuf *buf)
 
 static RedVDIReadBuf *vdi_port_get_read_buf(RedCharDeviceVDIPort *dev)
 {
-    RingItem *item;
+    GList *item;
     RedVDIReadBuf *buf;
 
-    if (!(item = ring_get_head(&dev->priv->read_bufs))) {
+    if (!(item = g_list_first(dev->priv->read_bufs))) {
         return NULL;
     }
 
-    ring_remove(item);
-    buf = SPICE_CONTAINEROF(item, RedVDIReadBuf, base.link);
+    buf = item->data;
+    dev->priv->read_bufs = g_list_delete_link(dev->priv->read_bufs, item);
 
     g_warn_if_fail(buf->base.refcount == 0);
     vdi_read_buf_init(buf);
@@ -816,7 +816,7 @@ static void vdi_port_read_buf_free(RedPipeItem *base)
     RedVDIReadBuf *buf = SPICE_UPCAST(RedVDIReadBuf, base);
 
     g_warn_if_fail(buf->base.refcount == 0);
-    ring_add(&buf->dev->priv->read_bufs, &buf->base.link);
+    buf->dev->priv->read_bufs = g_list_prepend(buf->dev->priv->read_bufs, buf);
 
     /* read_one_msg_from_vdi_port may have never completed because the read_bufs
        ring was empty. So we call it again so it can complete its work if
@@ -4477,8 +4477,6 @@ red_char_device_vdi_port_init(RedCharDeviceVDIPort *self)
 
     self->priv = RED_CHAR_DEVICE_VDIPORT_PRIVATE(self);
 
-    ring_init(&self->priv->read_bufs);
-
     self->priv->read_state = VDI_PORT_READ_STATE_READ_HEADER;
     self->priv->receive_pos = (uint8_t *)&self->priv->vdi_chunk_header;
     self->priv->receive_len = sizeof(self->priv->vdi_chunk_header);
diff --git a/server/stream.c b/server/stream.c
index 4732dee..746f1cf 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -359,7 +359,8 @@ static void before_reattach_stream(DisplayChannel *display,
             continue;
         }
 
-        if (red_pipe_item_is_linked(&dpi->dpi_pipe_item)) {
+        if (red_channel_client_pipe_item_is_linked(RED_CHANNEL_CLIENT(dcc),
+                                                   &dpi->dpi_pipe_item)) {
 #ifdef STREAM_STATS
             agent->stats.num_drops_pipe++;
 #endif
commit 46c83dfe1ff13cb7d8c556c609914dafeee040c8
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Wed May 4 15:32:25 2016 -0500

    Rename display_channel_set_monitors_config_to_primary()
    
    Since this function is a DisplayChannel method, use a name consistent
    with naming conventions.
    
    Acked-by: Pavel Grunt <pgrunt at redhat.com>

diff --git a/server/display-channel.c b/server/display-channel.c
index cd0cecf..61f55a6 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2080,7 +2080,7 @@ void display_channel_update_monitors_config(DisplayChannel *display,
         monitors_config_new(config->heads, count, max_allowed);
 }
 
-void set_monitors_config_to_primary(DisplayChannel *display)
+void display_channel_set_monitors_config_to_primary(DisplayChannel *display)
 {
     DrawContext *context = &display->priv->surfaces[0].context;
     QXLHead head = { 0, };
diff --git a/server/display-channel.h b/server/display-channel.h
index dd7ec8d..2f7df55 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -299,7 +299,7 @@ void                       display_channel_gl_draw_done              (DisplayCha
 
 void display_channel_update_monitors_config(DisplayChannel *display, QXLMonitorsConfig *config,
                                             uint16_t count, uint16_t max_allowed);
-void set_monitors_config_to_primary(DisplayChannel *display);
+void display_channel_set_monitors_config_to_primary(DisplayChannel *display);
 
 gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id);
 gboolean display_channel_surface_has_canvas(DisplayChannel *display, uint32_t surface_id);
diff --git a/server/red-worker.c b/server/red-worker.c
index 2cde7fd..62e5d86 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -634,7 +634,7 @@ static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
 
     display_channel_create_surface(display, 0, surface.width, surface.height, surface.stride, surface.format,
                                    line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
-    set_monitors_config_to_primary(display);
+    display_channel_set_monitors_config_to_primary(display);
 
     if (display_is_connected(worker) && !worker->display_channel->common.during_target_migrate) {
         /* guest created primary, so it will (hopefully) send a monitors_config
commit 5e74387d25c8658b8370b726a515f88b81daae35
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Wed May 4 14:33:23 2016 -0500

    Add DisplayChannelPrivate struct
    
    Move all of the DisplayChannel data memembers into a private struct to
    encapsulate things better. This necessitated a few new 'public' methods
    and a small bit of refactoring to avoid poking into DisplayChannel
    internals from too many places. The DisplayChannel and the
    DisplayChannelClient are still far too intertwined to completely avoid
    accessing private data, so at the moment the private struct is defined
    in display-channel.h and the DisplayChannelClient implementation
    still accesses it sometimes.

diff --git a/server/dcc-send.c b/server/dcc-send.c
index 7f28eae..7f0d87a 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -96,7 +96,7 @@ static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
 
     spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), FALSE);
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
     surface_lossy_region = &dcc->priv->surface_client_lossy_region[surface_id];
 
     if (!area) {
@@ -197,13 +197,13 @@ static void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
                 io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
                 dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] =
                                                                                image->descriptor.id;
-                stat_inc_counter(reds, display_channel->add_to_cache_counter, 1);
+                stat_inc_counter(reds, display_channel->priv->add_to_cache_counter, 1);
             }
         }
     }
 
     if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
-        stat_inc_counter(reds, display_channel->non_cache_counter, 1);
+        stat_inc_counter(reds, display_channel->priv->non_cache_counter, 1);
     }
 }
 
@@ -374,7 +374,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
             dcc->priv->send_data.pixmap_cache_items[dcc->priv->send_data.num_pixmap_cache_items++] =
                 image.descriptor.id;
             if (can_lossy || !lossy_cache_item) {
-                if (!display->enable_jpeg || lossy_cache_item) {
+                if (!display->priv->enable_jpeg || lossy_cache_item) {
                     image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
                 } else {
                     // making sure, in multiple monitor scenario, that lossy items that
@@ -386,7 +386,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
                                      &bitmap_palette_out, &lzplt_palette_out);
                 spice_assert(bitmap_palette_out == NULL);
                 spice_assert(lzplt_palette_out == NULL);
-                stat_inc_counter(reds, display->cache_hits_counter, 1);
+                stat_inc_counter(reds, display->priv->cache_hits_counter, 1);
                 pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock);
                 return FILL_BITS_TYPE_CACHE;
             } else {
@@ -409,7 +409,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
             return FILL_BITS_TYPE_SURFACE;
         }
 
-        surface = &display->surfaces[surface_id];
+        surface = &display->priv->surfaces[surface_id];
         image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
         image.descriptor.flags = 0;
         image.descriptor.width = surface->context.width;
@@ -1850,7 +1850,7 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc,
     spice_marshaller_add(base_marshaller,
                          (uint8_t *)&display_data, sizeof(display_data) - sizeof(uint32_t));
     display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller,
-                                                   display_channel->enable_jpeg);
+                                                   display_channel->priv->enable_jpeg);
 }
 
 static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc,
@@ -2136,7 +2136,7 @@ static void marshall_qxl_drawable(RedChannelClient *rcc,
     if (item->stream && red_marshall_stream_data(rcc, m, item)) {
         return;
     }
-    if (display->enable_jpeg)
+    if (display->priv->enable_jpeg)
         marshall_lossy_qxl_drawable(rcc, m, dpi);
     else
         marshall_lossless_qxl_drawable(rcc, m, dpi);
diff --git a/server/dcc.c b/server/dcc.c
index a56b658..a5a1b40 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -157,7 +157,7 @@ void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
         dcc->priv->surface_client_created[surface_id]) {
         return;
     }
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
     create = red_surface_create_item_new(RED_CHANNEL(display),
                                          surface_id, surface->context.width,
                                          surface->context.height,
@@ -174,7 +174,7 @@ RedImageItem *dcc_add_surface_area_image(DisplayChannelClient *dcc,
                                          int can_lossy)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
-    RedSurface *surface = &display->surfaces[surface_id];
+    RedSurface *surface = &display->priv->surfaces[surface_id];
     SpiceCanvas *canvas = surface->context.canvas;
     RedImageItem *item;
     int stride;
@@ -240,7 +240,7 @@ void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
     }
 
     display = DCC_TO_DC(dcc);
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
     if (!surface->context.canvas) {
         return;
     }
@@ -343,7 +343,7 @@ static void dcc_init_stream_agents(DisplayChannelClient *dcc)
 
     for (i = 0; i < NUM_STREAMS; i++) {
         StreamAgent *agent = &dcc->priv->stream_agents[i];
-        agent->stream = &display->streams_buf[i];
+        agent->stream = &display->priv->streams_buf[i];
         region_init(&agent->vis_region);
         region_init(&agent->clip);
     }
@@ -392,14 +392,14 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
 
     dcc_init_stream_agents(dcc);
 
-    image_encoders_init(&dcc->priv->encoders, &display->encoder_shared_data);
+    image_encoders_init(&dcc->priv->encoders, &display->priv->encoder_shared_data);
 
     return dcc;
 }
 
 static void dcc_create_all_streams(DisplayChannelClient *dcc)
 {
-    Ring *ring = &DCC_TO_DC(dcc)->streams;
+    Ring *ring = &DCC_TO_DC(dcc)->priv->streams;
     RingItem *item = ring;
 
     while ((item = ring_next(ring, item))) {
@@ -451,7 +451,7 @@ void dcc_start(DisplayChannelClient *dcc)
         return;
 
     red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
-    if (display->surfaces[0].context.canvas) {
+    if (display->priv->surfaces[0].context.canvas) {
         display_channel_current_flush(display, 0);
         red_channel_client_pipe_add_type(rcc, RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
         dcc_create_surface(dcc, 0);
@@ -538,7 +538,7 @@ static RedMonitorsConfigItem *red_monitors_config_item_new(RedChannel* channel,
 void dcc_push_monitors_config(DisplayChannelClient *dcc)
 {
     DisplayChannel *dc = DCC_TO_DC(dcc);
-    MonitorsConfig *monitors_config = dc->monitors_config;
+    MonitorsConfig *monitors_config = dc->priv->monitors_config;
     RedMonitorsConfigItem *mci;
 
     if (monitors_config == NULL) {
@@ -552,7 +552,7 @@ void dcc_push_monitors_config(DisplayChannelClient *dcc)
     }
 
     mci = red_monitors_config_item_new(red_channel_client_get_channel(RED_CHANNEL_CLIENT(dcc)),
-                                       monitors_config_ref(dc->monitors_config));
+                                       monitors_config_ref(dc->priv->monitors_config));
     red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &mci->pipe_item);
     red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
 }
@@ -724,14 +724,14 @@ int dcc_compress_image(DisplayChannelClient *dcc,
     stat_start_time_t start_time;
     int success = FALSE;
 
-    stat_start_time_init(&start_time, &display_channel->encoder_shared_data.off_stat);
+    stat_start_time_init(&start_time, &display_channel->priv->encoder_shared_data.off_stat);
 
     image_compression = get_compression_for_bitmap(src, dcc->priv->image_compression, drawable);
     switch (image_compression) {
     case SPICE_IMAGE_COMPRESSION_OFF:
         break;
     case SPICE_IMAGE_COMPRESSION_QUIC:
-        if (can_lossy && display_channel->enable_jpeg &&
+        if (can_lossy && display_channel->priv->enable_jpeg &&
             (src->format != SPICE_BITMAP_FMT_RGBA || !bitmap_has_extra_stride(src))) {
             success = image_encoders_compress_jpeg(&dcc->priv->encoders, dest, src, o_comp_data);
             break;
@@ -742,7 +742,7 @@ int dcc_compress_image(DisplayChannelClient *dcc,
         success = image_encoders_compress_glz(&dcc->priv->encoders, dest, src,
                                               drawable->red_drawable, &drawable->glz_retention,
                                               o_comp_data,
-                                              display_channel->enable_zlib_glz_wrap);
+                                              display_channel->priv->enable_zlib_glz_wrap);
         if (success) {
             break;
         }
@@ -768,7 +768,7 @@ lz_compress:
 
     if (!success) {
         uint64_t image_size = src->stride * (uint64_t)src->y;
-        stat_compress_add(&display_channel->encoder_shared_data.off_stat, start_time, image_size, image_size);
+        stat_compress_add(&display_channel->priv->encoder_shared_data.off_stat, start_time, image_size, image_size);
     }
 
     return success;
@@ -1115,15 +1115,15 @@ int dcc_handle_migrate_data(DisplayChannelClient *dcc, uint32_t size, void *mess
     if (migrate_data->low_bandwidth_setting) {
         red_channel_client_ack_set_client_window(RED_CHANNEL_CLIENT(dcc), WIDE_CLIENT_ACK_WINDOW);
         if (dcc->priv->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
-            display->enable_jpeg = TRUE;
+            display->priv->enable_jpeg = TRUE;
         }
         if (dcc->priv->zlib_glz_state == SPICE_WAN_COMPRESSION_AUTO) {
-            display->enable_zlib_glz_wrap = TRUE;
+            display->priv->enable_zlib_glz_wrap = TRUE;
         }
     }
 
     surfaces = (uint8_t *)message + migrate_data->surfaces_at_client_ptr;
-    surfaces_restored = display->enable_jpeg ?
+    surfaces_restored = display->priv->enable_jpeg ?
         restore_surfaces_lossy(dcc, (MigrateDisplaySurfacesAtClientLossy *)surfaces) :
         restore_surfaces_lossless(dcc, (MigrateDisplaySurfacesAtClientLossless*)surfaces);
 
diff --git a/server/display-channel.c b/server/display-channel.c
index 23f2873..cd0cecf 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -30,7 +30,7 @@ uint32_t display_channel_generate_uid(DisplayChannel *display)
 {
     spice_return_val_if_fail(display != NULL, 0);
 
-    return ++display->bits_unique;
+    return ++display->priv->bits_unique;
 }
 
 #define stat_start(stat, var)                                        \
@@ -40,7 +40,7 @@ void display_channel_compress_stats_reset(DisplayChannel *display)
 {
     spice_return_if_fail(display);
 
-    image_encoder_shared_stat_reset(&display->encoder_shared_data);
+    image_encoder_shared_stat_reset(&display->priv->encoder_shared_data);
 }
 
 void display_channel_compress_stats_print(const DisplayChannel *display_channel)
@@ -49,7 +49,7 @@ void display_channel_compress_stats_print(const DisplayChannel *display_channel)
     spice_return_if_fail(display_channel);
 
     spice_info("==> Compression stats for display %u", display_channel->common.base.id);
-    image_encoder_shared_stat_print(&display_channel->encoder_shared_data);
+    image_encoder_shared_stat_print(&display_channel->priv->encoder_shared_data);
 #endif
 }
 
@@ -101,7 +101,7 @@ MonitorsConfig* monitors_config_new(QXLHead *heads, ssize_t nheads, ssize_t max)
 int display_channel_get_streams_timeout(DisplayChannel *display)
 {
     int timeout = INT_MAX;
-    Ring *ring = &display->streams;
+    Ring *ring = &display->priv->streams;
     RingItem *item = ring;
 
     red_time_t now = spice_get_monotonic_time_ns();
@@ -139,20 +139,20 @@ void display_channel_set_stream_video(DisplayChannel *display, int stream_video)
         return;
     }
 
-    display->stream_video = stream_video;
+    display->priv->stream_video = stream_video;
 }
 
 void display_channel_set_video_codecs(DisplayChannel *display, GArray *video_codecs)
 {
     spice_return_if_fail(display);
 
-    g_array_unref(display->video_codecs);
-    display->video_codecs = g_array_ref(video_codecs);
+    g_array_unref(display->priv->video_codecs);
+    display->priv->video_codecs = g_array_ref(video_codecs);
 }
 
 static void stop_streams(DisplayChannel *display)
 {
-    Ring *ring = &display->streams;
+    Ring *ring = &display->priv->streams;
     RingItem *item = ring_get_head(ring);
 
     while (item) {
@@ -165,13 +165,13 @@ static void stop_streams(DisplayChannel *display)
         }
     }
 
-    display->next_item_trace = 0;
-    memset(display->items_trace, 0, sizeof(display->items_trace));
+    display->priv->next_item_trace = 0;
+    memset(display->priv->items_trace, 0, sizeof(display->priv->items_trace));
 }
 
 void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
 {
-    RedSurface *surface = &display->surfaces[surface_id];
+    RedSurface *surface = &display->priv->surfaces[surface_id];
     QXLInstance *qxl = display->common.qxl;
     DisplayChannelClient *dcc;
     GList *link, *next;
@@ -207,7 +207,7 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
 gboolean display_channel_surface_has_canvas(DisplayChannel *display,
                                             uint32_t surface_id)
 {
-    return display->surfaces[surface_id].context.canvas != NULL;
+    return display->priv->surfaces[surface_id].context.canvas != NULL;
 }
 
 static void streams_update_visible_region(DisplayChannel *display, Drawable *drawable)
@@ -225,7 +225,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
         return;
     }
 
-    ring = &display->streams;
+    ring = &display->priv->streams;
     item = ring_get_head(ring);
 
     while (item) {
@@ -301,11 +301,11 @@ static void current_add_drawable(DisplayChannel *display,
     RedSurface *surface;
     uint32_t surface_id = drawable->surface_id;
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
     ring_add_after(&drawable->tree_item.base.siblings_link, pos);
-    ring_add(&display->current_list, &drawable->list_link);
+    ring_add(&display->priv->current_list, &drawable->list_link);
     ring_add(&surface->current_list, &drawable->surface_list_link);
-    display->current_size++;
+    display->priv->current_size++;
     drawable->refs++;
 }
 
@@ -318,7 +318,7 @@ static void current_remove_drawable(DisplayChannel *display, Drawable *item)
     ring_remove(&item->list_link);
     ring_remove(&item->surface_list_link);
     drawable_unref(item);
-    display->current_size--;
+    display->priv->current_size--;
 }
 
 static void drawable_remove_from_pipes(Drawable *drawable)
@@ -375,7 +375,7 @@ static void current_remove(DisplayChannel *display, TreeItem *item)
 
 static void current_remove_all(DisplayChannel *display, int surface_id)
 {
-    Ring *ring = &display->surfaces[surface_id].current;
+    Ring *ring = &display->priv->surfaces[surface_id].current;
     RingItem *ring_item;
 
     while ((ring_item = ring_get_head(ring))) {
@@ -470,7 +470,7 @@ static void __exclude_region(DisplayChannel *display, Ring *ring, TreeItem *item
                              Ring **top_ring, Drawable *frame_candidate)
 {
     QRegion and_rgn;
-    stat_start(&display->__exclude_stat, start_time);
+    stat_start(&display->priv->__exclude_stat, start_time);
 
     region_clone(&and_rgn, rgn);
     region_and(&and_rgn, &item->rgn);
@@ -532,14 +532,14 @@ static void __exclude_region(DisplayChannel *display, Ring *ring, TreeItem *item
         }
     }
     region_destroy(&and_rgn);
-    stat_add(&display->__exclude_stat, start_time);
+    stat_add(&display->priv->__exclude_stat, start_time);
 }
 
 static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_item,
                            QRegion *rgn, TreeItem **last, Drawable *frame_candidate)
 {
     Ring *top_ring;
-    stat_start(&display->exclude_stat, start_time);
+    stat_start(&display->priv->exclude_stat, start_time);
 
     if (!ring_item) {
         return;
@@ -575,7 +575,7 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
             }
 
             if (region_is_empty(rgn)) {
-                stat_add(&display->exclude_stat, start_time);
+                stat_add(&display->priv->exclude_stat, start_time);
                 return;
             }
         }
@@ -584,7 +584,7 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
         while ((last && *last == (TreeItem *)ring_item) ||
                !(ring_item = ring_next(ring, ring_item))) {
             if (ring == top_ring) {
-                stat_add(&display->exclude_stat, start_time);
+                stat_add(&display->priv->exclude_stat, start_time);
                 return;
             }
             ring_item = &container->base.siblings_link;
@@ -596,9 +596,9 @@ static void exclude_region(DisplayChannel *display, Ring *ring, RingItem *ring_i
 
 static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable *item)
 {
-    stat_start(&display->add_stat, start_time);
+    stat_start(&display->priv->add_stat, start_time);
 #ifdef RED_WORKER_STAT
-    ++display->add_with_shadow_count;
+    ++display->priv->add_with_shadow_count;
 #endif
 
     RedDrawable *red_drawable = item->red_drawable;
@@ -609,7 +609,7 @@ static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable
 
     Shadow *shadow = shadow_new(&item->tree_item, &delta);
     if (!shadow) {
-        stat_add(&display->add_stat, start_time);
+        stat_add(&display->priv->add_stat, start_time);
         return FALSE;
     }
     // item and his shadow must initially be placed in the same container.
@@ -633,7 +633,7 @@ static int current_add_with_shadow(DisplayChannel *display, Ring *ring, Drawable
             stream_detach_behind(display, &item->tree_item.base.rgn, item);
         }
     }
-    stat_add(&display->add_stat, start_time);
+    stat_add(&display->priv->add_stat, start_time);
     return TRUE;
 }
 
@@ -643,7 +643,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
     RingItem *now;
     QRegion exclude_rgn;
     RingItem *exclude_base = NULL;
-    stat_start(&display->add_stat, start_time);
+    stat_start(&display->priv->add_stat, start_time);
 
     spice_assert(!region_is_empty(&item->base.rgn));
     region_init(&exclude_rgn);
@@ -665,7 +665,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
             if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) &&
                                                    !(test_res & REGION_TEST_LEFT_EXCLUSIVE) &&
                                                    current_add_equal(display, item, sibling)) {
-                stat_add(&display->add_stat, start_time);
+                stat_add(&display->priv->add_stat, start_time);
                 return FALSE;
             }
 
@@ -751,7 +751,7 @@ static int current_add(DisplayChannel *display, Ring *ring, Drawable *drawable)
         }
     }
     region_destroy(&exclude_rgn);
-    stat_add(&display->add_stat, start_time);
+    stat_add(&display->priv->add_stat, start_time);
     return TRUE;
 }
 
@@ -760,7 +760,7 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
     RedDrawable *red_drawable = drawable->red_drawable;
     SpiceImage *image;
 
-    if (display->stream_video == SPICE_STREAM_VIDEO_OFF) {
+    if (display->priv->stream_video == SPICE_STREAM_VIDEO_OFF) {
         return FALSE;
     }
 
@@ -780,7 +780,7 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
         return FALSE;
     }
 
-    if (display->stream_video == SPICE_STREAM_VIDEO_FILTER) {
+    if (display->priv->stream_video == SPICE_STREAM_VIDEO_FILTER) {
         SpiceRect* rect;
         int size;
 
@@ -797,26 +797,26 @@ static bool drawable_can_stream(DisplayChannel *display, Drawable *drawable)
 #ifdef RED_WORKER_STAT
 static void display_channel_print_stats(DisplayChannel *display)
 {
-    stat_time_t total = display->add_stat.total;
+    stat_time_t total = display->priv->add_stat.total;
     spice_info("add with shadow count %u",
-               display->add_with_shadow_count);
-    display->add_with_shadow_count = 0;
+               display->priv->add_with_shadow_count);
+    display->priv->add_with_shadow_count = 0;
     spice_info("add[%u] %f exclude[%u] %f __exclude[%u] %f",
-               display->add_stat.count,
+               display->priv->add_stat.count,
                stat_cpu_time_to_sec(total),
-               display->exclude_stat.count,
-               stat_cpu_time_to_sec(display->exclude_stat.total),
-               display->__exclude_stat.count,
-               stat_cpu_time_to_sec(display->__exclude_stat.total));
+               display->priv->exclude_stat.count,
+               stat_cpu_time_to_sec(display->priv->exclude_stat.total),
+               display->priv->__exclude_stat.count,
+               stat_cpu_time_to_sec(display->priv->__exclude_stat.total));
     spice_info("add %f%% exclude %f%% exclude2 %f%% __exclude %f%%",
-               (double)(total - display->exclude_stat.total) / total * 100,
-               (double)(display->exclude_stat.total) / total * 100,
-               (double)(display->exclude_stat.total -
-                        display->__exclude_stat.total) / display->exclude_stat.total * 100,
-               (double)(display->__exclude_stat.total) / display->exclude_stat.total * 100);
-    stat_reset(&display->add_stat);
-    stat_reset(&display->exclude_stat);
-    stat_reset(&display->__exclude_stat);
+               (double)(total - display->priv->exclude_stat.total) / total * 100,
+               (double)(display->priv->exclude_stat.total) / total * 100,
+               (double)(display->priv->exclude_stat.total -
+                        display->priv->__exclude_stat.total) / display->priv->exclude_stat.total * 100,
+               (double)(display->priv->__exclude_stat.total) / display->priv->exclude_stat.total * 100);
+    stat_reset(&display->priv->add_stat);
+    stat_reset(&display->priv->exclude_stat);
+    stat_reset(&display->priv->__exclude_stat);
 }
 #endif
 
@@ -831,7 +831,7 @@ static void drawable_ref_surface_deps(DisplayChannel *display, Drawable *drawabl
         if (surface_id == -1) {
             continue;
         }
-        surface = &display->surfaces[surface_id];
+        surface = &display->priv->surfaces[surface_id];
         surface->refs++;
     }
 }
@@ -840,7 +840,7 @@ static void surface_read_bits(DisplayChannel *display, int surface_id,
                               const SpiceRect *area, uint8_t *dest, int dest_stride)
 {
     SpiceCanvas *canvas;
-    RedSurface *surface = &display->surfaces[surface_id];
+    RedSurface *surface = &display->priv->surfaces[surface_id];
 
     canvas = surface->context.canvas;
     canvas->ops->read_bits(canvas, dest, dest_stride, area);
@@ -858,7 +858,7 @@ static void handle_self_bitmap(DisplayChannel *display, Drawable *drawable)
     int bpp;
     int all_set;
 
-    surface = &display->surfaces[drawable->surface_id];
+    surface = &display->priv->surfaces[drawable->surface_id];
 
     bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
     width = red_drawable->self_bitmap_area.right - red_drawable->self_bitmap_area.left;
@@ -910,7 +910,7 @@ static void surface_add_reverse_dependency(DisplayChannel *display, int surface_
         return;
     }
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
 
     depend_item->drawable = drawable;
     ring_add(&surface->depend_on_me, &depend_item->ring_item);
@@ -944,7 +944,7 @@ static void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id)
     RedSurface *surface;
     RingItem *ring_item;
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
 
     while ((ring_item = ring_get_tail(&surface->depend_on_me))) {
         Drawable *drawable;
@@ -965,7 +965,7 @@ static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable
         if (!display_channel_validate_surface(display, drawable->surface_id)) {
             return FALSE;
         }
-        context = &display->surfaces[surface_id].context;
+        context = &display->priv->surfaces[surface_id].context;
 
         if (drawable->bbox.top < 0)
                 return FALSE;
@@ -1019,7 +1019,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
     drawable->red_drawable = red_drawable_ref(red_drawable);
 
     drawable->surface_id = red_drawable->surface_id;
-    display->surfaces[drawable->surface_id].refs++;
+    display->priv->surfaces[drawable->surface_id].refs++;
 
     memcpy(drawable->surface_deps, red_drawable->surface_deps, sizeof(drawable->surface_deps));
     /*
@@ -1069,7 +1069,7 @@ static void display_channel_add_drawable(DisplayChannel *display, Drawable *draw
         return;
     }
 
-    Ring *ring = &display->surfaces[surface_id].current;
+    Ring *ring = &display->priv->surfaces[surface_id].current;
     int add_to_pipe;
     if (has_shadow(red_drawable)) {
         add_to_pipe = current_add_with_shadow(display, ring, drawable);
@@ -1082,7 +1082,7 @@ static void display_channel_add_drawable(DisplayChannel *display, Drawable *draw
         pipes_add_drawable(display, drawable);
 
 #ifdef RED_WORKER_STAT
-    if ((++display->add_count % 100) == 0)
+    if ((++display->priv->add_count % 100) == 0)
         display_channel_print_stats(display);
 #endif
 }
@@ -1146,7 +1146,7 @@ void display_channel_flush_all_surfaces(DisplayChannel *display)
     int x;
 
     for (x = 0; x < NUM_SURFACES; ++x) {
-        if (display->surfaces[x].context.canvas) {
+        if (display->priv->surfaces[x].context.canvas) {
             display_channel_current_flush(display, x);
         }
     }
@@ -1178,7 +1178,7 @@ void display_channel_free_glz_drawables(DisplayChannel *display)
 
 static bool free_one_drawable(DisplayChannel *display, int force_glz_free)
 {
-    RingItem *ring_item = ring_get_tail(&display->current_list);
+    RingItem *ring_item = ring_get_tail(&display->priv->current_list);
     Drawable *drawable;
     Container *container;
 
@@ -1200,7 +1200,7 @@ static bool free_one_drawable(DisplayChannel *display, int force_glz_free)
 
 void display_channel_current_flush(DisplayChannel *display, int surface_id)
 {
-    while (!ring_is_empty(&display->surfaces[surface_id].current_list)) {
+    while (!ring_is_empty(&display->priv->surfaces[surface_id].current_list)) {
         free_one_drawable(display, FALSE);
     }
     current_remove_all(display, surface_id);
@@ -1212,8 +1212,8 @@ void display_channel_free_some(DisplayChannel *display)
     DisplayChannelClient *dcc;
     GList *link, *next;
 
-    spice_debug("#draw=%d, #glz_draw=%d", display->drawable_count,
-                display->encoder_shared_data.glz_drawable_count);
+    spice_debug("#draw=%d, #glz_draw=%d", display->priv->drawable_count,
+                display->priv->encoder_shared_data.glz_drawable_count);
     FOREACH_CLIENT(display, link, next, dcc) {
         ImageEncoders *encoders = dcc_get_encoders(dcc);
 
@@ -1224,7 +1224,7 @@ void display_channel_free_some(DisplayChannel *display)
         }
     }
 
-    while (!ring_is_empty(&display->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
+    while (!ring_is_empty(&display->priv->current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
         free_one_drawable(display, TRUE);
     }
 
@@ -1239,29 +1239,29 @@ static Drawable* drawable_try_new(DisplayChannel *display)
 {
     Drawable *drawable;
 
-    if (!display->free_drawables)
+    if (!display->priv->free_drawables)
         return NULL;
 
-    drawable = &display->free_drawables->u.drawable;
-    display->free_drawables = display->free_drawables->u.next;
-    display->drawable_count++;
+    drawable = &display->priv->free_drawables->u.drawable;
+    display->priv->free_drawables = display->priv->free_drawables->u.next;
+    display->priv->drawable_count++;
 
     return drawable;
 }
 
 static void drawable_free(DisplayChannel *display, Drawable *drawable)
 {
-    ((_Drawable *)drawable)->u.next = display->free_drawables;
-    display->free_drawables = (_Drawable *)drawable;
+    ((_Drawable *)drawable)->u.next = display->priv->free_drawables;
+    display->priv->free_drawables = (_Drawable *)drawable;
 }
 
 static void drawables_init(DisplayChannel *display)
 {
     int i;
 
-    display->free_drawables = NULL;
+    display->priv->free_drawables = NULL;
     for (i = 0; i < NUM_DRAWABLES; i++) {
-        drawable_free(display, &display->drawables[i].u.drawable);
+        drawable_free(display, &display->priv->drawables[i].u.drawable);
     }
 }
 
@@ -1360,7 +1360,7 @@ void drawable_unref(Drawable *drawable)
         red_drawable_unref(drawable->red_drawable);
     }
     drawable_free(display, drawable);
-    display->drawable_count--;
+    display->priv->drawable_count--;
 }
 
 static void drawable_deps_draw(DisplayChannel *display, Drawable *drawable)
@@ -1385,11 +1385,11 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
 
     drawable_deps_draw(display, drawable);
 
-    surface = &display->surfaces[drawable->surface_id];
+    surface = &display->priv->surfaces[drawable->surface_id];
     canvas = surface->context.canvas;
     spice_return_if_fail(canvas);
 
-    image_cache_aging(&display->image_cache);
+    image_cache_aging(&display->priv->image_cache);
 
     region_add(&surface->draw_dirty_region, &drawable->red_drawable->bbox);
 
@@ -1397,8 +1397,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_FILL: {
         SpiceFill fill = drawable->red_drawable->u.fill;
         SpiceImage img1, img2;
-        image_cache_localize_brush(&display->image_cache, &fill.brush, &img1);
-        image_cache_localize_mask(&display->image_cache, &fill.mask, &img2);
+        image_cache_localize_brush(&display->priv->image_cache, &fill.brush, &img1);
+        image_cache_localize_mask(&display->priv->image_cache, &fill.mask, &img2);
         canvas->ops->draw_fill(canvas, &drawable->red_drawable->bbox,
                                &clip, &fill);
         break;
@@ -1406,17 +1406,17 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_OPAQUE: {
         SpiceOpaque opaque = drawable->red_drawable->u.opaque;
         SpiceImage img1, img2, img3;
-        image_cache_localize_brush(&display->image_cache, &opaque.brush, &img1);
-        image_cache_localize(&display->image_cache, &opaque.src_bitmap, &img2, drawable);
-        image_cache_localize_mask(&display->image_cache, &opaque.mask, &img3);
+        image_cache_localize_brush(&display->priv->image_cache, &opaque.brush, &img1);
+        image_cache_localize(&display->priv->image_cache, &opaque.src_bitmap, &img2, drawable);
+        image_cache_localize_mask(&display->priv->image_cache, &opaque.mask, &img3);
         canvas->ops->draw_opaque(canvas, &drawable->red_drawable->bbox, &clip, &opaque);
         break;
     }
     case QXL_DRAW_COPY: {
         SpiceCopy copy = drawable->red_drawable->u.copy;
         SpiceImage img1, img2;
-        image_cache_localize(&display->image_cache, &copy.src_bitmap, &img1, drawable);
-        image_cache_localize_mask(&display->image_cache, &copy.mask, &img2);
+        image_cache_localize(&display->priv->image_cache, &copy.src_bitmap, &img1, drawable);
+        image_cache_localize_mask(&display->priv->image_cache, &copy.mask, &img2);
         canvas->ops->draw_copy(canvas, &drawable->red_drawable->bbox,
                                &clip, &copy);
         break;
@@ -1424,7 +1424,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_TRANSPARENT: {
         SpiceTransparent transparent = drawable->red_drawable->u.transparent;
         SpiceImage img1;
-        image_cache_localize(&display->image_cache, &transparent.src_bitmap, &img1, drawable);
+        image_cache_localize(&display->priv->image_cache, &transparent.src_bitmap, &img1, drawable);
         canvas->ops->draw_transparent(canvas,
                                       &drawable->red_drawable->bbox, &clip, &transparent);
         break;
@@ -1432,7 +1432,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_ALPHA_BLEND: {
         SpiceAlphaBlend alpha_blend = drawable->red_drawable->u.alpha_blend;
         SpiceImage img1;
-        image_cache_localize(&display->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
+        image_cache_localize(&display->priv->image_cache, &alpha_blend.src_bitmap, &img1, drawable);
         canvas->ops->draw_alpha_blend(canvas,
                                       &drawable->red_drawable->bbox, &clip, &alpha_blend);
         break;
@@ -1445,8 +1445,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_BLEND: {
         SpiceBlend blend = drawable->red_drawable->u.blend;
         SpiceImage img1, img2;
-        image_cache_localize(&display->image_cache, &blend.src_bitmap, &img1, drawable);
-        image_cache_localize_mask(&display->image_cache, &blend.mask, &img2);
+        image_cache_localize(&display->priv->image_cache, &blend.src_bitmap, &img1, drawable);
+        image_cache_localize_mask(&display->priv->image_cache, &blend.mask, &img2);
         canvas->ops->draw_blend(canvas, &drawable->red_drawable->bbox,
                                 &clip, &blend);
         break;
@@ -1454,7 +1454,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_BLACKNESS: {
         SpiceBlackness blackness = drawable->red_drawable->u.blackness;
         SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &blackness.mask, &img1);
+        image_cache_localize_mask(&display->priv->image_cache, &blackness.mask, &img1);
         canvas->ops->draw_blackness(canvas,
                                     &drawable->red_drawable->bbox, &clip, &blackness);
         break;
@@ -1462,7 +1462,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_WHITENESS: {
         SpiceWhiteness whiteness = drawable->red_drawable->u.whiteness;
         SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &whiteness.mask, &img1);
+        image_cache_localize_mask(&display->priv->image_cache, &whiteness.mask, &img1);
         canvas->ops->draw_whiteness(canvas,
                                     &drawable->red_drawable->bbox, &clip, &whiteness);
         break;
@@ -1470,7 +1470,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_INVERS: {
         SpiceInvers invers = drawable->red_drawable->u.invers;
         SpiceImage img1;
-        image_cache_localize_mask(&display->image_cache, &invers.mask, &img1);
+        image_cache_localize_mask(&display->priv->image_cache, &invers.mask, &img1);
         canvas->ops->draw_invers(canvas,
                                  &drawable->red_drawable->bbox, &clip, &invers);
         break;
@@ -1478,9 +1478,9 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_ROP3: {
         SpiceRop3 rop3 = drawable->red_drawable->u.rop3;
         SpiceImage img1, img2, img3;
-        image_cache_localize_brush(&display->image_cache, &rop3.brush, &img1);
-        image_cache_localize(&display->image_cache, &rop3.src_bitmap, &img2, drawable);
-        image_cache_localize_mask(&display->image_cache, &rop3.mask, &img3);
+        image_cache_localize_brush(&display->priv->image_cache, &rop3.brush, &img1);
+        image_cache_localize(&display->priv->image_cache, &rop3.src_bitmap, &img2, drawable);
+        image_cache_localize_mask(&display->priv->image_cache, &rop3.mask, &img3);
         canvas->ops->draw_rop3(canvas, &drawable->red_drawable->bbox,
                                &clip, &rop3);
         break;
@@ -1488,9 +1488,9 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_COMPOSITE: {
         SpiceComposite composite = drawable->red_drawable->u.composite;
         SpiceImage src, mask;
-        image_cache_localize(&display->image_cache, &composite.src_bitmap, &src, drawable);
+        image_cache_localize(&display->priv->image_cache, &composite.src_bitmap, &src, drawable);
         if (composite.mask_bitmap)
-            image_cache_localize(&display->image_cache, &composite.mask_bitmap, &mask, drawable);
+            image_cache_localize(&display->priv->image_cache, &composite.mask_bitmap, &mask, drawable);
         canvas->ops->draw_composite(canvas, &drawable->red_drawable->bbox,
                                     &clip, &composite);
         break;
@@ -1498,7 +1498,7 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_STROKE: {
         SpiceStroke stroke = drawable->red_drawable->u.stroke;
         SpiceImage img1;
-        image_cache_localize_brush(&display->image_cache, &stroke.brush, &img1);
+        image_cache_localize_brush(&display->priv->image_cache, &stroke.brush, &img1);
         canvas->ops->draw_stroke(canvas,
                                  &drawable->red_drawable->bbox, &clip, &stroke);
         break;
@@ -1506,8 +1506,8 @@ static void drawable_draw(DisplayChannel *display, Drawable *drawable)
     case QXL_DRAW_TEXT: {
         SpiceText text = drawable->red_drawable->u.text;
         SpiceImage img1, img2;
-        image_cache_localize_brush(&display->image_cache, &text.fore_brush, &img1);
-        image_cache_localize_brush(&display->image_cache, &text.back_brush, &img2);
+        image_cache_localize_brush(&display->priv->image_cache, &text.fore_brush, &img1);
+        image_cache_localize_brush(&display->priv->image_cache, &text.back_brush, &img2);
         canvas->ops->draw_text(canvas, &drawable->red_drawable->bbox,
                                &clip, &text);
         break;
@@ -1599,11 +1599,11 @@ void display_channel_draw_until(DisplayChannel *display, const SpiceRect *area,
     spice_return_if_fail(last);
     spice_return_if_fail(ring_item_is_linked(&last->list_link));
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
 
     if (surface_id != last->surface_id) {
         // find the nearest older drawable from the appropriate surface
-        ring = &display->current_list;
+        ring = &display->priv->current_list;
         ring_item = &last->list_link;
         while ((ring_item = ring_next(ring, ring_item))) {
             now = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
@@ -1644,7 +1644,7 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su
     spice_return_if_fail(area->left >= 0 && area->top >= 0 &&
                          area->left < area->right && area->top < area->bottom);
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
 
     last = current_find_intersects_rect(&surface->current_list, NULL, area);
     if (last)
@@ -1681,7 +1681,7 @@ void display_channel_update(DisplayChannel *display,
     red_get_rect_ptr(&rect, area);
     display_channel_draw(display, &rect, surface_id);
 
-    surface = &display->surfaces[surface_id];
+    surface = &display->priv->surfaces[surface_id];
     if (*qxl_dirty_rects == NULL) {
         *num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
         *qxl_dirty_rects = spice_new0(QXLRect, *num_dirty_rects);
@@ -1721,7 +1721,7 @@ void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t surf
 {
     if (!display_channel_validate_surface(display, surface_id))
         return;
-    if (!display->surfaces[surface_id].context.canvas)
+    if (!display->priv->surfaces[surface_id].context.canvas)
         return;
 
     draw_depend_on_me(display, surface_id);
@@ -1741,15 +1741,15 @@ void display_channel_destroy_surfaces(DisplayChannel *display)
     spice_debug(NULL);
     //to handle better
     for (i = 0; i < NUM_SURFACES; ++i) {
-        if (display->surfaces[i].context.canvas) {
+        if (display->priv->surfaces[i].context.canvas) {
             display_channel_destroy_surface_wait(display, i);
-            if (display->surfaces[i].context.canvas) {
+            if (display->priv->surfaces[i].context.canvas) {
                 display_channel_surface_unref(display, i);
             }
-            spice_assert(!display->surfaces[i].context.canvas);
+            spice_assert(!display->priv->surfaces[i].context.canvas);
         }
     }
-    spice_warn_if_fail(ring_is_empty(&display->streams));
+    spice_warn_if_fail(ring_is_empty(&display->priv->streams));
 
     if (red_channel_is_connected(RED_CHANNEL(display))) {
         red_channel_pipes_add_type(RED_CHANNEL(display), RED_PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
@@ -1780,8 +1780,8 @@ create_canvas_for_surface(DisplayChannel *display, RedSurface *surface, uint32_t
     case RED_RENDERER_SW:
         canvas = canvas_create_for_data(surface->context.width, surface->context.height, surface->context.format,
                                         surface->context.line_0, surface->context.stride,
-                                        &display->image_cache.base,
-                                        &display->image_surfaces, NULL, NULL, NULL);
+                                        &display->priv->image_cache.base,
+                                        &display->priv->image_surfaces, NULL, NULL, NULL);
         surface->context.top_down = TRUE;
         surface->context.canvas_draws_on_surface = TRUE;
         return canvas;
@@ -1796,7 +1796,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
                                     uint32_t height, int32_t stride, uint32_t format,
                                     void *line_0, int data_is_valid, int send_client)
 {
-    RedSurface *surface = &display->surfaces[surface_id];
+    RedSurface *surface = &display->priv->surfaces[surface_id];
 
     spice_warn_if_fail(!surface->context.canvas);
 
@@ -1821,7 +1821,7 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
     region_init(&surface->draw_dirty_region);
     surface->refs = 1;
 
-    if (display->renderer == RED_RENDERER_INVALID) {
+    if (display->priv->renderer == RED_RENDERER_INVALID) {
         int i;
         QXLInstance *qxl = display->common.qxl;
         RedsState *reds = red_qxl_get_server(qxl->st);
@@ -1830,12 +1830,12 @@ void display_channel_create_surface(DisplayChannel *display, uint32_t surface_id
             uint32_t renderer = g_array_index(renderers, uint32_t, i);
             surface->context.canvas = create_canvas_for_surface(display, surface, renderer);
             if (surface->context.canvas) {
-                display->renderer = renderer;
+                display->priv->renderer = renderer;
                 break;
             }
         }
     } else {
-        surface->context.canvas = create_canvas_for_surface(display, surface, display->renderer);
+        surface->context.canvas = create_canvas_for_surface(display, surface, display->priv->renderer);
     }
 
     spice_return_if_fail(surface->context.canvas);
@@ -1859,8 +1859,8 @@ static void on_disconnect(RedChannelClient *rcc)
 
     // this was the last channel client
     spice_debug("#draw=%d, #glz_draw=%d",
-                display->drawable_count,
-                display->encoder_shared_data.glz_drawable_count);
+                display->priv->drawable_count,
+                display->priv->encoder_shared_data.glz_drawable_count);
 }
 
 static int handle_migrate_flush_mark(RedChannelClient *rcc)
@@ -1887,11 +1887,12 @@ static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *messa
 
 static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id)
 {
-    DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
+    DisplayChannelPrivate *p = SPICE_CONTAINEROF(surfaces, DisplayChannelPrivate, image_surfaces);
+    DisplayChannel *display = p->pub;
 
     spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), NULL);
 
-    return display->surfaces[surface_id].context.canvas;
+    return display->priv->surfaces[surface_id].context.canvas;
 }
 
 DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker, 
@@ -1919,31 +1920,32 @@ DisplayChannel* display_channel_new(SpiceServer *reds, RedWorker *worker,
         SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER,
         &cbs, dcc_handle_message);
     spice_return_val_if_fail(display, NULL);
+    display->priv->pub = display;
 
     clockid_t stat_clock = CLOCK_THREAD_CPUTIME_ID;
-    stat_init(&display->add_stat, "add", stat_clock);
-    stat_init(&display->exclude_stat, "exclude", stat_clock);
-    stat_init(&display->__exclude_stat, "__exclude", stat_clock);
+    stat_init(&display->priv->add_stat, "add", stat_clock);
+    stat_init(&display->priv->exclude_stat, "exclude", stat_clock);
+    stat_init(&display->priv->__exclude_stat, "__exclude", stat_clock);
 #ifdef RED_STATISTICS
     RedChannel *channel = RED_CHANNEL(display);
-    display->cache_hits_counter = stat_add_counter(reds, channel->stat,
-                                                   "cache_hits", TRUE);
-    display->add_to_cache_counter = stat_add_counter(reds, channel->stat,
-                                                     "add_to_cache", TRUE);
-    display->non_cache_counter = stat_add_counter(reds, channel->stat,
-                                                  "non_cache", TRUE);
+    display->priv->cache_hits_counter = stat_add_counter(reds, channel->stat,
+                                                         "cache_hits", TRUE);
+    display->priv->add_to_cache_counter = stat_add_counter(reds, channel->stat,
+                                                           "add_to_cache", TRUE);
+    display->priv->non_cache_counter = stat_add_counter(reds, channel->stat,
+                                                        "non_cache", TRUE);
 #endif
-    image_encoder_shared_init(&display->encoder_shared_data);
+    image_encoder_shared_init(&display->priv->encoder_shared_data);
 
-    display->n_surfaces = n_surfaces;
-    display->renderer = RED_RENDERER_INVALID;
+    display->priv->n_surfaces = n_surfaces;
+    display->priv->renderer = RED_RENDERER_INVALID;
 
-    ring_init(&display->current_list);
-    display->image_surfaces.ops = &image_surfaces_ops;
+    ring_init(&display->priv->current_list);
+    display->priv->image_surfaces.ops = &image_surfaces_ops;
     drawables_init(display);
-    image_cache_init(&display->image_cache);
-    display->stream_video = stream_video;
-    display->video_codecs = g_array_ref(video_codecs);
+    image_cache_init(&display->priv->image_cache);
+    display->priv->stream_video = stream_video;
+    display->priv->video_codecs = g_array_ref(video_codecs);
     display_channel_init_streams(display);
 
     return display;
@@ -1957,11 +1959,11 @@ void display_channel_process_surface_cmd(DisplayChannel *display, RedSurfaceCmd
     uint8_t *data;
 
     surface_id = surface->surface_id;
-    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
+    if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) {
         return;
     }
 
-    red_surface = &display->surfaces[surface_id];
+    red_surface = &display->priv->surfaces[surface_id];
 
     switch (surface->type) {
     case QXL_SURFACE_CMD_CREATE: {
@@ -2001,18 +2003,18 @@ void display_channel_process_surface_cmd(DisplayChannel *display, RedSurfaceCmd
 void display_channel_update_compression(DisplayChannel *display, DisplayChannelClient *dcc)
 {
     if (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) {
-        display->enable_jpeg = dcc_is_low_bandwidth(dcc);
+        display->priv->enable_jpeg = dcc_is_low_bandwidth(dcc);
     } else {
-        display->enable_jpeg = (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
+        display->priv->enable_jpeg = (dcc_get_jpeg_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
     }
 
     if (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_AUTO) {
-        display->enable_zlib_glz_wrap = dcc_is_low_bandwidth(dcc);
+        display->priv->enable_zlib_glz_wrap = dcc_is_low_bandwidth(dcc);
     } else {
-        display->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
+        display->priv->enable_zlib_glz_wrap = (dcc_get_zlib_glz_state(dcc) == SPICE_WAN_COMPRESSION_ALWAYS);
     }
-    spice_info("jpeg %s", display->enable_jpeg ? "enabled" : "disabled");
-    spice_info("zlib-over-glz %s", display->enable_zlib_glz_wrap ? "enabled" : "disabled");
+    spice_info("jpeg %s", display->priv->enable_jpeg ? "enabled" : "disabled");
+    spice_info("zlib-over-glz %s", display->priv->enable_zlib_glz_wrap ? "enabled" : "disabled");
 }
 
 void display_channel_gl_scanout(DisplayChannel *display)
@@ -2024,7 +2026,7 @@ static void set_gl_draw_async_count(DisplayChannel *display, int num)
 {
     QXLInstance *qxl = display->common.qxl;
 
-    display->gl_draw_async_count = num;
+    display->priv->gl_draw_async_count = num;
 
     if (num == 0) {
         red_qxl_gl_draw_async_complete(qxl);
@@ -2035,7 +2037,7 @@ void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *dra
 {
     int num;
 
-    spice_return_if_fail(display->gl_draw_async_count == 0);
+    spice_return_if_fail(display->priv->gl_draw_async_count == 0);
 
     num = red_channel_pipes_new_add_push(RED_CHANNEL(display), dcc_gl_draw_item_new, draw);
     set_gl_draw_async_count(display, num);
@@ -2043,23 +2045,23 @@ void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *dra
 
 void display_channel_gl_draw_done(DisplayChannel *display)
 {
-    set_gl_draw_async_count(display, display->gl_draw_async_count - 1);
+    set_gl_draw_async_count(display, display->priv->gl_draw_async_count - 1);
 }
 
 int display_channel_get_stream_id(DisplayChannel *display, Stream *stream)
 {
-    return (int)(stream - display->streams_buf);
+    return (int)(stream - display->priv->streams_buf);
 }
 
 gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id)
 {
-    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
+    if SPICE_UNLIKELY(surface_id >= display->priv->n_surfaces) {
         spice_warning("invalid surface_id %u", surface_id);
         return FALSE;
     }
-    if (!display->surfaces[surface_id].context.canvas) {
+    if (!display->priv->surfaces[surface_id].context.canvas) {
         spice_warning("canvas address is %p for %d (and is NULL)\n",
-                   &(display->surfaces[surface_id].context.canvas), surface_id);
+                   &(display->priv->surfaces[surface_id].context.canvas), surface_id);
         spice_warning("failed on %d", surface_id);
         return FALSE;
     }
@@ -2071,29 +2073,41 @@ void display_channel_update_monitors_config(DisplayChannel *display,
                                             uint16_t count, uint16_t max_allowed)
 {
 
-    if (display->monitors_config)
-        monitors_config_unref(display->monitors_config);
+    if (display->priv->monitors_config)
+        monitors_config_unref(display->priv->monitors_config);
 
-    display->monitors_config =
+    display->priv->monitors_config =
         monitors_config_new(config->heads, count, max_allowed);
 }
 
 void set_monitors_config_to_primary(DisplayChannel *display)
 {
-    DrawContext *context = &display->surfaces[0].context;
+    DrawContext *context = &display->priv->surfaces[0].context;
     QXLHead head = { 0, };
 
-    spice_return_if_fail(display->surfaces[0].context.canvas);
+    spice_return_if_fail(display->priv->surfaces[0].context.canvas);
 
-    if (display->monitors_config)
-        monitors_config_unref(display->monitors_config);
+    if (display->priv->monitors_config)
+        monitors_config_unref(display->priv->monitors_config);
 
     head.width = context->width;
     head.height = context->height;
-    display->monitors_config = monitors_config_new(&head, 1, 1);
+    display->priv->monitors_config = monitors_config_new(&head, 1, 1);
 }
 
 void display_channel_reset_image_cache(DisplayChannel *self)
 {
-    image_cache_reset(&self->image_cache);
+    image_cache_reset(&self->priv->image_cache);
+}
+
+void display_channel_debug_oom(DisplayChannel *display, const char *msg)
+{
+    RedChannel *channel = RED_CHANNEL(display);
+
+    spice_debug("%s #draw=%u, #glz_draw=%u current %u pipes %u",
+                msg,
+                display->priv->drawable_count,
+                display->priv->encoder_shared_data.glz_drawable_count,
+                display->priv->current_size,
+                red_channel_sum_pipes_size(channel));
 }
diff --git a/server/display-channel.h b/server/display-channel.h
index ba62950..dd7ec8d 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -157,8 +157,12 @@ struct _Drawable {
     } u;
 };
 
-struct DisplayChannel {
-    CommonGraphicsChannel common; // Must be the first thing
+typedef struct DisplayChannelPrivate DisplayChannelPrivate;
+/* FIXME: move to separate file */
+struct DisplayChannelPrivate
+{
+    DisplayChannel *pub;
+
     uint32_t bits_unique;
 
     MonitorsConfig *monitors_config;
@@ -208,6 +212,11 @@ struct DisplayChannel {
     ImageEncoderSharedData encoder_shared_data;
 };
 
+struct DisplayChannel {
+    CommonGraphicsChannel common; // Must be the first thing
+
+    DisplayChannelPrivate priv[1];
+};
 
 #define FOREACH_DCC(channel, _link, _next, _data)                   \
     for (_link = (channel ? RED_CHANNEL(channel)->clients : NULL), \
@@ -296,6 +305,8 @@ gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surf
 gboolean display_channel_surface_has_canvas(DisplayChannel *display, uint32_t surface_id);
 void display_channel_reset_image_cache(DisplayChannel *self);
 
+void display_channel_debug_oom(DisplayChannel *display, const char *msg);
+
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
     SpicePathSeg *seg1, *seg2;
diff --git a/server/red-worker.c b/server/red-worker.c
index 6df6420..2cde7fd 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -676,7 +676,9 @@ static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
     display_channel_destroy_surface_wait(display, 0);
     display_channel_surface_unref(display, 0);
 
+    /* FIXME: accessing private data only for warning purposes...
     spice_warn_if_fail(ring_is_empty(&display->streams));
+    */
     spice_warn_if_fail(!display_channel_surface_has_canvas(display, surface_id));
 
     cursor_channel_reset(worker->cursor_channel);
@@ -771,11 +773,7 @@ static void handle_dev_oom(void *opaque, void *payload)
 
     spice_return_if_fail(worker->running);
     // streams? but without streams also leak
-    spice_debug("OOM1 #draw=%u, #glz_draw=%u current %u pipes %u",
-                display->drawable_count,
-                display->encoder_shared_data.glz_drawable_count,
-                display->current_size,
-                red_channel_sum_pipes_size(display_red_channel));
+    display_channel_debug_oom(display, "OOM1");
     while (red_process_display(worker, &ring_is_empty)) {
         red_channel_push(display_red_channel);
     }
@@ -783,11 +781,7 @@ static void handle_dev_oom(void *opaque, void *payload)
         display_channel_free_some(worker->display_channel);
         red_qxl_flush_resources(worker->qxl);
     }
-    spice_debug("OOM2 #draw=%u, #glz_draw=%u current %u pipes %u",
-                display->drawable_count,
-                display->encoder_shared_data.glz_drawable_count,
-                display->current_size,
-                red_channel_sum_pipes_size(display_red_channel));
+    display_channel_debug_oom(display, "OOM2");
     red_qxl_clear_pending(worker->qxl->st, RED_DISPATCHER_PENDING_OOM);
 }
 
diff --git a/server/stream.c b/server/stream.c
index 8997c10..4732dee 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -23,9 +23,9 @@
 
 #define FPS_TEST_INTERVAL 1
 #define FOREACH_STREAMS(display, item)                  \
-    for (item = ring_get_head(&(display)->streams);     \
+    for (item = ring_get_head(&(display)->priv->streams);     \
          item != NULL;                                  \
-         item = ring_next(&(display)->streams, item))
+         item = ring_next(&(display)->priv->streams, item))
 
 static void stream_agent_stats_print(StreamAgent *agent)
 {
@@ -121,25 +121,25 @@ void stream_stop(DisplayChannel *display, Stream *stream)
         red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), stream_destroy_item_new(stream_agent));
         stream_agent_stats_print(stream_agent);
     }
-    display->streams_size_total -= stream->width * stream->height;
+    display->priv->streams_size_total -= stream->width * stream->height;
     ring_remove(&stream->link);
     stream_unref(display, stream);
 }
 
 static void stream_free(DisplayChannel *display, Stream *stream)
 {
-    stream->next = display->free_streams;
-    display->free_streams = stream;
+    stream->next = display->priv->free_streams;
+    display->priv->free_streams = stream;
 }
 
 void display_channel_init_streams(DisplayChannel *display)
 {
     int i;
 
-    ring_init(&display->streams);
-    display->free_streams = NULL;
+    ring_init(&display->priv->streams);
+    display->priv->free_streams = NULL;
     for (i = 0; i < NUM_STREAMS; i++) {
-        Stream *stream = &display->streams_buf[i];
+        Stream *stream = &display->priv->streams_buf[i];
         ring_item_init(&stream->link);
         stream_free(display, stream);
     }
@@ -153,7 +153,7 @@ void stream_unref(DisplayChannel *display, Stream *stream)
     spice_warn_if_fail(!ring_item_is_linked(&stream->link));
 
     stream_free(display, stream);
-    display->stream_count--;
+    display->priv->stream_count--;
 }
 
 void stream_agent_unref(DisplayChannel *display, StreamAgent *agent)
@@ -197,7 +197,7 @@ static void update_copy_graduality(DisplayChannel *display, Drawable *drawable)
     SpiceBitmap *bitmap;
     spice_return_if_fail(drawable->red_drawable->type == QXL_DRAW_COPY);
 
-    if (display->stream_video != SPICE_STREAM_VIDEO_FILTER) {
+    if (display->priv->stream_video != SPICE_STREAM_VIDEO_FILTER) {
         drawable->copy_bitmap_graduality = BITMAP_GRADUAL_INVALID;
         return;
     }
@@ -406,11 +406,11 @@ static void before_reattach_stream(DisplayChannel *display,
 static Stream *display_channel_stream_try_new(DisplayChannel *display)
 {
     Stream *stream;
-    if (!display->free_streams) {
+    if (!display->priv->free_streams) {
         return NULL;
     }
-    stream = display->free_streams;
-    display->free_streams = display->free_streams->next;
+    stream = display->priv->free_streams;
+    display->priv->free_streams = display->priv->free_streams->next;
     return stream;
 }
 
@@ -430,7 +430,7 @@ static void display_channel_create_stream(DisplayChannel *display, Drawable *dra
     spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY);
     src_rect = &drawable->red_drawable->u.copy.src_area;
 
-    ring_add(&display->streams, &stream->link);
+    ring_add(&display->priv->streams, &stream->link);
     stream->current = drawable;
     stream->last_time = drawable->creation_time;
     stream->width = src_rect->right - src_rect->left;
@@ -452,13 +452,13 @@ static void display_channel_create_stream(DisplayChannel *display, Drawable *dra
     }
     stream->num_input_frames = 0;
     stream->input_fps_start_time = drawable->creation_time;
-    display->streams_size_total += stream->width * stream->height;
-    display->stream_count++;
+    display->priv->streams_size_total += stream->width * stream->height;
+    display->priv->stream_count++;
     FOREACH_CLIENT(display, link, next, dcc) {
         dcc_create_stream(dcc, stream);
     }
     spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps",
-                (int)(stream - display->streams_buf), stream->width,
+                (int)(stream - display->priv->streams_buf), stream->width,
                 stream->height, stream->dest_area.left, stream->dest_area.top,
                 stream->dest_area.right, stream->dest_area.bottom,
                 stream->input_fps);
@@ -530,7 +530,7 @@ void stream_trace_update(DisplayChannel *display, Drawable *drawable)
         }
     }
 
-    trace = display->items_trace;
+    trace = display->priv->items_trace;
     trace_end = trace + NUM_TRACE_ITEMS;
     for (; trace < trace_end; trace++) {
         if (is_next_stream_frame(display, drawable, trace->width, trace->height,
@@ -597,7 +597,7 @@ static void dcc_update_streams_max_latency(DisplayChannelClient *dcc, StreamAgen
     }
 
     dcc_set_max_stream_latency(dcc, 0);
-    if (DCC_TO_DC(dcc)->stream_count == 1) {
+    if (DCC_TO_DC(dcc)->priv->stream_count == 1) {
         return;
     }
     for (i = 0; i < NUM_STREAMS; i++) {
@@ -656,7 +656,7 @@ static uint64_t get_initial_bit_rate(DisplayChannelClient *dcc, Stream *stream)
     /* dividing the available bandwidth among the active streams, and saving
      * (1-RED_STREAM_CHANNEL_CAPACITY) of it for other messages */
     return (RED_STREAM_CHANNEL_CAPACITY * bit_rate *
-            stream->width * stream->height) / DCC_TO_DC(dcc)->streams_size_total;
+            stream->width * stream->height) / DCC_TO_DC(dcc)->priv->streams_size_total;
 }
 
 static uint32_t get_roundtrip_ms(void *opaque)
@@ -729,8 +729,8 @@ static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc,
     int client_has_multi_codec = red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_MULTI_CODEC);
     int i;
 
-    for (i = 0; i < display->video_codecs->len; i++) {
-        RedVideoCodec* video_codec = &g_array_index (display->video_codecs, RedVideoCodec, i);
+    for (i = 0; i < display->priv->video_codecs->len; i++) {
+        RedVideoCodec* video_codec = &g_array_index (display->priv->video_codecs, RedVideoCodec, i);
 
         if (!client_has_multi_codec &&
             video_codec->type != SPICE_VIDEO_CODEC_TYPE_MJPEG) {
@@ -924,7 +924,7 @@ static void detach_stream_gracefully(DisplayChannel *display, Stream *stream,
  */
 void stream_detach_behind(DisplayChannel *display, QRegion *region, Drawable *drawable)
 {
-    Ring *ring = &display->streams;
+    Ring *ring = &display->priv->streams;
     RingItem *item = ring_get_head(ring);
     GList *link, *next;
     DisplayChannelClient *dcc;
@@ -960,7 +960,7 @@ void stream_detach_and_stop(DisplayChannel *display)
     RingItem *stream_item;
 
     spice_debug(NULL);
-    while ((stream_item = ring_get_head(&display->streams))) {
+    while ((stream_item = ring_get_head(&display->priv->streams))) {
         Stream *stream = SPICE_CONTAINEROF(stream_item, Stream, link);
 
         detach_stream_gracefully(display, stream, NULL);
@@ -970,7 +970,7 @@ void stream_detach_and_stop(DisplayChannel *display)
 
 void stream_timeout(DisplayChannel *display)
 {
-    Ring *ring = &display->streams;
+    Ring *ring = &display->priv->streams;
     RingItem *item;
 
     red_time_t now = spice_get_monotonic_time_ns();
@@ -993,7 +993,7 @@ void stream_trace_add_drawable(DisplayChannel *display, Drawable *item)
         return;
     }
 
-    trace = &display->items_trace[display->next_item_trace++ & ITEMS_TRACE_MASK];
+    trace = &display->priv->items_trace[display->priv->next_item_trace++ & ITEMS_TRACE_MASK];
     trace->time = item->creation_time;
     trace->first_frame_time = item->first_frame_time;
     trace->frames_count = item->frames_count;
commit fede3f38c5a37d6dd9bb2c9170298bf8d7b51449
Author: Jonathon Jongsma <jjongsma at redhat.com>
Date:   Thu Sep 15 11:05:01 2016 -0500

    Improve encapsulation of DisplayChannel
    
    Add a couple new functions to the header so that they can be called by
    other objects rather than poking into the internals of the struct.

diff --git a/server/dcc-send.c b/server/dcc-send.c
index 1d32276..7f28eae 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -94,7 +94,7 @@ static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
     QRegion lossy_region;
     DisplayChannel *display = DCC_TO_DC(dcc);
 
-    spice_return_val_if_fail(validate_surface(display, surface_id), FALSE);
+    spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), FALSE);
 
     surface = &display->surfaces[surface_id];
     surface_lossy_region = &dcc->priv->surface_client_lossy_region[surface_id];
@@ -403,7 +403,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
         RedSurface *surface;
 
         surface_id = simage->u.surface.surface_id;
-        if (!validate_surface(display, surface_id)) {
+        if (!display_channel_validate_surface(display, surface_id)) {
             spice_warning("Invalid surface in SPICE_IMAGE_TYPE_SURFACE");
             pthread_mutex_unlock(&dcc->priv->pixmap_cache->lock);
             return FILL_BITS_TYPE_SURFACE;
@@ -1694,7 +1694,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
         return FALSE;
     }
 
-    StreamAgent *agent = &dcc->priv->stream_agents[get_stream_id(display, stream)];
+    StreamAgent *agent = &dcc->priv->stream_agents[display_channel_get_stream_id(display, stream)];
     uint64_t time_now = spice_get_monotonic_time_ns();
 
     if (!dcc->priv->use_video_encoder_rate_control) {
@@ -1740,7 +1740,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
 
         red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL);
 
-        stream_data.base.id = get_stream_id(display, stream);
+        stream_data.base.id = display_channel_get_stream_id(display, stream);
         stream_data.base.multi_media_time = frame_mm_time;
         stream_data.data_size = outbuf->size;
 
@@ -1750,7 +1750,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc,
 
         red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL);
 
-        stream_data.base.id = get_stream_id(display, stream);
+        stream_data.base.id = display_channel_get_stream_id(display, stream);
         stream_data.base.multi_media_time = frame_mm_time;
         stream_data.data_size = outbuf->size;
         stream_data.width = copy->src_area.right - copy->src_area.left;
@@ -2159,7 +2159,7 @@ static void marshall_stream_start(RedChannelClient *rcc,
     SpiceClipRects clip_rects;
 
     stream_create.surface_id = 0;
-    stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream);
+    stream_create.id = display_channel_get_stream_id(DCC_TO_DC(dcc), stream);
     stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
     stream_create.codec_type = agent->video_encoder->codec_type;
 
@@ -2195,7 +2195,7 @@ static void marshall_stream_clip(RedChannelClient *rcc,
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base);
     SpiceMsgDisplayStreamClip stream_clip;
 
-    stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
+    stream_clip.id = display_channel_get_stream_id(DCC_TO_DC(dcc), agent->stream);
     stream_clip.clip.type = item->clip_type;
     stream_clip.clip.rects = item->rects;
 
@@ -2209,7 +2209,7 @@ static void marshall_stream_end(RedChannelClient *rcc,
     SpiceMsgDisplayStreamDestroy destroy;
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
-    destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream);
+    destroy.id = display_channel_get_stream_id(DCC_TO_DC(dcc), agent->stream);
     stream_agent_stop(agent);
     spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
 }
diff --git a/server/display-channel.c b/server/display-channel.c
index 108e69b..23f2873 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -203,6 +203,13 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id)
     spice_warn_if_fail(ring_is_empty(&surface->depend_on_me));
 }
 
+/* TODO: perhaps rename to "ready" or "realized" ? */
+gboolean display_channel_surface_has_canvas(DisplayChannel *display,
+                                            uint32_t surface_id)
+{
+    return display->surfaces[surface_id].context.canvas != NULL;
+}
+
 static void streams_update_visible_region(DisplayChannel *display, Drawable *drawable)
 {
     Ring *ring;
@@ -232,7 +239,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra
         }
 
         FOREACH_CLIENT(display, link, next, dcc) {
-            agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+            agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
 
             if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
                 region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
@@ -955,7 +962,7 @@ static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable
         /* surface_id must be validated before calling into
          * validate_drawable_bbox
          */
-        if (!validate_surface(display, drawable->surface_id)) {
+        if (!display_channel_validate_surface(display, drawable->surface_id)) {
             return FALSE;
         }
         context = &display->surfaces[surface_id].context;
@@ -998,7 +1005,7 @@ static Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t e
     }
     for (x = 0; x < 3; ++x) {
         if (red_drawable->surface_deps[x] != -1
-            && !validate_surface(display, red_drawable->surface_deps[x])) {
+            && !display_channel_validate_surface(display, red_drawable->surface_deps[x])) {
             return NULL;
         }
     }
@@ -1669,7 +1676,7 @@ void display_channel_update(DisplayChannel *display,
     SpiceRect rect;
     RedSurface *surface;
 
-    spice_return_if_fail(validate_surface(display, surface_id));
+    spice_return_if_fail(display_channel_validate_surface(display, surface_id));
 
     red_get_rect_ptr(&rect, area);
     display_channel_draw(display, &rect, surface_id);
@@ -1712,7 +1719,7 @@ static void display_channel_destroy_surface(DisplayChannel *display, uint32_t su
 
 void display_channel_destroy_surface_wait(DisplayChannel *display, uint32_t surface_id)
 {
-    if (!validate_surface(display, surface_id))
+    if (!display_channel_validate_surface(display, surface_id))
         return;
     if (!display->surfaces[surface_id].context.canvas)
         return;
@@ -1882,7 +1889,7 @@ static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t su
 {
     DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces);
 
-    spice_return_val_if_fail(validate_surface(display, surface_id), NULL);
+    spice_return_val_if_fail(display_channel_validate_surface(display, surface_id), NULL);
 
     return display->surfaces[surface_id].context.canvas;
 }
@@ -2038,3 +2045,55 @@ void display_channel_gl_draw_done(DisplayChannel *display)
 {
     set_gl_draw_async_count(display, display->gl_draw_async_count - 1);
 }
+
+int display_channel_get_stream_id(DisplayChannel *display, Stream *stream)
+{
+    return (int)(stream - display->streams_buf);
+}
+
+gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id)
+{
+    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
+        spice_warning("invalid surface_id %u", surface_id);
+        return FALSE;
+    }
+    if (!display->surfaces[surface_id].context.canvas) {
+        spice_warning("canvas address is %p for %d (and is NULL)\n",
+                   &(display->surfaces[surface_id].context.canvas), surface_id);
+        spice_warning("failed on %d", surface_id);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+void display_channel_update_monitors_config(DisplayChannel *display,
+                                            QXLMonitorsConfig *config,
+                                            uint16_t count, uint16_t max_allowed)
+{
+
+    if (display->monitors_config)
+        monitors_config_unref(display->monitors_config);
+
+    display->monitors_config =
+        monitors_config_new(config->heads, count, max_allowed);
+}
+
+void set_monitors_config_to_primary(DisplayChannel *display)
+{
+    DrawContext *context = &display->surfaces[0].context;
+    QXLHead head = { 0, };
+
+    spice_return_if_fail(display->surfaces[0].context.canvas);
+
+    if (display->monitors_config)
+        monitors_config_unref(display->monitors_config);
+
+    head.width = context->width;
+    head.height = context->height;
+    display->monitors_config = monitors_config_new(&head, 1, 1);
+}
+
+void display_channel_reset_image_cache(DisplayChannel *self)
+{
+    image_cache_reset(&self->image_cache);
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 7b71480..ba62950 100644
--- a/server/display-channel.h
+++ b/server/display-channel.h
@@ -208,10 +208,17 @@ struct DisplayChannel {
     ImageEncoderSharedData encoder_shared_data;
 };
 
-static inline int get_stream_id(DisplayChannel *display, Stream *stream)
-{
-    return (int)(stream - display->streams_buf);
-}
+
+#define FOREACH_DCC(channel, _link, _next, _data)                   \
+    for (_link = (channel ? RED_CHANNEL(channel)->clients : NULL), \
+         _next = (_link ? _link->next : NULL), \
+         _data = (_link ? _link->data : NULL); \
+         _link; \
+         _link = _next, \
+         _next = (_link ? _link->next : NULL), \
+         _data = (_link ? _link->data : NULL))
+
+int display_channel_get_stream_id(DisplayChannel *display, Stream *stream);
 
 typedef struct RedSurfaceDestroyItem {
     RedPipeItem pipe_item;
@@ -281,20 +288,13 @@ void                       display_channel_gl_draw                   (DisplayCha
                                                                       SpiceMsgDisplayGlDraw *draw);
 void                       display_channel_gl_draw_done              (DisplayChannel *display);
 
-static inline int validate_surface(DisplayChannel *display, uint32_t surface_id)
-{
-    if SPICE_UNLIKELY(surface_id >= display->n_surfaces) {
-        spice_warning("invalid surface_id %u", surface_id);
-        return 0;
-    }
-    if (!display->surfaces[surface_id].context.canvas) {
-        spice_warning("canvas address is %p for %d (and is NULL)\n",
-                   &(display->surfaces[surface_id].context.canvas), surface_id);
-        spice_warning("failed on %d", surface_id);
-        return 0;
-    }
-    return 1;
-}
+void display_channel_update_monitors_config(DisplayChannel *display, QXLMonitorsConfig *config,
+                                            uint16_t count, uint16_t max_allowed);
+void set_monitors_config_to_primary(DisplayChannel *display);
+
+gboolean display_channel_validate_surface(DisplayChannel *display, uint32_t surface_id);
+gboolean display_channel_surface_has_canvas(DisplayChannel *display, uint32_t surface_id);
+void display_channel_reset_image_cache(DisplayChannel *self);
 
 static inline int is_equal_path(SpicePath *path1, SpicePath *path2)
 {
diff --git a/server/red-worker.c b/server/red-worker.c
index 590412b..6df6420 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -247,7 +247,7 @@ static int red_process_display(RedWorker *worker, int *ring_is_empty)
                                    &update, ext_cmd.cmd.data)) {
                 break;
             }
-            if (!validate_surface(worker->display_channel, update.surface_id)) {
+            if (!display_channel_validate_surface(worker->display_channel, update.surface_id)) {
                 spice_warning("Invalid surface in QXL_CMD_UPDATE");
             } else {
                 display_channel_draw(worker->display_channel, &update.area, update.surface_id);
@@ -587,18 +587,6 @@ static void handle_dev_destroy_surfaces(void *opaque, void *payload)
     cursor_channel_reset(worker->cursor_channel);
 }
 
-static void display_update_monitors_config(DisplayChannel *display,
-                                           QXLMonitorsConfig *config,
-                                           uint16_t count, uint16_t max_allowed)
-{
-
-    if (display->monitors_config)
-        monitors_config_unref(display->monitors_config);
-
-    display->monitors_config =
-        monitors_config_new(config->heads, count, max_allowed);
-}
-
 static void red_worker_push_monitors_config(RedWorker *worker)
 {
     DisplayChannelClient *dcc;
@@ -609,21 +597,6 @@ static void red_worker_push_monitors_config(RedWorker *worker)
     }
 }
 
-static void set_monitors_config_to_primary(DisplayChannel *display)
-{
-    DrawContext *context = &display->surfaces[0].context;
-    QXLHead head = { 0, };
-
-    spice_return_if_fail(display->surfaces[0].context.canvas);
-
-    if (display->monitors_config)
-        monitors_config_unref(display->monitors_config);
-
-    head.width = context->width;
-    head.height = context->height;
-    display->monitors_config = monitors_config_new(&head, 1, 1);
-}
-
 static void dev_create_primary_surface(RedWorker *worker, uint32_t surface_id,
                                        QXLDevSurfaceCreate surface)
 {
@@ -689,12 +662,12 @@ static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
 {
     DisplayChannel *display = worker->display_channel;
 
-    if (!validate_surface(display, surface_id))
+    if (!display_channel_validate_surface(display, surface_id))
         return;
     spice_warn_if_fail(surface_id == 0);
 
     spice_debug(NULL);
-    if (!display->surfaces[surface_id].context.canvas) {
+    if (!display_channel_surface_has_canvas(display, surface_id)) {
         spice_warning("double destroy of primary surface");
         return;
     }
@@ -704,7 +677,7 @@ static void destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
     display_channel_surface_unref(display, 0);
 
     spice_warn_if_fail(ring_is_empty(&display->streams));
-    spice_warn_if_fail(!display->surfaces[surface_id].context.canvas);
+    spice_warn_if_fail(!display_channel_surface_has_canvas(display, surface_id));
 
     cursor_channel_reset(worker->cursor_channel);
 }
@@ -828,9 +801,8 @@ static void handle_dev_reset_cursor(void *opaque, void *payload)
 static void handle_dev_reset_image_cache(void *opaque, void *payload)
 {
     RedWorker *worker = opaque;
-    DisplayChannel *display = worker->display_channel;
 
-    image_cache_reset(&display->image_cache);
+    display_channel_reset_image_cache(worker->display_channel);
 }
 
 static void handle_dev_destroy_surface_wait_async(void *opaque, void *payload)
@@ -950,9 +922,9 @@ static void handle_dev_monitors_config_async(void *opaque, void *payload)
         /* TODO: raise guest bug (requires added QXL interface) */
         return;
     }
-    display_update_monitors_config(worker->display_channel, dev_monitors_config,
-                                   MIN(count, msg->max_monitors),
-                                   MIN(max_allowed, msg->max_monitors));
+    display_channel_update_monitors_config(worker->display_channel, dev_monitors_config,
+                                           MIN(count, msg->max_monitors),
+                                           MIN(max_allowed, msg->max_monitors));
     red_worker_push_monitors_config(worker);
 }
 
diff --git a/server/stream.c b/server/stream.c
index 4819723..8997c10 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -101,11 +101,11 @@ void stream_stop(DisplayChannel *display, Stream *stream)
     spice_return_if_fail(ring_item_is_linked(&stream->link));
     spice_return_if_fail(!stream->current);
 
-    spice_debug("stream %d", get_stream_id(display, stream));
+    spice_debug("stream %d", display_channel_get_stream_id(display, stream));
     FOREACH_CLIENT(display, link, next, dcc) {
         StreamAgent *stream_agent;
 
-        stream_agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+        stream_agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
         region_clear(&stream_agent->vis_region);
         region_clear(&stream_agent->clip);
         if (stream_agent->video_encoder && dcc_use_video_encoder_rate_control(dcc)) {
@@ -302,7 +302,7 @@ static void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *s
         StreamAgent *agent;
         QRegion clip_in_draw_dest;
 
-        agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+        agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
         region_or(&agent->vis_region, &drawable->tree_item.base.rgn);
 
         region_init(&clip_in_draw_dest);
@@ -349,7 +349,7 @@ static void before_reattach_stream(DisplayChannel *display,
         return;
     }
 
-    index = get_stream_id(display, stream);
+    index = display_channel_get_stream_id(display, stream);
     DRAWABLE_FOREACH_DPI_SAFE(stream->current, ring_item, next, dpi) {
         dcc = dpi->dcc;
         agent = dcc_get_stream_agent(dcc, index);
@@ -759,7 +759,7 @@ static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc,
 
 void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
 {
-    StreamAgent *agent = dcc_get_stream_agent(dcc, get_stream_id(DCC_TO_DC(dcc), stream));
+    StreamAgent *agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(DCC_TO_DC(dcc), stream));
 
     spice_return_if_fail(region_is_empty(&agent->vis_region));
 
@@ -796,7 +796,7 @@ void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
         agent->report_id = rand();
         red_pipe_item_init(&report_pipe_item->pipe_item,
                            RED_PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT);
-        report_pipe_item->stream_id = get_stream_id(DCC_TO_DC(dcc), stream);
+        report_pipe_item->stream_id = display_channel_get_stream_id(DCC_TO_DC(dcc), stream);
         red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &report_pipe_item->pipe_item);
     }
 #ifdef STREAM_STATS
@@ -839,7 +839,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc,
                                          Drawable *update_area_limit)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
-    int stream_id = get_stream_id(display, stream);
+    int stream_id = display_channel_get_stream_id(display, stream);
     StreamAgent *agent = dcc_get_stream_agent(dcc, stream_id);
 
     /* stopping the client from playing older frames at once*/
@@ -936,12 +936,12 @@ void stream_detach_behind(DisplayChannel *display, QRegion *region, Drawable *dr
         item = ring_next(ring, item);
 
         FOREACH_CLIENT(display, link, next, dcc) {
-            StreamAgent *agent = dcc_get_stream_agent(dcc, get_stream_id(display, stream));
+            StreamAgent *agent = dcc_get_stream_agent(dcc, display_channel_get_stream_id(display, stream));
 
             if (region_intersects(&agent->vis_region, region)) {
                 dcc_detach_stream_gracefully(dcc, stream, drawable);
                 detach = 1;
-                spice_debug("stream %d", get_stream_id(display, stream));
+                spice_debug("stream %d", display_channel_get_stream_id(display, stream));
             }
         }
         if (detach && stream->current) {


More information about the Spice-commits mailing list