worker: move some cursor code to cursor-channel.c

Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
Marc-André Lureau 2015-10-27 16:04:05 +00:00 committed by Frediano Ziglio
parent 266d344b7f
commit 070e0fcd63
5 changed files with 625 additions and 549 deletions

View File

@ -108,6 +108,7 @@ libspice_server_la_SOURCES = \
red_worker.c \
red_worker.h \
display-channel.h \
cursor-channel.c \
cursor-channel.h \
reds.c \
reds.h \

464
server/cursor-channel.c Normal file
View File

@ -0,0 +1,464 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
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/>.
*/
#include <glib.h>
#include "common/generated_server_marshallers.h"
#include "cursor-channel.h"
#define RCC_TO_CCC(rcc) SPICE_CONTAINEROF((rcc), CursorChannelClient, common.base)
#define CLIENT_CURSOR_CACHE
#include "cache_item.tmpl.c"
#undef CLIENT_CURSOR_CACHE
static inline CursorItem *alloc_cursor_item(void)
{
CursorItem *cursor_item;
cursor_item = g_slice_new0(CursorItem);
cursor_item->refs = 1;
return cursor_item;
}
CursorItem *cursor_item_new(RedCursorCmd *cmd, uint32_t group_id)
{
CursorItem *cursor_item;
spice_return_val_if_fail(cmd != NULL, NULL);
cursor_item = alloc_cursor_item();
cursor_item->group_id = group_id;
cursor_item->red_cursor = cmd;
return cursor_item;
}
void cursor_item_unref(QXLInstance *qxl, CursorItem *cursor)
{
if (!--cursor->refs) {
QXLReleaseInfoExt release_info_ext;
RedCursorCmd *cursor_cmd;
cursor_cmd = cursor->red_cursor;
release_info_ext.group_id = cursor->group_id;
release_info_ext.info = cursor_cmd->release_info;
qxl->st->qif->release_resource(qxl, release_info_ext);
red_put_cursor_cmd(cursor_cmd);
free(cursor_cmd);
g_slice_free(CursorItem, cursor);
}
}
static void cursor_set_item(CursorChannel *cursor, CursorItem *item)
{
if (cursor->item)
cursor_item_unref(red_worker_get_qxl(cursor->common.worker), cursor->item);
if (item)
item->refs++;
cursor->item = item;
}
static PipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, int num)
{
CursorPipeItem *item = spice_malloc0(sizeof(CursorPipeItem));
red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_CURSOR);
item->refs = 1;
item->cursor_item = data;
item->cursor_item->refs++;
return &item->base;
}
typedef struct {
void *data;
uint32_t size;
} AddBufInfo;
static void add_buf_from_info(SpiceMarshaller *m, AddBufInfo *info)
{
if (info->data) {
spice_marshaller_add_ref(m, info->data, info->size);
}
}
static void cursor_fill(CursorChannelClient *ccc, SpiceCursor *red_cursor,
CursorItem *cursor, AddBufInfo *addbuf)
{
RedCursorCmd *cursor_cmd;
addbuf->data = NULL;
if (!cursor) {
red_cursor->flags = SPICE_CURSOR_FLAGS_NONE;
return;
}
cursor_cmd = cursor->red_cursor;
*red_cursor = cursor_cmd->u.set.shape;
if (red_cursor->header.unique) {
if (red_cursor_cache_find(ccc, red_cursor->header.unique)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
return;
}
if (red_cursor_cache_add(ccc, red_cursor->header.unique, 1)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
}
}
if (red_cursor->data_size) {
addbuf->data = red_cursor->data;
addbuf->size = red_cursor->data_size;
}
}
static void red_reset_cursor_cache(RedChannelClient *rcc)
{
red_cursor_cache_reset(RCC_TO_CCC(rcc), CLIENT_CURSOR_CACHE_SIZE);
}
void cursor_channel_disconnect(RedChannel *channel)
{
if (!channel || !red_channel_is_connected(channel)) {
return;
}
red_channel_apply_clients(channel, red_reset_cursor_cache);
red_channel_disconnect(channel);
}
static void put_cursor_pipe_item(CursorChannelClient *ccc, CursorPipeItem *pipe_item)
{
spice_assert(pipe_item);
if (--pipe_item->refs) {
return;
}
spice_assert(!pipe_item_is_linked(&pipe_item->base));
cursor_item_unref(red_worker_get_qxl(ccc->common.worker), pipe_item->cursor_item);
free(pipe_item);
}
static void cursor_channel_client_on_disconnect(RedChannelClient *rcc)
{
if (!rcc) {
return;
}
red_reset_cursor_cache(rcc);
}
// TODO: share code between before/after_push since most of the items need the same
// release
static void cursor_channel_client_release_item_before_push(CursorChannelClient *ccc,
PipeItem *item)
{
switch (item->type) {
case PIPE_ITEM_TYPE_CURSOR: {
CursorPipeItem *cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
put_cursor_pipe_item(ccc, cursor_pipe_item);
break;
}
case PIPE_ITEM_TYPE_INVAL_ONE:
case PIPE_ITEM_TYPE_VERB:
case PIPE_ITEM_TYPE_CURSOR_INIT:
case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
free(item);
break;
default:
spice_error("invalid pipe item type");
}
}
static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
PipeItem *item)
{
switch (item->type) {
case PIPE_ITEM_TYPE_CURSOR: {
CursorPipeItem *cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
put_cursor_pipe_item(ccc, cursor_pipe_item);
break;
}
default:
spice_critical("invalid item type");
}
}
static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller,
PipeItem *pipe_item)
{
CursorChannel *cursor_channel;
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
SpiceMsgCursorInit msg;
AddBufInfo info;
spice_assert(rcc);
cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL);
msg.visible = cursor_channel->cursor_visible;
msg.position = cursor_channel->cursor_position;
msg.trail_length = cursor_channel->cursor_trail_length;
msg.trail_frequency = cursor_channel->cursor_trail_frequency;
cursor_fill(ccc, &msg.cursor, cursor_channel->item, &info);
spice_marshall_msg_cursor_init(base_marshaller, &msg);
add_buf_from_info(base_marshaller, &info);
}
static void cursor_marshall(RedChannelClient *rcc,
SpiceMarshaller *m, CursorPipeItem *cursor_pipe_item)
{
CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
CursorItem *cursor = cursor_pipe_item->cursor_item;
PipeItem *pipe_item = &cursor_pipe_item->base;
RedCursorCmd *cmd;
spice_assert(cursor_channel);
cmd = cursor->red_cursor;
switch (cmd->type) {
case QXL_CURSOR_MOVE:
{
SpiceMsgCursorMove cursor_move;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_MOVE, pipe_item);
cursor_move.position = cmd->u.position;
spice_marshall_msg_cursor_move(m, &cursor_move);
break;
}
case QXL_CURSOR_SET:
{
SpiceMsgCursorSet cursor_set;
AddBufInfo info;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item);
cursor_set.position = cmd->u.set.position;
cursor_set.visible = cursor_channel->cursor_visible;
cursor_fill(ccc, &cursor_set.cursor, cursor, &info);
spice_marshall_msg_cursor_set(m, &cursor_set);
add_buf_from_info(m, &info);
break;
}
case QXL_CURSOR_HIDE:
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_HIDE, pipe_item);
break;
case QXL_CURSOR_TRAIL:
{
SpiceMsgCursorTrail cursor_trail;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_TRAIL, pipe_item);
cursor_trail.length = cmd->u.trail.length;
cursor_trail.frequency = cmd->u.trail.frequency;
spice_marshall_msg_cursor_trail(m, &cursor_trail);
}
break;
default:
spice_error("bad cursor command %d", cmd->type);
}
}
static inline void red_marshall_inval(RedChannelClient *rcc,
SpiceMarshaller *base_marshaller, CacheItem *cach_item)
{
SpiceMsgDisplayInvalOne inval_one;
red_channel_client_init_send_data(rcc, cach_item->inval_type, NULL);
inval_one.id = *(uint64_t *)&cach_item->id;
spice_marshall_msg_cursor_inval_one(base_marshaller, &inval_one);
}
static void red_cursor_marshall_inval(RedChannelClient *rcc,
SpiceMarshaller *m, CacheItem *cach_item)
{
spice_assert(rcc);
red_marshall_inval(rcc, m, cach_item);
}
static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
{
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
switch (pipe_item->type) {
case PIPE_ITEM_TYPE_CURSOR:
cursor_marshall(rcc, m, SPICE_CONTAINEROF(pipe_item, CursorPipeItem, base));
break;
case PIPE_ITEM_TYPE_INVAL_ONE:
red_cursor_marshall_inval(rcc, m, (CacheItem *)pipe_item);
break;
case PIPE_ITEM_TYPE_VERB:
red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
break;
case PIPE_ITEM_TYPE_CURSOR_INIT:
red_reset_cursor_cache(rcc);
red_marshall_cursor_init(rcc, m, pipe_item);
break;
case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
red_reset_cursor_cache(rcc);
red_marshall_verb(rcc, SPICE_MSG_CURSOR_INVAL_ALL);
break;
default:
spice_error("invalid pipe item type");
}
cursor_channel_client_release_item_before_push(ccc, pipe_item);
red_channel_client_begin_send_message(rcc);
}
static CursorPipeItem *cursor_pipe_item_ref(CursorPipeItem *item)
{
spice_assert(item);
item->refs++;
return item;
}
static void cursor_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
{
CursorPipeItem *cursor_pipe_item;
spice_assert(item);
cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
cursor_pipe_item_ref(cursor_pipe_item);
}
static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
{
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
spice_assert(item);
if (item_pushed) {
cursor_channel_client_release_item_after_push(ccc, item);
} else {
spice_debug("not pushed (%d)", item->type);
cursor_channel_client_release_item_before_push(ccc, item);
}
}
CursorChannel* cursor_channel_new(RedWorker *worker, int migrate)
{
CursorChannel* cursor;
spice_info("create cursor channel");
cursor = (CursorChannel *)__new_channel(
worker, sizeof(CursorChannel),
SPICE_CHANNEL_CURSOR,
0,
cursor_channel_client_on_disconnect,
cursor_channel_send_item,
cursor_channel_hold_pipe_item,
cursor_channel_release_item,
red_channel_client_handle_message,
NULL,
NULL,
NULL);
cursor->cursor_visible = TRUE;
cursor->mouse_mode = SPICE_MOUSE_MODE_SERVER;
return cursor;
}
CursorChannelClient *cursor_channel_client_new(CommonChannel *common,
RedClient *client, RedsStream *stream,
int mig_target,
uint32_t *common_caps, int num_common_caps,
uint32_t *caps, int num_caps)
{
CursorChannelClient *ccc =
(CursorChannelClient*)common_channel_client_create(
sizeof(CursorChannelClient), common, client, stream,
mig_target,
FALSE,
common_caps,
num_common_caps,
caps,
num_caps);
if (!ccc) {
return NULL;
}
ring_init(&ccc->cursor_cache_lru);
ccc->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
return ccc;
}
void cursor_channel_process_cmd(CursorChannel *cursor, RedCursorCmd *cursor_cmd,
uint32_t group_id)
{
CursorItem *cursor_item;
int cursor_show = FALSE;
cursor_item = cursor_item_new(cursor_cmd, group_id);
switch (cursor_cmd->type) {
case QXL_CURSOR_SET:
cursor->cursor_visible = cursor_cmd->u.set.visible;
cursor_set_item(cursor, cursor_item);
break;
case QXL_CURSOR_MOVE:
cursor_show = !cursor->cursor_visible;
cursor->cursor_visible = TRUE;
cursor->cursor_position = cursor_cmd->u.position;
break;
case QXL_CURSOR_HIDE:
cursor->cursor_visible = FALSE;
break;
case QXL_CURSOR_TRAIL:
cursor->cursor_trail_length = cursor_cmd->u.trail.length;
cursor->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
break;
default:
spice_error("invalid cursor command %u", cursor_cmd->type);
}
if (red_channel_is_connected(&cursor->common.base) && (cursor->mouse_mode == SPICE_MOUSE_MODE_SERVER ||
cursor_cmd->type != QXL_CURSOR_MOVE || cursor_show)) {
red_channel_pipes_new_add(&cursor->common.base, new_cursor_pipe_item,
(void*)cursor_item);
}
cursor_item_unref(red_worker_get_qxl(cursor->common.worker), cursor_item);
}
void cursor_channel_reset(CursorChannel *cursor)
{
cursor_set_item(cursor, NULL);
cursor->cursor_visible = TRUE;
cursor->cursor_position.x = cursor->cursor_position.y = 0;
cursor->cursor_trail_length = cursor->cursor_trail_frequency = 0;
if (red_channel_is_connected(&cursor->common.base)) {
red_channel_pipes_add_type(&cursor->common.base,
PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
if (!cursor->common.during_target_migrate) {
red_pipes_add_verb(&cursor->common.base, SPICE_MSG_CURSOR_RESET);
}
if (!red_channel_wait_all_sent(&cursor->common.base,
DISPLAY_CLIENT_TIMEOUT)) {
red_channel_apply_clients(&cursor->common.base,
red_channel_client_disconnect_if_pending_send);
}
}
}

View File

@ -18,7 +18,11 @@
#ifndef CURSOR_CHANNEL_H_
# define CURSOR_CHANNEL_H_
#include "spice.h"
#include "reds.h"
#include "red_worker.h"
#include "red_parse_qxl.h"
#include "cache-item.h"
#include "stat.h"
#define CLIENT_CURSOR_CACHE_SIZE 256
@ -59,6 +63,13 @@ typedef struct CursorChannelClient {
typedef struct CursorChannel {
CommonChannel common; // Must be the first thing
CursorItem *item;
int cursor_visible;
SpicePoint16 cursor_position;
uint16_t cursor_trail_length;
uint16_t cursor_trail_frequency;
uint32_t mouse_mode;
#ifdef RED_STATISTICS
StatNodeRef stat;
#endif
@ -66,5 +77,20 @@ typedef struct CursorChannel {
G_STATIC_ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
CursorChannel* cursor_channel_new (RedWorker *worker, int migrate);
void cursor_channel_disconnect (RedChannel *channel);
void cursor_channel_reset (CursorChannel *cursor);
void cursor_channel_process_cmd (CursorChannel *cursor, RedCursorCmd *cursor_cmd,
uint32_t group_id);
CursorItem* cursor_item_new (RedCursorCmd *cmd, uint32_t group_id);
void cursor_item_unref (QXLInstance *qxl, CursorItem *cursor);
CursorChannelClient *cursor_channel_client_new(CommonChannel *common,
RedClient *client, RedsStream *stream,
int mig_target,
uint32_t *common_caps, int num_common_caps,
uint32_t *caps, int num_caps);
#endif /* CURSOR_CHANNEL_H_ */

View File

@ -265,33 +265,6 @@ struct SpiceWatch {
void *watch_func_opaque;
};
enum {
PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_CHANNEL_BASE,
PIPE_ITEM_TYPE_INVAL_ONE,
PIPE_ITEM_TYPE_CURSOR,
PIPE_ITEM_TYPE_CURSOR_INIT,
PIPE_ITEM_TYPE_IMAGE,
PIPE_ITEM_TYPE_STREAM_CREATE,
PIPE_ITEM_TYPE_STREAM_CLIP,
PIPE_ITEM_TYPE_STREAM_DESTROY,
PIPE_ITEM_TYPE_UPGRADE,
PIPE_ITEM_TYPE_VERB,
PIPE_ITEM_TYPE_MIGRATE_DATA,
PIPE_ITEM_TYPE_PIXMAP_SYNC,
PIPE_ITEM_TYPE_PIXMAP_RESET,
PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE,
PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE,
PIPE_ITEM_TYPE_CREATE_SURFACE,
PIPE_ITEM_TYPE_DESTROY_SURFACE,
PIPE_ITEM_TYPE_MONITORS_CONFIG,
PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
};
typedef struct VerbItem {
PipeItem base;
uint16_t verb;
} VerbItem;
#define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS
typedef struct SurfaceCreateItem {
@ -637,12 +610,6 @@ typedef struct RedWorker {
uint32_t bits_unique;
CursorItem *cursor;
int cursor_visible;
SpicePoint16 cursor_position;
uint16_t cursor_trail_length;
uint16_t cursor_trail_frequency;
_Drawable drawables[NUM_DRAWABLES];
_Drawable *free_drawables;
@ -654,8 +621,6 @@ typedef struct RedWorker {
spice_wan_compression_t jpeg_state;
spice_wan_compression_t zlib_glz_state;
uint32_t mouse_mode;
uint32_t streaming_video;
Stream streams_buf[NUM_STREAMS];
Stream *free_streams;
@ -732,7 +697,6 @@ static void red_draw_drawable(RedWorker *worker, Drawable *item);
static void red_update_area(RedWorker *worker, const SpiceRect *area, int surface_id);
static void red_update_area_till(RedWorker *worker, const SpiceRect *area, int surface_id,
Drawable *last);
static void cursor_item_unref(RedWorker *worker, CursorItem *cursor);
static inline void release_drawable(RedWorker *worker, Drawable *item);
static void red_display_release_stream(RedWorker *worker, StreamAgent *agent);
static inline void red_detach_stream(RedWorker *worker, Stream *stream, int detach_sized);
@ -751,15 +715,11 @@ static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surf
static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap,
uint32_t group_id);
static inline int _stride_is_extra(SpiceBitmap *bitmap);
static void red_disconnect_cursor(RedChannel *channel);
static void display_channel_client_release_item_before_push(DisplayChannelClient *dcc,
PipeItem *item);
static void display_channel_client_release_item_after_push(DisplayChannelClient *dcc,
PipeItem *item);
static void cursor_channel_client_release_item_before_push(CursorChannelClient *ccc,
PipeItem *item);
static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
PipeItem *item);
static void red_push_monitors_config(DisplayChannelClient *dcc);
@ -769,21 +729,6 @@ static void red_push_monitors_config(DisplayChannelClient *dcc);
* given a channel, iterate over it's clients
*/
/* a generic safe for loop macro */
#define SAFE_FOREACH(link, next, cond, ring, data, get_data) \
for ((((link) = ((cond) ? ring_get_head(ring) : NULL)), \
((next) = ((link) ? ring_next((ring), (link)) : NULL)), \
((data) = ((link)? (get_data) : NULL))); \
(link); \
(((link) = (next)), \
((next) = ((link) ? ring_next((ring), (link)) : NULL)), \
((data) = ((link)? (get_data) : NULL))))
#define LINK_TO_RCC(ptr) SPICE_CONTAINEROF(ptr, RedChannelClient, channel_link)
#define RCC_FOREACH_SAFE(link, next, rcc, channel) \
SAFE_FOREACH(link, next, channel, &(channel)->clients, rcc, LINK_TO_RCC(link))
#define LINK_TO_DCC(ptr) SPICE_CONTAINEROF(ptr, DisplayChannelClient, \
common.base.channel_link)
#define DCC_FOREACH_SAFE(link, next, dcc, channel) \
@ -911,6 +856,13 @@ static void print_compress_stats(DisplayChannel *display_channel)
#endif
QXLInstance* red_worker_get_qxl(RedWorker *worker)
{
spice_return_val_if_fail(worker != NULL, NULL);
return worker->qxl;
}
static MonitorsConfig *monitors_config_getref(MonitorsConfig *monitors_config)
{
monitors_config->refs++;
@ -1066,28 +1018,9 @@ static void show_draw_item(RedWorker *worker, DrawItem *draw_item, const char *p
draw_item->base.rgn.extents.y2);
}
static void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
{
VerbItem *item = spice_new(VerbItem, 1);
red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_VERB);
item->verb = verb;
red_channel_client_pipe_add(rcc, &item->base);
}
static inline void red_create_surface_item(DisplayChannelClient *dcc, int surface_id);
static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id);
static void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
{
RedChannelClient *rcc;
RingItem *link, *next;
RCC_FOREACH_SAFE(link, next, rcc, channel) {
red_pipe_add_verb(rcc, verb);
}
}
static inline void red_handle_drawable_surfaces_client_synced(
DisplayChannelClient *dcc, Drawable *drawable)
{
@ -1320,10 +1253,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32
}
}
#define CLIENT_CURSOR_CACHE
#include "cache_item.tmpl.c"
#undef CLIENT_CURSOR_CACHE
#define CLIENT_PALETTE_CACHE
#include "cache_item.tmpl.c"
#undef CLIENT_PALETTE_CACHE
@ -1333,11 +1262,6 @@ static void red_reset_palette_cache(DisplayChannelClient *dcc)
red_palette_cache_reset(dcc, CLIENT_PALETTE_CACHE_SIZE);
}
static void red_reset_cursor_cache(RedChannelClient *rcc)
{
red_cursor_cache_reset(RCC_TO_CCC(rcc), CLIENT_CURSOR_CACHE_SIZE);
}
static inline Drawable *alloc_drawable(RedWorker *worker)
{
Drawable *drawable;
@ -4231,123 +4155,6 @@ static void red_update_area(RedWorker *worker, const SpiceRect *area, int surfac
validate_area(worker, area, surface_id);
}
static void cursor_item_unref(RedWorker *worker, CursorItem *cursor)
{
if (!--cursor->refs) {
QXLReleaseInfoExt release_info_ext;
RedCursorCmd *cursor_cmd;
cursor_cmd = cursor->red_cursor;
release_info_ext.group_id = cursor->group_id;
release_info_ext.info = cursor_cmd->release_info;
worker->qxl->st->qif->release_resource(worker->qxl, release_info_ext);
red_put_cursor_cmd(cursor_cmd);
free(cursor_cmd);
g_slice_free(CursorItem, cursor);
}
}
static void red_set_cursor(RedWorker *worker, CursorItem *cursor)
{
if (worker->cursor) {
cursor_item_unref(worker, worker->cursor);
}
++cursor->refs;
worker->cursor = cursor;
}
static inline CursorItem *alloc_cursor_item(void)
{
CursorItem *cursor_item;
cursor_item = g_slice_new0(CursorItem);
cursor_item->refs = 1;
return cursor_item;
}
static CursorItem *cursor_item_new(RedCursorCmd *cmd, uint32_t group_id)
{
CursorItem *cursor_item;
spice_return_val_if_fail(cmd != NULL, NULL);
cursor_item = alloc_cursor_item();
cursor_item->group_id = group_id;
cursor_item->red_cursor = cmd;
return cursor_item;
}
static CursorPipeItem *cursor_pipe_item_ref(CursorPipeItem *item)
{
spice_assert(item);
item->refs++;
return item;
}
static PipeItem *new_cursor_pipe_item(RedChannelClient *rcc, void *data, int num)
{
CursorPipeItem *item = spice_malloc0(sizeof(CursorPipeItem));
red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_CURSOR);
item->refs = 1;
item->cursor_item = data;
item->cursor_item->refs++;
return &item->base;
}
static void put_cursor_pipe_item(CursorChannelClient *ccc, CursorPipeItem *pipe_item)
{
spice_assert(pipe_item);
if (--pipe_item->refs) {
return;
}
spice_assert(!pipe_item_is_linked(&pipe_item->base));
cursor_item_unref(ccc->common.worker, pipe_item->cursor_item);
free(pipe_item);
}
static void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint32_t group_id)
{
CursorItem *cursor_item;
int cursor_show = FALSE;
cursor_item = cursor_item_new(cursor_cmd, group_id);
switch (cursor_cmd->type) {
case QXL_CURSOR_SET:
worker->cursor_visible = cursor_cmd->u.set.visible;
red_set_cursor(worker, cursor_item);
break;
case QXL_CURSOR_MOVE:
cursor_show = !worker->cursor_visible;
worker->cursor_visible = TRUE;
worker->cursor_position = cursor_cmd->u.position;
break;
case QXL_CURSOR_HIDE:
worker->cursor_visible = FALSE;
break;
case QXL_CURSOR_TRAIL:
worker->cursor_trail_length = cursor_cmd->u.trail.length;
worker->cursor_trail_frequency = cursor_cmd->u.trail.frequency;
break;
default:
spice_error("invalid cursor command %u", cursor_cmd->type);
}
if (cursor_is_connected(worker) && (worker->mouse_mode == SPICE_MOUSE_MODE_SERVER ||
cursor_cmd->type != QXL_CURSOR_MOVE || cursor_show)) {
red_channel_pipes_new_add(&worker->cursor_channel->common.base, new_cursor_pipe_item,
(void*)cursor_item);
}
cursor_item_unref(worker, cursor_item);
}
static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty)
{
QXLCommandExt ext_cmd;
@ -4386,7 +4193,7 @@ static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ri
break;
}
qxl_process_cursor(worker, cursor, ext_cmd.group_id);
cursor_channel_process_cmd(worker->cursor_channel, cursor, ext_cmd.group_id);
break;
}
default:
@ -4650,11 +4457,6 @@ static void red_push_surface_image(DisplayChannelClient *dcc, int surface_id)
red_channel_client_push(&dcc->common.base);
}
typedef struct {
void *data;
uint32_t size;
} AddBufInfo;
static void marshaller_add_compressed(SpiceMarshaller *m,
RedCompressBuf *comp_buf, size_t size)
{
@ -4670,13 +4472,6 @@ static void marshaller_add_compressed(SpiceMarshaller *m,
}
static void add_buf_from_info(SpiceMarshaller *m, AddBufInfo *info)
{
if (info->data) {
spice_marshaller_add_ref(m, info->data, info->size);
}
}
static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable)
{
SpiceMsgDisplayBase base;
@ -6368,36 +6163,6 @@ static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id
}
}
static void cursor_fill(CursorChannelClient *ccc, SpiceCursor *red_cursor,
CursorItem *cursor, AddBufInfo *addbuf)
{
RedCursorCmd *cursor_cmd;
addbuf->data = NULL;
if (!cursor) {
red_cursor->flags = SPICE_CURSOR_FLAGS_NONE;
return;
}
cursor_cmd = cursor->red_cursor;
*red_cursor = cursor_cmd->u.set.shape;
if (red_cursor->header.unique) {
if (red_cursor_cache_find(ccc, red_cursor->header.unique)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
return;
}
if (red_cursor_cache_add(ccc, red_cursor->header.unique, 1)) {
red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
}
}
if (red_cursor->data_size) {
addbuf->data = red_cursor->data;
addbuf->size = red_cursor->data_size;
}
}
static inline void red_display_reset_send_data(DisplayChannelClient *dcc)
{
red_display_reset_compress_buf(dcc);
@ -8153,14 +7918,8 @@ static inline void marshall_qxl_drawable(RedChannelClient *rcc,
red_lossy_marshall_qxl_drawable(display_channel->common.worker, rcc, m, dpi);
}
static inline void red_marshall_verb(RedChannelClient *rcc, uint16_t verb)
{
spice_assert(rcc);
red_channel_client_init_send_data(rcc, verb, NULL);
}
static inline void red_marshall_inval(RedChannelClient *rcc,
SpiceMarshaller *base_marshaller, CacheItem *cach_item)
SpiceMarshaller *base_marshaller, CacheItem *cach_item)
{
SpiceMsgDisplayInvalOne inval_one;
@ -8545,93 +8304,6 @@ static void red_display_marshall_stream_end(RedChannelClient *rcc,
spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy);
}
static void red_cursor_marshall_inval(RedChannelClient *rcc,
SpiceMarshaller *m, CacheItem *cach_item)
{
spice_assert(rcc);
red_marshall_inval(rcc, m, cach_item);
}
static void red_marshall_cursor_init(RedChannelClient *rcc, SpiceMarshaller *base_marshaller,
PipeItem *pipe_item)
{
CursorChannel *cursor_channel;
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
RedWorker *worker;
SpiceMsgCursorInit msg;
AddBufInfo info;
spice_assert(rcc);
cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
worker = cursor_channel->common.worker;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_INIT, NULL);
msg.visible = worker->cursor_visible;
msg.position = worker->cursor_position;
msg.trail_length = worker->cursor_trail_length;
msg.trail_frequency = worker->cursor_trail_frequency;
cursor_fill(ccc, &msg.cursor, worker->cursor, &info);
spice_marshall_msg_cursor_init(base_marshaller, &msg);
add_buf_from_info(base_marshaller, &info);
}
static void cursor_marshall(RedChannelClient *rcc,
SpiceMarshaller *m, CursorPipeItem *cursor_pipe_item)
{
CursorChannel *cursor_channel = SPICE_CONTAINEROF(rcc->channel, CursorChannel, common.base);
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
CursorItem *cursor = cursor_pipe_item->cursor_item;
PipeItem *pipe_item = &cursor_pipe_item->base;
RedCursorCmd *cmd;
RedWorker *worker;
spice_assert(cursor_channel);
worker = cursor_channel->common.worker;
cmd = cursor->red_cursor;
switch (cmd->type) {
case QXL_CURSOR_MOVE:
{
SpiceMsgCursorMove cursor_move;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_MOVE, pipe_item);
cursor_move.position = cmd->u.position;
spice_marshall_msg_cursor_move(m, &cursor_move);
break;
}
case QXL_CURSOR_SET:
{
SpiceMsgCursorSet cursor_set;
AddBufInfo info;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_SET, pipe_item);
cursor_set.position = cmd->u.set.position;
cursor_set.visible = worker->cursor_visible;
cursor_fill(ccc, &cursor_set.cursor, cursor, &info);
spice_marshall_msg_cursor_set(m, &cursor_set);
add_buf_from_info(m, &info);
break;
}
case QXL_CURSOR_HIDE:
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_HIDE, pipe_item);
break;
case QXL_CURSOR_TRAIL:
{
SpiceMsgCursorTrail cursor_trail;
red_channel_client_init_send_data(rcc, SPICE_MSG_CURSOR_TRAIL, pipe_item);
cursor_trail.length = cmd->u.trail.length;
cursor_trail.frequency = cmd->u.trail.frequency;
spice_marshall_msg_cursor_trail(m, &cursor_trail);
}
break;
default:
spice_error("bad cursor command %d", cmd->type);
}
}
static void red_marshall_surface_create(RedChannelClient *rcc,
SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create)
{
@ -8789,37 +8461,6 @@ static void display_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item
}
}
static void cursor_channel_send_item(RedChannelClient *rcc, PipeItem *pipe_item)
{
SpiceMarshaller *m = red_channel_client_get_marshaller(rcc);
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
switch (pipe_item->type) {
case PIPE_ITEM_TYPE_CURSOR:
cursor_marshall(rcc, m, SPICE_CONTAINEROF(pipe_item, CursorPipeItem, base));
break;
case PIPE_ITEM_TYPE_INVAL_ONE:
red_cursor_marshall_inval(rcc, m, (CacheItem *)pipe_item);
break;
case PIPE_ITEM_TYPE_VERB:
red_marshall_verb(rcc, ((VerbItem*)pipe_item)->verb);
break;
case PIPE_ITEM_TYPE_CURSOR_INIT:
red_reset_cursor_cache(rcc);
red_marshall_cursor_init(rcc, m, pipe_item);
break;
case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
red_reset_cursor_cache(rcc);
red_marshall_verb(rcc, SPICE_MSG_CURSOR_INVAL_ALL);
break;
default:
spice_error("invalid pipe item type");
}
cursor_channel_client_release_item_before_push(ccc, pipe_item);
red_channel_client_begin_send_message(rcc);
}
static inline void red_push(RedWorker *worker)
{
if (worker->cursor_channel) {
@ -9267,7 +8908,8 @@ static inline void flush_cursor_commands(RedWorker *worker)
red_channel_send(channel);
if (red_now() >= end_time) {
spice_warning("flush cursor timeout");
red_disconnect_cursor(channel);
cursor_channel_disconnect(channel);
worker->cursor_channel = NULL;
} else {
sleep_count++;
usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
@ -9878,16 +9520,16 @@ SpiceCoreInterface worker_core = {
.watch_remove = worker_watch_remove,
};
static CommonChannelClient *common_channel_client_create(int size,
CommonChannel *common,
RedClient *client,
RedsStream *stream,
int mig_target,
int monitor_latency,
uint32_t *common_caps,
int num_common_caps,
uint32_t *caps,
int num_caps)
CommonChannelClient *common_channel_client_create(int size,
CommonChannel *common,
RedClient *client,
RedsStream *stream,
int mig_target,
int monitor_latency,
uint32_t *common_caps,
int num_common_caps,
uint32_t *caps,
int num_caps)
{
RedChannelClient *rcc =
red_channel_client_create(size, &common->base, client, stream, monitor_latency,
@ -9930,40 +9572,16 @@ DisplayChannelClient *display_channel_client_create(CommonChannel *common,
return dcc;
}
CursorChannelClient *cursor_channel_create_rcc(CommonChannel *common,
RedClient *client, RedsStream *stream,
int mig_target,
uint32_t *common_caps, int num_common_caps,
uint32_t *caps, int num_caps)
{
CursorChannelClient *ccc =
(CursorChannelClient*)common_channel_client_create(
sizeof(CursorChannelClient), common, client, stream,
mig_target,
FALSE,
common_caps,
num_common_caps,
caps,
num_caps);
if (!ccc) {
return NULL;
}
ring_init(&ccc->cursor_cache_lru);
ccc->cursor_cache_available = CLIENT_CURSOR_CACHE_SIZE;
return ccc;
}
static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type,
int migration_flags,
channel_disconnect_proc on_disconnect,
channel_send_pipe_item_proc send_item,
channel_hold_pipe_item_proc hold_item,
channel_release_pipe_item_proc release_item,
channel_handle_parsed_proc handle_parsed,
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
channel_handle_migrate_data_proc handle_migrate_data,
channel_handle_migrate_data_get_serial_proc migrate_get_serial)
RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type,
int migration_flags,
channel_disconnect_proc on_disconnect,
channel_send_pipe_item_proc send_item,
channel_hold_pipe_item_proc hold_item,
channel_release_pipe_item_proc release_item,
channel_handle_parsed_proc handle_parsed,
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
channel_handle_migrate_data_proc handle_migrate_data,
channel_handle_migrate_data_get_serial_proc migrate_get_serial)
{
RedChannel *channel = NULL;
CommonChannel *common;
@ -10288,28 +9906,6 @@ static void handle_new_display_channel(RedWorker *worker, RedClient *client, Red
on_new_display_channel_client(dcc);
}
static void cursor_channel_client_on_disconnect(RedChannelClient *rcc)
{
if (!rcc) {
return;
}
red_reset_cursor_cache(rcc);
}
static void red_disconnect_cursor(RedChannel *channel)
{
CommonChannel *common;
if (!channel || !red_channel_is_connected(channel)) {
return;
}
common = SPICE_CONTAINEROF(channel, CommonChannel, base);
spice_assert(channel == (RedChannel *)common->worker->cursor_channel);
common->worker->cursor_channel = NULL;
red_channel_apply_clients(channel, red_reset_cursor_cache);
red_channel_disconnect(channel);
}
static void red_migrate_cursor(RedWorker *worker, RedChannelClient *rcc)
{
if (red_channel_client_is_connected(rcc)) {
@ -10333,84 +9929,6 @@ static void on_new_cursor_channel(RedWorker *worker, RedChannelClient *rcc)
}
}
static void cursor_channel_hold_pipe_item(RedChannelClient *rcc, PipeItem *item)
{
CursorPipeItem *cursor_pipe_item;
spice_assert(item);
cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
cursor_pipe_item_ref(cursor_pipe_item);
}
// TODO: share code between before/after_push since most of the items need the same
// release
static void cursor_channel_client_release_item_before_push(CursorChannelClient *ccc,
PipeItem *item)
{
switch (item->type) {
case PIPE_ITEM_TYPE_CURSOR: {
CursorPipeItem *cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
put_cursor_pipe_item(ccc, cursor_pipe_item);
break;
}
case PIPE_ITEM_TYPE_INVAL_ONE:
case PIPE_ITEM_TYPE_VERB:
case PIPE_ITEM_TYPE_CURSOR_INIT:
case PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE:
free(item);
break;
default:
spice_error("invalid pipe item type");
}
}
static void cursor_channel_client_release_item_after_push(CursorChannelClient *ccc,
PipeItem *item)
{
switch (item->type) {
case PIPE_ITEM_TYPE_CURSOR: {
CursorPipeItem *cursor_pipe_item = SPICE_CONTAINEROF(item, CursorPipeItem, base);
put_cursor_pipe_item(ccc, cursor_pipe_item);
break;
}
default:
spice_critical("invalid item type");
}
}
static void cursor_channel_release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed)
{
CursorChannelClient *ccc = RCC_TO_CCC(rcc);
spice_assert(item);
if (item_pushed) {
cursor_channel_client_release_item_after_push(ccc, item);
} else {
spice_debug("not pushed (%d)", item->type);
cursor_channel_client_release_item_before_push(ccc, item);
}
}
static void cursor_channel_create(RedWorker *worker, int migrate)
{
if (worker->cursor_channel != NULL) {
return;
}
spice_info("create cursor channel");
worker->cursor_channel = (CursorChannel *)__new_channel(
worker, sizeof(*worker->cursor_channel),
SPICE_CHANNEL_CURSOR,
0,
cursor_channel_client_on_disconnect,
cursor_channel_send_item,
cursor_channel_hold_pipe_item,
cursor_channel_release_item,
red_channel_client_handle_message,
NULL,
NULL,
NULL);
}
static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream *stream,
int migrate,
uint32_t *common_caps, int num_common_caps,
@ -10425,7 +9943,7 @@ static void red_connect_cursor(RedWorker *worker, RedClient *client, RedsStream
}
channel = worker->cursor_channel;
spice_info("add cursor channel client");
ccc = cursor_channel_create_rcc(&channel->common, client, stream,
ccc = cursor_channel_client_new(&channel->common, client, stream,
migrate,
common_caps, num_common_caps,
caps, num_caps);
@ -10590,31 +10108,6 @@ void handle_dev_destroy_surface_wait(void *opaque, void *payload)
dev_destroy_surface_wait(worker, msg->surface_id);
}
static inline void red_cursor_reset(RedWorker *worker)
{
if (worker->cursor) {
cursor_item_unref(worker, worker->cursor);
worker->cursor = NULL;
}
worker->cursor_visible = TRUE;
worker->cursor_position.x = worker->cursor_position.y = 0;
worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
if (cursor_is_connected(worker)) {
red_channel_pipes_add_type(&worker->cursor_channel->common.base,
PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
if (!worker->cursor_channel->common.during_target_migrate) {
red_pipes_add_verb(&worker->cursor_channel->common.base, SPICE_MSG_CURSOR_RESET);
}
if (!red_channel_wait_all_sent(&worker->cursor_channel->common.base,
DISPLAY_CLIENT_TIMEOUT)) {
red_channel_apply_clients(&worker->cursor_channel->common.base,
red_channel_client_disconnect_if_pending_send);
}
}
}
/* called upon device reset */
/* TODO: split me*/
@ -10645,7 +10138,7 @@ static inline void dev_destroy_surfaces(RedWorker *worker)
red_display_clear_glz_drawables(worker->display_channel);
red_cursor_reset(worker);
cursor_channel_reset(worker->cursor_channel);
}
void handle_dev_destroy_surfaces(void *opaque, void *payload)
@ -10835,7 +10328,7 @@ static void dev_destroy_primary_surface(RedWorker *worker, uint32_t surface_id)
spice_assert(!worker->surfaces[surface_id].context.canvas);
red_cursor_reset(worker);
cursor_channel_reset(worker->cursor_channel);
}
void handle_dev_destroy_primary_surface(void *opaque, void *payload)
@ -11005,7 +10498,7 @@ void handle_dev_oom(void *opaque, void *payload)
void handle_dev_reset_cursor(void *opaque, void *payload)
{
red_cursor_reset((RedWorker *)opaque);
cursor_channel_reset(((RedWorker*)opaque)->cursor_channel);
}
void handle_dev_reset_image_cache(void *opaque, void *payload)
@ -11150,7 +10643,9 @@ void handle_dev_cursor_channel_create(void *opaque, void *payload)
RedChannel *red_channel;
// TODO: handle seemless migration. Temp, setting migrate to FALSE
cursor_channel_create(worker, FALSE);
if (!worker->cursor_channel) {
worker->cursor_channel = cursor_channel_new(worker, FALSE);
}
red_channel = &worker->cursor_channel->common.base;
send_data(worker->channel, &red_channel, sizeof(RedChannel *));
}
@ -11266,8 +10761,8 @@ void handle_dev_set_mouse_mode(void *opaque, void *payload)
RedWorkerMessageSetMouseMode *msg = payload;
RedWorker *worker = opaque;
worker->mouse_mode = msg->mode;
spice_info("mouse mode %u", worker->mouse_mode);
worker->cursor_channel->mouse_mode = msg->mode;
spice_info("mouse mode %u", worker->cursor_channel->mouse_mode);
}
void handle_dev_add_memslot_async(void *opaque, void *payload)
@ -11304,7 +10799,7 @@ static int loadvm_command(RedWorker *worker, QXLCommandExt *ext)
free(cursor_cmd);
return FALSE;
}
qxl_process_cursor(worker, cursor_cmd, ext->group_id);
cursor_channel_process_cmd(worker->cursor_channel, cursor_cmd, ext->group_id);
break;
case QXL_CMD_SURFACE:
surface_cmd = spice_new0(RedSurfaceCmd, 1);
@ -11581,12 +11076,10 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher)
if (worker->record_fd) {
dispatcher_register_universal_handler(dispatcher, worker_dispatcher_record);
}
worker->cursor_visible = TRUE;
spice_assert(num_renderers > 0);
worker->num_renderers = num_renderers;
memcpy(worker->renderers, renderers, sizeof(worker->renderers));
worker->renderer = RED_RENDERER_INVALID;
worker->mouse_mode = SPICE_MOUSE_MODE_SERVER;
worker->image_compression = image_compression;
worker->jpeg_state = jpeg_state;
worker->zlib_glz_state = zlib_glz_state;

View File

@ -32,6 +32,8 @@ typedef struct CommonChannelClient {
int is_low_bandwidth;
} CommonChannelClient;
#define DISPLAY_CLIENT_TIMEOUT 30000000000ULL //nano
#define CHANNEL_RECEIVE_BUF_SIZE 1024
typedef struct CommonChannel {
RedChannel base; // Must be the first thing
@ -45,7 +47,97 @@ typedef struct CommonChannel {
of the primary surface) */
} CommonChannel;
enum {
PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_CHANNEL_BASE,
PIPE_ITEM_TYPE_INVAL_ONE,
PIPE_ITEM_TYPE_CURSOR,
PIPE_ITEM_TYPE_CURSOR_INIT,
PIPE_ITEM_TYPE_IMAGE,
PIPE_ITEM_TYPE_STREAM_CREATE,
PIPE_ITEM_TYPE_STREAM_CLIP,
PIPE_ITEM_TYPE_STREAM_DESTROY,
PIPE_ITEM_TYPE_UPGRADE,
PIPE_ITEM_TYPE_VERB,
PIPE_ITEM_TYPE_MIGRATE_DATA,
PIPE_ITEM_TYPE_PIXMAP_SYNC,
PIPE_ITEM_TYPE_PIXMAP_RESET,
PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE,
PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE,
PIPE_ITEM_TYPE_CREATE_SURFACE,
PIPE_ITEM_TYPE_DESTROY_SURFACE,
PIPE_ITEM_TYPE_MONITORS_CONFIG,
PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
};
typedef struct VerbItem {
PipeItem base;
uint16_t verb;
} VerbItem;
static inline void red_marshall_verb(RedChannelClient *rcc, uint16_t verb)
{
spice_assert(rcc);
red_channel_client_init_send_data(rcc, verb, NULL);
}
static inline void red_pipe_add_verb(RedChannelClient* rcc, uint16_t verb)
{
VerbItem *item = spice_new(VerbItem, 1);
red_channel_pipe_item_init(rcc->channel, &item->base, PIPE_ITEM_TYPE_VERB);
item->verb = verb;
red_channel_client_pipe_add(rcc, &item->base);
}
/* a generic safe for loop macro */
#define SAFE_FOREACH(link, next, cond, ring, data, get_data) \
for ((((link) = ((cond) ? ring_get_head(ring) : NULL)), \
((next) = ((link) ? ring_next((ring), (link)) : NULL)), \
((data) = ((link)? (get_data) : NULL))); \
(link); \
(((link) = (next)), \
((next) = ((link) ? ring_next((ring), (link)) : NULL)), \
((data) = ((link)? (get_data) : NULL))))
#define LINK_TO_RCC(ptr) SPICE_CONTAINEROF(ptr, RedChannelClient, channel_link)
#define RCC_FOREACH_SAFE(link, next, rcc, channel) \
SAFE_FOREACH(link, next, channel, &(channel)->clients, rcc, LINK_TO_RCC(link))
static inline void red_pipes_add_verb(RedChannel *channel, uint16_t verb)
{
RedChannelClient *rcc;
RingItem *link, *next;
RCC_FOREACH_SAFE(link, next, rcc, channel) {
red_pipe_add_verb(rcc, verb);
}
}
RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher);
bool red_worker_run(RedWorker *worker);
QXLInstance* red_worker_get_qxl(RedWorker *worker);
CommonChannelClient *common_channel_client_create(int size,
CommonChannel *common,
RedClient *client,
RedsStream *stream,
int mig_target,
int monitor_latency,
uint32_t *common_caps,
int num_common_caps,
uint32_t *caps,
int num_caps);
RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_type,
int migration_flags,
channel_disconnect_proc on_disconnect,
channel_send_pipe_item_proc send_item,
channel_hold_pipe_item_proc hold_item,
channel_release_pipe_item_proc release_item,
channel_handle_parsed_proc handle_parsed,
channel_handle_migrate_flush_mark_proc handle_migrate_flush_mark,
channel_handle_migrate_data_proc handle_migrate_data,
channel_handle_migrate_data_get_serial_proc migrate_get_serial);
#endif