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

Alon Levy alevy at redhat.com
Thu May 5 06:01:39 PDT 2011


On Tue, May 03, 2011 at 01:56:25AM +0200, Marc-André Lureau wrote:
> On Tue, Apr 26, 2011 at 12:54 PM, Alon Levy <alevy at redhat.com> wrote:
> > 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
> 
> Last line should be with 05/62: move pipe from RedChannel

done.

> 
> > \ 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;
> 
> Can you add a comment to explain where dcc is being freed?
> 

I don't think it is. I mean, it should be released by
red_channel_client_destroy(&dcc->common.base), I'll need to find where that is
called / where that should be called.

> > +    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;
> 
> Same here, where is display_channel being freed?
> 

will check.

> > +    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)
> > +{
> 
> This is just an example, but from what I can see, we could just take
> CommonChannelClient as an argument, and access the rest from it.
> 
> It's easier to require the least amount of arguments, imho, and it
> seems there is a lot if not hundreds of function which could benefit
> this simplification as well. That would also help to put more correct
> prefixes and function names.
> 
> listen_to_new_client_channel() -> common_channel_client_listen()
> 

Yeah, I've taken that to heart, is it working wonders but is taking some time
to do all the fixes. RedRender in particular got a worker variable (despite my
pointing out it can be inferred), and I'll do the same any place I can. Ditto
about the correct prefix, and last about dropping usage of __ prefix.

> > +    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
> >
> > _______________________________________________
> > Spice-devel mailing list
> > Spice-devel at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/spice-devel
> >
> 
> 
> 
> -- 
> Marc-André Lureau


More information about the Spice-devel mailing list