Re: [Spice-devel] [PATCH server v2 05/13] red-channel: send marshaller message fd
Maybe it's just me, but I don't really understand the purpose of this patch. Can you give a big-picture explanation? On Thu, 2016-01-14 at 22:01 +0100, Marc-André Lureau wrote: > From: Marc-André Lureau > > Send the fd associated to the last message sent. > > Even if the fd is invalid, the sendfd msg is appended to the protocol, > for 2 reasons: > - trying to send an invalid fd does not have to close the connection (it > would with an invalid fd) > - even if the fd is invalid, the protocol expects an extra byte for the > ancillary data > > Signed-off-by: Marc-André Lureau > --- > server/red-channel.c | 16 > 1 file changed, 16 insertions(+) > > diff --git a/server/red-channel.c b/server/red-channel.c > index 306c87d..b33c91d 100644 > --- a/server/red-channel.c > +++ b/server/red-channel.c > @@ -608,8 +608,24 @@ static inline void > red_channel_client_release_sent_item(RedChannelClient *rcc) > static void red_channel_peer_on_out_msg_done(void *opaque) > { > RedChannelClient *rcc = (RedChannelClient *)opaque; > +int fd = spice_marshaller_get_fd(rcc->send_data.marshaller); > > rcc->send_data.size = 0; > + > +if (fd != -1) { > +if (fcntl(fd, F_GETFD) == -1) { > +close(fd); > +fd = -1; > +} > + > +if (reds_stream_send_msgfd(rcc->stream, fd) < 0) { > +perror("sendfd"); > +red_channel_client_disconnect(rcc); > +return; > +} > +close(fd); > +} > + > red_channel_client_release_sent_item(rcc); > if (rcc->send_data.blocked) { > rcc->send_data.blocked = FALSE; ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH server v2 03/13] tests: make sure all tests are built on default rule
On Fri, 2016-01-15 at 09:08 -0500, Frediano Ziglio wrote: > > > > Hi > > > > - Original Message - > > > > > > > > Hi > > > > > > > > On Fri, Jan 15, 2016 at 11:50 AM, Frediano Ziglio > > > > wrote: > > > > > > > > > > > Subject: [PATCH server v2 03/13] tests: make sure all tests are > > > > > > built > > > > > > on > > > > > > default rule > > > > > > > > > > > > We should have all or none, I don't see the point of having just > > > > > > some > > > > > > of > > > > > > them. > > > > > > > > > > > > > > > > I don't know why but this description (and subject) looks odd to me. > > > > > > > > > > I would put something like (if I understood it): > > > > > > > > > > "Programs listed in noinst_PROGRAMS inherit default rule/settings to > > > > > list > > > > > all > > > > > tests program also in this macro" > > > > > > > > > > > > > I don't mind changing the text, but I really don't understand yours ;) > > > > > > > > > > That means I didn't get the reason of the change. > > > > > > What's a rule for you? > > > > > > output: source > > > do_something_to_generate_output_from_source > > > > > > is a rule > > > > > > TESTS = xxx > > > > > > is a variable (also called macro) > > > > Yes > > > > the default rule being "all", it builds noinst_PROGRAMS but not > > check_PROGRAMS. I prefer either build all with noinst_PROGRAMS or none (in > > which case we should remove some of them duplicated in check_PROGRAMS) > > > > Really didn't get it before :) > Can you post again with an updated comment? > > Frediano I didn't fully understand the original comment either (nor did I really understand Frediano's suggested alternative ;). I think that even a simple re-wording would make it a little more clear: "Make sure that the default rule builds all tests." > > > > > > > > > > Signed-off-by: Marc-André Lureau > > > > > > --- > > > > > > server/tests/Makefile.am | 15 +++ > > > > > > 1 file changed, 7 insertions(+), 8 deletions(-) > > > > > > > > > > > > diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am > > > > > > index 15196f9..007930c 100644 > > > > > > --- a/server/tests/Makefile.am > > > > > > +++ b/server/tests/Makefile.am > > > > > > @@ -35,6 +35,12 @@ LDADD = > > > > > > \ > > > > > > $(SPICE_NONPKGCONFIG_LIBS) \ > > > > > > $(NULL) > > > > > > > > > > > > +TESTS = \ > > > > > > + stat_test \ > > > > > > + stream-test \ > > > > > > + test-qxl-parsing\ > > > > > > + $(NULL) > > > > > > + > > > > > > > > > > Why did you moved above? This just make the patch bigger. > > > > > > > > > > > > > It's saner/simpler to define before use. > > > > > > > > > > Let's say that is more similar to assignment and other languages so > > > it's easier to read by people not very friendly with Makefiles > > > (and honestly I think that many developers does not really like > > > Makefiles). > > > > > > > > > noinst_PROGRAMS =\ > > > > > > test_display_no_ssl \ > > > > > > test_display_streaming \ > > > > > > @@ -47,14 +53,7 @@ noinst_PROGRAMS = \ > > > > > > test_vdagent\ > > > > > > test_display_width_stride \ > > > > > > spice-server-replay \ > > > > > > - stream-test \ > > > > > > - stat_test \ > > > > > > - $(NULL) > > > > > > - > > > > > > -TESTS = \ > > > > > > - stat_test \ > > > > > > - test-qxl-parsing\ > > > > > > - stream-test \ > > > > > > + $(TESTS)\ > > > > > > $(NULL) > > > > > > > > > > > > check_PROGRAMS = $(TESTS) > > > > > > -- > > > > > > 2.5.0 > > > > > > > > > > > > > > > > > > > > > > Frediano > > > > > > > > > > > > > > > > -- > > > > Marc-André Lureau > > > > > ___ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH server v2 02/13] tests: link test-qxl-parsing with libserver
In general, I appreciate a bit more justification in the commit log so I can quickly understand the "why" in addition to the "what". In this case, I assume it's to reduce build time and avoid compiling these files twice. ACK with a slightly expanded commit log. Acked-by: Jonathon Jongsma On Thu, 2016-01-14 at 22:01 +0100, Marc-André Lureau wrote: > Signed-off-by: Marc-André Lureau > --- > server/tests/Makefile.am | 6 +- > 1 file changed, 1 insertion(+), 5 deletions(-) > > diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am > index 8caff04..15196f9 100644 > --- a/server/tests/Makefile.am > +++ b/server/tests/Makefile.am > @@ -91,8 +91,4 @@ libstat_test3_a_CPPFLAGS = $(AM_CPPFLAGS) > -DTEST_COMPRESS_STAT=1 -DTEST_RED_WORK > libstat_test4_a_SOURCES = stat-test.c > libstat_test4_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_COMPRESS_STAT=1 > -DTEST_RED_WORKER_STAT=1 -DTEST_NAME=stat_test4 > > -test_qxl_parsing_SOURCES = \ > - test-qxl-parsing.c \ > - ../red-parse-qxl.c \ > - ../memslot.c\ > - $(NULL) > +test_qxl_parsing_LDADD = ../libserver.la $(LDADD) ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 15/15] reds_num_of_clients() -> reds_get_n_clients()
On Mon, 2016-01-18 at 16:38 +, Frediano Ziglio wrote: > From: Jonathon Jongsma > > More consistent with glib naming conventions. Also make the function > static since it's not used outside of this source file. I don't know if this patch has changed slightly due to rebase, but the function appears to already be static. So we can remove this last sentence from the commit log. > --- > server/reds.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/server/reds.c b/server/reds.c > index 4de1640..22ab26d 100644 > --- a/server/reds.c > +++ b/server/reds.c > @@ -897,7 +897,7 @@ int reds_get_n_channels(RedsState *reds) > } > > > -static int reds_num_of_clients(RedsState *reds) > +static int reds_get_n_clients(RedsState *reds) > { > return reds ? reds->num_clients : 0; > } > @@ -905,7 +905,7 @@ static int reds_num_of_clients(RedsState *reds) > SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *s) > { > spice_assert(reds == s); > -return reds_num_of_clients(reds); > +return reds_get_n_clients(reds); > } > > static int secondary_channels[] = { ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 14/14] Add strings for translation
On Mon, 2016-01-18 at 10:05 +0100, Fabiano Fidêncio wrote: > While doing the work to use GTask isntead of GSimpleAsyncResult I've > noticed a few error strings that were not marked to be translated. > I am not exactly sure if it was intentional or not, but I do believe > that our error messages should be translated. > --- > po/POTFILES.in | 6 ++ > src/channel-main.c | 4 +++- > src/channel-port.c | 4 +++- > src/channel-usbredir.c | 4 ++-- > src/spice-channel.c | 2 +- > src/spice-pulse.c| 8 +--- > src/usb-acl-helper.c | 10 ++ > src/usb-device-manager.c | 4 ++-- > src/vmcstream.c | 4 +++- > src/win-usb-driver-install.c | 16 +--- > 10 files changed, 40 insertions(+), 22 deletions(-) > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index ad12609..7c79541 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -1,8 +1,14 @@ > +src/channel-main.c > +src/channel-port.c > src/channel-usbredir.c > src/desktop-integration.c > src/spice-channel.c > src/spice-cmdline.c > src/spice-option.c > +src/spice-pulse.c > +src/usb-acl-helper.c > src/usb-device-manager.c > src/usb-device-widget.c > src/usbutil.c > +src/vmcstream.c > +src/win-usb-driver-install.c > diff --git a/src/channel-main.c b/src/channel-main.c > index 6c0f238..40d5cff 100644 > --- a/src/channel-main.c > +++ b/src/channel-main.c > @@ -21,6 +21,8 @@ > #include > #include > > +#include > + > #include "glib-compat.h" > #include "spice-client.h" > #include "spice-common.h" > @@ -3143,7 +3145,7 @@ void spice_main_file_copy_async(SpiceMainChannel > *channel, > spice_main_file_copy_async, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"The agent is not connected"); > +_("The agent is not connected")); > return; > } > > diff --git a/src/channel-port.c b/src/channel-port.c > index 20ee2fa..86194ab 100644 > --- a/src/channel-port.c > +++ b/src/channel-port.c > @@ -23,6 +23,8 @@ > #include "spice-marshal.h" > #include "glib-compat.h" > > +#include > + > /** > * SECTION:channel-port > * @short_description: private communication channel > @@ -295,7 +297,7 @@ void spice_port_write_async(SpicePortChannel *self, > g_task_report_new_error(self, callback, > user_data, spice_port_write_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The port is not opened"); > +_("The port is not opened")); > return; > } > > diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c > index 4ddf7bf..824bc43 100644 > --- a/src/channel-usbredir.c > +++ b/src/channel-usbredir.c > @@ -344,14 +344,14 @@ void spice_usbredir_channel_connect_device_async( > if (!priv->host) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error libusb context not set"); > +_("Error libusb context not set")); > goto done; > } > > if (priv->state != STATE_DISCONNECTED) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error channel is busy"); > +_("Error channel is busy")); > goto done; > } > > diff --git a/src/spice-channel.c b/src/spice-channel.c > index dd32818..246609a 100644 > --- a/src/spice-channel.c > +++ b/src/spice-channel.c > @@ -2979,7 +2979,7 @@ void spice_channel_flush_async(SpiceChannel *self, > GCancellable *cancellable, > g_task_report_new_error(self, callback, user_data, > spice_channel_flush_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The channel is not ready yet"); > +_("The channel is not ready yet")); > return; > } > > diff --git a/src/spice-pulse.c b/src/spice-pulse.c > index 60a037c..5c3cfb7 100644 > --- a/src/spice-pulse.c > +++ b/src/spice-pulse.c > @@ -28,6 +28,8 @@ > #include > #include > > +#include > + > #define SPICE_PULSE_GET_PRIVATE(obj) \ > (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_PULSE, SpicePulsePrivate)) > > @@ -995,7 +997,7 @@ static void complete_task(SpicePulse *pulse, struct > async_task *task, const gcha > g_task_return_new_error(task->task, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"restore-info failed due %s", > +_("restore-info failed due %s"), As long as you're making a change here, it might be good to change this to "due to %s" instead of "due %s"? O
Re: [Spice-devel] [spice-gtk PATCH v2] gstaudio: set output parameter to NULL on error
Acked-by: Jonathon Jongsma On Mon, 2016-01-18 at 15:09 +0100, Victor Toso wrote: > This is not really triggered in the current code but this is usually > expected in case of errors; Also, the same function on record side > already does this. > --- > src/spice-gstaudio.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c > index 096fea4..2759c2b 100644 > --- a/src/spice-gstaudio.c > +++ b/src/spice-gstaudio.c > @@ -600,6 +600,10 @@ static gboolean > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), > FALSE); > > if (g_simple_async_result_propagate_error(simple, error)) { > +/* set out args that should have new alloc'ed memory to NULL */ > +if (volume != NULL) { > +*volume = NULL; > +} > return FALSE; > } > ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] Glib loop and scary corruption
Hi, I spend some time investigating in http://cgit.freedesktop.org/~fziglio/spice-server/commit/?h=refactory&id=48d5c2e74b6a866df2562c1aab8a1a3803bc788b, one of the last problems of glib loop. Beside I though that this patch also fix the symmetry between creation and destroying (stream is initialized during creation so usually is a good idea to deinitialize during destroying). Looking at the backtrace you can see that stream is inside a event handler after being freed by red_channel_client_disconnect called trying to push items (red_channel_client_push). My first idea was that glib called the event handler event after the watch was freed. This proved false after some testing. So I decided to checkout more or less same version and look at the code. Code was failing trying to retrieve header for a message, the push was called from red_channel_client_push handling a message of type SPICE_MSGC_ACK. But messages are read and handled in a loop in red_peer_handle_incoming which is called by a single watcher! So what's happen if: - SPICE_MSGC_ACK is read - handler is called with SPICE_MSGC_ACK - handler try to push messages - write fails as connection was closed - red_channel_client_disconnect is called - handler return to red_peer_handle_incoming - red_peer_handle_incoming calls red_peer_receive to read next message header (NOTE: error handler in red_peer_handle_incoming is called only if message is not handled) - red_peer_receive crash as rcc->stream is NULL! If you add a red_channel_client_disconnect after red_channel_client_push in red_channel_client_handle_message you can see the same problem. At this point. Why with Glib loop this happens more often? The reason is that the push is not called at last step of iteration so there is more probability to find items in red_channel_client_push (or at least the statistics on this change). So to sum up: - this issue is not a regression introduced by glib code; - the only thing left to check for glib is this statistical stuff (already at good point for Jonathon work). I'll post the patch based on master. Frediano ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 11/14] vmcstream: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:47AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/vmcstream.c | 129 > +++- > 1 file changed, 52 insertions(+), 77 deletions(-) > > diff --git a/src/vmcstream.c b/src/vmcstream.c > index 483dd5a..d9b62a0 100644 > --- a/src/vmcstream.c > +++ b/src/vmcstream.c > @@ -27,7 +27,7 @@ > struct _SpiceVmcInputStream > { > GInputStream parent_instance; > -GSimpleAsyncResult *result; > +GTask *task; > struct coroutine *coroutine; > > SpiceChannel *channel; > @@ -36,7 +36,6 @@ struct _SpiceVmcInputStream > gsize count; > gsize pos; > > -GCancellable *cancellable; > gulong cancel_id; > }; > > @@ -118,11 +117,12 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream > *self, > self->coroutine = coroutine_self(); > > while (size > 0) { > -SPICE_DEBUG("spicevmc co_data %p", self->result); > -if (!self->result) > +GCancellable *cancellable; > +SPICE_DEBUG("spicevmc co_data %p", self->task); > +if (!self->task) > coroutine_yield(NULL); > > -g_return_if_fail(self->result != NULL); > +g_return_if_fail(self->task != NULL); > > gsize min = MIN(self->count, size); > memcpy(self->buffer, data, min); > @@ -139,14 +139,13 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream > *self, > if (self->all && min > 0 && self->pos != self->count) > continue; > > -g_simple_async_result_set_op_res_gssize(self->result, self->pos); > +g_task_return_int(self->task, self->pos); > + > +cancellable = g_task_get_cancellable(self->task); > +if (cancellable) > +g_cancellable_disconnect(cancellable, self->cancel_id); > > -g_simple_async_result_complete_in_idle(self->result); > -g_clear_object(&self->result); > -if (self->cancellable) { > -g_cancellable_disconnect(self->cancellable, self->cancel_id); > -g_clear_object(&self->cancellable); > -} > +g_clear_object(&self->task); > } > > self->coroutine = NULL; > @@ -158,13 +157,12 @@ read_cancelled(GCancellable *cancellable, > { > 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); > +SPICE_DEBUG("read cancelled, %p", self->task); > +g_task_return_new_error(self->task, > +G_IO_ERROR, G_IO_ERROR_CANCELLED, > +"read cancelled"); > > -g_clear_object(&self->result); > +g_clear_object(&self->task); > > /* See FIXME */ > /* if (self->cancellable) { */ > @@ -183,21 +181,20 @@ spice_vmc_input_stream_read_all_async(GInputStream > *stream, >gpointer user_data) > { > SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > -GSimpleAsyncResult *result; > +GTask *task; > > /* no concurrent read permitted by ginputstream */ > -g_return_if_fail(self->result == NULL); > -g_return_if_fail(self->cancellable == NULL); > +g_return_if_fail(self->task == NULL); > +g_return_if_fail(g_task_get_cancellable(self->task) == NULL); > 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); > -self->result = result; > -self->cancellable = g_object_ref(cancellable); > +task = g_task_new(self, > + cancellable, > + callback, > + user_data); > +self->task = task; > if (cancellable) > self->cancel_id = > g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), > self, NULL); > @@ -211,27 +208,19 @@ spice_vmc_input_stream_read_all_finish(GInputStream > *stream, > GAsyncResult *result, > GError **error) > { > -GSimpleAsyncResult *simple; > +GTask *task = G_TASK(result); > +GCancellable *cancellable; > SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); > > -g_return_val_if_fail(g_simple_async_result_is_valid(result, > -G_OBJECT(self), > - > spice_vmc_inpu
Re: [Spice-devel] [PATCH 09/14] usb-acl-helper: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:45AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/usb-acl-helper.c | 76 > > 1 file changed, 35 insertions(+), 41 deletions(-) > > diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c > index 6a49627..17e2b3c 100644 > --- a/src/usb-acl-helper.c > +++ b/src/usb-acl-helper.c > @@ -35,10 +35,9 @@ > (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SPICE_TYPE_USB_ACL_HELPER, > SpiceUsbAclHelperPrivate)) > > struct _SpiceUsbAclHelperPrivate { > -GSimpleAsyncResult *result; > +GTask *task; > GIOChannel *in_ch; > GIOChannel *out_ch; > -GCancellable *cancellable; > gulong cancellable_id; > }; > > @@ -53,11 +52,11 @@ static void > spice_usb_acl_helper_cleanup(SpiceUsbAclHelper *self) > { > SpiceUsbAclHelperPrivate *priv = self->priv; > > -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); > -priv->cancellable = NULL; > +g_cancellable_disconnect(g_task_get_cancellable(priv->task), > + priv->cancellable_id); > priv->cancellable_id = 0; > > -g_clear_object(&priv->result); > +g_clear_object(&priv->task); > > if (priv->in_ch) { > g_io_channel_unref(priv->in_ch); > @@ -90,9 +89,9 @@ static void > spice_usb_acl_helper_class_init(SpiceUsbAclHelperClass *klass) > /* -- */ > /* callbacks */ > > -static void async_result_set_cancelled(GSimpleAsyncResult *result) > +static void async_result_set_cancelled(GTask *task) > { > -g_simple_async_result_set_error(result, > +g_task_return_new_error(task, > G_IO_ERROR, G_IO_ERROR_CANCELLED, > "Setting USB device node ACL cancelled"); > } > @@ -105,12 +104,13 @@ static gboolean cb_out_watch(GIOChannel*channel, > SpiceUsbAclHelperPrivate *priv = self->priv; > gboolean success = FALSE; > GError *err = NULL; > +GCancellable *cancellable; > GIOStatus status; > gchar *string; > gsize size; > > /* Check that we've not been cancelled */ > -if (priv->result == NULL) > +if (priv->task == NULL) > goto done; > > g_return_val_if_fail(channel == priv->out_ch, FALSE); > @@ -121,10 +121,11 @@ static gboolean cb_out_watch(GIOChannel*channel, > string[strlen(string) - 1] = 0; > if (!strcmp(string, "SUCCESS")) { > success = TRUE; > +g_task_return_boolean(priv->task, TRUE); > } else if (!strcmp(string, "CANCELED")) { > -async_result_set_cancelled(priv->result); > +async_result_set_cancelled(priv->task); > } else { > -g_simple_async_result_set_error(priv->result, > +g_task_return_new_error(priv->task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Error setting USB device node ACL: '%s'", > string); > @@ -132,10 +133,10 @@ static gboolean cb_out_watch(GIOChannel*channel, > g_free(string); > break; > case G_IO_STATUS_ERROR: > -g_simple_async_result_take_error(priv->result, err); > +g_task_return_error(priv->task, err); > break; > case G_IO_STATUS_EOF: > -g_simple_async_result_set_error(priv->result, > +g_task_return_new_error(priv->task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Unexpected EOF reading from acl helper stdout"); > break; > @@ -143,16 +144,16 @@ static gboolean cb_out_watch(GIOChannel*channel, > return TRUE; /* Wait for more input */ > } > > -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); > -priv->cancellable = NULL; > +cancellable = g_task_get_cancellable(priv->task); > +g_cancellable_disconnect(cancellable, priv->cancellable_id); > +cancellable = NULL; I forgot to mention in my previous mail that setting cancellable to NULL is probably not needed. Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 09/14] usb-acl-helper: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:45AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/usb-acl-helper.c | 76 > > 1 file changed, 35 insertions(+), 41 deletions(-) > > diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c > index 6a49627..17e2b3c 100644 > --- a/src/usb-acl-helper.c > +++ b/src/usb-acl-helper.c > @@ -35,10 +35,9 @@ > (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SPICE_TYPE_USB_ACL_HELPER, > SpiceUsbAclHelperPrivate)) > > struct _SpiceUsbAclHelperPrivate { > -GSimpleAsyncResult *result; > +GTask *task; > GIOChannel *in_ch; > GIOChannel *out_ch; > -GCancellable *cancellable; > gulong cancellable_id; > }; > > @@ -53,11 +52,11 @@ static void > spice_usb_acl_helper_cleanup(SpiceUsbAclHelper *self) > { > SpiceUsbAclHelperPrivate *priv = self->priv; > > -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); > -priv->cancellable = NULL; > +g_cancellable_disconnect(g_task_get_cancellable(priv->task), > + priv->cancellable_id); > priv->cancellable_id = 0; > > -g_clear_object(&priv->result); > +g_clear_object(&priv->task); > > if (priv->in_ch) { > g_io_channel_unref(priv->in_ch); > @@ -90,9 +89,9 @@ static void > spice_usb_acl_helper_class_init(SpiceUsbAclHelperClass *klass) > /* -- */ > /* callbacks */ > > -static void async_result_set_cancelled(GSimpleAsyncResult *result) > +static void async_result_set_cancelled(GTask *task) > { > -g_simple_async_result_set_error(result, > +g_task_return_new_error(task, > G_IO_ERROR, G_IO_ERROR_CANCELLED, > "Setting USB device node ACL cancelled"); > } > @@ -105,12 +104,13 @@ static gboolean cb_out_watch(GIOChannel*channel, > SpiceUsbAclHelperPrivate *priv = self->priv; > gboolean success = FALSE; > GError *err = NULL; > +GCancellable *cancellable; > GIOStatus status; > gchar *string; > gsize size; > > /* Check that we've not been cancelled */ > -if (priv->result == NULL) > +if (priv->task == NULL) > goto done; > > g_return_val_if_fail(channel == priv->out_ch, FALSE); > @@ -121,10 +121,11 @@ static gboolean cb_out_watch(GIOChannel*channel, > string[strlen(string) - 1] = 0; > if (!strcmp(string, "SUCCESS")) { > success = TRUE; > +g_task_return_boolean(priv->task, TRUE); > } else if (!strcmp(string, "CANCELED")) { > -async_result_set_cancelled(priv->result); > +async_result_set_cancelled(priv->task); > } else { > -g_simple_async_result_set_error(priv->result, > +g_task_return_new_error(priv->task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Error setting USB device node ACL: '%s'", > string); > @@ -132,10 +133,10 @@ static gboolean cb_out_watch(GIOChannel*channel, > g_free(string); > break; > case G_IO_STATUS_ERROR: > -g_simple_async_result_take_error(priv->result, err); > +g_task_return_error(priv->task, err); > break; > case G_IO_STATUS_EOF: > -g_simple_async_result_set_error(priv->result, > +g_task_return_new_error(priv->task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Unexpected EOF reading from acl helper stdout"); > break; > @@ -143,16 +144,16 @@ static gboolean cb_out_watch(GIOChannel*channel, > return TRUE; /* Wait for more input */ > } > > -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); > -priv->cancellable = NULL; > +cancellable = g_task_get_cancellable(priv->task); > +g_cancellable_disconnect(cancellable, priv->cancellable_id); > +cancellable = NULL; > priv->cancellable_id = 0; > > -g_simple_async_result_complete_in_idle(priv->result); > -g_clear_object(&priv->result); > - > if (!success) > spice_usb_acl_helper_cleanup(self); > > +g_clear_object(&priv->task); > + > done: > g_object_unref(self); > return FALSE; > @@ -193,7 +194,7 @@ void spice_usb_acl_helper_open_acl(SpiceUsbAclHelper > *self, > g_return_if_fail(SPICE_IS_USB_ACL_HELPER(self)); > > SpiceUsbAclHelperPrivate *priv = self->priv; > -GSimpleAsyncResult *result; > +GTask *task; > GError *err = NULL; > GIOStatus status; > GPid helper_pid; > @@ -202,25 +203,24 @@ void spice_usb_acl_helper_open_acl(SpiceUsbAclHelper > *self, > g
[Spice-devel] [PATCH 09/15] Change reds_on_main_agent_start() to take RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index b5268fb..0ab3dec 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -891,7 +891,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint return FALSE; } tokens = (SpiceMsgcMainAgentStart *)message; -reds_on_main_agent_start(mcc, tokens->num_tokens); +reds_on_main_agent_start(reds, mcc, tokens->num_tokens); break; } case SPICE_MSGC_MAIN_AGENT_DATA: { diff --git a/server/reds.c b/server/reds.c index bd905e2..db1f718 100644 --- a/server/reds.c +++ b/server/reds.c @@ -944,7 +944,7 @@ void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info) } } -void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens) +void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens) { SpiceCharDeviceState *dev_state = reds->agent_state.base; RedChannelClient *rcc; diff --git a/server/reds.h b/server/reds.h index fbb616d..4033724 100644 --- a/server/reds.h +++ b/server/reds.h @@ -94,7 +94,7 @@ void reds_update_stat_value(uint32_t value); /* callbacks from main channel messages */ -void reds_on_main_agent_start(MainChannelClient *mcc, uint32_t num_tokens); +void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens); void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens); uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size); void reds_release_agent_data_buffer(uint8_t *buf); -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 08/15] Change reds_fill_channels() to take a RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index 1b774f3..b5268fb 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -349,7 +349,7 @@ static void main_channel_marshall_channels(RedChannelClient *rcc, red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item); channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels) + reds_num_of_channels(reds) * sizeof(SpiceChannelId)); -reds_fill_channels(channels_info); +reds_fill_channels(reds, channels_info); spice_marshall_msg_main_channels_list(m, channels_info); free(channels_info); } diff --git a/server/reds.c b/server/reds.c index 0169fac..bd905e2 100644 --- a/server/reds.c +++ b/server/reds.c @@ -922,7 +922,7 @@ static int channel_is_secondary(RedChannel *channel) return FALSE; } -void reds_fill_channels(SpiceMsgChannels *channels_info) +void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info) { RingItem *now; int used_channels = 0; diff --git a/server/reds.h b/server/reds.h index aaa9477..fbb616d 100644 --- a/server/reds.h +++ b/server/reds.h @@ -86,7 +86,7 @@ void reds_client_disconnect(RedsState *reds, RedClient *client); // Temporary (?) for splitting main channel typedef struct MainMigrateData MainMigrateData; void reds_marshall_migrate_data(SpiceMarshaller *m); -void reds_fill_channels(SpiceMsgChannels *channels_info); +void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info); int reds_num_of_channels(RedsState *reds); #ifdef RED_STATISTICS void reds_update_stat_value(uint32_t value); -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 04/15] Change vdi_port_read_buf_unref() to take RedsState arg
From: Jonathon Jongsma --- server/reds.c | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/server/reds.c b/server/reds.c index 928cb83..4e0caba 100644 --- a/server/reds.c +++ b/server/reds.c @@ -214,7 +214,7 @@ static void reds_send_mm_time(void); static VDIReadBuf *vdi_port_read_buf_get(RedsState *reds); static VDIReadBuf *vdi_port_read_buf_ref(VDIReadBuf *buf); -static void vdi_port_read_buf_unref(VDIReadBuf *buf); +static void vdi_port_read_buf_unref(RedsState *reds, VDIReadBuf *buf); static ChannelSecurityOptions *channels_security = NULL; static int default_channel_security = @@ -440,7 +440,7 @@ static void reds_reset_vdp(RedsState *reds) state->receive_len = sizeof(state->vdi_chunk_header); state->message_receive_len = 0; if (state->current_read_buf) { -vdi_port_read_buf_unref(state->current_read_buf); +vdi_port_read_buf_unref(reds, state->current_read_buf); state->current_read_buf = NULL; } /* Reset read filter to start with clean state when the agent reconnects */ @@ -658,7 +658,7 @@ static void vdi_port_read_buf_release(uint8_t *data, void *opaque) { VDIReadBuf *buf = (VDIReadBuf *)opaque; -vdi_port_read_buf_unref(buf); +vdi_port_read_buf_unref(reds, buf); } /* returns TRUE if the buffer can be forwarded */ @@ -713,7 +713,9 @@ static VDIReadBuf* vdi_port_read_buf_ref(VDIReadBuf *buf) return buf; } -static void vdi_port_read_buf_unref(VDIReadBuf *buf) +/* FIXME: refactor so that unreffing the VDIReadBuf doesn't require accessing + * RedsState? */ +static void vdi_port_read_buf_unref(RedsState *reds, VDIReadBuf *buf) { if (!--buf->refs) { ring_add(&reds->agent_state.read_bufs, &buf->link); @@ -790,7 +792,7 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe if (vdi_port_read_buf_process(reds, state->vdi_chunk_header.port, dispatch_buf)) { return dispatch_buf; } else { -vdi_port_read_buf_unref(dispatch_buf); +vdi_port_read_buf_unref(reds, dispatch_buf); } } /* END switch */ } /* END while */ @@ -806,7 +808,8 @@ static SpiceCharDeviceMsgToClient *vdi_port_ref_msg_to_client(SpiceCharDeviceMsg static void vdi_port_unref_msg_to_client(SpiceCharDeviceMsgToClient *msg, void *opaque) { -vdi_port_read_buf_unref(msg); +RedsState *reds = opaque; +vdi_port_read_buf_unref(reds, msg); } /* after calling this, we unref the message, and the ref is in the instance side */ @@ -1163,7 +1166,7 @@ void reds_on_main_channel_migrate(MainChannelClient *mcc) vdi_port_read_buf_release, read_buf); } else { -vdi_port_read_buf_unref(read_buf); +vdi_port_read_buf_unref(reds, read_buf); } spice_assert(agent_state->receive_len); -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 13/15] Change red_on_main_agent_data() to take RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 6 +++--- server/reds.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index 3315d6c..a30ba1e 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -895,7 +895,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint break; } case SPICE_MSGC_MAIN_AGENT_DATA: { -reds_on_main_agent_data(mcc, message, size); +reds_on_main_agent_data(reds, mcc, message, size); break; } case SPICE_MSGC_MAIN_AGENT_TOKEN: { diff --git a/server/reds.c b/server/reds.c index 5c038ca..37d0393 100644 --- a/server/reds.c +++ b/server/reds.c @@ -1050,7 +1050,7 @@ static void reds_client_monitors_config_cleanup(RedsState *reds) cmc->mcc = NULL; } -static void reds_on_main_agent_monitors_config( +static void reds_on_main_agent_monitors_config(RedsState *reds, MainChannelClient *mcc, void *message, size_t size) { VDAgentMessage *msg_header; @@ -1075,7 +1075,7 @@ static void reds_on_main_agent_monitors_config( reds_client_monitors_config_cleanup(reds); } -void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size) +void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *message, size_t size) { VDIPortState *dev_state = &reds->agent_state; VDIChunkHeader *header; @@ -1089,7 +1089,7 @@ void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size) case AGENT_MSG_FILTER_DISCARD: return; case AGENT_MSG_FILTER_MONITORS_CONFIG: -reds_on_main_agent_monitors_config(mcc, message, size); +reds_on_main_agent_monitors_config(reds, mcc, message, size); return; case AGENT_MSG_FILTER_PROTO_ERROR: red_channel_client_shutdown(main_channel_client_get_base(mcc)); diff --git a/server/reds.h b/server/reds.h index 0294333..9672c5e 100644 --- a/server/reds.h +++ b/server/reds.h @@ -98,7 +98,7 @@ void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens); uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, size_t size); void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf); -void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size); +void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *message, size_t size); void reds_on_main_migrate_connected(int seamless); //should be called when all the clients // are connected to the target int reds_handle_migrate_data(MainChannelClient *mcc, -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 03/15] Change vdi_port_read_buf_get() to take RedsState arg
From: Jonathon Jongsma --- server/reds.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/reds.c b/server/reds.c index b347d1d..928cb83 100644 --- a/server/reds.c +++ b/server/reds.c @@ -212,7 +212,7 @@ static void reds_char_device_add_state(SpiceCharDeviceState *st); static void reds_char_device_remove_state(SpiceCharDeviceState *st); static void reds_send_mm_time(void); -static VDIReadBuf *vdi_port_read_buf_get(void); +static VDIReadBuf *vdi_port_read_buf_get(RedsState *reds); static VDIReadBuf *vdi_port_read_buf_ref(VDIReadBuf *buf); static void vdi_port_read_buf_unref(VDIReadBuf *buf); @@ -690,7 +690,7 @@ static int vdi_port_read_buf_process(RedsState *reds, int port, VDIReadBuf *buf) } } -static VDIReadBuf *vdi_port_read_buf_get(void) +static VDIReadBuf *vdi_port_read_buf_get(RedsState *reds) { VDIPortState *state = &reds->agent_state; RingItem *item; @@ -758,7 +758,7 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe state->message_receive_len = state->vdi_chunk_header.size; state->read_state = VDI_PORT_READ_STATE_GET_BUFF; case VDI_PORT_READ_STATE_GET_BUFF: { -if (!(state->current_read_buf = vdi_port_read_buf_get())) { +if (!(state->current_read_buf = vdi_port_read_buf_get(reds))) { return NULL; } state->receive_pos = state->current_read_buf->data; @@ -1281,7 +1281,7 @@ static int reds_agent_state_restore(SpiceMigrateDataMain *mig_data) uint32_t cur_buf_size; agent_state->read_state = VDI_PORT_READ_STATE_READ_DATA; -agent_state->current_read_buf = vdi_port_read_buf_get(); +agent_state->current_read_buf = vdi_port_read_buf_get(reds); spice_assert(agent_state->current_read_buf); partial_msg_header = (uint8_t *)mig_data + mig_data->agent2client.msg_header_ptr - sizeof(SpiceMiniDataHeader); -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 12/15] Change reds_client_monitors_config_cleanup() to take RedsState arg
From: Jonathon Jongsma --- server/reds.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/reds.c b/server/reds.c index b183ee1..5c038ca 100644 --- a/server/reds.c +++ b/server/reds.c @@ -1040,7 +1040,7 @@ void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf) dev_state->recv_from_client_buf_pushed = FALSE; } -static void reds_client_monitors_config_cleanup(void) +static void reds_client_monitors_config_cleanup(RedsState *reds) { RedsClientMonitorsConfig *cmc = &reds->client_monitors_config; @@ -1072,7 +1072,7 @@ static void reds_on_main_agent_monitors_config( monitors_config = (VDAgentMonitorsConfig *)(cmc->buffer + sizeof(*msg_header)); spice_debug("%s: %d", __func__, monitors_config->num_of_monitors); red_dispatcher_client_monitors_config(monitors_config); -reds_client_monitors_config_cleanup(); +reds_client_monitors_config_cleanup(reds); } void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size) @@ -3418,7 +3418,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface) reds->mouse_mode = SPICE_MOUSE_MODE_SERVER; -reds_client_monitors_config_cleanup(); +reds_client_monitors_config_cleanup(reds); reds->allow_multiple_clients = getenv(SPICE_DEBUG_ALLOW_MC_ENV) != NULL; if (reds->allow_multiple_clients) { -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 07/15] Change reds_num_of_clients() to take RedsState arg
From: Jonathon Jongsma --- server/reds.c | 4 ++-- server/reds.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/server/reds.c b/server/reds.c index 9b28a7c..0169fac 100644 --- a/server/reds.c +++ b/server/reds.c @@ -897,7 +897,7 @@ int reds_num_of_channels(RedsState *reds) } -int reds_num_of_clients(void) +static int reds_num_of_clients(RedsState *reds) { return reds ? reds->num_clients : 0; } @@ -905,7 +905,7 @@ int reds_num_of_clients(void) SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *s) { spice_assert(reds == s); -return reds_num_of_clients(); +return reds_num_of_clients(reds); } static int secondary_channels[] = { diff --git a/server/reds.h b/server/reds.h index 65e8f69..aaa9477 100644 --- a/server/reds.h +++ b/server/reds.h @@ -88,7 +88,6 @@ typedef struct MainMigrateData MainMigrateData; void reds_marshall_migrate_data(SpiceMarshaller *m); void reds_fill_channels(SpiceMsgChannels *channels_info); int reds_num_of_channels(RedsState *reds); -int reds_num_of_clients(void); #ifdef RED_STATISTICS void reds_update_stat_value(uint32_t value); #endif -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 14/15] reds_num_of_channels() -> reds_get_n_channels()
From: Jonathon Jongsma More consistent with glib naming conventions. --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index a30ba1e..9f8a861 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -348,7 +348,7 @@ static void main_channel_marshall_channels(RedChannelClient *rcc, red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item); channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels) -+ reds_num_of_channels(reds) * sizeof(SpiceChannelId)); ++ reds_get_n_channels(reds) * sizeof(SpiceChannelId)); reds_fill_channels(reds, channels_info); spice_marshall_msg_main_channels_list(m, channels_info); free(channels_info); diff --git a/server/reds.c b/server/reds.c index 37d0393..4de1640 100644 --- a/server/reds.c +++ b/server/reds.c @@ -891,7 +891,7 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou spice_char_device_write_buffer_add(reds->agent_state.base, char_dev_buf); } -int reds_num_of_channels(RedsState *reds) +int reds_get_n_channels(RedsState *reds) { return reds ? reds->num_of_channels : 0; } diff --git a/server/reds.h b/server/reds.h index 9672c5e..39fe291 100644 --- a/server/reds.h +++ b/server/reds.h @@ -87,7 +87,7 @@ void reds_client_disconnect(RedsState *reds, RedClient *client); typedef struct MainMigrateData MainMigrateData; void reds_marshall_migrate_data(SpiceMarshaller *m); void reds_fill_channels(RedsState *reds, SpiceMsgChannels *channels_info); -int reds_num_of_channels(RedsState *reds); +int reds_get_n_channels(RedsState *reds); #ifdef RED_STATISTICS void reds_update_stat_value(uint32_t value); #endif -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 01/15] Pass 'reds' as opaque data in vdi port char device
From: Jonathon Jongsma This allows us to access the RedsState variable non-globally without changing the signature of the callback functions. --- server/reds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/reds.c b/server/reds.c index 9868928..25e9f90 100644 --- a/server/reds.c +++ b/server/reds.c @@ -733,6 +733,7 @@ static void vdi_port_read_buf_unref(VDIReadBuf *buf) static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDeviceInstance *sin, void *opaque) { +RedsState *reds = opaque; VDIPortState *state = &reds->agent_state; SpiceCharDeviceInterface *sif; VDIReadBuf *dispatch_buf; @@ -2987,7 +2988,7 @@ static SpiceCharDeviceState *attach_to_red_agent(SpiceCharDeviceInstance *sin) REDS_TOKENS_TO_SEND, REDS_NUM_INTERNAL_AGENT_MESSAGES, &char_dev_state_cbs, - NULL); + reds); } else { spice_char_device_state_reset_dev_instance(state->base, sin); } -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 15/15] reds_num_of_clients() -> reds_get_n_clients()
From: Jonathon Jongsma More consistent with glib naming conventions. Also make the function static since it's not used outside of this source file. --- server/reds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/reds.c b/server/reds.c index 4de1640..22ab26d 100644 --- a/server/reds.c +++ b/server/reds.c @@ -897,7 +897,7 @@ int reds_get_n_channels(RedsState *reds) } -static int reds_num_of_clients(RedsState *reds) +static int reds_get_n_clients(RedsState *reds) { return reds ? reds->num_clients : 0; } @@ -905,7 +905,7 @@ static int reds_num_of_clients(RedsState *reds) SPICE_GNUC_VISIBLE int spice_server_get_num_clients(SpiceServer *s) { spice_assert(reds == s); -return reds_num_of_clients(reds); +return reds_get_n_clients(reds); } static int secondary_channels[] = { -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 11/15] Change reds_release_agent_data_buffer() to take RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index 31e65f0..3315d6c 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -1020,7 +1020,7 @@ static void main_channel_release_msg_rcv_buf(RedChannelClient *rcc, uint8_t *msg) { if (type == SPICE_MSGC_MAIN_AGENT_DATA) { -reds_release_agent_data_buffer(msg); +reds_release_agent_data_buffer(reds, msg); } } diff --git a/server/reds.c b/server/reds.c index d480ce3..b183ee1 100644 --- a/server/reds.c +++ b/server/reds.c @@ -1022,7 +1022,7 @@ uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, siz return dev_state->recv_from_client_buf->buf + sizeof(VDIChunkHeader); } -void reds_release_agent_data_buffer(uint8_t *buf) +void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf) { VDIPortState *dev_state = &reds->agent_state; diff --git a/server/reds.h b/server/reds.h index 2659493..0294333 100644 --- a/server/reds.h +++ b/server/reds.h @@ -96,8 +96,8 @@ void reds_update_stat_value(uint32_t value); void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens); void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens); -void reds_release_agent_data_buffer(uint8_t *buf); uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, size_t size); +void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf); void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size); void reds_on_main_migrate_connected(int seamless); //should be called when all the clients // are connected to the target -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 10/15] Change reds_get_agent_data_buffer() to take RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index 0ab3dec..31e65f0 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -1008,7 +1008,7 @@ static uint8_t *main_channel_alloc_msg_rcv_buf(RedChannelClient *rcc, MainChannelClient *mcc = SPICE_CONTAINEROF(rcc, MainChannelClient, base); if (type == SPICE_MSGC_MAIN_AGENT_DATA) { -return reds_get_agent_data_buffer(mcc, size); +return reds_get_agent_data_buffer(reds, mcc, size); } else { return main_chan->recv_buf; } diff --git a/server/reds.c b/server/reds.c index db1f718..d480ce3 100644 --- a/server/reds.c +++ b/server/reds.c @@ -997,7 +997,7 @@ void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens) num_tokens); } -uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size) +uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, size_t size) { VDIPortState *dev_state = &reds->agent_state; RedClient *client; diff --git a/server/reds.h b/server/reds.h index 4033724..2659493 100644 --- a/server/reds.h +++ b/server/reds.h @@ -96,8 +96,8 @@ void reds_update_stat_value(uint32_t value); void reds_on_main_agent_start(RedsState *reds, MainChannelClient *mcc, uint32_t num_tokens); void reds_on_main_agent_tokens(MainChannelClient *mcc, uint32_t num_tokens); -uint8_t *reds_get_agent_data_buffer(MainChannelClient *mcc, size_t size); void reds_release_agent_data_buffer(uint8_t *buf); +uint8_t *reds_get_agent_data_buffer(RedsState *reds, MainChannelClient *mcc, size_t size); void reds_on_main_agent_data(MainChannelClient *mcc, void *message, size_t size); void reds_on_main_migrate_connected(int seamless); //should be called when all the clients // are connected to the target -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 06/15] Change reds_num_of_channels() to take RedsState arg
From: Jonathon Jongsma --- server/main-channel.c | 2 +- server/reds.c | 2 +- server/reds.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/main-channel.c b/server/main-channel.c index 2a9f0ce..1b774f3 100644 --- a/server/main-channel.c +++ b/server/main-channel.c @@ -348,7 +348,7 @@ static void main_channel_marshall_channels(RedChannelClient *rcc, red_channel_client_init_send_data(rcc, SPICE_MSG_MAIN_CHANNELS_LIST, item); channels_info = (SpiceMsgChannels *)spice_malloc(sizeof(SpiceMsgChannels) -+ reds_num_of_channels() * sizeof(SpiceChannelId)); ++ reds_num_of_channels(reds) * sizeof(SpiceChannelId)); reds_fill_channels(channels_info); spice_marshall_msg_main_channels_list(m, channels_info); free(channels_info); diff --git a/server/reds.c b/server/reds.c index 11f0e1a..9b28a7c 100644 --- a/server/reds.c +++ b/server/reds.c @@ -891,7 +891,7 @@ void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mou spice_char_device_write_buffer_add(reds->agent_state.base, char_dev_buf); } -int reds_num_of_channels(void) +int reds_num_of_channels(RedsState *reds) { return reds ? reds->num_of_channels : 0; } diff --git a/server/reds.h b/server/reds.h index 76262ce..65e8f69 100644 --- a/server/reds.h +++ b/server/reds.h @@ -87,7 +87,7 @@ void reds_client_disconnect(RedsState *reds, RedClient *client); typedef struct MainMigrateData MainMigrateData; void reds_marshall_migrate_data(SpiceMarshaller *m); void reds_fill_channels(SpiceMsgChannels *channels_info); -int reds_num_of_channels(void); +int reds_num_of_channels(RedsState *reds); int reds_num_of_clients(void); #ifdef RED_STATISTICS void reds_update_stat_value(uint32_t value); -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 05/15] Change reds_handle_agent_mouse_event() to take RedsState arg
From: Jonathon Jongsma --- server/inputs-channel.c | 6 +++--- server/reds.c | 5 +++-- server/reds.h | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/server/inputs-channel.c b/server/inputs-channel.c index bb5b203..d13f9d7 100644 --- a/server/inputs-channel.c +++ b/server/inputs-channel.c @@ -396,7 +396,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui mouse_state->y = pos->y; mouse_state->buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(pos->buttons_state); mouse_state->display_id = pos->display_id; -reds_handle_agent_mouse_event(mouse_state); +reds_handle_agent_mouse_event(reds, mouse_state); break; } case SPICE_MSGC_INPUTS_MOUSE_PRESS: { @@ -413,7 +413,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) | (dz == -1 ? VD_AGENT_UBUTTON_MASK : 0) | (dz == 1 ? VD_AGENT_DBUTTON_MASK : 0); -reds_handle_agent_mouse_event(&inputs_channel->mouse_state); +reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state); } else if (tablet) { SpiceTabletInterface *sif; sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base); @@ -433,7 +433,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui if (reds_get_agent_mouse() && reds_has_vdagent()) { inputs_channel->mouse_state.buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state); -reds_handle_agent_mouse_event(&inputs_channel->mouse_state); +reds_handle_agent_mouse_event(reds, &inputs_channel->mouse_state); } else if (tablet) { SpiceTabletInterface *sif; sif = SPICE_CONTAINEROF(tablet->base.sif, SpiceTabletInterface, base); diff --git a/server/reds.c b/server/reds.c index 4e0caba..11f0e1a 100644 --- a/server/reds.c +++ b/server/reds.c @@ -834,10 +834,11 @@ static void vdi_port_send_tokens_to_client(RedClient *client, uint32_t tokens, v static void vdi_port_on_free_self_token(void *opaque) { +RedsState *reds = opaque; if (inputs_inited() && reds->pending_mouse_event) { spice_debug("pending mouse event"); -reds_handle_agent_mouse_event(inputs_get_mouse_state()); +reds_handle_agent_mouse_event(reds, inputs_get_mouse_state()); } } @@ -854,7 +855,7 @@ int reds_has_vdagent(void) return !!vdagent; } -void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state) +void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mouse_state) { SpiceCharDeviceWriteBuffer *char_dev_buf; VDInternalBuf *internal_buf; diff --git a/server/reds.h b/server/reds.h index e38a99a..76262ce 100644 --- a/server/reds.h +++ b/server/reds.h @@ -60,7 +60,7 @@ void reds_unregister_channel(RedsState *reds, RedChannel *channel); int reds_get_mouse_mode(RedsState *reds); // used by inputs_channel int reds_get_agent_mouse(void); // used by inputs_channel int reds_has_vdagent(void); // used by inputs channel -void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state); // used by inputs_channel +void reds_handle_agent_mouse_event(RedsState *reds, const VDAgentMouseState *mouse_state); // used by inputs_channel enum { RED_RENDERER_INVALID, -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 02/15] Change vdi_port_read_buf_process() to take RedsState arg
From: Jonathon Jongsma --- server/reds.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/reds.c b/server/reds.c index 25e9f90..b347d1d 100644 --- a/server/reds.c +++ b/server/reds.c @@ -662,7 +662,7 @@ static void vdi_port_read_buf_release(uint8_t *data, void *opaque) } /* returns TRUE if the buffer can be forwarded */ -static int vdi_port_read_buf_process(int port, VDIReadBuf *buf) +static int vdi_port_read_buf_process(RedsState *reds, int port, VDIReadBuf *buf) { VDIPortState *state = &reds->agent_state; int res; @@ -787,7 +787,7 @@ static SpiceCharDeviceMsgToClient *vdi_port_read_one_msg_from_device(SpiceCharDe } else { state->read_state = VDI_PORT_READ_STATE_GET_BUFF; } -if (vdi_port_read_buf_process(state->vdi_chunk_header.port, dispatch_buf)) { +if (vdi_port_read_buf_process(reds, state->vdi_chunk_header.port, dispatch_buf)) { return dispatch_buf; } else { vdi_port_read_buf_unref(dispatch_buf); @@ -1156,7 +1156,7 @@ void reds_on_main_channel_migrate(MainChannelClient *mcc) !agent_state->read_filter.msg_data_to_read); read_buf->len = read_data_len; -if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) { +if (vdi_port_read_buf_process(reds, agent_state->vdi_chunk_header.port, read_buf)) { main_channel_client_push_agent_data(mcc, read_buf->data, read_buf->len, -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 00/15] Backported some patches from refactory branches (18th Jan)
Many new patches try to incrementally remove global reds variable so they add RedsState* as parameter. All previous patches were merged. Jonathon Jongsma (15): Pass 'reds' as opaque data in vdi port char device Change vdi_port_read_buf_process() to take RedsState arg Change vdi_port_read_buf_get() to take RedsState arg Change vdi_port_read_buf_unref() to take RedsState arg Change reds_handle_agent_mouse_event() to take RedsState arg Change reds_num_of_channels() to take RedsState arg Change reds_num_of_clients() to take RedsState arg Change reds_fill_channels() to take a RedsState arg Change reds_on_main_agent_start() to take RedsState arg Change reds_get_agent_data_buffer() to take RedsState arg Change reds_release_agent_data_buffer() to take RedsState arg Change reds_client_monitors_config_cleanup() to take RedsState arg Change red_on_main_agent_data() to take RedsState arg reds_num_of_channels() -> reds_get_n_channels() reds_num_of_clients() -> reds_get_n_clients() server/inputs-channel.c | 6 ++--- server/main-channel.c | 12 - server/reds.c | 65 ++--- server/reds.h | 15 ++-- 4 files changed, 51 insertions(+), 47 deletions(-) -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH] tests: remove leaks in test-qxl-parsing
This make happy address sanitizer during make check. Otherwise memory leak detector can keep in and make tests fails. Signed-off-by: Frediano Ziglio --- server/tests/test-qxl-parsing.c | 10 +- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/tests/test-qxl-parsing.c b/server/tests/test-qxl-parsing.c index d44289f..a3b2e6c 100644 --- a/server/tests/test-qxl-parsing.c +++ b/server/tests/test-qxl-parsing.c @@ -65,6 +65,8 @@ int main(int argc, char **argv) QXLCursor *cursor; QXLDataChunk *chunks[2]; +void *surface_mem; + memset(&qxl, 0, sizeof(qxl)); qxl.surface_id = 123; @@ -75,7 +77,8 @@ int main(int argc, char **argv) qxl.u.surface_create.width = 128; qxl.u.surface_create.stride = 512; qxl.u.surface_create.height = 128; -qxl.u.surface_create.data = to_physical(malloc(0x1)); +surface_mem = malloc(0x1); +qxl.u.surface_create.data = to_physical(surface_mem); if (red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) failure(); @@ -117,6 +120,7 @@ int main(int argc, char **argv) if (red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) failure(); +free(red_cursor_cmd.u.set.shape.data); free(cursor); /* a circular list of empty chunks should not be a problems */ @@ -173,5 +177,9 @@ int main(int argc, char **argv) free(cursor); free(chunks[0]); +free(mem_info.mem_slots[0]); +free(mem_info.mem_slots); +free(surface_mem); + return exit_code; } -- 2.4.3 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 13/14] wocky-http-proxy: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:49AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. Is there an upstream for wocky-http-proxy where you should send this patch? > --- > src/wocky-http-proxy.c | 47 ++- > 1 file changed, 18 insertions(+), 29 deletions(-) > > diff --git a/src/wocky-http-proxy.c b/src/wocky-http-proxy.c > index d84cd72..f079e10 100644 > --- a/src/wocky-http-proxy.c > +++ b/src/wocky-http-proxy.c > @@ -254,14 +254,13 @@ error: > > typedef struct > { > - GSimpleAsyncResult *simple; > + GTask *task; >GIOStream *io_stream; >gchar *buffer; >gssize length; >gssize offset; >GDataInputStream *data_in; >gboolean has_cred; > - GCancellable *cancellable; > } ConnectAsyncData; > > static void request_write_cb (GObject *source, > @@ -282,26 +281,22 @@ free_connect_data (ConnectAsyncData *data) >if (data->data_in != NULL) > g_object_unref (data->data_in); > > - if (data->cancellable != NULL) > -g_object_unref (data->cancellable); > - >g_free (data); > } > > static void > complete_async_from_error (ConnectAsyncData *data, GError *error) > { > - GSimpleAsyncResult *simple = data->simple; > + GTask *task = data->task; > >if (error == NULL) > g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED, > "HTTP proxy server closed connection unexpectedly."); > > - g_simple_async_result_set_from_error (data->simple, error); > + g_task_return_error(data->task, error); >g_error_free (error); This should be removed > - g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL); > - g_simple_async_result_complete (simple); > - g_object_unref (simple); > + g_task_return_pointer(task, NULL, NULL); I don't think you need this g_task_return_pointer(), you already returned an error. > + g_object_unref (task); > } > > static void > @@ -312,7 +307,7 @@ do_write (GAsyncReadyCallback callback, ConnectAsyncData > *data) >g_output_stream_write_async (out, >data->buffer + data->offset, >data->length - data->offset, > - G_PRIORITY_DEFAULT, data->cancellable, > + G_PRIORITY_DEFAULT, g_task_get_cancellable(data->task), >callback, data); > } > > @@ -357,24 +352,22 @@ wocky_http_proxy_connect_async (GProxy *proxy, > GAsyncReadyCallback callback, > gpointer user_data) > { > - GSimpleAsyncResult *simple; > + GTask *task; >ConnectAsyncData *data; > > - simple = g_simple_async_result_new (G_OBJECT (proxy), > - callback, user_data, > - wocky_http_proxy_connect_async); > + task = g_task_new (proxy, > + cancellable, > + callback, > + user_data); > >data = g_new0 (ConnectAsyncData, 1); > - if (cancellable != NULL) > -data->cancellable = g_object_ref (cancellable); > - data->simple = simple; > + data->task = task; > >data->buffer = create_request (proxy_address, &data->has_cred); >data->length = strlen (data->buffer); >data->offset = 0; > > - g_simple_async_result_set_op_res_gpointer (simple, data, > - (GDestroyNotify) > free_connect_data); > + g_task_return_pointer (task, data, (GDestroyNotify) free_connect_data); Ah, I don't think the initial code meant g_task_return_pointer() here (there is no call to g_simple_async_result_complete_* in this function). It's rather a slight abuse of GSimpleAsyncResult API in order to get g_task_set_task_data functionality. Or maybe this is really the value that it wants to return to the user, but not before it's time to do that in reply_read_cb(). > >if (WOCKY_IS_HTTPS_PROXY (proxy)) > { > @@ -435,7 +428,7 @@ request_write_cb (GObject *source, >g_data_input_stream_read_until_async (data->data_in, >HTTP_END_MARKER, >G_PRIORITY_DEFAULT, > - data->cancellable, > + g_task_get_cancellable(data->task), >reply_read_cb, data); > > } > @@ -468,8 +461,7 @@ reply_read_cb (GObject *source, >return; > } > > - g_simple_async_result_complete (data->simple); You need a g_task_return_ here in my opinion. Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [spice-gtk PATCH v2] gstaudio: set output parameter to NULL on error
hmmm, subjectprefix with v2. sorry. This is v1. On Mon, Jan 18, 2016 at 03:09:48PM +0100, Victor Toso wrote: > This is not really triggered in the current code but this is usually > expected in case of errors; Also, the same function on record side > already does this. > --- > src/spice-gstaudio.c | 4 > 1 file changed, 4 insertions(+) > > diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c > index 096fea4..2759c2b 100644 > --- a/src/spice-gstaudio.c > +++ b/src/spice-gstaudio.c > @@ -600,6 +600,10 @@ static gboolean > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), > FALSE); > > if (g_simple_async_result_propagate_error(simple, error)) { > +/* set out args that should have new alloc'ed memory to NULL */ > +if (volume != NULL) { > +*volume = NULL; > +} > return FALSE; > } > > -- > 2.5.0 > > ___ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice-gtk PATCH v2] gstaudio: set output parameter to NULL on error
This is not really triggered in the current code but this is usually expected in case of errors; Also, the same function on record side already does this. --- src/spice-gstaudio.c | 4 1 file changed, 4 insertions(+) diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c index 096fea4..2759c2b 100644 --- a/src/spice-gstaudio.c +++ b/src/spice-gstaudio.c @@ -600,6 +600,10 @@ static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), FALSE); if (g_simple_async_result_propagate_error(simple, error)) { +/* set out args that should have new alloc'ed memory to NULL */ +if (volume != NULL) { +*volume = NULL; +} return FALSE; } -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 12/14] win-usb-driver-install: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:48AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/win-usb-driver-install.c | 86 > +--- > 1 file changed, 41 insertions(+), 45 deletions(-) > > diff --git a/src/win-usb-driver-install.c b/src/win-usb-driver-install.c > index 54e9b14..a7c4864 100644 > --- a/src/win-usb-driver-install.c > +++ b/src/win-usb-driver-install.c > @@ -44,8 +44,7 @@ > > struct _SpiceWinUsbDriverPrivate { > USBClerkReply reply; > -GSimpleAsyncResult*result; > -GCancellable *cancellable; > +GTask *task; > HANDLEhandle; > SpiceUsbDevice*device; > }; > @@ -144,16 +143,16 @@ void win_usb_driver_handle_reply_cb(GObject *gobject, > > if (err) { > g_warning("failed to read reply from usbclerk (%s)", err->message); > -g_simple_async_result_take_error(priv->result, err); > +g_task_return_error(priv->task, err); > goto failed_reply; > } > > if (bytes == 0) { > g_warning("unexpected EOF from usbclerk"); > -g_simple_async_result_set_error(priv->result, > -SPICE_WIN_USB_DRIVER_ERROR, > -SPICE_WIN_USB_DRIVER_ERROR_FAILED, > -"unexpected EOF from usbclerk"); > +g_task_return_new_error(priv->task, > +SPICE_WIN_USB_DRIVER_ERROR, > +SPICE_WIN_USB_DRIVER_ERROR_FAILED, > +"unexpected EOF from usbclerk"); > goto failed_reply; > } > > @@ -167,52 +166,53 @@ void win_usb_driver_handle_reply_cb(GObject *gobject, > if (priv->reply.hdr.magic != USB_CLERK_MAGIC) { > g_warning("usbclerk magic mismatch: mine=0x%04x server=0x%04x", >USB_CLERK_MAGIC, priv->reply.hdr.magic); > -g_simple_async_result_set_error(priv->result, > -SPICE_WIN_USB_DRIVER_ERROR, > -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > -"usbclerk magic mismatch"); > +g_task_return_new_error(priv->task, > +SPICE_WIN_USB_DRIVER_ERROR, > +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > +"usbclerk magic mismatch"); > goto failed_reply; > } > > if (priv->reply.hdr.version != USB_CLERK_VERSION) { > g_warning("usbclerk version mismatch: mine=0x%04x server=0x%04x", >USB_CLERK_VERSION, priv->reply.hdr.version); > -g_simple_async_result_set_error(priv->result, > -SPICE_WIN_USB_DRIVER_ERROR, > -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > -"usbclerk version mismatch"); > +g_task_return_new_error(priv->task, > +SPICE_WIN_USB_DRIVER_ERROR, > +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > +"usbclerk version mismatch"); > } > > if (priv->reply.hdr.type != USB_CLERK_REPLY) { > g_warning("usbclerk message with unexpected type %d", >priv->reply.hdr.type); > -g_simple_async_result_set_error(priv->result, > -SPICE_WIN_USB_DRIVER_ERROR, > -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > -"usbclerk message with unexpected > type"); > +g_task_return_new_error(priv->task, > +SPICE_WIN_USB_DRIVER_ERROR, > +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > +"usbclerk message with unexpected type"); > goto failed_reply; > } > > if (priv->reply.hdr.size != bytes) { > g_warning("usbclerk message size mismatch: read %"G_GSSIZE_FORMAT" > bytes hdr.size=%d", >bytes, priv->reply.hdr.size); > -g_simple_async_result_set_error(priv->result, > -SPICE_WIN_USB_DRIVER_ERROR, > -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > -"usbclerk message with unexpected > size"); > +g_task_return_new_error(priv->task, > +SPICE_WIN_USB_DRIVER_ERROR, > +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, > +"usbclerk message with unexpected size"); > goto failed_reply; > } > > if (priv->reply.status == 0) { > -g_simple_async_result_set_error(priv->resul
Re: [Spice-devel] [PATCH 07/14] spice-gstaudio: Use GTask instead of GSimpleAsyncResult
Hi, On Mon, Jan 18, 2016 at 02:51:05PM +0100, Christophe Fergeau wrote: > On Mon, Jan 18, 2016 at 10:05:43AM +0100, Fabiano Fidêncio wrote: > > Instead of using GSimpleAsyncResult, use the new GTask API, which is > > much more straightforward. > > --- > > src/spice-gstaudio.c | 48 ++-- > > 1 file changed, 10 insertions(+), 38 deletions(-) > > > > diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c > > index 096fea4..65fc173 100644 > > --- a/src/spice-gstaudio.c > > +++ b/src/spice-gstaudio.c > > @@ -570,16 +570,9 @@ static void > > spice_gstaudio_get_playback_volume_info_async(SpiceAudio *audio, > > > > GAsyncReadyCallback callback, > >gpointer > > user_data) > > { > > -GSimpleAsyncResult *simple; > > +GTask *task = g_task_new(audio, cancellable, callback, user_data); > > > > -simple = g_simple_async_result_new(G_OBJECT(audio), > > - callback, > > - user_data, > > - > > spice_gstaudio_get_playback_volume_info_async); > > -g_simple_async_result_set_check_cancellable (simple, cancellable); > > - > > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > > -g_simple_async_result_complete_in_idle(simple); > > +g_task_return_boolean(task, TRUE); > > } > > > > static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio > > *audio, > > @@ -594,14 +587,9 @@ static gboolean > > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > > gboolean lmute; > > gdouble vol; > > gboolean fake_channel = FALSE; > > -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; > > - > > -g_return_val_if_fail(g_simple_async_result_is_valid(res, > > -G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), > > FALSE); > > +GTask *task = G_TASK(res); > > > > -if (g_simple_async_result_propagate_error(simple, error)) { > > -return FALSE; > > -} > > +g_return_val_if_fail(g_task_is_valid(task, audio), FALSE); > > > I would keep a > if (g_task_had_error(task)) { > return g_task_propage_error(task, error); > } > > to avoid trying to do a lot of things when there had been an error. > > > if (p->playback.sink == NULL || p->playback.channels == 0) { > > SPICE_DEBUG("PlaybackChannel not created yet, force start"); > > @@ -647,7 +635,7 @@ static gboolean > > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > > } > > } > > > > -return g_simple_async_result_get_op_res_gboolean(simple); > > +return g_task_propagate_boolean(task, error); > > } > > > > static void spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, > > @@ -656,16 +644,9 @@ static void > > spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, > > > > GAsyncReadyCallback callback, > > gpointer user_data) > > { > > -GSimpleAsyncResult *simple; > > - > > -simple = g_simple_async_result_new(G_OBJECT(audio), > > - callback, > > - user_data, > > - > > spice_gstaudio_get_record_volume_info_async); > > -g_simple_async_result_set_check_cancellable (simple, cancellable); > > +GTask *task = g_task_new(audio, cancellable, callback, user_data); > > > > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > > -g_simple_async_result_complete_in_idle(simple); > > +g_task_return_boolean(task, TRUE); > > } > > > > static gboolean spice_gstaudio_get_record_volume_info_finish(SpiceAudio > > *audio, > > @@ -680,18 +661,9 @@ static gboolean > > spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, > > gboolean lmute; > > gdouble vol; > > gboolean fake_channel = FALSE; > > -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; > > +GTask *task = G_TASK(res); > > > > -g_return_val_if_fail(g_simple_async_result_is_valid(res, > > -G_OBJECT(audio), spice_gstaudio_get_record_volume_info_async), > > FALSE); > > - > > -if (g_simple_async_result_propagate_error(simple, error)) { > > -/* set out args that should have new alloc'ed memory to NULL */ > > -if (volume != NULL) { > > -*volume = NULL; > > -} > > I would keep this too, I'm a bit surprised it's only done in the record > case and not in the playback case. Indeed, seems that it was forgotten in the playback case. Both calls from channel-main don't mess with the output arg if the function return FALSE but it is recommended to set to NULL. > > Christophe > > > -return FALSE; > > -} > > +
Re: [Spice-devel] [PATCH 10/14] usb-device-manager: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:46AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/usb-device-manager.c | 61 > > 1 file changed, 30 insertions(+), 31 deletions(-) > > diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c > index c62f56e..1840177 100644 > --- a/src/usb-device-manager.c > +++ b/src/usb-device-manager.c > @@ -1055,15 +1055,16 @@ static void > spice_usb_device_manager_channel_connect_cb( > GObject *gobject, GAsyncResult *channel_res, gpointer user_data) > { > SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(gobject); > -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(user_data); > +GTask *task = G_TASK(user_data); > GError *err = NULL; > > spice_usbredir_channel_connect_device_finish(channel, channel_res, &err); > -if (err) { > -g_simple_async_result_take_error(result, err); > -} > -g_simple_async_result_complete(result); > -g_object_unref(result); > +if (err) > +g_task_return_error(task, err); > +else > +g_task_return_boolean(task, TRUE); > + > +g_object_unref(task); > } > > #ifdef G_OS_WIN32 > @@ -1229,7 +1230,7 @@ static void > spice_usb_device_manager_check_redir_on_connect( > SpiceUsbDeviceManager *self, SpiceChannel *channel) > { > SpiceUsbDeviceManagerPrivate *priv = self->priv; > -GSimpleAsyncResult *result; > +GTask *task; > SpiceUsbDevice *device; > libusb_device *libdev; > guint i; > @@ -1254,15 +1255,19 @@ static void > spice_usb_device_manager_check_redir_on_connect( > libdev, 0) == 0) { > /* Note: re-uses spice_usb_device_manager_connect_device_async's > completion handling code! */ > -result = g_simple_async_result_new(G_OBJECT(self), > - spice_usb_device_manager_auto_connect_cb, > - spice_usb_device_ref(device), > - > spice_usb_device_manager_connect_device_async); > +task = g_task_new(self, > + NULL, > + spice_usb_device_manager_auto_connect_cb, > + spice_usb_device_ref(device)); > + > +g_task_set_source_tag(task, > + spice_usb_device_manager_connect_device_async); > + I don't think this is used. Acked-by: Christophe Fergeau Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 08/14] spice-pulse: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:44AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/spice-pulse.c | 96 > +++ > 1 file changed, 33 insertions(+), 63 deletions(-) > > diff --git a/src/spice-pulse.c b/src/spice-pulse.c > index 22db893..60a037c 100644 > --- a/src/spice-pulse.c > +++ b/src/spice-pulse.c > @@ -34,13 +34,12 @@ > struct async_task { > SpicePulse *pulse; > SpiceMainChannel *main_channel; > -GSimpleAsyncResult *res; > +GTask *task; > GAsyncReadyCallbackcallback; > gpointer user_data; > gboolean is_playback; > pa_operation *pa_op; > gulong cancel_id; > -GCancellable *cancellable; > }; > > struct stream { > @@ -941,8 +940,8 @@ static gboolean free_async_task(gpointer user_data) > g_object_unref(task->pulse); > } > > -if (task->res) > -g_object_unref(task->res); > +if (task->task) > +g_object_unref(task->task); > > if (task->main_channel) > g_object_unref(task->main_channel); > @@ -950,10 +949,9 @@ static gboolean free_async_task(gpointer user_data) > if (task->pa_op != NULL) > pa_operation_unref(task->pa_op); > > -if (task->cancel_id != 0) { > -g_cancellable_disconnect(task->cancellable, task->cancel_id); > -g_clear_object(&task->cancellable); > -} > +if (task->cancel_id != 0) > +g_cancellable_disconnect(g_task_get_cancellable(task->task), > + task->cancel_id); You need to move the g_object_unref(task->task) after this. > > g_free(task); > return G_SOURCE_REMOVE; > @@ -981,14 +979,6 @@ static void cancel_task(GCancellable *cancellable, > gpointer user_data) > task->pulse->priv->pending_restore_task = NULL; > } > > -#if !GLIB_CHECK_VERSION(2,32,0) > -/* g_simple_async_result_set_check_cancellable is not present. Set an > error > - * in the GSimpleAsyncResult in case of _finish functions is called */ > -g_simple_async_result_set_error(task->res, > -SPICE_CLIENT_ERROR, > -SPICE_CLIENT_ERROR_FAILED, > -"Operation was cancelled"); > -#endif > /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=705395 > * Free the memory in idle */ > g_idle_add(free_async_task, task); > @@ -1001,27 +991,23 @@ static void complete_task(SpicePulse *pulse, struct > async_task *task, const gcha > > /* If we do have any err_msg, we failed */ > if (err_msg != NULL) { > -g_simple_async_result_set_op_res_gboolean(task->res, FALSE); > -g_simple_async_result_set_error(task->res, > -SPICE_CLIENT_ERROR, > -SPICE_CLIENT_ERROR_FAILED, > -"restore-info failed due %s", > -err_msg); > +g_task_return_boolean(task->task, FALSE); This can be removed. > +g_task_return_new_error(task->task, > +SPICE_CLIENT_ERROR, > +SPICE_CLIENT_ERROR_FAILED, > +"restore-info failed due %s", > +err_msg); > /* Volume-info does not change if stream is not found */ > } else if ((task->is_playback == TRUE && p->playback.info_updated == > FALSE) || > (task->is_playback == FALSE && p->record.info_updated == > FALSE)) { > -g_simple_async_result_set_op_res_gboolean(task->res, FALSE); > -g_simple_async_result_set_error(task->res, > -SPICE_CLIENT_ERROR, > -SPICE_CLIENT_ERROR_FAILED, > -"Stream not found by pulse"); > +g_task_return_boolean(task->task, FALSE); This can be removed too. > +g_task_return_new_error(task->task, > +SPICE_CLIENT_ERROR, > +SPICE_CLIENT_ERROR_FAILED, > +"Stream not found by pulse"); > } else { > -g_simple_async_result_set_op_res_gboolean(task->res, TRUE); > +g_task_return_boolean(task->task, TRUE); > } > - > -/* As all async calls to PulseAudio are done with glib mainloop, it is > - * safe to complete the operation synchronously here. */ > -g_simple_async_result_complete(task->res); > } > > static void spice_pulse_complete_async_task(struct async_task *task, const > gchar *err_msg) > @@ -1157,19 +1143,13 @@ static void pulse_stream_restore_info_async(gboolean
Re: [Spice-devel] [PATCH 07/14] spice-gstaudio: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:43AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/spice-gstaudio.c | 48 ++-- > 1 file changed, 10 insertions(+), 38 deletions(-) > > diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c > index 096fea4..65fc173 100644 > --- a/src/spice-gstaudio.c > +++ b/src/spice-gstaudio.c > @@ -570,16 +570,9 @@ static void > spice_gstaudio_get_playback_volume_info_async(SpiceAudio *audio, > > GAsyncReadyCallback callback, >gpointer user_data) > { > -GSimpleAsyncResult *simple; > +GTask *task = g_task_new(audio, cancellable, callback, user_data); > > -simple = g_simple_async_result_new(G_OBJECT(audio), > - callback, > - user_data, > - > spice_gstaudio_get_playback_volume_info_async); > -g_simple_async_result_set_check_cancellable (simple, cancellable); > - > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > -g_simple_async_result_complete_in_idle(simple); > +g_task_return_boolean(task, TRUE); > } > > static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio > *audio, > @@ -594,14 +587,9 @@ static gboolean > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > gboolean lmute; > gdouble vol; > gboolean fake_channel = FALSE; > -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; > - > -g_return_val_if_fail(g_simple_async_result_is_valid(res, > -G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), > FALSE); > +GTask *task = G_TASK(res); > > -if (g_simple_async_result_propagate_error(simple, error)) { > -return FALSE; > -} > +g_return_val_if_fail(g_task_is_valid(task, audio), FALSE); I would keep a if (g_task_had_error(task)) { return g_task_propage_error(task, error); } to avoid trying to do a lot of things when there had been an error. > if (p->playback.sink == NULL || p->playback.channels == 0) { > SPICE_DEBUG("PlaybackChannel not created yet, force start"); > @@ -647,7 +635,7 @@ static gboolean > spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio > } > } > > -return g_simple_async_result_get_op_res_gboolean(simple); > +return g_task_propagate_boolean(task, error); > } > > static void spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, > @@ -656,16 +644,9 @@ static void > spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, > GAsyncReadyCallback > callback, > gpointer user_data) > { > -GSimpleAsyncResult *simple; > - > -simple = g_simple_async_result_new(G_OBJECT(audio), > - callback, > - user_data, > - > spice_gstaudio_get_record_volume_info_async); > -g_simple_async_result_set_check_cancellable (simple, cancellable); > +GTask *task = g_task_new(audio, cancellable, callback, user_data); > > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > -g_simple_async_result_complete_in_idle(simple); > +g_task_return_boolean(task, TRUE); > } > > static gboolean spice_gstaudio_get_record_volume_info_finish(SpiceAudio > *audio, > @@ -680,18 +661,9 @@ static gboolean > spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, > gboolean lmute; > gdouble vol; > gboolean fake_channel = FALSE; > -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; > +GTask *task = G_TASK(res); > > -g_return_val_if_fail(g_simple_async_result_is_valid(res, > -G_OBJECT(audio), spice_gstaudio_get_record_volume_info_async), > FALSE); > - > -if (g_simple_async_result_propagate_error(simple, error)) { > -/* set out args that should have new alloc'ed memory to NULL */ > -if (volume != NULL) { > -*volume = NULL; > -} I would keep this too, I'm a bit surprised it's only done in the record case and not in the playback case. Christophe > -return FALSE; > -} > +g_return_val_if_fail(g_task_is_valid(task, audio), FALSE); > > if (p->record.src == NULL || p->record.channels == 0) { > SPICE_DEBUG("RecordChannel not created yet, force start"); > @@ -737,5 +709,5 @@ static gboolean > spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, > } > } > > -return g_simple_async_result_get_op_res_gboolean(simple); > +return g_task_propagate_boolean(task, error); > } > -- > 2.5.0 > > __
Re: [Spice-devel] [PATCH 06/14] spice-channel: Use GTask instead of GSimpleAsyncResult
Acked-by: Christophe Fergeau On Mon, Jan 18, 2016 at 10:05:42AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/spice-channel.c | 32 +--- > 1 file changed, 13 insertions(+), 19 deletions(-) > > diff --git a/src/spice-channel.c b/src/spice-channel.c > index ff85715..dd32818 100644 > --- a/src/spice-channel.c > +++ b/src/spice-channel.c > @@ -2124,9 +2124,7 @@ static void spice_channel_flushed(SpiceChannel > *channel, gboolean success) > GSList *l; > > for (l = c->flushing; l != NULL; l = l->next) { > -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(l->data); > -g_simple_async_result_set_op_res_gboolean(result, success); > -g_simple_async_result_complete_in_idle(result); > +g_task_return_boolean(G_TASK(l->data), success); > } > > g_slist_free_full(c->flushing, g_object_unref); > @@ -2970,7 +2968,7 @@ static void > spice_channel_send_migration_handshake(SpiceChannel *channel) > void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable, > GAsyncReadyCallback callback, gpointer > user_data) > { > -GSimpleAsyncResult *simple; > +GTask *task; > SpiceChannelPrivate *c; > gboolean was_empty; > > @@ -2978,26 +2976,25 @@ void spice_channel_flush_async(SpiceChannel *self, > GCancellable *cancellable, > c = self->priv; > > if (c->state != SPICE_CHANNEL_STATE_READY) { > -g_simple_async_report_error_in_idle(G_OBJECT(self), callback, > user_data, > +g_task_report_new_error(self, callback, user_data, > +spice_channel_flush_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "The channel is not ready yet"); > return; > } > > -simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, > - spice_channel_flush_async); > +task = g_task_new(self, cancellable, callback, user_data); > > STATIC_MUTEX_LOCK(c->xmit_queue_lock); > was_empty = g_queue_is_empty(&c->xmit_queue); > STATIC_MUTEX_UNLOCK(c->xmit_queue_lock); > if (was_empty) { > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > -g_simple_async_result_complete_in_idle(simple); > -g_object_unref(simple); > +g_task_return_boolean(task, TRUE); > +g_object_unref(task); > return; > } > > -c->flushing = g_slist_append(c->flushing, simple); > +c->flushing = g_slist_append(c->flushing, task); > } > > /** > @@ -3015,19 +3012,16 @@ void spice_channel_flush_async(SpiceChannel *self, > GCancellable *cancellable, > gboolean spice_channel_flush_finish(SpiceChannel *self, GAsyncResult *result, > GError **error) > { > -GSimpleAsyncResult *simple; > +GTask *task; > > g_return_val_if_fail(SPICE_IS_CHANNEL(self), FALSE); > g_return_val_if_fail(result != NULL, FALSE); > > -simple = (GSimpleAsyncResult *)result; > +task = G_TASK(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_channel_flush_async), FALSE); > +g_return_val_if_fail(g_task_is_valid(task, self), > + FALSE); > > CHANNEL_DEBUG(self, "flushed finished!"); > -return g_simple_async_result_get_op_res_gboolean(simple); > +return g_task_propagate_boolean(task, error); > } > -- > 2.5.0 > > ___ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] RFC: drop spice-gtk gtk+ 2.0 support
Hi - Original Message - > On Mon, Dec 21, 2015 at 4:54 PM, Marc-André Lureau > wrote: > > Hi, > > > > With virt-viewer now dropping gtk 2.0, I don't know anyone left using > > the spice-gtk with gtk+ 2.0. Thus I'd like to propose that the next > > spice-gtk release be the last with 2.0 support. fwiw, I also have a branch ready for a while. I'd like to see first local virgl support with gtk+2.0 released. Then switching to gtk3/gtkglarea to support wayland will be easier. cheers ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] RFC: drop spice-gtk gtk+ 2.0 support
On Mon, Jan 18, 2016 at 02:07:49PM +0100, Fabiano Fidêncio wrote: > On Mon, Dec 21, 2015 at 4:54 PM, Marc-André Lureau > wrote: > > Hi, > > > > With virt-viewer now dropping gtk 2.0, I don't know anyone left using > > the spice-gtk with gtk+ 2.0. Thus I'd like to propose that the next > > spice-gtk release be the last with 2.0 support. > > > > Comments? > > I completely agree with this. > I already have been working on a patch dropping the support and I will > submit it as soon we do the last release with gtk2 support. virt-manager is already gtk3 only too, as is GNOME boxes, so I doubt that there's any mainstream user of spice-gtk with gtk2, and if there was they can stick on an older maint branch if really needed Regards, Daniel -- |: http://berrange.com -o-http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] RFC: drop spice-gtk gtk+ 2.0 support
On Mon, Dec 21, 2015 at 4:54 PM, Marc-André Lureau wrote: > Hi, > > With virt-viewer now dropping gtk 2.0, I don't know anyone left using > the spice-gtk with gtk+ 2.0. Thus I'd like to propose that the next > spice-gtk release be the last with 2.0 support. > > Comments? I completely agree with this. I already have been working on a patch dropping the support and I will submit it as soon we do the last release with gtk2 support. Best Regards, -- Fabiano Fidêncio ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH] Change some functions to take RedsState arg
On Mon, 2016-01-18 at 06:07 -0500, Frediano Ziglio wrote: > > > > From: Jonathon Jongsma > > > > In preparation for getting rid of the global 'reds' variable, we > > need to > > pass the RedsState variable to all functions where it is needed. > > For now > > the callers just pass in the global reds variable. > > > > Functions changed: > > - reds_register_channel; > > - reds_unregister_channel; > > - reds_get_mouse_mode; > > - reds_set_mouse_mode; > > - reds_update_mouse_mode; > > - reds_agent_remove; > > - reds_find_channel; > > - reds_mig_cleanup; > > - reds_reset_vdp; > > - reds_main_channel_connected; > > - reds_client_disconnect; > > - reds_disconnect; > > - reds_mig_disconnect. > > > > Acked-by: Frediano Ziglio > > Does it sound reasonable as comment and patch (just a squash of > posted ones)? Yes, it does. It is a simple change Acked-by: Pavel Grunt Pavel > Should I number the title? > > Frediano > > > --- > > server/inputs-channel.c | 10 ++--- > > server/main-dispatcher.c | 2 +- > > server/red-dispatcher.c | 4 +- > > server/reds.c| 104 > > +++ > > server/reds.h| 8 ++-- > > server/smartcard.c | 2 +- > > server/sound.c | 6 +-- > > server/spicevmc.c| 4 +- > > 8 files changed, 70 insertions(+), 70 deletions(-) > > > > diff --git a/server/inputs-channel.c b/server/inputs-channel.c > > index c21cab8..bb5b203 100644 > > --- a/server/inputs-channel.c > > +++ b/server/inputs-channel.c > > @@ -364,7 +364,7 @@ static int > > inputs_channel_handle_parsed(RedChannelClient > > *rcc, uint32_t size, ui > > red_channel_client_pipe_add_type(rcc, > > PIPE_ITEM_MOUSE_MOTION_ACK); > > icc->motion_count = 0; > > } > > -if (mouse && reds_get_mouse_mode() == > > SPICE_MOUSE_MODE_SERVER) { > > +if (mouse && reds_get_mouse_mode(reds) == > > SPICE_MOUSE_MODE_SERVER) { > > SpiceMouseInterface *sif; > > sif = SPICE_CONTAINEROF(mouse->base.sif, > > SpiceMouseInterface, > > base); > > sif->motion(mouse, > > @@ -381,7 +381,7 @@ static int > > inputs_channel_handle_parsed(RedChannelClient > > *rcc, uint32_t size, ui > > red_channel_client_pipe_add_type(rcc, > > PIPE_ITEM_MOUSE_MOTION_ACK); > > icc->motion_count = 0; > > } > > -if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) { > > +if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) > > { > > break; > > } > > spice_assert((reds_get_agent_mouse() && > > reds_has_vdagent()) || > > tablet); > > @@ -407,7 +407,7 @@ static int > > inputs_channel_handle_parsed(RedChannelClient > > *rcc, uint32_t size, ui > > } else if (mouse_press->button == SPICE_MOUSE_BUTTON_DOWN) > > { > > dz = 1; > > } > > -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { > > +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) > > { > > if (reds_get_agent_mouse() && reds_has_vdagent()) { > > inputs_channel->mouse_state.buttons = > > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press- > > >buttons_state) > > | > > @@ -429,7 +429,7 @@ static int > > inputs_channel_handle_parsed(RedChannelClient > > *rcc, uint32_t size, ui > > } > > case SPICE_MSGC_INPUTS_MOUSE_RELEASE: { > > SpiceMsgcMouseRelease *mouse_release = message; > > -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { > > +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) > > { > > if (reds_get_agent_mouse() && reds_has_vdagent()) { > > inputs_channel->mouse_state.buttons = > > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release- > > >buttons_state); > > @@ -672,7 +672,7 @@ void inputs_init(void) > > red_channel_register_client_cbs(&g_inputs_channel->base, > > &client_cbs); > > > > red_channel_set_cap(&g_inputs_channel->base, > > SPICE_INPUTS_CAP_KEY_SCANCODE); > > -reds_register_channel(&g_inputs_channel->base); > > +reds_register_channel(reds, &g_inputs_channel->base); > > > > if (!(key_modifiers_timer = core->timer_add(core, > > key_modifiers_sender, > > NULL))) { > > spice_error("key modifiers timer create failed"); > > diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c > > index 2cb53ef..db87e05 100644 > > --- a/server/main-dispatcher.c > > +++ b/server/main-dispatcher.c > > @@ -136,7 +136,7 @@ static void > > main_dispatcher_handle_client_disconnect(void > > *opaque, > > MainDispatcherClientDisconnectMessage *msg = payload; > > > > spice_debug("client=%p", msg->client); > > -reds_client_disconnect(msg->client); > > +reds_client_disconnect(reds, msg->client); > > red_client_unref(msg->client); > > }
Re: [Spice-devel] [PATCH spice v2 3/4] dcc: make dcc_compress_image_*() private
Hi, Looks good Reviewed-by: Victor Toso On Fri, Jan 15, 2016 at 05:11:34PM +0100, Pavel Grunt wrote: > --- > server/dcc.c | 30 +++--- > server/dcc.h | 15 --- > 2 files changed, 15 insertions(+), 30 deletions(-) > > diff --git a/server/dcc.c b/server/dcc.c > index 097140a..9b65031 100644 > --- a/server/dcc.c > +++ b/server/dcc.c > @@ -646,9 +646,9 @@ static const LzImageType bitmap_fmt_to_lz_image_type[] = { > > #define MIN_GLZ_SIZE_FOR_ZLIB 100 > > -int dcc_compress_image_glz(DisplayChannelClient *dcc, > - SpiceImage *dest, SpiceBitmap *src, Drawable > *drawable, > - compress_send_data_t* o_comp_data) > +static int dcc_compress_image_glz(DisplayChannelClient *dcc, > + SpiceImage *dest, SpiceBitmap *src, > Drawable *drawable, > + compress_send_data_t* o_comp_data) > { > DisplayChannel *display_channel = DCC_TO_DC(dcc); > stat_start_time_t start_time; > @@ -723,9 +723,9 @@ glz: > return TRUE; > } > > -int dcc_compress_image_lz(DisplayChannelClient *dcc, > - SpiceImage *dest, SpiceBitmap *src, > - compress_send_data_t* o_comp_data, uint32_t > group_id) > +static int dcc_compress_image_lz(DisplayChannelClient *dcc, > + SpiceImage *dest, SpiceBitmap *src, > + compress_send_data_t* o_comp_data, uint32_t > group_id) > { > LzData *lz_data = &dcc->lz_data; > LzContext *lz = dcc->lz; > @@ -785,9 +785,9 @@ int dcc_compress_image_lz(DisplayChannelClient *dcc, > return TRUE; > } > > -int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage *dest, > -SpiceBitmap *src, compress_send_data_t* > o_comp_data, > -uint32_t group_id) > +static int dcc_compress_image_jpeg(DisplayChannelClient *dcc, SpiceImage > *dest, > + SpiceBitmap *src, compress_send_data_t* > o_comp_data, > + uint32_t group_id) > { > JpegData *jpeg_data = &dcc->jpeg_data; > LzData *lz_data = &dcc->lz_data; > @@ -910,9 +910,9 @@ int dcc_compress_image_jpeg(DisplayChannelClient *dcc, > SpiceImage *dest, > } > > #ifdef USE_LZ4 > -int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage *dest, > - SpiceBitmap *src, compress_send_data_t* > o_comp_data, > - uint32_t group_id) > +static int dcc_compress_image_lz4(DisplayChannelClient *dcc, SpiceImage > *dest, > + SpiceBitmap *src, compress_send_data_t* > o_comp_data, > + uint32_t group_id) > { > Lz4Data *lz4_data = &dcc->lz4_data; > Lz4EncoderContext *lz4 = dcc->lz4; > @@ -957,9 +957,9 @@ int dcc_compress_image_lz4(DisplayChannelClient *dcc, > SpiceImage *dest, > } > #endif > > -int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage *dest, > -SpiceBitmap *src, compress_send_data_t* > o_comp_data, > -uint32_t group_id) > +static int dcc_compress_image_quic(DisplayChannelClient *dcc, SpiceImage > *dest, > + SpiceBitmap *src, compress_send_data_t* > o_comp_data, > + uint32_t group_id) > { > QuicData *quic_data = &dcc->quic_data; > QuicContext *quic = dcc->quic; > diff --git a/server/dcc.h b/server/dcc.h > index 2a12226..f715792 100644 > --- a/server/dcc.h > +++ b/server/dcc.h > @@ -219,20 +219,5 @@ intdcc_compress_image > (DisplayCha > > SpiceImage *dest, SpiceBitmap *src, Drawable *drawable, >int > can_lossy, > > compress_send_data_t* o_comp_data); > -intdcc_compress_image_glz > (DisplayChannelClient *dcc, > - > SpiceImage *dest, SpiceBitmap *src, Drawable *drawable, > - > compress_send_data_t* o_comp_data); > -intdcc_compress_image_lz > (DisplayChannelClient *dcc, > - > SpiceImage *dest, SpiceBitmap *src, > - > compress_send_data_t* o_comp_data, uint32_t group_id); > -intdcc_compress_image_jpeg > (DisplayChannelClient *dcc, SpiceImage *dest, > -
Re: [Spice-devel] [PATCH spice v2 2/4] dcc-send: Use dcc_compress_image to compress image
Hi, On Fri, Jan 15, 2016 at 05:11:33PM +0100, Pavel Grunt wrote: > --- > server/dcc-send.c | 44 +++- > 1 file changed, 3 insertions(+), 41 deletions(-) > > diff --git a/server/dcc-send.c b/server/dcc-send.c > index c3f79ef..58e654e 100644 > --- a/server/dcc-send.c > +++ b/server/dcc-send.c > @@ -1920,20 +1920,14 @@ static void red_marshall_image(RedChannelClient *rcc, > SpiceMarshaller *m, ImageI > DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > DisplayChannel *display = DCC_TO_DC(dcc); > SpiceImage red_image; > -RedWorker *worker; > SpiceBitmap bitmap; > SpiceChunks *chunks; > QRegion *surface_lossy_region; > -int comp_succeeded = FALSE; > -int lossy_comp = FALSE; > -int quic_comp = FALSE; > -SpiceImageCompression comp_mode; > SpiceMsgDisplayDrawCopy copy; > SpiceMarshaller *src_bitmap_out, *mask_bitmap_out; > SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out; > > spice_assert(rcc && display && item); > -worker = display->common.worker; > > QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, > display_channel_generate_uid(display)); > red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP; > @@ -1981,44 +1975,12 @@ static void red_marshall_image(RedChannelClient *rcc, > SpiceMarshaller *m, ImageI > > compress_send_data_t comp_send_data = {0}; > > -comp_mode = dcc->image_compression; > - > -if (((comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_LZ) || > -(comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) && > !bitmap_has_extra_stride(&bitmap)) { > - > -if (bitmap_fmt_has_graduality(item->image_format)) { > -BitmapGradualType grad_level; > - > -grad_level = bitmap_get_graduality_level(&bitmap); > -if (grad_level == BITMAP_GRADUAL_HIGH) { > -// if we use lz for alpha, the stride can't be extra > -lossy_comp = display->enable_jpeg && item->can_lossy; > -quic_comp = TRUE; > -} > -} > -} else if (comp_mode == SPICE_IMAGE_COMPRESSION_QUIC) { > -quic_comp = TRUE; > -} > - > -uint32_t groupid = red_worker_get_memslot(worker)->internal_groupslot_id; > - > -if (lossy_comp) { > -comp_succeeded = dcc_compress_image_jpeg(dcc, &red_image, &bitmap, > &comp_send_data, groupid); > -} else if (quic_comp) { > -comp_succeeded = dcc_compress_image_quic(dcc, &red_image, &bitmap, > &comp_send_data, groupid); > -#ifdef USE_LZ4 > -} else if (comp_mode == SPICE_IMAGE_COMPRESSION_LZ4 && > - bitmap_fmt_is_rgb(bitmap.format) && > - red_channel_client_test_remote_cap(&dcc->common.base, > - > SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) { > -comp_succeeded = dcc_compress_image_lz4(dcc, &red_image, &bitmap, > &comp_send_data, groupid); > -#endif > -} else if (comp_mode != SPICE_IMAGE_COMPRESSION_OFF) { > -comp_succeeded = dcc_compress_image_lz(dcc, &red_image, &bitmap, > &comp_send_data, groupid); > -} > +int comp_succeeded = dcc_compress_image(dcc, &red_image, &bitmap, NULL, > item->can_lossy, &comp_send_data); > > surface_lossy_region = > &dcc->surface_client_lossy_region[item->surface_id]; > if (comp_succeeded) { > +int lossy_comp = red_image.descriptor.type == SPICE_IMAGE_TYPE_JPEG > || > + red_image.descriptor.type == > SPICE_IMAGE_TYPE_JPEG_ALPHA; This is not explained.. so, dcc_compress_image takes it->can_lossy but you need to verify it in the end. Maybe a helper function would be more clear? > spice_marshall_Image(src_bitmap_out, &red_image, > &bitmap_palette_out, &lzplt_palette_out); > > -- > 2.5.0 > > ___ > Spice-devel mailing list > Spice-devel@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/spice-devel ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH spice v2 1/4] dcc_compress_image: Handle NULL drawable
Hi, On Fri, Jan 15, 2016 at 05:11:32PM +0100, Pavel Grunt wrote: > --- > server/dcc.c | 38 +- > 1 file changed, 21 insertions(+), 17 deletions(-) The drawable being NULL only start to happen in the next patch, right? It might be worth to mention it. Also, if drawable is NULL it is either quic or lz/lz4, is that right? Patch looks good otherwise > > diff --git a/server/dcc.c b/server/dcc.c > index 2568e24..097140a 100644 > --- a/server/dcc.c > +++ b/server/dcc.c > @@ -1037,6 +1037,7 @@ int dcc_compress_image(DisplayChannelClient *dcc, > DisplayChannel *display_channel = DCC_TO_DC(dcc); > SpiceImageCompression image_compression = dcc->image_compression; > int quic_compress = FALSE; > +uint32_t group_id; > > if ((image_compression == SPICE_IMAGE_COMPRESSION_OFF) || > ((src->y * src->stride) < MIN_SIZE_TO_COMPRESS)) { // TODO: change > the size cond > @@ -1067,7 +1068,8 @@ int dcc_compress_image(DisplayChannelClient *dcc, > if ((src->x < MIN_DIMENSION_TO_QUIC) || (src->y < > MIN_DIMENSION_TO_QUIC)) { > quic_compress = FALSE; > } else { > -if (drawable->copy_bitmap_graduality == > BITMAP_GRADUAL_INVALID) { > +if (drawable == NULL || > +drawable->copy_bitmap_graduality == > BITMAP_GRADUAL_INVALID) { > quic_compress = > bitmap_fmt_has_graduality(src->format) && > bitmap_get_graduality_level(src) == > BITMAP_GRADUAL_HIGH; > } else { > @@ -1080,6 +1082,12 @@ int dcc_compress_image(DisplayChannelClient *dcc, > } > } > > +if (drawable != NULL) { > +group_id = drawable->group_id; > +} else { > +group_id = > red_worker_get_memslot(display_channel->common.worker)->internal_groupslot_id; > +} > + > if (quic_compress) { > #ifdef COMPRESS_DEBUG > spice_info("QUIC compress"); > @@ -1090,24 +1098,22 @@ int dcc_compress_image(DisplayChannelClient *dcc, > (image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ))) { > // if we use lz for alpha, the stride can't be extra > if (src->format != SPICE_BITMAP_FMT_RGBA || > !bitmap_has_extra_stride(src)) { > -return dcc_compress_image_jpeg(dcc, dest, > - src, o_comp_data, > drawable->group_id); > +return dcc_compress_image_jpeg(dcc, dest, src, o_comp_data, > group_id); > } > } > -return dcc_compress_image_quic(dcc, dest, > - src, o_comp_data, drawable->group_id); > +return dcc_compress_image_quic(dcc, dest, src, o_comp_data, > group_id); > } else { > int glz; > int ret; > -if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) || > -(image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) { > -glz = bitmap_fmt_has_graduality(src->format) && ( > -(src->x * src->y) < glz_enc_dictionary_get_size( > -dcc->glz_dict->dict)); > -} else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) || > - (image_compression == SPICE_IMAGE_COMPRESSION_LZ) || > - (image_compression == SPICE_IMAGE_COMPRESSION_LZ4)) { > +if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_LZ) || > +(image_compression == SPICE_IMAGE_COMPRESSION_LZ) || > +(image_compression == SPICE_IMAGE_COMPRESSION_LZ4) || > +drawable == NULL) { > glz = FALSE; > +} else if ((image_compression == SPICE_IMAGE_COMPRESSION_AUTO_GLZ) || > + (image_compression == SPICE_IMAGE_COMPRESSION_GLZ)) { > +glz = bitmap_fmt_has_graduality(src->format) && > + ((src->x * src->y) < > glz_enc_dictionary_get_size(dcc->glz_dict->dict)); > } else { > spice_error("invalid image compression type %u", > image_compression); > return FALSE; > @@ -1132,12 +1138,10 @@ int dcc_compress_image(DisplayChannelClient *dcc, > bitmap_fmt_is_rgb(src->format) && > red_channel_client_test_remote_cap(&dcc->common.base, > SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) { > -ret = dcc_compress_image_lz4(dcc, dest, src, o_comp_data, > - drawable->group_id); > +ret = dcc_compress_image_lz4(dcc, dest, src, o_comp_data, > group_id); > } else > #endif > -ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data, > -drawable->group_id); > +ret = dcc_compress_image_lz(dcc, dest, src, o_comp_data, > group_id); > #ifdef COMPRESS_DEBUG > spice_info("LZ LOC
[Spice-devel] [client v9 22/24] spice-gtk: Probe GStreamer before advertising support for a codec
Signed-off-by: Francois Gouget --- src/channel-display-gst.c | 17 +++-- src/channel-display-priv.h | 4 ++-- src/channel-display.c | 21 + 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c index c5ad2e9..7b7d0eb 100644 --- a/src/channel-display-gst.c +++ b/src/channel-display-gst.c @@ -204,8 +204,7 @@ static uint8_t* gst_decoder_decode_frame(VideoDecoder *video_decoder, return NULL; } -G_GNUC_INTERNAL -gboolean gstvideo_init(void) +static gboolean gstvideo_init(void) { static int success = 0; if (!success) { @@ -236,3 +235,17 @@ VideoDecoder* create_gstreamer_decoder(int codec_type, display_stream *stream) return (VideoDecoder*)decoder; } + +G_GNUC_INTERNAL +gboolean gstvideo_has_codec(int codec_type) +{ +gboolean has_codec = FALSE; + +VideoDecoder *decoder = create_gstreamer_decoder(codec_type, NULL); +if (decoder) { +has_codec = construct_pipeline((SpiceGstDecoder*)decoder); +decoder->destroy(decoder); +} + +return has_codec; +} diff --git a/src/channel-display-priv.h b/src/channel-display-priv.h index 2c64eb4..fee1047 100644 --- a/src/channel-display-priv.h +++ b/src/channel-display-priv.h @@ -70,9 +70,9 @@ VideoDecoder* create_mjpeg_decoder(int codec_type, display_stream *stream); #endif #ifdef HAVE_GSTVIDEO VideoDecoder* create_gstreamer_decoder(int codec_type, display_stream *stream); -gboolean gstvideo_init(void); +gboolean gstvideo_has_codec(int codec_type); #else -# define gstvideo_init() FALSE +# define gstvideo_has_codec(codec_type) FALSE #endif diff --git a/src/channel-display.c b/src/channel-display.c index 193f177..4a998b4 100644 --- a/src/channel-display.c +++ b/src/channel-display.c @@ -632,10 +632,23 @@ static void spice_display_channel_reset_capabilities(SpiceChannel *channel) #ifdef HAVE_BUILTIN_MJPEG spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_MJPEG); #endif -if (gstvideo_init()) { -spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_MJPEG); -spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_VP8); -spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_H264); +if (gstvideo_has_codec(SPICE_VIDEO_CODEC_TYPE_MJPEG)) { +spice_channel_set_capability(SPICE_CHANNEL(channel), + SPICE_DISPLAY_CAP_CODEC_MJPEG); +} else { +spice_info("GStreamer does not support the mjpeg codec"); +} +if (gstvideo_has_codec(SPICE_VIDEO_CODEC_TYPE_VP8)) { +spice_channel_set_capability(SPICE_CHANNEL(channel), + SPICE_DISPLAY_CAP_CODEC_VP8); +} else { +spice_info("GStreamer does not support the vp8 codec"); +} +if (gstvideo_has_codec(SPICE_VIDEO_CODEC_TYPE_H264)) { +spice_channel_set_capability(SPICE_CHANNEL(channel), + SPICE_DISPLAY_CAP_CODEC_H264); +} else { +spice_info("GStreamer does not support the h264 codec"); } } -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH] Change some functions to take RedsState arg
> > From: Jonathon Jongsma > > In preparation for getting rid of the global 'reds' variable, we need to > pass the RedsState variable to all functions where it is needed. For now > the callers just pass in the global reds variable. > > Functions changed: > - reds_register_channel; > - reds_unregister_channel; > - reds_get_mouse_mode; > - reds_set_mouse_mode; > - reds_update_mouse_mode; > - reds_agent_remove; > - reds_find_channel; > - reds_mig_cleanup; > - reds_reset_vdp; > - reds_main_channel_connected; > - reds_client_disconnect; > - reds_disconnect; > - reds_mig_disconnect. > > Acked-by: Frediano Ziglio Does it sound reasonable as comment and patch (just a squash of posted ones)? Should I number the title? Frediano > --- > server/inputs-channel.c | 10 ++--- > server/main-dispatcher.c | 2 +- > server/red-dispatcher.c | 4 +- > server/reds.c| 104 > +++ > server/reds.h| 8 ++-- > server/smartcard.c | 2 +- > server/sound.c | 6 +-- > server/spicevmc.c| 4 +- > 8 files changed, 70 insertions(+), 70 deletions(-) > > diff --git a/server/inputs-channel.c b/server/inputs-channel.c > index c21cab8..bb5b203 100644 > --- a/server/inputs-channel.c > +++ b/server/inputs-channel.c > @@ -364,7 +364,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > red_channel_client_pipe_add_type(rcc, > PIPE_ITEM_MOUSE_MOTION_ACK); > icc->motion_count = 0; > } > -if (mouse && reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) { > +if (mouse && reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_SERVER) { > SpiceMouseInterface *sif; > sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, > base); > sif->motion(mouse, > @@ -381,7 +381,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > red_channel_client_pipe_add_type(rcc, > PIPE_ITEM_MOUSE_MOTION_ACK); > icc->motion_count = 0; > } > -if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) { > +if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) { > break; > } > spice_assert((reds_get_agent_mouse() && reds_has_vdagent()) || > tablet); > @@ -407,7 +407,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > } else if (mouse_press->button == SPICE_MOUSE_BUTTON_DOWN) { > dz = 1; > } > -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { > +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { > if (reds_get_agent_mouse() && reds_has_vdagent()) { > inputs_channel->mouse_state.buttons = > > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) > | > @@ -429,7 +429,7 @@ static int inputs_channel_handle_parsed(RedChannelClient > *rcc, uint32_t size, ui > } > case SPICE_MSGC_INPUTS_MOUSE_RELEASE: { > SpiceMsgcMouseRelease *mouse_release = message; > -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { > +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { > if (reds_get_agent_mouse() && reds_has_vdagent()) { > inputs_channel->mouse_state.buttons = > > RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state); > @@ -672,7 +672,7 @@ void inputs_init(void) > red_channel_register_client_cbs(&g_inputs_channel->base, &client_cbs); > > red_channel_set_cap(&g_inputs_channel->base, > SPICE_INPUTS_CAP_KEY_SCANCODE); > -reds_register_channel(&g_inputs_channel->base); > +reds_register_channel(reds, &g_inputs_channel->base); > > if (!(key_modifiers_timer = core->timer_add(core, key_modifiers_sender, > NULL))) { > spice_error("key modifiers timer create failed"); > diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c > index 2cb53ef..db87e05 100644 > --- a/server/main-dispatcher.c > +++ b/server/main-dispatcher.c > @@ -136,7 +136,7 @@ static void main_dispatcher_handle_client_disconnect(void > *opaque, > MainDispatcherClientDisconnectMessage *msg = payload; > > spice_debug("client=%p", msg->client); > -reds_client_disconnect(msg->client); > +reds_client_disconnect(reds, msg->client); > red_client_unref(msg->client); > } > > diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c > index 0810798..dc958d9 100644 > --- a/server/red-dispatcher.c > +++ b/server/red-dispatcher.c > @@ -1044,7 +1044,7 @@ void red_dispatcher_init(QXLInstance *qxl) > client_cbs.migrate = red_dispatcher_cursor_migrate; > red_channel_register_client_cbs(channel, &client_cbs); > red_channel_set_data(channel, red_dispatcher); > -reds_register_c
[Spice-devel] [qxl v9 16/24] spiceqxl: Add SpiceVideoCodecs to specify video codec preferences
Signed-off-by: Francois Gouget --- examples/spiceqxl.xorg.conf.example | 7 +++ src/qxl.h | 1 + src/qxl_driver.c| 2 ++ src/spiceqxl_spice_server.c | 15 +++ 4 files changed, 25 insertions(+) diff --git a/examples/spiceqxl.xorg.conf.example b/examples/spiceqxl.xorg.conf.example index ec6321e..b6f4840 100644 --- a/examples/spiceqxl.xorg.conf.example +++ b/examples/spiceqxl.xorg.conf.example @@ -52,6 +52,13 @@ Section "Device" # default: filter #Option "SpiceStreamingVideo" "" +# Set video codecs to use. Provide a semicolon list of +# codecs, in preference order. Each codec requires an encoder +# which can be one of spice or gstreamer, and then a codec type, +# for instance mjpeg or vp8. The default is spice:mjpeg, +# which uses the builtin mjpeg encoder. +#Option "SpiceVideoCodecs" "" + # Set zlib glz wan compression. Options are auto, never, always. # default: auto #Option "SpiceZlibGlzWanCompression" "" diff --git a/src/qxl.h b/src/qxl.h index ff55604..5cc8d05 100644 --- a/src/qxl.h +++ b/src/qxl.h @@ -158,6 +158,7 @@ enum { OPTION_SURFACE_BUFFER_SIZE, OPTION_COMMAND_BUFFER_SIZE, OPTION_SPICE_SMARTCARD_FILE, +OPTION_SPICE_VIDEO_CODECS, #endif OPTION_COUNT, }; diff --git a/src/qxl_driver.c b/src/qxl_driver.c index e21addd..fc1b629 100644 --- a/src/qxl_driver.c +++ b/src/qxl_driver.c @@ -154,6 +154,8 @@ const OptionInfoRec DefaultOptions[] = "CommandBufferSize",OPTV_INTEGER, {DEFAULT_COMMAND_BUFFER_SIZE}, FALSE}, { OPTION_SPICE_SMARTCARD_FILE, "SpiceSmartcardFile", OPTV_STRING,{0}, FALSE}, +{ OPTION_SPICE_VIDEO_CODECS, + "SpiceVideoCodecs", OPTV_STRING,{0}, FALSE}, #endif { -1, NULL, OPTV_NONE, {0}, FALSE } diff --git a/src/spiceqxl_spice_server.c b/src/spiceqxl_spice_server.c index b2b31ff..15b0531 100644 --- a/src/spiceqxl_spice_server.c +++ b/src/spiceqxl_spice_server.c @@ -173,6 +173,9 @@ void xspice_set_spice_server_options(OptionInfoPtr options) const char *streaming_video = get_str_option(options, OPTION_SPICE_STREAMING_VIDEO, "XSPICE_STREAMING_VIDEO"); +const char *video_codecs = +get_str_option(options, OPTION_SPICE_VIDEO_CODECS, + "XSPICE_VIDEO_CODECS"); int agent_mouse = get_bool_option(options, OPTION_SPICE_AGENT_MOUSE, "XSPICE_AGENT_MOUSE"); @@ -294,6 +297,18 @@ void xspice_set_spice_server_options(OptionInfoPtr options) spice_server_set_streaming_video(spice_server, streaming_video_opt); } +if (video_codecs) { +#if SPICE_SERVER_VERSION >= 0x000c06 /* 0.12.6 */ +if (spice_server_set_video_codecs(spice_server, video_codecs)) { +fprintf(stderr, "spice: invalid video encoder %s\n", video_codecs); +exit(1); +} +#else +fprintf(stderr, "spice: video_codecs are not available (spice >= 0.12.6 required)\n"); +exit(1); +#endif +} + spice_server_set_agent_mouse(spice_server, agent_mouse); spice_server_set_playback_compression(spice_server, playback_compression); -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [qxl v9 17/24] Xspice: Add --video-codecs to specify encoder and codec preferences
Signed-off-by: Francois Gouget --- scripts/Xspice | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/Xspice b/scripts/Xspice index 15a5a5e..bf8112f 100755 --- a/scripts/Xspice +++ b/scripts/Xspice @@ -87,6 +87,7 @@ parser.add_argument('--zlib-glz-wan-compression', # TODO - sound support parser.add_argument('--streaming-video', choices=['off', 'all', 'filter'], help='filter by default') +parser.add_argument('--video-codecs', help="Sets a semicolon-separated list of preferred video codecs to use. Each takes the form encoder:codec, with spice:mjpeg being the default and other options being provided by gstreamer for the mjpeg, vp8 and h264 codecs.") add_boolean('--ipv4-only') add_boolean('--ipv6-only') parser.add_argument('--vdagent', action='store_true', dest='vdagent_enabled', default=False, help='launch vdagent & vdagentd. They provide clipboard & resolution automation') @@ -282,7 +283,7 @@ var_args = ['port', 'tls_port', 'disable_ticketing', 'x509_key_file', 'x509_key_password', 'tls_ciphers', 'dh_file', 'password', 'image_compression', 'jpeg_wan_compression', 'zlib_glz_wan_compression', -'streaming_video', 'deferred_fps', 'exit_on_disconnect', +'streaming_video', 'video_codecs', 'deferred_fps', 'exit_on_disconnect', 'vdagent_enabled', 'vdagent_virtio_path', 'vdagent_uinput_path', 'vdagent_uid', 'vdagent_gid'] -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [client v9 23/24] spice-gtk: Avoid copying the compressed message data for SpiceGstDecoder
Signed-off-by: Francois Gouget --- src/channel-display-gst.c | 88 +-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c index 7b7d0eb..bc7f94a 100644 --- a/src/channel-display-gst.c +++ b/src/channel-display-gst.c @@ -46,11 +46,43 @@ typedef struct SpiceGstDecoder { /* -- Output frame data -- */ +GMutex pipeline_mutex; +GCond pipeline_cond; +gboolean pipeline_wait; +uint32_t samples_count; + GstBuffer *buffer; GstMapInfo mapinfo; } SpiceGstDecoder; +/* Signals that the pipeline is done processing the last buffer we gave it. + * + * @decoder: The video decoder object. + * @samples: How many samples to add to the available samples count. + */ +static void signal_pipeline(SpiceGstDecoder *decoder, uint32_t samples) +{ +g_mutex_lock(&decoder->pipeline_mutex); +decoder->pipeline_wait = FALSE; +decoder->samples_count += samples; +g_cond_signal(&decoder->pipeline_cond); +g_mutex_unlock(&decoder->pipeline_mutex); +} + +static void appsrc_need_data_cb(GstAppSrc *src, guint length, gpointer user_data) +{ +SpiceGstDecoder *decoder = (SpiceGstDecoder*)user_data; +signal_pipeline(decoder, 0); +} + +static GstFlowReturn appsink_new_sample_cb(GstAppSink *appsrc, gpointer user_data) +{ +SpiceGstDecoder *decoder = (SpiceGstDecoder*)user_data; +signal_pipeline(decoder, 1); +return GST_FLOW_OK; +} + /* -- GStreamer pipeline -- */ static void reset_pipeline(SpiceGstDecoder *decoder) @@ -64,10 +96,18 @@ static void reset_pipeline(SpiceGstDecoder *decoder) gst_object_unref(decoder->appsink); gst_object_unref(decoder->pipeline); decoder->pipeline = NULL; + +g_mutex_clear(&decoder->pipeline_mutex); +g_cond_clear(&decoder->pipeline_cond); } static gboolean construct_pipeline(SpiceGstDecoder *decoder) { +g_mutex_init(&decoder->pipeline_mutex); +g_cond_init(&decoder->pipeline_cond); +decoder->pipeline_wait = TRUE; +decoder->samples_count = 0; + const gchar *src_caps, *gstdec_name; switch (decoder->base.codec_type) { case SPICE_VIDEO_CODEC_TYPE_MJPEG: @@ -99,7 +139,12 @@ static gboolean construct_pipeline(SpiceGstDecoder *decoder) } decoder->appsrc = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "src")); +GstAppSrcCallbacks appsrc_cbs = {&appsrc_need_data_cb, NULL, NULL, {NULL}}; +gst_app_src_set_callbacks(decoder->appsrc, &appsrc_cbs, decoder, NULL); + decoder->appsink = GST_APP_SINK(gst_bin_get_by_name(GST_BIN(decoder->pipeline), "sink")); +GstAppSinkCallbacks appsink_cbs = {NULL, NULL, &appsink_new_sample_cb, {NULL}}; +gst_app_sink_set_callbacks(decoder->appsink, &appsink_cbs, decoder, NULL); if (gst_element_set_state(decoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { SPICE_DEBUG("GStreamer error: Unable to set the pipeline to the playing state."); @@ -110,6 +155,11 @@ static gboolean construct_pipeline(SpiceGstDecoder *decoder) return TRUE; } +static void release_msg_in(gpointer data) +{ +spice_msg_in_unref((SpiceMsgIn*)data); +} + static gboolean push_compressed_buffer(SpiceGstDecoder *decoder, SpiceMsgIn *frame_msg) { @@ -120,8 +170,12 @@ static gboolean push_compressed_buffer(SpiceGstDecoder *decoder, return FALSE; } -GstBuffer *buffer = gst_buffer_new_allocate(NULL, size, NULL); -gst_buffer_fill(buffer, 0, data, size); +/* Reference frame_msg so it stays around until our 'deallocator' releases it */ +spice_msg_in_ref(frame_msg); +GstBuffer *buffer = gst_buffer_new_wrapped_full(GST_MEMORY_FLAG_READONLY, +data, size, 0, size, +frame_msg, &release_msg_in); + if (gst_app_src_push_buffer(decoder->appsrc, buffer) != GST_FLOW_OK) { SPICE_DEBUG("GStreamer error: unable to push frame of size %d", size); return FALSE; @@ -198,8 +252,36 @@ static uint8_t* gst_decoder_decode_frame(VideoDecoder *video_decoder, */ release_last_frame(decoder); +/* The pipeline may have called appsrc_need_data_cb() after we got the last + * output frame. This would cause us to return prematurely so reset + * pipeline_wait so we do wait for it to process this buffer. + */ +g_mutex_lock(&decoder->pipeline_mutex); +decoder->pipeline_wait = TRUE; +g_mutex_unlock(&decoder->pipeline_mutex); +/* Note that it's possible for appsrc_need_data_cb() to get called between + * now and the pipeline wait. But this will at most cause a one frame delay. + */ + if (push_compressed_buffer(decoder, frame_msg)) { -return pull_raw_frame(decoder); +/* Wait for the pipeline to either produce a decoded frame, or ask +
[Spice-devel] [client v9 24/24] spice-gtk: Use decodebin as a fallback for the GStreamer video decoder
This means future video codecs may be supported automatically. One can also force usage of decodebin by setting $SPICE_GSTVIDEO_AUTO. Signed-off-by: Francois Gouget --- src/channel-display-gst.c | 21 ++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c index bc7f94a..4e2c6f9 100644 --- a/src/channel-display-gst.c +++ b/src/channel-display-gst.c @@ -108,7 +108,16 @@ static gboolean construct_pipeline(SpiceGstDecoder *decoder) decoder->pipeline_wait = TRUE; decoder->samples_count = 0; -const gchar *src_caps, *gstdec_name; +/* Note that we cannot rely on typefind to always identify the stream type + * (e.g. VP8). So always set the source caps for streams we know about. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=756457 + * + * Furthermore decodebin will use vaapi if installed, which for a time + * could intentionally crash the application. So only use decodebin as a + * fallback for now. See: https://bugs.freedesktop.org/show_bug.cgi?id=90884 + */ +const gchar *src_caps; +const gchar *gstdec_name = NULL; switch (decoder->base.codec_type) { case SPICE_VIDEO_CODEC_TYPE_MJPEG: src_caps = "caps=image/jpeg"; @@ -123,8 +132,14 @@ static gboolean construct_pipeline(SpiceGstDecoder *decoder) gstdec_name = "h264parse ! avdec_h264"; break; default: -spice_warning("Unknown codec type %d", decoder->base.codec_type); -return -1; +SPICE_DEBUG("Unknown codec type %d. Trying decodebin.", +decoder->base.codec_type); +src_caps = ""; +break; +} +/* Set SPICE_GSTVIDEO_AUTO to test decodebin and maybe get hardware acceleration */ +if (!gstdec_name || getenv("SPICE_GSTVIDEO_AUTO")) { +gstdec_name = "decodebin"; } GError *err = NULL; -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [client v9 20/24] spice-gtk: Add a GStreamer video decoder for MJPEG, VP8 and h264
Based on a patch by Jeremy White. Signed-off-by: Francois Gouget --- configure.ac | 28 +- src/Makefile.am| 8 ++ src/channel-display-gst.c | 238 + src/channel-display-priv.h | 6 ++ src/channel-display.c | 10 ++ 5 files changed, 288 insertions(+), 2 deletions(-) create mode 100644 src/channel-display-gst.c diff --git a/configure.ac b/configure.ac index 38db8b5..cef73de 100644 --- a/configure.ac +++ b/configure.ac @@ -70,7 +70,7 @@ AC_CHECK_LIBM AC_SUBST(LIBM) AC_CONFIG_SUBDIRS([spice-common]) -PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= 0.12.10]) +PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= 0.12.11]) COMMON_CFLAGS='-I ${top_srcdir}/spice-common/ ${SPICE_PROTOCOL_CFLAGS}' AC_SUBST(COMMON_CFLAGS) @@ -292,6 +292,29 @@ AS_IF([test "x$enable_pulse$have_gstaudio" = "xnono"], [SPICE_WARNING([No PulseAudio or GStreamer 1.0 audio decoder, audio will not be streamed]) ]) +AC_ARG_ENABLE([gstvideo], + AS_HELP_STRING([--enable-gstvideo=@<:@auto/yes/no@:>@], + [Enable GStreamer video support @<:@default=auto@:>@]), + [], + [enable_gstvideo="auto"]) +AS_IF([test "x$enable_gstvideo" != "xno"], + [SPICE_CHECK_GSTREAMER(GSTVIDEO, 1.0, + [gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0], + [missing_gstreamer_elements="" + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-base 1.0], [appsrc videoconvert appsink]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-good 1.0], [jpegdec vp8dec]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-bad 1.0], [h264parse]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gstreamer-libav 1.0], [avdec_h264]) + AS_IF([test x"$missing_gstreamer_elements" = "xyes"], +SPICE_WARNING([The GStreamer video decoder can be built but may not work.])) + ], + [AS_IF([test "x$enable_gstvideo" = "xyes"], +AC_MSG_ERROR([GStreamer 1.0 video requested but not found])) + ]) + ], [have_gstvideo="no"] +) +AM_CONDITIONAL([HAVE_GSTVIDEO], [test "x$have_gstvideo" = "xyes"]) + AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, AC_MSG_CHECKING([for jpeglib.h]) AC_TRY_CPP( @@ -654,7 +677,7 @@ SPICE_CFLAGS="$SPICE_CFLAGS $WARN_CFLAGS" AC_SUBST(SPICE_CFLAGS) -SPICE_GLIB_CFLAGS="$PIXMAN_CFLAGS $PULSE_CFLAGS $GSTAUDIO_CFLAGS $GLIB2_CFLAGS $GIO_CFLAGS $GOBJECT2_CFLAGS $SSL_CFLAGS $SASL_CFLAGS" +SPICE_GLIB_CFLAGS="$PIXMAN_CFLAGS $PULSE_CFLAGS $GSTAUDIO_CFLAGS $GSTVIDEO_CFLAGS $GLIB2_CFLAGS $GIO_CFLAGS $GOBJECT2_CFLAGS $SSL_CFLAGS $SASL_CFLAGS" SPICE_GTK_CFLAGS="$SPICE_GLIB_CFLAGS $GTK_CFLAGS " AC_SUBST(SPICE_GLIB_CFLAGS) @@ -699,6 +722,7 @@ AC_MSG_NOTICE([ Coroutine:${with_coroutine} PulseAudio: ${enable_pulse} GStreamer Audio: ${have_gstaudio} +GStreamer Video: ${have_gstvideo} SASL support: ${have_sasl} Smartcard support:${have_smartcard} USB redirection support: ${have_usbredir} ${with_usbredir_hotplug} diff --git a/src/Makefile.am b/src/Makefile.am index 37b89fe..cb99610 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -98,6 +98,7 @@ SPICE_COMMON_CPPFLAGS = \ $(SSL_CFLAGS) \ $(SASL_CFLAGS) \ $(GSTAUDIO_CFLAGS) \ + $(GSTVIDEO_CFLAGS) \ $(SMARTCARD_CFLAGS) \ $(USBREDIR_CFLAGS) \ $(GUDEV_CFLAGS) \ @@ -210,6 +211,7 @@ libspice_client_glib_2_0_la_LIBADD = \ $(SSL_LIBS) \ $(PULSE_LIBS) \ $(GSTAUDIO_LIBS)\ + $(GSTVIDEO_LIBS)\ $(SASL_LIBS)\ $(SMARTCARD_LIBS) \ $(USBREDIR_LIBS)\ @@ -343,6 +345,12 @@ libspice_client_glib_2_0_la_SOURCES += \ $(NULL) endif +if HAVE_GSTVIDEO +libspice_client_glib_2_0_la_SOURCES += \ + channel-display-gst.c \ + $(NULL) +endif + if WITH_PHODAV libspice_client_glib_2_0_la_SOURCES += \ giopipe.c \ diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c new file mode 100644 index 000..c5ad2e9 --- /dev/null +++ b/src/channel-displa
[Spice-devel] [client v9 21/24] spice-gtk: Allow disabling support for the builtin MJPEG video decoder
This makes it possible to test the GStreamer video decoder with MJPEG streams. Signed-off-by: Francois Gouget --- configure.ac | 11 +++ src/Makefile.am| 7 ++- src/channel-display-priv.h | 2 ++ src/channel-display.c | 5 + 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index cef73de..8f44a59 100644 --- a/configure.ac +++ b/configure.ac @@ -315,6 +315,17 @@ AS_IF([test "x$enable_gstvideo" != "xno"], ) AM_CONDITIONAL([HAVE_GSTVIDEO], [test "x$have_gstvideo" = "xyes"]) +AC_ARG_ENABLE([builtin-mjpeg], + AS_HELP_STRING([--enable-builtin-mjpeg], [Enable the builtin mjpeg video decoder @<:@default=yes@:>@]), + [], + enable_builtin_mjpeg="yes") +AS_IF([test "x$enable_builtin_mjpeg" = "xyes"], + [AC_DEFINE([HAVE_BUILTIN_MJPEG], 1, [Use the builtin mjpeg decoder?])]) +AM_CONDITIONAL(HAVE_BUILTIN_MJPEG, [test "x$enable_builtin_mjpeg" != "xno"]) + +AS_IF([test "x$enable_builtin_mjpeg$enable_gstvideo" = "xnono"], + [SPICE_WARNING([No builtin MJPEG or GStreamer decoder, video will not be streamed])]) + AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, AC_MSG_CHECKING([for jpeglib.h]) AC_TRY_CPP( diff --git a/src/Makefile.am b/src/Makefile.am index cb99610..37a2234 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -257,7 +257,6 @@ libspice_client_glib_2_0_la_SOURCES = \ channel-cursor.c\ channel-display.c \ channel-display-priv.h \ - channel-display-mjpeg.c \ channel-inputs.c\ channel-main.c \ channel-playback.c \ @@ -345,6 +344,12 @@ libspice_client_glib_2_0_la_SOURCES += \ $(NULL) endif +if HAVE_BUILTIN_MJPEG +libspice_client_glib_2_0_la_SOURCES += \ + channel-display-mjpeg.c \ + $(NULL) +endif + if HAVE_GSTVIDEO libspice_client_glib_2_0_la_SOURCES += \ channel-display-gst.c \ diff --git a/src/channel-display-priv.h b/src/channel-display-priv.h index d8a03e9..2c64eb4 100644 --- a/src/channel-display-priv.h +++ b/src/channel-display-priv.h @@ -65,7 +65,9 @@ struct VideoDecoder { * @stream: The associated video stream. * @return: A pointer to a structure implementing the VideoDecoder methods. */ +#ifdef HAVE_BUILTIN_MJPEG VideoDecoder* create_mjpeg_decoder(int codec_type, display_stream *stream); +#endif #ifdef HAVE_GSTVIDEO VideoDecoder* create_gstreamer_decoder(int codec_type, display_stream *stream); gboolean gstvideo_init(void); diff --git a/src/channel-display.c b/src/channel-display.c index c1ccde5..193f177 100644 --- a/src/channel-display.c +++ b/src/channel-display.c @@ -629,8 +629,11 @@ static void spice_display_channel_reset_capabilities(SpiceChannel *channel) spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_STREAM_REPORT); } spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_MULTI_CODEC); +#ifdef HAVE_BUILTIN_MJPEG spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_MJPEG); +#endif if (gstvideo_init()) { +spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_MJPEG); spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_VP8); spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_CODEC_H264); } @@ -1038,9 +1041,11 @@ static void display_handle_stream_create(SpiceChannel *channel, SpiceMsgIn *in) display_update_stream_region(st); switch (op->codec_type) { +#ifdef HAVE_BUILTIN_MJPEG case SPICE_VIDEO_CODEC_TYPE_MJPEG: st->video_decoder = create_mjpeg_decoder(op->codec_type, st); break; +#endif default: #ifdef HAVE_GSTVIDEO st->video_decoder = create_gstreamer_decoder(op->codec_type, st); -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [client v9 18/24] spice-gtk: Enable adding alternative video decoders
This replaces the original channel-display-mjpeg API with a VideoDecoder base class which can be reimplemented by other decoders. Furthermore this moves the MJPEG-specific state information from the display_stream struct to a derived class of VideoDecoder. Signed-off-by: Francois Gouget --- src/channel-display-mjpeg.c | 131 src/channel-display-priv.h | 53 +- src/channel-display.c | 63 ++--- 3 files changed, 151 insertions(+), 96 deletions(-) diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c index 95d5b33..78e3d5a 100644 --- a/src/channel-display-mjpeg.c +++ b/src/channel-display-mjpeg.c @@ -23,12 +23,33 @@ #include "channel-display-priv.h" + +/* MJpeg decoder implementation */ + +typedef struct MJpegDecoder { +VideoDecoder base; + +/* -- The builtin mjpeg decoder -- */ + +SpiceMsgIn *frame_msg; +struct jpeg_source_mgr mjpeg_src; +struct jpeg_decompress_struct mjpeg_cinfo; +struct jpeg_error_mgr mjpeg_jerr; + +/* -- Output frame data -- */ + +uint8_t *out_frame; +} MJpegDecoder; + + +/* -- The JPEG library callbacks -- */ + static void mjpeg_src_init(struct jpeg_decompress_struct *cinfo) { -display_stream *st = SPICE_CONTAINEROF(cinfo->src, display_stream, mjpeg_src); -uint8_t *data; +MJpegDecoder *decoder = SPICE_CONTAINEROF(cinfo->src, MJpegDecoder, mjpeg_src); -cinfo->src->bytes_in_buffer = stream_get_current_frame(st, &data); +uint8_t *data; +cinfo->src->bytes_in_buffer = spice_msg_in_frame_data(decoder->frame_msg, &data); cinfo->src->next_input_byte = data; } @@ -49,68 +70,57 @@ static void mjpeg_src_term(struct jpeg_decompress_struct *cinfo) /* nothing */ } -G_GNUC_INTERNAL -void stream_mjpeg_init(display_stream *st) -{ -st->mjpeg_cinfo.err = jpeg_std_error(&st->mjpeg_jerr); -jpeg_create_decompress(&st->mjpeg_cinfo); - -st->mjpeg_src.init_source = mjpeg_src_init; -st->mjpeg_src.fill_input_buffer = mjpeg_src_fill; -st->mjpeg_src.skip_input_data = mjpeg_src_skip; -st->mjpeg_src.resync_to_restart = jpeg_resync_to_restart; -st->mjpeg_src.term_source = mjpeg_src_term; -st->mjpeg_cinfo.src = &st->mjpeg_src; -} -G_GNUC_INTERNAL -void stream_mjpeg_data(display_stream *st) +/* -- VideoDecoder's public API -- */ + +static uint8_t* mjpeg_decoder_decode_frame(VideoDecoder *video_decoder, + SpiceMsgIn *frame_msg) { -gboolean back_compat = st->channel->priv->peer_hdr.major_version == 1; +MJpegDecoder *decoder = (MJpegDecoder*)video_decoder; +gboolean back_compat = decoder->base.stream->channel->priv->peer_hdr.major_version == 1; int width; int height; uint8_t *dest; uint8_t *lines[4]; -stream_get_dimensions(st, &width, &height); -dest = g_malloc0(width * height * 4); +decoder->frame_msg = frame_msg; +stream_get_dimensions(decoder->base.stream, frame_msg, &width, &height); +g_free(decoder->out_frame); +dest = decoder->out_frame = g_malloc0(width * height * 4); -g_free(st->out_frame); -st->out_frame = dest; - -jpeg_read_header(&st->mjpeg_cinfo, 1); +jpeg_read_header(&decoder->mjpeg_cinfo, 1); #ifdef JCS_EXTENSIONS // requires jpeg-turbo if (back_compat) -st->mjpeg_cinfo.out_color_space = JCS_EXT_RGBX; +decoder->mjpeg_cinfo.out_color_space = JCS_EXT_RGBX; else -st->mjpeg_cinfo.out_color_space = JCS_EXT_BGRX; +decoder->mjpeg_cinfo.out_color_space = JCS_EXT_BGRX; #else #warning "You should consider building with libjpeg-turbo" -st->mjpeg_cinfo.out_color_space = JCS_RGB; +decoder->mjpeg_cinfo.out_color_space = JCS_RGB; #endif #ifndef SPICE_QUALITY -st->mjpeg_cinfo.dct_method = JDCT_IFAST; -st->mjpeg_cinfo.do_fancy_upsampling = FALSE; -st->mjpeg_cinfo.do_block_smoothing = FALSE; -st->mjpeg_cinfo.dither_mode = JDITHER_ORDERED; +decoder->mjpeg_cinfo.dct_method = JDCT_IFAST; +decoder->mjpeg_cinfo.do_fancy_upsampling = FALSE; +decoder->mjpeg_cinfo.do_block_smoothing = FALSE; +decoder->mjpeg_cinfo.dither_mode = JDITHER_ORDERED; #endif // TODO: in theory should check cinfo.output_height match with our height -jpeg_start_decompress(&st->mjpeg_cinfo); +jpeg_start_decompress(&decoder->mjpeg_cinfo); /* rec_outbuf_height is the recommended size of the output buffer we * pass to libjpeg for optimum performance */ -if (st->mjpeg_cinfo.rec_outbuf_height > G_N_ELEMENTS(lines)) { -jpeg_abort_decompress(&st->mjpeg_cinfo); -g_return_if_reached(); +if (decoder->mjpeg_cinfo.rec_outbuf_height > G_N_ELEMENTS(lines)) { +jpeg_abort_decompress(&decoder->mjpeg_cinfo); +g_return_val_if_reached(NULL); } -while (s
[Spice-devel] [spice v9 15/24] server: Add support for GStreamer 0.10
configure will use GStreamer 1.0 if present and fall back to GStreamer 0.10 otherwise. Signed-off-by: Francois Gouget --- configure.ac | 36 server/Makefile.am | 8 server/gstreamer-encoder.c | 102 + server/reds.c | 2 +- server/video-encoder.h | 2 +- 5 files changed, 123 insertions(+), 27 deletions(-) diff --git a/configure.ac b/configure.ac index a902e84..865d6e9 100644 --- a/configure.ac +++ b/configure.ac @@ -70,28 +70,48 @@ dnl Check optional features SPICE_CHECK_SMARTCARD AC_ARG_ENABLE(gstreamer, - AS_HELP_STRING([--enable-gstreamer=@<:@auto/yes/no@:>@], - [Enable GStreamer 1.0 support]),, + AS_HELP_STRING([--enable-gstreamer=@<:@auto/0.10/1.0/yes/no@:>@], + [Enable GStreamer support]),, [enable_gstreamer="auto"]) -if test "x$enable_gstreamer" != "xno"; then +if test "x$enable_gstreamer" != "xno" && test "x$enable_gstreamer" != "x0.10"; then SPICE_CHECK_GSTREAMER(GSTREAMER_1_0, 1.0, [gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0], -[enable_gstreamer="yes" +[enable_gstreamer="1.0" SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-base 1.0], [appsrc videoconvert appsink]) SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gstreamer-libav 1.0], [avenc_mjpeg]) SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-good 1.0], [vp8enc]) SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-ugly 1.0], [x264enc]) ], - [if test "x$enable_gstreamer" = "xyes"; then + [if test "x$enable_gstreamer" = "x1.0"; then AC_MSG_ERROR([GStreamer 1.0 support requested but not found. You may set GSTREAMER_1_0_CFLAGS and GSTREAMER_1_0_LIBS to avoid the need to call pkg-config.]) fi ]) fi AM_CONDITIONAL(HAVE_GSTREAMER_1_0, test "x$have_gstreamer_1_0" = "xyes") -if test x"$gstreamer_missing" != x; then -SPICE_WARNING([The following GStreamer $enable_gstreamer tools/elements are missing:$gstreamer_missing. The GStreamer video encoder can be built but may not work.]) +if test "x$enable_gstreamer" != "xno" && test "x$enable_gstreamer" != "x1.0"; then +SPICE_CHECK_GSTREAMER(GSTREAMER_0_10, 0.10, [gstreamer-0.10 gstreamer-base-0.10 gstreamer-app-0.10 gstreamer-video-0.10], +[enable_gstreamer="0.10" + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_0_10, [gst-plugins-base 0.10], [appsrc appsink]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_0_10, [gstreamer-ffmpeg 0.10], [ffmpegcolorspace ffenc_mjpeg]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_0_10, [gst-plugins-bad 0.10], [vp8enc]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_0_10, [gst-plugins-ugly 0.10], [x264enc]) +], +[if test "x$enable_gstreamer" = "x0.10"; then + AC_MSG_ERROR([GStreamer 0.10 support requested but not found. You may set GSTREAMER_0_10_CFLAGS and GSTREAMER_0_10_LIBS to avoid the need to call pkg-config.]) + fi +]) fi +AM_CONDITIONAL(HAVE_GSTREAMER_0_10, test "x$have_gstreamer_0_10" = "xyes") + +AS_IF([test "x$enable_gstreamer" = "xyes"], + [AC_MSG_ERROR("GStreamer support requested but not found")], + [test "x$enable_gstreamer" = "xauto"], + [enable_gstreamer="no" +]) +AS_IF([test x"$missing_gstreamer_elements" = xyes], +[SPICE_WARNING([The GStreamer video encoder can be built but may not work.]) +]) AC_ARG_ENABLE([automated_tests], AS_HELP_STRING([--enable-automated-tests], [Enable automated tests using spicy-screenshot (part of spice--gtk)]),, @@ -266,7 +286,7 @@ AC_MSG_NOTICE([ LZ4 support: ${enable_lz4} Smartcard:${have_smartcard} -GStreamer 1.0:${have_gstreamer_1_0} +GStreamer:${enable_gstreamer} SASL support: ${have_sasl} Automated tests: ${enable_automated_tests} Manual: ${have_asciidoc} diff --git a/server/Makefile.am b/server/Makefile.am index 9f33c93..d955a44 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ $(SASL_CFLAGS) \ $(SLIRP_CFLAGS) \ $(SMARTCARD_CFLAGS) \ + $(GSTREAMER_0_10_CFLAGS)\ $(GSTREAMER_1_0_CFLAGS) \ $(SPICE_PROTOCOL_CFLAGS)\ $(SSL_CFLAGS) \ @@ -44,6 +45,7 @@ libserver_la_LIBADD = \ $(PIXMAN_LIBS) \ $(SASL_LIBS)\
[Spice-devel] [PATCH] Change some functions to take RedsState arg
From: Jonathon Jongsma In preparation for getting rid of the global 'reds' variable, we need to pass the RedsState variable to all functions where it is needed. For now the callers just pass in the global reds variable. Functions changed: - reds_register_channel; - reds_unregister_channel; - reds_get_mouse_mode; - reds_set_mouse_mode; - reds_update_mouse_mode; - reds_agent_remove; - reds_find_channel; - reds_mig_cleanup; - reds_reset_vdp; - reds_main_channel_connected; - reds_client_disconnect; - reds_disconnect; - reds_mig_disconnect. Acked-by: Frediano Ziglio --- server/inputs-channel.c | 10 ++--- server/main-dispatcher.c | 2 +- server/red-dispatcher.c | 4 +- server/reds.c| 104 +++ server/reds.h| 8 ++-- server/smartcard.c | 2 +- server/sound.c | 6 +-- server/spicevmc.c| 4 +- 8 files changed, 70 insertions(+), 70 deletions(-) diff --git a/server/inputs-channel.c b/server/inputs-channel.c index c21cab8..bb5b203 100644 --- a/server/inputs-channel.c +++ b/server/inputs-channel.c @@ -364,7 +364,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK); icc->motion_count = 0; } -if (mouse && reds_get_mouse_mode() == SPICE_MOUSE_MODE_SERVER) { +if (mouse && reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_SERVER) { SpiceMouseInterface *sif; sif = SPICE_CONTAINEROF(mouse->base.sif, SpiceMouseInterface, base); sif->motion(mouse, @@ -381,7 +381,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui red_channel_client_pipe_add_type(rcc, PIPE_ITEM_MOUSE_MOTION_ACK); icc->motion_count = 0; } -if (reds_get_mouse_mode() != SPICE_MOUSE_MODE_CLIENT) { +if (reds_get_mouse_mode(reds) != SPICE_MOUSE_MODE_CLIENT) { break; } spice_assert((reds_get_agent_mouse() && reds_has_vdagent()) || tablet); @@ -407,7 +407,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui } else if (mouse_press->button == SPICE_MOUSE_BUTTON_DOWN) { dz = 1; } -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { if (reds_get_agent_mouse() && reds_has_vdagent()) { inputs_channel->mouse_state.buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_press->buttons_state) | @@ -429,7 +429,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui } case SPICE_MSGC_INPUTS_MOUSE_RELEASE: { SpiceMsgcMouseRelease *mouse_release = message; -if (reds_get_mouse_mode() == SPICE_MOUSE_MODE_CLIENT) { +if (reds_get_mouse_mode(reds) == SPICE_MOUSE_MODE_CLIENT) { if (reds_get_agent_mouse() && reds_has_vdagent()) { inputs_channel->mouse_state.buttons = RED_MOUSE_BUTTON_STATE_TO_AGENT(mouse_release->buttons_state); @@ -672,7 +672,7 @@ void inputs_init(void) red_channel_register_client_cbs(&g_inputs_channel->base, &client_cbs); red_channel_set_cap(&g_inputs_channel->base, SPICE_INPUTS_CAP_KEY_SCANCODE); -reds_register_channel(&g_inputs_channel->base); +reds_register_channel(reds, &g_inputs_channel->base); if (!(key_modifiers_timer = core->timer_add(core, key_modifiers_sender, NULL))) { spice_error("key modifiers timer create failed"); diff --git a/server/main-dispatcher.c b/server/main-dispatcher.c index 2cb53ef..db87e05 100644 --- a/server/main-dispatcher.c +++ b/server/main-dispatcher.c @@ -136,7 +136,7 @@ static void main_dispatcher_handle_client_disconnect(void *opaque, MainDispatcherClientDisconnectMessage *msg = payload; spice_debug("client=%p", msg->client); -reds_client_disconnect(msg->client); +reds_client_disconnect(reds, msg->client); red_client_unref(msg->client); } diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c index 0810798..dc958d9 100644 --- a/server/red-dispatcher.c +++ b/server/red-dispatcher.c @@ -1044,7 +1044,7 @@ void red_dispatcher_init(QXLInstance *qxl) client_cbs.migrate = red_dispatcher_cursor_migrate; red_channel_register_client_cbs(channel, &client_cbs); red_channel_set_data(channel, red_dispatcher); -reds_register_channel(channel); +reds_register_channel(reds, channel); channel = red_worker_get_display_channel(worker); client_cbs.connect = red_dispatcher_set_display_peer; @@ -1055,7 +1055,7 @@ void red_dispatcher_init(QXLInstance *qxl) red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG); red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION); red_channel_set_cap(channel, SPICE_DISPLAY_
[Spice-devel] [client v9 19/24] spice-gtk: Optimize handling of the decoded frame buffer
The MJPEG decoder does not need a zero-filled buffer. Signed-off-by: Francois Gouget --- src/channel-display-mjpeg.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c index 78e3d5a..6271cfb 100644 --- a/src/channel-display-mjpeg.c +++ b/src/channel-display-mjpeg.c @@ -39,6 +39,7 @@ typedef struct MJpegDecoder { /* -- Output frame data -- */ uint8_t *out_frame; +uint32_t out_size; } MJpegDecoder; @@ -85,8 +86,12 @@ static uint8_t* mjpeg_decoder_decode_frame(VideoDecoder *video_decoder, decoder->frame_msg = frame_msg; stream_get_dimensions(decoder->base.stream, frame_msg, &width, &height); -g_free(decoder->out_frame); -dest = decoder->out_frame = g_malloc0(width * height * 4); +if (decoder->out_size < width * height * 4) { +g_free(decoder->out_frame); +decoder->out_size = width * height * 4; +decoder->out_frame = g_malloc(decoder->out_size); +} +dest = decoder->out_frame; jpeg_read_header(&decoder->mjpeg_cinfo, 1); #ifdef JCS_EXTENSIONS -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice v9 14/24] server: Respect the GStreamer encoder's valid bit rate range
Otherwise it may get wrapped to a much lower value than intended. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 65 +++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index 3c1e86e..bcf28e7 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -20,6 +20,8 @@ #include #endif +#include + #include #include #include @@ -777,6 +779,65 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder) return TRUE; } +/* A helper for configure_pipeline() */ +static void set_gstenc_bitrate(SpiceGstEncoder *encoder) +{ +GObjectClass *class = G_OBJECT_GET_CLASS(encoder->gstenc); +GParamSpec *param = g_object_class_find_property(class, "bitrate"); +if (param == NULL) { +param = g_object_class_find_property(class, "target-bitrate"); +} +if (param) { +uint64_t gst_bit_rate = encoder->video_bit_rate; +if (strstr(g_param_spec_get_blurb(param), "kbit")) { +gst_bit_rate = gst_bit_rate / 1024; +} +switch (param->value_type) { +case G_TYPE_ULONG: { +GParamSpecULong *range = G_PARAM_SPEC_ULONG(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +case G_TYPE_LONG: { +GParamSpecLong *range = G_PARAM_SPEC_LONG(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +case G_TYPE_UINT: { +GParamSpecUInt *range = G_PARAM_SPEC_UINT(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +case G_TYPE_INT: { +GParamSpecInt *range = G_PARAM_SPEC_INT(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +case G_TYPE_UINT64: { +GParamSpecUInt64 *range = G_PARAM_SPEC_UINT64(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +case G_TYPE_INT64: { +GParamSpecInt64 *range = G_PARAM_SPEC_INT64(param); +gst_bit_rate = MAX(range->minimum, MIN(range->maximum, gst_bit_rate)); +break; +} +default: +spice_debug("the %s property has an unsupported type %zu", +g_param_spec_get_name(param), param->value_type); +} +spice_debug("setting the GStreamer %s to %"PRIu64, +g_param_spec_get_name(param), gst_bit_rate); +g_object_set(G_OBJECT(encoder->gstenc), + g_param_spec_get_name(param), gst_bit_rate, + NULL); +} else { +spice_printerr("Could not find the bit rate property for %s", + get_gst_codec_name(encoder)); +} +} + /* A helper for spice_gst_encoder_encode_frame() */ static gboolean configure_pipeline(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap) @@ -786,10 +847,10 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, } /* Configure the encoder bitrate, frame latency, etc. */ +set_gstenc_bitrate(encoder); switch (encoder->base.codec_type) { case SPICE_VIDEO_CODEC_TYPE_MJPEG: g_object_set(G_OBJECT(encoder->gstenc), - "bitrate", encoder->video_bit_rate, "max-threads", 1, /* zero-frame latency */ NULL); @@ -807,7 +868,6 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, g_object_set(G_OBJECT(encoder->gstenc), "resize-allowed", TRUE, /* for very low bit rates */ "min-quantizer", 10, /* seems virtually lossless */ - "target-bitrate", encoder->video_bit_rate, "end-usage", 1, /* CBR */ "lag-in-frames", 0, /* zero-frame latency */ "error-resilient", 1, /* for client frame drops */ @@ -818,7 +878,6 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, } case SPICE_VIDEO_CODEC_TYPE_H264: g_object_set(G_OBJECT(encoder->gstenc), - "bitrate", encoder->video_bit_rate / 1024, "qp-min", 15, /* virtually lossless */ "byte-stream", TRUE, "aud", FALSE, -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice v9 13/24] server: Cap the VP8 and h264 video quality to limit the bit rate
This prevents the bit rate from going insanely high on fast networks for no visible video quality improvement. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index bf60773..3c1e86e 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -806,6 +806,7 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, #endif g_object_set(G_OBJECT(encoder->gstenc), "resize-allowed", TRUE, /* for very low bit rates */ + "min-quantizer", 10, /* seems virtually lossless */ "target-bitrate", encoder->video_bit_rate, "end-usage", 1, /* CBR */ "lag-in-frames", 0, /* zero-frame latency */ @@ -818,6 +819,7 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, case SPICE_VIDEO_CODEC_TYPE_H264: g_object_set(G_OBJECT(encoder->gstenc), "bitrate", encoder->video_bit_rate / 1024, + "qp-min", 15, /* virtually lossless */ "byte-stream", TRUE, "aud", FALSE, "tune", 4, /* zero-frame latency */ -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice v9 12/24] server: Give up after a while if GStreamer cannot handle the video
This typically happens when sending very small frames (less than 16 pixels in one dimension) to the x264enc encoder. This avoids repeatedly wasting time rebuilding the pipeline. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 46 +- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index 44072f0..bf60773 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -74,6 +74,9 @@ typedef struct SpiceGstEncoder { SpiceFormatForGStreamer *format; SpiceBitmapFmt spice_format; +/* Number of consecutive frame encoding errors. */ +uint32_t errors; + /* -- GStreamer pipeline -- */ /* Pointers to the GStreamer pipeline elements. If pipeline is NULL the @@ -730,24 +733,27 @@ static void set_appsrc_caps(SpiceGstEncoder *encoder) g_object_set(G_OBJECT(encoder->appsrc), "caps", encoder->src_caps, NULL); } -/* A helper for spice_gst_encoder_encode_frame() */ -static gboolean create_pipeline(SpiceGstEncoder *encoder) +static const gchar* get_gst_codec_name(SpiceGstEncoder *encoder) { -const gchar* gstenc_name; switch (encoder->base.codec_type) { case SPICE_VIDEO_CODEC_TYPE_MJPEG: -gstenc_name = "avenc_mjpeg"; -break; +return "avenc_mjpeg"; case SPICE_VIDEO_CODEC_TYPE_VP8: -gstenc_name = "vp8enc"; -break; +return "vp8enc"; case SPICE_VIDEO_CODEC_TYPE_H264: -gstenc_name = "x264enc"; -break; +return "x264enc"; default: /* gstreamer_encoder_new() should have rejected this codec type */ spice_warning("unsupported codec type %d", encoder->base.codec_type); +return NULL; +} +} + +static gboolean create_pipeline(SpiceGstEncoder *encoder) +{ +const gchar* gstenc_name = get_gst_codec_name(encoder); +if (!gstenc_name) { return FALSE; } @@ -1148,6 +1154,7 @@ static int spice_gst_encoder_encode_frame(VideoEncoder *video_encoder, encoder->format = map_format(bitmap->format); if (!encoder->format) { spice_debug("unable to map format type %d", bitmap->format); +encoder->errors = 4; return VIDEO_ENCODER_FRAME_UNSUPPORTED; } encoder->spice_format = bitmap->format; @@ -1163,6 +1170,19 @@ static int spice_gst_encoder_encode_frame(VideoEncoder *video_encoder, } else if (encoder->pipeline) { reconfigure_pipeline(encoder); } +encoder->errors = 0; +} else if (encoder->errors >= 3) { +/* The pipeline keeps failing to handle the frames we send it, which is + * usually because they are too small (mouse pointer-sized). + * So give up until something changes. + */ +if (encoder->errors == 3) { +spice_debug("%s cannot compress %dx%d:%dbpp frames", +get_gst_codec_name(encoder), encoder->width, +encoder->height, encoder->format->bpp); +encoder->errors++; +} +return VIDEO_ENCODER_FRAME_UNSUPPORTED; } if (rate_control_is_active(encoder) && @@ -1174,12 +1194,20 @@ static int spice_gst_encoder_encode_frame(VideoEncoder *video_encoder, if (!is_pipeline_configured(encoder) && !configure_pipeline(encoder, bitmap)) { +encoder->errors++; return VIDEO_ENCODER_FRAME_UNSUPPORTED; } int rc = push_raw_frame(encoder, bitmap, src, top_down); if (rc == VIDEO_ENCODER_FRAME_ENCODE_DONE) { rc = pull_compressed_buffer(encoder, video_buffer); +if (rc != VIDEO_ENCODER_FRAME_ENCODE_DONE) { +/* The input buffer will be stuck in the pipeline, preventing + * later ones from being processed. So reset the pipeline. + */ +free_pipeline(encoder); +encoder->errors++; +} #ifdef DO_ZERO_COPY /* GStreamer should have released the source frame buffer by now */ if (encoder->needs_bitmap) { -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice v9 09/24] server: Add h264 support to the GStreamer video encoder
Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 17 - server/reds.c | 2 ++ server/video-encoder.h | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index 11be91b..fe07852 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -231,6 +231,9 @@ static gboolean create_pipeline(SpiceGstEncoder *encoder) case SPICE_VIDEO_CODEC_TYPE_VP8: gstenc_name = "vp8enc"; break; +case SPICE_VIDEO_CODEC_TYPE_H264: +gstenc_name = "x264enc"; +break; default: /* gstreamer_encoder_new() should have rejected this codec type */ spice_warning("unsupported codec type %d", encoder->base.codec_type); @@ -296,6 +299,17 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, NULL); break; } +case SPICE_VIDEO_CODEC_TYPE_H264: +g_object_set(G_OBJECT(encoder->gstenc), + "bitrate", encoder->bit_rate / 1024, + "byte-stream", TRUE, + "aud", FALSE, + "tune", 4, /* zero-frame latency */ + "sliced-threads", TRUE, /* zero-frame latency */ + "speed-preset", 1, /* ultrafast */ + "intra-refresh", TRUE, /* uniform compressed frame sizes */ + NULL); +break; default: /* gstreamer_encoder_new() should have rejected this codec type */ spice_warning("unknown encoder type %d", encoder->base.codec_type); @@ -700,7 +714,8 @@ VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type, void *cbs_opaque) { spice_return_val_if_fail(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG || - codec_type == SPICE_VIDEO_CODEC_TYPE_VP8, NULL); + codec_type == SPICE_VIDEO_CODEC_TYPE_VP8 || + codec_type == SPICE_VIDEO_CODEC_TYPE_H264, NULL); GError *err = NULL; if (!gst_init_check(NULL, NULL, &err)) { diff --git a/server/reds.c b/server/reds.c index a5f600c..18d8bb1 100644 --- a/server/reds.c +++ b/server/reds.c @@ -3494,12 +3494,14 @@ static new_video_encoder_t video_encoder_procs[] = { static const EnumNames video_codec_names[] = { {SPICE_VIDEO_CODEC_TYPE_MJPEG, "mjpeg"}, {SPICE_VIDEO_CODEC_TYPE_VP8, "vp8"}, +{SPICE_VIDEO_CODEC_TYPE_H264, "h264"}, {0, NULL}, }; static const EnumNames video_cap_names[] = { {SPICE_DISPLAY_CAP_CODEC_MJPEG, "mjpeg"}, {SPICE_DISPLAY_CAP_CODEC_VP8, "vp8"}, +{SPICE_DISPLAY_CAP_CODEC_H264, "h264"}, {0, NULL}, }; diff --git a/server/video-encoder.h b/server/video-encoder.h index db520eb..edfb392 100644 --- a/server/video-encoder.h +++ b/server/video-encoder.h @@ -193,6 +193,6 @@ VideoEncoder* gstreamer_encoder_new(SpiceVideoCodecType codec_type, void *cbs_opaque); #endif -#define VIDEO_ENCODER_DEFAULT_PREFERENCE "spice:mjpeg;gstreamer:mjpeg;gstreamer:vp8" +#define VIDEO_ENCODER_DEFAULT_PREFERENCE "spice:mjpeg;gstreamer:mjpeg;gstreamer:h264;gstreamer:vp8" #endif -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [spice v9 08/24] server: Avoid copying the input frame in the GStreamer encoder
This relies on the GStreamer buffer's lifetime being short enough which it is because: - We encode frames one by one. - For all encoders but MJPEG, the first element of the pipeline will convert the bitmap to another image format which entails copying it. So by the time the encoder starts its work, this buffer will not be needed anymore. - The MJPEG encoder does not perform inter-frame compression and thus does not need to keep hold of this buffer once it has processed it. Note that we can only avoid copies for the first 1 Mpixels or so. That's because Spice splits larger frames into more chunks than we can fit GstMemory fragments in a GStreamer buffer. So if there are more pixels we will avoid copies for the first 3840 KB and copy the rest. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 171 - 1 file changed, 152 insertions(+), 19 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index d1a1d27..11be91b 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -30,6 +30,8 @@ #define SPICE_GST_DEFAULT_FPS 30 +#define DO_ZERO_COPY + typedef struct { SpiceBitmapFmt spice_format; @@ -73,6 +75,11 @@ typedef struct SpiceGstEncoder { /* If src_caps is NULL the pipeline has not been configured yet. */ GstCaps *src_caps; +#ifdef DO_ZERO_COPY +/* Set to TRUE until GStreamer no longer needs the raw bitmap buffer. */ +gboolean needs_bitmap; +#endif + /* The frame counter for GStreamer buffers */ uint32_t frame; @@ -336,6 +343,17 @@ static void reconfigure_pipeline(SpiceGstEncoder *encoder) } } +static int is_chunk_padded(const SpiceBitmap *bitmap, uint32_t index) +{ +SpiceChunks *chunks = bitmap->data; +if (chunks->chunk[index].len % bitmap->stride != 0) { +spice_warning("chunk %d/%d is padded", + index, chunks->num_chunks); +return TRUE; +} +return FALSE; +} + /* A helper for push_raw_frame() */ static inline int line_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, uint32_t chunk_offset, uint32_t stream_stride, @@ -349,10 +367,7 @@ static inline int line_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, * time around. */ while (chunk_offset >= chunks->chunk[chunk_index].len) { - /* Make sure that the chunk is not padded */ - if (chunks->chunk[chunk_index].len % bitmap->stride != 0) { - spice_warning("chunk %d/%d is padded, cannot copy line %d/%d", - chunk_index, chunks->num_chunks, l, height); + if (is_chunk_padded(bitmap, chunk_index)) { return FALSE; } chunk_offset -= chunks->chunk[chunk_index].len; @@ -369,18 +384,83 @@ static inline int line_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, return TRUE; } +#ifdef DO_ZERO_COPY +/* A helper for zero_copy() */ +static void unref_bitmap(gpointer mem) +{ +SpiceGstEncoder *encoder = (SpiceGstEncoder*)mem; +encoder->needs_bitmap = FALSE; +} + +/* A helper for push_raw_frame() */ +static inline int zero_copy(SpiceGstEncoder *encoder, const SpiceBitmap *bitmap, +GstBuffer *buffer, uint32_t *chunk_index, +uint32_t *chunk_offset, uint32_t *len) +{ +/* We cannot control the lifetime of the bitmap but we can wrap it in + * the buffer anyway because: + * - Before returning from gst_encoder_encode_frame() we wait for the + * pipeline to have converted this frame into a compressed buffer. + * So it has to have gone through the frame at least once. + * - For all encoders but MJPEG, the first element of the pipeline will + * convert the bitmap to another image format which entails copying + * it. So by the time the encoder starts its work, this buffer will + * not be needed anymore. + * - The MJPEG encoder does not perform inter-frame compression and thus + * does not need to keep hold of this buffer once it has processed it. + * encoder->needs_bitmap lets us verify that these conditions still hold + * true through an assert. + */ +SpiceChunks *chunks = bitmap->data; +while (*chunk_offset >= chunks->chunk[*chunk_index].len) { +if (is_chunk_padded(bitmap, *chunk_index)) { +return FALSE; +} +*chunk_offset -= chunks->chunk[*chunk_index].len; +(*chunk_index)++; +} + +int max_mem = gst_buffer_get_max_memory(); +if (chunks->num_chunks - *chunk_index > max_mem) { +/* There are more chunks than we can fit memory objects in a + * buffer. This will cause the buffer to merge memory objects to + * fit the extra chunks, which means doing wasteful memory copies. + * So use the zero-copy approach for the first max
[Spice-devel] [spice v9 10/24] server: Shape the bit rate of the GStreamer codecs output
The GStreamer codecs don't follow the specified bit rate very closely: they can decide to exceed it for ten seconds or more if they consider the scene deserves it. Such long bursts are enough to cause network congestion, resulting in many lost frames which cause significant display corruption. So the GStreamer video encoder now uses a short 300ms virtual buffer to shape the compressed video output and ensure we don't exceed the target bit rate for any significant length of time. It could instead rely on the network feedback (when available) to lower the bit rate. However frequent GStreamer bit rate changes lower the overall compression level and also result in a lower average bit rate, both of which result in lower video quality. The GStreamer video encoder also keeps track of the encoded frame size so it can gather statistics and call update_client_playback_delay() with accurate information and also annotate the client report debug traces with the corresponding bit rate information. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 291 +++-- 1 file changed, 284 insertions(+), 7 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index fe07852..d384135 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -26,6 +26,7 @@ #include "red-common.h" #include "video-encoder.h" +#include "utils.h" #define SPICE_GST_DEFAULT_FPS 30 @@ -45,6 +46,11 @@ typedef struct SpiceGstVideoBuffer { GstMapInfo map; } SpiceGstVideoBuffer; +typedef struct { +uint32_t mm_time; +uint32_t size; +} SpiceGstFrameInformation; + typedef struct SpiceGstEncoder { VideoEncoder base; @@ -83,6 +89,45 @@ typedef struct SpiceGstEncoder { /* The frame counter for GStreamer buffers */ uint32_t frame; + +/* -- Encoded frame statistics -- */ + +/* Should be >= than FRAME_STATISTICS_COUNT. This is also used to annotate + * the client report debug traces with bit rate information. + */ +# define SPICE_GST_HISTORY_SIZE 60 + +/* A circular buffer containing the past encoded frames information. */ +SpiceGstFrameInformation history[SPICE_GST_HISTORY_SIZE]; + +/* The indices of the oldest and newest frames in the history buffer. */ +uint32_t history_first; +uint32_t history_last; + +/* How many frames to take into account when computing the effective + * bit rate, average frame size, etc. This should be large enough so the + * I and P frames average out, and short enough for it to reflect the + * current situation. + */ +# define SPICE_GST_FRAME_STATISTICS_COUNT 21 + +/* The index of the oldest frame taken into account for the statistics. */ +uint32_t stat_first; + +/* Used to compute the average frame size. */ +uint64_t stat_sum; + +/* Tracks the maximum frame size. */ +uint32_t stat_maximum; + + +/* -- Encoder bit rate control -- + * + * GStreamer encoders don't follow the specified bit rate very + * closely. These fields are used to ensure we don't exceed the desired + * stream bit rate, regardless of the GStreamer encoder's output. + */ + /* The bit rate target for the outgoing network stream. (bits per second) */ uint64_t bit_rate; @@ -91,6 +136,27 @@ typedef struct SpiceGstEncoder { /* The default bit rate */ # define SPICE_GST_DEFAULT_BITRATE (8 * 1024 * 1024) + +/* The bit rate control is performed using a virtual buffer to allow short + * term variations: bursts are allowed until the virtual buffer is full. + * Then frames are dropped to limit the bit rate. VBUFFER_SIZE defines the + * size of the virtual buffer in milliseconds worth of data. + */ +# define SPICE_GST_VBUFFER_SIZE 300 + +int32_t vbuffer_size; +int32_t vbuffer_free; + +/* When dropping frames, this is set to the minimum mm_time of the next + * frame to encode. Otherwise set to zero. + */ +uint32_t next_frame; + +/* Defines the minimum allowed fps. */ +# define SPICE_GST_MAX_PERIOD (NSEC_PER_SEC / 3) + +/* How big of a margin to take to cover for latency jitter. */ +# define SPICE_GST_LATENCY_MARGIN 0.1 } SpiceGstEncoder; @@ -127,6 +193,18 @@ static uint32_t get_source_fps(SpiceGstEncoder *encoder) encoder->cbs.get_source_fps(encoder->cbs_opaque) : SPICE_GST_DEFAULT_FPS; } +static uint32_t get_network_latency(SpiceGstEncoder *encoder) +{ +/* Assume that the network latency is symmetric */ +return encoder->cbs.get_roundtrip_ms ? +encoder->cbs.get_roundtrip_ms(encoder->cbs_opaque) / 2 : 0; +} + +static inline int rate_control_is_active(SpiceGstEncoder* encoder) +{ +return encoder->cbs.get_roundtrip_ms != NULL; +} + static inline int is_pipeline_configured(SpiceGstEncoder *encoder) { return encoder->src_caps != NULL; @@ -148,6 +226,182 @@ static void free_pipeline(SpiceGs
[Spice-devel] [spice v9 11/24] server: Adjust the GStreamer encoder bit rate to the network
The video encoder uses the client reports and/or notifications of server frame drops as its feedback mechanisms. In particular it keeps track of the maximum video margin and reduces the bit rate whenever the margin goes below certain thresholds or decreases too sharply. It uses these to figure out the lowest bit rate that causes negative feedback, and the highest bit rate that allows a return to positive feedbacks. It then works to narrow this range and settles on the lower end once the spread has gone below a given threshold. All the while it monitors the effective bit rate to ensure the target bit rate does not grow significantly beyond what the GStreamer encoder will produce: this avoids target bit rate 'bubbles' which would invariably be followed by a bit rate crash with accompanying frame loss. As soon as the network feedback indicates a significant degradation the bit rate is lowered to minimize the risk of frame loss and/or long freezes. It also relies on the existing shaping of the GStreamer output bit rate to minimize the pipeline reconfigurations. Signed-off-by: Francois Gouget --- server/gstreamer-encoder.c | 407 ++--- 1 file changed, 383 insertions(+), 24 deletions(-) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index d384135..44072f0 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -51,6 +51,12 @@ typedef struct { uint32_t size; } SpiceGstFrameInformation; +typedef enum SpiceGstBitRateStatus { +SPICE_GST_BITRATE_DECREASING, +SPICE_GST_BITRATE_INCREASING, +SPICE_GST_BITRATE_STABLE, +} SpiceGstBitRateStatus; + typedef struct SpiceGstEncoder { VideoEncoder base; @@ -89,6 +95,12 @@ typedef struct SpiceGstEncoder { /* The frame counter for GStreamer buffers */ uint32_t frame; +/* The GStreamer bit rate. */ +uint64_t video_bit_rate; + +/* Don't bother changing the GStreamer bit rate if close enough. */ +# define SPICE_GST_VIDEO_BITRATE_MARGIN 0.05 + /* -- Encoded frame statistics -- */ @@ -123,7 +135,7 @@ typedef struct SpiceGstEncoder { /* -- Encoder bit rate control -- * - * GStreamer encoders don't follow the specified bit rate very + * GStreamer encoders don't follow the specified video_bit_rate very * closely. These fields are used to ensure we don't exceed the desired * stream bit rate, regardless of the GStreamer encoder's output. */ @@ -131,7 +143,7 @@ typedef struct SpiceGstEncoder { /* The bit rate target for the outgoing network stream. (bits per second) */ uint64_t bit_rate; -/* The minimum bit rate */ +/* The minimum bit rate / bit rate increment. */ # define SPICE_GST_MIN_BITRATE (128 * 1024) /* The default bit rate */ @@ -157,6 +169,89 @@ typedef struct SpiceGstEncoder { /* How big of a margin to take to cover for latency jitter. */ # define SPICE_GST_LATENCY_MARGIN 0.1 + + +/* -- Network bit rate control -- + * + * State information for figuring out the optimal bit rate for the current + * network conditions. + */ + +/* The mm_time of the last bit rate change. */ +uint32_t last_change; + +/* How much to reduce the bit rate in case of network congestion. */ +# define SPICE_GST_BITRATE_CUT 2 +# define SPICE_GST_BITRATE_REDUCE (4.0 / 3.0) + +/* Never increase the bit rate by more than this amount (bits per second). */ +# define SPICE_GST_BITRATE_MAX_STEP (1024 * 1024) + +/* The maximum bit rate that one can maybe use without causing network + * congestion. + */ +uint64_t max_bit_rate; + +/* The last bit rate that let us recover from network congestion. */ +uint64_t min_bit_rate; + +/* Defines when the spread between max_bit_rate and min_bit_rate has been + * narrowed down enough. Note that this value should be large enough for + * min_bit_rate to allow recovery from network congestion in a reasonable + * time frame, and to absorb transient traffic spikes (potentially from + * other sources). + * This is also used as a multiplier for the video_bit_rate so it does not + * have to be changed too often. + */ +# define SPICE_GST_BITRATE_MARGIN SPICE_GST_BITRATE_REDUCE + +/* Whether the bit rate was last decreased, increased or kept stable. */ +SpiceGstBitRateStatus status; + +/* The network bit rate control uses an AIMD scheme (Additive Increase, + * Multiplicative Decrease). The increment step depends on the spread + * between the minimum and maximum bit rates. + */ +uint64_t bit_rate_step; + +/* How often to increase the bit rate. */ +uint32_t increase_interval; + +# define SPICE_GST_BITRATE_UP_INTERVAL (MSEC_PER_SEC * 2) +# define SPICE_GST_BITRATE_UP_CLIENT_STABLE (MSEC_PER_SEC * 60 * 2) +# define SPICE_GST_BITRATE_UP_SERVER_STABLE (MSEC_PER_SEC * 3600 * 4) +# def
[Spice-devel] [spice v9 07/24] server: Let the video encoder manage the compressed buffer
This way the video encoder is not forced to use malloc()/free(). This also allows more flexibility in how the video encoder manages the buffer which allows for a zero-copy implementation in both video encoders. Signed-off-by: Francois Gouget --- server/dcc-send.c | 24 +++-- server/dcc.c | 5 --- server/dcc.h | 3 -- server/gstreamer-encoder.c | 55 ++--- server/mjpeg-encoder.c | 87 +- server/video-encoder.h | 28 +++ 6 files changed, 124 insertions(+), 78 deletions(-) diff --git a/server/dcc-send.c b/server/dcc-send.c index e13f04f..e360018 100644 --- a/server/dcc-send.c +++ b/server/dcc-send.c @@ -1649,6 +1649,12 @@ static void red_lossy_marshall_qxl_draw_text(RedChannelClient *rcc, } } +static void red_release_video_encoder_buffer(uint8_t *data, void *opaque) +{ +VideoBuffer *buffer = (VideoBuffer*)opaque; +buffer->free(buffer); +} + static int red_marshall_stream_data(RedChannelClient *rcc, SpiceMarshaller *base_marshaller, Drawable *drawable) { @@ -1657,7 +1663,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc, Stream *stream = drawable->stream; SpiceImage *image; uint32_t frame_mm_time; -int n; +VideoBuffer *outbuf; int width, height; int ret; @@ -1689,7 +1695,6 @@ static int red_marshall_stream_data(RedChannelClient *rcc, StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)]; uint64_t time_now = spice_get_monotonic_time_ns(); -size_t outbuf_size; if (!dcc->use_video_encoder_rate_control) { if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { @@ -1705,13 +1710,11 @@ static int red_marshall_stream_data(RedChannelClient *rcc, frame_mm_time = drawable->red_drawable->mm_time ? drawable->red_drawable->mm_time : reds_get_mm_time(); -outbuf_size = dcc->send_data.stream_outbuf_size; ret = agent->video_encoder->encode_frame(agent->video_encoder, &image->u.bitmap, width, height, &drawable->red_drawable->u.copy.src_area, stream->top_down, frame_mm_time, - &dcc->send_data.stream_outbuf, - &outbuf_size, &n); + &outbuf); switch (ret) { case VIDEO_ENCODER_FRAME_DROP: spice_assert(dcc->use_video_encoder_rate_control); @@ -1727,7 +1730,6 @@ static int red_marshall_stream_data(RedChannelClient *rcc, spice_error("bad return value (%d) from VideoEncoder::encode_frame", ret); return FALSE; } -dcc->send_data.stream_outbuf_size = outbuf_size; if (!drawable->sized_stream) { SpiceMsgDisplayStreamData stream_data; @@ -1736,7 +1738,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc, stream_data.base.id = get_stream_id(display, stream); stream_data.base.multi_media_time = frame_mm_time; -stream_data.data_size = n; +stream_data.data_size = outbuf->size; spice_marshall_msg_display_stream_data(base_marshaller, &stream_data); } else { @@ -1746,7 +1748,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc, stream_data.base.id = get_stream_id(display, stream); stream_data.base.multi_media_time = frame_mm_time; -stream_data.data_size = n; +stream_data.data_size = outbuf->size; stream_data.width = width; stream_data.height = height; stream_data.dest = drawable->red_drawable->bbox; @@ -1755,12 +1757,12 @@ static int red_marshall_stream_data(RedChannelClient *rcc, rect_debug(&stream_data.dest); spice_marshall_msg_display_stream_data_sized(base_marshaller, &stream_data); } -spice_marshaller_add_ref(base_marshaller, - dcc->send_data.stream_outbuf, n); +spice_marshaller_add_ref_full(base_marshaller, outbuf->data, outbuf->size, + &red_release_video_encoder_buffer, outbuf); agent->last_send_time = time_now; #ifdef STREAM_STATS agent->stats.num_frames_sent++; -agent->stats.size_sent += n; +agent->stats.size_sent += outbuf->size; agent->stats.end = frame_mm_time; #endif diff --git a/server/dcc.c b/server/dcc.c index ed4598f..26fc754 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -384,10 +384,6 @@ DisplayChannelClient *dcc_new(DisplayChannel *display, // TODO: tune quality according to bandwidth dcc->jpeg_quality = 85; -size_t stream_buf_size; -stream_buf_size = 32*1024; -dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size); -dcc->send_data.stream_out
[Spice-devel] [spice v9 06/24] server: Add VP8 support to the GStreamer video encoder
Signed-off-by: Francois Gouget --- configure.ac | 4 +++ server/gstreamer-encoder.c | 73 +++--- server/video-encoder.h | 2 +- 3 files changed, 68 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 174f01f..a902e84 100644 --- a/configure.ac +++ b/configure.ac @@ -130,6 +130,10 @@ AC_SUBST([SPICE_PROTOCOL_MIN_VER]) PKG_CHECK_MODULES([GLIB2], [glib-2.0 >= 2.22]) AS_VAR_APPEND([SPICE_REQUIRES], [" glib-2.0 >= 2.22"]) +AC_CHECK_LIB(glib-2.0, g_get_num_processors, + AC_DEFINE([HAVE_G_GET_NUMPROCESSORS], 1, [Defined if we have g_get_num_processors()]),, + $GLIB2_LIBS) + PKG_CHECK_MODULES(PIXMAN, pixman-1 >= 0.17.7) AC_SUBST(PIXMAN_CFLAGS) AC_SUBST(PIXMAN_LIBS) diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index edf87df..6dab5f9 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -192,10 +192,26 @@ static void set_appsrc_caps(SpiceGstEncoder *encoder) /* A helper for spice_gst_encoder_encode_frame() */ static gboolean create_pipeline(SpiceGstEncoder *encoder) { +const gchar* gstenc_name; +switch (encoder->base.codec_type) +{ +case SPICE_VIDEO_CODEC_TYPE_MJPEG: +gstenc_name = "avenc_mjpeg"; +break; +case SPICE_VIDEO_CODEC_TYPE_VP8: +gstenc_name = "vp8enc"; +break; +default: +/* gstreamer_encoder_new() should have rejected this codec type */ +spice_warning("unsupported codec type %d", encoder->base.codec_type); +return FALSE; +} + GError *err = NULL; -const gchar *desc = "appsrc name=src format=2 do-timestamp=true ! videoconvert ! avenc_mjpeg name=encoder ! appsink name=sink"; +gchar *desc = g_strdup_printf("appsrc name=src format=2 do-timestamp=true ! videoconvert ! %s name=encoder ! appsink name=sink", gstenc_name); spice_debug("GStreamer pipeline: %s", desc); encoder->pipeline = gst_parse_launch_full(desc, NULL, GST_PARSE_FLAG_FATAL_ERRORS, &err); +g_free(desc); if (!encoder->pipeline || err) { spice_warning("GStreamer error: %s", err->message); g_clear_error(&err); @@ -221,18 +237,45 @@ static gboolean configure_pipeline(SpiceGstEncoder *encoder, /* Configure the encoder bitrate, frame latency, etc. */ adjust_bit_rate(encoder); -g_object_set(G_OBJECT(encoder->gstenc), - "bitrate", encoder->bit_rate, - "max-threads", 1, /* zero-frame latency */ - NULL); +switch (encoder->base.codec_type) { +case SPICE_VIDEO_CODEC_TYPE_MJPEG: +g_object_set(G_OBJECT(encoder->gstenc), + "bitrate", encoder->bit_rate, + "max-threads", 1, /* zero-frame latency */ + NULL); + +/* See https://bugzilla.gnome.org/show_bug.cgi?id=753257 */ +spice_debug("removing the pipeline clock"); +gst_pipeline_use_clock(GST_PIPELINE(encoder->pipeline), NULL); +break; +case SPICE_VIDEO_CODEC_TYPE_VP8: { +/* See http://www.webmproject.org/docs/encoder-parameters/ */ +#ifdef HAVE_G_GET_NUMPROCESSORS +int core_count = g_get_num_processors(); +#else +int core_count = 1; +#endif +g_object_set(G_OBJECT(encoder->gstenc), + "resize-allowed", TRUE, /* for very low bit rates */ + "target-bitrate", encoder->bit_rate, + "end-usage", 1, /* CBR */ + "lag-in-frames", 0, /* zero-frame latency */ + "error-resilient", 1, /* for client frame drops */ + "deadline", 100 / get_source_fps(encoder) / 2, /* usec */ + "threads", core_count - 1, + NULL); +break; +} +default: +/* gstreamer_encoder_new() should have rejected this codec type */ +spice_warning("unknown encoder type %d", encoder->base.codec_type); +free_pipeline(encoder); +return FALSE; +} /* Set the source caps */ set_appsrc_caps(encoder); -/* See https://bugzilla.gnome.org/show_bug.cgi?id=753257 */ -spice_debug("removing the pipeline clock"); -gst_pipeline_use_clock(GST_PIPELINE(encoder->pipeline), NULL); - /* Start playing */ spice_debug("setting state to PLAYING"); if (gst_element_set_state(encoder->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) { @@ -250,6 +293,15 @@ static void reconfigure_pipeline(SpiceGstEncoder *encoder) if (!is_pipeline_configured(encoder)) { return; } +if (encoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_VP8) { +/* vp8enc fails to account for caps changes that modify the frame size + * and complains about the buffer size. + * So recreate the pipeline from scratch. + */ +free_pipeline(encoder); +return; +} + if (gst_element_set_state(
[Spice-devel] [spice v9 04/24] server: Check the client video codec capabilities
Signed-off-by: Francois Gouget --- configure.ac| 2 +- server/dcc.c| 5 - server/dcc.h| 2 +- server/stream.c | 41 + 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index f80178e..174f01f 100644 --- a/configure.ac +++ b/configure.ac @@ -123,7 +123,7 @@ AS_IF([test x"$have_smartcard" = "xyes"], [ AS_VAR_APPEND([SPICE_REQUIRES], [" libcacard >= 0.1.2"]) ]) -SPICE_PROTOCOL_MIN_VER=0.12.10 +SPICE_PROTOCOL_MIN_VER=0.12.11 PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER]) AC_SUBST([SPICE_PROTOCOL_MIN_VER]) diff --git a/server/dcc.c b/server/dcc.c index 21e91c0..ed4598f 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -407,7 +407,10 @@ static void dcc_create_all_streams(DisplayChannelClient *dcc) while ((item = ring_next(ring, item))) { Stream *stream = SPICE_CONTAINEROF(item, Stream, link); -dcc_create_stream(dcc, stream); +if (!dcc_create_stream(dcc, stream)) { +stream_stop(DCC_TO_DC(dcc), stream); +return; +} } } diff --git a/server/dcc.h b/server/dcc.h index b510254..34ca346 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -173,7 +173,7 @@ void dcc_destroy_surface (DisplayCha uint32_t surface_id); void dcc_stream_agent_clip (DisplayChannelClient* dcc, StreamAgent *agent); -void dcc_create_stream (DisplayChannelClient *dcc, +gboolean dcc_create_stream (DisplayChannelClient *dcc, Stream *stream); void dcc_create_surface (DisplayChannelClient *dcc, int surface_id); diff --git a/server/stream.c b/server/stream.c index 9c335b6..bbc7003 100644 --- a/server/stream.c +++ b/server/stream.c @@ -440,7 +440,12 @@ static void display_channel_create_stream(DisplayChannel *display, Drawable *dra display->streams_size_total += stream->width * stream->height; display->stream_count++; FOREACH_DCC(display, dcc_ring_item, next, dcc) { -dcc_create_stream(dcc, stream); +if (!dcc_create_stream(dcc, stream)) { +drawable->stream = NULL; +stream->current = NULL; +stream_stop(display, stream); +return; +} } spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps", (int)(stream - display->streams_buf), stream->width, @@ -695,25 +700,32 @@ static void update_client_playback_delay(void *opaque, uint32_t delay_ms) } /* A helper for dcc_create_stream(). */ -static VideoEncoder* dcc_create_video_encoder(uint64_t starting_bit_rate, +static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc, + uint64_t starting_bit_rate, VideoEncoderRateControlCbs *cbs, void *cbs_opaque) { +RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc); +int client_has_multi_codec = red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_MULTI_CODEC); +if (!client_has_multi_codec || red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_CODEC_MJPEG)) { #ifdef HAVE_GSTREAMER_1_0 -VideoEncoder* video_encoder = gstreamer_encoder_new(starting_bit_rate, cbs, cbs_opaque); -if (video_encoder) { -return video_encoder; -} +VideoEncoder* video_encoder = gstreamer_encoder_new(starting_bit_rate, cbs, cbs_opaque); +if (video_encoder) { +return video_encoder; +} #endif -/* Use the builtin MJPEG video encoder as a fallback */ -return mjpeg_encoder_new(starting_bit_rate, cbs, cbs_opaque); +/* Use the builtin MJPEG video encoder as a fallback */ +return mjpeg_encoder_new(starting_bit_rate, cbs, cbs_opaque); +} + +return NULL; } -void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream) +gboolean dcc_create_stream(DisplayChannelClient *dcc, Stream *stream) { StreamAgent *agent = &dcc->stream_agents[get_stream_id(DCC_TO_DC(dcc), stream)]; -spice_return_if_fail(region_is_empty(&agent->vis_region)); +spice_return_val_if_fail(region_is_empty(&agent->vis_region), FALSE); stream->refs++; if (stream->current) { @@ -736,9 +748,13 @@ void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream) video_cbs.update_client_playback_delay = update_client_playback_delay; initial_bit_rate = get_initial_bit_rate(dcc, stream); -agent->video_e
[Spice-devel] [spice v9 05/24] server: Let the administrator pick the video encoder and codec
The Spice server administrator can specify the preferred encoder and codec preferences to optimize for CPU or bandwidth usage. Preferences are described in a semi-colon separated list of encoder:codec pairs. The server has a default preference list which can explicitly be selected by specifying 'auto'. The server then picks a codec supported by the client based on the following new client capabilities: * SPICE_DISPLAY_CAP_MULTI_CODEC which denotes a recent client that supports multiple codecs. This capability is needed to not have to hardcode that MJPEG is supported. This makes it possible to write clients that don't support MJPEG. * SPICE_DISPLAY_CAP_CODEC_XXX, where XXX is a supported codec. Note that for now the server only supports the MJPEG codec. Signed-off-by: Francois Gouget --- server/dcc-send.c | 2 +- server/display-channel.c | 13 server/display-channel.h | 5 ++ server/gstreamer-encoder.c | 6 +- server/mjpeg-encoder.c | 6 +- server/red-dispatcher.c| 17 + server/red-dispatcher.h| 8 +++ server/red-worker.c| 14 server/reds.c | 155 - server/reds.h | 13 server/spice-server.h | 1 + server/spice-server.syms | 5 ++ server/stream.c| 29 +++-- server/video-encoder.h | 23 ++- 14 files changed, 269 insertions(+), 28 deletions(-) diff --git a/server/dcc-send.c b/server/dcc-send.c index fd11b09..e13f04f 100644 --- a/server/dcc-send.c +++ b/server/dcc-send.c @@ -2189,7 +2189,7 @@ static void marshall_stream_start(RedChannelClient *rcc, stream_create.surface_id = 0; stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream); stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0; -stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG; +stream_create.codec_type = agent->video_encoder->codec_type; stream_create.src_width = stream->width; stream_create.src_height = stream->height; diff --git a/server/display-channel.c b/server/display-channel.c index 3bf065c..e81e697 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -219,6 +219,17 @@ void display_channel_set_stream_video(DisplayChannel *display, int stream_video) display->stream_video = stream_video; } +void display_channel_set_video_codecs(DisplayChannel *display, + int num_video_codecs, + RedVideoCodec *video_codecs) +{ +spice_return_if_fail(display); +spice_return_if_fail(num_video_codecs > RED_MAX_VIDEO_CODECS); + +display->num_video_codecs = num_video_codecs; +memcpy(display->video_codecs, video_codecs, sizeof(display->video_codecs)); +} + static void stop_streams(DisplayChannel *display) { Ring *ring = &display->streams; @@ -2072,6 +2083,8 @@ DisplayChannel* display_channel_new(RedWorker *worker, int migrate, int stream_v drawables_init(display); image_cache_init(&display->image_cache); display->stream_video = stream_video; +display->num_video_codecs = num_video_codecs; +memcpy(display->video_codecs, video_codecs, sizeof(display->video_codecs)); display_channel_init_streams(display); return display; diff --git a/server/display-channel.h b/server/display-channel.h index bf29cd3..f55d23b 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -185,6 +185,8 @@ struct DisplayChannel { uint32_t glz_drawable_count; int stream_video; +uint32_t num_video_codecs; +RedVideoCodec video_codecs[RED_MAX_VIDEO_CODECS]; uint32_t stream_count; Stream streams_buf[NUM_STREAMS]; Stream *free_streams; @@ -273,6 +275,9 @@ void display_channel_update (DisplayCha void display_channel_free_some (DisplayChannel *display); void display_channel_set_stream_video (DisplayChannel *display, int stream_video); +void display_channel_set_video_codecs (DisplayChannel *display, + int num_video_codecs, + RedVideoCodec *video_codecs); intdisplay_channel_get_streams_timeout (DisplayChannel *display); void display_channel_compress_stats_print (const DisplayChannel *display); void display_channel_compress_stats_reset (DisplayChannel *display); diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c index e934180..edf87df 100644 --- a/server/gstreamer-encoder.c +++ b/server/gstreamer-encoder.c @@ -494,10 +494,13 @@ static void spice_gst_encoder_get_stats(VideoEncoder *video_encoder,
[Spice-devel] [spice v9 03/24] server: Add a GStreamer 1.0 MJPEG video encoder and use it by default
This introduces a pared down GStreamer-based video encoder to serve as the basis for later enhancements. In this form the new encoder supports both regular and sized streams but lacks any rate control. It should still work fine if bandwidth is sufficient such as on LANs. Signed-off-by: Francois Gouget --- configure.ac | 25 +++ server/Makefile.am | 8 + server/gstreamer-encoder.c | 530 + server/stream.c| 19 +- server/video-encoder.h | 5 + 5 files changed, 585 insertions(+), 2 deletions(-) create mode 100644 server/gstreamer-encoder.c diff --git a/configure.ac b/configure.ac index 2b09ec7..f80178e 100644 --- a/configure.ac +++ b/configure.ac @@ -69,6 +69,30 @@ dnl = dnl Check optional features SPICE_CHECK_SMARTCARD +AC_ARG_ENABLE(gstreamer, + AS_HELP_STRING([--enable-gstreamer=@<:@auto/yes/no@:>@], + [Enable GStreamer 1.0 support]),, + [enable_gstreamer="auto"]) + +if test "x$enable_gstreamer" != "xno"; then +SPICE_CHECK_GSTREAMER(GSTREAMER_1_0, 1.0, [gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0], +[enable_gstreamer="yes" + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-base 1.0], [appsrc videoconvert appsink]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gstreamer-libav 1.0], [avenc_mjpeg]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-good 1.0], [vp8enc]) + SPICE_CHECK_GSTREAMER_ELEMENTS($GST_INSPECT_1_0, [gst-plugins-ugly 1.0], [x264enc]) + ], + [if test "x$enable_gstreamer" = "xyes"; then + AC_MSG_ERROR([GStreamer 1.0 support requested but not found. You may set GSTREAMER_1_0_CFLAGS and GSTREAMER_1_0_LIBS to avoid the need to call pkg-config.]) + fi +]) +fi +AM_CONDITIONAL(HAVE_GSTREAMER_1_0, test "x$have_gstreamer_1_0" = "xyes") + +if test x"$gstreamer_missing" != x; then +SPICE_WARNING([The following GStreamer $enable_gstreamer tools/elements are missing:$gstreamer_missing. The GStreamer video encoder can be built but may not work.]) +fi + AC_ARG_ENABLE([automated_tests], AS_HELP_STRING([--enable-automated-tests], [Enable automated tests using spicy-screenshot (part of spice--gtk)]),, [enable_automated_tests="no"]) @@ -238,6 +262,7 @@ AC_MSG_NOTICE([ LZ4 support: ${enable_lz4} Smartcard:${have_smartcard} +GStreamer 1.0:${have_gstreamer_1_0} SASL support: ${have_sasl} Automated tests: ${enable_automated_tests} Manual: ${have_asciidoc} diff --git a/server/Makefile.am b/server/Makefile.am index edeca99..9f33c93 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ $(SASL_CFLAGS) \ $(SLIRP_CFLAGS) \ $(SMARTCARD_CFLAGS) \ + $(GSTREAMER_1_0_CFLAGS) \ $(SPICE_PROTOCOL_CFLAGS)\ $(SSL_CFLAGS) \ $(VISIBILITY_HIDDEN_CFLAGS) \ @@ -43,6 +44,7 @@ libserver_la_LIBADD = \ $(PIXMAN_LIBS) \ $(SASL_LIBS)\ $(SLIRP_LIBS) \ + $(GSTREAMER_1_0_LIBS) \ $(SSL_LIBS) \ $(Z_LIBS) \ $(SPICE_NONPKGCONFIG_LIBS) \ @@ -151,6 +153,12 @@ libserver_la_SOURCES +=\ $(NULL) endif +if HAVE_GSTREAMER_1_0 +libserver_la_SOURCES +=\ + gstreamer-encoder.c \ + $(NULL) +endif + libspice_server_la_LIBADD = libserver.la libspice_server_la_SOURCES = diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c new file mode 100644 index 000..e934180 --- /dev/null +++ b/server/gstreamer-encoder.c @@ -0,0 +1,530 @@ +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* + Copyright (C) 2015 Jeremy White + Copyright (C) 2015 Francois Gouget + + 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
[Spice-devel] [spice v9 02/24] server: Enable adding alternative MJPEG video encoders
This replaces the original mjpeg_encoder API with a VideoEncoder base class which can be reimplemented by other encoders. This also renames the members and enums from mjpeg_* to video_*. Signed-off-by: Francois Gouget --- server/Makefile.am | 2 +- server/dcc-send.c | 24 server/dcc.c | 24 server/dcc.h | 2 +- server/mjpeg-encoder.c | 84 +++--- server/mjpeg-encoder.h | 100 --- server/stream.c| 40 ++--- server/stream.h| 4 +- server/video-encoder.h | 160 + 9 files changed, 258 insertions(+), 182 deletions(-) delete mode 100644 server/mjpeg-encoder.h create mode 100644 server/video-encoder.h diff --git a/server/Makefile.am b/server/Makefile.am index b20beec..edeca99 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -84,7 +84,6 @@ libserver_la_SOURCES =\ main-channel.c \ main-channel.h \ mjpeg-encoder.c \ - mjpeg-encoder.h \ red-channel.c \ red-channel.h \ red-common.h\ @@ -122,6 +121,7 @@ libserver_la_SOURCES = \ spicevmc.c \ spice_timer_queue.c \ spice_timer_queue.h \ + video-encoder.h \ zlib-encoder.c \ zlib-encoder.h \ image-cache.h \ diff --git a/server/dcc-send.c b/server/dcc-send.c index c3f79ef..fd11b09 100644 --- a/server/dcc-send.c +++ b/server/dcc-send.c @@ -1691,7 +1691,7 @@ static int red_marshall_stream_data(RedChannelClient *rcc, uint64_t time_now = spice_get_monotonic_time_ns(); size_t outbuf_size; -if (!dcc->use_mjpeg_encoder_rate_control) { +if (!dcc->use_video_encoder_rate_control) { if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { agent->frames--; #ifdef STREAM_STATS @@ -1706,25 +1706,25 @@ static int red_marshall_stream_data(RedChannelClient *rcc, drawable->red_drawable->mm_time : reds_get_mm_time(); outbuf_size = dcc->send_data.stream_outbuf_size; -ret = mjpeg_encoder_encode_frame(agent->mjpeg_encoder, - &image->u.bitmap, width, height, - &drawable->red_drawable->u.copy.src_area, - stream->top_down, frame_mm_time, -&dcc->send_data.stream_outbuf, - &outbuf_size, &n); +ret = agent->video_encoder->encode_frame(agent->video_encoder, + &image->u.bitmap, width, height, + &drawable->red_drawable->u.copy.src_area, + stream->top_down, frame_mm_time, + &dcc->send_data.stream_outbuf, + &outbuf_size, &n); switch (ret) { -case MJPEG_ENCODER_FRAME_DROP: -spice_assert(dcc->use_mjpeg_encoder_rate_control); +case VIDEO_ENCODER_FRAME_DROP: +spice_assert(dcc->use_video_encoder_rate_control); #ifdef STREAM_STATS agent->stats.num_drops_fps++; #endif return TRUE; -case MJPEG_ENCODER_FRAME_UNSUPPORTED: +case VIDEO_ENCODER_FRAME_UNSUPPORTED: return FALSE; -case MJPEG_ENCODER_FRAME_ENCODE_DONE: +case VIDEO_ENCODER_FRAME_ENCODE_DONE: break; default: -spice_error("bad return value (%d) from mjpeg_encoder_encode_frame", ret); +spice_error("bad return value (%d) from VideoEncoder::encode_frame", ret); return FALSE; } dcc->send_data.stream_outbuf_size = outbuf_size; diff --git a/server/dcc.c b/server/dcc.c index 2568e24..21e91c0 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -350,7 +350,7 @@ static void dcc_init_stream_agents(DisplayChannelClient *dcc) red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE); red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY); } -dcc->use_mjpeg_encoder_rate_control = +dcc->use_video_encoder_rate_control = red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT); } @@ -474,9 +474,9 @@ static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) StreamAgent *agent = &dcc->stream_agents[i]; region_destroy(&agent->vis_region); region_destroy(&agent->clip); -i
[Spice-devel] [protocol v9 01/24] protocol: Add support for the VP8 and h264 video codecs
Clients that support multiple codecs must advertise the SPICE_DISPLAY_CAP_MULTI_CODEC capability and one SPICE_DISPLAY_CAP_CODEC_XXX per supported codec. Signed-off-by: Francois Gouget --- spice.proto | 2 ++ spice/enums.h| 2 ++ spice/protocol.h | 4 3 files changed, 8 insertions(+) diff --git a/spice.proto b/spice.proto index af970f2..4a0778d 100644 --- a/spice.proto +++ b/spice.proto @@ -329,6 +329,8 @@ flags8 path_flags { /* TODO: C enum names changes */ enum8 video_codec_type { MJPEG = 1, +VP8, +H264, }; flags8 stream_flags { diff --git a/spice/enums.h b/spice/enums.h index 613db52..c6e9840 100644 --- a/spice/enums.h +++ b/spice/enums.h @@ -139,6 +139,8 @@ typedef enum SpicePathFlags { typedef enum SpiceVideoCodecType { SPICE_VIDEO_CODEC_TYPE_MJPEG = 1, +SPICE_VIDEO_CODEC_TYPE_VP8, +SPICE_VIDEO_CODEC_TYPE_H264, SPICE_VIDEO_CODEC_TYPE_ENUM_END } SpiceVideoCodecType; diff --git a/spice/protocol.h b/spice/protocol.h index 3e6c624..f4a2259 100644 --- a/spice/protocol.h +++ b/spice/protocol.h @@ -137,6 +137,10 @@ enum { SPICE_DISPLAY_CAP_LZ4_COMPRESSION, SPICE_DISPLAY_CAP_PREF_COMPRESSION, SPICE_DISPLAY_CAP_GL_SCANOUT, +SPICE_DISPLAY_CAP_MULTI_CODEC, +SPICE_DISPLAY_CAP_CODEC_MJPEG, +SPICE_DISPLAY_CAP_CODEC_VP8, +SPICE_DISPLAY_CAP_CODEC_H264, }; enum { -- 2.6.4 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH v9 00/24] Add GStreamer support for video streaming
The source changed so here is the new revision of this patchset. This patch series adds support for using GStreamer to encode and decode the video streams, adding support for VP8 and h264 codecs. As before the patches can also be grabbed from the repositories below: spice: https://github.com/fgouget/spice spice-gtk: https://github.com/fgouget/spice-gtk xf86-video-qxl: https://github.com/fgouget/xf86-video-qxl spice-protocol: https://github.com/fgouget/spice-protocol (there's also 'extras' branches with more experimental/future patches for the curious) Changes from v8: * Rebased on the current source. * Adjusted the Spice protocol version requirement. Changes from v7: * When the client has support for GStreamer video codecs it now checks the presence of each supported codec before advertising support for it. Changes from v6: * configure.ac uses the new m4 macros to check for GStreamer support and the presence of the needed plugins. * It separates adding checks for the client codec support from specifying which codec to use in the server and from adding VP8 support. -- Francois Gouget ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 05/14] smartcard-manager: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:41AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/smartcard-manager.c | 33 + > 1 file changed, 13 insertions(+), 20 deletions(-) > > diff --git a/src/smartcard-manager.c b/src/smartcard-manager.c > index 6578328..2310ab6 100644 > --- a/src/smartcard-manager.c > +++ b/src/smartcard-manager.c > @@ -476,8 +476,9 @@ end: > return retval; > } > > -static void smartcard_manager_init_helper(GSimpleAsyncResult *res, > - GObject *object, > +static void smartcard_manager_init_helper(GTask *task, > + gpointer object, > + gpointer task_data, >GCancellable *cancellable) > { > static GOnce smartcard_manager_once = G_ONCE_INIT; > @@ -492,8 +493,10 @@ static void > smartcard_manager_init_helper(GSimpleAsyncResult *res, > (GThreadFunc)smartcard_manager_init, > &args); > if (args.err != NULL) { > -g_simple_async_result_set_from_error(res, args.err); > +g_task_return_error(task, args.err); > g_error_free(args.err); g_task_return_error() takes ownership of args.err, you cannot/do not need to free it afterwards. > +} else { > +g_task_return_boolean(task, TRUE); > } > } > > @@ -504,17 +507,10 @@ void spice_smartcard_manager_init_async(SpiceSession > *session, > GAsyncReadyCallback callback, > gpointer opaque) > { > -GSimpleAsyncResult *res; > +GTask *task = g_task_new(session, cancellable, callback, opaque); > > -res = g_simple_async_result_new(G_OBJECT(session), > -callback, > -opaque, > -spice_smartcard_manager_init); > -g_simple_async_result_run_in_thread(res, > -smartcard_manager_init_helper, > -G_PRIORITY_DEFAULT, > -cancellable); > -g_object_unref(res); > +g_task_run_in_thread(task, smartcard_manager_init_helper); > +g_object_unref(task); > } > > G_GNUC_INTERNAL > @@ -522,21 +518,18 @@ gboolean > spice_smartcard_manager_init_finish(SpiceSession *session, > GAsyncResult *result, > GError **err) > { > -GSimpleAsyncResult *simple; > +GTask *task = G_TASK(result); > > g_return_val_if_fail(SPICE_IS_SESSION(session), FALSE); > -g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(result), FALSE); > +g_return_val_if_fail(G_IS_TASK(task), FALSE); > > SPICE_DEBUG("smartcard_manager_finish"); > > -simple = G_SIMPLE_ASYNC_RESULT(result); > -g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == > spice_smartcard_manager_init, FALSE); > -if (g_simple_async_result_propagate_error(simple, err)) > -return FALSE; > +g_return_val_if_fail(g_task_get_source_tag(task) == > spice_smartcard_manager_init, FALSE); Is this check working? Don't you need to call g_task_set_source_tag() for it to work? Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 04/14] channel-usbredir: Use GTask instead of GSimpleAsyncResult
Acked-by: Christophe Fergeau On Mon, Jan 18, 2016 at 10:05:40AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/channel-usbredir.c | 39 +-- > 1 file changed, 17 insertions(+), 22 deletions(-) > > diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c > index 0be72ba..4ddf7bf 100644 > --- a/src/channel-usbredir.c > +++ b/src/channel-usbredir.c > @@ -76,7 +76,7 @@ struct _SpiceUsbredirChannelPrivate { > int read_buf_size; > enum SpiceUsbredirChannelState state; > #if USE_POLKIT > -GSimpleAsyncResult *result; > +GTask *task; > SpiceUsbAclHelper *acl_helper; > #endif > }; > @@ -297,12 +297,14 @@ static void spice_usbredir_channel_open_acl_cb( > spice_usbredir_channel_open_device(channel, &err); > } > if (err) { > -g_simple_async_result_take_error(priv->result, err); > +g_task_return_error(priv->task, err); > libusb_unref_device(priv->device); > priv->device = NULL; > g_boxed_free(spice_usb_device_get_type(), priv->spice_device); > priv->spice_device = NULL; > priv->state = STATE_DISCONNECTED; > +} else { > +g_task_return_boolean(priv->task, TRUE); > } > > spice_usb_acl_helper_close_acl(priv->acl_helper); > @@ -310,8 +312,7 @@ static void spice_usbredir_channel_open_acl_cb( > g_object_set(spice_channel_get_session(SPICE_CHANNEL(channel)), > "inhibit-keyboard-grab", FALSE, NULL); > > -g_simple_async_result_complete_in_idle(priv->result); > -g_clear_object(&priv->result); > +g_clear_object(&priv->task); > } > #endif > > @@ -325,7 +326,7 @@ void spice_usbredir_channel_connect_device_async( >gpointer user_data) > { > SpiceUsbredirChannelPrivate *priv = channel->priv; > -GSimpleAsyncResult *result; > +GTask *task; > #if ! USE_POLKIT > GError *err = NULL; > #endif > @@ -338,18 +339,17 @@ void spice_usbredir_channel_connect_device_async( >spice_usb_device_get_pid(spice_device), >spice_device, channel); > > -result = g_simple_async_result_new(G_OBJECT(channel), callback, > user_data, > - > spice_usbredir_channel_connect_device_async); > +task = g_task_new(channel, cancellable, callback, user_data); > > if (!priv->host) { > -g_simple_async_result_set_error(result, > +g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Error libusb context not set"); > goto done; > } > > if (priv->state != STATE_DISCONNECTED) { > -g_simple_async_result_set_error(result, > +g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "Error channel is busy"); > goto done; > @@ -359,7 +359,7 @@ void spice_usbredir_channel_connect_device_async( > priv->spice_device = g_boxed_copy(spice_usb_device_get_type(), >spice_device); > #if USE_POLKIT > -priv->result = result; > +priv->task = task; > priv->state = STATE_WAITING_FOR_ACL_HELPER; > priv->acl_helper = spice_usb_acl_helper_new(); > g_object_set(spice_channel_get_session(SPICE_CHANNEL(channel)), > @@ -373,17 +373,17 @@ void spice_usbredir_channel_connect_device_async( > return; > #else > if (!spice_usbredir_channel_open_device(channel, &err)) { > -g_simple_async_result_take_error(result, err); > +g_task_return_error(task, err); > libusb_unref_device(priv->device); > priv->device = NULL; > g_boxed_free(spice_usb_device_get_type(), priv->spice_device); > priv->spice_device = NULL; > -} > +} else { > +g_task_return_boolean(task, TRUE); > #endif > > done: > -g_simple_async_result_complete_in_idle(result); > -g_object_unref(result); > +g_object_unref(task); > } > > G_GNUC_INTERNAL > @@ -392,16 +392,11 @@ gboolean spice_usbredir_channel_connect_device_finish( > GAsyncResult *res, > GError **err) > { > -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(res); > +GTask *task = G_TASK(res); > > -g_return_val_if_fail(g_simple_async_result_is_valid(res, > G_OBJECT(channel), > - > spice_usbredir_channel_connect_device_async), > - FALSE); > +g_return_val_if_fail(g_task_is_valid(task, channel), FALSE); > > -if (g_simple_async_result_propagate_error(result, err)) > -return FALSE; > - > -return TRUE; > +return g_task_propagate_bool
Re: [Spice-devel] [PATCH 03/14] channel-port: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:39AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/channel-port.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/src/channel-port.c b/src/channel-port.c > index 6e01caa..20ee2fa 100644 > --- a/src/channel-port.c > +++ b/src/channel-port.c > @@ -292,7 +292,8 @@ void spice_port_write_async(SpicePortChannel *self, > c = self->priv; > > if (!c->opened) { > -g_simple_async_report_error_in_idle(G_OBJECT(self), callback, > user_data, > +g_task_report_new_error(self, callback, > +user_data, spice_port_write_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > "The port is not opened"); > return; ACK. Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH 02/14] channel-main: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:38AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > --- > src/channel-main.c | 83 > ++ > 1 file changed, 34 insertions(+), 49 deletions(-) > > diff --git a/src/channel-main.c b/src/channel-main.c > index 06dd121..6c0f238 100644 > --- a/src/channel-main.c > +++ b/src/channel-main.c > @@ -923,10 +923,9 @@ static gboolean flush_foreach_remove(gpointer key > G_GNUC_UNUSED, > gpointer value, gpointer user_data) > { > gboolean success = GPOINTER_TO_UINT(user_data); > -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(value); > +GTask *result = value; > +g_task_return_boolean(result, success); > > -g_simple_async_result_set_op_res_gboolean(result, success); > -g_simple_async_result_complete_in_idle(result); > return TRUE; > } > > @@ -940,38 +939,31 @@ static void file_xfer_flushed(SpiceMainChannel > *channel, gboolean success) > static void file_xfer_flush_async(SpiceMainChannel *channel, GCancellable > *cancellable, >GAsyncReadyCallback callback, gpointer > user_data) > { > -GSimpleAsyncResult *simple; > +GTask *task; > SpiceMainChannelPrivate *c = channel->priv; > gboolean was_empty; > > -simple = g_simple_async_result_new(G_OBJECT(channel), callback, > user_data, > - file_xfer_flush_async); > +task = g_task_new(channel, cancellable, callback, user_data); > > was_empty = g_queue_is_empty(c->agent_msg_queue); > if (was_empty) { > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > -g_simple_async_result_complete_in_idle(simple); > -g_object_unref(simple); > +g_task_return_boolean(task, TRUE); > +g_object_unref(task); > return; > } > > /* wait until the last message currently in the queue has been sent */ > -g_hash_table_insert(c->flushing, g_queue_peek_tail(c->agent_msg_queue), > simple); > +g_hash_table_insert(c->flushing, g_queue_peek_tail(c->agent_msg_queue), > task); > } > > static gboolean file_xfer_flush_finish(SpiceMainChannel *channel, > GAsyncResult *result, > GError **error) > { > -GSimpleAsyncResult *simple = (GSimpleAsyncResult *)result; > +GTask *task = G_TASK(result); > > -g_return_val_if_fail(g_simple_async_result_is_valid(result, > -G_OBJECT(channel), file_xfer_flush_async), FALSE); > +g_return_val_if_fail(g_task_is_valid(result, channel), FALSE); > > -if (g_simple_async_result_propagate_error(simple, error)) { > -return FALSE; > -} > - > -return g_simple_async_result_get_op_res_gboolean(simple); > +return g_task_propagate_boolean(task, error); > } > > /* coroutine context */ > @@ -982,16 +974,15 @@ static void agent_send_msg_queue(SpiceMainChannel > *channel) > > while (c->agent_tokens > 0 && > !g_queue_is_empty(c->agent_msg_queue)) { > -GSimpleAsyncResult *simple; > +GTask *task; > c->agent_tokens--; > out = g_queue_pop_head(c->agent_msg_queue); > spice_msg_out_send_internal(out); > > -simple = g_hash_table_lookup(c->flushing, out); > -if (simple) { > +task = g_hash_table_lookup(c->flushing, out); > +if (task) { > /* if there's a flush task waiting for this message, finish it */ > -g_simple_async_result_set_op_res_gboolean(simple, TRUE); > -g_simple_async_result_complete_in_idle(simple); > +g_task_return_boolean(task, TRUE); > g_hash_table_remove(c->flushing, out); > } > } > @@ -1776,7 +1767,7 @@ static void file_xfer_close_cb(GObject *object, > GAsyncResult *close_res, > gpointer user_data) > { > -GSimpleAsyncResult *res; > +GTask *task; > SpiceFileTransferTask *self; > GError *error = NULL; > > @@ -1794,15 +1785,15 @@ static void file_xfer_close_cb(GObject *object, > > /* Notify to user that files have been transferred or something error > happened. */ > -res = g_simple_async_result_new(G_OBJECT(self->priv->channel), > -self->priv->callback, > -self->priv->user_data, > -spice_main_file_copy_async); > +task = g_task_new(self->priv->channel, > + self->priv->cancellable, > + self->priv->callback, > + self->priv->user_data); > if (self->priv->error) { > -g_simple_async_result_take_error(res, self->priv->error); > -g_simple_async_result_set_op_res_gboolean(res, FALSE); > +
Re: [Spice-devel] [PATCH 01/14] channel-base: Use GTask instead of GSimpleAsyncResult
On Mon, Jan 18, 2016 at 10:05:37AM +0100, Fabiano Fidêncio wrote: > Instead of using GSimpleAsyncResult, use the new GTask API, which is > much more straightforward. > For using the new GTask API, let's bump GIO (part of GLib) dependency > version to 2.36, which is safe based on major distro support: > - Debian Jessie: glib-2.42 > - RHEL-7.1: glib-2.40 > - SLES12: glib-2.38 > - Ubuntu LTS 14.04: glib-2.40 > --- > configure.ac | 6 +++--- > src/channel-base.c | 26 ++ > 2 files changed, 13 insertions(+), 19 deletions(-) > > diff --git a/configure.ac b/configure.ac > index 38db8b5..e113487 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -201,7 +201,7 @@ fi > > AC_CHECK_FUNCS(clearenv strtok_r) > > -PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.28) > +PKG_CHECK_MODULES(GLIB2, glib-2.0) > AC_SUBST(GLIB2_CFLAGS) > AC_SUBST(GLIB2_LIBS) > > @@ -209,7 +209,7 @@ PKG_CHECK_MODULES(GOBJECT2, gobject-2.0) > AC_SUBST(GOBJECT2_CFLAGS) > AC_SUBST(GOBJECT2_LIBS) > > -PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.10.0 $gio_os) > +PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.36 $gio_os) > AC_SUBST(GIO_CFLAGS) > AC_SUBST(GIO_LIBS) > > @@ -217,7 +217,7 @@ PKG_CHECK_MODULES(CAIRO, cairo >= 1.2.0) > AC_SUBST(CAIRO_CFLAGS) > AC_SUBST(CAIRO_LIBS) > > -PKG_CHECK_MODULES(GTHREAD, gthread-2.0 > 2.0.0) > +PKG_CHECK_MODULES(GTHREAD, gthread-2.0) > AC_SUBST(GTHREAD_CFLAGS) > AC_SUBST(GTHREAD_LIBS) > > diff --git a/src/channel-base.c b/src/channel-base.c > index 13e4ced..517e7b2 100644 > --- a/src/channel-base.c > +++ b/src/channel-base.c > @@ -240,10 +240,9 @@ void spice_channel_set_handlers(SpiceChannelClass *klass, > static void > vmc_write_free_cb(uint8_t *data, void *user_data) > { > -GSimpleAsyncResult *result = user_data; > +GTask *task = user_data; > > -g_simple_async_result_complete_in_idle(result); The callback for the async call was called after vmc_write_free_cb() runs (ie after the message has been sent in spice_channel_write_msg)... > -g_object_unref(result); > +g_object_unref(task); > } > > G_GNUC_INTERNAL > @@ -254,15 +253,14 @@ void spice_vmc_write_async(SpiceChannel *self, > gpointer user_data) > { > SpiceMsgOut *msg; > -GSimpleAsyncResult *simple; > +GTask *task; > > -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); > +task = g_task_new(self, cancellable, callback, user_data); > +g_task_return_int(task, count); ... but with this call here, I suspect the ordering of the async callback being called, and spice_channel_write_msg() being called become unspecified. Have you checked that it's actually a non-issue? If yes, this would deserve detailed explanations in the commit log. Christophe signature.asc Description: PGP signature ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
Re: [Spice-devel] [PATCH] Remove GSLice usage
On Mon, Jan 18, 2016 at 11:10 AM, Christophe Fergeau wrote: > On Mon, Jan 18, 2016 at 04:15:36AM -0500, Marc-André Lureau wrote: >> Hi >> >> - Original Message - >> > It's being slowly deprecated im glib > > s/im/in/ > >> > https://bugzilla.gnome.org/show_bug.cgi?id=754687 >> > --- >> > src/channel-display.c | 6 +++--- >> > src/channel-smartcard.c | 4 ++-- >> > src/spice-channel-cache.h | 8 >> > src/spice-channel.c | 8 >> > src/spice-grabsequence.c | 8 >> > src/spice-util.c | 4 ++-- >> > src/wocky-http-proxy.c| 4 ++-- >> > 7 files changed, 21 insertions(+), 21 deletions(-) >> > >> > diff --git a/src/channel-display.c b/src/channel-display.c >> > index dc73235..6a474b1 100644 >> > --- a/src/channel-display.c >> > +++ b/src/channel-display.c >> > @@ -635,7 +635,7 @@ static void destroy_surface(gpointer data) >> > display_surface *surface = data; >> > >> > destroy_canvas(surface); >> > -g_slice_free(display_surface, surface); >> > +g_free(surface); >> > } >> > >> > static void spice_display_channel_init(SpiceDisplayChannel *channel) >> > @@ -869,7 +869,7 @@ static void display_handle_mode(SpiceChannel *channel, >> > SpiceMsgIn *in) >> > >> > g_warn_if_fail(c->mark == FALSE); >> > >> > -surface = g_slice_new0(display_surface); >> > +surface = g_new0(display_surface, 1); >> > surface->format = mode->bits == 32 ? >> > SPICE_SURFACE_FMT_32_xRGB : SPICE_SURFACE_FMT_16_555; >> > surface->width = mode->x_res; >> > @@ -1674,7 +1674,7 @@ static void >> > display_handle_surface_create(SpiceChannel >> > *channel, SpiceMsgIn *in) >> > { >> > SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv; >> > SpiceMsgSurfaceCreate *create = spice_msg_in_parsed(in); >> > -display_surface *surface = g_slice_new0(display_surface); >> > +display_surface *surface = g_new0(display_surface, 1); >> > >> > surface->surface_id = create->surface_id; >> > surface->format = create->format; >> > diff --git a/src/channel-smartcard.c b/src/channel-smartcard.c >> > index b5535e6..e2e1aad 100644 >> > --- a/src/channel-smartcard.c >> > +++ b/src/channel-smartcard.c >> > @@ -241,7 +241,7 @@ smartcard_message_free(SpiceSmartcardChannelMessage >> > *message) >> > { >> > if (message->message) >> > spice_msg_out_unref(message->message); >> > -g_slice_free(SpiceSmartcardChannelMessage, message); >> > +g_free(message); >> > } >> > >> > #if USE_SMARTCARD >> > @@ -301,7 +301,7 @@ smartcard_message_new(VSCMsgType msg_type, SpiceMsgOut >> > *msg_out) >> > { >> > SpiceSmartcardChannelMessage *message; >> > >> > -message = g_slice_new0(SpiceSmartcardChannelMessage); >> > +message = g_new0(SpiceSmartcardChannelMessage, 1); >> > message->message = msg_out; >> > message->message_type = msg_type; >> > >> > diff --git a/src/spice-channel-cache.h b/src/spice-channel-cache.h >> > index e609a67..75cc2cd 100644 >> > --- a/src/spice-channel-cache.h >> > +++ b/src/spice-channel-cache.h >> > @@ -37,7 +37,7 @@ typedef struct display_cache { >> > >> > static inline display_cache_item* cache_item_new(guint64 id, gboolean >> > lossy) >> > { >> > -display_cache_item *self = g_slice_new(display_cache_item); >> > +display_cache_item *self = g_new(display_cache_item, 1); >> > self->id = id; >> > self->lossy = lossy; >> > self->ref_count = 1; >> > @@ -46,12 +46,12 @@ static inline display_cache_item* >> > cache_item_new(guint64 >> > id, gboolean lossy) >> > >> > static inline void cache_item_free(display_cache_item *self) >> > { >> > -g_slice_free(display_cache_item, self); >> > +g_free(self); >> > } >> > >> > static inline display_cache* cache_new(GDestroyNotify value_destroy) >> > { >> > -display_cache * self = g_slice_new(display_cache); >> > +display_cache * self = g_new(display_cache, 1); >> > self->table = g_hash_table_new_full(g_int64_hash, g_int64_equal, >> > (GDestroyNotify) cache_item_free, >> > value_destroy); >> > @@ -131,7 +131,7 @@ static inline void cache_clear(display_cache *cache) >> > static inline void cache_free(display_cache *cache) >> > { >> > g_hash_table_unref(cache->table); >> > -g_slice_free(display_cache, cache); >> > +g_free(cache); >> > } >> > >> > G_END_DECLS >> > diff --git a/src/spice-channel.c b/src/spice-channel.c >> > index 41c94d0..ff85715 100644 >> > --- a/src/spice-channel.c >> > +++ b/src/spice-channel.c >> > @@ -471,7 +471,7 @@ SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel) >> > >> > g_return_val_if_fail(channel != NULL, NULL); >> > >> > -in = g_slice_new0(SpiceMsgIn); >> > +in = g_new0(SpiceMsgIn, 1); >> > in->refcount = 1; >> > in->channel = channel; >> > >> > @@ -519,7 +519,7 @@ void spice_msg_in_unref(SpiceMsgIn *in) >> > } else { >> >
Re: [Spice-devel] [PATCH] Remove GSLice usage
On Mon, Jan 18, 2016 at 04:15:36AM -0500, Marc-André Lureau wrote: > Hi > > - Original Message - > > It's being slowly deprecated im glib s/im/in/ > > https://bugzilla.gnome.org/show_bug.cgi?id=754687 > > --- > > src/channel-display.c | 6 +++--- > > src/channel-smartcard.c | 4 ++-- > > src/spice-channel-cache.h | 8 > > src/spice-channel.c | 8 > > src/spice-grabsequence.c | 8 > > src/spice-util.c | 4 ++-- > > src/wocky-http-proxy.c| 4 ++-- > > 7 files changed, 21 insertions(+), 21 deletions(-) > > > > diff --git a/src/channel-display.c b/src/channel-display.c > > index dc73235..6a474b1 100644 > > --- a/src/channel-display.c > > +++ b/src/channel-display.c > > @@ -635,7 +635,7 @@ static void destroy_surface(gpointer data) > > display_surface *surface = data; > > > > destroy_canvas(surface); > > -g_slice_free(display_surface, surface); > > +g_free(surface); > > } > > > > static void spice_display_channel_init(SpiceDisplayChannel *channel) > > @@ -869,7 +869,7 @@ static void display_handle_mode(SpiceChannel *channel, > > SpiceMsgIn *in) > > > > g_warn_if_fail(c->mark == FALSE); > > > > -surface = g_slice_new0(display_surface); > > +surface = g_new0(display_surface, 1); > > surface->format = mode->bits == 32 ? > > SPICE_SURFACE_FMT_32_xRGB : SPICE_SURFACE_FMT_16_555; > > surface->width = mode->x_res; > > @@ -1674,7 +1674,7 @@ static void display_handle_surface_create(SpiceChannel > > *channel, SpiceMsgIn *in) > > { > > SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv; > > SpiceMsgSurfaceCreate *create = spice_msg_in_parsed(in); > > -display_surface *surface = g_slice_new0(display_surface); > > +display_surface *surface = g_new0(display_surface, 1); > > > > surface->surface_id = create->surface_id; > > surface->format = create->format; > > diff --git a/src/channel-smartcard.c b/src/channel-smartcard.c > > index b5535e6..e2e1aad 100644 > > --- a/src/channel-smartcard.c > > +++ b/src/channel-smartcard.c > > @@ -241,7 +241,7 @@ smartcard_message_free(SpiceSmartcardChannelMessage > > *message) > > { > > if (message->message) > > spice_msg_out_unref(message->message); > > -g_slice_free(SpiceSmartcardChannelMessage, message); > > +g_free(message); > > } > > > > #if USE_SMARTCARD > > @@ -301,7 +301,7 @@ smartcard_message_new(VSCMsgType msg_type, SpiceMsgOut > > *msg_out) > > { > > SpiceSmartcardChannelMessage *message; > > > > -message = g_slice_new0(SpiceSmartcardChannelMessage); > > +message = g_new0(SpiceSmartcardChannelMessage, 1); > > message->message = msg_out; > > message->message_type = msg_type; > > > > diff --git a/src/spice-channel-cache.h b/src/spice-channel-cache.h > > index e609a67..75cc2cd 100644 > > --- a/src/spice-channel-cache.h > > +++ b/src/spice-channel-cache.h > > @@ -37,7 +37,7 @@ typedef struct display_cache { > > > > static inline display_cache_item* cache_item_new(guint64 id, gboolean > > lossy) > > { > > -display_cache_item *self = g_slice_new(display_cache_item); > > +display_cache_item *self = g_new(display_cache_item, 1); > > self->id = id; > > self->lossy = lossy; > > self->ref_count = 1; > > @@ -46,12 +46,12 @@ static inline display_cache_item* cache_item_new(guint64 > > id, gboolean lossy) > > > > static inline void cache_item_free(display_cache_item *self) > > { > > -g_slice_free(display_cache_item, self); > > +g_free(self); > > } > > > > static inline display_cache* cache_new(GDestroyNotify value_destroy) > > { > > -display_cache * self = g_slice_new(display_cache); > > +display_cache * self = g_new(display_cache, 1); > > self->table = g_hash_table_new_full(g_int64_hash, g_int64_equal, > > (GDestroyNotify) cache_item_free, > > value_destroy); > > @@ -131,7 +131,7 @@ static inline void cache_clear(display_cache *cache) > > static inline void cache_free(display_cache *cache) > > { > > g_hash_table_unref(cache->table); > > -g_slice_free(display_cache, cache); > > +g_free(cache); > > } > > > > G_END_DECLS > > diff --git a/src/spice-channel.c b/src/spice-channel.c > > index 41c94d0..ff85715 100644 > > --- a/src/spice-channel.c > > +++ b/src/spice-channel.c > > @@ -471,7 +471,7 @@ SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel) > > > > g_return_val_if_fail(channel != NULL, NULL); > > > > -in = g_slice_new0(SpiceMsgIn); > > +in = g_new0(SpiceMsgIn, 1); > > in->refcount = 1; > > in->channel = channel; > > > > @@ -519,7 +519,7 @@ void spice_msg_in_unref(SpiceMsgIn *in) > > } else { > > g_free(in->data); > > } > > -g_slice_free(SpiceMsgIn, in); > > +g_free(in); > > } > > > > G_GNUC_INTERNAL > > @@ -624,7 +624,7 @@ SpiceMsgOut *spice_msg_ou
Re: [Spice-devel] [PATCH 14/14] Add strings for translation
On Mon, Jan 18, 2016 at 10:05:50AM +0100, Fabiano Fidêncio wrote: > While doing the work to use GTask isntead of GSimpleAsyncResult I've instead > noticed a few error strings that were not marked to be translated. > I am not exactly sure if it was intentional or not, but I do believe > that our error messages should be translated. > --- > po/POTFILES.in | 6 ++ > src/channel-main.c | 4 +++- > src/channel-port.c | 4 +++- > src/channel-usbredir.c | 4 ++-- > src/spice-channel.c | 2 +- > src/spice-pulse.c| 8 +--- > src/usb-acl-helper.c | 10 ++ > src/usb-device-manager.c | 4 ++-- > src/vmcstream.c | 4 +++- > src/win-usb-driver-install.c | 16 +--- > 10 files changed, 40 insertions(+), 22 deletions(-) > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index ad12609..7c79541 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -1,8 +1,14 @@ > +src/channel-main.c > +src/channel-port.c > src/channel-usbredir.c > src/desktop-integration.c > src/spice-channel.c > src/spice-cmdline.c > src/spice-option.c > +src/spice-pulse.c > +src/usb-acl-helper.c > src/usb-device-manager.c > src/usb-device-widget.c > src/usbutil.c > +src/vmcstream.c > +src/win-usb-driver-install.c > diff --git a/src/channel-main.c b/src/channel-main.c > index 6c0f238..40d5cff 100644 > --- a/src/channel-main.c > +++ b/src/channel-main.c > @@ -21,6 +21,8 @@ > #include > #include > > +#include > + > #include "glib-compat.h" > #include "spice-client.h" > #include "spice-common.h" > @@ -3143,7 +3145,7 @@ void spice_main_file_copy_async(SpiceMainChannel > *channel, > spice_main_file_copy_async, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"The agent is not connected"); > +_("The agent is not connected")); > return; > } > > diff --git a/src/channel-port.c b/src/channel-port.c > index 20ee2fa..86194ab 100644 > --- a/src/channel-port.c > +++ b/src/channel-port.c > @@ -23,6 +23,8 @@ > #include "spice-marshal.h" > #include "glib-compat.h" > > +#include > + > /** > * SECTION:channel-port > * @short_description: private communication channel > @@ -295,7 +297,7 @@ void spice_port_write_async(SpicePortChannel *self, > g_task_report_new_error(self, callback, > user_data, spice_port_write_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The port is not opened"); > +_("The port is not opened")); > return; > } > > diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c > index 4ddf7bf..824bc43 100644 > --- a/src/channel-usbredir.c > +++ b/src/channel-usbredir.c > @@ -344,14 +344,14 @@ void spice_usbredir_channel_connect_device_async( > if (!priv->host) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error libusb context not set"); > +_("Error libusb context not set")); > goto done; > } > > if (priv->state != STATE_DISCONNECTED) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error channel is busy"); > +_("Error channel is busy")); > goto done; > } > > diff --git a/src/spice-channel.c b/src/spice-channel.c > index dd32818..246609a 100644 > --- a/src/spice-channel.c > +++ b/src/spice-channel.c > @@ -2979,7 +2979,7 @@ void spice_channel_flush_async(SpiceChannel *self, > GCancellable *cancellable, > g_task_report_new_error(self, callback, user_data, > spice_channel_flush_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The channel is not ready yet"); > +_("The channel is not ready yet")); > return; > } > > diff --git a/src/spice-pulse.c b/src/spice-pulse.c > index 60a037c..5c3cfb7 100644 > --- a/src/spice-pulse.c > +++ b/src/spice-pulse.c > @@ -28,6 +28,8 @@ > #include > #include > > +#include > + > #define SPICE_PULSE_GET_PRIVATE(obj) \ > (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_PULSE, SpicePulsePrivate)) > > @@ -995,7 +997,7 @@ static void complete_task(SpicePulse *pulse, struct > async_task *task, const gcha > g_task_return_new_error(task->task, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"restore-info failed due %s", > +_("restore-info failed due %s"), > err_msg); > /* Volume-info does not change if strea
Re: [Spice-devel] [PATCH 14/14] Add strings for translation
ack - Original Message - > While doing the work to use GTask isntead of GSimpleAsyncResult I've > noticed a few error strings that were not marked to be translated. > I am not exactly sure if it was intentional or not, but I do believe > that our error messages should be translated. > --- > po/POTFILES.in | 6 ++ > src/channel-main.c | 4 +++- > src/channel-port.c | 4 +++- > src/channel-usbredir.c | 4 ++-- > src/spice-channel.c | 2 +- > src/spice-pulse.c| 8 +--- > src/usb-acl-helper.c | 10 ++ > src/usb-device-manager.c | 4 ++-- > src/vmcstream.c | 4 +++- > src/win-usb-driver-install.c | 16 +--- > 10 files changed, 40 insertions(+), 22 deletions(-) > > diff --git a/po/POTFILES.in b/po/POTFILES.in > index ad12609..7c79541 100644 > --- a/po/POTFILES.in > +++ b/po/POTFILES.in > @@ -1,8 +1,14 @@ > +src/channel-main.c > +src/channel-port.c > src/channel-usbredir.c > src/desktop-integration.c > src/spice-channel.c > src/spice-cmdline.c > src/spice-option.c > +src/spice-pulse.c > +src/usb-acl-helper.c > src/usb-device-manager.c > src/usb-device-widget.c > src/usbutil.c > +src/vmcstream.c > +src/win-usb-driver-install.c > diff --git a/src/channel-main.c b/src/channel-main.c > index 6c0f238..40d5cff 100644 > --- a/src/channel-main.c > +++ b/src/channel-main.c > @@ -21,6 +21,8 @@ > #include > #include > > +#include > + > #include "glib-compat.h" > #include "spice-client.h" > #include "spice-common.h" > @@ -3143,7 +3145,7 @@ void spice_main_file_copy_async(SpiceMainChannel > *channel, > spice_main_file_copy_async, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"The agent is not connected"); > +_("The agent is not connected")); > return; > } > > diff --git a/src/channel-port.c b/src/channel-port.c > index 20ee2fa..86194ab 100644 > --- a/src/channel-port.c > +++ b/src/channel-port.c > @@ -23,6 +23,8 @@ > #include "spice-marshal.h" > #include "glib-compat.h" > > +#include > + > /** > * SECTION:channel-port > * @short_description: private communication channel > @@ -295,7 +297,7 @@ void spice_port_write_async(SpicePortChannel *self, > g_task_report_new_error(self, callback, > user_data, spice_port_write_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The port is not opened"); > +_("The port is not opened")); > return; > } > > diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c > index 4ddf7bf..824bc43 100644 > --- a/src/channel-usbredir.c > +++ b/src/channel-usbredir.c > @@ -344,14 +344,14 @@ void spice_usbredir_channel_connect_device_async( > if (!priv->host) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error libusb context not set"); > +_("Error libusb context not set")); > goto done; > } > > if (priv->state != STATE_DISCONNECTED) { > g_task_return_new_error(task, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"Error channel is busy"); > +_("Error channel is busy")); > goto done; > } > > diff --git a/src/spice-channel.c b/src/spice-channel.c > index dd32818..246609a 100644 > --- a/src/spice-channel.c > +++ b/src/spice-channel.c > @@ -2979,7 +2979,7 @@ void spice_channel_flush_async(SpiceChannel *self, > GCancellable *cancellable, > g_task_report_new_error(self, callback, user_data, > spice_channel_flush_async, > SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, > -"The channel is not ready yet"); > +_("The channel is not ready yet")); > return; > } > > diff --git a/src/spice-pulse.c b/src/spice-pulse.c > index 60a037c..5c3cfb7 100644 > --- a/src/spice-pulse.c > +++ b/src/spice-pulse.c > @@ -28,6 +28,8 @@ > #include > #include > > +#include > + > #define SPICE_PULSE_GET_PRIVATE(obj) \ > (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_PULSE, > SpicePulsePrivate)) > > @@ -995,7 +997,7 @@ static void complete_task(SpicePulse *pulse, struct > async_task *task, const gcha > g_task_return_new_error(task->task, > SPICE_CLIENT_ERROR, > SPICE_CLIENT_ERROR_FAILED, > -"restore-info failed due %s", > +_("restore-info failed due %s"), > err_msg); > /* Volume-info does not change if stream is not found */ > } else if ((t
Re: [Spice-devel] [PATCH] Remove GSLice usage
Hi - Original Message - > It's being slowly deprecated im glib > https://bugzilla.gnome.org/show_bug.cgi?id=754687 > --- > src/channel-display.c | 6 +++--- > src/channel-smartcard.c | 4 ++-- > src/spice-channel-cache.h | 8 > src/spice-channel.c | 8 > src/spice-grabsequence.c | 8 > src/spice-util.c | 4 ++-- > src/wocky-http-proxy.c| 4 ++-- > 7 files changed, 21 insertions(+), 21 deletions(-) > > diff --git a/src/channel-display.c b/src/channel-display.c > index dc73235..6a474b1 100644 > --- a/src/channel-display.c > +++ b/src/channel-display.c > @@ -635,7 +635,7 @@ static void destroy_surface(gpointer data) > display_surface *surface = data; > > destroy_canvas(surface); > -g_slice_free(display_surface, surface); > +g_free(surface); > } > > static void spice_display_channel_init(SpiceDisplayChannel *channel) > @@ -869,7 +869,7 @@ static void display_handle_mode(SpiceChannel *channel, > SpiceMsgIn *in) > > g_warn_if_fail(c->mark == FALSE); > > -surface = g_slice_new0(display_surface); > +surface = g_new0(display_surface, 1); > surface->format = mode->bits == 32 ? > SPICE_SURFACE_FMT_32_xRGB : SPICE_SURFACE_FMT_16_555; > surface->width = mode->x_res; > @@ -1674,7 +1674,7 @@ static void display_handle_surface_create(SpiceChannel > *channel, SpiceMsgIn *in) > { > SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv; > SpiceMsgSurfaceCreate *create = spice_msg_in_parsed(in); > -display_surface *surface = g_slice_new0(display_surface); > +display_surface *surface = g_new0(display_surface, 1); > > surface->surface_id = create->surface_id; > surface->format = create->format; > diff --git a/src/channel-smartcard.c b/src/channel-smartcard.c > index b5535e6..e2e1aad 100644 > --- a/src/channel-smartcard.c > +++ b/src/channel-smartcard.c > @@ -241,7 +241,7 @@ smartcard_message_free(SpiceSmartcardChannelMessage > *message) > { > if (message->message) > spice_msg_out_unref(message->message); > -g_slice_free(SpiceSmartcardChannelMessage, message); > +g_free(message); > } > > #if USE_SMARTCARD > @@ -301,7 +301,7 @@ smartcard_message_new(VSCMsgType msg_type, SpiceMsgOut > *msg_out) > { > SpiceSmartcardChannelMessage *message; > > -message = g_slice_new0(SpiceSmartcardChannelMessage); > +message = g_new0(SpiceSmartcardChannelMessage, 1); > message->message = msg_out; > message->message_type = msg_type; > > diff --git a/src/spice-channel-cache.h b/src/spice-channel-cache.h > index e609a67..75cc2cd 100644 > --- a/src/spice-channel-cache.h > +++ b/src/spice-channel-cache.h > @@ -37,7 +37,7 @@ typedef struct display_cache { > > static inline display_cache_item* cache_item_new(guint64 id, gboolean lossy) > { > -display_cache_item *self = g_slice_new(display_cache_item); > +display_cache_item *self = g_new(display_cache_item, 1); > self->id = id; > self->lossy = lossy; > self->ref_count = 1; > @@ -46,12 +46,12 @@ static inline display_cache_item* cache_item_new(guint64 > id, gboolean lossy) > > static inline void cache_item_free(display_cache_item *self) > { > -g_slice_free(display_cache_item, self); > +g_free(self); > } > > static inline display_cache* cache_new(GDestroyNotify value_destroy) > { > -display_cache * self = g_slice_new(display_cache); > +display_cache * self = g_new(display_cache, 1); > self->table = g_hash_table_new_full(g_int64_hash, g_int64_equal, > (GDestroyNotify) cache_item_free, > value_destroy); > @@ -131,7 +131,7 @@ static inline void cache_clear(display_cache *cache) > static inline void cache_free(display_cache *cache) > { > g_hash_table_unref(cache->table); > -g_slice_free(display_cache, cache); > +g_free(cache); > } > > G_END_DECLS > diff --git a/src/spice-channel.c b/src/spice-channel.c > index 41c94d0..ff85715 100644 > --- a/src/spice-channel.c > +++ b/src/spice-channel.c > @@ -471,7 +471,7 @@ SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel) > > g_return_val_if_fail(channel != NULL, NULL); > > -in = g_slice_new0(SpiceMsgIn); > +in = g_new0(SpiceMsgIn, 1); > in->refcount = 1; > in->channel = channel; > > @@ -519,7 +519,7 @@ void spice_msg_in_unref(SpiceMsgIn *in) > } else { > g_free(in->data); > } > -g_slice_free(SpiceMsgIn, in); > +g_free(in); > } > > G_GNUC_INTERNAL > @@ -624,7 +624,7 @@ SpiceMsgOut *spice_msg_out_new(SpiceChannel *channel, int > type) > > g_return_val_if_fail(c != NULL, NULL); > > -out = g_slice_new0(SpiceMsgOut); > +out = g_new0(SpiceMsgOut, 1); > out->refcount = 1; > out->channel = channel; > out->ro_check = msg_check_read_only(c->channel_type, type); > @@ -660,7 +660,7 @@ void spice_msg_out_unref(Spice
[Spice-devel] [PATCH 07/14] spice-gstaudio: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/spice-gstaudio.c | 48 ++-- 1 file changed, 10 insertions(+), 38 deletions(-) diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c index 096fea4..65fc173 100644 --- a/src/spice-gstaudio.c +++ b/src/spice-gstaudio.c @@ -570,16 +570,9 @@ static void spice_gstaudio_get_playback_volume_info_async(SpiceAudio *audio, GAsyncReadyCallback callback, gpointer user_data) { -GSimpleAsyncResult *simple; +GTask *task = g_task_new(audio, cancellable, callback, user_data); -simple = g_simple_async_result_new(G_OBJECT(audio), - callback, - user_data, - spice_gstaudio_get_playback_volume_info_async); -g_simple_async_result_set_check_cancellable (simple, cancellable); - -g_simple_async_result_set_op_res_gboolean(simple, TRUE); -g_simple_async_result_complete_in_idle(simple); +g_task_return_boolean(task, TRUE); } static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio, @@ -594,14 +587,9 @@ static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio gboolean lmute; gdouble vol; gboolean fake_channel = FALSE; -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; - -g_return_val_if_fail(g_simple_async_result_is_valid(res, -G_OBJECT(audio), spice_gstaudio_get_playback_volume_info_async), FALSE); +GTask *task = G_TASK(res); -if (g_simple_async_result_propagate_error(simple, error)) { -return FALSE; -} +g_return_val_if_fail(g_task_is_valid(task, audio), FALSE); if (p->playback.sink == NULL || p->playback.channels == 0) { SPICE_DEBUG("PlaybackChannel not created yet, force start"); @@ -647,7 +635,7 @@ static gboolean spice_gstaudio_get_playback_volume_info_finish(SpiceAudio *audio } } -return g_simple_async_result_get_op_res_gboolean(simple); +return g_task_propagate_boolean(task, error); } static void spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, @@ -656,16 +644,9 @@ static void spice_gstaudio_get_record_volume_info_async(SpiceAudio *audio, GAsyncReadyCallback callback, gpointer user_data) { -GSimpleAsyncResult *simple; - -simple = g_simple_async_result_new(G_OBJECT(audio), - callback, - user_data, - spice_gstaudio_get_record_volume_info_async); -g_simple_async_result_set_check_cancellable (simple, cancellable); +GTask *task = g_task_new(audio, cancellable, callback, user_data); -g_simple_async_result_set_op_res_gboolean(simple, TRUE); -g_simple_async_result_complete_in_idle(simple); +g_task_return_boolean(task, TRUE); } static gboolean spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, @@ -680,18 +661,9 @@ static gboolean spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, gboolean lmute; gdouble vol; gboolean fake_channel = FALSE; -GSimpleAsyncResult *simple = (GSimpleAsyncResult *) res; +GTask *task = G_TASK(res); -g_return_val_if_fail(g_simple_async_result_is_valid(res, -G_OBJECT(audio), spice_gstaudio_get_record_volume_info_async), FALSE); - -if (g_simple_async_result_propagate_error(simple, error)) { -/* set out args that should have new alloc'ed memory to NULL */ -if (volume != NULL) { -*volume = NULL; -} -return FALSE; -} +g_return_val_if_fail(g_task_is_valid(task, audio), FALSE); if (p->record.src == NULL || p->record.channels == 0) { SPICE_DEBUG("RecordChannel not created yet, force start"); @@ -737,5 +709,5 @@ static gboolean spice_gstaudio_get_record_volume_info_finish(SpiceAudio *audio, } } -return g_simple_async_result_get_op_res_gboolean(simple); +return g_task_propagate_boolean(task, error); } -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 05/14] smartcard-manager: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/smartcard-manager.c | 33 + 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/smartcard-manager.c b/src/smartcard-manager.c index 6578328..2310ab6 100644 --- a/src/smartcard-manager.c +++ b/src/smartcard-manager.c @@ -476,8 +476,9 @@ end: return retval; } -static void smartcard_manager_init_helper(GSimpleAsyncResult *res, - GObject *object, +static void smartcard_manager_init_helper(GTask *task, + gpointer object, + gpointer task_data, GCancellable *cancellable) { static GOnce smartcard_manager_once = G_ONCE_INIT; @@ -492,8 +493,10 @@ static void smartcard_manager_init_helper(GSimpleAsyncResult *res, (GThreadFunc)smartcard_manager_init, &args); if (args.err != NULL) { -g_simple_async_result_set_from_error(res, args.err); +g_task_return_error(task, args.err); g_error_free(args.err); +} else { +g_task_return_boolean(task, TRUE); } } @@ -504,17 +507,10 @@ void spice_smartcard_manager_init_async(SpiceSession *session, GAsyncReadyCallback callback, gpointer opaque) { -GSimpleAsyncResult *res; +GTask *task = g_task_new(session, cancellable, callback, opaque); -res = g_simple_async_result_new(G_OBJECT(session), -callback, -opaque, -spice_smartcard_manager_init); -g_simple_async_result_run_in_thread(res, -smartcard_manager_init_helper, -G_PRIORITY_DEFAULT, -cancellable); -g_object_unref(res); +g_task_run_in_thread(task, smartcard_manager_init_helper); +g_object_unref(task); } G_GNUC_INTERNAL @@ -522,21 +518,18 @@ gboolean spice_smartcard_manager_init_finish(SpiceSession *session, GAsyncResult *result, GError **err) { -GSimpleAsyncResult *simple; +GTask *task = G_TASK(result); g_return_val_if_fail(SPICE_IS_SESSION(session), FALSE); -g_return_val_if_fail(G_IS_SIMPLE_ASYNC_RESULT(result), FALSE); +g_return_val_if_fail(G_IS_TASK(task), FALSE); SPICE_DEBUG("smartcard_manager_finish"); -simple = G_SIMPLE_ASYNC_RESULT(result); -g_return_val_if_fail(g_simple_async_result_get_source_tag(simple) == spice_smartcard_manager_init, FALSE); -if (g_simple_async_result_propagate_error(simple, err)) -return FALSE; +g_return_val_if_fail(g_task_get_source_tag(task) == spice_smartcard_manager_init, FALSE); spice_smartcard_manager_update_monitor(); -return TRUE; +return g_task_propagate_boolean(task, err); } /** -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 12/14] win-usb-driver-install: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/win-usb-driver-install.c | 86 +--- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/src/win-usb-driver-install.c b/src/win-usb-driver-install.c index 54e9b14..a7c4864 100644 --- a/src/win-usb-driver-install.c +++ b/src/win-usb-driver-install.c @@ -44,8 +44,7 @@ struct _SpiceWinUsbDriverPrivate { USBClerkReply reply; -GSimpleAsyncResult*result; -GCancellable *cancellable; +GTask *task; HANDLEhandle; SpiceUsbDevice*device; }; @@ -144,16 +143,16 @@ void win_usb_driver_handle_reply_cb(GObject *gobject, if (err) { g_warning("failed to read reply from usbclerk (%s)", err->message); -g_simple_async_result_take_error(priv->result, err); +g_task_return_error(priv->task, err); goto failed_reply; } if (bytes == 0) { g_warning("unexpected EOF from usbclerk"); -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_FAILED, -"unexpected EOF from usbclerk"); +g_task_return_new_error(priv->task, +SPICE_WIN_USB_DRIVER_ERROR, +SPICE_WIN_USB_DRIVER_ERROR_FAILED, +"unexpected EOF from usbclerk"); goto failed_reply; } @@ -167,52 +166,53 @@ void win_usb_driver_handle_reply_cb(GObject *gobject, if (priv->reply.hdr.magic != USB_CLERK_MAGIC) { g_warning("usbclerk magic mismatch: mine=0x%04x server=0x%04x", USB_CLERK_MAGIC, priv->reply.hdr.magic); -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, -"usbclerk magic mismatch"); +g_task_return_new_error(priv->task, +SPICE_WIN_USB_DRIVER_ERROR, +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, +"usbclerk magic mismatch"); goto failed_reply; } if (priv->reply.hdr.version != USB_CLERK_VERSION) { g_warning("usbclerk version mismatch: mine=0x%04x server=0x%04x", USB_CLERK_VERSION, priv->reply.hdr.version); -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, -"usbclerk version mismatch"); +g_task_return_new_error(priv->task, +SPICE_WIN_USB_DRIVER_ERROR, +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, +"usbclerk version mismatch"); } if (priv->reply.hdr.type != USB_CLERK_REPLY) { g_warning("usbclerk message with unexpected type %d", priv->reply.hdr.type); -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, -"usbclerk message with unexpected type"); +g_task_return_new_error(priv->task, +SPICE_WIN_USB_DRIVER_ERROR, +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, +"usbclerk message with unexpected type"); goto failed_reply; } if (priv->reply.hdr.size != bytes) { g_warning("usbclerk message size mismatch: read %"G_GSSIZE_FORMAT" bytes hdr.size=%d", bytes, priv->reply.hdr.size); -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, -"usbclerk message with unexpected size"); +g_task_return_new_error(priv->task, +SPICE_WIN_USB_DRIVER_ERROR, +SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, +"usbclerk message with unexpected size"); goto failed_reply; } if (priv->reply.status == 0) { -g_simple_async_result_set_error(priv->result, -SPICE_WIN_USB_DRIVER_ERROR, -SPICE_WIN_USB_DRIVER_ERROR_MESSAGE, -"usbclerk error reply"); +g_task_return_new_error(priv->task, +
[Spice-devel] [PATCH 09/14] usb-acl-helper: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/usb-acl-helper.c | 76 1 file changed, 35 insertions(+), 41 deletions(-) diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c index 6a49627..17e2b3c 100644 --- a/src/usb-acl-helper.c +++ b/src/usb-acl-helper.c @@ -35,10 +35,9 @@ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), SPICE_TYPE_USB_ACL_HELPER, SpiceUsbAclHelperPrivate)) struct _SpiceUsbAclHelperPrivate { -GSimpleAsyncResult *result; +GTask *task; GIOChannel *in_ch; GIOChannel *out_ch; -GCancellable *cancellable; gulong cancellable_id; }; @@ -53,11 +52,11 @@ static void spice_usb_acl_helper_cleanup(SpiceUsbAclHelper *self) { SpiceUsbAclHelperPrivate *priv = self->priv; -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); -priv->cancellable = NULL; +g_cancellable_disconnect(g_task_get_cancellable(priv->task), + priv->cancellable_id); priv->cancellable_id = 0; -g_clear_object(&priv->result); +g_clear_object(&priv->task); if (priv->in_ch) { g_io_channel_unref(priv->in_ch); @@ -90,9 +89,9 @@ static void spice_usb_acl_helper_class_init(SpiceUsbAclHelperClass *klass) /* -- */ /* callbacks */ -static void async_result_set_cancelled(GSimpleAsyncResult *result) +static void async_result_set_cancelled(GTask *task) { -g_simple_async_result_set_error(result, +g_task_return_new_error(task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Setting USB device node ACL cancelled"); } @@ -105,12 +104,13 @@ static gboolean cb_out_watch(GIOChannel*channel, SpiceUsbAclHelperPrivate *priv = self->priv; gboolean success = FALSE; GError *err = NULL; +GCancellable *cancellable; GIOStatus status; gchar *string; gsize size; /* Check that we've not been cancelled */ -if (priv->result == NULL) +if (priv->task == NULL) goto done; g_return_val_if_fail(channel == priv->out_ch, FALSE); @@ -121,10 +121,11 @@ static gboolean cb_out_watch(GIOChannel*channel, string[strlen(string) - 1] = 0; if (!strcmp(string, "SUCCESS")) { success = TRUE; +g_task_return_boolean(priv->task, TRUE); } else if (!strcmp(string, "CANCELED")) { -async_result_set_cancelled(priv->result); +async_result_set_cancelled(priv->task); } else { -g_simple_async_result_set_error(priv->result, +g_task_return_new_error(priv->task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Error setting USB device node ACL: '%s'", string); @@ -132,10 +133,10 @@ static gboolean cb_out_watch(GIOChannel*channel, g_free(string); break; case G_IO_STATUS_ERROR: -g_simple_async_result_take_error(priv->result, err); +g_task_return_error(priv->task, err); break; case G_IO_STATUS_EOF: -g_simple_async_result_set_error(priv->result, +g_task_return_new_error(priv->task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Unexpected EOF reading from acl helper stdout"); break; @@ -143,16 +144,16 @@ static gboolean cb_out_watch(GIOChannel*channel, return TRUE; /* Wait for more input */ } -g_cancellable_disconnect(priv->cancellable, priv->cancellable_id); -priv->cancellable = NULL; +cancellable = g_task_get_cancellable(priv->task); +g_cancellable_disconnect(cancellable, priv->cancellable_id); +cancellable = NULL; priv->cancellable_id = 0; -g_simple_async_result_complete_in_idle(priv->result); -g_clear_object(&priv->result); - if (!success) spice_usb_acl_helper_cleanup(self); +g_clear_object(&priv->task); + done: g_object_unref(self); return FALSE; @@ -193,7 +194,7 @@ void spice_usb_acl_helper_open_acl(SpiceUsbAclHelper *self, g_return_if_fail(SPICE_IS_USB_ACL_HELPER(self)); SpiceUsbAclHelperPrivate *priv = self->priv; -GSimpleAsyncResult *result; +GTask *task; GError *err = NULL; GIOStatus status; GPid helper_pid; @@ -202,25 +203,24 @@ void spice_usb_acl_helper_open_acl(SpiceUsbAclHelper *self, gint in, out; gchar buf[128]; -result = g_simple_async_result_new(G_OBJECT(self), callback, user_data, - spice_usb_acl_helper_open_acl); +task = g_task_new(self, cancellable, callback, user_data); if (priv->out_ch) { -g_simple_async_result_set_error(result, +
[Spice-devel] [PATCH 03/14] channel-port: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/channel-port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/channel-port.c b/src/channel-port.c index 6e01caa..20ee2fa 100644 --- a/src/channel-port.c +++ b/src/channel-port.c @@ -292,7 +292,8 @@ void spice_port_write_async(SpicePortChannel *self, c = self->priv; if (!c->opened) { -g_simple_async_report_error_in_idle(G_OBJECT(self), callback, user_data, +g_task_report_new_error(self, callback, +user_data, spice_port_write_async, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "The port is not opened"); return; -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 06/14] spice-channel: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/spice-channel.c | 32 +--- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/src/spice-channel.c b/src/spice-channel.c index ff85715..dd32818 100644 --- a/src/spice-channel.c +++ b/src/spice-channel.c @@ -2124,9 +2124,7 @@ static void spice_channel_flushed(SpiceChannel *channel, gboolean success) GSList *l; for (l = c->flushing; l != NULL; l = l->next) { -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(l->data); -g_simple_async_result_set_op_res_gboolean(result, success); -g_simple_async_result_complete_in_idle(result); +g_task_return_boolean(G_TASK(l->data), success); } g_slist_free_full(c->flushing, g_object_unref); @@ -2970,7 +2968,7 @@ static void spice_channel_send_migration_handshake(SpiceChannel *channel) void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { -GSimpleAsyncResult *simple; +GTask *task; SpiceChannelPrivate *c; gboolean was_empty; @@ -2978,26 +2976,25 @@ void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable, c = self->priv; if (c->state != SPICE_CHANNEL_STATE_READY) { -g_simple_async_report_error_in_idle(G_OBJECT(self), callback, user_data, +g_task_report_new_error(self, callback, user_data, +spice_channel_flush_async, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "The channel is not ready yet"); return; } -simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data, - spice_channel_flush_async); +task = g_task_new(self, cancellable, callback, user_data); STATIC_MUTEX_LOCK(c->xmit_queue_lock); was_empty = g_queue_is_empty(&c->xmit_queue); STATIC_MUTEX_UNLOCK(c->xmit_queue_lock); if (was_empty) { -g_simple_async_result_set_op_res_gboolean(simple, TRUE); -g_simple_async_result_complete_in_idle(simple); -g_object_unref(simple); +g_task_return_boolean(task, TRUE); +g_object_unref(task); return; } -c->flushing = g_slist_append(c->flushing, simple); +c->flushing = g_slist_append(c->flushing, task); } /** @@ -3015,19 +3012,16 @@ void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable, gboolean spice_channel_flush_finish(SpiceChannel *self, GAsyncResult *result, GError **error) { -GSimpleAsyncResult *simple; +GTask *task; g_return_val_if_fail(SPICE_IS_CHANNEL(self), FALSE); g_return_val_if_fail(result != NULL, FALSE); -simple = (GSimpleAsyncResult *)result; +task = G_TASK(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_channel_flush_async), FALSE); +g_return_val_if_fail(g_task_is_valid(task, self), + FALSE); CHANNEL_DEBUG(self, "flushed finished!"); -return g_simple_async_result_get_op_res_gboolean(simple); +return g_task_propagate_boolean(task, error); } -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 11/14] vmcstream: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/vmcstream.c | 129 +++- 1 file changed, 52 insertions(+), 77 deletions(-) diff --git a/src/vmcstream.c b/src/vmcstream.c index 483dd5a..d9b62a0 100644 --- a/src/vmcstream.c +++ b/src/vmcstream.c @@ -27,7 +27,7 @@ struct _SpiceVmcInputStream { GInputStream parent_instance; -GSimpleAsyncResult *result; +GTask *task; struct coroutine *coroutine; SpiceChannel *channel; @@ -36,7 +36,6 @@ struct _SpiceVmcInputStream gsize count; gsize pos; -GCancellable *cancellable; gulong cancel_id; }; @@ -118,11 +117,12 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, self->coroutine = coroutine_self(); while (size > 0) { -SPICE_DEBUG("spicevmc co_data %p", self->result); -if (!self->result) +GCancellable *cancellable; +SPICE_DEBUG("spicevmc co_data %p", self->task); +if (!self->task) coroutine_yield(NULL); -g_return_if_fail(self->result != NULL); +g_return_if_fail(self->task != NULL); gsize min = MIN(self->count, size); memcpy(self->buffer, data, min); @@ -139,14 +139,13 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, if (self->all && min > 0 && self->pos != self->count) continue; -g_simple_async_result_set_op_res_gssize(self->result, self->pos); +g_task_return_int(self->task, self->pos); + +cancellable = g_task_get_cancellable(self->task); +if (cancellable) +g_cancellable_disconnect(cancellable, self->cancel_id); -g_simple_async_result_complete_in_idle(self->result); -g_clear_object(&self->result); -if (self->cancellable) { -g_cancellable_disconnect(self->cancellable, self->cancel_id); -g_clear_object(&self->cancellable); -} +g_clear_object(&self->task); } self->coroutine = NULL; @@ -158,13 +157,12 @@ read_cancelled(GCancellable *cancellable, { 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); +SPICE_DEBUG("read cancelled, %p", self->task); +g_task_return_new_error(self->task, +G_IO_ERROR, G_IO_ERROR_CANCELLED, +"read cancelled"); -g_clear_object(&self->result); +g_clear_object(&self->task); /* See FIXME */ /* if (self->cancellable) { */ @@ -183,21 +181,20 @@ spice_vmc_input_stream_read_all_async(GInputStream *stream, gpointer user_data) { SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream); -GSimpleAsyncResult *result; +GTask *task; /* no concurrent read permitted by ginputstream */ -g_return_if_fail(self->result == NULL); -g_return_if_fail(self->cancellable == NULL); +g_return_if_fail(self->task == NULL); +g_return_if_fail(g_task_get_cancellable(self->task) == NULL); 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); -self->result = result; -self->cancellable = g_object_ref(cancellable); +task = g_task_new(self, + cancellable, + callback, + user_data); +self->task = task; if (cancellable) self->cancel_id = g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL); @@ -211,27 +208,19 @@ spice_vmc_input_stream_read_all_finish(GInputStream *stream, GAsyncResult *result, GError **error) { -GSimpleAsyncResult *simple; +GTask *task = G_TASK(result); +GCancellable *cancellable; 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); - -simple = (GSimpleAsyncResult *)result; +g_return_val_if_fail(g_task_is_valid(task, self), -1); /* FIXME: calling _finish() is required. Disconnecting in read_cancelled() causes a deadlock. #705395 */ -if (self->cancellable) { -g_cancellable_d
[Spice-devel] [PATCH 02/14] channel-main: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/channel-main.c | 83 ++ 1 file changed, 34 insertions(+), 49 deletions(-) diff --git a/src/channel-main.c b/src/channel-main.c index 06dd121..6c0f238 100644 --- a/src/channel-main.c +++ b/src/channel-main.c @@ -923,10 +923,9 @@ static gboolean flush_foreach_remove(gpointer key G_GNUC_UNUSED, gpointer value, gpointer user_data) { gboolean success = GPOINTER_TO_UINT(user_data); -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(value); +GTask *result = value; +g_task_return_boolean(result, success); -g_simple_async_result_set_op_res_gboolean(result, success); -g_simple_async_result_complete_in_idle(result); return TRUE; } @@ -940,38 +939,31 @@ static void file_xfer_flushed(SpiceMainChannel *channel, gboolean success) static void file_xfer_flush_async(SpiceMainChannel *channel, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { -GSimpleAsyncResult *simple; +GTask *task; SpiceMainChannelPrivate *c = channel->priv; gboolean was_empty; -simple = g_simple_async_result_new(G_OBJECT(channel), callback, user_data, - file_xfer_flush_async); +task = g_task_new(channel, cancellable, callback, user_data); was_empty = g_queue_is_empty(c->agent_msg_queue); if (was_empty) { -g_simple_async_result_set_op_res_gboolean(simple, TRUE); -g_simple_async_result_complete_in_idle(simple); -g_object_unref(simple); +g_task_return_boolean(task, TRUE); +g_object_unref(task); return; } /* wait until the last message currently in the queue has been sent */ -g_hash_table_insert(c->flushing, g_queue_peek_tail(c->agent_msg_queue), simple); +g_hash_table_insert(c->flushing, g_queue_peek_tail(c->agent_msg_queue), task); } static gboolean file_xfer_flush_finish(SpiceMainChannel *channel, GAsyncResult *result, GError **error) { -GSimpleAsyncResult *simple = (GSimpleAsyncResult *)result; +GTask *task = G_TASK(result); -g_return_val_if_fail(g_simple_async_result_is_valid(result, -G_OBJECT(channel), file_xfer_flush_async), FALSE); +g_return_val_if_fail(g_task_is_valid(result, channel), FALSE); -if (g_simple_async_result_propagate_error(simple, error)) { -return FALSE; -} - -return g_simple_async_result_get_op_res_gboolean(simple); +return g_task_propagate_boolean(task, error); } /* coroutine context */ @@ -982,16 +974,15 @@ static void agent_send_msg_queue(SpiceMainChannel *channel) while (c->agent_tokens > 0 && !g_queue_is_empty(c->agent_msg_queue)) { -GSimpleAsyncResult *simple; +GTask *task; c->agent_tokens--; out = g_queue_pop_head(c->agent_msg_queue); spice_msg_out_send_internal(out); -simple = g_hash_table_lookup(c->flushing, out); -if (simple) { +task = g_hash_table_lookup(c->flushing, out); +if (task) { /* if there's a flush task waiting for this message, finish it */ -g_simple_async_result_set_op_res_gboolean(simple, TRUE); -g_simple_async_result_complete_in_idle(simple); +g_task_return_boolean(task, TRUE); g_hash_table_remove(c->flushing, out); } } @@ -1776,7 +1767,7 @@ static void file_xfer_close_cb(GObject *object, GAsyncResult *close_res, gpointer user_data) { -GSimpleAsyncResult *res; +GTask *task; SpiceFileTransferTask *self; GError *error = NULL; @@ -1794,15 +1785,15 @@ static void file_xfer_close_cb(GObject *object, /* Notify to user that files have been transferred or something error happened. */ -res = g_simple_async_result_new(G_OBJECT(self->priv->channel), -self->priv->callback, -self->priv->user_data, -spice_main_file_copy_async); +task = g_task_new(self->priv->channel, + self->priv->cancellable, + self->priv->callback, + self->priv->user_data); if (self->priv->error) { -g_simple_async_result_take_error(res, self->priv->error); -g_simple_async_result_set_op_res_gboolean(res, FALSE); +g_task_return_error(task, self->priv->error); +g_task_return_boolean(task, FALSE); } else { -g_simple_async_result_set_op_res_gboolean(res, TRUE); +g_task_return_boolean(task, TRUE); if (spice_util_get_debug()) { gint64 now = g_get_monotonic_time(); gchar
[Spice-devel] [PATCH 13/14] wocky-http-proxy: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/wocky-http-proxy.c | 47 ++- 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/src/wocky-http-proxy.c b/src/wocky-http-proxy.c index d84cd72..f079e10 100644 --- a/src/wocky-http-proxy.c +++ b/src/wocky-http-proxy.c @@ -254,14 +254,13 @@ error: typedef struct { - GSimpleAsyncResult *simple; + GTask *task; GIOStream *io_stream; gchar *buffer; gssize length; gssize offset; GDataInputStream *data_in; gboolean has_cred; - GCancellable *cancellable; } ConnectAsyncData; static void request_write_cb (GObject *source, @@ -282,26 +281,22 @@ free_connect_data (ConnectAsyncData *data) if (data->data_in != NULL) g_object_unref (data->data_in); - if (data->cancellable != NULL) -g_object_unref (data->cancellable); - g_free (data); } static void complete_async_from_error (ConnectAsyncData *data, GError *error) { - GSimpleAsyncResult *simple = data->simple; + GTask *task = data->task; if (error == NULL) g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_PROXY_FAILED, "HTTP proxy server closed connection unexpectedly."); - g_simple_async_result_set_from_error (data->simple, error); + g_task_return_error(data->task, error); g_error_free (error); - g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL); - g_simple_async_result_complete (simple); - g_object_unref (simple); + g_task_return_pointer(task, NULL, NULL); + g_object_unref (task); } static void @@ -312,7 +307,7 @@ do_write (GAsyncReadyCallback callback, ConnectAsyncData *data) g_output_stream_write_async (out, data->buffer + data->offset, data->length - data->offset, - G_PRIORITY_DEFAULT, data->cancellable, + G_PRIORITY_DEFAULT, g_task_get_cancellable(data->task), callback, data); } @@ -357,24 +352,22 @@ wocky_http_proxy_connect_async (GProxy *proxy, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *simple; + GTask *task; ConnectAsyncData *data; - simple = g_simple_async_result_new (G_OBJECT (proxy), - callback, user_data, - wocky_http_proxy_connect_async); + task = g_task_new (proxy, + cancellable, + callback, + user_data); data = g_new0 (ConnectAsyncData, 1); - if (cancellable != NULL) -data->cancellable = g_object_ref (cancellable); - data->simple = simple; + data->task = task; data->buffer = create_request (proxy_address, &data->has_cred); data->length = strlen (data->buffer); data->offset = 0; - g_simple_async_result_set_op_res_gpointer (simple, data, - (GDestroyNotify) free_connect_data); + g_task_return_pointer (task, data, (GDestroyNotify) free_connect_data); if (WOCKY_IS_HTTPS_PROXY (proxy)) { @@ -435,7 +428,7 @@ request_write_cb (GObject *source, g_data_input_stream_read_until_async (data->data_in, HTTP_END_MARKER, G_PRIORITY_DEFAULT, - data->cancellable, + g_task_get_cancellable(data->task), reply_read_cb, data); } @@ -468,8 +461,7 @@ reply_read_cb (GObject *source, return; } - g_simple_async_result_complete (data->simple); - g_object_unref (data->simple); + g_object_unref (data->task); } static GIOStream * @@ -477,13 +469,10 @@ wocky_http_proxy_connect_finish (GProxy *proxy, GAsyncResult *result, GError **error) { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - ConnectAsyncData *data = g_simple_async_result_get_op_res_gpointer (simple); - - if (g_simple_async_result_propagate_error (simple, error)) -return NULL; + GTask *task = G_TASK (result); + ConnectAsyncData *data = g_task_propagate_pointer (task, error); - return g_object_ref (data->io_stream); + return data ? g_object_ref (data->io_stream) : NULL; } static gboolean -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 14/14] Add strings for translation
While doing the work to use GTask isntead of GSimpleAsyncResult I've noticed a few error strings that were not marked to be translated. I am not exactly sure if it was intentional or not, but I do believe that our error messages should be translated. --- po/POTFILES.in | 6 ++ src/channel-main.c | 4 +++- src/channel-port.c | 4 +++- src/channel-usbredir.c | 4 ++-- src/spice-channel.c | 2 +- src/spice-pulse.c| 8 +--- src/usb-acl-helper.c | 10 ++ src/usb-device-manager.c | 4 ++-- src/vmcstream.c | 4 +++- src/win-usb-driver-install.c | 16 +--- 10 files changed, 40 insertions(+), 22 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index ad12609..7c79541 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,8 +1,14 @@ +src/channel-main.c +src/channel-port.c src/channel-usbredir.c src/desktop-integration.c src/spice-channel.c src/spice-cmdline.c src/spice-option.c +src/spice-pulse.c +src/usb-acl-helper.c src/usb-device-manager.c src/usb-device-widget.c src/usbutil.c +src/vmcstream.c +src/win-usb-driver-install.c diff --git a/src/channel-main.c b/src/channel-main.c index 6c0f238..40d5cff 100644 --- a/src/channel-main.c +++ b/src/channel-main.c @@ -21,6 +21,8 @@ #include #include +#include + #include "glib-compat.h" #include "spice-client.h" #include "spice-common.h" @@ -3143,7 +3145,7 @@ void spice_main_file_copy_async(SpiceMainChannel *channel, spice_main_file_copy_async, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"The agent is not connected"); +_("The agent is not connected")); return; } diff --git a/src/channel-port.c b/src/channel-port.c index 20ee2fa..86194ab 100644 --- a/src/channel-port.c +++ b/src/channel-port.c @@ -23,6 +23,8 @@ #include "spice-marshal.h" #include "glib-compat.h" +#include + /** * SECTION:channel-port * @short_description: private communication channel @@ -295,7 +297,7 @@ void spice_port_write_async(SpicePortChannel *self, g_task_report_new_error(self, callback, user_data, spice_port_write_async, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"The port is not opened"); +_("The port is not opened")); return; } diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c index 4ddf7bf..824bc43 100644 --- a/src/channel-usbredir.c +++ b/src/channel-usbredir.c @@ -344,14 +344,14 @@ void spice_usbredir_channel_connect_device_async( if (!priv->host) { g_task_return_new_error(task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"Error libusb context not set"); +_("Error libusb context not set")); goto done; } if (priv->state != STATE_DISCONNECTED) { g_task_return_new_error(task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"Error channel is busy"); +_("Error channel is busy")); goto done; } diff --git a/src/spice-channel.c b/src/spice-channel.c index dd32818..246609a 100644 --- a/src/spice-channel.c +++ b/src/spice-channel.c @@ -2979,7 +2979,7 @@ void spice_channel_flush_async(SpiceChannel *self, GCancellable *cancellable, g_task_report_new_error(self, callback, user_data, spice_channel_flush_async, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"The channel is not ready yet"); +_("The channel is not ready yet")); return; } diff --git a/src/spice-pulse.c b/src/spice-pulse.c index 60a037c..5c3cfb7 100644 --- a/src/spice-pulse.c +++ b/src/spice-pulse.c @@ -28,6 +28,8 @@ #include #include +#include + #define SPICE_PULSE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_PULSE, SpicePulsePrivate)) @@ -995,7 +997,7 @@ static void complete_task(SpicePulse *pulse, struct async_task *task, const gcha g_task_return_new_error(task->task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, -"restore-info failed due %s", +_("restore-info failed due %s"), err_msg); /* Volume-info does not change if stream is not found */ } else if ((task->is_playback == TRUE && p->playback.info_updated == FALSE) || @@ -1004,7 +1006,7 @@ static void complete_task(SpicePulse *pulse, struct async_task *task, const gcha g_task_return_new_error(task->task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ER
[Spice-devel] [PATCH 10/14] usb-device-manager: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/usb-device-manager.c | 61 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c index c62f56e..1840177 100644 --- a/src/usb-device-manager.c +++ b/src/usb-device-manager.c @@ -1055,15 +1055,16 @@ static void spice_usb_device_manager_channel_connect_cb( GObject *gobject, GAsyncResult *channel_res, gpointer user_data) { SpiceUsbredirChannel *channel = SPICE_USBREDIR_CHANNEL(gobject); -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(user_data); +GTask *task = G_TASK(user_data); GError *err = NULL; spice_usbredir_channel_connect_device_finish(channel, channel_res, &err); -if (err) { -g_simple_async_result_take_error(result, err); -} -g_simple_async_result_complete(result); -g_object_unref(result); +if (err) +g_task_return_error(task, err); +else +g_task_return_boolean(task, TRUE); + +g_object_unref(task); } #ifdef G_OS_WIN32 @@ -1229,7 +1230,7 @@ static void spice_usb_device_manager_check_redir_on_connect( SpiceUsbDeviceManager *self, SpiceChannel *channel) { SpiceUsbDeviceManagerPrivate *priv = self->priv; -GSimpleAsyncResult *result; +GTask *task; SpiceUsbDevice *device; libusb_device *libdev; guint i; @@ -1254,15 +1255,19 @@ static void spice_usb_device_manager_check_redir_on_connect( libdev, 0) == 0) { /* Note: re-uses spice_usb_device_manager_connect_device_async's completion handling code! */ -result = g_simple_async_result_new(G_OBJECT(self), - spice_usb_device_manager_auto_connect_cb, - spice_usb_device_ref(device), - spice_usb_device_manager_connect_device_async); +task = g_task_new(self, + NULL, + spice_usb_device_manager_auto_connect_cb, + spice_usb_device_ref(device)); + +g_task_set_source_tag(task, + spice_usb_device_manager_connect_device_async); + spice_usbredir_channel_connect_device_async( SPICE_USBREDIR_CHANNEL(channel), libdev, device, NULL, spice_usb_device_manager_channel_connect_cb, - result); + task); libusb_unref_device(libdev); return; /* We've taken the channel! */ } @@ -1401,15 +1406,14 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, GAsyncReadyCallback callback, gpointer user_data) { -GSimpleAsyncResult *result; +GTask *task; g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self)); g_return_if_fail(device != NULL); SPICE_DEBUG("connecting device %p", device); -result = g_simple_async_result_new(G_OBJECT(self), callback, user_data, - spice_usb_device_manager_connect_device_async); +task = g_task_new(self, cancellable, callback, user_data); #ifdef USE_USBREDIR SpiceUsbDeviceManagerPrivate *priv = self->priv; @@ -1417,7 +1421,7 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, guint i; if (spice_usb_device_manager_is_device_connected(self, device)) { -g_simple_async_result_set_error(result, +g_task_return_new_error(task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Cannot connect an already connected usb device"); goto done; @@ -1441,10 +1445,10 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, g_ptr_array_remove(priv->devices, device); g_signal_emit(self, signals[DEVICE_REMOVED], 0, device); spice_usb_device_unref(device); -g_simple_async_result_set_error(result, -SPICE_CLIENT_ERROR, -SPICE_CLIENT_ERROR_FAILED, -_("Device was not found")); +g_task_return_new_error(task, +SPICE_CLIENT_ERROR, +SPICE_CLIENT_ERROR_FAILED, +_("Device was not found")); goto done; } #endif @@ -1453,20 +1457,19 @@ _spice_usb_device_manager_connect_device_async(SpiceUsbDeviceManager *self, device, cancellable,
[Spice-devel] [PATCH 08/14] spice-pulse: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/spice-pulse.c | 96 +++ 1 file changed, 33 insertions(+), 63 deletions(-) diff --git a/src/spice-pulse.c b/src/spice-pulse.c index 22db893..60a037c 100644 --- a/src/spice-pulse.c +++ b/src/spice-pulse.c @@ -34,13 +34,12 @@ struct async_task { SpicePulse *pulse; SpiceMainChannel *main_channel; -GSimpleAsyncResult *res; +GTask *task; GAsyncReadyCallbackcallback; gpointer user_data; gboolean is_playback; pa_operation *pa_op; gulong cancel_id; -GCancellable *cancellable; }; struct stream { @@ -941,8 +940,8 @@ static gboolean free_async_task(gpointer user_data) g_object_unref(task->pulse); } -if (task->res) -g_object_unref(task->res); +if (task->task) +g_object_unref(task->task); if (task->main_channel) g_object_unref(task->main_channel); @@ -950,10 +949,9 @@ static gboolean free_async_task(gpointer user_data) if (task->pa_op != NULL) pa_operation_unref(task->pa_op); -if (task->cancel_id != 0) { -g_cancellable_disconnect(task->cancellable, task->cancel_id); -g_clear_object(&task->cancellable); -} +if (task->cancel_id != 0) +g_cancellable_disconnect(g_task_get_cancellable(task->task), + task->cancel_id); g_free(task); return G_SOURCE_REMOVE; @@ -981,14 +979,6 @@ static void cancel_task(GCancellable *cancellable, gpointer user_data) task->pulse->priv->pending_restore_task = NULL; } -#if !GLIB_CHECK_VERSION(2,32,0) -/* g_simple_async_result_set_check_cancellable is not present. Set an error - * in the GSimpleAsyncResult in case of _finish functions is called */ -g_simple_async_result_set_error(task->res, -SPICE_CLIENT_ERROR, -SPICE_CLIENT_ERROR_FAILED, -"Operation was cancelled"); -#endif /* FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=705395 * Free the memory in idle */ g_idle_add(free_async_task, task); @@ -1001,27 +991,23 @@ static void complete_task(SpicePulse *pulse, struct async_task *task, const gcha /* If we do have any err_msg, we failed */ if (err_msg != NULL) { -g_simple_async_result_set_op_res_gboolean(task->res, FALSE); -g_simple_async_result_set_error(task->res, -SPICE_CLIENT_ERROR, -SPICE_CLIENT_ERROR_FAILED, -"restore-info failed due %s", -err_msg); +g_task_return_boolean(task->task, FALSE); +g_task_return_new_error(task->task, +SPICE_CLIENT_ERROR, +SPICE_CLIENT_ERROR_FAILED, +"restore-info failed due %s", +err_msg); /* Volume-info does not change if stream is not found */ } else if ((task->is_playback == TRUE && p->playback.info_updated == FALSE) || (task->is_playback == FALSE && p->record.info_updated == FALSE)) { -g_simple_async_result_set_op_res_gboolean(task->res, FALSE); -g_simple_async_result_set_error(task->res, -SPICE_CLIENT_ERROR, -SPICE_CLIENT_ERROR_FAILED, -"Stream not found by pulse"); +g_task_return_boolean(task->task, FALSE); +g_task_return_new_error(task->task, +SPICE_CLIENT_ERROR, +SPICE_CLIENT_ERROR_FAILED, +"Stream not found by pulse"); } else { -g_simple_async_result_set_op_res_gboolean(task->res, TRUE); +g_task_return_boolean(task->task, TRUE); } - -/* As all async calls to PulseAudio are done with glib mainloop, it is - * safe to complete the operation synchronously here. */ -g_simple_async_result_complete(task->res); } static void spice_pulse_complete_async_task(struct async_task *task, const gchar *err_msg) @@ -1157,19 +1143,13 @@ static void pulse_stream_restore_info_async(gboolean is_playback, gpointer user_data) { SpicePulsePrivate *p = SPICE_PULSE(audio)->priv; -GSimpleAsyncResult *simple; +GTask *res; struct async_task *task = g_malloc0(sizeof(struct async_task)); pa_operation *op = NULL; -simple = g_simple_async_result_new(G_OBJECT(audio), - callback, -
[Spice-devel] [PATCH 04/14] channel-usbredir: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. --- src/channel-usbredir.c | 39 +-- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c index 0be72ba..4ddf7bf 100644 --- a/src/channel-usbredir.c +++ b/src/channel-usbredir.c @@ -76,7 +76,7 @@ struct _SpiceUsbredirChannelPrivate { int read_buf_size; enum SpiceUsbredirChannelState state; #if USE_POLKIT -GSimpleAsyncResult *result; +GTask *task; SpiceUsbAclHelper *acl_helper; #endif }; @@ -297,12 +297,14 @@ static void spice_usbredir_channel_open_acl_cb( spice_usbredir_channel_open_device(channel, &err); } if (err) { -g_simple_async_result_take_error(priv->result, err); +g_task_return_error(priv->task, err); libusb_unref_device(priv->device); priv->device = NULL; g_boxed_free(spice_usb_device_get_type(), priv->spice_device); priv->spice_device = NULL; priv->state = STATE_DISCONNECTED; +} else { +g_task_return_boolean(priv->task, TRUE); } spice_usb_acl_helper_close_acl(priv->acl_helper); @@ -310,8 +312,7 @@ static void spice_usbredir_channel_open_acl_cb( g_object_set(spice_channel_get_session(SPICE_CHANNEL(channel)), "inhibit-keyboard-grab", FALSE, NULL); -g_simple_async_result_complete_in_idle(priv->result); -g_clear_object(&priv->result); +g_clear_object(&priv->task); } #endif @@ -325,7 +326,7 @@ void spice_usbredir_channel_connect_device_async( gpointer user_data) { SpiceUsbredirChannelPrivate *priv = channel->priv; -GSimpleAsyncResult *result; +GTask *task; #if ! USE_POLKIT GError *err = NULL; #endif @@ -338,18 +339,17 @@ void spice_usbredir_channel_connect_device_async( spice_usb_device_get_pid(spice_device), spice_device, channel); -result = g_simple_async_result_new(G_OBJECT(channel), callback, user_data, - spice_usbredir_channel_connect_device_async); +task = g_task_new(channel, cancellable, callback, user_data); if (!priv->host) { -g_simple_async_result_set_error(result, +g_task_return_new_error(task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Error libusb context not set"); goto done; } if (priv->state != STATE_DISCONNECTED) { -g_simple_async_result_set_error(result, +g_task_return_new_error(task, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED, "Error channel is busy"); goto done; @@ -359,7 +359,7 @@ void spice_usbredir_channel_connect_device_async( priv->spice_device = g_boxed_copy(spice_usb_device_get_type(), spice_device); #if USE_POLKIT -priv->result = result; +priv->task = task; priv->state = STATE_WAITING_FOR_ACL_HELPER; priv->acl_helper = spice_usb_acl_helper_new(); g_object_set(spice_channel_get_session(SPICE_CHANNEL(channel)), @@ -373,17 +373,17 @@ void spice_usbredir_channel_connect_device_async( return; #else if (!spice_usbredir_channel_open_device(channel, &err)) { -g_simple_async_result_take_error(result, err); +g_task_return_error(task, err); libusb_unref_device(priv->device); priv->device = NULL; g_boxed_free(spice_usb_device_get_type(), priv->spice_device); priv->spice_device = NULL; -} +} else { +g_task_return_boolean(task, TRUE); #endif done: -g_simple_async_result_complete_in_idle(result); -g_object_unref(result); +g_object_unref(task); } G_GNUC_INTERNAL @@ -392,16 +392,11 @@ gboolean spice_usbredir_channel_connect_device_finish( GAsyncResult *res, GError **err) { -GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT(res); +GTask *task = G_TASK(res); -g_return_val_if_fail(g_simple_async_result_is_valid(res, G_OBJECT(channel), - spice_usbredir_channel_connect_device_async), - FALSE); +g_return_val_if_fail(g_task_is_valid(task, channel), FALSE); -if (g_simple_async_result_propagate_error(result, err)) -return FALSE; - -return TRUE; +return g_task_propagate_boolean(task, err); } G_GNUC_INTERNAL -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 01/14] channel-base: Use GTask instead of GSimpleAsyncResult
Instead of using GSimpleAsyncResult, use the new GTask API, which is much more straightforward. For using the new GTask API, let's bump GIO (part of GLib) dependency version to 2.36, which is safe based on major distro support: - Debian Jessie: glib-2.42 - RHEL-7.1: glib-2.40 - SLES12: glib-2.38 - Ubuntu LTS 14.04: glib-2.40 --- configure.ac | 6 +++--- src/channel-base.c | 26 ++ 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/configure.ac b/configure.ac index 38db8b5..e113487 100644 --- a/configure.ac +++ b/configure.ac @@ -201,7 +201,7 @@ fi AC_CHECK_FUNCS(clearenv strtok_r) -PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.28) +PKG_CHECK_MODULES(GLIB2, glib-2.0) AC_SUBST(GLIB2_CFLAGS) AC_SUBST(GLIB2_LIBS) @@ -209,7 +209,7 @@ PKG_CHECK_MODULES(GOBJECT2, gobject-2.0) AC_SUBST(GOBJECT2_CFLAGS) AC_SUBST(GOBJECT2_LIBS) -PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.10.0 $gio_os) +PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.36 $gio_os) AC_SUBST(GIO_CFLAGS) AC_SUBST(GIO_LIBS) @@ -217,7 +217,7 @@ PKG_CHECK_MODULES(CAIRO, cairo >= 1.2.0) AC_SUBST(CAIRO_CFLAGS) AC_SUBST(CAIRO_LIBS) -PKG_CHECK_MODULES(GTHREAD, gthread-2.0 > 2.0.0) +PKG_CHECK_MODULES(GTHREAD, gthread-2.0) AC_SUBST(GTHREAD_CFLAGS) AC_SUBST(GTHREAD_LIBS) diff --git a/src/channel-base.c b/src/channel-base.c index 13e4ced..517e7b2 100644 --- a/src/channel-base.c +++ b/src/channel-base.c @@ -240,10 +240,9 @@ void spice_channel_set_handlers(SpiceChannelClass *klass, static void vmc_write_free_cb(uint8_t *data, void *user_data) { -GSimpleAsyncResult *result = user_data; +GTask *task = user_data; -g_simple_async_result_complete_in_idle(result); -g_object_unref(result); +g_object_unref(task); } G_GNUC_INTERNAL @@ -254,15 +253,14 @@ void spice_vmc_write_async(SpiceChannel *self, gpointer user_data) { SpiceMsgOut *msg; -GSimpleAsyncResult *simple; +GTask *task; -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); +task = g_task_new(self, cancellable, callback, user_data); +g_task_return_int(task, 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); + vmc_write_free_cb, task); spice_msg_out_send(msg); } @@ -270,17 +268,13 @@ G_GNUC_INTERNAL gssize spice_vmc_write_finish(SpiceChannel *self, GAsyncResult *result, GError **error) { -GSimpleAsyncResult *simple; +GTask *task; g_return_val_if_fail(result != NULL, -1); -simple = (GSimpleAsyncResult *)result; +task = G_TASK(result); -if (g_simple_async_result_propagate_error(simple, error)) -return -1; +g_return_val_if_fail(g_task_is_valid(task, self), -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 g_task_propagate_int(task, error); } -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH 00/14] gobject: Use GTask API
This series (apart from the last patch) could be merged into a single patch. I haven't done this because I'm not so sure about some changes in the spice-{gstaudio,pulse}, like in spice_gstaudio_get_record_volume_info_finish() or in pulse_stream_restore_info_finish(). Fabiano Fidêncio (14): channel-base: Use GTask instead of GSimpleAsyncResult channel-main: Use GTask instead of GSimpleAsyncResult channel-port: Use GTask instead of GSimpleAsyncResult channel-usbredir: Use GTask instead of GSimpleAsyncResult smartcard-manager: Use GTask instead of GSimpleAsyncResult spice-channel: Use GTask instead of GSimpleAsyncResult spice-gstaudio: Use GTask instead of GSimpleAsyncResult spice-pulse: Use GTask instead of GSimpleAsyncResult usb-acl-helper: Use GTask instead of GSimpleAsyncResult usb-device-manager: Use GTask instead of GSimpleAsyncResult vmcstream: Use GTask instead of GSimpleAsyncResult win-usb-driver-install: Use GTask instead of GSimpleAsyncResult wocky-http-proxy: Use GTask instead of GSimpleAsyncResult Add strings for translation configure.ac | 6 +- po/POTFILES.in | 6 ++ src/channel-base.c | 26 - src/channel-main.c | 85 src/channel-port.c | 7 ++- src/channel-usbredir.c | 43 +++--- src/smartcard-manager.c | 33 +-- src/spice-channel.c | 34 +-- src/spice-gstaudio.c | 48 src/spice-pulse.c| 98 src/usb-acl-helper.c | 86 ++-- src/usb-device-manager.c | 65 +++-- src/vmcstream.c | 131 ++- src/win-usb-driver-install.c | 90 +++-- src/wocky-http-proxy.c | 47 ++-- 15 files changed, 340 insertions(+), 465 deletions(-) -- 2.5.0 ___ Spice-devel mailing list Spice-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/spice-devel
[Spice-devel] [PATCH] Remove GSLice usage
It's being slowly deprecated im glib https://bugzilla.gnome.org/show_bug.cgi?id=754687 --- src/channel-display.c | 6 +++--- src/channel-smartcard.c | 4 ++-- src/spice-channel-cache.h | 8 src/spice-channel.c | 8 src/spice-grabsequence.c | 8 src/spice-util.c | 4 ++-- src/wocky-http-proxy.c| 4 ++-- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/channel-display.c b/src/channel-display.c index dc73235..6a474b1 100644 --- a/src/channel-display.c +++ b/src/channel-display.c @@ -635,7 +635,7 @@ static void destroy_surface(gpointer data) display_surface *surface = data; destroy_canvas(surface); -g_slice_free(display_surface, surface); +g_free(surface); } static void spice_display_channel_init(SpiceDisplayChannel *channel) @@ -869,7 +869,7 @@ static void display_handle_mode(SpiceChannel *channel, SpiceMsgIn *in) g_warn_if_fail(c->mark == FALSE); -surface = g_slice_new0(display_surface); +surface = g_new0(display_surface, 1); surface->format = mode->bits == 32 ? SPICE_SURFACE_FMT_32_xRGB : SPICE_SURFACE_FMT_16_555; surface->width = mode->x_res; @@ -1674,7 +1674,7 @@ static void display_handle_surface_create(SpiceChannel *channel, SpiceMsgIn *in) { SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv; SpiceMsgSurfaceCreate *create = spice_msg_in_parsed(in); -display_surface *surface = g_slice_new0(display_surface); +display_surface *surface = g_new0(display_surface, 1); surface->surface_id = create->surface_id; surface->format = create->format; diff --git a/src/channel-smartcard.c b/src/channel-smartcard.c index b5535e6..e2e1aad 100644 --- a/src/channel-smartcard.c +++ b/src/channel-smartcard.c @@ -241,7 +241,7 @@ smartcard_message_free(SpiceSmartcardChannelMessage *message) { if (message->message) spice_msg_out_unref(message->message); -g_slice_free(SpiceSmartcardChannelMessage, message); +g_free(message); } #if USE_SMARTCARD @@ -301,7 +301,7 @@ smartcard_message_new(VSCMsgType msg_type, SpiceMsgOut *msg_out) { SpiceSmartcardChannelMessage *message; -message = g_slice_new0(SpiceSmartcardChannelMessage); +message = g_new0(SpiceSmartcardChannelMessage, 1); message->message = msg_out; message->message_type = msg_type; diff --git a/src/spice-channel-cache.h b/src/spice-channel-cache.h index e609a67..75cc2cd 100644 --- a/src/spice-channel-cache.h +++ b/src/spice-channel-cache.h @@ -37,7 +37,7 @@ typedef struct display_cache { static inline display_cache_item* cache_item_new(guint64 id, gboolean lossy) { -display_cache_item *self = g_slice_new(display_cache_item); +display_cache_item *self = g_new(display_cache_item, 1); self->id = id; self->lossy = lossy; self->ref_count = 1; @@ -46,12 +46,12 @@ static inline display_cache_item* cache_item_new(guint64 id, gboolean lossy) static inline void cache_item_free(display_cache_item *self) { -g_slice_free(display_cache_item, self); +g_free(self); } static inline display_cache* cache_new(GDestroyNotify value_destroy) { -display_cache * self = g_slice_new(display_cache); +display_cache * self = g_new(display_cache, 1); self->table = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify) cache_item_free, value_destroy); @@ -131,7 +131,7 @@ static inline void cache_clear(display_cache *cache) static inline void cache_free(display_cache *cache) { g_hash_table_unref(cache->table); -g_slice_free(display_cache, cache); +g_free(cache); } G_END_DECLS diff --git a/src/spice-channel.c b/src/spice-channel.c index 41c94d0..ff85715 100644 --- a/src/spice-channel.c +++ b/src/spice-channel.c @@ -471,7 +471,7 @@ SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel) g_return_val_if_fail(channel != NULL, NULL); -in = g_slice_new0(SpiceMsgIn); +in = g_new0(SpiceMsgIn, 1); in->refcount = 1; in->channel = channel; @@ -519,7 +519,7 @@ void spice_msg_in_unref(SpiceMsgIn *in) } else { g_free(in->data); } -g_slice_free(SpiceMsgIn, in); +g_free(in); } G_GNUC_INTERNAL @@ -624,7 +624,7 @@ SpiceMsgOut *spice_msg_out_new(SpiceChannel *channel, int type) g_return_val_if_fail(c != NULL, NULL); -out = g_slice_new0(SpiceMsgOut); +out = g_new0(SpiceMsgOut, 1); out->refcount = 1; out->channel = channel; out->ro_check = msg_check_read_only(c->channel_type, type); @@ -660,7 +660,7 @@ void spice_msg_out_unref(SpiceMsgOut *out) if (out->refcount > 0) return; spice_marshaller_destroy(out->marshaller); -g_slice_free(SpiceMsgOut, out); +g_free(out); } /* system context */ diff --git a/src/spice-grabsequence.c b/src/spice-grabsequence.c index 26bf96f..3d87329 100644 --- a/src/spice-grabsequ