Make channel client callbacks virtual functions

Rather than having an API to register client callbacks for each channel
type, make them vfuncs.

Since the client callbacks are registered identically for each channel
of the same type, it doesn't make sense for to require these to be
registered separately for each object.  It's cleaner to have these be
per-class properties, so they've been converted to virtual functions.

Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
Jonathon Jongsma 2019-03-20 09:28:34 +00:00 committed by Frediano Ziglio
parent fe52264204
commit 14403117b5
16 changed files with 76 additions and 123 deletions

View File

@ -75,6 +75,12 @@ enum {
RED_PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE,
};
/**
* Migrate a client channel from a CursorChannel.
* This is the equivalent of RedChannel client migrate callback.
*/
void cursor_channel_client_migrate(RedChannelClient *client);
G_END_DECLS
#endif /* CURSOR_CHANNEL_CLIENT_H_ */

View File

@ -335,9 +335,12 @@ void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode)
cursor->mouse_mode = mode;
}
void cursor_channel_connect(CursorChannel *cursor, RedClient *client, RedStream *stream,
int migrate,
RedChannelCapabilities *caps)
/**
* Connect a new client to CursorChannel.
*/
static void
cursor_channel_connect(CursorChannel *cursor, RedClient *client, RedStream *stream,
int migrate, RedChannelCapabilities *caps)
{
CursorChannelClient *ccc;
@ -392,6 +395,10 @@ cursor_channel_class_init(CursorChannelClass *klass)
channel_class->handle_message = red_channel_client_handle_message;
channel_class->send_item = cursor_channel_send_item;
// client callbacks
channel_class->connect = (channel_client_connect_proc) cursor_channel_connect;
channel_class->migrate = cursor_channel_client_migrate;
}
static void

View File

@ -60,21 +60,6 @@ void cursor_channel_do_init (CursorChannel *cursor);
void cursor_channel_process_cmd (CursorChannel *cursor, RedCursorCmd *cursor_cmd);
void cursor_channel_set_mouse_mode(CursorChannel *cursor, uint32_t mode);
/**
* Connect a new client to CursorChannel.
*/
void cursor_channel_connect (CursorChannel *cursor, RedClient *client,
RedStream *stream,
int migrate,
RedChannelCapabilities *caps);
/**
* Migrate a client channel from a CursorChannel.
* This is the equivalent of RedChannel client migrate callback.
* See comment on cursor_channel_new.
*/
void cursor_channel_client_migrate(RedChannelClient *client);
G_END_DECLS
#endif /* CURSOR_CHANNEL_H_ */

View File

@ -26,6 +26,12 @@
G_DEFINE_TYPE(DisplayChannel, display_channel, TYPE_COMMON_GRAPHICS_CHANNEL)
static void display_channel_connect(RedChannel *channel, RedClient *client,
RedStream *stream, int migration,
RedChannelCapabilities *caps);
static void display_channel_disconnect(RedChannelClient *rcc);
static void display_channel_migrate(RedChannelClient *rcc);
enum {
PROP0,
PROP_N_SURFACES,
@ -2500,6 +2506,11 @@ display_channel_class_init(DisplayChannelClass *klass)
channel_class->handle_migrate_data = handle_migrate_data;
channel_class->handle_migrate_data_get_serial = handle_migrate_data_get_serial;
// client callbacks
channel_class->connect = display_channel_connect;
channel_class->disconnect = display_channel_disconnect;
channel_class->migrate = display_channel_migrate;
g_object_class_install_property(object_class,
PROP_N_SURFACES,
g_param_spec_uint("n-surfaces",
@ -2590,7 +2601,7 @@ void display_channel_update_qxl_running(DisplayChannel *display, bool running)
}
}
void
static void
display_channel_connect(RedChannel *channel, RedClient *client,
RedStream *stream, int migration,
RedChannelCapabilities *caps)
@ -2613,7 +2624,7 @@ display_channel_connect(RedChannel *channel, RedClient *client,
dcc_start(dcc);
}
void display_channel_disconnect(RedChannelClient *rcc)
static void display_channel_disconnect(RedChannelClient *rcc)
{
DisplayChannel *display = DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
@ -2640,7 +2651,7 @@ static void red_migrate_display(DisplayChannel *display, RedChannelClient *rcc)
}
}
void display_channel_migrate(RedChannelClient *rcc)
static void display_channel_migrate(RedChannelClient *rcc)
{
DisplayChannel *display = DISPLAY_CHANNEL(red_channel_client_get_channel(rcc));
red_migrate_display(display, rcc);

View File

@ -159,11 +159,6 @@ void display_channel_reset_image_cache(DisplayChannel *self);
void display_channel_debug_oom(DisplayChannel *display, const char *msg);
void display_channel_update_qxl_running(DisplayChannel *display, bool running);
void display_channel_connect(RedChannel *channel, RedClient *client,
RedStream *stream, int migration,
RedChannelCapabilities *caps);
void display_channel_disconnect(RedChannelClient *rcc);
void display_channel_migrate(RedChannelClient *rcc);
G_END_DECLS

View File

@ -542,17 +542,12 @@ InputsChannel* inputs_channel_new(RedsState *reds)
static void
inputs_channel_constructed(GObject *object)
{
ClientCbs client_cbs = { NULL, };
InputsChannel *self = INPUTS_CHANNEL(object);
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
SpiceCoreInterfaceInternal *core = red_channel_get_core_interface(RED_CHANNEL(self));
G_OBJECT_CLASS(inputs_channel_parent_class)->constructed(object);
client_cbs.connect = inputs_connect;
client_cbs.migrate = inputs_migrate;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
red_channel_set_cap(RED_CHANNEL(self), SPICE_INPUTS_CAP_KEY_SCANCODE);
reds_register_channel(reds, RED_CHANNEL(self));
@ -596,6 +591,10 @@ inputs_channel_class_init(InputsChannelClass *klass)
channel_class->send_item = inputs_channel_send_item;
channel_class->handle_migrate_data = inputs_channel_handle_migrate_data;
channel_class->handle_migrate_flush_mark = inputs_channel_handle_migrate_flush_mark;
// client callbacks
channel_class->connect = inputs_connect;
channel_class->migrate = inputs_migrate;
}
static SpiceKbdInstance* inputs_channel_get_keyboard(InputsChannel *inputs)

View File

@ -264,15 +264,11 @@ static void
main_channel_constructed(GObject *object)
{
MainChannel *self = MAIN_CHANNEL(object);
ClientCbs client_cbs = { NULL, };
G_OBJECT_CLASS(main_channel_parent_class)->constructed(object);
red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
red_channel_set_cap(RED_CHANNEL(self), SPICE_MAIN_CAP_SEAMLESS_MIGRATE);
client_cbs.migrate = main_channel_client_migrate;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
}
static void
@ -295,6 +291,9 @@ main_channel_class_init(MainChannelClass *klass)
channel_class->send_item = main_channel_client_send_item;
channel_class->handle_migrate_flush_mark = main_channel_handle_migrate_flush_mark;
channel_class->handle_migrate_data = main_channel_handle_migrate_data;
// client callbacks
channel_class->migrate = main_channel_client_migrate;
}
static int main_channel_connect_semi_seamless(MainChannel *main_channel)

View File

@ -86,7 +86,6 @@ struct RedChannelPrivate
RedChannelCapabilities local_caps;
uint32_t migration_flags;
ClientCbs client_cbs;
// TODO: when different channel_clients are in different threads
// from Channel -> need to protect!
pthread_t thread_id;
@ -302,6 +301,10 @@ red_channel_class_init(RedChannelClass *klass)
| G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property(object_class, PROP_DISPATCHER, spec);
klass->connect = red_channel_client_default_connect;
klass->disconnect = red_channel_client_default_disconnect;
klass->migrate = red_channel_client_default_migrate;
}
static void
@ -311,10 +314,6 @@ red_channel_init(RedChannel *self)
red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER);
self->priv->thread_id = pthread_self();
self->priv->client_cbs.connect = red_channel_client_default_connect;
self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
self->priv->client_cbs.migrate = red_channel_client_default_migrate;
}
// utility to avoid possible invalid function cast
@ -380,20 +379,6 @@ const RedStatNode *red_channel_get_stat_node(RedChannel *channel)
return &channel->priv->stat;
}
void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs)
{
spice_assert(client_cbs->connect || channel->priv->type == SPICE_CHANNEL_MAIN);
channel->priv->client_cbs.connect = client_cbs->connect;
if (client_cbs->disconnect) {
channel->priv->client_cbs.disconnect = client_cbs->disconnect;
}
if (client_cbs->migrate) {
channel->priv->client_cbs.migrate = client_cbs->migrate;
}
}
static void add_capability(uint32_t **caps, int *num_caps, uint32_t cap)
{
int nbefore, n;
@ -518,9 +503,9 @@ static void handle_dispatcher_connect(void *opaque, void *payload)
{
RedMessageConnect *msg = payload;
RedChannel *channel = msg->channel;
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
channel->priv->client_cbs.connect(channel, msg->client, msg->stream,
msg->migration, &msg->caps);
klass->connect(channel, msg->client, msg->stream, msg->migration, &msg->caps);
g_object_unref(msg->client);
red_channel_capabilities_reset(&msg->caps);
}
@ -531,7 +516,8 @@ void red_channel_connect(RedChannel *channel, RedClient *client,
{
if (channel->priv->dispatcher == NULL ||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
channel->priv->client_cbs.connect(channel, client, stream, migration, caps);
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
klass->connect(channel, client, stream, migration, caps);
return;
}
@ -759,8 +745,9 @@ static void handle_dispatcher_migrate(void *opaque, void *payload)
{
RedMessageMigrate *msg = payload;
RedChannel *channel = red_channel_client_get_channel(msg->rcc);
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
channel->priv->client_cbs.migrate(msg->rcc);
klass->migrate(msg->rcc);
g_object_unref(msg->rcc);
}
@ -768,7 +755,8 @@ void red_channel_migrate_client(RedChannel *channel, RedChannelClient *rcc)
{
if (channel->priv->dispatcher == NULL ||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
channel->priv->client_cbs.migrate(rcc);
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
klass->migrate(rcc);
return;
}
@ -785,15 +773,17 @@ static void handle_dispatcher_disconnect(void *opaque, void *payload)
{
RedMessageDisconnect *msg = payload;
RedChannel *channel = red_channel_client_get_channel(msg->rcc);
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
channel->priv->client_cbs.disconnect(msg->rcc);
klass->disconnect(msg->rcc);
}
void red_channel_disconnect_client(RedChannel *channel, RedChannelClient *rcc)
{
if (channel->priv->dispatcher == NULL ||
pthread_equal(pthread_self(), channel->priv->thread_id)) {
channel->priv->client_cbs.disconnect(rcc);
RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
klass->disconnect(rcc);
return;
}

View File

@ -63,16 +63,6 @@ typedef void (*channel_client_disconnect_proc)(RedChannelClient *base);
typedef void (*channel_client_migrate_proc)(RedChannelClient *base);
/*
* callbacks that are triggered from client events.
* They should be called from the thread that handles the RedClient
*/
typedef struct {
channel_client_connect_proc connect;
channel_client_disconnect_proc disconnect;
channel_client_migrate_proc migrate;
} ClientCbs;
static inline gboolean test_capability(const uint32_t *caps, int num_caps, uint32_t cap)
{
return VD_AGENT_HAS_CAPABILITY(caps, num_caps, cap);
@ -107,6 +97,14 @@ struct RedChannelClass
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 handle_migrate_data_get_serial;
/*
* callbacks that are triggered from client events.
* They should be called from the thread that handles the RedClient
*/
channel_client_connect_proc connect;
channel_client_disconnect_proc disconnect;
channel_client_migrate_proc migrate;
};
#define FOREACH_CLIENT(_channel, _data) \
@ -122,7 +120,6 @@ void red_channel_remove_client(RedChannel *channel, RedChannelClient *rcc);
void red_channel_init_stat_node(RedChannel *channel, const RedStatNode *parent, const char *name);
void red_channel_register_client_cbs(RedChannel *channel, const ClientCbs *client_cbs);
// caps are freed when the channel is destroyed
void red_channel_set_common_cap(RedChannel *channel, uint32_t cap);
void red_channel_set_cap(RedChannel *channel, uint32_t cap);

View File

@ -695,12 +695,7 @@ stream_device_create_channel(StreamDevice *dev)
g_return_if_fail(id >= 0);
StreamChannel *stream_channel = stream_channel_new(reds, id);
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;
red_channel_register_client_cbs(RED_CHANNEL(cursor_channel), &client_cbs);
dev->stream_channel = stream_channel;
dev->cursor_channel = cursor_channel;

View File

@ -1144,12 +1144,6 @@ RedWorker* red_worker_new(QXLInstance *qxl)
channel = RED_CHANNEL(worker->cursor_channel);
red_channel_init_stat_node(channel, &worker->stat, "cursor_channel");
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, dispatcher,
FALSE,
@ -1159,12 +1153,6 @@ RedWorker* red_worker_new(QXLInstance *qxl)
channel = RED_CHANNEL(worker->display_channel);
red_channel_init_stat_node(channel, &worker->stat, "display_channel");
ClientCbs client_display_cbs = { NULL, };
client_display_cbs.connect = display_channel_connect;
client_display_cbs.disconnect = display_channel_disconnect;
client_display_cbs.migrate = display_channel_migrate;
red_channel_register_client_cbs(channel, &client_display_cbs);
return worker;
}

View File

@ -535,13 +535,9 @@ red_smartcard_channel_constructed(GObject *object)
{
RedSmartcardChannel *self = RED_SMARTCARD_CHANNEL(object);
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
ClientCbs client_cbs = { NULL, };
G_OBJECT_CLASS(red_smartcard_channel_parent_class)->constructed(object);
client_cbs.connect = smartcard_connect_client;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
reds_register_channel(reds, RED_CHANNEL(self));
}
@ -559,6 +555,8 @@ red_smartcard_channel_class_init(RedSmartcardChannelClass *klass)
channel_class->handle_migrate_flush_mark = smartcard_channel_client_handle_migrate_flush_mark;
channel_class->handle_migrate_data = smartcard_channel_client_handle_migrate_data;
// client callbacks
channel_class->connect = smartcard_connect_client;
}
static void smartcard_init(RedsState *reds)

View File

@ -1377,16 +1377,11 @@ playback_channel_init(PlaybackChannel *self)
static void
playback_channel_constructed(GObject *object)
{
ClientCbs client_cbs = { NULL, };
SndChannel *self = SND_CHANNEL(object);
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
G_OBJECT_CLASS(playback_channel_parent_class)->constructed(object);
client_cbs.connect = snd_set_playback_peer;
client_cbs.migrate = snd_migrate_channel_client;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY)) {
red_channel_set_cap(RED_CHANNEL(self), SPICE_PLAYBACK_CAP_CELT_0_5_1);
}
@ -1407,6 +1402,10 @@ playback_channel_class_init(PlaybackChannelClass *klass)
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_PLAYBACK, NULL);
channel_class->handle_message = red_channel_client_handle_message;
channel_class->send_item = playback_channel_send_item;
// client callbacks
channel_class->connect = snd_set_playback_peer;
channel_class->migrate = snd_migrate_channel_client;
}
void snd_attach_playback(RedsState *reds, SpicePlaybackInstance *sin)
@ -1427,16 +1426,11 @@ record_channel_init(RecordChannel *self)
static void
record_channel_constructed(GObject *object)
{
ClientCbs client_cbs = { NULL, };
SndChannel *self = SND_CHANNEL(object);
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
G_OBJECT_CLASS(record_channel_parent_class)->constructed(object);
client_cbs.connect = snd_set_record_peer;
client_cbs.migrate = snd_migrate_channel_client;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
if (snd_codec_is_capable(SPICE_AUDIO_DATA_MODE_CELT_0_5_1, SND_CODEC_ANY_FREQUENCY)) {
red_channel_set_cap(RED_CHANNEL(self), SPICE_RECORD_CAP_CELT_0_5_1);
}
@ -1457,6 +1451,10 @@ record_channel_class_init(RecordChannelClass *klass)
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_RECORD, NULL);
channel_class->handle_message = record_channel_handle_message;
channel_class->send_item = record_channel_send_item;
// client callbacks
channel_class->connect = snd_set_record_peer;
channel_class->migrate = snd_migrate_channel_client;
}
void snd_attach_record(RedsState *reds, SpiceRecordInstance *sin)

View File

@ -185,14 +185,10 @@ static void
red_vmc_channel_constructed(GObject *object)
{
RedVmcChannel *self = RED_VMC_CHANNEL(object);
ClientCbs client_cbs = { NULL, };
RedsState *reds = red_channel_get_server(RED_CHANNEL(self));
G_OBJECT_CLASS(red_vmc_channel_parent_class)->constructed(object);
client_cbs.connect = spicevmc_connect;
red_channel_register_client_cbs(RED_CHANNEL(self), &client_cbs);
red_channel_init_stat_node(RED_CHANNEL(self), NULL, "spicevmc");
const RedStatNode *stat = red_channel_get_stat_node(RED_CHANNEL(self));
stat_init_counter(&self->in_data, reds, stat, "in_data", TRUE);
@ -723,6 +719,9 @@ red_vmc_channel_class_init(RedVmcChannelClass *klass)
channel_class->send_item = spicevmc_red_channel_send_item;
channel_class->handle_migrate_flush_mark = spicevmc_channel_client_handle_migrate_flush_mark;
channel_class->handle_migrate_data = spicevmc_channel_client_handle_migrate_data;
// client callbacks
channel_class->connect = spicevmc_connect;
}
static void

View File

@ -443,15 +443,11 @@ stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedStream
static void
stream_channel_constructed(GObject *object)
{
ClientCbs client_cbs = { NULL, };
RedChannel *red_channel = RED_CHANNEL(object);
RedsState *reds = red_channel_get_server(red_channel);
G_OBJECT_CLASS(stream_channel_parent_class)->constructed(object);
client_cbs.connect = stream_channel_connect;
red_channel_register_client_cbs(red_channel, &client_cbs);
red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
@ -470,6 +466,7 @@ stream_channel_class_init(StreamChannelClass *klass)
channel_class->handle_message = handle_message;
channel_class->send_item = stream_channel_send_item;
channel_class->connect = stream_channel_connect;
}
static void

View File

@ -105,25 +105,14 @@ test_connect_client(RedChannel *channel, RedClient *client, RedStream *stream,
}
}
static void
red_test_channel_constructed(GObject *object)
{
G_OBJECT_CLASS(red_test_channel_parent_class)->constructed(object);
ClientCbs client_cbs = { .connect = test_connect_client, };
red_channel_register_client_cbs(RED_CHANNEL(object), &client_cbs);
}
static void
red_test_channel_class_init(RedTestChannelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->constructed = red_test_channel_constructed;
RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);
channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_PORT, NULL);
channel_class->handle_message = red_channel_client_handle_message;
channel_class->send_item = test_channel_send_item;
channel_class->connect = test_connect_client;
}
static uint8_t *