From 14403117b5ed4cb9d6dec1dda0cd2c1bbd0ad348 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Wed, 20 Mar 2019 09:28:34 +0000 Subject: [PATCH] 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 Acked-by: Frediano Ziglio --- server/cursor-channel-client.h | 6 +++++ server/cursor-channel.c | 13 ++++++++--- server/cursor-channel.h | 15 ------------ server/display-channel.c | 17 +++++++++++--- server/display-channel.h | 5 ---- server/inputs-channel.c | 9 ++++---- server/main-channel.c | 7 +++--- server/red-channel.c | 42 +++++++++++++--------------------- server/red-channel.h | 19 +++++++-------- server/red-stream-device.c | 5 ---- server/red-worker.c | 12 ---------- server/smartcard.c | 6 ++--- server/sound.c | 18 +++++++-------- server/spicevmc.c | 7 +++--- server/stream-channel.c | 5 +--- server/tests/test-channel.c | 13 +---------- 16 files changed, 76 insertions(+), 123 deletions(-) diff --git a/server/cursor-channel-client.h b/server/cursor-channel-client.h index 56b3b312..4deae535 100644 --- a/server/cursor-channel-client.h +++ b/server/cursor-channel-client.h @@ -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_ */ diff --git a/server/cursor-channel.c b/server/cursor-channel.c index e8af01b0..d936b791 100644 --- a/server/cursor-channel.c +++ b/server/cursor-channel.c @@ -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 diff --git a/server/cursor-channel.h b/server/cursor-channel.h index 332aa987..dc48279a 100644 --- a/server/cursor-channel.h +++ b/server/cursor-channel.h @@ -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_ */ diff --git a/server/display-channel.c b/server/display-channel.c index e9368668..c2129c71 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -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); diff --git a/server/display-channel.h b/server/display-channel.h index 7dfedd75..8dfdf523 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -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 diff --git a/server/inputs-channel.c b/server/inputs-channel.c index a7df62e2..eff5421a 100644 --- a/server/inputs-channel.c +++ b/server/inputs-channel.c @@ -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) diff --git a/server/main-channel.c b/server/main-channel.c index f866fb4a..a48e74be 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -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) diff --git a/server/red-channel.c b/server/red-channel.c index 8d4992fa..121c7e47 100644 --- a/server/red-channel.c +++ b/server/red-channel.c @@ -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; } diff --git a/server/red-channel.h b/server/red-channel.h index bb3a95e8..4bfd81ee 100644 --- a/server/red-channel.h +++ b/server/red-channel.h @@ -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); diff --git a/server/red-stream-device.c b/server/red-stream-device.c index cf5a6e9a..b4c32f71 100644 --- a/server/red-stream-device.c +++ b/server/red-stream-device.c @@ -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; diff --git a/server/red-worker.c b/server/red-worker.c index d6b69f29..129f9f93 100644 --- a/server/red-worker.c +++ b/server/red-worker.c @@ -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; } diff --git a/server/smartcard.c b/server/smartcard.c index 9ccfbc6b..e3e746ca 100644 --- a/server/smartcard.c +++ b/server/smartcard.c @@ -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) diff --git a/server/sound.c b/server/sound.c index 44b27dec..167f68c5 100644 --- a/server/sound.c +++ b/server/sound.c @@ -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) diff --git a/server/spicevmc.c b/server/spicevmc.c index 51550c1a..d094166e 100644 --- a/server/spicevmc.c +++ b/server/spicevmc.c @@ -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 diff --git a/server/stream-channel.c b/server/stream-channel.c index c38ee043..ed844d6d 100644 --- a/server/stream-channel.c +++ b/server/stream-channel.c @@ -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 diff --git a/server/tests/test-channel.c b/server/tests/test-channel.c index 1c9148df..9700e31c 100644 --- a/server/tests/test-channel.c +++ b/server/tests/test-channel.c @@ -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 *