[Spice-devel] [PATCH v2 2/4] rename red-dispatcher.* files to red-qxl.*

Jonathon Jongsma jjongsma at redhat.com
Thu Mar 3 17:40:24 UTC 2016


Acked-by: Jonathon Jongsma <jjongsma at redhat.com>


On Thu, 2016-03-03 at 16:28 +0000, Frediano Ziglio wrote:
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
>  server/Makefile.am        |    4 +-
>  server/agent-msg-filter.c |    2 +-
>  server/display-channel.h  |    2 +-
>  server/red-dispatcher.c   | 1032 --------------------------------------------
> -
>  server/red-dispatcher.h   |  272 ------------
>  server/red-qxl.c          | 1032
> +++++++++++++++++++++++++++++++++++++++++++++
>  server/red-qxl.h          |  272 ++++++++++++
>  server/red-worker.h       |    2 +-
>  server/reds.c             |    2 +-
>  server/sound.c            |    2 +-
>  10 files changed, 1311 insertions(+), 1311 deletions(-)
>  delete mode 100644 server/red-dispatcher.c
>  delete mode 100644 server/red-dispatcher.h
>  create mode 100644 server/red-qxl.c
>  create mode 100644 server/red-qxl.h
> 
> diff --git a/server/Makefile.am b/server/Makefile.am
> index 9eb5f44..a7a8d9f 100644
> --- a/server/Makefile.am
> +++ b/server/Makefile.am
> @@ -93,8 +93,8 @@ libserver_la_SOURCES =				\
>  	red-common.h				\
>  	dispatcher.c				\
>  	dispatcher.h				\
> -	red-dispatcher.c			\
> -	red-dispatcher.h			\
> +	red-qxl.c				\
> +	red-qxl.h				\
>  	main-dispatcher.c			\
>  	main-dispatcher.h			\
>  	migration-protocol.h		\
> diff --git a/server/agent-msg-filter.c b/server/agent-msg-filter.c
> index d72a3e4..a6aee9e 100644
> --- a/server/agent-msg-filter.c
> +++ b/server/agent-msg-filter.c
> @@ -25,7 +25,7 @@
>  #include "red-common.h"
>  #include "agent-msg-filter.h"
>  #include "reds.h"
> -#include "red-dispatcher.h"
> +#include "red-qxl.h"
>  
>  void agent_msg_filter_init(struct AgentMsgFilter *filter,
>                             gboolean copy_paste, gboolean file_xfer,
> diff --git a/server/display-channel.h b/server/display-channel.h
> index cf40edd..1bccd22 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -33,7 +33,7 @@
>  #include "red-record-qxl.h"
>  #include "demarshallers.h"
>  #include "red-channel.h"
> -#include "red-dispatcher.h"
> +#include "red-qxl.h"
>  #include "dispatcher.h"
>  #include "main-channel.h"
>  #include "migration-protocol.h"
> diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c
> deleted file mode 100644
> index cfc113d..0000000
> --- a/server/red-dispatcher.c
> +++ /dev/null
> @@ -1,1032 +0,0 @@
> -/*
> -   Copyright (C) 2009 Red Hat, Inc.
> -
> -   This library is free software; you can redistribute it and/or
> -   modify it under the terms of the GNU Lesser General Public
> -   License as published by the Free Software Foundation; either
> -   version 2.1 of the License, or (at your option) any later version.
> -
> -   This library is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> -   Lesser General Public License for more details.
> -
> -   You should have received a copy of the GNU Lesser General Public
> -   License along with this library; if not, see <http://www.gnu.org/licenses/
> >.
> -*/
> -#ifdef HAVE_CONFIG_H
> -#include <config.h>
> -#endif
> -
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <unistd.h>
> -#include <errno.h>
> -#include <string.h>
> -#include <pthread.h>
> -#include <sys/socket.h>
> -#include <inttypes.h>
> -
> -#include <spice/qxl_dev.h>
> -#include "common/quic.h"
> -
> -#include "spice.h"
> -#include "red-worker.h"
> -#include "sw-canvas.h"
> -#include "reds.h"
> -#include "dispatcher.h"
> -#include "red-parse-qxl.h"
> -
> -#include "red-dispatcher.h"
> -
> -
> -struct AsyncCommand {
> -    RedWorkerMessage message;
> -    uint64_t cookie;
> -};
> -
> -struct RedDispatcher {
> -    QXLWorker base;
> -    QXLInstance *qxl;
> -    Dispatcher dispatcher;
> -    uint32_t pending;
> -    int primary_active;
> -    int x_res;
> -    int y_res;
> -    int use_hardware_cursor;
> -    QXLDevSurfaceCreate surface_create;
> -    unsigned int max_monitors;
> -};
> -
> -static int red_qxl_check_qxl_version(RedDispatcher *rd, int major, int minor)
> -{
> -    int qxl_major = rd->qxl->st->qif->base.major_version;
> -    int qxl_minor = rd->qxl->st->qif->base.minor_version;
> -
> -    return ((qxl_major > major) ||
> -            ((qxl_major == major) && (qxl_minor >= minor)));
> -}
> -
> -static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
> -                                     RedsStream *stream, int migration,
> -                                     int num_common_caps, uint32_t
> *common_caps, int num_caps,
> -                                     uint32_t *caps)
> -{
> -    RedWorkerMessageDisplayConnect payload = {0,};
> -    RedDispatcher *dispatcher;
> -
> -    spice_debug("%s", "");
> -    dispatcher = (RedDispatcher *)channel->data;
> -    payload.client = client;
> -    payload.stream = stream;
> -    payload.migration = migration;
> -    payload.num_common_caps = num_common_caps;
> -    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
> -    payload.num_caps = num_caps;
> -    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
> -
> -    memcpy(payload.common_caps, common_caps,
> sizeof(uint32_t)*num_common_caps);
> -    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> -                            &payload);
> -}
> -
> -static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
> -{
> -    RedWorkerMessageDisplayDisconnect payload;
> -    RedDispatcher *dispatcher;
> -
> -    if (!rcc->channel) {
> -        return;
> -    }
> -
> -    dispatcher = (RedDispatcher *)rcc->channel->data;
> -
> -    spice_printerr("");
> -    payload.rcc = rcc;
> -
> -    // TODO: we turned it to be sync, due to client_destroy . Should we
> support async? - for this we will need ref count
> -    // for channels
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
> -                            &payload);
> -}
> -
> -static void red_qxl_display_migrate(RedChannelClient *rcc)
> -{
> -    RedWorkerMessageDisplayMigrate payload;
> -    RedDispatcher *dispatcher;
> -    if (!rcc->channel) {
> -        return;
> -    }
> -    dispatcher = (RedDispatcher *)rcc->channel->data;
> -    spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel
> ->id);
> -    payload.rcc = rcc;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> -                            &payload);
> -}
> -
> -static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client,
> RedsStream *stream,
> -                                    int migration, int num_common_caps,
> -                                    uint32_t *common_caps, int num_caps,
> -                                    uint32_t *caps)
> -{
> -    RedWorkerMessageCursorConnect payload = {0,};
> -    RedDispatcher *dispatcher = (RedDispatcher *)channel->data;
> -    spice_printerr("");
> -    payload.client = client;
> -    payload.stream = stream;
> -    payload.migration = migration;
> -    payload.num_common_caps = num_common_caps;
> -    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
> -    payload.num_caps = num_caps;
> -    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
> -
> -    memcpy(payload.common_caps, common_caps,
> sizeof(uint32_t)*num_common_caps);
> -    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_CURSOR_CONNECT,
> -                            &payload);
> -}
> -
> -static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
> -{
> -    RedWorkerMessageCursorDisconnect payload;
> -    RedDispatcher *dispatcher;
> -
> -    if (!rcc->channel) {
> -        return;
> -    }
> -
> -    dispatcher = (RedDispatcher *)rcc->channel->data;
> -    spice_printerr("");
> -    payload.rcc = rcc;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
> -                            &payload);
> -}
> -
> -static void red_qxl_cursor_migrate(RedChannelClient *rcc)
> -{
> -    RedWorkerMessageCursorMigrate payload;
> -    RedDispatcher *dispatcher;
> -
> -    if (!rcc->channel) {
> -        return;
> -    }
> -    dispatcher = (RedDispatcher *)rcc->channel->data;
> -    spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel
> ->id);
> -    payload.rcc = rcc;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_CURSOR_MIGRATE,
> -                            &payload);
> -}
> -
> -static void red_qxl_update_area(RedDispatcher *dispatcher, uint32_t
> surface_id,
> -                                QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
> -                                uint32_t num_dirty_rects, uint32_t
> clear_dirty_region)
> -{
> -    RedWorkerMessageUpdate payload = {0,};
> -
> -    payload.surface_id = surface_id;
> -    payload.qxl_area = qxl_area;
> -    payload.qxl_dirty_rects = qxl_dirty_rects;
> -    payload.num_dirty_rects = num_dirty_rects;
> -    payload.clear_dirty_region = clear_dirty_region;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_UPDATE,
> -                            &payload);
> -}
> -
> -gboolean red_qxl_use_client_monitors_config(RedDispatcher *dispatcher)
> -{
> -    return (red_qxl_check_qxl_version(dispatcher, 3, 3) &&
> -        dispatcher->qxl->st->qif->client_monitors_config &&
> -        dispatcher->qxl->st->qif->client_monitors_config(dispatcher->qxl,
> NULL));
> -}
> -
> -gboolean red_qxl_client_monitors_config(RedDispatcher *dispatcher,
> -                                        VDAgentMonitorsConfig
> *monitors_config)
> -{
> -    return (dispatcher->qxl->st->qif->client_monitors_config &&
> -        dispatcher->qxl->st->qif->client_monitors_config(dispatcher->qxl,
> -                                                          monitors_config));
> -}
> -
> -static AsyncCommand *async_command_alloc(RedDispatcher *dispatcher,
> -                                         RedWorkerMessage message,
> -                                         uint64_t cookie)
> -{
> -    AsyncCommand *async_command = spice_new0(AsyncCommand, 1);
> -
> -    async_command->cookie = cookie;
> -    async_command->message = message;
> -
> -    spice_debug("%p", async_command);
> -    return async_command;
> -}
> -
> -static void red_qxl_update_area_async(RedDispatcher *dispatcher,
> -                                      uint32_t surface_id,
> -                                      QXLRect *qxl_area,
> -                                      uint32_t clear_dirty_region,
> -                                      uint64_t cookie)
> -{
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
> -    RedWorkerMessageUpdateAsync payload;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.surface_id = surface_id;
> -    payload.qxl_area = *qxl_area;
> -    payload.clear_dirty_region = clear_dirty_region;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            message,
> -                            &payload);
> -}
> -
> -static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t
> surface_id,
> -                                   QXLRect *qxl_area, QXLRect
> *qxl_dirty_rects,
> -                                   uint32_t num_dirty_rects, uint32_t
> clear_dirty_region)
> -{
> -    red_qxl_update_area((RedDispatcher*)qxl_worker, surface_id, qxl_area,
> -                        qxl_dirty_rects, num_dirty_rects,
> clear_dirty_region);
> -}
> -
> -static void red_qxl_add_memslot(RedDispatcher *dispatcher, QXLDevMemSlot
> *mem_slot)
> -{
> -    RedWorkerMessageAddMemslot payload;
> -
> -    payload.mem_slot = *mem_slot;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_ADD_MEMSLOT,
> -                            &payload);
> -}
> -
> -static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot
> *mem_slot)
> -{
> -    red_qxl_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
> -}
> -
> -static void red_qxl_add_memslot_async(RedDispatcher *dispatcher,
> QXLDevMemSlot *mem_slot, uint64_t cookie)
> -{
> -    RedWorkerMessageAddMemslotAsync payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.mem_slot = *mem_slot;
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void red_qxl_del_memslot(RedDispatcher *dispatcher, uint32_t
> slot_group_id, uint32_t slot_id)
> -{
> -    RedWorkerMessageDelMemslot payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
> -
> -    payload.slot_group_id = slot_group_id;
> -    payload.slot_id = slot_id;
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t
> slot_group_id, uint32_t slot_id)
> -{
> -    red_qxl_del_memslot((RedDispatcher*)qxl_worker, slot_group_id, slot_id);
> -}
> -
> -static void red_qxl_destroy_surfaces(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageDestroySurfaces payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DESTROY_SURFACES,
> -                            &payload);
> -}
> -
> -static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
> -{
> -    red_qxl_destroy_surfaces((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_destroy_surfaces_async(RedDispatcher *dispatcher,
> uint64_t cookie)
> -{
> -    RedWorkerMessageDestroySurfacesAsync payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void red_qxl_destroy_primary_surface_complete(RedDispatcher
> *dispatcher)
> -{
> -    dispatcher->x_res = 0;
> -    dispatcher->y_res = 0;
> -    dispatcher->use_hardware_cursor = FALSE;
> -    dispatcher->primary_active = FALSE;
> -
> -    reds_update_client_mouse_allowed(reds);
> -}
> -
> -static void
> -red_qxl_destroy_primary_surface_sync(RedDispatcher *dispatcher,
> -                                     uint32_t surface_id)
> -{
> -    RedWorkerMessageDestroyPrimarySurface payload;
> -    payload.surface_id = surface_id;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
> -                            &payload);
> -    red_qxl_destroy_primary_surface_complete(dispatcher);
> -}
> -
> -static void
> -red_qxl_destroy_primary_surface_async(RedDispatcher *dispatcher,
> -                                      uint32_t surface_id, uint64_t cookie)
> -{
> -    RedWorkerMessageDestroyPrimarySurfaceAsync payload;
> -    RedWorkerMessage message =
> RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.surface_id = surface_id;
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void
> -red_qxl_destroy_primary_surface(RedDispatcher *dispatcher,
> -                                uint32_t surface_id, int async, uint64_t
> cookie)
> -{
> -    if (async) {
> -        red_qxl_destroy_primary_surface_async(dispatcher, surface_id,
> cookie);
> -    } else {
> -        red_qxl_destroy_primary_surface_sync(dispatcher, surface_id);
> -    }
> -}
> -
> -static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker,
> uint32_t surface_id)
> -{
> -    red_qxl_destroy_primary_surface((RedDispatcher*)qxl_worker, surface_id,
> 0, 0);
> -}
> -
> -static void red_qxl_create_primary_surface_complete(RedDispatcher
> *dispatcher)
> -{
> -    QXLDevSurfaceCreate *surface = &dispatcher->surface_create;
> -
> -    dispatcher->x_res = surface->width;
> -    dispatcher->y_res = surface->height;
> -    dispatcher->use_hardware_cursor = surface->mouse_mode;
> -    dispatcher->primary_active = TRUE;
> -
> -    reds_update_client_mouse_allowed(reds);
> -    memset(&dispatcher->surface_create, 0, sizeof(QXLDevSurfaceCreate));
> -}
> -
> -static void
> -red_qxl_create_primary_surface_async(RedDispatcher *dispatcher, uint32_t
> surface_id,
> -                                     QXLDevSurfaceCreate *surface, uint64_t
> cookie)
> -{
> -    RedWorkerMessageCreatePrimarySurfaceAsync payload;
> -    RedWorkerMessage message =
> RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
> -
> -    dispatcher->surface_create = *surface;
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.surface_id = surface_id;
> -    payload.surface = *surface;
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void
> -red_qxl_create_primary_surface_sync(RedDispatcher *dispatcher, uint32_t
> surface_id,
> -                                    QXLDevSurfaceCreate *surface)
> -{
> -    RedWorkerMessageCreatePrimarySurface payload = {0,};
> -
> -    dispatcher->surface_create = *surface;
> -    payload.surface_id = surface_id;
> -    payload.surface = *surface;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
> -                            &payload);
> -    red_qxl_create_primary_surface_complete(dispatcher);
> -}
> -
> -static void
> -red_qxl_create_primary_surface(RedDispatcher *dispatcher, uint32_t
> surface_id,
> -                               QXLDevSurfaceCreate *surface, int async,
> uint64_t cookie)
> -{
> -    if (async) {
> -        red_qxl_create_primary_surface_async(dispatcher, surface_id, surface,
> cookie);
> -    } else {
> -        red_qxl_create_primary_surface_sync(dispatcher, surface_id, surface);
> -    }
> -}
> -
> -static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t
> surface_id,
> -                                      QXLDevSurfaceCreate *surface)
> -{
> -    red_qxl_create_primary_surface((RedDispatcher*)qxl_worker, surface_id,
> surface, 0, 0);
> -}
> -
> -static void red_qxl_reset_image_cache(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageResetImageCache payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
> -                            &payload);
> -}
> -
> -static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
> -{
> -    red_qxl_reset_image_cache((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_reset_cursor(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageResetCursor payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_RESET_CURSOR,
> -                            &payload);
> -}
> -
> -static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
> -{
> -    red_qxl_reset_cursor((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_destroy_surface_wait_sync(RedDispatcher *dispatcher,
> -                                              uint32_t surface_id)
> -{
> -    RedWorkerMessageDestroySurfaceWait payload;
> -
> -    payload.surface_id = surface_id;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
> -                            &payload);
> -}
> -
> -static void red_qxl_destroy_surface_wait_async(RedDispatcher *dispatcher,
> -                                               uint32_t surface_id,
> -                                               uint64_t cookie)
> -{
> -    RedWorkerMessageDestroySurfaceWaitAsync payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.surface_id = surface_id;
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void red_qxl_destroy_surface_wait(RedDispatcher *dispatcher,
> -                                         uint32_t surface_id,
> -                                         int async, uint64_t cookie)
> -{
> -    if (async) {
> -        red_qxl_destroy_surface_wait_async(dispatcher, surface_id, cookie);
> -    } else {
> -        red_qxl_destroy_surface_wait_sync(dispatcher, surface_id);
> -    }
> -}
> -
> -static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t
> surface_id)
> -{
> -    red_qxl_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id, 0,
> 0);
> -}
> -
> -static void red_qxl_reset_memslots(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageResetMemslots payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_RESET_MEMSLOTS,
> -                            &payload);
> -}
> -
> -static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
> -{
> -    red_qxl_reset_memslots((RedDispatcher*)qxl_worker);
> -}
> -
> -static bool red_qxl_set_pending(RedDispatcher *dispatcher, int pending)
> -{
> -    // this is not atomic but is not an issue
> -    if (test_bit(pending, dispatcher->pending)) {
> -        return TRUE;
> -    }
> -
> -    set_bit(pending, &dispatcher->pending);
> -    return FALSE;
> -}
> -
> -static void red_qxl_wakeup(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageWakeup payload;
> -
> -    if (red_qxl_set_pending(dispatcher, RED_DISPATCHER_PENDING_WAKEUP))
> -        return;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_WAKEUP,
> -                            &payload);
> -}
> -
> -static void qxl_worker_wakeup(QXLWorker *qxl_worker)
> -{
> -    red_qxl_wakeup((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_oom(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageOom payload;
> -
> -    if (red_qxl_set_pending(dispatcher, RED_DISPATCHER_PENDING_OOM))
> -        return;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_OOM,
> -                            &payload);
> -}
> -
> -static void qxl_worker_oom(QXLWorker *qxl_worker)
> -{
> -    red_qxl_oom((RedDispatcher*)qxl_worker);
> -}
> -
> -void red_qxl_start(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageStart payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_START,
> -                            &payload);
> -}
> -
> -static void qxl_worker_start(QXLWorker *qxl_worker)
> -{
> -    red_qxl_start((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t
> cookie)
> -{
> -    RedWorkerMessageFlushSurfacesAsync payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void red_qxl_monitors_config_async(RedDispatcher *dispatcher,
> -                                          QXLPHYSICAL monitors_config,
> -                                          int group_id,
> -                                          uint64_t cookie)
> -{
> -    RedWorkerMessageMonitorsConfigAsync payload;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC;
> -
> -    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> -    payload.monitors_config = monitors_config;
> -    payload.group_id = group_id;
> -    payload.max_monitors = dispatcher->max_monitors;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> -}
> -
> -static void red_qxl_driver_unload(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageDriverUnload payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_DRIVER_UNLOAD,
> -                            &payload);
> -}
> -
> -void red_qxl_stop(RedDispatcher *dispatcher)
> -{
> -    RedWorkerMessageStop payload;
> -
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_STOP,
> -                            &payload);
> -}
> -
> -static void qxl_worker_stop(QXLWorker *qxl_worker)
> -{
> -    red_qxl_stop((RedDispatcher*)qxl_worker);
> -}
> -
> -static void red_qxl_loadvm_commands(RedDispatcher *dispatcher,
> -                                    struct QXLCommandExt *ext,
> -                                    uint32_t count)
> -{
> -    RedWorkerMessageLoadvmCommands payload;
> -
> -    spice_printerr("");
> -    payload.count = count;
> -    payload.ext = ext;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_LOADVM_COMMANDS,
> -                            &payload);
> -}
> -
> -static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
> -                                       struct QXLCommandExt *ext,
> -                                       uint32_t count)
> -{
> -    red_qxl_loadvm_commands((RedDispatcher*)qxl_worker, ext, count);
> -}
> -
> -void red_qxl_set_mm_time(RedDispatcher *dispatcher, uint32_t mm_time)
> -{
> -    dispatcher->qxl->st->qif->set_mm_time(dispatcher->qxl, mm_time);
> -}
> -
> -void red_qxl_attach_worker(RedDispatcher *dispatcher)
> -{
> -    QXLInstance *qxl = dispatcher->qxl;
> -    qxl->st->qif->attache_worker(qxl, &dispatcher->base);
> -}
> -
> -void red_qxl_set_compression_level(RedDispatcher *dispatcher, int level)
> -{
> -    dispatcher->qxl->st->qif->set_compression_level(dispatcher->qxl, level);
> -}
> -
> -uint32_t red_qxl_get_ram_size(RedDispatcher *dispatcher)
> -{
> -    QXLDevInitInfo qxl_info;
> -    dispatcher->qxl->st->qif->get_init_info(dispatcher->qxl, &qxl_info);
> -    return qxl_info.qxl_ram_size;
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_wakeup(QXLInstance *instance)
> -{
> -    red_qxl_wakeup(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_oom(QXLInstance *instance)
> -{
> -    red_qxl_oom(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_start(QXLInstance *instance)
> -{
> -    red_qxl_start(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_stop(QXLInstance *instance)
> -{
> -    red_qxl_stop(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
> -                    struct QXLRect *area, struct QXLRect *dirty_rects,
> -                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
> -{
> -    red_qxl_update_area(instance->st->dispatcher, surface_id, area,
> dirty_rects,
> -                        num_dirty_rects, clear_dirty_region);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot)
> -{
> -    red_qxl_add_memslot(instance->st->dispatcher, slot);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id,
> uint32_t slot_id)
> -{
> -    red_qxl_del_memslot(instance->st->dispatcher, slot_group_id, slot_id);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_reset_memslots(QXLInstance *instance)
> -{
> -    red_qxl_reset_memslots(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_surfaces(QXLInstance *instance)
> -{
> -    red_qxl_destroy_surfaces(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t
> surface_id)
> -{
> -    red_qxl_destroy_primary_surface(instance->st->dispatcher, surface_id, 0,
> 0);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t
> surface_id,
> -                                QXLDevSurfaceCreate *surface)
> -{
> -    red_qxl_create_primary_surface(instance->st->dispatcher, surface_id,
> surface, 0, 0);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_reset_image_cache(QXLInstance *instance)
> -{
> -    red_qxl_reset_image_cache(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_reset_cursor(QXLInstance *instance)
> -{
> -    red_qxl_reset_cursor(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t
> surface_id)
> -{
> -    red_qxl_destroy_surface_wait(instance->st->dispatcher, surface_id, 0, 0);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt
> *ext, uint32_t count)
> -{
> -    red_qxl_loadvm_commands(instance->st->dispatcher, ext, count);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id,
> QXLRect *qxl_area,
> -                                 uint32_t clear_dirty_region, uint64_t
> cookie)
> -{
> -    red_qxl_update_area_async(instance->st->dispatcher, surface_id, qxl_area,
> -                                     clear_dirty_region, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot,
> uint64_t cookie)
> -{
> -    red_qxl_add_memslot_async(instance->st->dispatcher, slot, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie)
> -{
> -    red_qxl_destroy_surfaces_async(instance->st->dispatcher, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t
> surface_id, uint64_t cookie)
> -{
> -    red_qxl_destroy_primary_surface(instance->st->dispatcher, surface_id, 1,
> cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t
> surface_id,
> -                                QXLDevSurfaceCreate *surface, uint64_t
> cookie)
> -{
> -    red_qxl_create_primary_surface(instance->st->dispatcher, surface_id,
> surface, 1, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t
> surface_id, uint64_t cookie)
> -{
> -    red_qxl_destroy_surface_wait(instance->st->dispatcher, surface_id, 1,
> cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
> -{
> -    red_qxl_flush_surfaces_async(instance->st->dispatcher, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_monitors_config_async(QXLInstance *instance, QXLPHYSICAL
> monitors_config,
> -                                     int group_id, uint64_t cookie)
> -{
> -    red_qxl_monitors_config_async(instance->st->dispatcher, monitors_config,
> group_id, cookie);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_set_max_monitors(QXLInstance *instance, unsigned int
> max_monitors)
> -{
> -    instance->st->dispatcher->max_monitors = MAX(1u, max_monitors);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_driver_unload(QXLInstance *instance)
> -{
> -    red_qxl_driver_unload(instance->st->dispatcher);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_gl_scanout(QXLInstance *qxl,
> -                          int fd,
> -                          uint32_t width, uint32_t height,
> -                          uint32_t stride, uint32_t format,
> -                          int y_0_top)
> -{
> -    spice_return_if_fail(qxl != NULL);
> -    spice_return_if_fail(qxl->st->gl_draw_async == NULL);
> -
> -    pthread_mutex_lock(&qxl->st->scanout_mutex);
> -
> -    if (qxl->st->scanout.drm_dma_buf_fd != -1) {
> -        close(qxl->st->scanout.drm_dma_buf_fd);
> -    }
> -
> -    qxl->st->scanout = (SpiceMsgDisplayGlScanoutUnix) {
> -        .flags = y_0_top ? SPICE_GL_SCANOUT_FLAGS_Y0TOP : 0,
> -        .drm_dma_buf_fd = fd,
> -        .width = width,
> -        .height = height,
> -        .stride = stride,
> -        .drm_fourcc_format = format
> -    };
> -
> -    pthread_mutex_unlock(&qxl->st->scanout_mutex);
> -
> -    /* FIXME: find a way to coallesce all pending SCANOUTs */
> -    dispatcher_send_message(&qxl->st->dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_GL_SCANOUT, NULL);
> -}
> -
> -SPICE_GNUC_VISIBLE
> -void spice_qxl_gl_draw_async(QXLInstance *qxl,
> -                             uint32_t x, uint32_t y,
> -                             uint32_t w, uint32_t h,
> -                             uint64_t cookie)
> -{
> -    RedDispatcher *dispatcher;
> -    RedWorkerMessage message = RED_WORKER_MESSAGE_GL_DRAW_ASYNC;
> -    SpiceMsgDisplayGlDraw draw = {
> -        .x = x,
> -        .y = y,
> -        .w = w,
> -        .h = h
> -    };
> -
> -    spice_return_if_fail(qxl != NULL);
> -    spice_return_if_fail(qxl->st->scanout.drm_dma_buf_fd != -1);
> -    spice_return_if_fail(qxl->st->gl_draw_async == NULL);
> -
> -    dispatcher = qxl->st->dispatcher;
> -    qxl->st->gl_draw_async = async_command_alloc(dispatcher, message,
> cookie);
> -    dispatcher_send_message(&dispatcher->dispatcher, message, &draw);
> -}
> -
> -void red_qxl_async_complete(struct RedDispatcher *dispatcher,
> -                            AsyncCommand *async_command)
> -{
> -    spice_debug("%p: cookie %" PRId64, async_command, async_command->cookie);
> -    switch (async_command->message) {
> -    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
> -    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
> -    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
> -    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
> -    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
> -    case RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC:
> -    case RED_WORKER_MESSAGE_GL_DRAW_ASYNC:
> -        break;
> -    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
> -        red_qxl_create_primary_surface_complete(dispatcher);
> -        break;
> -    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
> -        red_qxl_destroy_primary_surface_complete(dispatcher);
> -        break;
> -    default:
> -        spice_warning("unexpected message %d", async_command->message);
> -    }
> -    dispatcher->qxl->st->qif->async_complete(dispatcher->qxl,
> -                                             async_command->cookie);
> -    free(async_command);
> -}
> -
> -void red_qxl_init(QXLInstance *qxl)
> -{
> -    RedDispatcher *red_dispatcher;
> -    RedChannel *channel;
> -    ClientCbs client_cbs = { NULL, };
> -
> -    spice_return_if_fail(qxl != NULL);
> -    spice_return_if_fail(qxl->st->dispatcher == NULL);
> -
> -    static gsize initialized = FALSE;
> -    if (g_once_init_enter(&initialized)) {
> -        quic_init();
> -        sw_canvas_init();
> -        g_once_init_leave(&initialized, TRUE);
> -    }
> -
> -    red_dispatcher = spice_new0(RedDispatcher, 1);
> -    red_dispatcher->qxl = qxl;
> -    dispatcher_init(&red_dispatcher->dispatcher, RED_WORKER_MESSAGE_COUNT,
> NULL);
> -    red_dispatcher->base.major_version = SPICE_INTERFACE_QXL_MAJOR;
> -    red_dispatcher->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
> -    red_dispatcher->base.wakeup = qxl_worker_wakeup;
> -    red_dispatcher->base.oom = qxl_worker_oom;
> -    red_dispatcher->base.start = qxl_worker_start;
> -    red_dispatcher->base.stop = qxl_worker_stop;
> -    red_dispatcher->base.update_area = qxl_worker_update_area;
> -    red_dispatcher->base.add_memslot = qxl_worker_add_memslot;
> -    red_dispatcher->base.del_memslot = qxl_worker_del_memslot;
> -    red_dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
> -    red_dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
> -    red_dispatcher->base.create_primary_surface =
> qxl_worker_create_primary_surface;
> -    red_dispatcher->base.destroy_primary_surface =
> qxl_worker_destroy_primary_surface;
> -
> -    red_dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
> -    red_dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
> -    red_dispatcher->base.destroy_surface_wait =
> qxl_worker_destroy_surface_wait;
> -    red_dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
> -
> -    red_dispatcher->max_monitors = UINT_MAX;
> -
> -    // TODO: reference and free
> -    RedWorker *worker = red_worker_new(qxl, red_dispatcher);
> -
> -    // TODO: move to their respective channel files
> -    channel = red_worker_get_cursor_channel(worker);
> -    client_cbs.connect = red_qxl_set_cursor_peer;
> -    client_cbs.disconnect = red_qxl_disconnect_cursor_peer;
> -    client_cbs.migrate = red_qxl_cursor_migrate;
> -    red_channel_register_client_cbs(channel, &client_cbs);
> -    red_channel_set_data(channel, red_dispatcher);
> -    reds_register_channel(reds, channel);
> -
> -    channel = red_worker_get_display_channel(worker);
> -    client_cbs.connect = red_qxl_set_display_peer;
> -    client_cbs.disconnect = red_qxl_disconnect_display_peer;
> -    client_cbs.migrate = red_qxl_display_migrate;
> -    red_channel_register_client_cbs(channel, &client_cbs);
> -    red_channel_set_data(channel, red_dispatcher);
> -    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
> -    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
> -    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
> -    reds_register_channel(reds, channel);
> -
> -    red_worker_run(worker);
> -
> -    qxl->st->dispatcher = red_dispatcher;
> -}
> -
> -struct Dispatcher *red_qxl_get_dispatcher(RedDispatcher *red_dispatcher)
> -{
> -    return &red_dispatcher->dispatcher;
> -}
> -
> -void red_qxl_set_dispatcher_opaque(RedDispatcher *red_dispatcher,
> -                                          void *opaque)
> -{
> -    dispatcher_set_opaque(&red_dispatcher->dispatcher, opaque);
> -}
> -
> -void red_qxl_clear_pending(RedDispatcher *red_dispatcher, int pending)
> -{
> -    spice_return_if_fail(red_dispatcher != NULL);
> -
> -    clear_bit(pending, &red_dispatcher->pending);
> -}
> -
> -gboolean red_qxl_get_primary_active(RedDispatcher *dispatcher)
> -{
> -    return dispatcher->primary_active;
> -}
> -
> -gboolean red_qxl_get_allow_client_mouse(RedDispatcher *dispatcher, gint
> *x_res, gint *y_res)
> -{
> -    if (dispatcher->use_hardware_cursor) {
> -        if (x_res)
> -            *x_res = dispatcher->x_res;
> -        if (y_res)
> -            *y_res = dispatcher->y_res;
> -    }
> -    return dispatcher->use_hardware_cursor;
> -}
> -
> -void red_qxl_on_ic_change(RedDispatcher *dispatcher, SpiceImageCompression
> ic)
> -{
> -    RedWorkerMessageSetCompression payload;
> -    payload.image_compression = ic;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_SET_COMPRESSION,
> -                            &payload);
> -}
> -
> -void red_qxl_on_sv_change(RedDispatcher *dispatcher, int sv)
> -{
> -    RedWorkerMessageSetStreamingVideo payload;
> -    payload.streaming_video = sv;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
> -                            &payload);
> -}
> -
> -void red_qxl_set_mouse_mode(RedDispatcher *dispatcher, uint32_t mode)
> -{
> -    RedWorkerMessageSetMouseMode payload;
> -    payload.mode = mode;
> -    dispatcher_send_message(&dispatcher->dispatcher,
> -                            RED_WORKER_MESSAGE_SET_MOUSE_MODE,
> -                            &payload);
> -}
> diff --git a/server/red-dispatcher.h b/server/red-dispatcher.h
> deleted file mode 100644
> index 1348e6c..0000000
> --- a/server/red-dispatcher.h
> +++ /dev/null
> @@ -1,272 +0,0 @@
> -/*
> -   Copyright (C) 2009 Red Hat, Inc.
> -
> -   This library is free software; you can redistribute it and/or
> -   modify it under the terms of the GNU Lesser General Public
> -   License as published by the Free Software Foundation; either
> -   version 2.1 of the License, or (at your option) any later version.
> -
> -   This library is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> -   Lesser General Public License for more details.
> -
> -   You should have received a copy of the GNU Lesser General Public
> -   License along with this library; if not, see <http://www.gnu.org/licenses/
> >.
> -*/
> -
> -#ifndef _H_RED_DISPATCHER
> -#define _H_RED_DISPATCHER
> -
> -#include "red-channel.h"
> -
> -typedef struct RedDispatcher RedDispatcher;
> -
> -typedef struct AsyncCommand AsyncCommand;
> -
> -void red_qxl_init(QXLInstance *qxl);
> -
> -void red_qxl_set_mm_time(RedDispatcher *dispatcher, uint32_t);
> -void red_qxl_on_ic_change(RedDispatcher *dispatcher, SpiceImageCompression
> ic);
> -void red_qxl_on_sv_change(RedDispatcher *dispatcher, int sv);
> -void red_qxl_set_mouse_mode(RedDispatcher *dispatcher, uint32_t mode);
> -void red_qxl_attach_worker(RedDispatcher *dispatcher);
> -void red_qxl_set_compression_level(RedDispatcher *dispatcher, int level);
> -void red_qxl_stop(RedDispatcher *dispatcher);
> -void red_qxl_start(RedDispatcher *dispatcher);
> -uint32_t red_qxl_get_ram_size(RedDispatcher *dispatcher);
> -void red_qxl_async_complete(struct RedDispatcher *, AsyncCommand *);
> -struct Dispatcher *red_qxl_get_dispatcher(struct RedDispatcher *);
> -gboolean red_qxl_use_client_monitors_config(RedDispatcher *dispatcher);
> -gboolean red_qxl_client_monitors_config(RedDispatcher *dispatcher,
> VDAgentMonitorsConfig *monitors_config);
> -gboolean red_qxl_get_primary_active(RedDispatcher *dispatcher);
> -gboolean red_qxl_get_allow_client_mouse(RedDispatcher *dispatcher, gint
> *x_res, gint *y_res);
> -
> -typedef uint32_t RedWorkerMessage;
> -
> -/* Keep message order, only append new messages!
> - * Replay code store enum values into save files.
> - */
> -enum {
> -    RED_WORKER_MESSAGE_NOP,
> -
> -    RED_WORKER_MESSAGE_UPDATE,
> -    RED_WORKER_MESSAGE_WAKEUP,
> -    RED_WORKER_MESSAGE_OOM,
> -    RED_WORKER_MESSAGE_READY, /* unused */
> -
> -    RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> -    RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
> -    RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> -    RED_WORKER_MESSAGE_START,
> -    RED_WORKER_MESSAGE_STOP,
> -    RED_WORKER_MESSAGE_CURSOR_CONNECT,
> -    RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
> -    RED_WORKER_MESSAGE_CURSOR_MIGRATE,
> -    RED_WORKER_MESSAGE_SET_COMPRESSION,
> -    RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
> -    RED_WORKER_MESSAGE_SET_MOUSE_MODE,
> -    RED_WORKER_MESSAGE_ADD_MEMSLOT,
> -    RED_WORKER_MESSAGE_DEL_MEMSLOT,
> -    RED_WORKER_MESSAGE_RESET_MEMSLOTS,
> -    RED_WORKER_MESSAGE_DESTROY_SURFACES,
> -    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
> -    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
> -    RED_WORKER_MESSAGE_RESET_CURSOR,
> -    RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
> -    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
> -    RED_WORKER_MESSAGE_LOADVM_COMMANDS,
> -    /* async commands */
> -    RED_WORKER_MESSAGE_UPDATE_ASYNC,
> -    RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
> -    RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
> -    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
> -    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
> -    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
> -    /* suspend/windows resolution change command */
> -    RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
> -
> -    RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE, /* unused */
> -    RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE, /* unused */
> -
> -    RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC,
> -    RED_WORKER_MESSAGE_DRIVER_UNLOAD,
> -    RED_WORKER_MESSAGE_GL_SCANOUT,
> -    RED_WORKER_MESSAGE_GL_DRAW_ASYNC,
> -
> -    RED_WORKER_MESSAGE_COUNT // LAST
> -};
> -
> -typedef struct RedWorkerMessageDisplayConnect {
> -    RedClient * client;
> -    RedsStream * stream;
> -    uint32_t *common_caps; // red_worker should free
> -    uint32_t *caps;        // red_worker should free
> -    int migration;
> -    int num_common_caps;
> -    int num_caps;
> -} RedWorkerMessageDisplayConnect;
> -
> -typedef struct RedWorkerMessageDisplayDisconnect {
> -    RedChannelClient *rcc;
> -} RedWorkerMessageDisplayDisconnect;
> -
> -typedef struct RedWorkerMessageDisplayMigrate {
> -    RedChannelClient *rcc;
> -} RedWorkerMessageDisplayMigrate;
> -
> -typedef struct RedWorkerMessageCursorConnect {
> -    RedClient *client;
> -    RedsStream *stream;
> -    int migration;
> -    uint32_t *common_caps; // red_worker should free
> -    int num_common_caps;
> -    uint32_t *caps;        // red_worker should free
> -    int num_caps;
> -} RedWorkerMessageCursorConnect;
> -
> -typedef struct RedWorkerMessageCursorDisconnect {
> -    RedChannelClient *rcc;
> -} RedWorkerMessageCursorDisconnect;
> -
> -typedef struct RedWorkerMessageCursorMigrate {
> -    RedChannelClient *rcc;
> -} RedWorkerMessageCursorMigrate;
> -
> -typedef struct RedWorkerMessageUpdate {
> -    uint32_t surface_id;
> -    QXLRect * qxl_area;
> -    QXLRect * qxl_dirty_rects;
> -    uint32_t num_dirty_rects;
> -    uint32_t clear_dirty_region;
> -} RedWorkerMessageUpdate;
> -
> -typedef struct RedWorkerMessageAsync {
> -    AsyncCommand *cmd;
> -} RedWorkerMessageAsync;
> -
> -typedef struct RedWorkerMessageUpdateAsync {
> -    RedWorkerMessageAsync base;
> -    uint32_t surface_id;
> -    QXLRect qxl_area;
> -    uint32_t clear_dirty_region;
> -} RedWorkerMessageUpdateAsync;
> -
> -typedef struct RedWorkerMessageAddMemslot {
> -    QXLDevMemSlot mem_slot;
> -} RedWorkerMessageAddMemslot;
> -
> -typedef struct RedWorkerMessageAddMemslotAsync {
> -    RedWorkerMessageAsync base;
> -    QXLDevMemSlot mem_slot;
> -} RedWorkerMessageAddMemslotAsync;
> -
> -typedef struct RedWorkerMessageDelMemslot {
> -    uint32_t slot_group_id;
> -    uint32_t slot_id;
> -} RedWorkerMessageDelMemslot;
> -
> -typedef struct RedWorkerMessageDestroySurfaces {
> -} RedWorkerMessageDestroySurfaces;
> -
> -typedef struct RedWorkerMessageDestroySurfacesAsync {
> -    RedWorkerMessageAsync base;
> -} RedWorkerMessageDestroySurfacesAsync;
> -
> -
> -typedef struct RedWorkerMessageDestroyPrimarySurface {
> -    uint32_t surface_id;
> -} RedWorkerMessageDestroyPrimarySurface;
> -
> -typedef struct RedWorkerMessageDestroyPrimarySurfaceAsync {
> -    RedWorkerMessageAsync base;
> -    uint32_t surface_id;
> -} RedWorkerMessageDestroyPrimarySurfaceAsync;
> -
> -typedef struct RedWorkerMessageCreatePrimarySurfaceAsync {
> -    RedWorkerMessageAsync base;
> -    uint32_t surface_id;
> -    QXLDevSurfaceCreate surface;
> -} RedWorkerMessageCreatePrimarySurfaceAsync;
> -
> -typedef struct RedWorkerMessageCreatePrimarySurface {
> -    uint32_t surface_id;
> -    QXLDevSurfaceCreate surface;
> -} RedWorkerMessageCreatePrimarySurface;
> -
> -typedef struct RedWorkerMessageResetImageCache {
> -} RedWorkerMessageResetImageCache;
> -
> -typedef struct RedWorkerMessageResetCursor {
> -} RedWorkerMessageResetCursor;
> -
> -typedef struct RedWorkerMessageWakeup {
> -} RedWorkerMessageWakeup;
> -
> -typedef struct RedWorkerMessageOom {
> -} RedWorkerMessageOom;
> -
> -typedef struct RedWorkerMessageStart {
> -} RedWorkerMessageStart;
> -
> -typedef struct RedWorkerMessageFlushSurfacesAsync {
> -    RedWorkerMessageAsync base;
> -} RedWorkerMessageFlushSurfacesAsync;
> -
> -typedef struct RedWorkerMessageStop {
> -} RedWorkerMessageStop;
> -
> -/* this command is sync, so it's ok to pass a pointer */
> -typedef struct RedWorkerMessageLoadvmCommands {
> -    uint32_t count;
> -    QXLCommandExt *ext;
> -} RedWorkerMessageLoadvmCommands;
> -
> -typedef struct RedWorkerMessageSetCompression {
> -    SpiceImageCompression image_compression;
> -} RedWorkerMessageSetCompression;
> -
> -typedef struct RedWorkerMessageSetStreamingVideo {
> -    uint32_t streaming_video;
> -} RedWorkerMessageSetStreamingVideo;
> -
> -typedef struct RedWorkerMessageSetMouseMode {
> -    uint32_t mode;
> -} RedWorkerMessageSetMouseMode;
> -
> -typedef struct RedWorkerMessageDisplayChannelCreate {
> -} RedWorkerMessageDisplayChannelCreate;
> -
> -typedef struct RedWorkerMessageCursorChannelCreate {
> -} RedWorkerMessageCursorChannelCreate;
> -
> -typedef struct RedWorkerMessageDestroySurfaceWait {
> -    uint32_t surface_id;
> -} RedWorkerMessageDestroySurfaceWait;
> -
> -typedef struct RedWorkerMessageDestroySurfaceWaitAsync {
> -    RedWorkerMessageAsync base;
> -    uint32_t surface_id;
> -} RedWorkerMessageDestroySurfaceWaitAsync;
> -
> -typedef struct RedWorkerMessageResetMemslots {
> -} RedWorkerMessageResetMemslots;
> -
> -typedef struct RedWorkerMessageMonitorsConfigAsync {
> -    RedWorkerMessageAsync base;
> -    QXLPHYSICAL monitors_config;
> -    int group_id;
> -    unsigned int max_monitors;
> -} RedWorkerMessageMonitorsConfigAsync;
> -
> -typedef struct RedWorkerMessageDriverUnload {
> -} RedWorkerMessageDriverUnload;
> -
> -enum {
> -    RED_DISPATCHER_PENDING_WAKEUP,
> -    RED_DISPATCHER_PENDING_OOM,
> -};
> -
> -void red_qxl_clear_pending(RedDispatcher *red_dispatcher, int pending);
> -
> -#endif
> diff --git a/server/red-qxl.c b/server/red-qxl.c
> new file mode 100644
> index 0000000..3dfeae6
> --- /dev/null
> +++ b/server/red-qxl.c
> @@ -0,0 +1,1032 @@
> +/*
> +   Copyright (C) 2009 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/
> >.
> +*/
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <string.h>
> +#include <pthread.h>
> +#include <sys/socket.h>
> +#include <inttypes.h>
> +
> +#include <spice/qxl_dev.h>
> +#include "common/quic.h"
> +
> +#include "spice.h"
> +#include "red-worker.h"
> +#include "sw-canvas.h"
> +#include "reds.h"
> +#include "dispatcher.h"
> +#include "red-parse-qxl.h"
> +
> +#include "red-qxl.h"
> +
> +
> +struct AsyncCommand {
> +    RedWorkerMessage message;
> +    uint64_t cookie;
> +};
> +
> +struct RedDispatcher {
> +    QXLWorker base;
> +    QXLInstance *qxl;
> +    Dispatcher dispatcher;
> +    uint32_t pending;
> +    int primary_active;
> +    int x_res;
> +    int y_res;
> +    int use_hardware_cursor;
> +    QXLDevSurfaceCreate surface_create;
> +    unsigned int max_monitors;
> +};
> +
> +static int red_qxl_check_qxl_version(RedDispatcher *rd, int major, int minor)
> +{
> +    int qxl_major = rd->qxl->st->qif->base.major_version;
> +    int qxl_minor = rd->qxl->st->qif->base.minor_version;
> +
> +    return ((qxl_major > major) ||
> +            ((qxl_major == major) && (qxl_minor >= minor)));
> +}
> +
> +static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
> +                                     RedsStream *stream, int migration,
> +                                     int num_common_caps, uint32_t
> *common_caps, int num_caps,
> +                                     uint32_t *caps)
> +{
> +    RedWorkerMessageDisplayConnect payload = {0,};
> +    RedDispatcher *dispatcher;
> +
> +    spice_debug("%s", "");
> +    dispatcher = (RedDispatcher *)channel->data;
> +    payload.client = client;
> +    payload.stream = stream;
> +    payload.migration = migration;
> +    payload.num_common_caps = num_common_caps;
> +    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
> +    payload.num_caps = num_caps;
> +    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
> +
> +    memcpy(payload.common_caps, common_caps,
> sizeof(uint32_t)*num_common_caps);
> +    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> +                            &payload);
> +}
> +
> +static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
> +{
> +    RedWorkerMessageDisplayDisconnect payload;
> +    RedDispatcher *dispatcher;
> +
> +    if (!rcc->channel) {
> +        return;
> +    }
> +
> +    dispatcher = (RedDispatcher *)rcc->channel->data;
> +
> +    spice_printerr("");
> +    payload.rcc = rcc;
> +
> +    // TODO: we turned it to be sync, due to client_destroy . Should we
> support async? - for this we will need ref count
> +    // for channels
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
> +                            &payload);
> +}
> +
> +static void red_qxl_display_migrate(RedChannelClient *rcc)
> +{
> +    RedWorkerMessageDisplayMigrate payload;
> +    RedDispatcher *dispatcher;
> +    if (!rcc->channel) {
> +        return;
> +    }
> +    dispatcher = (RedDispatcher *)rcc->channel->data;
> +    spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel
> ->id);
> +    payload.rcc = rcc;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> +                            &payload);
> +}
> +
> +static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client,
> RedsStream *stream,
> +                                    int migration, int num_common_caps,
> +                                    uint32_t *common_caps, int num_caps,
> +                                    uint32_t *caps)
> +{
> +    RedWorkerMessageCursorConnect payload = {0,};
> +    RedDispatcher *dispatcher = (RedDispatcher *)channel->data;
> +    spice_printerr("");
> +    payload.client = client;
> +    payload.stream = stream;
> +    payload.migration = migration;
> +    payload.num_common_caps = num_common_caps;
> +    payload.common_caps = spice_malloc(sizeof(uint32_t)*num_common_caps);
> +    payload.num_caps = num_caps;
> +    payload.caps = spice_malloc(sizeof(uint32_t)*num_caps);
> +
> +    memcpy(payload.common_caps, common_caps,
> sizeof(uint32_t)*num_common_caps);
> +    memcpy(payload.caps, caps, sizeof(uint32_t)*num_caps);
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_CURSOR_CONNECT,
> +                            &payload);
> +}
> +
> +static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
> +{
> +    RedWorkerMessageCursorDisconnect payload;
> +    RedDispatcher *dispatcher;
> +
> +    if (!rcc->channel) {
> +        return;
> +    }
> +
> +    dispatcher = (RedDispatcher *)rcc->channel->data;
> +    spice_printerr("");
> +    payload.rcc = rcc;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
> +                            &payload);
> +}
> +
> +static void red_qxl_cursor_migrate(RedChannelClient *rcc)
> +{
> +    RedWorkerMessageCursorMigrate payload;
> +    RedDispatcher *dispatcher;
> +
> +    if (!rcc->channel) {
> +        return;
> +    }
> +    dispatcher = (RedDispatcher *)rcc->channel->data;
> +    spice_printerr("channel type %u id %u", rcc->channel->type, rcc->channel
> ->id);
> +    payload.rcc = rcc;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_CURSOR_MIGRATE,
> +                            &payload);
> +}
> +
> +static void red_qxl_update_area(RedDispatcher *dispatcher, uint32_t
> surface_id,
> +                                QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
> +                                uint32_t num_dirty_rects, uint32_t
> clear_dirty_region)
> +{
> +    RedWorkerMessageUpdate payload = {0,};
> +
> +    payload.surface_id = surface_id;
> +    payload.qxl_area = qxl_area;
> +    payload.qxl_dirty_rects = qxl_dirty_rects;
> +    payload.num_dirty_rects = num_dirty_rects;
> +    payload.clear_dirty_region = clear_dirty_region;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_UPDATE,
> +                            &payload);
> +}
> +
> +gboolean red_qxl_use_client_monitors_config(RedDispatcher *dispatcher)
> +{
> +    return (red_qxl_check_qxl_version(dispatcher, 3, 3) &&
> +        dispatcher->qxl->st->qif->client_monitors_config &&
> +        dispatcher->qxl->st->qif->client_monitors_config(dispatcher->qxl,
> NULL));
> +}
> +
> +gboolean red_qxl_client_monitors_config(RedDispatcher *dispatcher,
> +                                        VDAgentMonitorsConfig
> *monitors_config)
> +{
> +    return (dispatcher->qxl->st->qif->client_monitors_config &&
> +        dispatcher->qxl->st->qif->client_monitors_config(dispatcher->qxl,
> +                                                          monitors_config));
> +}
> +
> +static AsyncCommand *async_command_alloc(RedDispatcher *dispatcher,
> +                                         RedWorkerMessage message,
> +                                         uint64_t cookie)
> +{
> +    AsyncCommand *async_command = spice_new0(AsyncCommand, 1);
> +
> +    async_command->cookie = cookie;
> +    async_command->message = message;
> +
> +    spice_debug("%p", async_command);
> +    return async_command;
> +}
> +
> +static void red_qxl_update_area_async(RedDispatcher *dispatcher,
> +                                      uint32_t surface_id,
> +                                      QXLRect *qxl_area,
> +                                      uint32_t clear_dirty_region,
> +                                      uint64_t cookie)
> +{
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE_ASYNC;
> +    RedWorkerMessageUpdateAsync payload;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.surface_id = surface_id;
> +    payload.qxl_area = *qxl_area;
> +    payload.clear_dirty_region = clear_dirty_region;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            message,
> +                            &payload);
> +}
> +
> +static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t
> surface_id,
> +                                   QXLRect *qxl_area, QXLRect
> *qxl_dirty_rects,
> +                                   uint32_t num_dirty_rects, uint32_t
> clear_dirty_region)
> +{
> +    red_qxl_update_area((RedDispatcher*)qxl_worker, surface_id, qxl_area,
> +                        qxl_dirty_rects, num_dirty_rects,
> clear_dirty_region);
> +}
> +
> +static void red_qxl_add_memslot(RedDispatcher *dispatcher, QXLDevMemSlot
> *mem_slot)
> +{
> +    RedWorkerMessageAddMemslot payload;
> +
> +    payload.mem_slot = *mem_slot;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_ADD_MEMSLOT,
> +                            &payload);
> +}
> +
> +static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot
> *mem_slot)
> +{
> +    red_qxl_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
> +}
> +
> +static void red_qxl_add_memslot_async(RedDispatcher *dispatcher,
> QXLDevMemSlot *mem_slot, uint64_t cookie)
> +{
> +    RedWorkerMessageAddMemslotAsync payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.mem_slot = *mem_slot;
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void red_qxl_del_memslot(RedDispatcher *dispatcher, uint32_t
> slot_group_id, uint32_t slot_id)
> +{
> +    RedWorkerMessageDelMemslot payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
> +
> +    payload.slot_group_id = slot_group_id;
> +    payload.slot_id = slot_id;
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t
> slot_group_id, uint32_t slot_id)
> +{
> +    red_qxl_del_memslot((RedDispatcher*)qxl_worker, slot_group_id, slot_id);
> +}
> +
> +static void red_qxl_destroy_surfaces(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageDestroySurfaces payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DESTROY_SURFACES,
> +                            &payload);
> +}
> +
> +static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
> +{
> +    red_qxl_destroy_surfaces((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_destroy_surfaces_async(RedDispatcher *dispatcher,
> uint64_t cookie)
> +{
> +    RedWorkerMessageDestroySurfacesAsync payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void red_qxl_destroy_primary_surface_complete(RedDispatcher
> *dispatcher)
> +{
> +    dispatcher->x_res = 0;
> +    dispatcher->y_res = 0;
> +    dispatcher->use_hardware_cursor = FALSE;
> +    dispatcher->primary_active = FALSE;
> +
> +    reds_update_client_mouse_allowed(reds);
> +}
> +
> +static void
> +red_qxl_destroy_primary_surface_sync(RedDispatcher *dispatcher,
> +                                     uint32_t surface_id)
> +{
> +    RedWorkerMessageDestroyPrimarySurface payload;
> +    payload.surface_id = surface_id;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
> +                            &payload);
> +    red_qxl_destroy_primary_surface_complete(dispatcher);
> +}
> +
> +static void
> +red_qxl_destroy_primary_surface_async(RedDispatcher *dispatcher,
> +                                      uint32_t surface_id, uint64_t cookie)
> +{
> +    RedWorkerMessageDestroyPrimarySurfaceAsync payload;
> +    RedWorkerMessage message =
> RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.surface_id = surface_id;
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void
> +red_qxl_destroy_primary_surface(RedDispatcher *dispatcher,
> +                                uint32_t surface_id, int async, uint64_t
> cookie)
> +{
> +    if (async) {
> +        red_qxl_destroy_primary_surface_async(dispatcher, surface_id,
> cookie);
> +    } else {
> +        red_qxl_destroy_primary_surface_sync(dispatcher, surface_id);
> +    }
> +}
> +
> +static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker,
> uint32_t surface_id)
> +{
> +    red_qxl_destroy_primary_surface((RedDispatcher*)qxl_worker, surface_id,
> 0, 0);
> +}
> +
> +static void red_qxl_create_primary_surface_complete(RedDispatcher
> *dispatcher)
> +{
> +    QXLDevSurfaceCreate *surface = &dispatcher->surface_create;
> +
> +    dispatcher->x_res = surface->width;
> +    dispatcher->y_res = surface->height;
> +    dispatcher->use_hardware_cursor = surface->mouse_mode;
> +    dispatcher->primary_active = TRUE;
> +
> +    reds_update_client_mouse_allowed(reds);
> +    memset(&dispatcher->surface_create, 0, sizeof(QXLDevSurfaceCreate));
> +}
> +
> +static void
> +red_qxl_create_primary_surface_async(RedDispatcher *dispatcher, uint32_t
> surface_id,
> +                                     QXLDevSurfaceCreate *surface, uint64_t
> cookie)
> +{
> +    RedWorkerMessageCreatePrimarySurfaceAsync payload;
> +    RedWorkerMessage message =
> RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC;
> +
> +    dispatcher->surface_create = *surface;
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.surface_id = surface_id;
> +    payload.surface = *surface;
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void
> +red_qxl_create_primary_surface_sync(RedDispatcher *dispatcher, uint32_t
> surface_id,
> +                                    QXLDevSurfaceCreate *surface)
> +{
> +    RedWorkerMessageCreatePrimarySurface payload = {0,};
> +
> +    dispatcher->surface_create = *surface;
> +    payload.surface_id = surface_id;
> +    payload.surface = *surface;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
> +                            &payload);
> +    red_qxl_create_primary_surface_complete(dispatcher);
> +}
> +
> +static void
> +red_qxl_create_primary_surface(RedDispatcher *dispatcher, uint32_t
> surface_id,
> +                               QXLDevSurfaceCreate *surface, int async,
> uint64_t cookie)
> +{
> +    if (async) {
> +        red_qxl_create_primary_surface_async(dispatcher, surface_id, surface,
> cookie);
> +    } else {
> +        red_qxl_create_primary_surface_sync(dispatcher, surface_id, surface);
> +    }
> +}
> +
> +static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t
> surface_id,
> +                                      QXLDevSurfaceCreate *surface)
> +{
> +    red_qxl_create_primary_surface((RedDispatcher*)qxl_worker, surface_id,
> surface, 0, 0);
> +}
> +
> +static void red_qxl_reset_image_cache(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageResetImageCache payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
> +                            &payload);
> +}
> +
> +static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
> +{
> +    red_qxl_reset_image_cache((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_reset_cursor(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageResetCursor payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_RESET_CURSOR,
> +                            &payload);
> +}
> +
> +static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
> +{
> +    red_qxl_reset_cursor((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_destroy_surface_wait_sync(RedDispatcher *dispatcher,
> +                                              uint32_t surface_id)
> +{
> +    RedWorkerMessageDestroySurfaceWait payload;
> +
> +    payload.surface_id = surface_id;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
> +                            &payload);
> +}
> +
> +static void red_qxl_destroy_surface_wait_async(RedDispatcher *dispatcher,
> +                                               uint32_t surface_id,
> +                                               uint64_t cookie)
> +{
> +    RedWorkerMessageDestroySurfaceWaitAsync payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.surface_id = surface_id;
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void red_qxl_destroy_surface_wait(RedDispatcher *dispatcher,
> +                                         uint32_t surface_id,
> +                                         int async, uint64_t cookie)
> +{
> +    if (async) {
> +        red_qxl_destroy_surface_wait_async(dispatcher, surface_id, cookie);
> +    } else {
> +        red_qxl_destroy_surface_wait_sync(dispatcher, surface_id);
> +    }
> +}
> +
> +static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t
> surface_id)
> +{
> +    red_qxl_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id, 0,
> 0);
> +}
> +
> +static void red_qxl_reset_memslots(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageResetMemslots payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_RESET_MEMSLOTS,
> +                            &payload);
> +}
> +
> +static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
> +{
> +    red_qxl_reset_memslots((RedDispatcher*)qxl_worker);
> +}
> +
> +static bool red_qxl_set_pending(RedDispatcher *dispatcher, int pending)
> +{
> +    // this is not atomic but is not an issue
> +    if (test_bit(pending, dispatcher->pending)) {
> +        return TRUE;
> +    }
> +
> +    set_bit(pending, &dispatcher->pending);
> +    return FALSE;
> +}
> +
> +static void red_qxl_wakeup(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageWakeup payload;
> +
> +    if (red_qxl_set_pending(dispatcher, RED_DISPATCHER_PENDING_WAKEUP))
> +        return;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_WAKEUP,
> +                            &payload);
> +}
> +
> +static void qxl_worker_wakeup(QXLWorker *qxl_worker)
> +{
> +    red_qxl_wakeup((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_oom(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageOom payload;
> +
> +    if (red_qxl_set_pending(dispatcher, RED_DISPATCHER_PENDING_OOM))
> +        return;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_OOM,
> +                            &payload);
> +}
> +
> +static void qxl_worker_oom(QXLWorker *qxl_worker)
> +{
> +    red_qxl_oom((RedDispatcher*)qxl_worker);
> +}
> +
> +void red_qxl_start(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageStart payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_START,
> +                            &payload);
> +}
> +
> +static void qxl_worker_start(QXLWorker *qxl_worker)
> +{
> +    red_qxl_start((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t
> cookie)
> +{
> +    RedWorkerMessageFlushSurfacesAsync payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void red_qxl_monitors_config_async(RedDispatcher *dispatcher,
> +                                          QXLPHYSICAL monitors_config,
> +                                          int group_id,
> +                                          uint64_t cookie)
> +{
> +    RedWorkerMessageMonitorsConfigAsync payload;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC;
> +
> +    payload.base.cmd = async_command_alloc(dispatcher, message, cookie);
> +    payload.monitors_config = monitors_config;
> +    payload.group_id = group_id;
> +    payload.max_monitors = dispatcher->max_monitors;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &payload);
> +}
> +
> +static void red_qxl_driver_unload(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageDriverUnload payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_DRIVER_UNLOAD,
> +                            &payload);
> +}
> +
> +void red_qxl_stop(RedDispatcher *dispatcher)
> +{
> +    RedWorkerMessageStop payload;
> +
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_STOP,
> +                            &payload);
> +}
> +
> +static void qxl_worker_stop(QXLWorker *qxl_worker)
> +{
> +    red_qxl_stop((RedDispatcher*)qxl_worker);
> +}
> +
> +static void red_qxl_loadvm_commands(RedDispatcher *dispatcher,
> +                                    struct QXLCommandExt *ext,
> +                                    uint32_t count)
> +{
> +    RedWorkerMessageLoadvmCommands payload;
> +
> +    spice_printerr("");
> +    payload.count = count;
> +    payload.ext = ext;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_LOADVM_COMMANDS,
> +                            &payload);
> +}
> +
> +static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
> +                                       struct QXLCommandExt *ext,
> +                                       uint32_t count)
> +{
> +    red_qxl_loadvm_commands((RedDispatcher*)qxl_worker, ext, count);
> +}
> +
> +void red_qxl_set_mm_time(RedDispatcher *dispatcher, uint32_t mm_time)
> +{
> +    dispatcher->qxl->st->qif->set_mm_time(dispatcher->qxl, mm_time);
> +}
> +
> +void red_qxl_attach_worker(RedDispatcher *dispatcher)
> +{
> +    QXLInstance *qxl = dispatcher->qxl;
> +    qxl->st->qif->attache_worker(qxl, &dispatcher->base);
> +}
> +
> +void red_qxl_set_compression_level(RedDispatcher *dispatcher, int level)
> +{
> +    dispatcher->qxl->st->qif->set_compression_level(dispatcher->qxl, level);
> +}
> +
> +uint32_t red_qxl_get_ram_size(RedDispatcher *dispatcher)
> +{
> +    QXLDevInitInfo qxl_info;
> +    dispatcher->qxl->st->qif->get_init_info(dispatcher->qxl, &qxl_info);
> +    return qxl_info.qxl_ram_size;
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_wakeup(QXLInstance *instance)
> +{
> +    red_qxl_wakeup(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_oom(QXLInstance *instance)
> +{
> +    red_qxl_oom(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_start(QXLInstance *instance)
> +{
> +    red_qxl_start(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_stop(QXLInstance *instance)
> +{
> +    red_qxl_stop(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
> +                    struct QXLRect *area, struct QXLRect *dirty_rects,
> +                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
> +{
> +    red_qxl_update_area(instance->st->dispatcher, surface_id, area,
> dirty_rects,
> +                        num_dirty_rects, clear_dirty_region);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot)
> +{
> +    red_qxl_add_memslot(instance->st->dispatcher, slot);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id,
> uint32_t slot_id)
> +{
> +    red_qxl_del_memslot(instance->st->dispatcher, slot_group_id, slot_id);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_reset_memslots(QXLInstance *instance)
> +{
> +    red_qxl_reset_memslots(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_surfaces(QXLInstance *instance)
> +{
> +    red_qxl_destroy_surfaces(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t
> surface_id)
> +{
> +    red_qxl_destroy_primary_surface(instance->st->dispatcher, surface_id, 0,
> 0);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t
> surface_id,
> +                                QXLDevSurfaceCreate *surface)
> +{
> +    red_qxl_create_primary_surface(instance->st->dispatcher, surface_id,
> surface, 0, 0);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_reset_image_cache(QXLInstance *instance)
> +{
> +    red_qxl_reset_image_cache(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_reset_cursor(QXLInstance *instance)
> +{
> +    red_qxl_reset_cursor(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t
> surface_id)
> +{
> +    red_qxl_destroy_surface_wait(instance->st->dispatcher, surface_id, 0, 0);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt
> *ext, uint32_t count)
> +{
> +    red_qxl_loadvm_commands(instance->st->dispatcher, ext, count);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id,
> QXLRect *qxl_area,
> +                                 uint32_t clear_dirty_region, uint64_t
> cookie)
> +{
> +    red_qxl_update_area_async(instance->st->dispatcher, surface_id, qxl_area,
> +                                     clear_dirty_region, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot,
> uint64_t cookie)
> +{
> +    red_qxl_add_memslot_async(instance->st->dispatcher, slot, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie)
> +{
> +    red_qxl_destroy_surfaces_async(instance->st->dispatcher, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t
> surface_id, uint64_t cookie)
> +{
> +    red_qxl_destroy_primary_surface(instance->st->dispatcher, surface_id, 1,
> cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t
> surface_id,
> +                                QXLDevSurfaceCreate *surface, uint64_t
> cookie)
> +{
> +    red_qxl_create_primary_surface(instance->st->dispatcher, surface_id,
> surface, 1, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t
> surface_id, uint64_t cookie)
> +{
> +    red_qxl_destroy_surface_wait(instance->st->dispatcher, surface_id, 1,
> cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
> +{
> +    red_qxl_flush_surfaces_async(instance->st->dispatcher, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_monitors_config_async(QXLInstance *instance, QXLPHYSICAL
> monitors_config,
> +                                     int group_id, uint64_t cookie)
> +{
> +    red_qxl_monitors_config_async(instance->st->dispatcher, monitors_config,
> group_id, cookie);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_set_max_monitors(QXLInstance *instance, unsigned int
> max_monitors)
> +{
> +    instance->st->dispatcher->max_monitors = MAX(1u, max_monitors);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_driver_unload(QXLInstance *instance)
> +{
> +    red_qxl_driver_unload(instance->st->dispatcher);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_gl_scanout(QXLInstance *qxl,
> +                          int fd,
> +                          uint32_t width, uint32_t height,
> +                          uint32_t stride, uint32_t format,
> +                          int y_0_top)
> +{
> +    spice_return_if_fail(qxl != NULL);
> +    spice_return_if_fail(qxl->st->gl_draw_async == NULL);
> +
> +    pthread_mutex_lock(&qxl->st->scanout_mutex);
> +
> +    if (qxl->st->scanout.drm_dma_buf_fd != -1) {
> +        close(qxl->st->scanout.drm_dma_buf_fd);
> +    }
> +
> +    qxl->st->scanout = (SpiceMsgDisplayGlScanoutUnix) {
> +        .flags = y_0_top ? SPICE_GL_SCANOUT_FLAGS_Y0TOP : 0,
> +        .drm_dma_buf_fd = fd,
> +        .width = width,
> +        .height = height,
> +        .stride = stride,
> +        .drm_fourcc_format = format
> +    };
> +
> +    pthread_mutex_unlock(&qxl->st->scanout_mutex);
> +
> +    /* FIXME: find a way to coallesce all pending SCANOUTs */
> +    dispatcher_send_message(&qxl->st->dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_GL_SCANOUT, NULL);
> +}
> +
> +SPICE_GNUC_VISIBLE
> +void spice_qxl_gl_draw_async(QXLInstance *qxl,
> +                             uint32_t x, uint32_t y,
> +                             uint32_t w, uint32_t h,
> +                             uint64_t cookie)
> +{
> +    RedDispatcher *dispatcher;
> +    RedWorkerMessage message = RED_WORKER_MESSAGE_GL_DRAW_ASYNC;
> +    SpiceMsgDisplayGlDraw draw = {
> +        .x = x,
> +        .y = y,
> +        .w = w,
> +        .h = h
> +    };
> +
> +    spice_return_if_fail(qxl != NULL);
> +    spice_return_if_fail(qxl->st->scanout.drm_dma_buf_fd != -1);
> +    spice_return_if_fail(qxl->st->gl_draw_async == NULL);
> +
> +    dispatcher = qxl->st->dispatcher;
> +    qxl->st->gl_draw_async = async_command_alloc(dispatcher, message,
> cookie);
> +    dispatcher_send_message(&dispatcher->dispatcher, message, &draw);
> +}
> +
> +void red_qxl_async_complete(struct RedDispatcher *dispatcher,
> +                            AsyncCommand *async_command)
> +{
> +    spice_debug("%p: cookie %" PRId64, async_command, async_command->cookie);
> +    switch (async_command->message) {
> +    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
> +    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
> +    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
> +    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
> +    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
> +    case RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC:
> +    case RED_WORKER_MESSAGE_GL_DRAW_ASYNC:
> +        break;
> +    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
> +        red_qxl_create_primary_surface_complete(dispatcher);
> +        break;
> +    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
> +        red_qxl_destroy_primary_surface_complete(dispatcher);
> +        break;
> +    default:
> +        spice_warning("unexpected message %d", async_command->message);
> +    }
> +    dispatcher->qxl->st->qif->async_complete(dispatcher->qxl,
> +                                             async_command->cookie);
> +    free(async_command);
> +}
> +
> +void red_qxl_init(QXLInstance *qxl)
> +{
> +    RedDispatcher *red_dispatcher;
> +    RedChannel *channel;
> +    ClientCbs client_cbs = { NULL, };
> +
> +    spice_return_if_fail(qxl != NULL);
> +    spice_return_if_fail(qxl->st->dispatcher == NULL);
> +
> +    static gsize initialized = FALSE;
> +    if (g_once_init_enter(&initialized)) {
> +        quic_init();
> +        sw_canvas_init();
> +        g_once_init_leave(&initialized, TRUE);
> +    }
> +
> +    red_dispatcher = spice_new0(RedDispatcher, 1);
> +    red_dispatcher->qxl = qxl;
> +    dispatcher_init(&red_dispatcher->dispatcher, RED_WORKER_MESSAGE_COUNT,
> NULL);
> +    red_dispatcher->base.major_version = SPICE_INTERFACE_QXL_MAJOR;
> +    red_dispatcher->base.minor_version = SPICE_INTERFACE_QXL_MINOR;
> +    red_dispatcher->base.wakeup = qxl_worker_wakeup;
> +    red_dispatcher->base.oom = qxl_worker_oom;
> +    red_dispatcher->base.start = qxl_worker_start;
> +    red_dispatcher->base.stop = qxl_worker_stop;
> +    red_dispatcher->base.update_area = qxl_worker_update_area;
> +    red_dispatcher->base.add_memslot = qxl_worker_add_memslot;
> +    red_dispatcher->base.del_memslot = qxl_worker_del_memslot;
> +    red_dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
> +    red_dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
> +    red_dispatcher->base.create_primary_surface =
> qxl_worker_create_primary_surface;
> +    red_dispatcher->base.destroy_primary_surface =
> qxl_worker_destroy_primary_surface;
> +
> +    red_dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
> +    red_dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
> +    red_dispatcher->base.destroy_surface_wait =
> qxl_worker_destroy_surface_wait;
> +    red_dispatcher->base.loadvm_commands = qxl_worker_loadvm_commands;
> +
> +    red_dispatcher->max_monitors = UINT_MAX;
> +
> +    // TODO: reference and free
> +    RedWorker *worker = red_worker_new(qxl, red_dispatcher);
> +
> +    // TODO: move to their respective channel files
> +    channel = red_worker_get_cursor_channel(worker);
> +    client_cbs.connect = red_qxl_set_cursor_peer;
> +    client_cbs.disconnect = red_qxl_disconnect_cursor_peer;
> +    client_cbs.migrate = red_qxl_cursor_migrate;
> +    red_channel_register_client_cbs(channel, &client_cbs);
> +    red_channel_set_data(channel, red_dispatcher);
> +    reds_register_channel(reds, channel);
> +
> +    channel = red_worker_get_display_channel(worker);
> +    client_cbs.connect = red_qxl_set_display_peer;
> +    client_cbs.disconnect = red_qxl_disconnect_display_peer;
> +    client_cbs.migrate = red_qxl_display_migrate;
> +    red_channel_register_client_cbs(channel, &client_cbs);
> +    red_channel_set_data(channel, red_dispatcher);
> +    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
> +    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
> +    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
> +    reds_register_channel(reds, channel);
> +
> +    red_worker_run(worker);
> +
> +    qxl->st->dispatcher = red_dispatcher;
> +}
> +
> +struct Dispatcher *red_qxl_get_dispatcher(RedDispatcher *red_dispatcher)
> +{
> +    return &red_dispatcher->dispatcher;
> +}
> +
> +void red_qxl_set_dispatcher_opaque(RedDispatcher *red_dispatcher,
> +                                          void *opaque)
> +{
> +    dispatcher_set_opaque(&red_dispatcher->dispatcher, opaque);
> +}
> +
> +void red_qxl_clear_pending(RedDispatcher *red_dispatcher, int pending)
> +{
> +    spice_return_if_fail(red_dispatcher != NULL);
> +
> +    clear_bit(pending, &red_dispatcher->pending);
> +}
> +
> +gboolean red_qxl_get_primary_active(RedDispatcher *dispatcher)
> +{
> +    return dispatcher->primary_active;
> +}
> +
> +gboolean red_qxl_get_allow_client_mouse(RedDispatcher *dispatcher, gint
> *x_res, gint *y_res)
> +{
> +    if (dispatcher->use_hardware_cursor) {
> +        if (x_res)
> +            *x_res = dispatcher->x_res;
> +        if (y_res)
> +            *y_res = dispatcher->y_res;
> +    }
> +    return dispatcher->use_hardware_cursor;
> +}
> +
> +void red_qxl_on_ic_change(RedDispatcher *dispatcher, SpiceImageCompression
> ic)
> +{
> +    RedWorkerMessageSetCompression payload;
> +    payload.image_compression = ic;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_SET_COMPRESSION,
> +                            &payload);
> +}
> +
> +void red_qxl_on_sv_change(RedDispatcher *dispatcher, int sv)
> +{
> +    RedWorkerMessageSetStreamingVideo payload;
> +    payload.streaming_video = sv;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
> +                            &payload);
> +}
> +
> +void red_qxl_set_mouse_mode(RedDispatcher *dispatcher, uint32_t mode)
> +{
> +    RedWorkerMessageSetMouseMode payload;
> +    payload.mode = mode;
> +    dispatcher_send_message(&dispatcher->dispatcher,
> +                            RED_WORKER_MESSAGE_SET_MOUSE_MODE,
> +                            &payload);
> +}
> diff --git a/server/red-qxl.h b/server/red-qxl.h
> new file mode 100644
> index 0000000..1348e6c
> --- /dev/null
> +++ b/server/red-qxl.h
> @@ -0,0 +1,272 @@
> +/*
> +   Copyright (C) 2009 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see <http://www.gnu.org/licenses/
> >.
> +*/
> +
> +#ifndef _H_RED_DISPATCHER
> +#define _H_RED_DISPATCHER
> +
> +#include "red-channel.h"
> +
> +typedef struct RedDispatcher RedDispatcher;
> +
> +typedef struct AsyncCommand AsyncCommand;
> +
> +void red_qxl_init(QXLInstance *qxl);
> +
> +void red_qxl_set_mm_time(RedDispatcher *dispatcher, uint32_t);
> +void red_qxl_on_ic_change(RedDispatcher *dispatcher, SpiceImageCompression
> ic);
> +void red_qxl_on_sv_change(RedDispatcher *dispatcher, int sv);
> +void red_qxl_set_mouse_mode(RedDispatcher *dispatcher, uint32_t mode);
> +void red_qxl_attach_worker(RedDispatcher *dispatcher);
> +void red_qxl_set_compression_level(RedDispatcher *dispatcher, int level);
> +void red_qxl_stop(RedDispatcher *dispatcher);
> +void red_qxl_start(RedDispatcher *dispatcher);
> +uint32_t red_qxl_get_ram_size(RedDispatcher *dispatcher);
> +void red_qxl_async_complete(struct RedDispatcher *, AsyncCommand *);
> +struct Dispatcher *red_qxl_get_dispatcher(struct RedDispatcher *);
> +gboolean red_qxl_use_client_monitors_config(RedDispatcher *dispatcher);
> +gboolean red_qxl_client_monitors_config(RedDispatcher *dispatcher,
> VDAgentMonitorsConfig *monitors_config);
> +gboolean red_qxl_get_primary_active(RedDispatcher *dispatcher);
> +gboolean red_qxl_get_allow_client_mouse(RedDispatcher *dispatcher, gint
> *x_res, gint *y_res);
> +
> +typedef uint32_t RedWorkerMessage;
> +
> +/* Keep message order, only append new messages!
> + * Replay code store enum values into save files.
> + */
> +enum {
> +    RED_WORKER_MESSAGE_NOP,
> +
> +    RED_WORKER_MESSAGE_UPDATE,
> +    RED_WORKER_MESSAGE_WAKEUP,
> +    RED_WORKER_MESSAGE_OOM,
> +    RED_WORKER_MESSAGE_READY, /* unused */
> +
> +    RED_WORKER_MESSAGE_DISPLAY_CONNECT,
> +    RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
> +    RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
> +    RED_WORKER_MESSAGE_START,
> +    RED_WORKER_MESSAGE_STOP,
> +    RED_WORKER_MESSAGE_CURSOR_CONNECT,
> +    RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
> +    RED_WORKER_MESSAGE_CURSOR_MIGRATE,
> +    RED_WORKER_MESSAGE_SET_COMPRESSION,
> +    RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
> +    RED_WORKER_MESSAGE_SET_MOUSE_MODE,
> +    RED_WORKER_MESSAGE_ADD_MEMSLOT,
> +    RED_WORKER_MESSAGE_DEL_MEMSLOT,
> +    RED_WORKER_MESSAGE_RESET_MEMSLOTS,
> +    RED_WORKER_MESSAGE_DESTROY_SURFACES,
> +    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE,
> +    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE,
> +    RED_WORKER_MESSAGE_RESET_CURSOR,
> +    RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
> +    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
> +    RED_WORKER_MESSAGE_LOADVM_COMMANDS,
> +    /* async commands */
> +    RED_WORKER_MESSAGE_UPDATE_ASYNC,
> +    RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
> +    RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
> +    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
> +    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
> +    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
> +    /* suspend/windows resolution change command */
> +    RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
> +
> +    RED_WORKER_MESSAGE_DISPLAY_CHANNEL_CREATE, /* unused */
> +    RED_WORKER_MESSAGE_CURSOR_CHANNEL_CREATE, /* unused */
> +
> +    RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC,
> +    RED_WORKER_MESSAGE_DRIVER_UNLOAD,
> +    RED_WORKER_MESSAGE_GL_SCANOUT,
> +    RED_WORKER_MESSAGE_GL_DRAW_ASYNC,
> +
> +    RED_WORKER_MESSAGE_COUNT // LAST
> +};
> +
> +typedef struct RedWorkerMessageDisplayConnect {
> +    RedClient * client;
> +    RedsStream * stream;
> +    uint32_t *common_caps; // red_worker should free
> +    uint32_t *caps;        // red_worker should free
> +    int migration;
> +    int num_common_caps;
> +    int num_caps;
> +} RedWorkerMessageDisplayConnect;
> +
> +typedef struct RedWorkerMessageDisplayDisconnect {
> +    RedChannelClient *rcc;
> +} RedWorkerMessageDisplayDisconnect;
> +
> +typedef struct RedWorkerMessageDisplayMigrate {
> +    RedChannelClient *rcc;
> +} RedWorkerMessageDisplayMigrate;
> +
> +typedef struct RedWorkerMessageCursorConnect {
> +    RedClient *client;
> +    RedsStream *stream;
> +    int migration;
> +    uint32_t *common_caps; // red_worker should free
> +    int num_common_caps;
> +    uint32_t *caps;        // red_worker should free
> +    int num_caps;
> +} RedWorkerMessageCursorConnect;
> +
> +typedef struct RedWorkerMessageCursorDisconnect {
> +    RedChannelClient *rcc;
> +} RedWorkerMessageCursorDisconnect;
> +
> +typedef struct RedWorkerMessageCursorMigrate {
> +    RedChannelClient *rcc;
> +} RedWorkerMessageCursorMigrate;
> +
> +typedef struct RedWorkerMessageUpdate {
> +    uint32_t surface_id;
> +    QXLRect * qxl_area;
> +    QXLRect * qxl_dirty_rects;
> +    uint32_t num_dirty_rects;
> +    uint32_t clear_dirty_region;
> +} RedWorkerMessageUpdate;
> +
> +typedef struct RedWorkerMessageAsync {
> +    AsyncCommand *cmd;
> +} RedWorkerMessageAsync;
> +
> +typedef struct RedWorkerMessageUpdateAsync {
> +    RedWorkerMessageAsync base;
> +    uint32_t surface_id;
> +    QXLRect qxl_area;
> +    uint32_t clear_dirty_region;
> +} RedWorkerMessageUpdateAsync;
> +
> +typedef struct RedWorkerMessageAddMemslot {
> +    QXLDevMemSlot mem_slot;
> +} RedWorkerMessageAddMemslot;
> +
> +typedef struct RedWorkerMessageAddMemslotAsync {
> +    RedWorkerMessageAsync base;
> +    QXLDevMemSlot mem_slot;
> +} RedWorkerMessageAddMemslotAsync;
> +
> +typedef struct RedWorkerMessageDelMemslot {
> +    uint32_t slot_group_id;
> +    uint32_t slot_id;
> +} RedWorkerMessageDelMemslot;
> +
> +typedef struct RedWorkerMessageDestroySurfaces {
> +} RedWorkerMessageDestroySurfaces;
> +
> +typedef struct RedWorkerMessageDestroySurfacesAsync {
> +    RedWorkerMessageAsync base;
> +} RedWorkerMessageDestroySurfacesAsync;
> +
> +
> +typedef struct RedWorkerMessageDestroyPrimarySurface {
> +    uint32_t surface_id;
> +} RedWorkerMessageDestroyPrimarySurface;
> +
> +typedef struct RedWorkerMessageDestroyPrimarySurfaceAsync {
> +    RedWorkerMessageAsync base;
> +    uint32_t surface_id;
> +} RedWorkerMessageDestroyPrimarySurfaceAsync;
> +
> +typedef struct RedWorkerMessageCreatePrimarySurfaceAsync {
> +    RedWorkerMessageAsync base;
> +    uint32_t surface_id;
> +    QXLDevSurfaceCreate surface;
> +} RedWorkerMessageCreatePrimarySurfaceAsync;
> +
> +typedef struct RedWorkerMessageCreatePrimarySurface {
> +    uint32_t surface_id;
> +    QXLDevSurfaceCreate surface;
> +} RedWorkerMessageCreatePrimarySurface;
> +
> +typedef struct RedWorkerMessageResetImageCache {
> +} RedWorkerMessageResetImageCache;
> +
> +typedef struct RedWorkerMessageResetCursor {
> +} RedWorkerMessageResetCursor;
> +
> +typedef struct RedWorkerMessageWakeup {
> +} RedWorkerMessageWakeup;
> +
> +typedef struct RedWorkerMessageOom {
> +} RedWorkerMessageOom;
> +
> +typedef struct RedWorkerMessageStart {
> +} RedWorkerMessageStart;
> +
> +typedef struct RedWorkerMessageFlushSurfacesAsync {
> +    RedWorkerMessageAsync base;
> +} RedWorkerMessageFlushSurfacesAsync;
> +
> +typedef struct RedWorkerMessageStop {
> +} RedWorkerMessageStop;
> +
> +/* this command is sync, so it's ok to pass a pointer */
> +typedef struct RedWorkerMessageLoadvmCommands {
> +    uint32_t count;
> +    QXLCommandExt *ext;
> +} RedWorkerMessageLoadvmCommands;
> +
> +typedef struct RedWorkerMessageSetCompression {
> +    SpiceImageCompression image_compression;
> +} RedWorkerMessageSetCompression;
> +
> +typedef struct RedWorkerMessageSetStreamingVideo {
> +    uint32_t streaming_video;
> +} RedWorkerMessageSetStreamingVideo;
> +
> +typedef struct RedWorkerMessageSetMouseMode {
> +    uint32_t mode;
> +} RedWorkerMessageSetMouseMode;
> +
> +typedef struct RedWorkerMessageDisplayChannelCreate {
> +} RedWorkerMessageDisplayChannelCreate;
> +
> +typedef struct RedWorkerMessageCursorChannelCreate {
> +} RedWorkerMessageCursorChannelCreate;
> +
> +typedef struct RedWorkerMessageDestroySurfaceWait {
> +    uint32_t surface_id;
> +} RedWorkerMessageDestroySurfaceWait;
> +
> +typedef struct RedWorkerMessageDestroySurfaceWaitAsync {
> +    RedWorkerMessageAsync base;
> +    uint32_t surface_id;
> +} RedWorkerMessageDestroySurfaceWaitAsync;
> +
> +typedef struct RedWorkerMessageResetMemslots {
> +} RedWorkerMessageResetMemslots;
> +
> +typedef struct RedWorkerMessageMonitorsConfigAsync {
> +    RedWorkerMessageAsync base;
> +    QXLPHYSICAL monitors_config;
> +    int group_id;
> +    unsigned int max_monitors;
> +} RedWorkerMessageMonitorsConfigAsync;
> +
> +typedef struct RedWorkerMessageDriverUnload {
> +} RedWorkerMessageDriverUnload;
> +
> +enum {
> +    RED_DISPATCHER_PENDING_WAKEUP,
> +    RED_DISPATCHER_PENDING_OOM,
> +};
> +
> +void red_qxl_clear_pending(RedDispatcher *red_dispatcher, int pending);
> +
> +#endif
> diff --git a/server/red-worker.h b/server/red-worker.h
> index b22d41d..e51e261 100644
> --- a/server/red-worker.h
> +++ b/server/red-worker.h
> @@ -19,7 +19,7 @@
>  #define _H_REDWORKER
>  
>  #include "red-common.h"
> -#include "red-dispatcher.h"
> +#include "red-qxl.h"
>  #include "red-parse-qxl.h"
>  
>  typedef struct RedWorker RedWorker;
> diff --git a/server/reds.c b/server/reds.c
> index decf846..8ab4bbd 100644
> --- a/server/reds.c
> +++ b/server/reds.c
> @@ -57,7 +57,7 @@
>  #include "agent-msg-filter.h"
>  #include "inputs-channel.h"
>  #include "main-channel.h"
> -#include "red-dispatcher.h"
> +#include "red-qxl.h"
>  #include "main-dispatcher.h"
>  #include "sound.h"
>  #include "stat.h"
> diff --git a/server/sound.c b/server/sound.c
> index 54891c5..227c6f1 100644
> --- a/server/sound.c
> +++ b/server/sound.c
> @@ -33,7 +33,7 @@
>  #include "red-common.h"
>  #include "main-channel.h"
>  #include "reds.h"
> -#include "red-dispatcher.h"
> +#include "red-qxl.h"
>  #include "sound.h"
>  #include "common/snd_codec.h"
>  #include "demarshallers.h"


More information about the Spice-devel mailing list