mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-30 17:49:02 +00:00
Move thread/dispatching handling to RedChannel
Currently channel threading/handling is spread between RedQxl, RedWorker and RedChannel. Move more to RedChannel simplify RedQxl and RedWorker. Signed-off-by: Frediano Ziglio <fziglio@redhat.com> Acked-by: Jonathon Jongsma <jjongsma@redhat.com>
This commit is contained in:
parent
46efdc1e09
commit
571dc645c5
@ -228,7 +228,8 @@ static void cursor_channel_send_item(RedChannelClient *rcc, RedPipeItem *pipe_it
|
||||
}
|
||||
|
||||
CursorChannel* cursor_channel_new(RedsState *server, int id,
|
||||
const SpiceCoreInterfaceInternal *core)
|
||||
const SpiceCoreInterfaceInternal *core,
|
||||
Dispatcher *dispatcher)
|
||||
{
|
||||
spice_debug("create cursor channel");
|
||||
return g_object_new(TYPE_CURSOR_CHANNEL,
|
||||
@ -238,6 +239,7 @@ CursorChannel* cursor_channel_new(RedsState *server, int id,
|
||||
"id", id,
|
||||
"migration-flags", 0,
|
||||
"handle-acks", TRUE,
|
||||
"dispatcher", dispatcher,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include "common-graphics-channel.h"
|
||||
#include "red-parse-qxl.h"
|
||||
#include "dispatcher.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -47,17 +48,12 @@ GType cursor_channel_get_type(void) G_GNUC_CONST;
|
||||
/**
|
||||
* Create CursorChannel.
|
||||
* Since CursorChannel is intended to be run in a separate thread,
|
||||
* it does not register its own client callbacks since they would
|
||||
* be called from a different thread. Therefore users of this
|
||||
* class are responsible for registering their own client callbacks
|
||||
* for CursorChannel. These 'wrapper' client callbacks must forward
|
||||
* execution on to the CursorChannel thread.
|
||||
* cursor_channel_client_migrate() and cursor_channel_connect() are
|
||||
* provided as helper functions and should only be called from the
|
||||
* CursorChannel thread.
|
||||
* the function accepts a dispatcher parameter to allows some
|
||||
* operations to be executed in the channel thread.
|
||||
*/
|
||||
CursorChannel* cursor_channel_new(RedsState *server, int id,
|
||||
const SpiceCoreInterfaceInternal *core);
|
||||
const SpiceCoreInterfaceInternal *core,
|
||||
Dispatcher *dispatcher);
|
||||
|
||||
void cursor_channel_reset (CursorChannel *cursor);
|
||||
void cursor_channel_do_init (CursorChannel *cursor);
|
||||
@ -66,8 +62,6 @@ void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32
|
||||
|
||||
/**
|
||||
* Connect a new client to CursorChannel.
|
||||
* This is the equivalent of RedChannel client connect callback.
|
||||
* See comment on cursor_channel_new.
|
||||
*/
|
||||
void cursor_channel_connect (CursorChannel *cursor, RedClient *client,
|
||||
RedStream *stream,
|
||||
|
||||
@ -2227,6 +2227,7 @@ static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t su
|
||||
DisplayChannel* display_channel_new(RedsState *reds,
|
||||
QXLInstance *qxl,
|
||||
const SpiceCoreInterfaceInternal *core,
|
||||
Dispatcher *dispatcher,
|
||||
int migrate, int stream_video,
|
||||
GArray *video_codecs,
|
||||
uint32_t n_surfaces)
|
||||
@ -2246,6 +2247,7 @@ DisplayChannel* display_channel_new(RedsState *reds,
|
||||
"n-surfaces", n_surfaces,
|
||||
"video-codecs", video_codecs,
|
||||
"handle-acks", TRUE,
|
||||
"dispatcher", dispatcher,
|
||||
NULL);
|
||||
if (display) {
|
||||
display_channel_set_stream_video(display, stream_video);
|
||||
|
||||
@ -99,6 +99,7 @@ struct Drawable {
|
||||
DisplayChannel* display_channel_new (RedsState *reds,
|
||||
QXLInstance *qxl,
|
||||
const SpiceCoreInterfaceInternal *core,
|
||||
Dispatcher *dispatcher,
|
||||
int migrate,
|
||||
int stream_video,
|
||||
GArray *video_codecs,
|
||||
|
||||
@ -90,6 +90,12 @@ struct RedChannelPrivate
|
||||
// TODO: when different channel_clients are in different threads
|
||||
// from Channel -> need to protect!
|
||||
pthread_t thread_id;
|
||||
/* Setting dispatcher allows the channel to execute code in the right
|
||||
* thread.
|
||||
* thread_id will be used to check the channel thread and automatically
|
||||
* use the dispatcher if the thread is different.
|
||||
*/
|
||||
Dispatcher *dispatcher;
|
||||
RedsState *reds;
|
||||
RedStatNode stat;
|
||||
};
|
||||
@ -103,7 +109,8 @@ enum {
|
||||
PROP_TYPE,
|
||||
PROP_ID,
|
||||
PROP_HANDLE_ACKS,
|
||||
PROP_MIGRATION_FLAGS
|
||||
PROP_MIGRATION_FLAGS,
|
||||
PROP_DISPATCHER,
|
||||
};
|
||||
|
||||
static void
|
||||
@ -134,6 +141,9 @@ red_channel_get_property(GObject *object,
|
||||
case PROP_MIGRATION_FLAGS:
|
||||
g_value_set_uint(value, self->priv->migration_flags);
|
||||
break;
|
||||
case PROP_DISPATCHER:
|
||||
g_value_set_object(value, self->priv->dispatcher);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
@ -167,6 +177,10 @@ red_channel_set_property(GObject *object,
|
||||
case PROP_MIGRATION_FLAGS:
|
||||
self->priv->migration_flags = g_value_get_uint(value);
|
||||
break;
|
||||
case PROP_DISPATCHER:
|
||||
g_clear_object(&self->priv->dispatcher);
|
||||
self->priv->dispatcher = g_value_dup_object(value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
|
||||
}
|
||||
@ -177,6 +191,7 @@ red_channel_finalize(GObject *object)
|
||||
{
|
||||
RedChannel *self = RED_CHANNEL(object);
|
||||
|
||||
g_clear_object(&self->priv->dispatcher);
|
||||
red_channel_capabilities_reset(&self->priv->local_caps);
|
||||
|
||||
G_OBJECT_CLASS(red_channel_parent_class)->finalize(object);
|
||||
@ -279,6 +294,14 @@ red_channel_class_init(RedChannelClass *klass)
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
g_object_class_install_property(object_class, PROP_MIGRATION_FLAGS, spec);
|
||||
|
||||
spec = g_param_spec_object("dispatcher", "dispatcher",
|
||||
"Dispatcher bound to channel thread",
|
||||
TYPE_DISPATCHER,
|
||||
G_PARAM_STATIC_STRINGS
|
||||
| G_PARAM_READWRITE
|
||||
| G_PARAM_CONSTRUCT_ONLY);
|
||||
g_object_class_install_property(object_class, PROP_DISPATCHER, spec);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -483,11 +506,49 @@ void red_channel_disconnect(RedChannel *channel)
|
||||
red_channel_foreach_client(channel, red_channel_client_disconnect);
|
||||
}
|
||||
|
||||
typedef struct RedMessageConnect {
|
||||
RedChannel *channel;
|
||||
RedClient *client;
|
||||
RedStream *stream;
|
||||
RedChannelCapabilities caps;
|
||||
int migration;
|
||||
} RedMessageConnect;
|
||||
|
||||
static void handle_dispatcher_connect(void *opaque, void *payload)
|
||||
{
|
||||
RedMessageConnect *msg = payload;
|
||||
RedChannel *channel = msg->channel;
|
||||
|
||||
channel->priv->client_cbs.connect(channel, msg->client, msg->stream,
|
||||
msg->migration, &msg->caps);
|
||||
g_object_unref(msg->client);
|
||||
red_channel_capabilities_reset(&msg->caps);
|
||||
}
|
||||
|
||||
void red_channel_connect(RedChannel *channel, RedClient *client,
|
||||
RedStream *stream, int migration,
|
||||
RedChannelCapabilities *caps)
|
||||
{
|
||||
channel->priv->client_cbs.connect(channel, client, stream, migration, caps);
|
||||
if (channel->priv->dispatcher == NULL ||
|
||||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
|
||||
channel->priv->client_cbs.connect(channel, client, stream, migration, caps);
|
||||
return;
|
||||
}
|
||||
|
||||
Dispatcher *dispatcher = channel->priv->dispatcher;
|
||||
|
||||
// get a reference potentially the main channel can be destroyed in
|
||||
// the main thread causing RedClient to be destroyed before using it
|
||||
RedMessageConnect payload = {
|
||||
.channel = channel,
|
||||
.client = g_object_ref(client),
|
||||
.stream = stream,
|
||||
.migration = migration
|
||||
};
|
||||
red_channel_capabilities_init(&payload.caps, caps);
|
||||
|
||||
dispatcher_send_message_custom(dispatcher, handle_dispatcher_connect,
|
||||
&payload, sizeof(payload), false);
|
||||
}
|
||||
|
||||
GList *red_channel_get_clients(RedChannel *channel)
|
||||
@ -690,12 +751,55 @@ const RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *sel
|
||||
return &self->priv->local_caps;
|
||||
}
|
||||
|
||||
typedef struct RedMessageMigrate {
|
||||
RedChannelClient *rcc;
|
||||
} RedMessageMigrate;
|
||||
|
||||
static void handle_dispatcher_migrate(void *opaque, void *payload)
|
||||
{
|
||||
RedMessageMigrate *msg = payload;
|
||||
RedChannel *channel = red_channel_client_get_channel(msg->rcc);
|
||||
|
||||
channel->priv->client_cbs.migrate(msg->rcc);
|
||||
g_object_unref(msg->rcc);
|
||||
}
|
||||
|
||||
void red_channel_migrate_client(RedChannel *channel, RedChannelClient *rcc)
|
||||
{
|
||||
channel->priv->client_cbs.migrate(rcc);
|
||||
if (channel->priv->dispatcher == NULL ||
|
||||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
|
||||
channel->priv->client_cbs.migrate(rcc);
|
||||
return;
|
||||
}
|
||||
|
||||
RedMessageMigrate payload = { .rcc = g_object_ref(rcc) };
|
||||
dispatcher_send_message_custom(channel->priv->dispatcher, handle_dispatcher_migrate,
|
||||
&payload, sizeof(payload), false);
|
||||
}
|
||||
|
||||
typedef struct RedMessageDisconnect {
|
||||
RedChannelClient *rcc;
|
||||
} RedMessageDisconnect;
|
||||
|
||||
static void handle_dispatcher_disconnect(void *opaque, void *payload)
|
||||
{
|
||||
RedMessageDisconnect *msg = payload;
|
||||
RedChannel *channel = red_channel_client_get_channel(msg->rcc);
|
||||
|
||||
channel->priv->client_cbs.disconnect(msg->rcc);
|
||||
}
|
||||
|
||||
void red_channel_disconnect_client(RedChannel *channel, RedChannelClient *rcc)
|
||||
{
|
||||
channel->priv->client_cbs.disconnect(rcc);
|
||||
if (channel->priv->dispatcher == NULL ||
|
||||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
|
||||
channel->priv->client_cbs.disconnect(rcc);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: we turned it to be sync, due to client_destroy . Should we support async? - for this we will need ref count
|
||||
// for channels
|
||||
RedMessageDisconnect payload = { .rcc = rcc };
|
||||
dispatcher_send_message_custom(channel->priv->dispatcher, handle_dispatcher_disconnect,
|
||||
&payload, sizeof(payload), true);
|
||||
}
|
||||
|
||||
110
server/red-qxl.c
110
server/red-qxl.c
@ -75,102 +75,6 @@ int red_qxl_check_qxl_version(QXLInstance *qxl, int major, int minor)
|
||||
((qxl_major == major) && (qxl_minor >= minor)));
|
||||
}
|
||||
|
||||
static void red_qxl_set_display_peer(RedChannel *channel, RedClient *client,
|
||||
RedStream *stream, int migration,
|
||||
RedChannelCapabilities *caps)
|
||||
{
|
||||
RedWorkerMessageDisplayConnect payload = {0,};
|
||||
Dispatcher *dispatcher;
|
||||
|
||||
spice_debug("%s", "");
|
||||
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
// get a reference potentially the main channel can be destroyed in
|
||||
// the main thread causing RedClient to be destroyed before using it
|
||||
payload.client = g_object_ref(client);
|
||||
payload.stream = stream;
|
||||
payload.migration = migration;
|
||||
red_channel_capabilities_init(&payload.caps, caps);
|
||||
|
||||
dispatcher_send_message(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_CONNECT,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_disconnect_display_peer(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageDisplayDisconnect payload;
|
||||
Dispatcher *dispatcher;
|
||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||
|
||||
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
|
||||
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,
|
||||
RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_display_migrate(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageDisplayMigrate payload;
|
||||
Dispatcher *dispatcher;
|
||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||
|
||||
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
payload.rcc = g_object_ref(rcc);
|
||||
dispatcher_send_message(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_set_cursor_peer(RedChannel *channel, RedClient *client, RedStream *stream,
|
||||
int migration,
|
||||
RedChannelCapabilities *caps)
|
||||
{
|
||||
RedWorkerMessageCursorConnect payload = {0,};
|
||||
Dispatcher *dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
// get a reference potentially the main channel can be destroyed in
|
||||
// the main thread causing RedClient to be destroyed before using it
|
||||
payload.client = g_object_ref(client);
|
||||
payload.stream = stream;
|
||||
payload.migration = migration;
|
||||
red_channel_capabilities_init(&payload.caps, caps);
|
||||
|
||||
dispatcher_send_message(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_CONNECT,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_disconnect_cursor_peer(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageCursorDisconnect payload;
|
||||
Dispatcher *dispatcher;
|
||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||
|
||||
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
payload.rcc = rcc;
|
||||
|
||||
dispatcher_send_message(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_cursor_migrate(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageCursorMigrate payload;
|
||||
Dispatcher *dispatcher;
|
||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||
|
||||
dispatcher = (Dispatcher *)g_object_get_data(G_OBJECT(channel), "dispatcher");
|
||||
payload.rcc = g_object_ref(rcc);
|
||||
dispatcher_send_message(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
|
||||
&payload);
|
||||
}
|
||||
|
||||
static void red_qxl_update_area(QXLState *qxl_state, uint32_t surface_id,
|
||||
QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
|
||||
uint32_t num_dirty_rects, uint32_t clear_dirty_region)
|
||||
@ -914,8 +818,6 @@ size_t red_qxl_get_monitors_count(const QXLInstance *qxl)
|
||||
void red_qxl_init(RedsState *reds, QXLInstance *qxl)
|
||||
{
|
||||
QXLState *qxl_state;
|
||||
ClientCbs client_cursor_cbs = { NULL, };
|
||||
ClientCbs client_display_cbs = { NULL, };
|
||||
|
||||
spice_return_if_fail(qxl != NULL);
|
||||
|
||||
@ -948,17 +850,7 @@ void red_qxl_init(RedsState *reds, QXLInstance *qxl)
|
||||
qxl_state->max_monitors = UINT_MAX;
|
||||
qxl->st = qxl_state;
|
||||
|
||||
// TODO: move to their respective channel files
|
||||
client_cursor_cbs.connect = red_qxl_set_cursor_peer;
|
||||
client_cursor_cbs.disconnect = red_qxl_disconnect_cursor_peer;
|
||||
client_cursor_cbs.migrate = red_qxl_cursor_migrate;
|
||||
|
||||
client_display_cbs.connect = red_qxl_set_display_peer;
|
||||
client_display_cbs.disconnect = red_qxl_disconnect_display_peer;
|
||||
client_display_cbs.migrate = red_qxl_display_migrate;
|
||||
|
||||
qxl_state->worker = red_worker_new(qxl, &client_cursor_cbs,
|
||||
&client_display_cbs);
|
||||
qxl_state->worker = red_worker_new(qxl);
|
||||
|
||||
red_worker_run(qxl_state->worker);
|
||||
}
|
||||
|
||||
@ -1283,9 +1283,6 @@ static void replay_handle_dev_input(QXLWorker *worker, SpiceReplay *replay,
|
||||
break;
|
||||
case RED_WORKER_MESSAGE_UPDATE:
|
||||
// XXX do anything? we record the correct bitmaps already.
|
||||
case RED_WORKER_MESSAGE_DISPLAY_CONNECT:
|
||||
// we want to ignore this one - it is sent on client connection, we
|
||||
// shall have our own clients
|
||||
case RED_WORKER_MESSAGE_WAKEUP:
|
||||
// safe to ignore
|
||||
break;
|
||||
|
||||
@ -696,7 +696,7 @@ stream_device_create_channel(StreamDevice *dev)
|
||||
|
||||
StreamChannel *stream_channel = stream_channel_new(reds, id);
|
||||
|
||||
CursorChannel *cursor_channel = cursor_channel_new(reds, id, core);
|
||||
CursorChannel *cursor_channel = cursor_channel_new(reds, id, core, NULL);
|
||||
ClientCbs client_cbs = { NULL, };
|
||||
client_cbs.connect = (channel_client_connect_proc) cursor_channel_connect;
|
||||
client_cbs.migrate = cursor_channel_client_migrate;
|
||||
|
||||
@ -695,20 +695,19 @@ static void handle_dev_create_primary_surface_async(void *opaque, void *payload)
|
||||
red_qxl_async_complete(worker->qxl, msg->base.cookie);
|
||||
}
|
||||
|
||||
static void handle_dev_display_connect(void *opaque, void *payload)
|
||||
static void
|
||||
handle_dev_display_connect(RedChannel *channel, RedClient *client,
|
||||
RedStream *stream, int migration,
|
||||
RedChannelCapabilities *caps)
|
||||
{
|
||||
RedWorkerMessageDisplayConnect *msg = payload;
|
||||
RedWorker *worker = opaque;
|
||||
DisplayChannel *display = worker->display_channel;
|
||||
DisplayChannel *display = DISPLAY_CHANNEL(channel);
|
||||
DisplayChannelClient *dcc;
|
||||
RedWorker *worker = g_object_get_data(G_OBJECT(channel), "worker");
|
||||
|
||||
spice_debug("connect new client");
|
||||
spice_return_if_fail(display);
|
||||
|
||||
dcc = dcc_new(display, msg->client, msg->stream, msg->migration, &msg->caps,
|
||||
dcc = dcc_new(display, client, stream, migration, caps,
|
||||
worker->image_compression, worker->jpeg_state, worker->zlib_glz_state);
|
||||
g_object_unref(msg->client);
|
||||
red_channel_capabilities_reset(&msg->caps);
|
||||
if (!dcc) {
|
||||
return;
|
||||
}
|
||||
@ -717,30 +716,23 @@ static void handle_dev_display_connect(void *opaque, void *payload)
|
||||
dcc_start(dcc);
|
||||
}
|
||||
|
||||
static void handle_dev_display_disconnect(void *opaque, void *payload)
|
||||
static void
|
||||
handle_dev_display_disconnect(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageDisplayDisconnect *msg = payload;
|
||||
RedChannelClient *rcc = msg->rcc;
|
||||
RedWorker *worker = opaque;
|
||||
RedChannel *channel = red_channel_client_get_channel(rcc);
|
||||
RedWorker *worker = g_object_get_data(G_OBJECT(channel), "worker");
|
||||
|
||||
spice_debug("disconnect display client");
|
||||
spice_assert(rcc);
|
||||
|
||||
guest_set_client_capabilities(worker);
|
||||
|
||||
red_channel_client_disconnect(rcc);
|
||||
}
|
||||
|
||||
static void handle_dev_display_migrate(void *opaque, void *payload)
|
||||
static void handle_dev_display_migrate(RedChannelClient *rcc)
|
||||
{
|
||||
RedWorkerMessageDisplayMigrate *msg = payload;
|
||||
RedWorker *worker = opaque;
|
||||
|
||||
RedChannelClient *rcc = msg->rcc;
|
||||
spice_debug("migrate display client");
|
||||
spice_assert(rcc);
|
||||
red_migrate_display(worker->display_channel, rcc);
|
||||
g_object_unref(rcc);
|
||||
DisplayChannel *display = DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
|
||||
red_migrate_display(display, rcc);
|
||||
}
|
||||
|
||||
static inline uint32_t qxl_monitors_config_size(uint32_t heads)
|
||||
@ -792,40 +784,6 @@ async_complete:
|
||||
red_qxl_async_complete(worker->qxl, msg->base.cookie);
|
||||
}
|
||||
|
||||
/* TODO: special, perhaps use another dispatcher? */
|
||||
static void handle_dev_cursor_connect(void *opaque, void *payload)
|
||||
{
|
||||
RedWorkerMessageCursorConnect *msg = payload;
|
||||
RedWorker *worker = opaque;
|
||||
|
||||
spice_debug("cursor connect");
|
||||
cursor_channel_connect(worker->cursor_channel,
|
||||
msg->client, msg->stream, msg->migration,
|
||||
&msg->caps);
|
||||
g_object_unref(msg->client);
|
||||
red_channel_capabilities_reset(&msg->caps);
|
||||
}
|
||||
|
||||
static void handle_dev_cursor_disconnect(void *opaque, void *payload)
|
||||
{
|
||||
RedWorkerMessageCursorDisconnect *msg = payload;
|
||||
RedChannelClient *rcc = msg->rcc;
|
||||
|
||||
spice_debug("disconnect cursor client");
|
||||
spice_return_if_fail(rcc);
|
||||
red_channel_client_disconnect(rcc);
|
||||
}
|
||||
|
||||
static void handle_dev_cursor_migrate(void *opaque, void *payload)
|
||||
{
|
||||
RedWorkerMessageCursorMigrate *msg = payload;
|
||||
RedChannelClient *rcc = msg->rcc;
|
||||
|
||||
spice_debug("migrate cursor client");
|
||||
cursor_channel_client_migrate(rcc);
|
||||
g_object_unref(rcc);
|
||||
}
|
||||
|
||||
static void handle_dev_set_compression(void *opaque, void *payload)
|
||||
{
|
||||
RedWorkerMessageSetCompression *msg = payload;
|
||||
@ -999,36 +957,6 @@ static void worker_dispatcher_record(void *opaque, uint32_t message_type, void *
|
||||
static void register_callbacks(Dispatcher *dispatcher)
|
||||
{
|
||||
/* TODO: register cursor & display specific msg in respective channel files */
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_CONNECT,
|
||||
handle_dev_display_connect,
|
||||
sizeof(RedWorkerMessageDisplayConnect),
|
||||
false);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_DISCONNECT,
|
||||
handle_dev_display_disconnect,
|
||||
sizeof(RedWorkerMessageDisplayDisconnect),
|
||||
true);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_DISPLAY_MIGRATE,
|
||||
handle_dev_display_migrate,
|
||||
sizeof(RedWorkerMessageDisplayMigrate),
|
||||
false);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_CONNECT,
|
||||
handle_dev_cursor_connect,
|
||||
sizeof(RedWorkerMessageCursorConnect),
|
||||
false);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_DISCONNECT,
|
||||
handle_dev_cursor_disconnect,
|
||||
sizeof(RedWorkerMessageCursorDisconnect),
|
||||
true);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_CURSOR_MIGRATE,
|
||||
handle_dev_cursor_migrate,
|
||||
sizeof(RedWorkerMessageCursorMigrate),
|
||||
false);
|
||||
dispatcher_register_handler(dispatcher,
|
||||
RED_WORKER_MESSAGE_UPDATE,
|
||||
handle_dev_update,
|
||||
@ -1260,9 +1188,7 @@ static GSourceFuncs worker_source_funcs = {
|
||||
.dispatch = worker_source_dispatch,
|
||||
};
|
||||
|
||||
RedWorker* red_worker_new(QXLInstance *qxl,
|
||||
const ClientCbs *client_cursor_cbs,
|
||||
const ClientCbs *client_display_cbs)
|
||||
RedWorker* red_worker_new(QXLInstance *qxl)
|
||||
{
|
||||
QXLDevInitInfo init_info;
|
||||
RedWorker *worker;
|
||||
@ -1318,21 +1244,31 @@ RedWorker* red_worker_new(QXLInstance *qxl,
|
||||
worker->event_timeout = INF_EVENT_WAIT;
|
||||
|
||||
worker->cursor_channel = cursor_channel_new(reds, qxl->id,
|
||||
&worker->core);
|
||||
&worker->core, dispatcher);
|
||||
channel = RED_CHANNEL(worker->cursor_channel);
|
||||
red_channel_init_stat_node(channel, &worker->stat, "cursor_channel");
|
||||
red_channel_register_client_cbs(channel, client_cursor_cbs);
|
||||
g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
|
||||
|
||||
ClientCbs client_cursor_cbs = { NULL, };
|
||||
client_cursor_cbs.connect = (channel_client_connect_proc) cursor_channel_connect;
|
||||
client_cursor_cbs.disconnect = NULL;
|
||||
client_cursor_cbs.migrate = cursor_channel_client_migrate;
|
||||
red_channel_register_client_cbs(channel, &client_cursor_cbs);
|
||||
|
||||
// TODO: handle seamless migration. Temp, setting migrate to FALSE
|
||||
worker->display_channel = display_channel_new(reds, qxl, &worker->core, FALSE,
|
||||
worker->display_channel = display_channel_new(reds, qxl, &worker->core, dispatcher,
|
||||
FALSE,
|
||||
reds_get_streaming_video(reds),
|
||||
reds_get_video_codecs(reds),
|
||||
init_info.n_surfaces);
|
||||
channel = RED_CHANNEL(worker->display_channel);
|
||||
red_channel_init_stat_node(channel, &worker->stat, "display_channel");
|
||||
red_channel_register_client_cbs(channel, client_display_cbs);
|
||||
g_object_set_data(G_OBJECT(channel), "dispatcher", dispatcher);
|
||||
g_object_set_data(G_OBJECT(channel), "worker", worker);
|
||||
|
||||
ClientCbs client_display_cbs = { NULL, };
|
||||
client_display_cbs.connect = handle_dev_display_connect;
|
||||
client_display_cbs.disconnect = handle_dev_display_disconnect;
|
||||
client_display_cbs.migrate = handle_dev_display_migrate;
|
||||
red_channel_register_client_cbs(channel, &client_display_cbs);
|
||||
|
||||
return worker;
|
||||
}
|
||||
|
||||
@ -28,9 +28,7 @@
|
||||
|
||||
typedef struct RedWorker RedWorker;
|
||||
|
||||
RedWorker* red_worker_new(QXLInstance *qxl,
|
||||
const ClientCbs *client_cursor_cbs,
|
||||
const ClientCbs *client_display_cbs);
|
||||
RedWorker* red_worker_new(QXLInstance *qxl);
|
||||
bool red_worker_run(RedWorker *worker);
|
||||
void red_worker_free(RedWorker *worker);
|
||||
|
||||
@ -51,14 +49,14 @@ enum {
|
||||
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_DISPLAY_CONNECT_DEPRECATED,
|
||||
RED_WORKER_MESSAGE_DISPLAY_DISCONNECT_DEPRECATED,
|
||||
RED_WORKER_MESSAGE_DISPLAY_MIGRATE_DEPRECATED,
|
||||
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_CURSOR_CONNECT_DEPRECATED,
|
||||
RED_WORKER_MESSAGE_CURSOR_DISCONNECT_DEPRECATED,
|
||||
RED_WORKER_MESSAGE_CURSOR_MIGRATE_DEPRECATED,
|
||||
RED_WORKER_MESSAGE_SET_COMPRESSION,
|
||||
RED_WORKER_MESSAGE_SET_STREAMING_VIDEO,
|
||||
RED_WORKER_MESSAGE_SET_MOUSE_MODE,
|
||||
@ -97,36 +95,6 @@ enum {
|
||||
RED_WORKER_MESSAGE_COUNT // LAST
|
||||
};
|
||||
|
||||
typedef struct RedWorkerMessageDisplayConnect {
|
||||
RedClient * client;
|
||||
RedStream * stream;
|
||||
RedChannelCapabilities caps; // red_worker should reset
|
||||
int migration;
|
||||
} RedWorkerMessageDisplayConnect;
|
||||
|
||||
typedef struct RedWorkerMessageDisplayDisconnect {
|
||||
RedChannelClient *rcc;
|
||||
} RedWorkerMessageDisplayDisconnect;
|
||||
|
||||
typedef struct RedWorkerMessageDisplayMigrate {
|
||||
RedChannelClient *rcc;
|
||||
} RedWorkerMessageDisplayMigrate;
|
||||
|
||||
typedef struct RedWorkerMessageCursorConnect {
|
||||
RedClient *client;
|
||||
RedStream *stream;
|
||||
int migration;
|
||||
RedChannelCapabilities caps; // red_worker should reset
|
||||
} RedWorkerMessageCursorConnect;
|
||||
|
||||
typedef struct RedWorkerMessageCursorDisconnect {
|
||||
RedChannelClient *rcc;
|
||||
} RedWorkerMessageCursorDisconnect;
|
||||
|
||||
typedef struct RedWorkerMessageCursorMigrate {
|
||||
RedChannelClient *rcc;
|
||||
} RedWorkerMessageCursorMigrate;
|
||||
|
||||
typedef struct RedWorkerMessageUpdate {
|
||||
uint32_t surface_id;
|
||||
QXLRect * qxl_area;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user