[Spice-devel] [RFC v4 29/62] server/red_worker: split display and cursor channels

Alon Levy alevy at redhat.com
Tue Apr 26 03:54:54 PDT 2011


Introduce DisplayChannelClient, CursorChannelClient, CommonChannelClient.
don't disconnect channel on client disconnect.
Move all caches to the ChannelClient's.

Remove reference counting of the channel - need to split this to a separate
patch. The rationalization for this:
/* TODO: Why do we reference count the listener?
 * really - what's the lifecycle of a listener? isn't it from peer connection
 * until removal? the drawable's etc. have a valid lifetime outside of this, but
 * isn't the listener's lifetime exactly this?
 * This was meant to allow deletion of the display_channel itself - but now
 * we don't actually ever delete that.
 * */

No new functionality introduced.

TODO: fix crash:
Still have the possibility of crashing if too many disconnections happen at
once. Noticed that this happens if we call disconnect with two different channel
clients pointing to the same channel. should make sure the channel destruction
happens from a single thread? should only happen from main thread. check
by printing pthread_self.
---
 server/red_channel.c             |   12 -
 server/red_channel.h             |    2 -
 server/red_client_cache.h        |   54 +-
 server/red_client_shared_cache.h |   50 +-
 server/red_worker.c              | 1709 +++++++++++++++++++++-----------------
 5 files changed, 1019 insertions(+), 808 deletions(-)

diff --git a/server/red_channel.c b/server/red_channel.c
index b2d0cdb..4625158 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -840,23 +840,11 @@ void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc)
     rcc->ack_data.messages_window = 0;
 }
 
-void red_channel_ack_zero_messages_window(RedChannel *channel)
-{
-    red_channel_client_ack_zero_messages_window(channel->rcc);
-}
-
 void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window)
 {
     rcc->ack_data.client_window = client_window;
 }
 
-void red_channel_ack_set_client_window(RedChannel* channel, int client_window)
-{
-    if (channel->rcc) {
-        red_channel_client_ack_set_client_window(channel->rcc, client_window);
-    }
-}
-
 static void red_channel_client_unlink(RedChannelClient *rcc)
 {
     ring_remove(&rcc->client_link);
diff --git a/server/red_channel.h b/server/red_channel.h
index 44a40f0..261aa60 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -296,8 +296,6 @@ void red_channel_pipes_add_type(RedChannel *channel, int pipe_item_type);
 void red_channel_client_ack_zero_messages_window(RedChannelClient *rcc);
 void red_channel_client_ack_set_client_window(RedChannelClient *rcc, int client_window);
 void red_channel_client_push_set_ack(RedChannelClient *rcc);
-void red_channel_ack_zero_messages_window(RedChannel *channel);
-void red_channel_ack_set_client_window(RedChannel *channel, int client_window);
 void red_channel_push_set_ack(RedChannel *channel);
 
 /* TODO: This sets all clients to shut state - probably we want to close per channel */
diff --git a/server/red_client_cache.h b/server/red_client_cache.h
index 18ff47e..ea90b97 100644
--- a/server/red_client_cache.h
+++ b/server/red_client_cache.h
@@ -24,7 +24,7 @@
 #define FUNC_NAME(name) red_cursor_cache_##name
 #define VAR_NAME(name) cursor_cache_##name
 #define CHANNEL CursorChannel
-#define CHANNELCLIENT RedChannelClient
+#define CHANNELCLIENT CursorChannelClient
 
 #elif defined(CLIENT_PALETTE_CACHE)
 
@@ -35,7 +35,7 @@
 #define FUNC_NAME(name) red_palette_cache_##name
 #define VAR_NAME(name) palette_cache_##name
 #define CHANNEL DisplayChannel
-#define CHANNELCLIENT RedChannelClient
+#define CHANNELCLIENT DisplayChannelClient
 #else
 
 #error "no cache type."
@@ -44,14 +44,14 @@
 
 #define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
 
-static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
+static CacheItem *FUNC_NAME(find)(CHANNELCLIENT *channel_client, uint64_t id)
 {
-    CacheItem *item = channel->CACHE_NAME[CACHE_HASH_KEY(id)];
+    CacheItem *item = channel_client->CACHE_NAME[CACHE_HASH_KEY(id)];
 
     while (item) {
         if (item->id == id) {
             ring_remove(&item->u.cache_data.lru_link);
-            ring_add(&channel->VAR_NAME(lru), &item->u.cache_data.lru_link);
+            ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
             break;
         }
         item = item->u.cache_data.next;
@@ -62,10 +62,10 @@ static CacheItem *FUNC_NAME(find)(CHANNEL *channel, uint64_t id)
 static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
 {
     CacheItem **now;
-    CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
+    CHANNEL *channel = CHANNEL_FROM_RCC(&channel_client->common.base);
     ASSERT(item);
 
-    now = &channel->CACHE_NAME[CACHE_HASH_KEY(item->id)];
+    now = &channel_client->CACHE_NAME[CACHE_HASH_KEY(item->id)];
     for (;;) {
         ASSERT(*now);
         if (*now == item) {
@@ -75,56 +75,55 @@ static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
         now = &(*now)->u.cache_data.next;
     }
     ring_remove(&item->u.cache_data.lru_link);
-    channel->VAR_NAME(items)--;
-    channel->VAR_NAME(available) += item->size;
+    channel_client->VAR_NAME(items)--;
+    channel_client->VAR_NAME(available) += item->size;
 
     red_channel_pipe_item_init(&channel->common.base, &item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
-    red_channel_client_pipe_add_tail(channel_client, &item->u.pipe_data); // for now
+    red_channel_client_pipe_add_tail(&channel_client->common.base, &item->u.pipe_data); // for now
 }
 
 static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
 {
-    CHANNEL *channel = CHANNEL_FROM_RCC(channel_client);
     CacheItem *item;
     int key;
 
     item = spice_new(CacheItem, 1);
 
-    channel->VAR_NAME(available) -= size;
-    while (channel->VAR_NAME(available) < 0) {
-        CacheItem *tail = (CacheItem *)ring_get_tail(&channel->VAR_NAME(lru));
+    channel_client->VAR_NAME(available) -= size;
+    while (channel_client->VAR_NAME(available) < 0) {
+        CacheItem *tail = (CacheItem *)ring_get_tail(&channel_client->VAR_NAME(lru));
         if (!tail) {
-            channel->VAR_NAME(available) += size;
+            channel_client->VAR_NAME(available) += size;
             free(item);
             return FALSE;
         }
         FUNC_NAME(remove)(channel_client, tail);
     }
-    ++channel->VAR_NAME(items);
-    item->u.cache_data.next = channel->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
-    channel->CACHE_NAME[key] = item;
+    ++channel_client->VAR_NAME(items);
+    item->u.cache_data.next = channel_client->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
+    channel_client->CACHE_NAME[key] = item;
     ring_item_init(&item->u.cache_data.lru_link);
-    ring_add(&channel->VAR_NAME(lru), &item->u.cache_data.lru_link);
+    ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
     item->id = id;
     item->size = size;
     item->inval_type = CACHE_INVAL_TYPE;
     return TRUE;
 }
 
-static void FUNC_NAME(reset)(CHANNEL *channel, long size)
+static void FUNC_NAME(reset)(CHANNELCLIENT *channel_client, long size)
 {
     int i;
 
     for (i = 0; i < CACHE_HASH_SIZE; i++) {
-        while (channel->CACHE_NAME[i]) {
-            CacheItem *item = channel->CACHE_NAME[i];
-            channel->CACHE_NAME[i] = item->u.cache_data.next;
+        while (channel_client->CACHE_NAME[i]) {
+            CacheItem *item = channel_client->CACHE_NAME[i];
+            channel_client->CACHE_NAME[i] = item->u.cache_data.next;
             free(item);
         }
     }
-    ring_init(&channel->VAR_NAME(lru));
-    channel->VAR_NAME(available) = size;
-    channel->VAR_NAME(items) = 0;
+    ring_init(&channel_client->VAR_NAME(lru));
+    channel_client->VAR_NAME(available) = size;
+    channel_client->VAR_NAME(items) = 0;
 }
 
 
@@ -136,4 +135,5 @@ static void FUNC_NAME(reset)(CHANNEL *channel, long size)
 #undef FUNC_NAME
 #undef VAR_NAME
 #undef CHANNEL
-
+#undef CHANNELCLIENT
+#undef CHANNEL_FROM_RCC
\ No newline at end of file
diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
index 9b4b01c..533fb67 100644
--- a/server/red_client_shared_cache.h
+++ b/server/red_client_shared_cache.h
@@ -26,7 +26,6 @@
 #define FUNC_NAME(name) pixmap_cache_##name
 #define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
 #define CHANNEL DisplayChannel
-#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF(rcc->channel, CHANNEL, common.base);
 #define CACH_GENERATION pixmap_cache_generation
 #define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
 #else
@@ -35,14 +34,14 @@
 
 #endif
 
+#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
 
-static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClient *rcc)
+static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
 {
-    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     NewCacheItem *item;
     uint64_t serial;
 
-    serial = red_channel_client_get_message_serial(rcc);
+    serial = red_channel_client_get_message_serial(&dcc->common.base);
     pthread_mutex_lock(&cache->lock);
     item = cache->hash_table[CACHE_HASH_KEY(id)];
 
@@ -50,9 +49,9 @@ static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, RedChannelClien
         if (item->id == id) {
             ring_remove(&item->lru_link);
             ring_add(&cache->lru, &item->lru_link);
-            ASSERT(channel->common.id < MAX_CACHE_CLIENTS)
-            item->sync[channel->common.id] = serial;
-            cache->sync[channel->common.id] = serial;
+            ASSERT(dcc->common.id < MAX_CACHE_CLIENTS)
+            item->sync[dcc->common.id] = serial;
+            cache->sync[dcc->common.id] = serial;
             *lossy = item->lossy;
             break;
         }
@@ -81,9 +80,8 @@ static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
     return !!item;
 }
 
-static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, RedChannelClient *rcc)
+static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc)
 {
-    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     NewCacheItem *item;
     uint64_t serial;
     int key;
@@ -91,14 +89,15 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
     ASSERT(size > 0);
 
     item = spice_new(NewCacheItem, 1);
-    serial = red_channel_client_get_message_serial(rcc);
+    serial = red_channel_client_get_message_serial(&dcc->common.base);
 
     pthread_mutex_lock(&cache->lock);
 
-    if (cache->generation != channel->CACH_GENERATION) {
-        if (!channel->pending_pixmaps_sync) {
-            red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_PIXMAP_SYNC);
-            channel->pending_pixmaps_sync = TRUE;
+    if (cache->generation != dcc->CACH_GENERATION) {
+        if (!dcc->pending_pixmaps_sync) {
+            red_channel_client_pipe_add_type(
+                &dcc->common.base, PIPE_ITEM_TYPE_PIXMAP_SYNC);
+            dcc->pending_pixmaps_sync = TRUE;
         }
         pthread_mutex_unlock(&cache->lock);
         free(item);
@@ -111,7 +110,7 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
         NewCacheItem **now;
 
         if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) ||
-                                                   tail->sync[channel->common.id] == serial) {
+                                                   tail->sync[dcc->common.id] == serial) {
             cache->available += size;
             pthread_mutex_unlock(&cache->lock);
             free(item);
@@ -130,8 +129,8 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
         ring_remove(&tail->lru_link);
         cache->items--;
         cache->available += tail->size;
-        cache->sync[channel->common.id] = serial;
-        display_channel_push_release(channel, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
+        cache->sync[dcc->common.id] = serial;
+        display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
         free(tail);
     }
     ++cache->items;
@@ -143,8 +142,8 @@ static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, R
     item->size = size;
     item->lossy = lossy;
     memset(item->sync, 0, sizeof(item->sync));
-    item->sync[channel->common.id] = serial;
-    cache->sync[channel->common.id] = serial;
+    item->sync[dcc->common.id] = serial;
+    cache->sync[dcc->common.id] = serial;
     pthread_mutex_unlock(&cache->lock);
     return TRUE;
 }
@@ -169,25 +168,24 @@ static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
     cache->items = 0;
 }
 
-static void FUNC_NAME(reset)(CACHE *cache, RedChannelClient *rcc, SpiceMsgWaitForChannels* sync_data)
+static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
 {
-    CHANNEL *channel = CHANNEL_FROM_RCC(rcc);
     uint8_t wait_count;
     uint64_t serial;
     uint32_t i;
 
-    serial = red_channel_client_get_message_serial(rcc);
+    serial = red_channel_client_get_message_serial(&dcc->common.base);
     pthread_mutex_lock(&cache->lock);
     PRIVATE_FUNC_NAME(clear)(cache);
 
-    channel->CACH_GENERATION = ++cache->generation;
-    cache->generation_initiator.client = channel->common.id;
+    dcc->CACH_GENERATION = ++cache->generation;
+    cache->generation_initiator.client = dcc->common.id;
     cache->generation_initiator.message = serial;
-    cache->sync[channel->common.id] = serial;
+    cache->sync[dcc->common.id] = serial;
 
     wait_count = 0;
     for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
-        if (cache->sync[i] && i != channel->common.id) {
+        if (cache->sync[i] && i != dcc->common.id) {
             sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
             sync_data->wait_list[wait_count].channel_id = i;
             sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
diff --git a/server/red_worker.c b/server/red_worker.c
index 1c9bf1c..683df38 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -16,6 +16,16 @@
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
+/* Common variable abberiviations:
+ *
+ * rcc - RedChannelClient
+ * ccc - CursorChannelClient (not to be confused with common_cc)
+ * common_cc - CommonChannelClient
+ * dcc - DisplayChannelClient
+ * cursor_red_channel - downcast of CursorChannel to RedChannel
+ * display_red_channel - downcast of DisplayChannel to RedChannel
+ */
+
 #include <stdio.h>
 #include <stdarg.h>
 #include <sys/epoll.h>
@@ -467,9 +477,10 @@ typedef struct FreeList {
 } FreeList;
 
 typedef struct DisplayChannel DisplayChannel;
+typedef struct DisplayChannelClient DisplayChannelClient;
 
 typedef struct  {
-    DisplayChannel *display_channel;
+    DisplayChannelClient *dcc;
     RedCompressBuf *bufs_head;
     RedCompressBuf *bufs_tail;
     jmp_buf jmp_env;
@@ -537,7 +548,7 @@ struct RedGlzDrawable {
     GlzDrawableInstanceItem instances_pool[MAX_GLZ_DRAWABLE_INSTANCES];
     Ring instances;
     uint8_t instances_count;
-    DisplayChannel *display_channel;
+    DisplayChannelClient *dcc;
 };
 
 pthread_mutex_t glz_dictionary_list_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -556,16 +567,23 @@ typedef struct GlzSharedDictionary {
 
 typedef struct CommonChannel {
     RedChannel base; // Must be the first thing
-    EventListener listener;
-    uint32_t id;
+    event_listener_action_proc listener_action;
     struct RedWorker *worker;
     uint8_t recv_buf[RECIVE_BUF_SIZE];
+    uint32_t id_alloc; // bitfield. TODO - use this instead of shift scheme.
 } CommonChannel;
 
 typedef struct Surfaces Surfaces;
 
-struct DisplayChannel {
-    CommonChannel common; // Must be the first thing
+typedef struct CommonChannelClient {
+    RedChannelClient base;
+    EventListener listener;
+    uint32_t id;
+    Surfaces *surfaces;
+} CommonChannelClient;
+
+struct DisplayChannelClient {
+    CommonChannelClient common;
 
     int expect_init;
     int expect_migrate_mark;
@@ -580,7 +598,15 @@ struct DisplayChannel {
     long palette_cache_available;
     uint32_t palette_cache_items;
 
-    StreamAgent stream_agents[NUM_STREAMS];
+    struct {
+        uint32_t stream_outbuf_size;
+        uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
+
+        RedCompressBuf *free_compress_bufs;
+        RedCompressBuf *used_compress_bufs;
+
+        FreeList free_list;
+    } send_data;
 
     /* global lz encoding entities */
     GlzSharedDictionary *glz_dict;
@@ -594,15 +620,16 @@ struct DisplayChannel {
     uint8_t surface_client_created[NUM_SURFACES];
     QRegion surface_client_lossy_region[NUM_SURFACES];
 
-    struct {
-        uint32_t stream_outbuf_size;
-        uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!!
+    StreamAgent stream_agents[NUM_STREAMS];
+};
 
-        RedCompressBuf *free_compress_bufs;
-        RedCompressBuf *used_compress_bufs;
+struct DisplayChannel {
+    CommonChannel common; // Must be the first thing
 
-        FreeList free_list;
-    } send_data;
+    // only required for one client, can be the first (or choose it by speed
+    // and keep a pointer to it here?)
+    int expect_migrate_mark;
+    int expect_migrate_data;
 
     int enable_jpeg;
     int jpeg_quality;
@@ -624,13 +651,17 @@ struct DisplayChannel {
 #endif
 };
 
-typedef struct CursorChannel {
-    CommonChannel common; // Must be the first thing
+typedef struct CursorChannelClient {
+    CommonChannelClient common;
 
     CacheItem *cursor_cache[CURSOR_CACHE_HASH_SIZE];
     Ring cursor_cache_lru;
     long cursor_cache_available;
     uint32_t cursor_cache_items;
+} CursorChannelClient;
+
+typedef struct CursorChannel {
+    CommonChannel common; // Must be the first thing
 
 #ifdef RED_STATISTICS
     StatNodeRef stat;
@@ -820,6 +851,8 @@ struct Surfaces {
     uint32_t n_surfaces;
     SpiceImageSurfaces image_surfaces;
 
+    DisplayChannelClient *dcc; // NULL possible (iff no clients)
+
     Stream streams_buf[NUM_STREAMS];
     Stream *free_streams;
     Ring streams;
@@ -932,25 +965,26 @@ static void red_update_area_surfaces(RedWorker *worker, Surfaces *surfaces,
 #endif
 static void red_release_cursor(RedWorker *worker, CursorItem *cursor);
 static inline void release_drawable(RedWorker *worker, Surfaces *surfaces, Drawable *item);
-static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent);
+static void red_display_release_stream(Surfaces *surfaces, StreamAgent *agent);
 static inline void red_detach_stream(Surfaces *surfaces, Stream *stream);
-static void red_stop_stream(RedWorker *worker, Surfaces *surfaces, Stream *stream);
+static void red_stop_stream(Surfaces *surfaces, Stream *stream);
 static inline void red_stream_maintenance(RedWorker *worker,
                     Surfaces *surfaces, Drawable *candidate, Drawable *sect);
 static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller);
-static void red_release_pixmap_cache(DisplayChannel *channel);
-static void red_release_glz(DisplayChannel *channel);
-static void red_freeze_glz(DisplayChannel *channel);
-static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
+static void red_release_pixmap_cache(DisplayChannelClient *dcc);
+static void red_release_glz(DisplayChannelClient *dcc);
+static void red_freeze_glz(DisplayChannelClient *dcc);
+static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id,
                                          uint64_t* sync_data);
-static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item);
-static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel);
-static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable);
-static void reset_rate(RedWorker *worker, StreamAgent *stream_agent);
+static void red_display_release_stream_clip(Surfaces* surfaces, StreamClipItem *item);
+static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
+static void red_display_free_glz_drawable(DisplayChannelClient *dcc,
+                                          RedGlzDrawable *drawable);
+static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent);
 static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
 static inline int _stride_is_extra(SpiceBitmap *bitmap);
 static void red_disconnect_cursor(RedChannel *channel);
-static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item);
+static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item);
 
 #ifdef DUMP_BITMAP
 static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id);
@@ -1154,11 +1188,32 @@ static void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
     red_channel_client_pipe_add(rcc, &item->base);
 }
 
-static inline void red_create_surface_item(RedWorker *worker, int surface_id);
+static inline void red_create_surface_item(RedWorker *worker,
+                                           DisplayChannelClient *dcc, int surface_id);
 static void red_add_surface_image(RedWorker *worker, int surface_id);
+static void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
+{
+    RedChannelClient *rcc = channel->rcc;
+
+    if (!rcc) {
+        return;
+    }
+    red_pipe_add_verb(rcc, verb);
+}
 
-static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker, Drawable *drawable)
+#define DCC_TO_WORKER(dcc) \
+    (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker)
+
+#define DCC_TO_DC(dcc) SPICE_CONTAINEROF((dcc)->common.base.channel,\
+                                         DisplayChannel, common.base)
+
+#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base)
+#define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base)
+
+static inline void red_handle_drawable_surfaces_client_synced(
+                        DisplayChannelClient *dcc, Drawable *drawable)
 {
+    RedWorker *worker = DCC_TO_WORKER(dcc);
     int x;
 
     for (x = 0; x < 3; ++x) {
@@ -1166,20 +1221,20 @@ static inline void red_handle_drawable_surfaces_client_synced(RedWorker *worker,
 
         surface_id = drawable->surfaces_dest[x];
         if (surface_id != -1) {
-            if (worker->display_channel->surface_client_created[surface_id] == TRUE) {
+            if (dcc->surface_client_created[surface_id] == TRUE) {
                 continue;
             }
-            red_create_surface_item(worker, surface_id);
+            red_create_surface_item(worker, dcc, surface_id);
             red_current_flush(worker, &worker->surfaces, surface_id);
             red_add_surface_image(worker, surface_id);
         }
     }
 
-    if (worker->display_channel->surface_client_created[drawable->surface_id] == TRUE) {
+    if (dcc->surface_client_created[drawable->surface_id] == TRUE) {
         return;
     }
 
-    red_create_surface_item(worker, drawable->surface_id);
+    red_create_surface_item(worker, dcc, drawable->surface_id);
     red_current_flush(worker, &worker->surfaces, drawable->surface_id);
     red_add_surface_image(worker, drawable->surface_id);
 }
@@ -1196,16 +1251,16 @@ static int cursor_connected(RedWorker *worker)
         &worker->cursor_channel->common.base));
 }
 
-static inline void red_pipe_add_drawable(RedWorker *worker, Drawable *drawable)
+static inline void red_pipe_add_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
-    if (!display_connected(worker)) {
+    if (!dcc) {
         return;
     }
 
-    red_handle_drawable_surfaces_client_synced(worker, drawable);
+    red_handle_drawable_surfaces_client_synced(dcc, drawable);
 
     drawable->refs++;
-    red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &drawable->pipe_item);
+    red_channel_client_pipe_add(&dcc->common.base, &drawable->pipe_item);
 }
 
 static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *drawable)
@@ -1217,19 +1272,19 @@ static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *dr
     red_channel_client_pipe_add_tail(worker->display_channel->common.base.rcc, &drawable->pipe_item);
 }
 
-static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *drawable,
+static inline void red_pipe_add_drawable_after(DisplayChannelClient *dcc, Drawable *drawable,
                                                Drawable *pos_after)
 {
-    if (!display_connected(worker)) {
+    if (!dcc) {
         return;
     }
 
     if (!pos_after || !pipe_item_is_linked(&pos_after->pipe_item)) {
-        red_pipe_add_drawable(worker, drawable);
+        red_pipe_add_drawable(dcc, drawable);
         return;
     }
     drawable->refs++;
-    red_channel_client_pipe_add_after(worker->display_channel->common.base.rcc, &drawable->pipe_item, &pos_after->pipe_item);
+    red_channel_client_pipe_add_after(&dcc->common.base, &drawable->pipe_item, &pos_after->pipe_item);
 }
 
 static inline PipeItem *red_pipe_get_tail(RedWorker *worker)
@@ -1310,14 +1365,14 @@ static void common_release_recv_buf(RedChannelClient *rcc,
 #include "red_client_cache.h"
 #undef CLIENT_PALETTE_CACHE
 
-static void red_reset_palette_cache(DisplayChannel *display_channel)
+static void red_reset_palette_cache(DisplayChannelClient *dcc)
 {
-    red_palette_cache_reset(display_channel, CLIENT_PALETTE_CACHE_SIZE);
+    red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
 }
 
-static void red_reset_cursor_cache(CursorChannel *channel)
+static void red_reset_cursor_cache(RedChannelClient *rcc)
 {
-    red_cursor_cache_reset(channel, CLIENT_CURSOR_CACHE_SIZE);
+    red_cursor_cache_reset(RCC_TO_CCC(rcc), CLIENT_CURSOR_CACHE_SIZE);
 }
 
 static inline Drawable *alloc_drawable(RedWorker *worker)
@@ -1366,18 +1421,19 @@ static SurfaceDestroyItem *get_surface_destroy_item(RedChannel *channel,
     return destroy;
 }
 
-static inline void red_destroy_surface_item(RedWorker *worker, uint32_t surface_id)
+static inline void red_destroy_surface_item(RedWorker *worker,
+    DisplayChannelClient *dcc, uint32_t surface_id)
 {
     SurfaceDestroyItem *destroy;
     RedChannel *channel;
 
-    if (!display_connected(worker)) {
+    if (!dcc || !dcc->surface_client_created[surface_id]) {
         return;
     }
-    worker->display_channel->surface_client_created[surface_id] = FALSE;
+    dcc->surface_client_created[surface_id] = FALSE;
     channel = &worker->display_channel->common.base;
     destroy = get_surface_destroy_item(channel, surface_id);
-    red_channel_client_pipe_add(channel->rcc, &destroy->pipe_item);
+    red_channel_client_pipe_add(&dcc->common.base, &destroy->pipe_item);
 }
 
 static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces,
@@ -1402,7 +1458,7 @@ static inline void red_destroy_surface(RedWorker *worker, Surfaces *surfaces,
 
         region_destroy(&surface->draw_dirty_region);
         surface->context.canvas = NULL;
-        red_destroy_surface_item(worker, surface_id);
+        red_destroy_surface_item(worker, surfaces->dcc, surface_id);
 
         PANIC_ON(!ring_is_empty(&surface->depend_on_me));
     }
@@ -1684,20 +1740,22 @@ static void red_current_clear(RedWorker *worker, Surfaces *surfaces, int surface
     }
 }
 
-static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface_id, int force)
+static void red_clear_surface_drawables_from_pipe(DisplayChannelClient *dcc, int surface_id, int force)
 {
     Ring *ring;
     PipeItem *item;
     int x;
+    RedChannelClient *rcc;
 
-    if (!display_connected(worker)) {
+    if (!dcc) {
         return;
     }
 
     /* removing the newest drawables that their destination is surface_id and
        no other drawable depends on them */
 
-    ring = &worker->display_channel->common.base.rcc->pipe;
+    rcc = &dcc->common.base;
+    ring = &dcc->common.base.pipe;
     item = (PipeItem *) ring;
     while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) {
         Drawable *drawable;
@@ -1713,11 +1771,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
         if (drawable->surface_id == surface_id) {
             PipeItem *tmp_item = item;
             item = (PipeItem *)ring_prev(ring, (RingItem *)item);
-            ring_remove(&tmp_item->link);
-            worker->display_channel->common.base.release_item(
-                worker->display_channel->common.base.rcc, tmp_item, FALSE);
-            worker->display_channel->common.base.rcc->pipe_size--;
-
+            red_channel_client_pipe_remove_and_release(rcc, tmp_item);
             if (!item) {
                 item = (PipeItem *)ring;
             }
@@ -1741,7 +1795,7 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface
     }
 
     if (item) {
-        red_wait_pipe_item_sent(&worker->display_channel->common.base, item);
+        red_wait_pipe_item_sent(&dcc->common.base, item);
     }
 }
 
@@ -2145,10 +2199,10 @@ static inline void red_detach_stream(Surfaces *surfaces, Stream *stream)
     stream->current = NULL;
 }
 
-static StreamClipItem *__new_stream_clip(DisplayChannel* channel, StreamAgent *agent)
+static StreamClipItem *__new_stream_clip(DisplayChannelClient* dcc, StreamAgent *agent)
 {
     StreamClipItem *item = spice_new(StreamClipItem, 1);
-    red_channel_pipe_item_init(&channel->common.base,
+    red_channel_pipe_item_init(dcc->common.base.channel,
                     (PipeItem *)item, PIPE_ITEM_TYPE_STREAM_CLIP);
 
     item->stream_agent = agent;
@@ -2157,10 +2211,10 @@ static StreamClipItem *__new_stream_clip(DisplayChannel* channel, StreamAgent *a
     return item;
 }
 
-static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *agent,
+static void push_stream_clip_by_drawable(DisplayChannelClient* dcc, StreamAgent *agent,
                                          Drawable *drawable)
 {
-    StreamClipItem *item = __new_stream_clip(channel, agent);
+    StreamClipItem *item = __new_stream_clip(dcc, agent);
     int n_rects;
 
     if (!item) {
@@ -2179,12 +2233,12 @@ static void push_stream_clip_by_drawable(DisplayChannel* channel, StreamAgent *a
         item->rects->num_rects = n_rects;
         region_ret_rects(&drawable->tree_item.base.rgn, item->rects->rects, n_rects);
     }
-    red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
+    red_channel_client_pipe_add(&dcc->common.base, (PipeItem *)item);
 }
 
-static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
+static void push_stream_clip(DisplayChannelClient* dcc, StreamAgent *agent)
 {
-    StreamClipItem *item = __new_stream_clip(channel, agent);
+    StreamClipItem *item = __new_stream_clip(dcc, agent);
     int n_rects;
 
     if (!item) {
@@ -2197,13 +2251,13 @@ static void push_stream_clip(DisplayChannel* channel, StreamAgent *agent)
     item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
     item->rects->num_rects = n_rects;
     region_ret_rects(&agent->vis_region, item->rects->rects, n_rects);
-    red_channel_client_pipe_add(channel->common.base.rcc, (PipeItem *)item);
+    red_channel_client_pipe_add(&dcc->common.base, (PipeItem *)item);
 }
 
-static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipItem *item)
+static void red_display_release_stream_clip(Surfaces* surfaces, StreamClipItem *item)
 {
     if (!--item->refs) {
-        red_display_release_stream(channel, item->stream_agent);
+        red_display_release_stream(surfaces, item->stream_agent);
         if (item->rects) {
             free(item->rects);
         }
@@ -2211,55 +2265,61 @@ static void red_display_release_stream_clip(DisplayChannel* channel, StreamClipI
     }
 }
 
-static void red_attach_stream(RedWorker *worker, Surfaces *surfaces, Drawable *drawable, Stream *stream)
+static void red_attach_stream(Surfaces *surfaces, Drawable *drawable, Stream *stream)
 {
-    DisplayChannel *channel;
+    DisplayChannelClient *dcc;
+    StreamAgent *agent;
+
     ASSERT(!drawable->stream && !stream->current);
     ASSERT(drawable && stream);
     stream->current = drawable;
     drawable->stream = stream;
     stream->last_time = drawable->creation_time;
 
-    if ((channel = worker->display_channel)) {
-        StreamAgent *agent = &channel->stream_agents[stream - surfaces->streams_buf];
+    if (surfaces->dcc) {
+        dcc = surfaces->dcc;
+        agent = &dcc->stream_agents[stream - surfaces->streams_buf];
         if (!region_is_equal(&agent->vis_region, &drawable->tree_item.base.rgn)) {
             region_destroy(&agent->vis_region);
             region_clone(&agent->vis_region, &drawable->tree_item.base.rgn);
-            push_stream_clip_by_drawable(channel, agent, drawable);
+            push_stream_clip_by_drawable(dcc, agent, drawable);
         }
     }
 }
 
-static void red_stop_stream(RedWorker *worker, Surfaces *surfaces, Stream *stream)
+static void red_stop_stream(Surfaces *surfaces, Stream *stream)
 {
-    DisplayChannel *channel;
+    DisplayChannelClient *dcc = surfaces->dcc;
     ASSERT(ring_item_is_linked(&stream->link));
     ASSERT(!stream->current);
 
-    if ((channel = worker->display_channel)) {
+    if (surfaces->dcc) {
         StreamAgent *stream_agent;
-        stream_agent = &channel->stream_agents[stream - surfaces->streams_buf];
+        stream_agent = &dcc->stream_agents[stream - surfaces->streams_buf];
         region_clear(&stream_agent->vis_region);
         ASSERT(!pipe_item_is_linked(&stream_agent->destroy_item));
         stream->refs++;
-        red_channel_client_pipe_add(channel->common.base.rcc, &stream_agent->destroy_item);
+        red_channel_client_pipe_add(&dcc->common.base, &stream_agent->destroy_item);
     }
     ring_remove(&stream->link);
     red_release_stream(surfaces, stream);
 }
 
-static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
+static inline void red_detach_stream_gracefully(Surfaces *surfaces, Stream *stream)
 {
-    DisplayChannel *channel;
-    ASSERT(stream->current);
+    RedChannel *channel;
+    RedChannelClient *rcc;
 
-    if ((channel = worker->display_channel) && !pipe_item_is_linked(&stream->current->pipe_item)) {
+    ASSERT(stream->current);
+    if (surfaces->dcc && !pipe_item_is_linked(&stream->current->pipe_item)) {
         UpgradeItem *upgrade_item;
         int n_rects;
+        rcc = &surfaces->dcc->common.base;
+        channel = rcc->channel;
 
         upgrade_item = spice_new(UpgradeItem, 1);
         upgrade_item->refs = 1;
-        red_channel_pipe_item_init(&channel->common.base,
+        red_channel_pipe_item_init(channel,
                 &upgrade_item->base, PIPE_ITEM_TYPE_UPGRADE);
         upgrade_item->drawable = stream->current;
         upgrade_item->drawable->refs++;
@@ -2267,30 +2327,29 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
         upgrade_item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects));
         upgrade_item->rects->num_rects = n_rects;
         region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn, upgrade_item->rects->rects, n_rects);
-        red_channel_client_pipe_add(channel->common.base.rcc, &upgrade_item->base);
+        red_channel_client_pipe_add(rcc, &upgrade_item->base);
     }
-    red_detach_stream(&worker->surfaces, stream);
+    red_detach_stream(surfaces, stream);
 }
 
 // region should be a primary surface region
-static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
+static void red_detach_streams_behind(Surfaces *surfaces, QRegion *region)
 {
-    Surfaces *surfaces = &worker->surfaces;
     Ring *ring = &surfaces->streams;
     RingItem *item = ring_get_head(ring);
-    DisplayChannel *channel = worker->display_channel;
+    DisplayChannelClient *dcc = surfaces->dcc;
 
     while (item) {
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
         item = ring_next(ring, item);
 
-        if (channel) {
-            StreamAgent *agent = &channel->stream_agents[stream - surfaces->streams_buf];
+        if (dcc) {
+            StreamAgent *agent = &dcc->stream_agents[stream - surfaces->streams_buf];
             if (region_intersects(&agent->vis_region, region)) {
                 region_clear(&agent->vis_region);
-                push_stream_clip(channel, agent);
+                push_stream_clip(dcc, agent);
                 if (stream->current) {
-                    red_detach_stream_gracefully(worker, stream);
+                    red_detach_stream_gracefully(surfaces, stream);
                 }
             }
         } else if (stream->current && region_intersects(&stream->current->tree_item.base.rgn,
@@ -2300,14 +2359,13 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region)
     }
 }
 
-static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
+static void red_streams_update_clip(RedWorker *worker, Surfaces *surfaces, Drawable *drawable)
 {
-    DisplayChannel *channel = worker->display_channel;
-    Surfaces *surfaces = &worker->surfaces;
     Ring *ring;
     RingItem *item;
+    DisplayChannelClient *dcc = surfaces->dcc;
 
-    if (!display_connected(worker)) {
+    if (!surfaces->dcc) {
         return;
     }
 
@@ -2325,7 +2383,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
 
         item = ring_next(ring, item);
 
-        agent = &channel->stream_agents[stream - surfaces->streams_buf];
+        agent = &dcc->stream_agents[stream - surfaces->streams_buf];
 
         if (stream->current == drawable) {
             continue;
@@ -2333,7 +2391,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable)
 
         if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) {
             region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn);
-            push_stream_clip(channel, agent);
+            push_stream_clip(dcc, agent);
         }
     }
 }
@@ -2375,17 +2433,17 @@ static inline void red_handle_streams_timout(RedWorker *worker, Surfaces *surfac
         item = ring_next(ring, item);
         if (now >= (stream->last_time + RED_STREAM_TIMOUT)) {
             if (stream->current) {
-                red_detach_stream_gracefully(worker, stream);
+                red_detach_stream_gracefully(surfaces, stream);
             }
-            red_stop_stream(worker, &worker->surfaces, stream);
+            red_stop_stream(surfaces, stream);
         }
     }
 }
 
-static void red_display_release_stream(DisplayChannel *display, StreamAgent *agent)
+static void red_display_release_stream(Surfaces *surfaces, StreamAgent *agent)
 {
     ASSERT(agent->stream);
-    red_release_stream(&display->common.worker->surfaces, agent->stream);
+    red_release_stream(surfaces, agent->stream);
 }
 
 static inline Stream *red_alloc_stream(Surfaces *surfaces)
@@ -2399,15 +2457,15 @@ static inline Stream *red_alloc_stream(Surfaces *surfaces)
     return stream;
 }
 
-static int get_bit_rate(RedWorker *worker,
+static int get_bit_rate(DisplayChannelClient *dcc,
     int width, int height)
 {
     uint64_t bit_rate = width * height * BEST_BIT_RATE_PER_PIXEL; 
     MainChannelClient *mcc;
     int is_low_bandwidth = 0;
     
-    if (display_connected(worker)) {
-        mcc = red_client_get_main(worker->display_channel->common.base.rcc->client);
+    if (dcc) {
+        mcc = red_client_get_main(dcc->common.base.client);
         is_low_bandwidth = main_channel_client_is_low_bandwidth(mcc);
     }
 
@@ -2418,9 +2476,9 @@ static int get_bit_rate(RedWorker *worker,
     return bit_rate;
 }
 
-static void red_display_create_stream(DisplayChannel *display, Stream *stream)
+static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
 {
-    StreamAgent *agent = &display->stream_agents[stream - display->common.worker->surfaces.streams_buf];
+    StreamAgent *agent = &dcc->stream_agents[stream - dcc->common.surfaces->streams_buf];
     stream->refs++;
     ASSERT(region_is_empty(&agent->vis_region));
     if (stream->current) {
@@ -2431,13 +2489,15 @@ static void red_display_create_stream(DisplayChannel *display, Stream *stream)
     }
     agent->drops = 0;
     agent->fps = MAX_FPS;
-    reset_rate(display->common.worker, agent);
-    red_channel_client_pipe_add(display->common.base.rcc, &agent->create_item);
+    reset_rate(dcc, agent);
+    red_channel_client_pipe_add(&dcc->common.base, &agent->create_item);
 }
 
-static void red_create_stream(RedWorker *worker, Drawable *drawable)
+/* TODO: we create the stream even if dcc is NULL, i.e. no client - or
+ * maybe we can't reach this function in that case? question: do we want to? */
+static void red_create_stream(Surfaces *surfaces, Drawable *drawable)
 {
-    Surfaces *surfaces = &worker->surfaces;
+    DisplayChannelClient *dcc = surfaces->dcc;
     Stream *stream;
     SpiceRect* src_rect;
     int stream_width;
@@ -2463,48 +2523,49 @@ static void red_create_stream(RedWorker *worker, Drawable *drawable)
     stream->height = src_rect->bottom - src_rect->top;
     stream->dest_area = drawable->red_drawable->bbox;
     stream->refs = 1;
-    stream->bit_rate = get_bit_rate(worker, stream_width, stream_height);
+    stream->bit_rate = get_bit_rate(dcc, stream_width, stream_height);
     SpiceBitmap *bitmap = &drawable->red_drawable->u.copy.src_bitmap->u.bitmap;
     stream->top_down = !!(bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN);
     drawable->stream = stream;
 
-    if (worker->display_channel) {
-        red_display_create_stream(worker->display_channel, stream);
+    if (dcc) {
+        red_display_create_stream(dcc, stream);
     }
 
     return;
 }
 
-static void red_disply_start_streams(DisplayChannel *display_channel)
+static void red_disply_start_streams(DisplayChannelClient *dcc)
 {
-    Ring *ring = &display_channel->common.worker->surfaces.streams;
+    Ring *ring = &dcc->common.surfaces->streams;
     RingItem *item = ring;
 
     while ((item = ring_next(ring, item))) {
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
-        red_display_create_stream(display_channel, stream);
+        red_display_create_stream(dcc, stream);
     }
 }
 
-static void red_display_init_streams(DisplayChannel *display)
+static void red_display_client_init_streams(DisplayChannelClient *dcc)
 {
     int i;
+    Surfaces *surfaces = dcc->common.surfaces;
+    RedChannel *channel = dcc->common.base.channel;
+
     for (i = 0; i < NUM_STREAMS; i++) {
-        StreamAgent *agent = &display->stream_agents[i];
-        agent->stream = &display->common.worker->surfaces.streams_buf[i];
+        StreamAgent *agent = &dcc->stream_agents[i];
+        agent->stream = &surfaces->streams_buf[i];
         region_init(&agent->vis_region);
-        red_channel_pipe_item_init(&display->common.base,
-                    &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
-        red_channel_pipe_item_init(&display->common.base,
-                    &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
+        red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE);
+        red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY);
     }
 }
 
-static void red_display_destroy_streams(DisplayChannel *display)
+static void red_display_destroy_streams(DisplayChannelClient *dcc)
 {
     int i;
     for (i = 0; i < NUM_STREAMS; i++) {
-        StreamAgent *agent = &display->stream_agents[i];
+        StreamAgent *agent = &dcc->stream_agents[i];
         region_destroy(&agent->vis_region);
     }
 }
@@ -2572,12 +2633,12 @@ static inline int red_is_next_stream_frame(RedWorker *worker, const Drawable *ca
                                       prev->stream);
 }
 
-static void reset_rate(RedWorker *worker, StreamAgent *stream_agent)
+static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent)
 {
     Stream *stream = stream_agent->stream;
     int rate;
 
-    rate = get_bit_rate(worker, stream->width, stream->height);
+    rate = get_bit_rate(dcc, stream->width, stream->height);
     if (rate == stream->bit_rate) {
         return;
     }
@@ -2598,14 +2659,16 @@ static int display_channel_is_low_bandwidth(DisplayChannel *display_channel)
 
 static inline void pre_stream_item_swap(RedWorker *worker, Surfaces *surfaces, Stream *stream)
 {
+    DisplayChannelClient *dcc = surfaces->dcc;
+
     ASSERT(stream->current);
 
-    if (!display_connected(worker) || !display_channel_is_low_bandwidth(worker->display_channel)) {
+    if (!dcc || !display_channel_is_low_bandwidth(worker->display_channel)) {
         return;
     }
 
     int index = stream - surfaces->streams_buf;
-    StreamAgent *agent = &worker->display_channel->stream_agents[index];
+    StreamAgent *agent = &dcc->stream_agents[index];
 
     if (pipe_item_is_linked(&stream->current->pipe_item)) {
         ++agent->drops;
@@ -2663,10 +2726,11 @@ static inline int red_is_stream_start(Drawable *drawable)
 }
 
 // returns whether a stream was created
-static int red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable,
-                                 int frames_count,
-                                 int gradual_frames_count,
-                                 int last_gradual_frame)
+static int red_stream_add_frame(RedWorker* worker, Surfaces *surfaces,
+                                Drawable *frame_drawable,
+                                int frames_count,
+                                int gradual_frames_count,
+                                int last_gradual_frame)
 {
     red_update_copy_graduality(worker, frame_drawable);
     frame_drawable->frames_count = frames_count + 1;
@@ -2687,7 +2751,7 @@ static int red_stream_add_frame(RedWorker* worker, Drawable *frame_drawable,
     }
 
     if (red_is_stream_start(frame_drawable)) {
-        red_create_stream(worker, frame_drawable);
+        red_create_stream(surfaces, frame_drawable);
         return TRUE;
     }
     return FALSE;
@@ -2710,9 +2774,9 @@ static inline void red_stream_maintenance(RedWorker *worker,
         pre_stream_item_swap(worker, surfaces, stream);
         red_detach_stream(surfaces, stream);
         prev->streamable = FALSE; //prevent item trace
-        red_attach_stream(worker, surfaces, candidate, stream);
+        red_attach_stream(surfaces, candidate, stream);
     } else {
-        red_stream_add_frame(worker, candidate,
+        red_stream_add_frame(worker, surfaces, candidate,
                              prev->frames_count,
                              prev->gradual_frames_count,
                              prev->last_gradual_frame);
@@ -2737,6 +2801,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
     DrawItem *other_draw_item;
     Drawable *drawable;
     Drawable *other_drawable;
+    DisplayChannelClient *dcc = surfaces->dcc;
 
     if (other->type != TREE_ITEM_TYPE_DRAWABLE) {
         return FALSE;
@@ -2755,9 +2820,9 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
         red_stream_maintenance(worker, surfaces, drawable, other_drawable);
         __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
         if (add_after) {
-            red_pipe_add_drawable_after(worker, drawable, other_drawable);
+            red_pipe_add_drawable_after(dcc, drawable, other_drawable);
         } else {
-            red_pipe_add_drawable(worker, drawable);
+            red_pipe_add_drawable(dcc, drawable);
         }
         remove_drawable(worker, surfaces, other_drawable);
         return TRUE;
@@ -2767,7 +2832,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
     case QXL_EFFECT_REVERT_ON_DUP:
         if (is_same_drawable(worker, drawable, other_drawable)) {
             if (!ring_item_is_linked(&other_drawable->pipe_item.link)) {
-                red_pipe_add_drawable(worker, drawable);
+                red_pipe_add_drawable(dcc, drawable);
             }
             remove_drawable(worker, surfaces, other_drawable);
             return TRUE;
@@ -2777,7 +2842,7 @@ static inline int red_current_add_equal(RedWorker *worker, Surfaces *surfaces,
         if (is_same_geometry(worker, drawable, other_drawable)) {
             __current_add_drawable(worker, surfaces, drawable, &other->siblings_link);
             remove_drawable(worker, surfaces, other_drawable);
-            red_pipe_add_drawable(worker, drawable);
+            red_pipe_add_drawable(dcc, drawable);
             return TRUE;
         }
         break;
@@ -2813,7 +2878,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Surfaces *surfaces, D
                                                            &stream->dest_area,
                                                            stream->last_time,
                                                            stream)) {
-            red_attach_stream(worker, surfaces, drawable, stream);
+            red_attach_stream(surfaces, drawable, stream);
             return;
         }
         item = ring_next(ring, item);
@@ -2824,7 +2889,7 @@ static inline void red_use_stream_trace(RedWorker *worker, Surfaces *surfaces, D
     for (; trace < trace_end; trace++) {
         if (__red_is_next_stream_frame(worker, drawable, trace->width, trace->height,
                                        &trace->dest_area, trace->time, NULL)) {
-            if (red_stream_add_frame(worker, drawable,
+            if (red_stream_add_frame(worker, surfaces, drawable,
                                      trace->frames_count,
                                      trace->gradual_frames_count,
                                      trace->last_gradual_frame)) {
@@ -2843,7 +2908,7 @@ static void red_reset_stream_trace(RedWorker *worker, Surfaces *surfaces)
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
         item = ring_next(ring, item);
         if (!stream->current) {
-            red_stop_stream(worker, surfaces, stream);
+            red_stop_stream(surfaces, stream);
         } else {
             red_printf("attached stream");
         }
@@ -2957,10 +3022,10 @@ static inline int red_current_add(RedWorker *worker, Surfaces *surfaces,
         region_or(&exclude_rgn, &item->base.rgn);
         exclude_region(worker, surfaces, ring, exclude_base, &exclude_rgn, NULL, drawable);
         red_use_stream_trace(worker, surfaces, drawable);
-        red_streams_update_clip(worker, drawable);
+        red_streams_update_clip(worker, surfaces, drawable);
     } else {
         if (drawable->surface_id == 0) {
-            red_detach_streams_behind(worker, &drawable->tree_item.base.rgn);
+            red_detach_streams_behind(surfaces, &drawable->tree_item.base.rgn);
         }
     }
     region_destroy(&exclude_rgn);
@@ -3019,7 +3084,7 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Surfaces *surfa
 
     // only primary surface streams are supported
     if (item->surface_id == 0) {
-        red_detach_streams_behind(worker, &shadow->base.rgn);
+        red_detach_streams_behind(surfaces, &shadow->base.rgn);
     }
     ring_add(ring, &shadow->base.siblings_link);
     __current_add_drawable(worker, surfaces, item, ring);
@@ -3028,10 +3093,10 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Surfaces *surfa
         region_clone(&exclude_rgn, &item->tree_item.base.rgn);
         exclude_region(worker, surfaces, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL);
         region_destroy(&exclude_rgn);
-        red_streams_update_clip(worker, item);
+        red_streams_update_clip(worker, surfaces, item);
     } else {
         if (item->surface_id == 0) {
-            red_detach_streams_behind(worker, &item->tree_item.base.rgn);
+            red_detach_streams_behind(surfaces, &item->tree_item.base.rgn);
         }
     }
     stat_add(&worker->add_stat, start_time);
@@ -3252,12 +3317,13 @@ static void free_one_drawable(RedWorker *worker, Surfaces *surfaces, int force_g
     RingItem *ring_item = ring_get_tail(&surfaces->current_list);
     Drawable *drawable;
     Container *container;
+    DisplayChannelClient *dcc = surfaces->dcc;
 
     ASSERT(ring_item);
     drawable = SPICE_CONTAINEROF(ring_item, Drawable, list_link);
     if (drawable->red_glz_drawable && force_glz_free) {
         ASSERT(worker->display_channel);
-        red_display_free_glz_drawable(worker->display_channel, drawable->red_glz_drawable);
+        red_display_free_glz_drawable(dcc, drawable->red_glz_drawable);
     }
     red_draw_drawable(worker, surfaces, drawable);
     container = drawable->tree_item.base.container;
@@ -3358,7 +3424,7 @@ static inline int red_handle_surfaces_dependencies(RedWorker *worker,
                 QRegion depend_region;
                 region_init(&depend_region);
                 region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]);
-                red_detach_streams_behind(worker, &depend_region);
+                red_detach_streams_behind(surfaces, &depend_region);
             }
         }
     }
@@ -3387,6 +3453,7 @@ static inline void red_process_drawable_surfaces(RedWorker *worker,
 {
     int surface_id;
     Drawable *item = get_drawable(worker, surfaces, drawable->effect, drawable, group_id);
+    DisplayChannelClient *dcc = surfaces->dcc;
 
     ASSERT(item);
 
@@ -3445,7 +3512,7 @@ static inline void red_process_drawable_surfaces(RedWorker *worker,
         if (item->tree_item.effect != QXL_EFFECT_OPAQUE) {
             surfaces->transparent_count++;
         }
-        red_pipe_add_drawable(worker, item);
+        red_pipe_add_drawable(dcc, item);
 #ifdef DRAW_ALL
         red_draw_qxl_drawable(worker, surfaces, item);
 #endif
@@ -3498,7 +3565,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
            otherwise "current" will hold items that other drawables may depend on, and then
            red_current_clear will remove them from the pipe. */
         red_current_clear(worker, surfaces, surface_id);
-        red_clear_surface_drawables_from_pipe(worker, surface_id, FALSE);
+        red_clear_surface_drawables_from_pipe(surfaces->dcc, surface_id, FALSE);
         red_destroy_surface(worker, surfaces, surface_id);
         break;
     default:
@@ -4386,20 +4453,22 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
 static void red_free_some(RedWorker *worker)
 {
     int n = 0;
+    DisplayChannelClient *dcc = worker->surfaces.dcc;
+    GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
 
-    if (worker->display_channel && worker->display_channel->glz_dict) {
+    if (glz_dict) {
         // encoding using the dictionary is prevented since the following operations might
         // change the dictionary
-        pthread_rwlock_wrlock(&worker->display_channel->glz_dict->encode_lock);
-        n = red_display_free_some_independent_glz_drawables(worker->display_channel);
+        pthread_rwlock_wrlock(&glz_dict->encode_lock);
+        n = red_display_free_some_independent_glz_drawables(dcc);
     }
 
     while (!ring_is_empty(&worker->surfaces.current_list) && n++ < RED_RELEASE_BUNCH_SIZE) {
         free_one_drawable(worker, &worker->surfaces, TRUE);
     }
 
-    if (worker->display_channel && worker->display_channel->glz_dict) {
-        pthread_rwlock_unlock(&worker->display_channel->glz_dict->encode_lock);
+    if (glz_dict) {
+        pthread_rwlock_unlock(&glz_dict->encode_lock);
     }
 }
 
@@ -4501,7 +4570,7 @@ typedef struct {
     uint32_t size;
 } AddBufInfo;
 
-static void marshaller_add_compressed(RedWorker *worker, SpiceMarshaller *m,
+static void marshaller_add_compressed(SpiceMarshaller *m,
                                       RedCompressBuf *comp_buf, size_t size)
 {
     size_t max = size;
@@ -4549,7 +4618,7 @@ static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
     spice_marshall_DisplayBase(base_marshaller, &base);
 }
 
-static inline void fill_palette(DisplayChannel *display_channel,
+static inline void fill_palette(DisplayChannelClient *dcc,
                                 SpicePalette *palette,
                                 uint8_t *flags)
 {
@@ -4557,43 +4626,43 @@ static inline void fill_palette(DisplayChannel *display_channel,
         return;
     }
     if (palette->unique) {
-        if (red_palette_cache_find(display_channel, palette->unique)) {
+        if (red_palette_cache_find(dcc, palette->unique)) {
             *flags |= SPICE_BITMAP_FLAGS_PAL_FROM_CACHE;
             return;
         }
-        if (red_palette_cache_add(display_channel->common.base.rcc, palette->unique, 1)) {
+        if (red_palette_cache_add(dcc, palette->unique, 1)) {
             *flags |= SPICE_BITMAP_FLAGS_PAL_CACHE_ME;
         }
     }
 }
 
-static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannel *display_channel)
+static inline RedCompressBuf *red_display_alloc_compress_buf(DisplayChannelClient *dcc)
 {
     RedCompressBuf *ret;
 
-    if (display_channel->send_data.free_compress_bufs) {
-        ret = display_channel->send_data.free_compress_bufs;
-        display_channel->send_data.free_compress_bufs = ret->next;
+    if (dcc->send_data.free_compress_bufs) {
+        ret = dcc->send_data.free_compress_bufs;
+        dcc->send_data.free_compress_bufs = ret->next;
     } else {
         ret = spice_new(RedCompressBuf, 1);
     }
 
-    ret->next = display_channel->send_data.used_compress_bufs;
-    display_channel->send_data.used_compress_bufs = ret;
+    ret->next = dcc->send_data.used_compress_bufs;
+    dcc->send_data.used_compress_bufs = ret;
     return ret;
 }
 
-static inline void __red_display_free_compress_buf(DisplayChannel *display_channel,
+static inline void __red_display_free_compress_buf(DisplayChannelClient *dcc,
                                                    RedCompressBuf *buf)
 {
-    buf->next = display_channel->send_data.free_compress_bufs;
-    display_channel->send_data.free_compress_bufs = buf;
+    buf->next = dcc->send_data.free_compress_bufs;
+    dcc->send_data.free_compress_bufs = buf;
 }
 
-static void red_display_free_compress_buf(DisplayChannel *display_channel,
+static void red_display_free_compress_buf(DisplayChannelClient *dcc,
                                           RedCompressBuf *buf)
 {
-    RedCompressBuf **curr_used = &display_channel->send_data.used_compress_bufs;
+    RedCompressBuf **curr_used = &dcc->send_data.used_compress_bufs;
 
     for (;;) {
         ASSERT(*curr_used);
@@ -4603,15 +4672,15 @@ static void red_display_free_compress_buf(DisplayChannel *display_channel,
         }
         curr_used = &(*curr_used)->next;
     }
-    __red_display_free_compress_buf(display_channel, buf);
+    __red_display_free_compress_buf(dcc, buf);
 }
 
-static void red_display_reset_compress_buf(DisplayChannel *display_channel)
+static void red_display_reset_compress_buf(DisplayChannelClient *dcc)
 {
-    while (display_channel->send_data.used_compress_bufs) {
-        RedCompressBuf *buf = display_channel->send_data.used_compress_bufs;
-        display_channel->send_data.used_compress_bufs = buf->next;
-        __red_display_free_compress_buf(display_channel, buf);
+    while (dcc->send_data.used_compress_bufs) {
+        RedCompressBuf *buf = dcc->send_data.used_compress_bufs;
+        dcc->send_data.used_compress_bufs = buf->next;
+        __red_display_free_compress_buf(dcc, buf);
     }
 }
 
@@ -4621,7 +4690,7 @@ static void red_display_reset_compress_buf(DisplayChannel *display_channel)
 
 /* if already exists, returns it. Otherwise allocates and adds it (1) to the ring tail
    in the channel (2) to the Drawable*/
-static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Drawable *drawable)
+static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannelClient *dcc, Drawable *drawable)
 {
     RedGlzDrawable *ret;
 
@@ -4631,7 +4700,7 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Dra
 
     ret = spice_new(RedGlzDrawable, 1);
 
-    ret->display_channel = channel;
+    ret->dcc = dcc;
     ret->red_drawable = drawable->red_drawable;
     ret->drawable = drawable;
     ret->group_id = drawable->group_id;
@@ -4640,7 +4709,7 @@ static RedGlzDrawable *red_display_get_glz_drawable(DisplayChannel *channel, Dra
     ring_init(&ret->instances);
 
     ring_item_init(&ret->link);
-    ring_add_before(&ret->link, &channel->glz_drawables);
+    ring_add_before(&ret->link, &dcc->glz_drawables);
     drawable->red_glz_drawable = ret;
 
     return ret;
@@ -4669,9 +4738,11 @@ static GlzDrawableInstanceItem *red_display_add_glz_drawable_instance(RedGlzDraw
    it is not used by Drawable).
    NOTE - 1) can be called only by the display channel that created the drawable
           2) it is assumed that the instance was already removed from the dictionary*/
-static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
+static void red_display_free_glz_drawable_instance(DisplayChannelClient *dcc,
                                                    GlzDrawableInstanceItem *glz_drawable_instance)
 {
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+    RedWorker *worker = display_channel->common.worker;
     RedGlzDrawable *glz_drawable;
 
     ASSERT(glz_drawable_instance);
@@ -4679,7 +4750,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
 
     glz_drawable = glz_drawable_instance->red_glz_drawable;
 
-    ASSERT(glz_drawable->display_channel == channel);
+    ASSERT(glz_drawable->dcc == dcc);
     ASSERT(glz_drawable->instances_count);
 
     ring_remove(&glz_drawable_instance->glz_link);
@@ -4698,7 +4769,7 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
         if (drawable) {
             drawable->red_glz_drawable = NULL;
         } else { // no reference to the qxl drawable left
-            free_red_drawable(channel->common.worker, glz_drawable->red_drawable,
+            free_red_drawable(worker, glz_drawable->red_drawable,
                               glz_drawable->group_id, glz_drawable->self_bitmap);
         }
 
@@ -4709,26 +4780,30 @@ static void red_display_free_glz_drawable_instance(DisplayChannel *channel,
     }
 }
 
-static void red_display_handle_glz_drawables_to_free(DisplayChannel* channel)
+static void red_display_handle_glz_drawables_to_free(DisplayChannelClient* dcc)
 {
     RingItem *ring_link;
-    pthread_mutex_lock(&channel->glz_drawables_inst_to_free_lock);
 
-    while ((ring_link = ring_get_head(&channel->glz_drawables_inst_to_free))) {
+    if (!dcc->glz_dict) {
+        return;
+    }
+    pthread_mutex_lock(&dcc->glz_drawables_inst_to_free_lock);
+    while ((ring_link = ring_get_head(&dcc->glz_drawables_inst_to_free))) {
         GlzDrawableInstanceItem *drawable_instance = SPICE_CONTAINEROF(ring_link,
                                                                  GlzDrawableInstanceItem,
                                                                  free_link);
-        red_display_free_glz_drawable_instance(channel, drawable_instance);
+        red_display_free_glz_drawable_instance(dcc, drawable_instance);
     }
-
-    pthread_mutex_unlock(&channel->glz_drawables_inst_to_free_lock);
+    pthread_mutex_unlock(&dcc->glz_drawables_inst_to_free_lock);
 }
 
-/* releases all the instances of the drawable from the dictionary and the display channel.
-   The release of the last instance will also release the drawable itself and the qxl drawable
-   if possible.
-   NOTE - the caller should prevent encoding using the dictionary during this operation*/
-static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawable *drawable)
+/*
+ * Releases all the instances of the drawable from the dictionary and the display channel client.
+ * The release of the last instance will also release the drawable itself and the qxl drawable
+ * if possible.
+ * NOTE - the caller should prevent encoding using the dictionary during this operation
+ */
+static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable)
 {
     RingItem *head_instance = ring_get_head(&drawable->instances);
     int cont = (head_instance != NULL);
@@ -4743,11 +4818,11 @@ static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawabl
                                                         glz_link);
         if (!ring_item_is_linked(&instance->free_link)) {
             // the instance didn't get out from window yet
-            glz_enc_dictionary_remove_image(channel->glz_dict->dict,
+            glz_enc_dictionary_remove_image(dcc->glz_dict->dict,
                                             instance->glz_instance,
-                                            &channel->glz_data.usr);
+                                            &dcc->glz_data.usr);
         }
-        red_display_free_glz_drawable_instance(channel, instance);
+        red_display_free_glz_drawable_instance(dcc, instance);
 
         if (cont) {
             head_instance = ring_get_head(&drawable->instances);
@@ -4757,45 +4832,56 @@ static void red_display_free_glz_drawable(DisplayChannel *channel, RedGlzDrawabl
 
 /* Clear all lz drawables - enforce their removal from the global dictionary.
    NOTE - prevents encoding using the dictionary during the operation*/
-static void red_display_clear_glz_drawables(DisplayChannel *channel)
+static void red_display_client_clear_glz_drawables(DisplayChannelClient *dcc)
 {
     RingItem *ring_link;
+    GlzSharedDictionary *glz_dict = dcc ? dcc->glz_dict : NULL;
 
-    if (!channel || !channel->glz_dict) {
+    if (!glz_dict) {
         return;
     }
 
     // assure no display channel is during global lz encoding
-    pthread_rwlock_wrlock(&channel->glz_dict->encode_lock);
-
-    while ((ring_link = ring_get_head(&channel->glz_drawables))) {
+    pthread_rwlock_wrlock(&glz_dict->encode_lock);
+    while ((ring_link = ring_get_head(&dcc->glz_drawables))) {
         RedGlzDrawable *drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link);
         // no need to lock the to_free list, since we assured no other thread is encoding and
         // thus not other thread access the to_free list of the channel
-        red_display_free_glz_drawable(channel, drawable);
+        red_display_free_glz_drawable(dcc, drawable);
     }
+    pthread_rwlock_unlock(&glz_dict->encode_lock);
+}
+
+static void red_display_clear_glz_drawables(DisplayChannel *display_channel)
+{
+    DisplayChannelClient *dcc = display_channel ?
+        RCC_TO_DCC(display_channel->common.base.rcc) : NULL;
 
-    pthread_rwlock_unlock(&channel->glz_dict->encode_lock);
+    if (!dcc) {
+        return;
+    }
+    red_display_client_clear_glz_drawables(dcc);
 }
 
-/* Remove from the global lz dictionary some glz_drawables that have no reference to
-   Drawable (their qxl drawables are released too).
-   NOTE - the caller should prevent encoding using the dictionary during the operation*/
-static int red_display_free_some_independent_glz_drawables(DisplayChannel *channel)
+/*
+ * Remove from the global lz dictionary some glz_drawables that have no reference to
+ * Drawable (their qxl drawables are released too).
+ * NOTE - the caller should prevent encoding using the dictionary during the operation
+ */
+static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc)
 {
+    RingItem *ring_link;
     int n = 0;
 
-    if (!channel) {
+    if (!dcc) {
         return 0;
     }
-
-    RingItem *ring_link = ring_get_head(&channel->glz_drawables);
-
+    ring_link = ring_get_head(&dcc->glz_drawables);
     while ((n < RED_RELEASE_BUNCH_SIZE) && (ring_link != NULL)) {
         RedGlzDrawable *glz_drawable = SPICE_CONTAINEROF(ring_link, RedGlzDrawable, link);
-        ring_link = ring_next(&channel->glz_drawables, ring_link);
+        ring_link = ring_next(&dcc->glz_drawables, ring_link);
         if (!glz_drawable->drawable) {
-            red_display_free_glz_drawable(channel, glz_drawable);
+            red_display_free_glz_drawable(dcc, glz_drawable);
             n++;
         }
     }
@@ -4913,7 +4999,7 @@ static inline int encoder_usr_more_space(EncoderData *enc_data, uint32_t **io_pt
 {
     RedCompressBuf *buf;
 
-    if (!(buf = red_display_alloc_compress_buf(enc_data->display_channel))) {
+    if (!(buf = red_display_alloc_compress_buf(enc_data->dcc))) {
         return 0;
     }
     enc_data->bufs_tail->send_next = buf;
@@ -5023,24 +5109,22 @@ static int zlib_usr_more_input(ZlibEncoderUsrContext *usr, uint8_t** input)
 
     usr_data->u.compressed_data.next = usr_data->u.compressed_data.next->send_next;
     usr_data->u.compressed_data.size_left -= buf_size;
-    
     return buf_size;
-
 }
 
 static void glz_usr_free_image(GlzEncoderUsrContext *usr, GlzUsrImageContext *image)
 {
     GlzData *lz_data = (GlzData *)usr;
     GlzDrawableInstanceItem *glz_drawable_instance = (GlzDrawableInstanceItem *)image;
-    DisplayChannel *drawable_channel = glz_drawable_instance->red_glz_drawable->display_channel;
-    DisplayChannel *this_channel = SPICE_CONTAINEROF(lz_data, DisplayChannel, glz_data);
-    if (this_channel == drawable_channel) {
-        red_display_free_glz_drawable_instance(drawable_channel, glz_drawable_instance);
+    DisplayChannelClient *drawable_cc = glz_drawable_instance->red_glz_drawable->dcc;
+    DisplayChannelClient *this_cc = SPICE_CONTAINEROF(lz_data, DisplayChannelClient, glz_data);
+    if (this_cc == drawable_cc) {
+        red_display_free_glz_drawable_instance(drawable_cc, glz_drawable_instance);
     } else {
-        pthread_mutex_lock(&drawable_channel->glz_drawables_inst_to_free_lock);
+        pthread_mutex_lock(&drawable_cc->glz_drawables_inst_to_free_lock);
         ring_add_before(&glz_drawable_instance->free_link,
-                        &drawable_channel->glz_drawables_inst_to_free);
-        pthread_mutex_unlock(&drawable_channel->glz_drawables_inst_to_free_lock);
+                        &drawable_cc->glz_drawables_inst_to_free);
+        pthread_mutex_unlock(&drawable_cc->glz_drawables_inst_to_free_lock);
     }
 }
 
@@ -5078,16 +5162,17 @@ static inline void red_init_lz(RedWorker *worker)
     }
 }
 
-static inline void red_display_init_glz_data(DisplayChannel *display)
+/* TODO: split off to DisplayChannel? avoid just copying those cb pointers */
+static inline void red_display_init_glz_data(DisplayChannelClient *dcc)
 {
-    display->glz_data.usr.error = glz_usr_error;
-    display->glz_data.usr.warn = glz_usr_warn;
-    display->glz_data.usr.info = glz_usr_warn;
-    display->glz_data.usr.malloc = glz_usr_malloc;
-    display->glz_data.usr.free = glz_usr_free;
-    display->glz_data.usr.more_space = glz_usr_more_space;
-    display->glz_data.usr.more_lines = glz_usr_more_lines;
-    display->glz_data.usr.free_image = glz_usr_free_image;
+    dcc->glz_data.usr.error = glz_usr_error;
+    dcc->glz_data.usr.warn = glz_usr_warn;
+    dcc->glz_data.usr.info = glz_usr_warn;
+    dcc->glz_data.usr.malloc = glz_usr_malloc;
+    dcc->glz_data.usr.free = glz_usr_free;
+    dcc->glz_data.usr.more_space = glz_usr_more_space;
+    dcc->glz_data.usr.more_lines = glz_usr_more_lines;
+    dcc->glz_data.usr.free_image = glz_usr_free_image;
 }
 
 static inline void red_init_jpeg(RedWorker *worker)
@@ -5261,16 +5346,17 @@ typedef struct compress_send_data_t {
 } compress_send_data_t;
 
 
-static inline int red_glz_compress_image(DisplayChannel *display_channel,
+static inline int red_glz_compress_image(DisplayChannelClient *dcc,
                                          SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
                                          compress_send_data_t* o_comp_data)
 {
-    RedWorker *worker = (RedWorker *)display_channel->common.worker;
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+    RedWorker *worker = display_channel->common.worker;
 #ifdef COMPRESS_STAT
     stat_time_t start_time = stat_now();
 #endif
     ASSERT(BITMAP_FMT_IS_RGB[src->format]);
-    GlzData *glz_data = &display_channel->glz_data;
+    GlzData *glz_data = &dcc->glz_data;
     ZlibData *zlib_data;
     LzImageType type = MAP_BITMAP_FMT_TO_LZ_IMAGE_TYPE[src->format];
     RedGlzDrawable *glz_drawable;
@@ -5278,7 +5364,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     int glz_size;
     int zlib_size;
 
-    glz_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
+    glz_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
     glz_data->data.bufs_head = glz_data->data.bufs_tail;
 
     if (!glz_data->data.bufs_head) {
@@ -5286,9 +5372,9 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     }
 
     glz_data->data.bufs_head->send_next = NULL;
-    glz_data->data.display_channel = display_channel;
+    glz_data->data.dcc = dcc;
 
-    glz_drawable = red_display_get_glz_drawable(display_channel, drawable);
+    glz_drawable = red_display_get_glz_drawable(dcc, drawable);
     glz_drawable_instance = red_display_add_glz_drawable_instance(glz_drawable);
 
     glz_data->data.u.lines_data.chunks = src->data;
@@ -5297,7 +5383,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     glz_data->data.u.lines_data.reverse = 0;
     glz_data->usr.more_lines = glz_usr_more_lines;
 
-    glz_size = glz_encode(display_channel->glz, type, src->x, src->y,
+    glz_size = glz_encode(dcc->glz, type, src->x, src->y,
                           (src->flags & SPICE_BITMAP_FLAGS_TOP_DOWN), NULL, 0,
                           src->stride, (uint8_t*)glz_data->data.bufs_head->buf,
                           sizeof(glz_data->data.bufs_head->buf),
@@ -5314,7 +5400,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
 #endif
     zlib_data = &worker->zlib_data;
 
-    zlib_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
+    zlib_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
     zlib_data->data.bufs_head = zlib_data->data.bufs_tail;
 
     if (!zlib_data->data.bufs_head) {
@@ -5323,7 +5409,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
     }
 
     zlib_data->data.bufs_head->send_next = NULL;
-    zlib_data->data.display_channel = display_channel;
+    zlib_data->data.dcc = dcc;
 
     zlib_data->data.u.compressed_data.next = glz_data->data.bufs_head;
     zlib_data->data.u.compressed_data.size_left = glz_size;
@@ -5337,7 +5423,7 @@ static inline int red_glz_compress_image(DisplayChannel *display_channel,
         while (zlib_data->data.bufs_head) {
             RedCompressBuf *buf = zlib_data->data.bufs_head;
             zlib_data->data.bufs_head = buf->send_next;
-            red_display_free_compress_buf(display_channel, buf);
+            red_display_free_compress_buf(dcc, buf);
         }
         goto glz;
     }
@@ -5361,10 +5447,11 @@ glz:
     return TRUE;
 }
 
-static inline int red_lz_compress_image(DisplayChannel *display_channel,
+static inline int red_lz_compress_image(DisplayChannelClient *dcc,
                                         SpiceImage *dest, SpiceBitmap *src,
                                         compress_send_data_t* o_comp_data, uint32_t group_id)
 {
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     RedWorker *worker = display_channel->common.worker;
     LzData *lz_data = &worker->lz_data;
     LzContext *lz = worker->lz;
@@ -5375,7 +5462,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
     stat_time_t start_time = stat_now();
 #endif
 
-    lz_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
+    lz_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
     lz_data->data.bufs_head = lz_data->data.bufs_tail;
 
     if (!lz_data->data.bufs_head) {
@@ -5383,13 +5470,13 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
     }
 
     lz_data->data.bufs_head->send_next = NULL;
-    lz_data->data.display_channel = display_channel;
+    lz_data->data.dcc = dcc;
 
     if (setjmp(lz_data->data.jmp_env)) {
         while (lz_data->data.bufs_head) {
             RedCompressBuf *buf = lz_data->data.bufs_head;
             lz_data->data.bufs_head = buf->send_next;
-            red_display_free_compress_buf(display_channel, buf);
+            red_display_free_compress_buf(dcc, buf);
         }
         return FALSE;
     }
@@ -5427,7 +5514,7 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
         o_comp_data->comp_buf = lz_data->data.bufs_head;
         o_comp_data->comp_buf_size = size;
 
-        fill_palette(display_channel, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
+        fill_palette(dcc, dest->u.lz_plt.palette, &(dest->u.lz_plt.flags));
         o_comp_data->lzplt_palette = dest->u.lz_plt.palette;
     }
 
@@ -5436,10 +5523,11 @@ static inline int red_lz_compress_image(DisplayChannel *display_channel,
     return TRUE;
 }
 
-static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *dest,
+static int red_jpeg_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
                                    SpiceBitmap *src, compress_send_data_t* o_comp_data,
                                    uint32_t group_id)
 {
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     RedWorker *worker = display_channel->common.worker;
     JpegData *jpeg_data = &worker->jpeg_data;
     LzData *lz_data = &worker->lz_data;
@@ -5475,7 +5563,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
         return FALSE;
     }
 
-    jpeg_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
+    jpeg_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
     jpeg_data->data.bufs_head = jpeg_data->data.bufs_tail;
 
     if (!jpeg_data->data.bufs_head) {
@@ -5484,13 +5572,13 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
     }
 
     jpeg_data->data.bufs_head->send_next = NULL;
-    jpeg_data->data.display_channel = display_channel;
+    jpeg_data->data.dcc = dcc;
 
     if (setjmp(jpeg_data->data.jmp_env)) {
         while (jpeg_data->data.bufs_head) {
             RedCompressBuf *buf = jpeg_data->data.bufs_head;
             jpeg_data->data.bufs_head = buf->send_next;
-            red_display_free_compress_buf(display_channel, buf);
+            red_display_free_compress_buf(dcc, buf);
         }
         return FALSE;
     }
@@ -5541,7 +5629,7 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
      comp_head_left = sizeof(lz_data->data.bufs_head->buf) - comp_head_filled;
      lz_out_start_byte = ((uint8_t *)lz_data->data.bufs_head->buf) + comp_head_filled;
 
-     lz_data->data.display_channel = display_channel;
+     lz_data->data.dcc = dcc;
 
      lz_data->data.u.lines_data.chunks = src->data;
      lz_data->data.u.lines_data.stride = src->stride;
@@ -5577,10 +5665,11 @@ static int red_jpeg_compress_image(DisplayChannel *display_channel, SpiceImage *
     return TRUE;
 }
 
-static inline int red_quic_compress_image(DisplayChannel *display_channel, SpiceImage *dest,
+static inline int red_quic_compress_image(DisplayChannelClient *dcc, SpiceImage *dest,
                                           SpiceBitmap *src, compress_send_data_t* o_comp_data,
                                           uint32_t group_id)
 {
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     RedWorker *worker = display_channel->common.worker;
     QuicData *quic_data = &worker->quic_data;
     QuicContext *quic = worker->quic;
@@ -5608,7 +5697,7 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
         return FALSE;
     }
 
-    quic_data->data.bufs_tail = red_display_alloc_compress_buf(display_channel);
+    quic_data->data.bufs_tail = red_display_alloc_compress_buf(dcc);
     quic_data->data.bufs_head = quic_data->data.bufs_tail;
 
     if (!quic_data->data.bufs_head) {
@@ -5616,13 +5705,13 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
     }
 
     quic_data->data.bufs_head->send_next = NULL;
-    quic_data->data.display_channel = display_channel;
+    quic_data->data.dcc = dcc;
 
     if (setjmp(quic_data->data.jmp_env)) {
         while (quic_data->data.bufs_head) {
             RedCompressBuf *buf = quic_data->data.bufs_head;
             quic_data->data.bufs_head = buf->send_next;
-            red_display_free_compress_buf(display_channel, buf);
+            red_display_free_compress_buf(dcc, buf);
         }
         return FALSE;
     }
@@ -5665,11 +5754,12 @@ static inline int red_quic_compress_image(DisplayChannel *display_channel, Spice
 
 #define MIN_SIZE_TO_COMPRESS 54
 #define MIN_DIMENSION_TO_QUIC 3
-static inline int red_compress_image(DisplayChannel *display_channel,
+static inline int red_compress_image(DisplayChannelClient *dcc,
                                      SpiceImage *dest, SpiceBitmap *src, Drawable *drawable,
                                      int can_lossy,
                                      compress_send_data_t* o_comp_data)
 {
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     spice_image_compression_t image_compression =
         display_channel->common.worker->image_compression;
     int quic_compress = FALSE;
@@ -5726,11 +5816,11 @@ static inline int red_compress_image(DisplayChannel *display_channel,
             (image_compression == SPICE_IMAGE_COMPRESS_AUTO_GLZ))) {
             // if we use lz for alpha, the stride can't be extra 
             if (src->format != SPICE_BITMAP_FMT_RGBA || !_stride_is_extra(src)) {
-                return red_jpeg_compress_image(display_channel, dest,
+                return red_jpeg_compress_image(dcc, dest,
                                                src, o_comp_data, drawable->group_id);
             }
         }
-        return red_quic_compress_image(display_channel, dest,
+        return red_quic_compress_image(dcc, dest,
                                        src, o_comp_data, drawable->group_id);
     } else {
         int glz;
@@ -5739,7 +5829,7 @@ static inline int red_compress_image(DisplayChannel *display_channel,
             (image_compression == SPICE_IMAGE_COMPRESS_GLZ)) {
             glz = BITMAP_FMT_IS_RGB[src->format] && (
                     (src->x * src->y) < glz_enc_dictionary_get_size(
-                        display_channel->glz_dict->dict));
+                        dcc->glz_dict->dict));
         } else if ((image_compression == SPICE_IMAGE_COMPRESS_AUTO_LZ) ||
                    (image_compression == SPICE_IMAGE_COMPRESS_LZ)) {
             glz = FALSE;
@@ -5748,20 +5838,20 @@ static inline int red_compress_image(DisplayChannel *display_channel,
         }
 
         if (glz) {
-            /* using the global dictionary only if it is not freezed */
-            pthread_rwlock_rdlock(&display_channel->glz_dict->encode_lock);
-            if (!display_channel->glz_dict->migrate_freeze) {
-                ret = red_glz_compress_image(display_channel,
+            /* using the global dictionary only if it is not frozen */
+            pthread_rwlock_rdlock(&dcc->glz_dict->encode_lock);
+            if (!dcc->glz_dict->migrate_freeze) {
+                ret = red_glz_compress_image(dcc,
                                              dest, src,
                                              drawable, o_comp_data);
             } else {
                 glz = FALSE;
             }
-            pthread_rwlock_unlock(&display_channel->glz_dict->encode_lock);
+            pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
         }
 
         if (!glz) {
-            ret = red_lz_compress_image(display_channel, dest, src, o_comp_data,
+            ret = red_lz_compress_image(dcc, dest, src, o_comp_data,
                                         drawable->group_id);
 #ifdef COMPRESS_DEBUG
             red_printf("LZ LOCAL compress");
@@ -5781,13 +5871,14 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc,
                                                          int is_lossy)
 {
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
     if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
         ASSERT(image->descriptor.width * image->descriptor.height > 0);
         if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) {
-            if (pixmap_cache_add(display_channel->pixmap_cache, image->descriptor.id,
+            if (pixmap_cache_add(dcc->pixmap_cache, image->descriptor.id,
                                  image->descriptor.width * image->descriptor.height, is_lossy,
-                                 rcc)) {
+                                 dcc)) {
                 io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME;
                 stat_inc_counter(display_channel->add_to_cache_counter, 1);
             }
@@ -5810,11 +5901,12 @@ typedef enum {
 
 /* if the number of times fill_bits can be called per one qxl_drawable increases -
    MAX_LZ_DRAWABLE_INSTANCES must be increased as well */
-static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
+static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m,
                               SpiceImage *simage, Drawable *drawable, int can_lossy)
 {
+    RedChannelClient *rcc = &dcc->common.base;
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    RedWorker *worker = display_channel->common.worker;
+    Surfaces *surfaces = dcc->common.surfaces;
     SpiceImage image;
     compress_send_data_t comp_send_data = {0};
     SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out;
@@ -5828,8 +5920,8 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
 
     if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) {
         int lossy_cache_item;
-        if (pixmap_cache_hit(display_channel->pixmap_cache, image.descriptor.id,
-                             &lossy_cache_item, rcc)) {
+        if (pixmap_cache_hit(dcc->pixmap_cache, image.descriptor.id,
+                             &lossy_cache_item, dcc)) {
             if (can_lossy || !lossy_cache_item) {
                 if (!display_channel->enable_jpeg || lossy_cache_item) {
                     image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE;
@@ -5846,7 +5938,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
                 stat_inc_counter(display_channel->cache_hits_counter, 1);
                 return FILL_BITS_TYPE_CACHE;
             } else {
-                pixmap_cache_set_lossy(display_channel->pixmap_cache, simage->descriptor.id,
+                pixmap_cache_set_lossy(dcc->pixmap_cache, simage->descriptor.id,
                                        FALSE);
                 image.descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME;
             }
@@ -5859,9 +5951,9 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
         RedSurface *surface;
 
         surface_id = simage->u.surface.surface_id;
-        validate_surface(&worker->surfaces, surface_id);
+        validate_surface(surfaces, surface_id);
 
-        surface = &worker->surfaces.surfaces[surface_id];
+        surface = &surfaces->surfaces[surface_id];
         image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE;
         image.descriptor.flags = 0;
         image.descriptor.width = surface->context.width;
@@ -5882,7 +5974,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
         /* Images must be added to the cache only after they are compressed
            in order to prevent starvation in the client between pixmap_cache and
            global dictionary (in cases of multiple monitors) */
-        if (!red_compress_image(display_channel, &image, &simage->u.bitmap,
+        if (!red_compress_image(dcc, &image, &simage->u.bitmap,
                                 drawable, can_lossy, &comp_send_data)) {
             SpicePalette *palette;
 
@@ -5892,7 +5984,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
             bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN;
 
             palette = bitmap->palette;
-            fill_palette(display_channel, palette, &bitmap->flags);
+            fill_palette(dcc, palette, &bitmap->flags);
             spice_marshall_Image(m, &image,
                                  &bitmap_palette_out, &lzplt_palette_out);
             ASSERT(lzplt_palette_out == NULL);
@@ -5911,7 +6003,7 @@ static FillBitsType fill_bits(RedChannelClient *rcc, SpiceMarshaller *m,
                                  &bitmap_palette_out, &lzplt_palette_out);
             ASSERT(bitmap_palette_out == NULL);
 
-            marshaller_add_compressed(worker, m, comp_send_data.comp_buf,
+            marshaller_add_compressed(m, comp_send_data.comp_buf,
                                       comp_send_data.comp_buf_size);
 
             if (lzplt_palette_out && comp_send_data.lzplt_palette) {
@@ -5942,16 +6034,17 @@ static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m,
                       SpiceImage *mask_bitmap, Drawable *drawable)
 {
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
     if (mask_bitmap && m) {
         if (display_channel->common.worker->image_compression != SPICE_IMAGE_COMPRESS_OFF) {
             spice_image_compression_t save_img_comp =
                 display_channel->common.worker->image_compression;
             display_channel->common.worker->image_compression = SPICE_IMAGE_COMPRESS_OFF;
-            fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
+            fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
             display_channel->common.worker->image_compression = save_img_comp;
         } else {
-            fill_bits(rcc, m, mask_bitmap, drawable, FALSE);
+            fill_bits(dcc, m, mask_bitmap, drawable, FALSE);
         }
     }
 }
@@ -5967,7 +6060,7 @@ static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id
     }
 }
 
-static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
+static void fill_cursor(CursorChannelClient *ccc, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
 {
     addbuf->data = NULL;
 
@@ -5983,11 +6076,11 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
         *red_cursor = cursor_cmd->u.set.shape;
 
         if (red_cursor->header.unique) {
-            if (red_cursor_cache_find(cursor_channel, red_cursor->header.unique)) {
+            if (red_cursor_cache_find(ccc, red_cursor->header.unique)) {
                 red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
                 return;
             }
-            if (red_cursor_cache_add(cursor_channel->common.base.rcc, red_cursor->header.unique, 1)) {
+            if (red_cursor_cache_add(ccc, red_cursor->header.unique, 1)) {
                 red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
             }
         }
@@ -6008,24 +6101,25 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
     }
 }
 
-static inline void red_display_reset_send_data(DisplayChannel *channel)
+static inline void red_display_reset_send_data(DisplayChannelClient *dcc)
 {
-    red_display_reset_compress_buf(channel);
-    channel->send_data.free_list.res->count = 0;
-    memset(channel->send_data.free_list.sync, 0, sizeof(channel->send_data.free_list.sync));
+    red_display_reset_compress_buf(dcc);
+    dcc->send_data.free_list.res->count = 0;
+    memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync));
 }
 
 /* set area=NULL for testing the whole surface */
-static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surface_id,
+static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id,
                                  const SpiceRect *area, SpiceRect *out_lossy_area)
 {
     RedSurface *surface;
     QRegion *surface_lossy_region;
     QRegion lossy_region;
+    Surfaces *surfaces = dcc->common.surfaces;
 
-    validate_surface(&display_channel->common.worker->surfaces, surface_id);
-    surface = &display_channel->common.worker->surfaces.surfaces[surface_id];
-    surface_lossy_region = &display_channel->surface_client_lossy_region[surface_id];
+    validate_surface(surfaces, surface_id);
+    surface = &surfaces->surfaces[surface_id];
+    surface_lossy_region = &dcc->surface_client_lossy_region[surface_id];
 
     if (!area) {
         if (region_is_empty(surface_lossy_region)) {
@@ -6060,7 +6154,7 @@ static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surfa
 static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *area,
                            Drawable *drawable, BitmapData *out_data)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
     if (image == NULL) {
         // self bitmap
@@ -6072,8 +6166,8 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *
         int is_hit_lossy;
 
         out_data->id = image->descriptor.id;
-        if (pixmap_cache_hit(display_channel->pixmap_cache, image->descriptor.id,
-                             &is_hit_lossy, rcc)) {
+        if (pixmap_cache_hit(dcc->pixmap_cache, image->descriptor.id,
+                             &is_hit_lossy, dcc)) {
             out_data->type = BITMAP_DATA_TYPE_CACHE;
             if (is_hit_lossy) {
                 return TRUE;
@@ -6094,7 +6188,7 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *
     out_data->type = BITMAP_DATA_TYPE_SURFACE;
     out_data->id = image->u.surface.surface_id;
 
-    if (is_surface_area_lossy(display_channel, out_data->id,
+    if (is_surface_area_lossy(dcc, out_data->id,
                               area, &out_data->lossy_rect))
     {
         return TRUE;
@@ -6115,7 +6209,7 @@ static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush,
     }
 }
 
-static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *display_channel,
+static void surface_lossy_region_update(RedWorker *worker, DisplayChannelClient *dcc,
                                         Drawable *item, int has_mask, int lossy)
 {
     QRegion *surface_lossy_region;
@@ -6125,7 +6219,7 @@ static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *displ
         return;
     }
 
-    surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id];
+    surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id];
     drawable = item->red_drawable;
 
     if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS ) {
@@ -6155,8 +6249,8 @@ static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *displ
 
 static inline int drawable_intersects_with_areas(Drawable *drawable, int surface_ids[],
                                                  SpiceRect *surface_areas[],
-                                                 int num_surfaces) 
-{   
+                                                 int num_surfaces)
+{
     int i;
     for (i = 0; i < num_surfaces; i++) {
         if (surface_ids[i] == drawable->red_drawable->surface_id) {
@@ -6172,7 +6266,7 @@ static inline int drawable_depends_on_areas(Drawable *drawable,
                                             int surface_ids[],
                                             SpiceRect surface_areas[],
                                             int num_surfaces)
-{   
+{
     int i;
     RedDrawable *red_drawable;
     int drawable_has_shadow;
@@ -6227,7 +6321,7 @@ static inline int drawable_depends_on_areas(Drawable *drawable,
 
 
 static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
-                                                        DisplayChannel *display_channel,
+                                                        DisplayChannelClient *dcc,
                                                         int surface_ids[],
                                                         SpiceRect *surface_areas[],
                                                         int num_surfaces)
@@ -6236,7 +6330,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
     Ring *pipe;
 
     ASSERT(num_surfaces);
-    pipe = &display_channel->common.base.rcc->pipe;
+    pipe = &dcc->common.base.pipe;
 
     for (pipe_item = (PipeItem *)ring_get_head(pipe);
          pipe_item;
@@ -6247,7 +6341,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
         if (pipe_item->type != PIPE_ITEM_TYPE_DRAW)
             continue;
         drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
-      
+
         if (ring_item_is_linked(&drawable->list_link))
             continue; // item hasn't been rendered
 
@@ -6260,7 +6354,7 @@ static int pipe_rendered_drawables_intersect_with_areas(RedWorker *worker,
 }
 
 static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
-                                                            DisplayChannel *display_channel,
+                                                            DisplayChannelClient *dcc,
                                                             int first_surface_id,
                                                             SpiceRect *first_area)
 {
@@ -6274,7 +6368,7 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
     resent_areas[0] = *first_area;
     num_resent = 1;
 
-    pipe = &display_channel->common.base.rcc->pipe;
+    pipe = &dcc->common.base.pipe;
 
     // going from the oldest to the newest
     for (pipe_item = (PipeItem *)ring_get_tail(pipe);
@@ -6312,17 +6406,18 @@ static void red_pipe_replace_rendered_drawables_with_images(RedWorker *worker,
 }
 
 static void red_add_lossless_drawable_dependencies(RedWorker *worker,
-                                                   DisplayChannel *display_channel,
+                                                   RedChannelClient *rcc,
                                                    Drawable *item,
                                                    int deps_surfaces_ids[],
                                                    SpiceRect *deps_areas[],
                                                    int num_deps)
 {
     RedDrawable *drawable = item->red_drawable;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Surfaces *surfaces = dcc->common.surfaces;
     int sync_rendered = FALSE;
     int i;
 
-
     if (!ring_item_is_linked(&item->list_link)) {
         /* drawable was already rendered, we may not be able to retrieve the lossless data
            for the lossy areas */
@@ -6332,7 +6427,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
         // that were rendered, affected the areas that need to be resent
         if (!drawable_intersects_with_areas(item, deps_surfaces_ids,
                                             deps_areas, num_deps)) {
-            if (pipe_rendered_drawables_intersect_with_areas(worker, display_channel,
+            if (pipe_rendered_drawables_intersect_with_areas(worker, dcc,
                                                              deps_surfaces_ids,
                                                              deps_areas,
                                                              num_deps)) {
@@ -6344,7 +6439,7 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
     } else {
         sync_rendered = FALSE;
         for (i = 0; i < num_deps; i++) {
-            red_update_area_till(worker, &worker->surfaces, deps_areas[i],
+            red_update_area_till(worker, surfaces, deps_areas[i],
                                  deps_surfaces_ids[i], item);
         }
     }
@@ -6367,11 +6462,11 @@ static void red_add_lossless_drawable_dependencies(RedWorker *worker,
         drawable_bbox[0] = &drawable->bbox;
 
         // check if the other rendered images in the pipe have updated the drawable bbox
-        if (pipe_rendered_drawables_intersect_with_areas(worker, display_channel,
+        if (pipe_rendered_drawables_intersect_with_areas(worker, dcc,
                                                          drawable_surface_id,
                                                          drawable_bbox,
                                                          1)) {
-            red_pipe_replace_rendered_drawables_with_images(worker, display_channel,
+            red_pipe_replace_rendered_drawables_with_images(worker, dcc,
                                                             drawable->surface_id,
                                                             &drawable->bbox);
         }
@@ -6388,6 +6483,7 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
                                    Drawable *item)
 {
     RedDrawable *drawable = item->red_drawable;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceFill fill;
@@ -6401,7 +6497,7 @@ static void red_marshall_qxl_draw_fill(RedWorker *worker,
                         &mask_bitmap_out);
 
     if (brush_pat_out) {
-        fill_bits(rcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE);
     }
 
     fill_mask(rcc, mask_bitmap_out, fill.mask.bitmap, item);
@@ -6413,7 +6509,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
                                          SpiceMarshaller *m,
                                          Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
 
     int dest_allowed_lossy = FALSE;
@@ -6432,7 +6528,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
     brush_is_lossy = is_brush_lossy(rcc, &drawable->u.fill.brush, item,
                                     &brush_bitmap_data);
     if (!dest_allowed_lossy) {
-        dest_is_lossy = is_surface_area_lossy(display_channel, item->surface_id, &drawable->bbox,
+        dest_is_lossy = is_surface_area_lossy(dcc, item->surface_id, &drawable->bbox,
                                               &dest_lossy_area);
     }
 
@@ -6442,7 +6538,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
 
         red_marshall_qxl_draw_fill(worker, rcc, m, item);
         // either the brush operation is opaque, or the dest is not lossy
-        surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
+        surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
@@ -6460,7 +6556,7 @@ static void red_lossy_marshall_qxl_draw_fill(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -6470,6 +6566,7 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
                                              SpiceMarshaller *base_marshaller,
                                              Drawable *item, int src_allowed_lossy)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *brush_pat_out;
     SpiceMarshaller *src_bitmap_out;
@@ -6486,11 +6583,11 @@ static FillBitsType red_marshall_qxl_draw_opaque(RedWorker *worker,
                           &brush_pat_out,
                           &mask_bitmap_out);
 
-    src_send_type = fill_bits(rcc, src_bitmap_out, opaque.src_bitmap, item,
+    src_send_type = fill_bits(dcc, src_bitmap_out, opaque.src_bitmap, item,
                               src_allowed_lossy);
 
     if (brush_pat_out) {
-        fill_bits(rcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE);
     }
     fill_mask(rcc, mask_bitmap_out, opaque.mask.bitmap, item);
 
@@ -6502,7 +6599,7 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
                                            SpiceMarshaller *m,
                                            Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
 
     int src_allowed_lossy;
@@ -6539,11 +6636,11 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
             src_is_lossy = FALSE;
         }
 
-        surface_lossy_region_update(worker, display_channel, item, has_mask, src_is_lossy);
+        surface_lossy_region_update(worker, dcc, item, has_mask, src_is_lossy);
     } else {
         int resend_surface_ids[2];
         SpiceRect *resend_areas[2];
-        int num_resend = 0;      
+        int num_resend = 0;
 
         if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
             resend_surface_ids[num_resend] = src_bitmap_data.id;
@@ -6557,7 +6654,7 @@ static void red_lossy_marshall_qxl_draw_opaque(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -6568,6 +6665,7 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
                                            Drawable *item, int src_allowed_lossy)
 {
     RedDrawable *drawable = item->red_drawable;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
     SpiceCopy copy;
@@ -6581,7 +6679,7 @@ static FillBitsType red_marshall_qxl_draw_copy(RedWorker *worker,
                         &src_bitmap_out,
                         &mask_bitmap_out);
 
-    src_send_type = fill_bits(rcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
+    src_send_type = fill_bits(dcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy);
     fill_mask(rcc, mask_bitmap_out, copy.mask.bitmap, item);
 
     return src_send_type;
@@ -6592,7 +6690,7 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.copy.mask.bitmap;
     int src_is_lossy;
@@ -6610,7 +6708,7 @@ static void red_lossy_marshall_qxl_draw_copy(RedWorker *worker,
         src_is_lossy = FALSE;
     }
 
-    surface_lossy_region_update(worker, display_channel, item, has_mask,
+    surface_lossy_region_update(worker, dcc, item, has_mask,
                                 src_is_lossy);
 }
 
@@ -6619,6 +6717,7 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceTransparent transparent;
@@ -6629,7 +6728,7 @@ static void red_marshall_qxl_draw_transparent(RedWorker *worker,
     spice_marshall_Transparent(base_marshaller,
                                &transparent,
                                &src_bitmap_out);
-    fill_bits(rcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
+    fill_bits(dcc, src_bitmap_out, transparent.src_bitmap, item, FALSE);
 }
 
 static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
@@ -6637,7 +6736,6 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
                                                 SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -6655,7 +6753,7 @@ static void red_lossy_marshall_qxl_draw_transparent(RedWorker *worker,
         resend_surface_ids[0] = src_bitmap_data.id;
         resend_areas[0] = &src_bitmap_data.lossy_rect;
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, 1);
     }
 }
@@ -6666,6 +6764,7 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
                                                   Drawable *item,
                                                   int src_allowed_lossy)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceAlphaBlend alpha_blend;
@@ -6677,7 +6776,7 @@ static FillBitsType red_marshall_qxl_draw_alpha_blend(RedWorker *worker,
     spice_marshall_AlphaBlend(base_marshaller,
                               &alpha_blend,
                               &src_bitmap_out);
-    src_send_type = fill_bits(rcc, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
+    src_send_type = fill_bits(dcc, src_bitmap_out, alpha_blend.src_bitmap, item, src_allowed_lossy);
 
     return src_send_type;
 }
@@ -6687,7 +6786,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
                                                 SpiceMarshaller *base_marshaller,
                                                 Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -6705,7 +6804,7 @@ static void red_lossy_marshall_qxl_draw_alpha_blend(RedWorker *worker,
     }
 
     if (src_is_lossy) {
-        surface_lossy_region_update(worker, display_channel, item, FALSE, src_is_lossy);
+        surface_lossy_region_update(worker, dcc, item, FALSE, src_is_lossy);
     } // else, the area stays lossy/lossless as the destination
 }
 
@@ -6729,7 +6828,7 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceRect src_rect;
     int horz_offset;
@@ -6747,10 +6846,10 @@ static void red_lossy_marshall_qxl_copy_bits(RedWorker *worker,
     src_rect.right = drawable->bbox.right + horz_offset;
     src_rect.bottom = drawable->bbox.bottom + vert_offset;
 
-    src_is_lossy = is_surface_area_lossy(display_channel, item->surface_id,
+    src_is_lossy = is_surface_area_lossy(dcc, item->surface_id,
                                          &src_rect, &src_lossy_area);
 
-    surface_lossy_region_update(worker, display_channel, item, FALSE,
+    surface_lossy_region_update(worker, dcc, item, FALSE,
                                 src_is_lossy);
 }
 
@@ -6759,6 +6858,7 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
                                     SpiceMarshaller *base_marshaller,
                                     Drawable *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceMarshaller *src_bitmap_out;
     SpiceMarshaller *mask_bitmap_out;
@@ -6772,7 +6872,7 @@ static void red_marshall_qxl_draw_blend(RedWorker *worker,
                          &src_bitmap_out,
                          &mask_bitmap_out);
 
-    fill_bits(rcc, src_bitmap_out, blend.src_bitmap, item, FALSE);
+    fill_bits(dcc, src_bitmap_out, blend.src_bitmap, item, FALSE);
 
     fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item);
 }
@@ -6782,7 +6882,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
                                           SpiceMarshaller *base_marshaller,
                                           Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -6791,7 +6891,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
 
     src_is_lossy = is_bitmap_lossy(rcc, drawable->u.blend.src_bitmap,
                                    &drawable->u.blend.src_area, item, &src_bitmap_data);
-    dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
+    dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
                                           &drawable->bbox, &dest_lossy_area);
 
     if (!dest_is_lossy &&
@@ -6814,7 +6914,7 @@ static void red_lossy_marshall_qxl_draw_blend(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -6844,13 +6944,13 @@ static void red_lossy_marshall_qxl_draw_blackness(RedWorker *worker,
                                               SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.blackness.mask.bitmap;
 
     red_marshall_qxl_draw_blackness(worker, rcc, base_marshaller, item);
 
-    surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
+    surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
 }
 
 static void red_marshall_qxl_draw_whiteness(RedWorker *worker,
@@ -6878,13 +6978,13 @@ static void red_lossy_marshall_qxl_draw_whiteness(RedWorker *worker,
                                               SpiceMarshaller *base_marshaller,
                                               Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int has_mask = !!drawable->u.whiteness.mask.bitmap;
 
     red_marshall_qxl_draw_whiteness(worker, rcc, base_marshaller, item);
 
-    surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
+    surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
 }
 
 static void red_marshall_qxl_draw_inverse(RedWorker *worker,
@@ -6920,6 +7020,7 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceRop3 rop3;
     SpiceMarshaller *src_bitmap_out;
@@ -6935,10 +7036,10 @@ static void red_marshall_qxl_draw_rop3(RedWorker *worker,
                         &brush_pat_out,
                         &mask_bitmap_out);
 
-    fill_bits(rcc, src_bitmap_out, rop3.src_bitmap, item, FALSE);
+    fill_bits(dcc, src_bitmap_out, rop3.src_bitmap, item, FALSE);
 
     if (brush_pat_out) {
-        fill_bits(rcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE);
     }
     fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item);
 }
@@ -6948,7 +7049,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int src_is_lossy;
     BitmapData src_bitmap_data;
@@ -6961,7 +7062,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
                                    &drawable->u.rop3.src_area, item, &src_bitmap_data);
     brush_is_lossy = is_brush_lossy(rcc, &drawable->u.rop3.brush, item,
                                     &brush_bitmap_data);
-    dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
+    dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
                                           &drawable->bbox, &dest_lossy_area);
 
     if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) &&
@@ -6969,11 +7070,11 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
         !dest_is_lossy) {
         int has_mask = !!drawable->u.rop3.mask.bitmap;
         red_marshall_qxl_draw_rop3(worker, rcc, base_marshaller, item);
-        surface_lossy_region_update(worker, display_channel, item, has_mask, FALSE);
+        surface_lossy_region_update(worker, dcc, item, has_mask, FALSE);
     } else {
         int resend_surface_ids[3];
         SpiceRect *resend_areas[3];
-        int num_resend = 0; 
+        int num_resend = 0;
 
         if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) {
             resend_surface_ids[num_resend] = src_bitmap_data.id;
@@ -6993,7 +7094,7 @@ static void red_lossy_marshall_qxl_draw_rop3(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -7003,6 +7104,7 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
                                      SpiceMarshaller *base_marshaller,
                                      Drawable *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceStroke stroke;
     SpiceMarshaller *brush_pat_out;
@@ -7018,7 +7120,7 @@ static void red_marshall_qxl_draw_stroke(RedWorker *worker,
 
     fill_attr(style_out, &stroke.attr, item->group_id);
     if (brush_pat_out) {
-        fill_bits(rcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE);
     }
 }
 
@@ -7027,7 +7129,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
                                            SpiceMarshaller *base_marshaller,
                                            Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int brush_is_lossy;
     BitmapData brush_bitmap_data;
@@ -7046,7 +7148,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
     if (drawable->u.stroke.brush.type != SPICE_BRUSH_TYPE_SOLID &&
         ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) ||
         (rop & SPICE_ROPD_OP_XOR))) {
-        dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
+        dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
                                               &drawable->bbox, &dest_lossy_area);
     }
 
@@ -7072,7 +7174,7 @@ static void red_lossy_marshall_qxl_draw_stroke(RedWorker *worker,
             num_resend++;
         }
 
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -7082,6 +7184,7 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
                                    SpiceMarshaller *base_marshaller,
                                    Drawable *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     SpiceText text;
     SpiceMarshaller *brush_pat_out;
@@ -7096,10 +7199,10 @@ static void red_marshall_qxl_draw_text(RedWorker *worker,
                         &back_brush_pat_out);
 
     if (brush_pat_out) {
-        fill_bits(rcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE);
     }
     if (back_brush_pat_out) {
-        fill_bits(rcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
+        fill_bits(dcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE);
     }
 }
 
@@ -7108,7 +7211,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
                                          SpiceMarshaller *base_marshaller,
                                          Drawable *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *drawable = item->red_drawable;
     int fg_is_lossy;
     BitmapData fg_bitmap_data;
@@ -7135,7 +7238,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
 
     if ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) ||
         (rop & SPICE_ROPD_OP_XOR)) {
-        dest_is_lossy = is_surface_area_lossy(display_channel, drawable->surface_id,
+        dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id,
                                               &drawable->bbox, &dest_lossy_area);
     }
 
@@ -7165,7 +7268,7 @@ static void red_lossy_marshall_qxl_draw_text(RedWorker *worker,
             resend_areas[num_resend] = &dest_lossy_area;
             num_resend++;
         }
-        red_add_lossless_drawable_dependencies(worker, display_channel, item,
+        red_add_lossless_drawable_dependencies(worker, rcc, item,
                                                resend_surface_ids, resend_areas, num_resend);
     }
 }
@@ -7268,10 +7371,10 @@ static inline void red_marshall_qxl_drawable(RedWorker *worker, RedChannelClient
     }
 }
 
-static void display_channel_push_release(DisplayChannel *channel, uint8_t type, uint64_t id,
+static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id,
                                          uint64_t* sync_data)
 {
-    FreeList *free_list = &channel->send_data.free_list;
+    FreeList *free_list = &dcc->send_data.free_list;
     int i;
 
     for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
@@ -7294,8 +7397,8 @@ static void display_channel_push_release(DisplayChannel *channel, uint8_t type,
 
 static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
-    FreeList *free_list = &display_channel->send_data.free_list;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    FreeList *free_list = &dcc->send_data.free_list;
     SpiceDataHeader *header = red_channel_client_get_header(rcc);
 
     if (free_list->res->count) {
@@ -7314,7 +7417,7 @@ static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarsha
         spice_marshall_msg_display_inval_list(inval_m, free_list->res);
 
         for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
-            if (i != display_channel->common.id && free_list->sync[i] != 0) {
+            if (i != dcc->common.id && free_list->sync[i] != 0) {
                 free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY;
                 free_list->wait.header.wait_list[sync_count].channel_id = i;
                 free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i];
@@ -7344,29 +7447,6 @@ static inline void display_begin_send_message(RedChannelClient *rcc, SpiceMarsha
     red_channel_client_begin_send_message(rcc);
 }
 
-static inline RedChannel *red_ref_channel(RedChannel *channel)
-{
-    CommonChannel *common;
-
-    if (!channel) {
-        return NULL;
-    }
-    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
-    ++common->listener.refs;
-    return channel;
-}
-
-static inline void red_unref_channel(RedChannel *channel)
-{
-    CommonChannel *common;
-
-    ASSERT(channel);
-    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
-    if (!--common->listener.refs) {
-        red_channel_destroy(channel);
-    }
-}
-
 static inline uint8_t *red_get_image_line(RedWorker *worker, SpiceChunks *chunks, size_t *offset,
                                           int *chunk_nr, int stride)
 {
@@ -7545,11 +7625,12 @@ static int red_rgb16bpp_to_24 (RedWorker *worker, const SpiceRect *src,
 static inline int red_marshall_stream_data(RedChannelClient *rcc,
                   SpiceMarshaller *base_marshaller, Drawable *drawable)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
     Stream *stream = drawable->stream;
     SpiceImage *image;
     RedWorker* worker;
-    Surfaces *surfaces;
+    Surfaces *surfaces = dcc->common.surfaces;
     uint8_t *frame;
     size_t frame_stride;
     int n;
@@ -7558,14 +7639,13 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     ASSERT(drawable->red_drawable->type == QXL_DRAW_COPY);
 
     worker = display_channel->common.worker;
-    surfaces = &worker->surfaces;
     image = drawable->red_drawable->u.copy.src_bitmap;
 
     if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) {
         return FALSE;
     }
 
-    StreamAgent *agent = &display_channel->stream_agents[stream - surfaces->streams_buf];
+    StreamAgent *agent = &dcc->stream_agents[stream - surfaces->streams_buf];
     uint64_t time_now = red_now();
     if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) {
         agent->frames--;
@@ -7603,18 +7683,18 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     }
 
     while ((n = mjpeg_encoder_encode_frame(stream->mjpeg_encoder,
-                                           display_channel->send_data.stream_outbuf,
-                                           display_channel->send_data.stream_outbuf_size)) == 0) {
+                                           dcc->send_data.stream_outbuf,
+                                           dcc->send_data.stream_outbuf_size)) == 0) {
         uint8_t *new_buf;
         size_t new_size;
 
-        new_size = display_channel->send_data.stream_outbuf_size * 2;
+        new_size = dcc->send_data.stream_outbuf_size * 2;
         new_buf = spice_malloc(new_size);
 
         red_display_unshare_stream_buf(display_channel);
-        free(display_channel->send_data.stream_outbuf);
-        display_channel->send_data.stream_outbuf = new_buf;
-        display_channel->send_data.stream_outbuf_size = new_size;
+        free(dcc->send_data.stream_outbuf);
+        dcc->send_data.stream_outbuf = new_buf;
+        dcc->send_data.stream_outbuf_size = new_size;
         red_display_share_stream_buf(display_channel);
     }
 
@@ -7627,7 +7707,7 @@ static inline int red_marshall_stream_data(RedChannelClient *rcc,
     stream_data.data_size = n;
     spice_marshall_msg_display_stream_data(base_marshaller, &stream_data);
     spice_marshaller_add_ref(base_marshaller,
-                             display_channel->send_data.stream_outbuf, n);
+                             dcc->send_data.stream_outbuf, n);
     agent->last_send_time = time_now;
     return TRUE;
 }
@@ -7678,30 +7758,30 @@ static void display_channel_marshall_migrate(RedChannelClient *rcc,
 
 static void display_channel_marshall_migrate_data(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     DisplayChannelMigrateData display_data;
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL);
 
-    ASSERT(display_channel->pixmap_cache);
+    ASSERT(dcc->pixmap_cache);
     display_data.magic = DISPLAY_MIGRATE_DATA_MAGIC;
     ASSERT(MAX_CACHE_CLIENTS == 4); //MIGRATE_DATA_VERSION dependent
     display_data.version = DISPLAY_MIGRATE_DATA_VERSION;
 
     display_data.message_serial = red_channel_client_get_message_serial(rcc);
 
-    display_data.pixmap_cache_freezer = pixmap_cache_freeze(display_channel->pixmap_cache);
-    display_data.pixmap_cache_id = display_channel->pixmap_cache->id;
-    display_data.pixmap_cache_size = display_channel->pixmap_cache->size;
-    memcpy(display_data.pixmap_cache_clients, display_channel->pixmap_cache->sync,
+    display_data.pixmap_cache_freezer = pixmap_cache_freeze(dcc->pixmap_cache);
+    display_data.pixmap_cache_id = dcc->pixmap_cache->id;
+    display_data.pixmap_cache_size = dcc->pixmap_cache->size;
+    memcpy(display_data.pixmap_cache_clients, dcc->pixmap_cache->sync,
            sizeof(display_data.pixmap_cache_clients));
 
-    ASSERT(display_channel->glz_dict);
-    red_freeze_glz(display_channel);
-    display_data.glz_dict_id = display_channel->glz_dict->id;
-    glz_enc_dictionary_get_restore_data(display_channel->glz_dict->dict,
+    ASSERT(dcc->glz_dict);
+    red_freeze_glz(dcc);
+    display_data.glz_dict_id = dcc->glz_dict->id;
+    glz_enc_dictionary_get_restore_data(dcc->glz_dict->dict,
                                         &display_data.glz_dict_restore_data,
-                                        &display_channel->glz_data.usr);
+                                        &dcc->glz_data.usr);
 
     spice_marshaller_add_ref(base_marshaller,
                              (uint8_t *)&display_data, sizeof(display_data));
@@ -7709,12 +7789,12 @@ static void display_channel_marshall_migrate_data(RedChannelClient *rcc, SpiceMa
 
 static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMsgWaitForChannels wait;
     PixmapCache *pixmap_cache;
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_WAIT_FOR_CHANNELS, NULL);
-    pixmap_cache = display_channel->pixmap_cache;
+    pixmap_cache = dcc->pixmap_cache;
 
     pthread_mutex_lock(&pixmap_cache->lock);
 
@@ -7722,8 +7802,8 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMar
     wait.wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY;
     wait.wait_list[0].channel_id = pixmap_cache->generation_initiator.client;
     wait.wait_list[0].message_serial = pixmap_cache->generation_initiator.message;
-    display_channel->pixmap_cache_generation = pixmap_cache->generation;
-    display_channel->pending_pixmaps_sync = FALSE;
+    dcc->pixmap_cache_generation = pixmap_cache->generation;
+    dcc->pending_pixmaps_sync = FALSE;
 
     pthread_mutex_unlock(&pixmap_cache->lock);
 
@@ -7732,11 +7812,11 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, SpiceMar
 
 static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMsgWaitForChannels wait;
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL);
-    pixmap_cache_reset(display_channel->pixmap_cache, rcc, &wait);
+    pixmap_cache_reset(dcc->pixmap_cache, dcc, &wait);
 
     spice_marshall_msg_display_inval_all_pixmaps(base_marshaller,
                                                  &wait);
@@ -7744,7 +7824,8 @@ static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMar
 
 static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     SpiceImage red_image;
     RedWorker *worker;
     SpiceBitmap bitmap;
@@ -7818,7 +7899,7 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
                                                           &bitmap,
                                                           worker->mem_slots.internal_groupslot_id);
                 if (grad_level == BITMAP_GRADUAL_HIGH) {
-                    // if we use lz for alpha, the stride can't be extra 
+                    // if we use lz for alpha, the stride can't be extra
                     lossy_comp = display_channel->enable_jpeg && item->can_lossy;
                 } else {
                     lz_comp = TRUE;
@@ -7830,27 +7911,27 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
     }
 
     if (lossy_comp) {
-        comp_succeeded = red_jpeg_compress_image(display_channel, &red_image,
+        comp_succeeded = red_jpeg_compress_image(dcc, &red_image,
                                                  &bitmap, &comp_send_data,
                                                  worker->mem_slots.internal_groupslot_id);
     } else {
         if (!lz_comp) {
-            comp_succeeded = red_quic_compress_image(display_channel, &red_image, &bitmap,
+            comp_succeeded = red_quic_compress_image(dcc, &red_image, &bitmap,
                                                      &comp_send_data,
                                                      worker->mem_slots.internal_groupslot_id);
         } else {
-            comp_succeeded = red_lz_compress_image(display_channel, &red_image, &bitmap,
+            comp_succeeded = red_lz_compress_image(dcc, &red_image, &bitmap,
                                                    &comp_send_data,
                                                    worker->mem_slots.internal_groupslot_id);
         }
     }
 
-    surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id];
+    surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id];
     if (comp_succeeded) {
         spice_marshall_Image(src_bitmap_out, &red_image,
                              &bitmap_palette_out, &lzplt_palette_out);
 
-        marshaller_add_compressed(worker, src_bitmap_out,
+        marshaller_add_compressed(src_bitmap_out,
                                   comp_send_data.comp_buf, comp_send_data.comp_buf_size);
 
         if (lzplt_palette_out && comp_send_data.lzplt_palette) {
@@ -7877,6 +7958,7 @@ static void red_marshall_image( RedChannelClient *rcc, SpiceMarshaller *m, Image
 
 static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller *m, UpgradeItem *item)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     RedDrawable *red_drawable;
     SpiceMsgDisplayDrawCopy copy;
     SpiceMarshaller *src_bitmap_out, *mask_bitmap_out;
@@ -7899,13 +7981,13 @@ static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller
     spice_marshall_msg_display_draw_copy(m, &copy,
                                          &src_bitmap_out, &mask_bitmap_out);
 
-    fill_bits(rcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
+    fill_bits(dcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE);
 }
 
 static void red_display_marshall_stream_start(RedChannelClient *rcc,
                      SpiceMarshaller *base_marshaller, StreamAgent *agent)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     Stream *stream = agent->stream;
 
     agent->last_send_time = 0;
@@ -7916,7 +7998,7 @@ static void red_display_marshall_stream_start(RedChannelClient *rcc,
     SpiceClipRects clip_rects;
 
     stream_create.surface_id = 0;
-    stream_create.id = agent - display_channel->stream_agents;
+    stream_create.id = agent - dcc->stream_agents;
     stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0;
     stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG;
 
@@ -7942,7 +8024,7 @@ static void red_display_marshall_stream_clip(RedChannelClient *rcc,
                                          SpiceMarshaller *base_marshaller,
                                          StreamClipItem *item)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     StreamAgent *agent = item->stream_agent;
     Stream *stream = agent->stream;
 
@@ -7951,7 +8033,7 @@ static void red_display_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 = agent - display_channel->stream_agents;
+    stream_clip.id = agent - dcc->stream_agents;
     stream_clip.clip.type = item->clip_type;
     stream_clip.clip.rects = item->rects;
 
@@ -7961,11 +8043,11 @@ static void red_display_marshall_stream_clip(RedChannelClient *rcc,
 static void red_display_marshall_stream_end(RedChannelClient *rcc,
                    SpiceMarshaller *base_marshaller, StreamAgent* agent)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMsgDisplayStreamDestroy destroy;
 
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL);
-    destroy.id = agent - display_channel->stream_agents;
+    destroy.id = agent - dcc->stream_agents;
 
     spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
 }
@@ -7980,6 +8062,7 @@ static void red_cursor_marshall_inval(RedChannelClient *rcc,
 static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller)
 {
     CursorChannel *cursor_channel;
+    CursorChannelClient *ccc = RCC_TO_CCC(rcc);
     RedWorker *worker;
     SpiceMsgCursorInit msg;
     AddBufInfo info;
@@ -7994,7 +8077,7 @@ static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *bas
     msg.trail_length = worker->cursor_trail_length;
     msg.trail_frequency = worker->cursor_trail_frequency;
 
-    fill_cursor(cursor_channel, &msg.cursor, worker->cursor, &info);
+    fill_cursor(ccc, &msg.cursor, worker->cursor, &info);
     spice_marshall_msg_cursor_init(base_marshaller, &msg);
     add_buf_from_info(base_marshaller, &info);
 }
@@ -8003,6 +8086,7 @@ static void red_marshall_local_cursor(RedChannelClient *rcc,
           SpiceMarshaller *base_marshaller, LocalCursor *cursor)
 {
     CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
+    CursorChannelClient *ccc = RCC_TO_CCC(rcc);
     SpiceMsgCursorSet cursor_set;
     AddBufInfo info;
     RedWorker *worker;
@@ -8013,7 +8097,7 @@ static void red_marshall_local_cursor(RedChannelClient *rcc,
     cursor_set.position = cursor->position;
     cursor_set.visible = worker->cursor_visible;
 
-    fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
+    fill_cursor(ccc, &cursor_set.cursor, &cursor->base, &info);
     spice_marshall_msg_cursor_set(base_marshaller, &cursor_set);
     add_buf_from_info(base_marshaller, &info);
     red_release_cursor(worker, (CursorItem *)cursor);
@@ -8033,6 +8117,7 @@ static void red_marshall_cursor(RedChannelClient *rcc,
                    SpiceMarshaller *m, CursorItem *cursor)
 {
     CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
+    CursorChannelClient *ccc = RCC_TO_CCC(rcc);
     RedCursorCmd *cmd;
     RedWorker *worker;
 
@@ -8059,7 +8144,7 @@ static void red_marshall_cursor(RedChannelClient *rcc,
             cursor_set.position = cmd->u.set.position;
             cursor_set.visible = worker->cursor_visible;
 
-            fill_cursor(cursor_channel, &cursor_set.cursor, cursor, &info);
+            fill_cursor(ccc, &cursor_set.cursor, cursor, &info);
             spice_marshall_msg_cursor_set(m, &cursor_set);
             add_buf_from_info(m, &info);
             break;
@@ -8086,10 +8171,9 @@ static void red_marshall_cursor(RedChannelClient *rcc,
 static void red_marshall_surface_create(RedChannelClient *rcc,
     SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
 
-    ASSERT(display_channel);
-    region_init(&display_channel->surface_client_lossy_region[surface_create->surface_id]);
+    region_init(&dcc->surface_client_lossy_region[surface_create->surface_id]);
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL);
 
     spice_marshall_msg_display_surface_create(base_marshaller, surface_create);
@@ -8098,12 +8182,10 @@ static void red_marshall_surface_create(RedChannelClient *rcc,
 static void red_marshall_surface_destroy(RedChannelClient *rcc,
        SpiceMarshaller *base_marshaller, uint32_t surface_id)
 {
-    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     SpiceMsgSurfaceDestroy surface_destroy;
 
-    ASSERT(display_channel);
-
-    region_destroy(&display_channel->surface_client_lossy_region[surface_id]);
+    region_destroy(&dcc->surface_client_lossy_region[surface_id]);
     red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL);
 
     surface_destroy.surface_id = surface_id;
@@ -8114,10 +8196,12 @@ static void red_marshall_surface_destroy(RedChannelClient *rcc,
 static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
-    DisplayChannel *display_channel = (DisplayChannel *)red_ref_channel(rcc->channel);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
     RedWorker *worker = display_channel->common.worker;
+    Surfaces *surfaces = dcc->common.surfaces;
 
-    red_display_reset_send_data(display_channel);
+    red_display_reset_send_data(dcc);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_DRAW: {
         Drawable *drawable = SPICE_CONTAINEROF(pipe_item, Drawable, pipe_item);
@@ -8132,19 +8216,19 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
     case PIPE_ITEM_TYPE_STREAM_CREATE: {
         StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item);
         red_display_marshall_stream_start(rcc, m, agent);
-        red_display_release_stream(display_channel, agent);
+        red_display_release_stream(surfaces, agent);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_CLIP: {
         StreamClipItem* clip_item = (StreamClipItem *)pipe_item;
         red_display_marshall_stream_clip(rcc, m, clip_item);
-        red_display_release_stream_clip(display_channel, clip_item);
+        red_display_release_stream_clip(surfaces, clip_item);
         break;
     }
     case PIPE_ITEM_TYPE_STREAM_DESTROY: {
         StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item);
         red_display_marshall_stream_end(rcc, m, agent);
-        red_display_release_stream(display_channel, agent);
+        red_display_release_stream(surfaces, agent);
         break;
     }
     case PIPE_ITEM_TYPE_UPGRADE:
@@ -8177,7 +8261,7 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_PALLET_CACHE:
-        red_reset_palette_cache(display_channel);
+        red_reset_palette_cache(dcc);
         red_marshall_verb(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES);
         free(pipe_item);
         break;
@@ -8202,15 +8286,12 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
     if (red_channel_client_send_message_pending(rcc)) {
         display_begin_send_message(rcc, m);
     }
-    red_unref_channel(&display_channel->common.base);
 }
 
 static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
 {
     SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
-    CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
 
-    red_ref_channel(rcc->channel);
     switch (pipe_item->type) {
     case PIPE_ITEM_TYPE_CURSOR:
         red_marshall_cursor(rcc, m, (CursorItem *)pipe_item);
@@ -8232,12 +8313,12 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_CURSOR_INIT:
-        red_reset_cursor_cache(cursor_channel);
+        red_reset_cursor_cache(rcc);
         red_marshall_cursor_init(rcc, m);
         free(pipe_item);
         break;
     case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
-        red_reset_cursor_cache(cursor_channel);
+        red_reset_cursor_cache(rcc);
         red_marshall_verb(rcc, SPICE_MSG_CURSOR_INVAL_ALL);
         free(pipe_item);
         break;
@@ -8245,7 +8326,6 @@ static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
         red_error("invalid pipe item type");
     }
     red_channel_client_begin_send_message(rcc);
-    red_unref_channel(rcc->channel);
 }
 
 static inline void red_push(RedWorker *worker)
@@ -8329,7 +8409,6 @@ void red_show_tree(RedWorker *worker)
 static void red_disconnect_channel(RedChannel *channel)
 {
     red_channel_disconnect(channel);
-    red_unref_channel(channel);
 }
 
 static void init_surfaces(Surfaces *surfaces)
@@ -8338,10 +8417,11 @@ static void init_surfaces(Surfaces *surfaces)
     image_surface_init(surfaces);
 }
 
-static void red_disconnect_display(RedChannelClient *rcc)
+static void display_channel_client_disconnect(RedChannelClient *rcc)
 {
     // TODO: MC: right now we assume single channel
     DisplayChannel *display_channel;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     CommonChannel *common;
     RedWorker *worker;
 
@@ -8355,32 +8435,38 @@ static void red_disconnect_display(RedChannelClient *rcc)
 #ifdef COMPRESS_STAT
     print_compress_stats(display_channel);
 #endif
-    worker->display_channel = NULL;
-    red_display_unshare_stream_buf(display_channel);
-    red_release_pixmap_cache(display_channel);
-    red_release_glz(display_channel);
-    red_reset_palette_cache(display_channel);
-    free(display_channel->send_data.stream_outbuf);
-    red_display_reset_compress_buf(display_channel);
-    while (display_channel->send_data.free_compress_bufs) {
-        RedCompressBuf *buf = display_channel->send_data.free_compress_bufs;
-        display_channel->send_data.free_compress_bufs = buf->next;
+    red_release_pixmap_cache(dcc);
+    red_release_glz(dcc);
+    red_reset_palette_cache(dcc);
+    free(dcc->send_data.stream_outbuf);
+    red_display_reset_compress_buf(dcc);
+    while (dcc->send_data.free_compress_bufs) {
+        RedCompressBuf *buf = dcc->send_data.free_compress_bufs;
+        dcc->send_data.free_compress_bufs = buf->next;
         free(buf);
     }
-    free(display_channel->send_data.free_list.res);
-    red_display_destroy_streams(display_channel);
-    red_disconnect_channel(rcc->channel);
+    free(dcc->send_data.free_list.res);
+    red_display_destroy_streams(dcc);
+    red_channel_client_pipe_clear(rcc); // do this before deleting surfaces
+    worker->surfaces.dcc = NULL;
+    red_channel_client_disconnect(rcc);
 }
 
 void red_disconnect_all_display_TODO_remove_me(RedChannel *channel)
 {
+    DisplayChannel *display_channel;
+    RedWorker *worker;
     // TODO: we need to record the client that actually causes the timeout. So
     // we need to check the locations of the various pipe heads when counting,
     // and disconnect only those/that.
     if (!channel) {
         return;
     }
-    red_channel_apply_clients(channel, red_disconnect_display);
+    display_channel = SPICE_CONTAINEROF(channel, DisplayChannel, common.base);
+    worker = display_channel->common.worker;
+    red_channel_apply_clients(channel, display_channel_client_disconnect);
+    worker->display_channel = NULL;
+    red_display_unshare_stream_buf(display_channel);
 }
 
 static void red_migrate_display(RedWorker *worker)
@@ -8500,33 +8586,31 @@ static SurfaceCreateItem *get_surface_create_item(
     return create;
 }
 
-static inline void __red_create_surface_item(RedWorker *worker, int surface_id, uint32_t flags)
+static inline void __red_create_surface_item(RedWorker *worker,
+    DisplayChannelClient *dcc, int surface_id, uint32_t flags)
 {
     RedSurface *surface;
     SurfaceCreateItem *create;
+    Surfaces *surfaces = dcc ? dcc->common.surfaces : NULL;
 
-    if (!display_connected(worker)) {
+    if (!dcc) {
         return;
     }
-
-    surface = &worker->surfaces.surfaces[surface_id];
-
-    create = get_surface_create_item(&worker->display_channel->common.base,
+    surface = &surfaces->surfaces[surface_id];
+    create = get_surface_create_item(dcc->common.base.channel,
             surface_id, surface->context.width, surface->context.height,
                                      surface->context.format, flags);
-
-    worker->display_channel->surface_client_created[surface_id] = TRUE;
-
-    red_channel_client_pipe_add(worker->display_channel->common.base.rcc, &create->pipe_item);
+    dcc->surface_client_created[surface_id] = TRUE;
+    red_channel_client_pipe_add(&dcc->common.base, &create->pipe_item);
 }
 
-static inline void red_create_surface_item(RedWorker *worker, int surface_id)
+static inline void red_create_surface_item(RedWorker *worker,
+                                           DisplayChannelClient *dcc, int surface_id)
 {
-    if (is_primary_surface(surface_id)) {
-        __red_create_surface_item(worker, surface_id, SPICE_SURFACE_FLAGS_PRIMARY);
-    } else {
-        __red_create_surface_item(worker, surface_id, 0);
-    }
+    int is_primary = is_primary_surface(surface_id);
+
+    __red_create_surface_item(worker, dcc, surface_id,
+        is_primary ? SPICE_SURFACE_FLAGS_PRIMARY : 0);
 }
 
 static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
@@ -8536,6 +8620,8 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
 {
     uint32_t i;
     RedSurface *surface = &surfaces->surfaces[surface_id];
+    DisplayChannelClient *dcc = surfaces->dcc;
+
     if (stride >= 0) {
         PANIC("Untested path stride >= 0");
     }
@@ -8566,7 +8652,7 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
 
-        red_create_surface_item(worker, surface_id);
+        red_create_surface_item(worker, dcc, surface_id);
         return;
     }
 
@@ -8577,7 +8663,7 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
                                                             surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
             worker->renderer = worker->renderers[i];
-            red_create_surface_item(worker, surface_id);
+            red_create_surface_item(worker, dcc, surface_id);
             return;
         }
     }
@@ -8585,7 +8671,8 @@ static inline void red_create_surface(RedWorker *worker, Surfaces *surfaces,
     PANIC("unable to create drawing canvas");
 }
 
-static void red_wait_outgoing_item(RedChannel *channel);
+static void red_wait_outgoing_item(RedChannelClient *rcc);
+static void red_wait_outgoing_items(RedChannel *channel);
 
 static inline void flush_display_commands(RedWorker *worker)
 {
@@ -8614,7 +8701,6 @@ static inline void flush_display_commands(RedWorker *worker)
                 break;
             }
             RedChannel *channel = (RedChannel *)worker->display_channel;
-            red_ref_channel(channel);
             red_channel_receive(channel);
             red_channel_send(channel);
             // TODO: MC: the whole timeout will break since it takes lowest timeout, should
@@ -8626,7 +8712,6 @@ static inline void flush_display_commands(RedWorker *worker)
                 sleep_count++;
                 usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
             }
-            red_unref_channel(channel);
         }
     }
 }
@@ -8658,7 +8743,6 @@ static inline void flush_cursor_commands(RedWorker *worker)
                 break;
             }
             RedChannel *channel = (RedChannel *)worker->cursor_channel;
-            red_ref_channel(channel);
             red_channel_receive(channel);
             red_channel_send(channel);
             if (red_now() >= end_time) {
@@ -8668,7 +8752,6 @@ static inline void flush_cursor_commands(RedWorker *worker)
                 sleep_count++;
                 usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
             }
-            red_unref_channel(channel);
         }
     }
 }
@@ -8679,41 +8762,43 @@ static inline void flush_all_qxl_commands(RedWorker *worker)
     flush_cursor_commands(worker);
 }
 
-static void push_new_primary_surface(RedWorker *worker)
+static void push_new_primary_surface(DisplayChannelClient *dcc)
 {
-    DisplayChannel *display_channel;
+    RedWorker *worker = DCC_TO_WORKER(dcc);
+    RedChannelClient *rcc = &dcc->common.base;
 
-    if ((display_channel = worker->display_channel)) {
-        red_channel_client_pipe_add_type(display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-        if (!display_channel->common.base.migrate) {
-            red_create_surface_item(worker, 0);
-        }
-        red_channel_push(&worker->display_channel->common.base);
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+    if (!worker->display_channel->common.base.migrate) {
+        red_create_surface_item(worker, dcc, 0);
     }
+    red_channel_client_push(rcc);
 }
 
-static int display_channel_wait_for_init(DisplayChannel *display_channel)
+/* TODO: this function is evil^Wsynchronous, fix */
+static int display_channel_wait_for_init(DisplayChannelClient *dcc)
 {
-    display_channel->expect_init = TRUE;
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+
+    dcc->expect_init = TRUE;
     uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
     for (;;) {
         red_channel_receive((RedChannel *)display_channel);
         if (!red_channel_is_connected(&display_channel->common.base)) {
             break;
         }
-        if (display_channel->pixmap_cache && display_channel->glz_dict) {
-            display_channel->pixmap_cache_generation = display_channel->pixmap_cache->generation;
-            display_channel->glz = glz_encoder_create(display_channel->common.id,
-                                                      display_channel->glz_dict->dict,
-                                                      &display_channel->glz_data.usr);
-            if (!display_channel->glz) {
+        if (dcc->pixmap_cache && dcc->glz_dict) {
+            dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
+            /* TODO: move common.id? if it's used for a per client structure.. */
+            red_printf("creating encoder with id == %d", dcc->common.id);
+            dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
+            if (!dcc->glz) {
                 PANIC("create global lz failed");
             }
             return TRUE;
         }
         if (red_now() > end_time) {
             red_printf("timeout");
-            red_disconnect_all_display_TODO_remove_me((RedChannel *)display_channel);
+            display_channel_client_disconnect(&dcc->common.base);
             break;
         }
         usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
@@ -8721,10 +8806,12 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
     return FALSE;
 }
 
-static void on_new_display_channel(RedWorker *worker)
+static void on_new_display_channel_client(DisplayChannelClient *dcc)
 {
-    DisplayChannel *display_channel = worker->display_channel;
-    ASSERT(display_channel);
+    DisplayChannel *display_channel = DCC_TO_DC(dcc);
+    RedWorker *worker = display_channel->common.worker;
+    Surfaces *surfaces = dcc->common.surfaces;
+    RedChannelClient *rcc = &dcc->common.base;
 
     red_channel_push_set_ack(&display_channel->common.base);
 
@@ -8733,17 +8820,17 @@ static void on_new_display_channel(RedWorker *worker)
         return;
     }
 
-    if (!display_channel_wait_for_init(display_channel)) {
+    if (!display_channel_wait_for_init(dcc)) {
         return;
     }
-    red_channel_ack_zero_messages_window(&display_channel->common.base);
-    if (worker->surfaces.surfaces[0].context.canvas) {
-        red_current_flush(worker, &worker->surfaces, 0);
-        push_new_primary_surface(worker);
+    red_channel_client_ack_zero_messages_window(&dcc->common.base);
+    if (surfaces->surfaces[0].context.canvas) {
+        red_current_flush(worker, surfaces, 0);
+        push_new_primary_surface(dcc);
         red_add_surface_image(worker, 0);
         if (red_channel_is_connected(&display_channel->common.base)) {
-            red_pipe_add_verb(display_channel->common.base.rcc, SPICE_MSG_DISPLAY_MARK);
-            red_disply_start_streams(display_channel);
+            red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
+            red_disply_start_streams(dcc);
         }
     }
 }
@@ -8765,11 +8852,11 @@ static GlzSharedDictionary *_red_find_glz_dictionary(uint8_t dict_id)
     return ret;
 }
 
-static GlzSharedDictionary *_red_create_glz_dictionary(DisplayChannel *display,
-                                                       uint8_t id,
+static GlzSharedDictionary *_red_create_glz_dictionary(uint8_t id,
                                                        GlzEncDictContext *opaque_dict)
 {
     GlzSharedDictionary *shared_dict = spice_new0(GlzSharedDictionary, 1);
+
     shared_dict->dict = opaque_dict;
     shared_dict->id = id;
     shared_dict->refs = 1;
@@ -8779,12 +8866,12 @@ static GlzSharedDictionary *_red_create_glz_dictionary(DisplayChannel *display,
     return shared_dict;
 }
 
-static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannel *display,
+static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannelClient *dcc,
                                                       uint8_t id, int window_size)
 {
     GlzEncDictContext *glz_dict = glz_enc_dictionary_create(window_size,
                                                             MAX_LZ_ENCODERS,
-                                                            &display->glz_data.usr);
+                                                            &dcc->glz_data.usr);
 #ifdef COMPRESS_DEBUG
     red_printf("Lz Window %d Size=%d", id, window_size);
 #endif
@@ -8792,23 +8879,23 @@ static GlzSharedDictionary *red_create_glz_dictionary(DisplayChannel *display,
         PANIC("failed creating lz dictionary");
         return NULL;
     }
-    return _red_create_glz_dictionary(display, id, glz_dict);
+    return _red_create_glz_dictionary(id, glz_dict);
 }
 
-static GlzSharedDictionary *red_create_restored_glz_dictionary(DisplayChannel *display,
+static GlzSharedDictionary *red_create_restored_glz_dictionary(DisplayChannelClient *dcc,
                                                                uint8_t id,
                                                                GlzEncDictRestoreData *restore_data)
 {
     GlzEncDictContext *glz_dict = glz_enc_dictionary_restore(restore_data,
-                                                             &display->glz_data.usr);
+                                                             &dcc->glz_data.usr);
     if (!glz_dict) {
         PANIC("failed creating lz dictionary");
         return NULL;
     }
-    return _red_create_glz_dictionary(display, id, glz_dict);
+    return _red_create_glz_dictionary(id, glz_dict);
 }
 
-static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
+static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannelClient *dcc,
                                                    uint8_t id, int window_size)
 {
     GlzSharedDictionary *shared_dict = NULL;
@@ -8818,7 +8905,7 @@ static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
     shared_dict = _red_find_glz_dictionary(id);
 
     if (!shared_dict) {
-        shared_dict = red_create_glz_dictionary(display, id, window_size);
+        shared_dict = red_create_glz_dictionary(dcc, id, window_size);
         ring_add(&glz_dictionary_list, &shared_dict->base);
     } else {
         shared_dict->refs++;
@@ -8827,7 +8914,7 @@ static GlzSharedDictionary *red_get_glz_dictionary(DisplayChannel *display,
     return shared_dict;
 }
 
-static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
+static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannelClient *dcc,
                                                        uint8_t id,
                                                        GlzEncDictRestoreData *restore_data)
 {
@@ -8838,7 +8925,7 @@ static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
     shared_dict = _red_find_glz_dictionary(id);
 
     if (!shared_dict) {
-        shared_dict = red_create_restored_glz_dictionary(display, id, restore_data);
+        shared_dict = red_create_restored_glz_dictionary(dcc, id, restore_data);
         ring_add(&glz_dictionary_list, &shared_dict->base);
     } else {
         shared_dict->refs++;
@@ -8847,30 +8934,30 @@ static GlzSharedDictionary *red_restore_glz_dictionary(DisplayChannel *display,
     return shared_dict;
 }
 
-static void red_freeze_glz(DisplayChannel *channel)
+static void red_freeze_glz(DisplayChannelClient *dcc)
 {
-    pthread_rwlock_wrlock(&channel->glz_dict->encode_lock);
-    if (!channel->glz_dict->migrate_freeze) {
-        channel->glz_dict->migrate_freeze = TRUE;
+    pthread_rwlock_wrlock(&dcc->glz_dict->encode_lock);
+    if (!dcc->glz_dict->migrate_freeze) {
+        dcc->glz_dict->migrate_freeze = TRUE;
     }
-    pthread_rwlock_unlock(&channel->glz_dict->encode_lock);
+    pthread_rwlock_unlock(&dcc->glz_dict->encode_lock);
 }
 
 /* destroy encoder, and dictionary if no one uses it*/
-static void red_release_glz(DisplayChannel *channel)
+static void red_release_glz(DisplayChannelClient *dcc)
 {
     GlzSharedDictionary *shared_dict;
 
-    red_display_clear_glz_drawables(channel);
+    red_display_client_clear_glz_drawables(dcc);
 
-    glz_encoder_destroy(channel->glz);
-    channel->glz = NULL;
+    glz_encoder_destroy(dcc->glz);
+    dcc->glz = NULL;
 
-    if (!(shared_dict = channel->glz_dict)) {
+    if (!(shared_dict = dcc->glz_dict)) {
         return;
     }
 
-    channel->glz_dict = NULL;
+    dcc->glz_dict = NULL;
     pthread_mutex_lock(&cache_lock);
     if (--shared_dict->refs) {
         pthread_mutex_unlock(&cache_lock);
@@ -8878,7 +8965,7 @@ static void red_release_glz(DisplayChannel *channel)
     }
     ring_remove(&shared_dict->base);
     pthread_mutex_unlock(&cache_lock);
-    glz_enc_dictionary_destroy(shared_dict->dict, &channel->glz_data.usr);
+    glz_enc_dictionary_destroy(shared_dict->dict, &dcc->glz_data.usr);
     free(shared_dict);
 }
 
@@ -8917,13 +9004,13 @@ static PixmapCache *red_get_pixmap_cache(uint8_t id, int64_t size)
     return cache;
 }
 
-static void red_release_pixmap_cache(DisplayChannel *channel)
+static void red_release_pixmap_cache(DisplayChannelClient *dcc)
 {
     PixmapCache *cache;
-    if (!(cache = channel->pixmap_cache)) {
+    if (!(cache = dcc->pixmap_cache)) {
         return;
     }
-    channel->pixmap_cache = NULL;
+    dcc->pixmap_cache = NULL;
     pthread_mutex_lock(&cache_lock);
     if (--cache->refs) {
         pthread_mutex_unlock(&cache_lock);
@@ -8935,56 +9022,58 @@ static void red_release_pixmap_cache(DisplayChannel *channel)
     free(cache);
 }
 
-static int display_channel_init_cache(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
+static int display_channel_init_cache(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
 {
-    ASSERT(!channel->pixmap_cache);
-    return !!(channel->pixmap_cache = red_get_pixmap_cache(init_info->pixmap_cache_id,
-                                                           init_info->pixmap_cache_size));
+    ASSERT(!dcc->pixmap_cache);
+    return !!(dcc->pixmap_cache = red_get_pixmap_cache(init_info->pixmap_cache_id,
+                                                       init_info->pixmap_cache_size));
 }
 
-static int display_channel_init_glz_dictionary(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
+static int display_channel_init_glz_dictionary(DisplayChannelClient *dcc,
+                                               SpiceMsgcDisplayInit *init_info)
 {
-    ASSERT(!channel->glz_dict);
-    ring_init(&channel->glz_drawables);
-    ring_init(&channel->glz_drawables_inst_to_free);
-    pthread_mutex_init(&channel->glz_drawables_inst_to_free_lock, NULL);
-    return !!(channel->glz_dict = red_get_glz_dictionary(channel,
-                                                         init_info->glz_dictionary_id,
-                                                         init_info->glz_dictionary_window_size));
+    ASSERT(!dcc->glz_dict);
+    ring_init(&dcc->glz_drawables);
+    ring_init(&dcc->glz_drawables_inst_to_free);
+    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
+    return !!(dcc->glz_dict = red_get_glz_dictionary(dcc,
+                                                     init_info->glz_dictionary_id,
+                                                     init_info->glz_dictionary_window_size));
 }
 
-static int display_channel_init(DisplayChannel *channel, SpiceMsgcDisplayInit *init_info)
+static int display_channel_init(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info)
 {
-    return (display_channel_init_cache(channel, init_info) &&
-            display_channel_init_glz_dictionary(channel, init_info));
+    return (display_channel_init_cache(dcc, init_info) &&
+            display_channel_init_glz_dictionary(dcc, init_info));
 }
 
-static int display_channel_handle_migrate_glz_dictionary(DisplayChannel *channel,
+static int display_channel_handle_migrate_glz_dictionary(DisplayChannelClient *dcc,
                                                          DisplayChannelMigrateData *migrate_info)
 {
-    ASSERT(!channel->glz_dict);
-    ring_init(&channel->glz_drawables);
-    ring_init(&channel->glz_drawables_inst_to_free);
-    pthread_mutex_init(&channel->glz_drawables_inst_to_free_lock, NULL);
-    return !!(channel->glz_dict = red_restore_glz_dictionary(channel,
-                                                             migrate_info->glz_dict_id,
-                                                             &migrate_info->glz_dict_restore_data));
+    ASSERT(!dcc->glz_dict);
+    ring_init(&dcc->glz_drawables);
+    ring_init(&dcc->glz_drawables_inst_to_free);
+    pthread_mutex_init(&dcc->glz_drawables_inst_to_free_lock, NULL);
+    return !!(dcc->glz_dict = red_restore_glz_dictionary(dcc,
+                                                         migrate_info->glz_dict_id,
+                                                         &migrate_info->glz_dict_restore_data));
 }
 
 static int display_channel_handle_migrate_mark(RedChannelClient *rcc)
 {
-    DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    RedChannel *channel = &display_channel->common.base;
 
-    if (!channel->expect_migrate_mark) {
+    if (!display_channel->expect_migrate_mark) {
         red_printf("unexpected");
         return FALSE;
     }
-    channel->expect_migrate_mark = FALSE;
-    red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_MIGRATE_DATA);
+    display_channel->expect_migrate_mark = FALSE;
+    red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA);
     return TRUE;
 }
 
-static uint64_t display_channel_handle_migrate_data_get_serial_proc(
+static uint64_t display_channel_handle_migrate_data_get_serial(
                 RedChannelClient *rcc, uint32_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data = message;
@@ -9004,8 +9093,10 @@ static uint64_t display_channel_handle_migrate_data_get_serial_proc(
 static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message)
 {
     DisplayChannelMigrateData *migrate_data;
+    DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    RedChannel *channel = &display_channel->common.base;
     int i;
-    DisplayChannel *channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base);
 
     if (size < sizeof(*migrate_data)) {
         red_printf("bad message size");
@@ -9017,51 +9108,54 @@ static uint64_t display_channel_handle_migrate_data(RedChannelClient *rcc, uint3
         red_printf("invalid content");
         return FALSE;
     }
-    if (!channel->expect_migrate_data) {
+    if (!display_channel->expect_migrate_data) {
         red_printf("unexpected");
         return FALSE;
     }
-    channel->expect_migrate_data = FALSE;
-    if (!(channel->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
+    display_channel->expect_migrate_data = FALSE;
+    if (!(dcc->pixmap_cache = red_get_pixmap_cache(migrate_data->pixmap_cache_id, -1))) {
         return FALSE;
     }
-    pthread_mutex_lock(&channel->pixmap_cache->lock);
+    pthread_mutex_lock(&dcc->pixmap_cache->lock);
     for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
-        channel->pixmap_cache->sync[i] = MAX(channel->pixmap_cache->sync[i],
-                                             migrate_data->pixmap_cache_clients[i]);
+        dcc->pixmap_cache->sync[i] = MAX(dcc->pixmap_cache->sync[i],
+                                         migrate_data->pixmap_cache_clients[i]);
     }
-    pthread_mutex_unlock(&channel->pixmap_cache->lock);
+    pthread_mutex_unlock(&dcc->pixmap_cache->lock);
 
     if (migrate_data->pixmap_cache_freezer) {
-        channel->pixmap_cache->size = migrate_data->pixmap_cache_size;
-        red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_PIXMAP_RESET);
+        dcc->pixmap_cache->size = migrate_data->pixmap_cache_size;
+        // TODO - should this be red_channel_client_pipe_add_type?
+        red_channel_pipes_add_type(channel,
+                                   PIPE_ITEM_TYPE_PIXMAP_RESET);
     }
 
-    if (display_channel_handle_migrate_glz_dictionary(channel, migrate_data)) {
-        channel->glz = glz_encoder_create(channel->common.id,
-                                          channel->glz_dict->dict, &channel->glz_data.usr);
-        if (!channel->glz) {
+    if (display_channel_handle_migrate_glz_dictionary(dcc, migrate_data)) {
+        dcc->glz = glz_encoder_create(dcc->common.id,
+                                      dcc->glz_dict->dict, &dcc->glz_data.usr);
+        if (!dcc->glz) {
             PANIC("create global lz failed");
         }
     } else {
         PANIC("restoring global lz dictionary failed");
     }
 
-    red_channel_client_pipe_add_type(channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-    red_channel_ack_zero_messages_window(&channel->common.base);
+    red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+    red_channel_client_ack_zero_messages_window(rcc);
     return TRUE;
 }
 
 static int display_channel_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
 {
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
     switch (type) {
     case SPICE_MSGC_DISPLAY_INIT:
-        if (!((DisplayChannel *)rcc->channel)->expect_init) {
+        if (!dcc->expect_init) {
             red_printf("unexpected SPICE_MSGC_DISPLAY_INIT");
             return FALSE;
         }
-        ((DisplayChannel *)rcc->channel)->expect_init = FALSE;
-        return display_channel_init((DisplayChannel *)rcc->channel, (SpiceMsgcDisplayInit *)message);
+        dcc->expect_init = FALSE;
+        return display_channel_init(dcc, (SpiceMsgcDisplayInit *)message);
     default:
         return red_channel_client_handle_message(rcc, size, type, message);
     }
@@ -9093,23 +9187,24 @@ int common_channel_config_socket(RedChannelClient *rcc)
     return TRUE;
 }
 
-static void free_common_channel_from_listener(EventListener *ctx)
+static void free_common_cc_from_listener(EventListener *ctx)
 {
-    CommonChannel* common = SPICE_CONTAINEROF(ctx, CommonChannel, listener);
+    CommonChannelClient* common_cc = SPICE_CONTAINEROF(ctx, CommonChannelClient, listener);
 
-    free(common);
+    red_printf("");
+    free(common_cc);
 }
 
-void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
+static void worker_watch_update_mask(SpiceWatch *watch, int event_mask)
 {
 }
 
-SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
+static SpiceWatch *worker_watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
     return NULL; // apparently allowed?
 }
 
-void worker_watch_remove(SpiceWatch *watch)
+static void worker_watch_remove(SpiceWatch *watch)
 {
 }
 
@@ -9119,8 +9214,74 @@ SpiceCoreInterface worker_core = {
     .watch_remove = worker_watch_remove,
 };
 
-static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
-                                 RedClient *client, RedsStream *stream, int migrate,
+static CommonChannelClient *common_channel_client_create(int size,
+    CommonChannel *common, RedClient *client, RedsStream *stream)
+{
+    MainChannelClient *mcc = red_client_get_main(client);
+    RedChannelClient *rcc =
+        red_channel_client_create(size, &common->base, client, stream);
+    CommonChannelClient *common_cc = (CommonChannelClient*)rcc;
+
+    // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
+    // make sense, does it?
+    red_channel_client_ack_set_client_window(rcc,
+        main_channel_client_is_low_bandwidth(mcc) ?
+        WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
+    return common_cc;
+}
+
+
+DisplayChannelClient *display_channel_client_create(CommonChannel *common,
+                             RedClient *client, RedsStream *stream)
+{
+    DisplayChannelClient *dcc =
+        (DisplayChannelClient*)common_channel_client_create(
+            sizeof(DisplayChannelClient), common, client, stream);
+
+    if (!dcc) {
+        return NULL;
+    }
+    ring_init(&dcc->palette_cache_lru);
+    dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
+    return dcc;
+}
+
+CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
+                             RedClient *client, RedsStream *stream)
+{
+    CursorChannelClient *ccc =
+        (CursorChannelClient*)common_channel_client_create(
+            sizeof(CursorChannelClient), common, client, stream);
+
+    if (!ccc) {
+        return NULL;
+    }
+    ring_init(&ccc->cursor_cache_lru);
+    ccc->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
+    return ccc;
+}
+
+static int listen_to_new_client_channel(CommonChannel *common,
+    CommonChannelClient *common_cc, RedsStream *stream)
+{
+    struct epoll_event event;
+
+    common_cc->listener.refs = 1;
+    common_cc->listener.action = common->listener_action;
+    common_cc->listener.free = free_common_cc_from_listener;
+    ASSERT(common->base.clients_num);
+    common_cc->id = common->worker->id;
+    red_printf("NEW ID = %d", common_cc->id);
+    event.events = EPOLLIN | EPOLLOUT | EPOLLET;
+    event.data.ptr = &common_cc->listener;
+    if (epoll_ctl(common->worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
+        red_printf("epoll_ctl failed, %s", strerror(errno));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id, int migrate,
                                  event_listener_action_proc handler,
                                  channel_disconnect_proc disconnect,
                                  channel_send_pipe_item_proc send_item,
@@ -9133,10 +9294,8 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
                                  channel_handle_migrate_data_proc handle_migrate_data,
                                  channel_handle_migrate_data_get_serial_proc handle_migrate_data_get_serial)
 {
-    struct epoll_event event;
-    RedChannel *channel;
+    RedChannel *channel = NULL;
     CommonChannel *common;
-    MainChannelClient *mcc = red_client_get_main(client);
 
     channel = red_channel_create_parser(size, &worker_core, migrate,
                                         TRUE /* handle_acks */,
@@ -9158,45 +9317,26 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     if (!channel) {
         goto error;
     }
-    red_channel_client_create(sizeof(RedChannelClient), channel, client, stream);
-    common->id = worker->id;
-    common->listener.refs = 1;
-    common->listener.action = handler;
-    common->listener.free = free_common_channel_from_listener;
     common->worker = worker;
-    // TODO: Should this be distinctive for the Display/Cursor channels? doesn't
-    // make sense, does it?
-    red_channel_ack_set_client_window(channel,
-        main_channel_client_is_low_bandwidth(mcc) ?
-        WIDE_CLIENT_ACK_WINDOW : NARROW_CLIENT_ACK_WINDOW);
-
-    event.events = EPOLLIN | EPOLLOUT | EPOLLET;
-    event.data.ptr = &common->listener;
-    if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
-        red_printf("epoll_ctl failed, %s", strerror(errno));
-        goto error;
-    }
-
+    common->listener_action = handler;
     return channel;
 
 error:
     free(channel);
-    reds_stream_free(stream);
-
     return NULL;
 }
 
 static void handle_channel_events(EventListener *in_listener, uint32_t events)
 {
-    CommonChannel *common = SPICE_CONTAINEROF(in_listener, CommonChannel, listener);
-    RedChannel *channel = &common->base;
+    CommonChannelClient *common_cc = SPICE_CONTAINEROF(in_listener, CommonChannelClient, listener);
+    RedChannelClient *rcc = &common_cc->base;
 
-    if ((events & EPOLLIN)) {
-        red_channel_receive(channel);
+    if ((events & EPOLLIN) && red_channel_client_is_connected(rcc)) {
+        red_channel_client_receive(rcc);
     }
 
-    if (red_channel_any_blocked(channel)) {
-        red_channel_send(channel);
+    if (rcc->send_data.blocked && red_channel_client_is_connected(rcc)) {
+        red_channel_client_push(rcc);
     }
 }
 
@@ -9222,11 +9362,14 @@ static void display_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item
     }
 }
 
-static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed /* ignored */)
+static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
+                                         int item_pushed /* ignored */)
 {
     RedChannel *channel = rcc->channel;
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     RedWorker *worker = common->worker;
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+    Surfaces *surfaces = dcc->common.surfaces;
 
     ASSERT(item);
     switch (item->type) {
@@ -9236,7 +9379,7 @@ static void display_channel_release_item(RedChannelClient *rcc, PipeItem *item,
                          SPICE_CONTAINEROF(item, Drawable, pipe_item));
         break;
     case PIPE_ITEM_TYPE_STREAM_CLIP:
-        red_display_release_stream_clip((DisplayChannel *)channel, (StreamClipItem *)item);
+        red_display_release_stream_clip(surfaces, (StreamClipItem *)item);
         break;
     case PIPE_ITEM_TYPE_UPGRADE:
         release_upgrade_item(worker, &worker->surfaces, (UpgradeItem *)item);
@@ -9296,19 +9439,19 @@ static void dispatch_cursor_channel_client_disconnect(RedChannelClient *rcc)
     red_dispatcher_disconnect_cursor_client(dispatcher, rcc);
 }
 
-static void handle_new_display_channel(RedWorker *worker, RedClient *client, RedsStream *stream,
-                                       int migrate)
+static void ensure_display_channel_created(RedWorker *worker, int migrate)
 {
     DisplayChannel *display_channel;
-    size_t stream_buf_size;
-    int is_low_bandwidth = main_channel_client_is_low_bandwidth(red_client_get_main(client));
 
-    red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
+    if (worker->display_channel) {
+        return;
+    }
 
-    if (!(display_channel = (DisplayChannel *)__new_channel(
+    red_printf("create display channel");
+    if (!(worker->display_channel = (DisplayChannel *)__new_channel(
             worker, sizeof(*display_channel),
-            SPICE_CHANNEL_DISPLAY, client, stream,
-            migrate, handle_channel_events,
+            SPICE_CHANNEL_DISPLAY, migrate,
+            handle_channel_events,
             dispatch_display_channel_client_disconnect,
             display_channel_send_item,
             display_channel_hold_pipe_item,
@@ -9318,9 +9461,11 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
             display_channel_on_outgoing_error,
             display_channel_handle_migrate_mark,
             display_channel_handle_migrate_data,
-            display_channel_handle_migrate_data_get_serial_proc))) {
+            display_channel_handle_migrate_data_get_serial
+            ))) {
         return;
     }
+    display_channel = worker->display_channel;
 #ifdef RED_STATISTICS
     display_channel->stat = stat_add_node(worker->stat, "display_channel", TRUE);
     display_channel->common.base.out_bytes_counter = stat_add_counter(display_channel->stat,
@@ -9332,22 +9477,45 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
     display_channel->non_cache_counter = stat_add_counter(display_channel->stat,
                                                           "non_cache", TRUE);
 #endif
-    ring_init(&display_channel->palette_cache_lru);
-    display_channel->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
-    red_display_init_streams(display_channel);
+    stat_compress_init(&display_channel->lz_stat, lz_stat_name);
+    stat_compress_init(&display_channel->glz_stat, glz_stat_name);
+    stat_compress_init(&display_channel->quic_stat, quic_stat_name);
+    stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name);
+    stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name);
+    stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
+}
+
+
+static void handle_new_display_channel(RedWorker *worker, RedClient *client, RedsStream *stream,
+                                       int migrate)
+{
+    DisplayChannel *display_channel;
+    DisplayChannelClient *dcc;
+    size_t stream_buf_size;
+    int is_low_bandwidth = main_channel_client_is_low_bandwidth(red_client_get_main(client));
+
+    red_disconnect_all_display_TODO_remove_me((RedChannel *)worker->display_channel);
+    ensure_display_channel_created(worker, migrate);
+    if (!worker->display_channel) {
+        return;
+    }
+    display_channel = worker->display_channel;
+    red_printf("add display channel client");
+    dcc = display_channel_client_create(&display_channel->common, client, stream);
+    if (!dcc) {
+        return;
+    }
 
     stream_buf_size = 32*1024;
-    display_channel->send_data.stream_outbuf = spice_malloc(stream_buf_size);
-    display_channel->send_data.stream_outbuf_size = stream_buf_size;
+    dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
+    dcc->send_data.stream_outbuf_size = stream_buf_size;
     red_display_share_stream_buf(display_channel);
-    red_display_init_glz_data(display_channel);
-    worker->display_channel = display_channel;
-
+    red_display_init_glz_data(dcc);
 
-    display_channel->send_data.free_list.res =
+    dcc->send_data.free_list.res =
         spice_malloc(sizeof(SpiceResourceList) +
                      DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
-    display_channel->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
+    dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
 
     if (worker->jpeg_state == SPICE_WAN_COMPRESSION_AUTO) {
         display_channel->enable_jpeg = is_low_bandwidth;
@@ -9370,17 +9538,17 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
 
     // todo: tune level according to bandwidth
     display_channel->zlib_level = ZLIB_DEFAULT_COMPRESSION_LEVEL;
+    if (!listen_to_new_client_channel(&display_channel->common, &dcc->common, stream)) {
+        goto error;
+    }
+    dcc->common.surfaces = &worker->surfaces;
+    dcc->common.surfaces->dcc = dcc;
+    red_display_client_init_streams(dcc);
+    on_new_display_channel_client(dcc);
+    return;
 
-    red_ref_channel((RedChannel*)display_channel);
-    on_new_display_channel(worker);
-    red_unref_channel((RedChannel*)display_channel);
-
-    stat_compress_init(&display_channel->lz_stat, lz_stat_name);
-    stat_compress_init(&display_channel->glz_stat, glz_stat_name);
-    stat_compress_init(&display_channel->quic_stat, quic_stat_name);
-    stat_compress_init(&display_channel->jpeg_stat, jpeg_stat_name);
-    stat_compress_init(&display_channel->zlib_glz_stat, zlib_stat_name);
-    stat_compress_init(&display_channel->jpeg_alpha_stat, jpeg_alpha_stat_name);
+error:
+    red_channel_client_destroy(&dcc->common.base);
 }
 
 static void red_disconnect_cursor(RedChannel *channel)
@@ -9393,7 +9561,7 @@ static void red_disconnect_cursor(RedChannel *channel)
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     ASSERT(channel == (RedChannel *)common->worker->cursor_channel);
     common->worker->cursor_channel = NULL;
-    red_reset_cursor_cache((CursorChannel *)channel);
+    red_channel_apply_clients(channel, red_reset_cursor_cache);
     red_disconnect_channel(channel);
 }
 
@@ -9405,15 +9573,17 @@ static void red_migrate_cursor(RedWorker *worker)
     }
 }
 
-static void on_new_cursor_channel(RedWorker *worker)
+static void on_new_cursor_channel(RedWorker *worker, RedChannelClient *rcc)
 {
     CursorChannel *channel = worker->cursor_channel;
 
     ASSERT(channel);
-    red_channel_ack_zero_messages_window(&channel->common.base);
-    red_channel_push_set_ack(&channel->common.base);
+    red_channel_client_ack_zero_messages_window(rcc);
+    red_channel_client_push_set_ack(rcc);
+    // TODO: why do we check for context.canvas? defer this to after display cc is connected
+    // and test it's canvas? this is just a test to see if there is an active renderer?
     if (worker->surfaces.surfaces[0].context.canvas && !channel->common.base.migrate) {
-        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
+        red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
 }
 
@@ -9437,37 +9607,53 @@ static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, i
     }
 }
 
+static void ensure_cursor_channel_created(RedWorker *worker, int migrate)
+{
+    if (worker->cursor_channel != NULL) {
+        return;
+    }
+    red_printf("create cursor channel");
+    worker->cursor_channel = (CursorChannel *)__new_channel(
+        worker, sizeof(*worker->cursor_channel),
+        SPICE_CHANNEL_CURSOR, migrate,
+        handle_channel_events,
+        dispatch_cursor_channel_client_disconnect,
+        cursor_channel_send_item,
+        cursor_channel_hold_pipe_item,
+        cursor_channel_release_item,
+        red_channel_client_handle_message,
+        cursor_channel_on_incoming_error,
+        cursor_channel_on_outgoing_error,
+        NULL,
+        NULL,
+        NULL);
+}
+
+
 static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
                                int migrate)
 {
     CursorChannel *channel;
+    CursorChannelClient *ccc;
 
     red_disconnect_cursor((RedChannel *)worker->cursor_channel);
-
-    if (!(channel = (CursorChannel *)__new_channel(
-            worker, sizeof(*channel),
-            SPICE_CHANNEL_CURSOR, client, stream, migrate,
-            handle_channel_events,
-            dispatch_cursor_channel_client_disconnect,
-            cursor_channel_send_item,
-            cursor_channel_hold_pipe_item,
-            cursor_channel_release_item,
-            red_channel_client_handle_message,
-            cursor_channel_on_incoming_error,
-            cursor_channel_on_outgoing_error,
-            NULL,
-            NULL,
-            NULL))) {
+    ensure_cursor_channel_created(worker, migrate);
+    if (worker->cursor_channel == NULL) {
+        red_printf("failed to create cursor channel");
+        return;
+    }
+    channel = worker->cursor_channel;
+    red_printf("add cursor channel client");
+    ccc = cursor_channel_create_rcc(&channel->common, client, stream);
+    if (!ccc) {
         return;
     }
 #ifdef RED_STATISTICS
     channel->stat = stat_add_node(worker->stat, "cursor_channel", TRUE);
     channel->common.base.out_bytes_counter = stat_add_counter(channel->stat, "out_bytes", TRUE);
 #endif
-    ring_init(&channel->cursor_cache_lru);
-    channel->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
-    worker->cursor_channel = channel;
-    on_new_cursor_channel(worker);
+    listen_to_new_client_channel(&channel->common, &ccc->common, stream);
+    on_new_cursor_channel(worker, &ccc->common.base);
 }
 
 typedef struct __attribute__ ((__packed__)) CursorData {
@@ -9528,16 +9714,47 @@ static void red_cursor_flush(RedWorker *worker)
     red_release_cursor(worker, &local->base);
 }
 
-static void red_wait_outgoing_item(RedChannel *channel)
+static void red_wait_outgoing_item(RedChannelClient *rcc)
 {
     uint64_t end_time;
     int blocked;
 
-    if (!channel || !red_channel_all_blocked(channel)) {
+    if (!red_channel_client_blocked(rcc)) {
         return;
     }
-    red_ref_channel(channel);
+    end_time = red_now() + DETACH_TIMEOUT;
+    red_printf("blocked");
+
+    do {
+        usleep(DETACH_SLEEP_DURATION);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+    } while ((blocked = red_channel_client_blocked(rcc)) && red_now() < end_time);
+
+    if (blocked) {
+        red_printf("timeout");
+        // TODO - shutting down the socket but we still need to trigger
+        // disconnection. Right now we wait for main channel to error for that.
+        red_channel_client_shutdown(rcc);
+    }
+}
+
+static void rcc_shutdown_if_blocked(RedChannelClient *rcc)
+{
+    if (red_channel_client_blocked(rcc)) {
+        red_channel_client_shutdown(rcc);
+    }
+}
+
+static void red_wait_outgoing_items(RedChannel *channel)
+{
+    uint64_t end_time;
+    int blocked;
 
+    if (!red_channel_any_blocked(channel)) {
+        return;
+    }
+ 
     end_time = red_now() + DETACH_TIMEOUT;
     red_printf("blocked");
 
@@ -9545,59 +9762,52 @@ static void red_wait_outgoing_item(RedChannel *channel)
         usleep(DETACH_SLEEP_DURATION);
         red_channel_receive(channel);
         red_channel_send(channel);
-    } while ((blocked = red_channel_all_blocked(channel)) && red_now() < end_time);
+    } while ((blocked = red_channel_any_blocked(channel)) && red_now() < end_time);
 
     if (blocked) {
         red_printf("timeout");
-        // TODO - not MC friendly
-        red_channel_apply_clients(channel, channel->disconnect);
+        red_channel_apply_clients(channel, rcc_shutdown_if_blocked);
     }
-    red_unref_channel(channel);
 }
 
-static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
+/* TODO: more evil sync stuff. anything with the word wait in it's name. */
+static void red_wait_pipe_item_sent(RedChannelClient *rcc, PipeItem *item)
 {
-    CommonChannel *common;
+    RedChannel *channel = rcc->channel;
     uint64_t end_time;
     int item_in_pipe;
 
-    if (!channel) {
+    if (!red_channel_client_blocked(rcc)) {
         return;
     }
 
     red_printf("");
-    common = SPICE_CONTAINEROF(channel, CommonChannel, base);
-    red_ref_channel(channel);
-    channel->hold_item(channel->rcc, item);
+    channel->hold_item(rcc, item);
 
     end_time = red_now() + CHANNEL_PUSH_TIMEOUT;
 
-    if (red_channel_all_blocked(channel)) {
-        red_channel_receive(channel);
-        red_channel_send(channel);
+    if (red_channel_client_blocked(rcc)) {
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
     }
-    // todo: different push for each channel
-    red_push(common->worker);
+    red_channel_client_push(rcc);
 
     while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) {
         usleep(CHANNEL_PUSH_SLEEP_DURATION);
-        red_channel_receive(channel);
-        red_channel_send(channel);
-        red_push(common->worker);
+        red_channel_client_receive(rcc);
+        red_channel_client_send(rcc);
+        red_channel_client_push(rcc);
     }
 
     if (item_in_pipe) {
         red_printf("timeout");
-        // TODO - not MC friendly
-        red_channel_apply_clients(channel, channel->disconnect);
+        red_channel_client_disconnect(rcc);
     } else {
-        if (red_channel_item_being_sent(channel, item)) {
-            red_wait_outgoing_item(channel);
+        if (red_channel_client_item_being_sent(rcc, item)) {
+            red_wait_outgoing_item(rcc);
         }
     }
-
-    channel->release_item(channel->rcc, item, FALSE);
-    red_unref_channel(channel);
+    channel->release_item(rcc, item, FALSE);
 }
 
 static inline void handle_dev_update(RedWorker *worker)
@@ -9663,6 +9873,9 @@ static inline void handle_dev_del_memslot(RedWorker *worker)
 
 static inline void destroy_surface_wait(RedWorker *worker, Surfaces *surfaces, int surface_id)
 {
+    DisplayChannelClient *dcc = surfaces->dcc;
+    RedChannelClient *rcc = &dcc->common.base;
+
     if (!surfaces->surfaces[surface_id].context.canvas) {
         return;
     }
@@ -9672,12 +9885,12 @@ static inline void destroy_surface_wait(RedWorker *worker, Surfaces *surfaces, i
        otherwise "current" will hold items that other drawables may depend on, and then
        red_current_clear will remove them from the pipe. */
     red_current_clear(worker, surfaces, surface_id);
-    red_clear_surface_drawables_from_pipe(worker, surface_id, TRUE);
+    red_clear_surface_drawables_from_pipe(dcc, surface_id, TRUE);
     // in case that the pipe didn't contain any item that is dependent on the surface, but
     // there is one during sending.
-    red_wait_outgoing_item((RedChannel *)worker->display_channel);
-    if (worker->display_channel) {
-        ASSERT(red_channel_no_item_being_sent(&worker->display_channel->common.base));
+    red_wait_outgoing_item(rcc);
+    if (dcc) {
+        ASSERT(red_channel_client_no_item_being_sent(rcc));
     }
 }
 
@@ -9701,6 +9914,8 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 }
 
 /* called upon device reset */
+
+/* TODO: split me*/
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
     Surfaces *surfaces = &worker->surfaces;
@@ -9721,18 +9936,22 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     }
     ASSERT(ring_is_empty(&surfaces->streams));
 
-    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-    if (worker->cursor_channel) {
-        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+    if (cursor_connected(worker)) {
+        red_wait_outgoing_items(&worker->cursor_channel->common.base);
+        red_channel_pipes_add_type(&worker->cursor_channel->common.base,
+                                   PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
-            red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
+            red_pipes_add_verb(&worker->cursor_channel->common.base,
+                               SPICE_MSG_CURSOR_RESET);
         }
         ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
     }
 
-    if (worker->display_channel) {
-        red_channel_client_pipe_add_type(worker->display_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
-        red_pipe_add_verb(worker->display_channel->common.base.rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
+    if (display_connected(worker)) {
+        red_channel_pipes_add_type(&worker->display_channel->common.base,
+                                   PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
+        red_pipes_add_verb(&worker->display_channel->common.base,
+                           SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
     }
 
     red_display_clear_glz_drawables(worker->display_channel);
@@ -9788,6 +10007,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     RedWorkerMessage message;
     uint32_t surface_id;
     Surfaces *surfaces = &worker->surfaces;
+    RedChannel *cursor_red_channel = &worker->cursor_channel->common.base;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
 
@@ -9799,13 +10019,13 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
         worker->cursor = NULL;
     }
 
-    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-    if (worker->cursor_channel) {
-        red_channel_client_pipe_add_type(worker->cursor_channel->common.base.rcc, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+    if (cursor_connected(worker)) {
+        red_wait_outgoing_items(cursor_red_channel);
+        red_channel_pipes_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
         if (!worker->cursor_channel->common.base.migrate) {
-            red_pipe_add_verb(worker->cursor_channel->common.base.rcc, SPICE_MSG_CURSOR_RESET);
+            red_pipes_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
         }
-        ASSERT(red_channel_no_item_being_sent(&worker->cursor_channel->common.base));
+        ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
     }
 
     flush_all_qxl_commands(worker);
@@ -9813,7 +10033,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     red_destroy_surface(worker, surfaces, 0);
     ASSERT(ring_is_empty(&surfaces->streams));
 
-    ASSERT(!worker->surfaces.surfaces[surface_id].context.canvas);
+    ASSERT(!surfaces->surfaces[surface_id].context.canvas);
 
     worker->cursor_visible = TRUE;
     worker->cursor_position.x = worker->cursor_position.y = 0;
@@ -9861,12 +10081,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
             worker->cursor = NULL;
         }
 
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-        if (worker->cursor_channel) {
-            red_channel_client_pipe_add_type(cursor_red_channel->rcc,
-                                             PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        if (cursor_connected(worker)) {
+            red_wait_outgoing_items(cursor_red_channel);
+            red_channel_pipes_add_type(cursor_red_channel, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
             if (!cursor_red_channel->migrate) {
-                red_pipe_add_verb(cursor_red_channel->rcc, SPICE_MSG_CURSOR_RESET);
+                red_pipes_add_verb(cursor_red_channel, SPICE_MSG_CURSOR_RESET);
             }
             ASSERT(red_channel_no_item_being_sent(cursor_red_channel));
 
@@ -9912,7 +10131,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
 
         red_printf("disconnect display client");
         receive_data(worker->channel, &rcc, sizeof(RedChannelClient *));
-        red_disconnect_display(rcc);
+        display_channel_client_disconnect(rcc);
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
@@ -9927,15 +10146,15 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_printf("stop");
         ASSERT(worker->running);
         worker->running = FALSE;
-        red_display_clear_glz_drawables(worker->display_channel);
+        red_display_client_clear_glz_drawables(worker->surfaces.dcc);
         for (x = 0; x < NUM_SURFACES; ++x) {
             if (worker->surfaces.surfaces[x].context.canvas) {
                 red_current_flush(worker, &worker->surfaces, x);
             }
         }
         red_cursor_flush(worker);
-        red_wait_outgoing_item((RedChannel *)worker->display_channel);
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+        red_wait_outgoing_items(display_red_channel);
+        red_wait_outgoing_items(cursor_red_channel);
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
@@ -10162,6 +10381,13 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     write_message(worker->channel, &message);
 }
 
+static void red_display_cc_free_glz_drawables(RedChannelClient *rcc)
+{
+    DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
+
+    red_display_handle_glz_drawables_to_free(dcc);
+}
+
 void *red_worker_main(void *arg)
 {
     RedWorker worker;
@@ -10192,11 +10418,12 @@ void *red_worker_main(void *arg)
         num_events = epoll_wait(worker.epoll, events, MAX_EPOLL_SOURCES, worker.epoll_timeout);
         red_handle_streams_timout(&worker, &worker.surfaces);
 
-        if (worker.display_channel && worker.display_channel->glz_dict) {
+        if (worker.display_channel) {
             /* during migration, in the dest, the display channel can be initialized
                while the global lz data not since migrate data msg hasn't been
                received yet */
-            red_display_handle_glz_drawables_to_free(worker.display_channel);
+            red_channel_apply_clients(&worker.display_channel->common.base,
+                red_display_cc_free_glz_drawables);
         }
 
         worker.epoll_timeout = INF_EPOLL_WAIT;
-- 
1.7.4.4



More information about the Spice-devel mailing list