On Wed, Jan 22, 2014 at 07:26:50PM +0100, Marc-André Lureau wrote: > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> > > This allows to use conveniently GIOStream APIs without caring about > coroutine and Spice messages details. > --- > gtk/Makefile.am | 2 + > gtk/channel-base.c | 48 +++++ > gtk/channel-port.c | 33 +-- > gtk/spice-channel-priv.h | 8 + > gtk/vmcstream.c | 532 +++++++++++++++++++++++++++++++++++++++++++++++ > gtk/vmcstream.h | 81 ++++++++ > 6 files changed, 674 insertions(+), 30 deletions(-) > create mode 100644 gtk/vmcstream.c > create mode 100644 gtk/vmcstream.h > > diff --git a/gtk/Makefile.am b/gtk/Makefile.am > index 62afd36..7ceb22f 100644 > --- a/gtk/Makefile.am > +++ b/gtk/Makefile.am > @@ -255,6 +255,8 @@ libspice_client_glib_2_0_la_SOURCES = \ > usbutil.c \ > usbutil.h \ > $(USB_ACL_HELPER_SRCS) \ > + vmcstream.c \ > + vmcstream.h \ > \ > decode.h \ > decode-glz.c \ > diff --git a/gtk/channel-base.c b/gtk/channel-base.c > index 646042d..363dda5 100644 > --- a/gtk/channel-base.c > +++ b/gtk/channel-base.c > @@ -232,3 +232,51 @@ void spice_channel_set_handlers(SpiceChannelClass *klass, > spice_channel_add_base_handlers(klass); > set_handlers(klass, handlers, n); > } > + > +static void > +vmc_write_free_cb(uint8_t *data, void *user_data) > +{ > + GSimpleAsyncResult *result = user_data; > + > + g_simple_async_result_complete_in_idle(result); > + g_object_unref(result); > +} > + > +G_GNUC_INTERNAL > +void spice_vmc_write_async(SpiceChannel *self, > + const void *buffer, gsize count, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceMsgOut *msg; > + GSimpleAsyncResult *simple; > + > + simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > + spice_port_write_async); > + g_simple_async_result_set_op_res_gssize(simple, count); > + > + msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA); > + spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count, > + vmc_write_free_cb, simple); > + spice_msg_out_send(msg); > +} > + > +G_GNUC_INTERNAL > +gssize spice_vmc_write_finish(SpiceChannel *self, > + GAsyncResult *result, GError **error) > +{ > + GSimpleAsyncResult *simple; > + > + g_return_val_if_fail(result != NULL, -1); > + > + simple = (GSimpleAsyncResult *)result; > + > + if (g_simple_async_result_propagate_error(simple, error)) > + return -1; > + > + g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self), > + spice_port_write_async), -1); > + > + return g_simple_async_result_get_op_res_gssize(simple); > +} I think Hans asked you to split these helpers in a separate commit in his review. > diff --git a/gtk/channel-port.c b/gtk/channel-port.c > index 0a8b37f..5512713 100644 > --- a/gtk/channel-port.c > +++ b/gtk/channel-port.c > @@ -289,14 +289,6 @@ static void port_handle_msg(SpiceChannel *channel, SpiceMsgIn *in) > emit_main_context(channel, SPICE_PORT_DATA, buf, size); > } > > -static void port_write_free_cb(uint8_t *data, void *user_data) > -{ > - GSimpleAsyncResult *result = user_data; > - > - g_simple_async_result_complete(result); > - g_object_unref(result); > -} > - > /** > * spice_port_write_async: > * @port: A #SpicePortChannel > @@ -320,9 +312,7 @@ void spice_port_write_async(SpicePortChannel *self, > GAsyncReadyCallback callback, > gpointer user_data) > { > - GSimpleAsyncResult *simple; > SpicePortChannelPrivate *c; > - SpiceMsgOut *msg; > > g_return_if_fail(SPICE_IS_PORT_CHANNEL(self)); > g_return_if_fail(buffer != NULL); > @@ -335,14 +325,8 @@ void spice_port_write_async(SpicePortChannel *self, > return; > } > > - simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > - spice_port_write_async); > - g_simple_async_result_set_op_res_gssize(simple, count); > - > - msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA); > - spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count, > - port_write_free_cb, simple); > - spice_msg_out_send(msg); > + spice_vmc_write_async(SPICE_CHANNEL(self), buffer, count, > + cancellable, callback, user_data); > } > > /** > @@ -360,20 +344,9 @@ void spice_port_write_async(SpicePortChannel *self, > gssize spice_port_write_finish(SpicePortChannel *self, > GAsyncResult *result, GError **error) > { > - GSimpleAsyncResult *simple; > - > g_return_val_if_fail(SPICE_IS_PORT_CHANNEL(self), -1); > - g_return_val_if_fail(result != NULL, -1); > - > - simple = (GSimpleAsyncResult *)result; > - > - if (g_simple_async_result_propagate_error(simple, error)) > - return -1; > - > - g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self), > - spice_port_write_async), -1); > > - return g_simple_async_result_get_op_res_gssize(simple); > + return spice_vmc_write_finish(SPICE_CHANNEL(self), result, error); > } > > /** > diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h > index 0816061..35704ea 100644 > --- a/gtk/spice-channel-priv.h > +++ b/gtk/spice-channel-priv.h > @@ -196,6 +196,14 @@ void spice_caps_set(GArray *caps, guint32 cap, const gchar *desc); > > gchar *spice_channel_supported_string(void); > > +void spice_vmc_write_async(SpiceChannel *self, > + const void *buffer, gsize count, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > +gssize spice_vmc_write_finish(SpiceChannel *self, > + GAsyncResult *result, GError **error); > + > G_END_DECLS > > #endif /* __SPICE_CLIENT_CHANNEL_PRIV_H__ */ > diff --git a/gtk/vmcstream.c b/gtk/vmcstream.c > new file mode 100644 > index 0000000..724ee58 > --- /dev/null > +++ b/gtk/vmcstream.c > @@ -0,0 +1,532 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Red Hat, Inc. 2014 > + > + 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 <string.h> > + > +#include "vmcstream.h" > +#include "spice-channel-priv.h" > +#include "gio-coroutine.h" > + > +struct _SpiceVmcInputStream > +{ > + GInputStream parent_instance; > + GSimpleAsyncResult *result; > + struct coroutine *coroutine; > + > + SpiceChannel *channel; > + gboolean all; > + guint8 *buffer; > + gsize count; > + gsize pos; > + > + GCancellable *cancellable; > + gulong cancel_id; > +}; > + > +struct _SpiceVmcInputStreamClass > +{ > + GInputStreamClass parent_class; > +}; > + > +static gssize spice_vmc_input_stream_read (GInputStream *stream, > + void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error); Tabs here, probably better to get rid of them for consistency. > +static void spice_vmc_input_stream_read_async (GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > +static gssize spice_vmc_input_stream_read_finish (GInputStream *stream, > + GAsyncResult *result, > + GError **error); > +static gssize spice_vmc_input_stream_skip (GInputStream *stream, > + gsize count, > + GCancellable *cancellable, > + GError **error); > +static gboolean spice_vmc_input_stream_close (GInputStream *stream, > + GCancellable *cancellable, > + GError **error); > +static void spice_vmc_input_stream_finalize (GObject *object); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcInputStream, spice_vmc_input_stream, G_TYPE_INPUT_STREAM,) G_DEFINE_TYPE() to get rid of the trailing comma? > + > + > +static void > +spice_vmc_input_stream_class_init(SpiceVmcInputStreamClass *klass) > +{ > + GObjectClass *object_class; > + GInputStreamClass *istream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_input_stream_finalize; > + > + istream_class = G_INPUT_STREAM_CLASS(klass); > + istream_class->read_fn = spice_vmc_input_stream_read; > + istream_class->read_async = spice_vmc_input_stream_read_async; > + istream_class->read_finish = spice_vmc_input_stream_read_finish; > + istream_class->skip = spice_vmc_input_stream_skip; > + istream_class->close_fn = spice_vmc_input_stream_close; > +} > + > +static void > +spice_vmc_input_stream_finalize(GObject *object) > +{ > + G_OBJECT_CLASS (spice_vmc_input_stream_parent_class)->finalize(object); > +} Not strictly needed > + > +static void > +spice_vmc_input_stream_init(SpiceVmcInputStream *self) > +{ > +} > + > +static SpiceVmcInputStream * > +spice_vmc_input_stream_new(void) > +{ > + SpiceVmcInputStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_INPUT_STREAM, NULL); > + > + return self; > +} > + > +/* coroutine */ > +G_GNUC_INTERNAL void > +spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, > + const gpointer d, gsize size) This function is not used in this patch, is unusual in a stream implementation, ... it's probably better to add it with the webdav patch or in a separate commit, and to have a comment explaining what it is. > +{ > + guint8 *data = d; > + > + g_return_if_fail(SPICE_IS_VMC_INPUT_STREAM(self)); > + g_return_if_fail(self->coroutine == NULL); > + > + self->coroutine = coroutine_self(); > + > + while (size > 0) { > + SPICE_DEBUG("webdav co_data %p", self->result); s/webdav/spicevmc > + if (!self->result) > + coroutine_yield(NULL); > + > + g_return_if_fail(self->result != NULL); > + > + gsize min = MIN(self->count, size); > + memcpy(self->buffer, data, min); > + > + size -= min; > + data += min; > + > + SPICE_DEBUG("webdav co_data complete: %" G_GSIZE_FORMAT s/webdav/spicevmc > + "/%" G_GSIZE_FORMAT, min, self->count); > + > + self->pos += min; > + self->buffer += min; > + > + if (self->all && min > 0 && self->pos != self->count) > + continue; > + > + g_simple_async_result_set_op_res_gssize(self->result, self->pos); > + g_simple_async_result_complete_in_idle(self->result); > + g_clear_object(&self->result); > + } > + > + self->coroutine = NULL; > +} > + > +static void > +read_cancelled(GCancellable *cancellable, > + gpointer user_data) > +{ > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(user_data); > + > + SPICE_DEBUG("read cancelled, %p", self->result); > + g_simple_async_result_set_error(self->result, > + G_IO_ERROR, G_IO_ERROR_CANCELLED, > + "read cancelled"); > + g_simple_async_result_complete_in_idle(self->result); > + g_clear_object(&self->result); > +} > + > +void > +spice_vmc_input_stream_read_all_async(GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + GSimpleAsyncResult *result; > + > + /* no concurrent read permitted by ginputstream */ > + g_return_if_fail(self->result == NULL); > + g_return_if_fail(self->cancellable == NULL); Isn't it what g_input_stream_set_pending() is meant for? > + self->all = TRUE; > + self->buffer = buffer; > + self->count = count; > + self->pos = 0; > + result = g_simple_async_result_new(G_OBJECT(self), > + callback, > + user_data, > + spice_vmc_input_stream_read_async); I think it's missing g_simple_async_result_set_op_res_gssize(self->result, count); > + self->result = result; Calling _finish() is not supposed to be mandatory after calling an _async() function. Things will not work quite well here if _finish() is not called, it would be nice to at least document it. > + self->cancellable = g_object_ref(cancellable); > + if (cancellable) > + self->cancel_id = > + g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL); > + > + if (self->coroutine) > + coroutine_yieldto(self->coroutine, NULL); > +} > + > +gssize > +spice_vmc_input_stream_read_all_finish(GInputStream *stream, > + GAsyncResult *result, > + GError **error) > +{ > + GSimpleAsyncResult *simple; > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + > + g_return_val_if_fail(g_simple_async_result_is_valid(result, > + G_OBJECT(self), > + spice_vmc_input_stream_read_async), > + -1); > + > + if (self->cancellable) { > + g_cancellable_disconnect(self->cancellable, self->cancel_id); > + g_clear_object(&self->cancellable); > + } > + > + simple = (GSimpleAsyncResult *)result; > + > + if (g_simple_async_result_propagate_error(simple, error)) > + return -1; > + > + return g_simple_async_result_get_op_res_gssize(simple); > +} > + > +static void > +spice_vmc_input_stream_read_async(GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + GSimpleAsyncResult *result; > + > + /* no concurrent read permitted by ginputstream */ > + g_return_if_fail(self->result == NULL); > + g_return_if_fail(self->cancellable == NULL); > + self->all = FALSE; > + self->buffer = buffer; > + self->count = count; > + self->pos = 0; > + result = g_simple_async_result_new(G_OBJECT(self), > + callback, > + user_data, > + spice_vmc_input_stream_read_async); > + self->result = result; > + self->cancellable = g_object_ref(cancellable); > + if (cancellable) > + self->cancel_id = > + g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL); > + > + if (self->coroutine) > + coroutine_yieldto(self->coroutine, NULL); Also missing a call to g_simple_async_result_set_op_res_gssize(self->result, count); > +} > + > +static gssize > +spice_vmc_input_stream_read_finish(GInputStream *stream, > + GAsyncResult *result, > + GError **error) > +{ > + GSimpleAsyncResult *simple; > + SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > + > + g_return_val_if_fail(g_simple_async_result_is_valid(result, > + G_OBJECT(self), > + spice_vmc_input_stream_read_async), > + -1); > + > + if (self->cancellable) { > + g_cancellable_disconnect(self->cancellable, self->cancel_id); > + g_clear_object(&self->cancellable); > + } > + > + simple = (GSimpleAsyncResult *)result; > + > + if (g_simple_async_result_propagate_error(simple, error)) > + return -1; > + > + return g_simple_async_result_get_op_res_gssize(simple); > +} > + > +static gssize > +spice_vmc_input_stream_read(GInputStream *stream, > + void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + g_return_val_if_reached(-1); > +} > + > +static gssize > +spice_vmc_input_stream_skip(GInputStream *stream, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + g_return_val_if_reached(-1); > +} > + > +static gboolean > +spice_vmc_input_stream_close(GInputStream *stream, > + GCancellable *cancellable, > + GError **error) > +{ > + SPICE_DEBUG("fake close"); > + return TRUE; > +} > + > +/* OUTPUT */ > + > +struct _SpiceVmcOutputStream > +{ > + GOutputStream parent_instance; > + > + SpiceChannel *channel; /* weak */ > +}; > + > +struct _SpiceVmcOutputStreamClass > +{ > + GOutputStreamClass parent_class; > +}; > + > +static void spice_vmc_output_stream_finalize (GObject *object); > +static gssize spice_vmc_output_stream_write_fn (GOutputStream *stream, > + const void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error); > +static gssize spice_vmc_output_stream_write_finish (GOutputStream *stream, > + GAsyncResult *result, > + GError **error); > +static void spice_vmc_output_stream_write_async (GOutputStream *stream, > + const void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcOutputStream, spice_vmc_output_stream, G_TYPE_OUTPUT_STREAM,) G_DEFINE_TYPE ? > + > + > +static void > +spice_vmc_output_stream_class_init(SpiceVmcOutputStreamClass *klass) > +{ > + GObjectClass *object_class; > + GOutputStreamClass *ostream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_output_stream_finalize; > + > + ostream_class = G_OUTPUT_STREAM_CLASS(klass); > + ostream_class->write_fn = spice_vmc_output_stream_write_fn; > + ostream_class->write_async = spice_vmc_output_stream_write_async; > + ostream_class->write_finish = spice_vmc_output_stream_write_finish; > +} > + > +static void > +spice_vmc_output_stream_finalize(GObject *object) > +{ > + G_OBJECT_CLASS(spice_vmc_output_stream_parent_class)->finalize(object); > +} Not needed. > + > +static void > +spice_vmc_output_stream_init(SpiceVmcOutputStream *self) > +{ > +} > + > +static SpiceVmcOutputStream * > +spice_vmc_output_stream_new(SpiceChannel *channel) > +{ > + SpiceVmcOutputStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_OUTPUT_STREAM, NULL); > + self->channel = channel; > + > + return self; > +} > + > +static gssize > +spice_vmc_output_stream_write_fn(GOutputStream *stream, > + const void *buffer, > + gsize count, > + GCancellable *cancellable, > + GError **error) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + SpiceMsgOut *msg_out; > + > + msg_out = spice_msg_out_new(SPICE_CHANNEL(self->channel), > + SPICE_MSGC_SPICEVMC_DATA); > + spice_marshaller_add(msg_out->marshaller, buffer, count); > + spice_msg_out_send(msg_out); > + > + return count; > +} > + > +static gssize > +spice_vmc_output_stream_write_finish(GOutputStream *stream, > + GAsyncResult *simple, > + GError **error) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + GSimpleAsyncResult *res = > + g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(simple)); > + > + SPICE_DEBUG("webdav write finish"); s/webdav/spicevmc > + return spice_vmc_write_finish(self->channel, G_ASYNC_RESULT(res), error); > +} > + > +static void > +write_cb(GObject *source_object, > + GAsyncResult *res, > + gpointer user_data) > +{ > + GSimpleAsyncResult *simple = user_data; > + > + g_simple_async_result_set_op_res_gpointer(simple, res, NULL); > + > + g_simple_async_result_complete(simple); > + g_object_unref(simple); > +} > + > +static void > +spice_vmc_output_stream_write_async(GOutputStream *stream, > + const void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data) > +{ > + SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream); > + GSimpleAsyncResult *simple; > + > + SPICE_DEBUG("webdav write async"); s/webdav/spicevmc > + /* an AsyncResult to forward async op to channel */ > + simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > + spice_vmc_output_stream_write_async); > + > + spice_vmc_write_async(self->channel, buffer, count, > + cancellable, write_cb, > + simple); > +} > + > +/* STREAM */ > + > +struct _SpiceVmcStream > +{ > + GIOStream parent_instance; > + > + SpiceChannel *channel; /* weak */ > + SpiceVmcInputStream *in; > + SpiceVmcOutputStream *out; > +}; > + > +struct _SpiceVmcStreamClass > +{ > + GIOStreamClass parent_class; > +}; > + > +static void spice_vmc_stream_finalize (GObject *object); > +static GInputStream * spice_vmc_stream_get_input_stream (GIOStream *stream); > +static GOutputStream * spice_vmc_stream_get_output_stream (GIOStream *stream); > + > +G_DEFINE_TYPE_WITH_CODE(SpiceVmcStream, spice_vmc_stream, G_TYPE_IO_STREAM,) > + > +static void > +spice_vmc_stream_class_init(SpiceVmcStreamClass *klass) > +{ > + GObjectClass *object_class; > + GIOStreamClass *iostream_class; > + > + object_class = G_OBJECT_CLASS(klass); > + object_class->finalize = spice_vmc_stream_finalize; > + > + iostream_class = G_IO_STREAM_CLASS(klass); > + iostream_class->get_input_stream = spice_vmc_stream_get_input_stream; > + iostream_class->get_output_stream = spice_vmc_stream_get_output_stream; > +} > + > +static void > +spice_vmc_stream_finalize(GObject *object) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(object); > + > + g_clear_object(&self->in); > + g_clear_object(&self->out); > + > + G_OBJECT_CLASS(spice_vmc_stream_parent_class)->finalize(object); > +} > + > +static void > +spice_vmc_stream_init(SpiceVmcStream *self) > +{ > +} > + > +SpiceVmcStream * > +spice_vmc_stream_new(SpiceChannel *channel) > +{ > + SpiceVmcStream *self; > + > + self = g_object_new(SPICE_TYPE_VMC_STREAM, NULL); > + self->channel = channel; Can't we create the output/input channels here to save the need for SpiceVmcStream::channel? > + > + return self; > +} > + > +static GInputStream * > +spice_vmc_stream_get_input_stream(GIOStream *stream) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(stream); > + > + if (!self->in) > + self->in = spice_vmc_input_stream_new(); > + > + return G_INPUT_STREAM(self->in); > +} > + > +static GOutputStream * > +spice_vmc_stream_get_output_stream(GIOStream *stream) > +{ > + SpiceVmcStream *self = SPICE_VMC_STREAM(stream); > + > + if (!self->out) > + self->out = spice_vmc_output_stream_new(self->channel); > + > + return G_OUTPUT_STREAM(self->out); > +} > diff --git a/gtk/vmcstream.h b/gtk/vmcstream.h > new file mode 100644 > index 0000000..1316b77 > --- /dev/null > +++ b/gtk/vmcstream.h > @@ -0,0 +1,81 @@ > +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ > +/* > + Copyright (C) 2013 Red Hat, Inc. 2014 > + > + This library is free software; you can redistribute it and/or > + modify it under the terms of the GNU Lesser General Public > + License as published by the Free Software Foundation; either > + version 2.1 of the License, or (at your option) any later version. > + > + This library is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + Lesser General Public License for more details. > + > + You should have received a copy of the GNU Lesser General Public > + License along with this library; if not, see <http://www.gnu.org/licenses/>. > +*/ > +#ifndef __SPICE_VMC_STREAM_H__ > +#define __SPICE_VMC_STREAM_H__ > + > +#include <gio/gio.h> > + > +#include "spice-types.h" > + > +G_BEGIN_DECLS > + > +#define SPICE_TYPE_VMC_INPUT_STREAM (spice_vmc_input_stream_get_type ()) > +#define SPICE_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStream)) > +#define SPICE_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass)) > +#define SPICE_IS_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_INPUT_STREAM)) > +#define SPICE_IS_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_INPUT_STREAM)) > +#define SPICE_VMC_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass)) > + > +typedef struct _SpiceVmcInputStreamClass SpiceVmcInputStreamClass; > +typedef struct _SpiceVmcInputStream SpiceVmcInputStream; > + > +GType spice_vmc_input_stream_get_type (void) G_GNUC_CONST; > +void spice_vmc_input_stream_co_data (SpiceVmcInputStream *input, > + const gpointer data, > + gsize size); > + > +void spice_vmc_input_stream_read_all_async(GInputStream *stream, > + void *buffer, > + gsize count, > + int io_priority, > + GCancellable *cancellable, > + GAsyncReadyCallback callback, > + gpointer user_data); > +gssize spice_vmc_input_stream_read_all_finish(GInputStream *stream, > + GAsyncResult *result, > + GError **error); > + > + > +#define SPICE_TYPE_VMC_OUTPUT_STREAM (spice_vmc_output_stream_get_type ()) > +#define SPICE_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStream)) > +#define SPICE_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass)) > +#define SPICE_IS_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_OUTPUT_STREAM)) > +#define SPICE_IS_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_OUTPUT_STREAM)) > +#define SPICE_VMC_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass)) > + > +typedef struct _SpiceVmcOutputStreamClass SpiceVmcOutputStreamClass; > +typedef struct _SpiceVmcOutputStream SpiceVmcOutputStream; > + > +GType spice_vmc_output_stream_get_type (void) G_GNUC_CONST; > + > +#define SPICE_TYPE_VMC_STREAM (spice_vmc_stream_get_type ()) > +#define SPICE_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStream)) > +#define SPICE_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass)) > +#define SPICE_IS_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_STREAM)) > +#define SPICE_IS_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_STREAM)) > +#define SPICE_VMC_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass)) > + > +typedef struct _SpiceVmcStreamClass SpiceVmcStreamClass; > +typedef struct _SpiceVmcStream SpiceVmcStream; > + > +GType spice_vmc_stream_get_type (void) G_GNUC_CONST; > +SpiceVmcStream* spice_vmc_stream_new (SpiceChannel *channel); > + > +G_END_DECLS > + > +#endif /* __SPICE_VMC_STREAM_H__ */ > -- > 1.8.4.2 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel
Attachment:
pgpg7afS7ZSPM.pgp
Description: PGP signature
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel