diff --git a/patches/sources b/patches/sources index bbda2a69..1689ba1b 100644 --- a/patches/sources +++ b/patches/sources @@ -15,8 +15,8 @@ GCRYPT_SRC="https://www.gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.8.4.tar.gz" PIXMAN_SRC="https://www.cairographics.org/releases/pixman-0.38.0.tar.gz" OPENSSL_SRC="https://www.openssl.org/source/old/1.1.1/openssl-1.1.1b.tar.gz" OPUS_SRC="https://archive.mozilla.org/pub/opus/opus-1.3.tar.gz" -SPICE_PROTOCOL_SRC="https://www.spice-space.org/download/releases/spice-protocol-0.12.15.tar.bz2" -SPICE_SERVER_SRC="https://www.spice-space.org/download/releases/spice-server/spice-0.14.1.tar.bz2" +SPICE_PROTOCOL_SRC="https://www.spice-space.org/download/releases/spice-protocol-0.14.4.tar.xz" +SPICE_SERVER_SRC="https://www.spice-space.org/download/releases/spice-server/spice-0.14.3.tar.bz2" USB_SRC="https://github.com/libusb/libusb/releases/download/v1.0.24/libusb-1.0.24.tar.bz2" USBREDIR_SRC="https://www.spice-space.org/download/usbredir/usbredir-0.8.0.tar.bz2" QEMU_SRC="https://github.com/utmapp/qemu/releases/download/v6.2.0-utm/qemu-6.2.0-utm.tar.bz2" @@ -29,7 +29,7 @@ GST_GOOD_SRC="https://gstreamer.freedesktop.org/src/gst-plugins-good/gst-plugins XML2_SRC="http://xmlsoft.org/sources/libxml2-2.9.10.tar.gz" SOUP_SRC="https://ftp.gnome.org/pub/GNOME/sources/libsoup/2.65/libsoup-2.65.1.tar.xz" PHODAV_SRC="http://ftp.gnome.org/pub/GNOME/sources/phodav/2.2/phodav-2.2.tar.xz" -SPICE_CLIENT_SRC="https://www.spice-space.org/download/gtk/spice-gtk-0.36.tar.bz2" +SPICE_CLIENT_SRC="https://www.spice-space.org/download/gtk/spice-gtk-0.40.tar.xz" # Source files for GPU acceleration DEPOT_TOOLS_REPO="https://chromium.googlesource.com/chromium/tools/depot_tools.git" diff --git a/patches/spice-0.14.1.patch b/patches/spice-0.14.1.patch deleted file mode 100644 index 8bfc5f12..00000000 --- a/patches/spice-0.14.1.patch +++ /dev/null @@ -1,256 +0,0 @@ -diff -aur a/Makefile.in b/Makefile.in ---- a/Makefile.in 2018-08-22 04:32:02.000000000 -0700 -+++ b/Makefile.in 2019-04-23 11:52:06.000000000 -0700 -@@ -422,7 +422,7 @@ - valgrind_tools = @valgrind_tools@ - NULL = - ACLOCAL_AMFLAGS = -I m4 --SUBDIRS = subprojects/spice-common server docs tools -+SUBDIRS = subprojects/spice-common server docs - pkgconfigdir = $(libdir)/pkgconfig - pkgconfig_DATA = spice-server.pc - DISTCHECK_CONFIGURE_FLAGS = \ - -From 23e9f84657479298f2527dc84ba64f00d811bc96 Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Wed, 24 Apr 2019 18:50:25 -0700 -Subject: [PATCH 1/2] OSX: added support for OSX/iOS - -Fix some Apple specific issues such as lack of %m print format and buggy TCP_NOPUSH implementation ---- - server/red-stream.c | 16 +++++++++++++++- - server/red-worker.c | 2 ++ - server/reds.c | 18 +++++++++++++++++- - 3 files changed, 34 insertions(+), 2 deletions(-) - -diff --git a/server/red-stream.c b/server/red-stream.c -index 18c4a935..3fec87cf 100644 ---- a/server/red-stream.c -+++ b/server/red-stream.c -@@ -39,7 +39,7 @@ - #include "reds.h" - - // compatibility for *BSD systems --#ifndef TCP_CORK -+#if !defined(TCP_CORK) && !defined(__APPLE__) - #define TCP_CORK TCP_NOPUSH - #endif - -@@ -100,6 +100,7 @@ struct RedStreamPrivate { - SpiceCoreInterfaceInternal *core; - }; - -+#if !defined(__APPLE__) // TCP_CORK doesn't exist and TCP_NOPUSH is broken - /** - * Set TCP_CORK on socket - */ -@@ -109,6 +110,7 @@ static int socket_set_cork(int socket, int enabled) - SPICE_VERIFY(sizeof(enabled) == sizeof(int)); - return setsockopt(socket, IPPROTO_TCP, TCP_CORK, &enabled, sizeof(enabled)); - } -+#endif - - static ssize_t stream_write_cb(RedStream *s, const void *buf, size_t size) - { -@@ -223,6 +225,7 @@ bool red_stream_write_all(RedStream *stream, const void *in_buf, size_t n) - - bool red_stream_set_auto_flush(RedStream *s, bool auto_flush) - { -+#if !defined(__APPLE__) - if (s->priv->use_cork == !auto_flush) { - return true; - } -@@ -239,15 +242,18 @@ bool red_stream_set_auto_flush(RedStream *s, bool auto_flush) - socket_set_cork(s->socket, 0); - s->priv->corked = false; - } -+#endif - return true; - } - - void red_stream_flush(RedStream *s) - { -+#if !defined(__APPLE__) - if (s->priv->corked) { - socket_set_cork(s->socket, 0); - socket_set_cork(s->socket, 1); - } -+#endif - } - - #if HAVE_SASL -@@ -352,8 +358,16 @@ int red_stream_send_msgfd(RedStream *stream, int fd) - memcpy(CMSG_DATA(cmsg), &fd, fd_size); - } - -+#if defined(__APPLE__) -+ int set = 1; -+ setsockopt(stream->socket, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int)); -+#endif - do { -+#if defined(__APPLE__) -+ r = sendmsg(stream->socket, &msgh, 0); -+#else - r = sendmsg(stream->socket, &msgh, MSG_NOSIGNAL); -+#endif - } while (r < 0 && (errno == EINTR || errno == EAGAIN)); - - return r; -diff --git a/server/red-worker.c b/server/red-worker.c -index ccab9d96..04c695bb 100644 ---- a/server/red-worker.c -+++ b/server/red-worker.c -@@ -1391,7 +1391,9 @@ bool red_worker_run(RedWorker *worker) - spice_error("create thread failed %d", r); - } - pthread_sigmask(SIG_SETMASK, &curr_sig_mask, NULL); -+#if !defined(__APPLE__) // not supported - pthread_setname_np(worker->thread, "SPICE Worker"); -+#endif - - return r == 0; - } -diff --git a/server/reds.c b/server/reds.c -index 85043a88..f1e19b87 100644 ---- a/server/reds.c -+++ b/server/reds.c -@@ -3555,6 +3555,7 @@ static const int video_codec_caps[] = { - static const char* parse_next_video_codec(const char *codecs, char **encoder, - char **codec) - { -+ size_t len; - if (!codecs) { - return NULL; - } -@@ -3562,8 +3563,22 @@ static const char* parse_next_video_codec(const char *codecs, char **encoder, - if (!*codecs) { - return NULL; - } -+ len = strcspn(codecs, ";"); - int n; - *encoder = *codec = NULL; -+#if defined(__APPLE__) -+ char *aencoder = malloc(len); -+ char *acodec = malloc(len); -+ if (sscanf(codecs, "%[0-9a-zA-Z_]:%[0-9a-zA-Z_]%n", aencoder, acodec, &n) == 2) { -+ // this avoids accepting "encoder:codec" followed by garbage like "$%*" -+ if (codecs[n] != ';' && codecs[n] != '\0') { -+ free(acodec); -+ acodec = NULL; -+ } -+ } -+ *encoder = aencoder; -+ *codec = acodec; -+#else - if (sscanf(codecs, "%m[0-9a-zA-Z_]:%m[0-9a-zA-Z_]%n", encoder, codec, &n) == 2) { - // this avoids accepting "encoder:codec" followed by garbage like "$%*" - if (codecs[n] != ';' && codecs[n] != '\0') { -@@ -3571,7 +3586,8 @@ static const char* parse_next_video_codec(const char *codecs, char **encoder, - *codec = NULL; - } - } -- return codecs + strcspn(codecs, ";"); -+#endif -+ return codecs + len; - } - - static void reds_set_video_codecs_from_string(RedsState *reds, const char *codecs) --- -2.28.0 - -From 9fe644b11858d803d51a5b162be0b18d864fc5c3 Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Wed, 28 Jul 2021 17:22:25 -0700 -Subject: [PATCH 2/2] net-utils: fix EINVAL error on AF_UNIX sockets on darwin - ---- - server/net-utils.c | 26 +++++++++++++++++++++++--- - 1 file changed, 23 insertions(+), 3 deletions(-) - -diff --git a/server/net-utils.c b/server/net-utils.c -index ca8a4e7f..8265f15e 100644 ---- a/server/net-utils.c -+++ b/server/net-utils.c -@@ -34,6 +34,25 @@ - - #include "net-utils.h" - -+static inline bool -+darwin_einval_on_unix_socket(int fd, int err) -+{ -+#if defined(__APPLE__) -+ if (err == EINVAL || err == EOPNOTSUPP) { -+ union { -+ struct sockaddr sa; -+ char buf[1024]; -+ } addr; -+ socklen_t len = sizeof(addr); -+ -+ if (getsockname(fd, &addr.sa, &len) == 0 && addr.sa.sa_family == AF_UNIX) { -+ return true; -+ } -+ } -+#endif -+ return false; -+} -+ - /** - * red_socket_set_keepalive: - * @fd: a socket file descriptor -@@ -46,7 +65,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) - int keepalive = !!enable; - - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) == -1) { -- if (errno != ENOTSUP) { -+ if (errno != ENOTSUP && !darwin_einval_on_unix_socket(fd, errno)) { - g_warning("setsockopt for keepalive failed, %s", strerror(errno)); - return false; - } -@@ -58,7 +77,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) - - #ifdef HAVE_TCP_KEEPIDLE - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout)) == -1) { -- if (errno != ENOTSUP) { -+ if (errno != ENOTSUP && !darwin_einval_on_unix_socket(fd, errno)) { - g_warning("setsockopt for keepalive timeout failed, %s", strerror(errno)); - return false; - } -@@ -81,7 +100,8 @@ bool red_socket_set_no_delay(int fd, bool no_delay) - - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - &optval, sizeof(optval)) != 0) { -- if (errno != ENOTSUP && errno != ENOPROTOOPT) { -+ if (errno != ENOTSUP && errno != ENOPROTOOPT && -+ !darwin_einval_on_unix_socket(fd, errno)) { - spice_warning("setsockopt failed, %s", strerror(errno)); - return false; - } --- -2.28.0 - -From 3977c49109906b9ab26950e301a5ad684c36a57d Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Tue, 2 Nov 2021 12:56:54 -0700 -Subject: [PATCH] reds: always send monitors config - -Windows VDagent needs this to apply the resolution changes. ---- - server/reds.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/reds.c b/server/reds.c -index f1e19b87..2fa2cfae 100644 ---- a/server/reds.c -+++ b/server/reds.c -@@ -1182,7 +1182,7 @@ void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, const void - return; - case AGENT_MSG_FILTER_MONITORS_CONFIG: - reds_on_main_agent_monitors_config(reds, mcc, message, size); -- return; -+ break; - case AGENT_MSG_FILTER_PROTO_ERROR: - red_channel_client_shutdown(RED_CHANNEL_CLIENT(mcc)); - return; --- -2.28.0 - diff --git a/patches/spice-0.14.3.patch b/patches/spice-0.14.3.patch new file mode 100644 index 00000000..d882bdef --- /dev/null +++ b/patches/spice-0.14.3.patch @@ -0,0 +1,551 @@ +From c74ae160e3ac6d726fd312ba36f5ca4bfed0eb9c Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 13:36:13 +0100 +Subject: [PATCH 01/10] Fix compatibility with MSG_NOSIGNAL and Darwin + +Darwin does not have MSG_NOSIGNAL but allows to set a SO_NOSIGPIPE +option to disable sending SIGPIPE writing to closed socket. +Note that *BSD has the SO_NOSIGPIPE option but does not affect all +write calls so instead continue to use MSG_NOSIGNAL instead on +that systems. + +Signed-off-by: Frediano Ziglio +--- + server/net-utils.c | 12 ++++++++++++ + server/net-utils.h | 1 + + server/reds.c | 1 + + server/sys-socket.h | 4 ++++ + 4 files changed, 18 insertions(+) + +diff --git a/server/net-utils.c b/server/net-utils.c +index 144bfd8f..78b94886 100644 +--- a/server/net-utils.c ++++ b/server/net-utils.c +@@ -150,3 +150,15 @@ int red_socket_get_no_delay(int fd) + + return delay_val; + } ++ ++/** ++ * red_socket_set_nosigpipe ++ * @fd: a socket file descriptor ++ */ ++void red_socket_set_nosigpipe(int fd, bool enable) ++{ ++#if defined(SO_NOSIGPIPE) && defined(__APPLE__) ++ int val = !!enable; ++ setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &val, sizeof(val)); ++#endif ++} +diff --git a/server/net-utils.h b/server/net-utils.h +index f95d689a..b93ec0ab 100644 +--- a/server/net-utils.h ++++ b/server/net-utils.h +@@ -24,5 +24,6 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout); + bool red_socket_set_no_delay(int fd, bool no_delay); + int red_socket_get_no_delay(int fd); + bool red_socket_set_non_blocking(int fd, bool non_blocking); ++void red_socket_set_nosigpipe(int fd, bool enable); + + #endif /* RED_NET_UTILS_H_ */ +diff --git a/server/reds.c b/server/reds.c +index ee8cf387..d91b32b0 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -2458,6 +2458,7 @@ static RedLinkInfo *reds_init_client_connection(RedsState *reds, int socket) + } + + red_socket_set_keepalive(socket, TRUE, KEEPALIVE_TIMEOUT); ++ red_socket_set_nosigpipe(socket, true); + + link = g_new0(RedLinkInfo, 1); + link->reds = reds; +diff --git a/server/sys-socket.h b/server/sys-socket.h +index 3a3b7878..2935cfb5 100644 +--- a/server/sys-socket.h ++++ b/server/sys-socket.h +@@ -139,4 +139,8 @@ int socket_newpair(int type, int protocol, int sv[2]); + #define socketpair(family, type, protocol, sv) socket_newpair(type, protocol, sv) + #endif + ++#if defined(SO_NOSIGPIPE) && defined(__APPLE__) ++#define MSG_NOSIGNAL 0 ++#endif ++ + #endif // RED_SYS_SOCKET_H_ +-- +2.32.0 (Apple Git-132) + +From c3ca9e8db128fb8e9fa033f8f1aabb96514f6f94 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 14:30:37 +0100 +Subject: [PATCH 02/10] Fix compatibility with pthread_setname_np and Darwin + +On Darwin pthread_setname_np accepts only an argument and +set current thread name. + +Signed-off-by: Frediano Ziglio +--- + server/red-worker.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/server/red-worker.c b/server/red-worker.c +index 12a8e739..2f07337e 100644 +--- a/server/red-worker.c ++++ b/server/red-worker.c +@@ -1120,6 +1120,9 @@ static void *red_worker_main(void *arg) + RedWorker *worker = arg; + + spice_debug("begin"); ++#if defined(__APPLE__) ++ pthread_setname_np("SPICE Worker"); ++#endif + SPICE_VERIFY(MAX_PIPE_SIZE > WIDE_CLIENT_ACK_WINDOW && + MAX_PIPE_SIZE > NARROW_CLIENT_ACK_WINDOW); //ensure wakeup by ack message + +@@ -1159,7 +1162,9 @@ bool red_worker_run(RedWorker *worker) + #ifndef _WIN32 + pthread_sigmask(SIG_SETMASK, &curr_sig_mask, NULL); + #endif ++#if !defined(__APPLE__) + pthread_setname_np(worker->thread, "SPICE Worker"); ++#endif + + return r == 0; + } +-- +2.32.0 (Apple Git-132) + +From d728111a51c8c08806e78c3b0d46d92a048b865a Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 14:35:10 +0100 +Subject: [PATCH 03/10] Fix compatibility with mremap and Darwin + +Darwin does not have mremap. Use munmap+mmap instead. +That code is not in a hot path, number of nodes do not change very +often. + +Signed-off-by: Frediano Ziglio +--- + tools/reds_stat.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/tools/reds_stat.c b/tools/reds_stat.c +index deffec1b..7d35c45b 100644 +--- a/tools/reds_stat.c ++++ b/tools/reds_stat.c +@@ -86,7 +86,6 @@ int main(int argc, char **argv) + pid_t kvm_pid = 0; + uint32_t num_of_nodes = 0; + size_t shm_size; +- size_t shm_old_size; + int shm_name_len; + int ret = EXIT_FAILURE; + int fd; +@@ -142,11 +141,11 @@ int main(int argc, char **argv) + printf("spice statistics\n\n"); + if (num_of_nodes != reds_stat->num_of_nodes) { + num_of_nodes = reds_stat->num_of_nodes; +- shm_old_size = shm_size; ++ munmap(reds_stat, shm_size); + shm_size = header_size + num_of_nodes * sizeof(SpiceStatNode); +- reds_stat = mremap(reds_stat, shm_old_size, shm_size, MREMAP_MAYMOVE); ++ reds_stat = (SpiceStat *)mmap(NULL, shm_size, PROT_READ, MAP_SHARED, fd, 0); + if (reds_stat == (SpiceStat *)MAP_FAILED) { +- perror("mremap"); ++ perror("mmap"); + goto error; + } + reds_nodes = (SpiceStatNode *)((char *) reds_stat + header_size); +-- +2.32.0 (Apple Git-132) + +From 20e058fd9ba28892adffc8d2ade809b698577756 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 20:47:05 +0100 +Subject: [PATCH 04/10] Fix compatibility with TCP_KEEPIDLE and Darwin + +Darwin uses for the same setting the TCP_KEEPALIVE option. +Use TCP_KEEPALIVE instead of TCP_KEEPIDLE for Darwin. + +Signed-off-by: Frediano Ziglio +--- + server/net-utils.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/server/net-utils.c b/server/net-utils.c +index 78b94886..32ceb3b8 100644 +--- a/server/net-utils.c ++++ b/server/net-utils.c +@@ -35,6 +35,10 @@ + #include "net-utils.h" + #include "sys-socket.h" + ++#if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) && defined(__APPLE__) ++#define TCP_KEEPIDLE TCP_KEEPALIVE ++#endif ++ + /** + * red_socket_set_keepalive: + * @fd: a socket file descriptor +@@ -57,7 +61,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) + return true; + } + +-#ifdef HAVE_TCP_KEEPIDLE ++#ifdef TCP_KEEPIDLE + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout)) == -1) { + if (errno != ENOTSUP) { + g_warning("setsockopt for keepalive timeout failed, %s", strerror(errno)); +-- +2.32.0 (Apple Git-132) + +From eb21efe8e5d6fa2cc893b1f7fec356fd06834d30 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 20:50:56 +0100 +Subject: [PATCH 05/10] Fix compatibility with ENOTSUP and Darwin + +Darwin uses also the constant EOPNOTSUPP for the same reasons. +In some versions EOPNOTSUPP is defined as ENOTSUP. +Check both values, not only ENOTSUP. + +Signed-off-by: Frediano Ziglio +--- + server/net-utils.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/server/net-utils.c b/server/net-utils.c +index 32ceb3b8..f0aecc3d 100644 +--- a/server/net-utils.c ++++ b/server/net-utils.c +@@ -39,6 +39,12 @@ + #define TCP_KEEPIDLE TCP_KEEPALIVE + #endif + ++#if defined(EOPNOTSUPP) && EOPNOTSUPP != ENOTSUP ++#define NOTSUP_ERROR(err) ((err) == ENOTSUP || (err) == EOPNOTSUPP) ++#else ++#define NOTSUP_ERROR(err) ((err) == ENOTSUP) ++#endif ++ + /** + * red_socket_set_keepalive: + * @fd: a socket file descriptor +@@ -51,7 +57,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) + int keepalive = !!enable; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) == -1) { +- if (errno != ENOTSUP) { ++ if (!NOTSUP_ERROR(errno)) { + g_warning("setsockopt for keepalive failed, %s", strerror(errno)); + return false; + } +@@ -63,7 +69,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) + + #ifdef TCP_KEEPIDLE + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout)) == -1) { +- if (errno != ENOTSUP) { ++ if (!NOTSUP_ERROR(errno)) { + g_warning("setsockopt for keepalive timeout failed, %s", strerror(errno)); + return false; + } +@@ -86,7 +92,7 @@ bool red_socket_set_no_delay(int fd, bool no_delay) + + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + &optval, sizeof(optval)) != 0) { +- if (errno != ENOTSUP && errno != ENOPROTOOPT) { ++ if (!NOTSUP_ERROR(errno) && errno != ENOPROTOOPT) { + spice_warning("setsockopt failed, %s", strerror(errno)); + return false; + } +-- +2.32.0 (Apple Git-132) + +From f93264cb497ea3ab45d35ab3e03546d1cdaa1600 Mon Sep 17 00:00:00 2001 +From: Frediano Ziglio +Date: Wed, 15 Apr 2020 21:15:34 +0100 +Subject: [PATCH 06/10] Fix compatibility with TCP sockets and Darwin + +Using socket pairs and trying to set a TCP level option on the +socket setsockopt returns EINVAL error and not ENOTSUP as +expected. +Check this case and handle as ENOTSUP (ignoring it). + +Signed-off-by: Frediano Ziglio +--- + server/net-utils.c | 26 +++++++++++++++++++++++--- + 1 file changed, 23 insertions(+), 3 deletions(-) + +diff --git a/server/net-utils.c b/server/net-utils.c +index f0aecc3d..e9778e73 100644 +--- a/server/net-utils.c ++++ b/server/net-utils.c +@@ -45,6 +45,25 @@ + #define NOTSUP_ERROR(err) ((err) == ENOTSUP) + #endif + ++static inline bool ++darwin_einval_on_unix_socket(int fd, int err) ++{ ++#if defined(__APPLE__) ++ if (err == EINVAL) { ++ union { ++ struct sockaddr sa; ++ char buf[1024]; ++ } addr; ++ socklen_t len = sizeof(addr); ++ ++ if (getsockname(fd, &addr.sa, &len) == 0 && addr.sa.sa_family == AF_UNIX) { ++ return true; ++ } ++ } ++#endif ++ return false; ++} ++ + /** + * red_socket_set_keepalive: + * @fd: a socket file descriptor +@@ -57,7 +76,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) + int keepalive = !!enable; + + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) == -1) { +- if (!NOTSUP_ERROR(errno)) { ++ if (!NOTSUP_ERROR(errno) && !darwin_einval_on_unix_socket(fd, errno)) { + g_warning("setsockopt for keepalive failed, %s", strerror(errno)); + return false; + } +@@ -69,7 +88,7 @@ bool red_socket_set_keepalive(int fd, bool enable, int timeout) + + #ifdef TCP_KEEPIDLE + if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &timeout, sizeof(timeout)) == -1) { +- if (!NOTSUP_ERROR(errno)) { ++ if (!NOTSUP_ERROR(errno) && !darwin_einval_on_unix_socket(fd, errno)) { + g_warning("setsockopt for keepalive timeout failed, %s", strerror(errno)); + return false; + } +@@ -92,7 +111,8 @@ bool red_socket_set_no_delay(int fd, bool no_delay) + + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, + &optval, sizeof(optval)) != 0) { +- if (!NOTSUP_ERROR(errno) && errno != ENOPROTOOPT) { ++ if (!NOTSUP_ERROR(errno) && errno != ENOPROTOOPT && ++ !darwin_einval_on_unix_socket(fd, errno)) { + spice_warning("setsockopt failed, %s", strerror(errno)); + return false; + } +-- +2.32.0 (Apple Git-132) + +From 2e6271dbbab76e3868a6cee1c9a800d87ccd30a1 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 19:17:58 -0800 +Subject: [PATCH 07/10] red-stream: disable socket_set_cork() on Darwin + +TCP_NOPUSH is broken and cannot be used. +--- + server/red-stream.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/server/red-stream.c b/server/red-stream.c +index 2c13aa2f..77d44c9a 100644 +--- a/server/red-stream.c ++++ b/server/red-stream.c +@@ -42,7 +42,7 @@ + #include "websocket.h" + + // compatibility for *BSD systems +-#if !defined(TCP_CORK) && !defined(_WIN32) ++#if !defined(TCP_CORK) && !defined(_WIN32) && !defined(__APPLE__) + #define TCP_CORK TCP_NOPUSH + #endif + +@@ -105,7 +105,8 @@ struct RedStreamPrivate { + SpiceCoreInterfaceInternal *core; + }; + +-#ifndef _WIN32 ++// TCP_NOPUSH is broken on Darwin ++#if !defined(_WIN32) && !defined(__APPLE__) + /** + * Set TCP_CORK on socket + */ +-- +2.32.0 (Apple Git-132) + +From 740fb04a95ff2a5aebd67f488e7d6f19b62fe3c1 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 19:20:06 -0800 +Subject: [PATCH 08/10] meson: fix build on Darwin + +--- + meson.build | 4 +++- + server/tests/meson.build | 6 +++++- + tools/meson.build | 2 +- + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/meson.build b/meson.build +index f8f89798..6d0a35a1 100644 +--- a/meson.build ++++ b/meson.build +@@ -102,7 +102,9 @@ foreach dep : ['libjpeg', 'zlib'] + spice_server_deps += dependency(dep) + endforeach + +-if host_machine.system() != 'windows' ++if host_machine.system() in ['darwin', 'ios'] ++ # librt and libm not required ++elif host_machine.system() != 'windows' + foreach dep : ['librt', 'libm'] + spice_server_deps += compiler.find_library(dep) + endforeach +diff --git a/server/tests/meson.build b/server/tests/meson.build +index 09ba0f22..7e1bbf73 100644 +--- a/server/tests/meson.build ++++ b/server/tests/meson.build +@@ -72,8 +72,12 @@ if host_machine.system() != 'windows' + tests += [ + ['test-stream', true], + ['test-stat-file', true], +- ['test-websocket', false], + ] ++ if host_machine.system() not in ['darwin', 'ios'] ++ tests += [ ++ ['test-websocket', false], ++ ] ++ endif + endif + + if spice_server_has_gstreamer +diff --git a/tools/meson.build b/tools/meson.build +index 8ec2cc91..4962f63d 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -1,4 +1,4 @@ +-if host_machine.system() != 'windows' ++if host_machine.system() not in ['ios', 'windows'] + executable('reds_stat', 'reds_stat.c', + install : false, + include_directories : spice_server_include, +-- +2.32.0 (Apple Git-132) + +From a411fbcb321347356a78126e923bd49aa91381df Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 19:23:44 -0800 +Subject: [PATCH 09/10] reds: always send monitors config + +When the Windows VDagent sees a new monitor config, it will trigger a +refresh of the display resolution. This is needed when the device driver +does not have the capability to see the resolution change directly from +QEMU (for example VirtIO GPU) and depends on VDagent to see the change. +--- + server/reds.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/server/reds.c b/server/reds.c +index d91b32b0..9513b5cf 100644 +--- a/server/reds.c ++++ b/server/reds.c +@@ -1256,7 +1256,7 @@ void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, const void + return; + case AGENT_MSG_FILTER_MONITORS_CONFIG: + reds_on_main_agent_monitors_config(reds, mcc, message, size); +- return; ++ break; + case AGENT_MSG_FILTER_PROTO_ERROR: + red_channel_client_shutdown(RED_CHANNEL_CLIENT(mcc)); + return; +-- +2.32.0 (Apple Git-132) + +From e32a7ea61569b7771f0ef655fba86f6d23d53d31 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 20:09:34 -0800 +Subject: [PATCH 10/10] gstreamer-encoder: work without Orc + +If Orc is missing, GStreamer will still work. +--- + meson.build | 6 +++++- + server/gstreamer-encoder.c | 11 +++++++++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 6d0a35a1..f8ad4f07 100644 +--- a/meson.build ++++ b/meson.build +@@ -134,7 +134,11 @@ if spice_server_gst_version != 'no' + dep = '@0@-@1@'.format(dep, spice_server_gst_version) + spice_server_deps += dependency(dep) + endforeach +- spice_server_deps += dependency('orc-0.4') ++ orc_dep = dependency('orc-0.4', required : false) ++ if orc_dep.found() ++ spice_server_deps += orc_dep ++ spice_server_config_data.set('HAVE_GST_ORC', '1') ++ endif + + gst_def = 'HAVE_GSTREAMER' + if spice_server_gst_version == '1.0' +diff --git a/server/gstreamer-encoder.c b/server/gstreamer-encoder.c +index 3ca04d7a..238463f2 100644 +--- a/server/gstreamer-encoder.c ++++ b/server/gstreamer-encoder.c +@@ -25,7 +25,9 @@ + #include + #include + #include ++#ifdef HAVE_GST_ORC + #include ++#endif + + #include "red-common.h" + #include "video-encoder.h" +@@ -1705,6 +1707,7 @@ static void spice_gst_encoder_get_stats(VideoEncoder *video_encoder, + } + } + ++#ifdef HAVE_GST_ORC + /* Check if ORC library can work. + * ORC library is used quite extensively by GStreamer + * to generate code dynamically. If ORC cannot work, GStreamer +@@ -1728,6 +1731,14 @@ static bool orc_check(void) + } + return orc_dynamic_code_ok; + } ++#else // HAVE_GST_ORC ++/* If we don't have Orc, GStreamer will still work ++ */ ++static bool orc_check(void) ++{ ++ return true; ++} ++#endif + + VideoEncoder *gstreamer_encoder_new(SpiceVideoCodecType codec_type, + uint64_t starting_bit_rate, +-- +2.32.0 (Apple Git-132) + +--- a/subprojects/spice-common/meson.build 2022-03-04 19:26:32.000000000 -0800 ++++ b/subprojects/spice-common/meson.build 2022-03-04 19:26:03.000000000 -0800 +@@ -14,7 +14,9 @@ + '-Wall', + '-Wextra', + '-Werror', +- '-Wno-unused-parameter'] ++ '-Wno-unused-parameter', ++ '-Wno-unused-function', ++ '-Wno-deprecated-declarations'] + + if get_option('alignment-checks') + spice_common_global_cflags += ['-DSPICE_DEBUG_ALIGNMENT'] +@@ -137,7 +139,7 @@ + if get_option('python-checks') + foreach module : ['six', 'pyparsing'] + message('Checking for python module @0@'.format(module)) +- cmd = run_command(python, '-m', module) ++ cmd = run_command(python, '-c', 'import @0@'.format(module)) + if cmd.returncode() != 0 + error('Python module @0@ not found'.format(module)) + endif diff --git a/patches/spice-gtk-0.36.patch b/patches/spice-gtk-0.36.patch deleted file mode 100644 index 9987f1dc..00000000 --- a/patches/spice-gtk-0.36.patch +++ /dev/null @@ -1,1209 +0,0 @@ -diff -aur a/config.h.in b/config.h.in ---- a/config.h.in 2019-01-16 05:38:41.000000000 -0800 -+++ b/config.h.in 2019-04-15 20:07:05.000000000 -0700 -@@ -61,6 +61,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_INTTYPES_H - -+/* Use libucontext? */ -+#undef HAVE_LIBUCONTEXT -+ - /* Define if libva is available */ - #undef HAVE_LIBVA - -diff -aur a/configure b/configure ---- a/configure 2019-01-16 05:38:40.000000000 -0800 -+++ b/configure 2019-04-15 20:07:05.000000000 -0700 -@@ -727,6 +727,7 @@ - INTROSPECTION_SCANNER - HAVE_INTROSPECTION_FALSE - HAVE_INTROSPECTION_TRUE -+UCONTEXT_LIBS - WITH_GTHREAD_FALSE - WITH_GTHREAD_TRUE - WITH_WINFIBER_FALSE -@@ -17851,6 +17852,97 @@ - - fi - fi -+ -+pkg_failed=no -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cairo >= 1.2.0" >&5 -+$as_echo_n "checking for cairo >= 1.2.0... " >&6; } -+ -+if test -n "$CAIRO_CFLAGS"; then -+ pkg_cv_CAIRO_CFLAGS="$CAIRO_CFLAGS" -+ elif test -n "$PKG_CONFIG"; then -+ if test -n "$PKG_CONFIG" && \ -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cairo >= 1.2.0\""; } >&5 -+ ($PKG_CONFIG --exists --print-errors "cairo >= 1.2.0") 2>&5 -+ ac_status=$? -+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 -+ test $ac_status = 0; }; then -+ pkg_cv_CAIRO_CFLAGS=`$PKG_CONFIG --cflags "cairo >= 1.2.0" 2>/dev/null` -+ test "x$?" != "x0" && pkg_failed=yes -+else -+ pkg_failed=yes -+fi -+ else -+ pkg_failed=untried -+fi -+if test -n "$CAIRO_LIBS"; then -+ pkg_cv_CAIRO_LIBS="$CAIRO_LIBS" -+ elif test -n "$PKG_CONFIG"; then -+ if test -n "$PKG_CONFIG" && \ -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cairo >= 1.2.0\""; } >&5 -+ ($PKG_CONFIG --exists --print-errors "cairo >= 1.2.0") 2>&5 -+ ac_status=$? -+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 -+ test $ac_status = 0; }; then -+ pkg_cv_CAIRO_LIBS=`$PKG_CONFIG --libs "cairo >= 1.2.0" 2>/dev/null` -+ test "x$?" != "x0" && pkg_failed=yes -+else -+ pkg_failed=yes -+fi -+ else -+ pkg_failed=untried -+fi -+ -+ -+ -+if test $pkg_failed = yes; then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+$as_echo "no" >&6; } -+ -+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then -+ _pkg_short_errors_supported=yes -+else -+ _pkg_short_errors_supported=no -+fi -+ if test $_pkg_short_errors_supported = yes; then -+ CAIRO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "cairo >= 1.2.0" 2>&1` -+ else -+ CAIRO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "cairo >= 1.2.0" 2>&1` -+ fi -+ # Put the nasty error message in config.log where it belongs -+ echo "$CAIRO_PKG_ERRORS" >&5 -+ -+ as_fn_error $? "Package requirements (cairo >= 1.2.0) were not met: -+ -+$CAIRO_PKG_ERRORS -+ -+Consider adjusting the PKG_CONFIG_PATH environment variable if you -+installed software in a non-standard prefix. -+ -+Alternatively, you may set the environment variables CAIRO_CFLAGS -+and CAIRO_LIBS to avoid the need to call pkg-config. -+See the pkg-config man page for more details." "$LINENO" 5 -+elif test $pkg_failed = untried; then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -+$as_echo "no" >&6; } -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it -+is in your PATH or set the PKG_CONFIG environment variable to the full -+path to pkg-config. -+ -+Alternatively, you may set the environment variables CAIRO_CFLAGS -+and CAIRO_LIBS to avoid the need to call pkg-config. -+See the pkg-config man page for more details. -+ -+To get pkg-config, see . -+See \`config.log' for more details" "$LINENO" 5; } -+else -+ CAIRO_CFLAGS=$pkg_cv_CAIRO_CFLAGS -+ CAIRO_LIBS=$pkg_cv_CAIRO_LIBS -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -+$as_echo "yes" >&6; } -+ -+fi - GTK_CFLAGS="$GTK_CFLAGS -DGDK_VERSION_MIN_REQUIRED=$GTK_ENCODED_VERSION \ - -DGDK_VERSION_MAX_ALLOWED=$GTK_ENCODED_VERSION" - fi -@@ -18264,98 +18356,6 @@ - - - pkg_failed=no --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CAIRO" >&5 --$as_echo_n "checking for CAIRO... " >&6; } -- --if test -n "$CAIRO_CFLAGS"; then -- pkg_cv_CAIRO_CFLAGS="$CAIRO_CFLAGS" -- elif test -n "$PKG_CONFIG"; then -- if test -n "$PKG_CONFIG" && \ -- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cairo >= 1.2.0\""; } >&5 -- ($PKG_CONFIG --exists --print-errors "cairo >= 1.2.0") 2>&5 -- ac_status=$? -- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 -- test $ac_status = 0; }; then -- pkg_cv_CAIRO_CFLAGS=`$PKG_CONFIG --cflags "cairo >= 1.2.0" 2>/dev/null` -- test "x$?" != "x0" && pkg_failed=yes --else -- pkg_failed=yes --fi -- else -- pkg_failed=untried --fi --if test -n "$CAIRO_LIBS"; then -- pkg_cv_CAIRO_LIBS="$CAIRO_LIBS" -- elif test -n "$PKG_CONFIG"; then -- if test -n "$PKG_CONFIG" && \ -- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"cairo >= 1.2.0\""; } >&5 -- ($PKG_CONFIG --exists --print-errors "cairo >= 1.2.0") 2>&5 -- ac_status=$? -- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 -- test $ac_status = 0; }; then -- pkg_cv_CAIRO_LIBS=`$PKG_CONFIG --libs "cairo >= 1.2.0" 2>/dev/null` -- test "x$?" != "x0" && pkg_failed=yes --else -- pkg_failed=yes --fi -- else -- pkg_failed=untried --fi -- -- -- --if test $pkg_failed = yes; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -- --if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then -- _pkg_short_errors_supported=yes --else -- _pkg_short_errors_supported=no --fi -- if test $_pkg_short_errors_supported = yes; then -- CAIRO_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "cairo >= 1.2.0" 2>&1` -- else -- CAIRO_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "cairo >= 1.2.0" 2>&1` -- fi -- # Put the nasty error message in config.log where it belongs -- echo "$CAIRO_PKG_ERRORS" >&5 -- -- as_fn_error $? "Package requirements (cairo >= 1.2.0) were not met: -- --$CAIRO_PKG_ERRORS -- --Consider adjusting the PKG_CONFIG_PATH environment variable if you --installed software in a non-standard prefix. -- --Alternatively, you may set the environment variables CAIRO_CFLAGS --and CAIRO_LIBS to avoid the need to call pkg-config. --See the pkg-config man page for more details." "$LINENO" 5 --elif test $pkg_failed = untried; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 --$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} --as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it --is in your PATH or set the PKG_CONFIG environment variable to the full --path to pkg-config. -- --Alternatively, you may set the environment variables CAIRO_CFLAGS --and CAIRO_LIBS to avoid the need to call pkg-config. --See the pkg-config man page for more details. -- --To get pkg-config, see . --See \`config.log' for more details" "$LINENO" 5; } --else -- CAIRO_CFLAGS=$pkg_cv_CAIRO_CFLAGS -- CAIRO_LIBS=$pkg_cv_CAIRO_LIBS -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 --$as_echo "yes" >&6; } -- --fi -- -- --pkg_failed=no - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTHREAD" >&5 - $as_echo_n "checking for GTHREAD... " >&6; } - -@@ -20119,6 +20119,50 @@ - fi - - -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libucontext_makecontext in -lucontext" >&5 -+$as_echo_n "checking for libucontext_makecontext in -lucontext... " >&6; } -+if ${ac_cv_lib_ucontext_libucontext_makecontext+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lucontext $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char libucontext_makecontext (); -+int -+main () -+{ -+return libucontext_makecontext (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_ucontext_libucontext_makecontext=yes -+else -+ ac_cv_lib_ucontext_libucontext_makecontext=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ucontext_libucontext_makecontext" >&5 -+$as_echo "$ac_cv_lib_ucontext_libucontext_makecontext" >&6; } -+if test "x$ac_cv_lib_ucontext_libucontext_makecontext" = xyes; then : -+ UCONTEXT_LIBS='-lucontext' -+$as_echo "#define HAVE_LIBUCONTEXT 1" >>confdefs.h -+ -+fi -+ -+ -+ - if test "0" = "1"; then - HAVE_INTROSPECTION_TRUE= - HAVE_INTROSPECTION_FALSE='#' -diff -aur a/src/Makefile.in b/src/Makefile.in ---- a/src/Makefile.in 2019-01-16 05:38:41.000000000 -0800 -+++ b/src/Makefile.in 2019-04-15 20:07:05.000000000 -0700 -@@ -210,8 +210,8 @@ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ -- $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ -- $(am__DEPENDENCIES_1) -+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ -+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) - am__libspice_client_glib_impl_la_SOURCES_DIST = bio-gio.c bio-gio.h \ - spice-audio.c spice-audio-priv.h spice-gstaudio.c \ - spice-gstaudio.h spice-common.h spice-util.c spice-util-priv.h \ -@@ -628,6 +628,7 @@ - SSL_LIBS = @SSL_LIBS@ - STOW = @STOW@ - STRIP = @STRIP@ -+UCONTEXT_LIBS = @UCONTEXT_LIBS@ - USBREDIR_CFLAGS = @USBREDIR_CFLAGS@ - USBREDIR_LIBS = @USBREDIR_LIBS@ - USB_IDS = @USB_IDS@ -@@ -848,7 +849,8 @@ - $(JPEG_LIBS) $(JSON_LIBS) $(Z_LIBS) $(LZ4_LIBS) $(PIXMAN_LIBS) \ - $(SSL_LIBS) $(PULSE_LIBS) $(GSTAUDIO_LIBS) $(GSTVIDEO_LIBS) \ - $(SASL_LIBS) $(SMARTCARD_LIBS) $(USBREDIR_LIBS) $(GUDEV_LIBS) \ -- $(PHODAV_LIBS) $(NULL) $(am__append_10) $(am__append_12) -+ $(PHODAV_LIBS) $(UCONTEXT_LIBS) $(NULL) $(am__append_10) \ -+ $(am__append_12) - @WITH_POLKIT_FALSE@USB_ACL_HELPER_SRCS = - @WITH_POLKIT_TRUE@USB_ACL_HELPER_SRCS = \ - @WITH_POLKIT_TRUE@ usb-acl-helper.c \ -From 42de36de002bbcba7534446445b6a811dc780e50 Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Wed, 24 Apr 2019 18:42:46 -0700 -Subject: [PATCH 1/3] autoconf: removed cairo dependency for glib only builds - ---- - configure.ac | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 2f63422..e835eeb 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -147,7 +147,8 @@ AM_CONDITIONAL([WITH_GTK],[test "$with_gtk" != "no"]) - AS_IF([test "x$with_gtk" != "xno"], - [AS_IF([test "x$os_win32" = "xyes"], - [PKG_CHECK_MODULES(GTK, gtk+-3.0 >= $GTK_REQUIRED)], -- [PKG_CHECK_MODULES(GTK, gtk+-3.0 >= $GTK_REQUIRED epoxy)])] -+ [PKG_CHECK_MODULES(GTK, gtk+-3.0 >= $GTK_REQUIRED epoxy)]) -+ PKG_CHECK_MODULES(CAIRO, cairo >= 1.2.0)] - [GTK_CFLAGS="$GTK_CFLAGS -DGDK_VERSION_MIN_REQUIRED=$GTK_ENCODED_VERSION \ - -DGDK_VERSION_MAX_ALLOWED=$GTK_ENCODED_VERSION"]) - SPICE_GTK_REQUIRES="${SPICE_GTK_REQUIRES} gtk+-3.0 >= $GTK_REQUIRED" -@@ -169,8 +170,6 @@ PKG_CHECK_MODULES(GOBJECT2, gobject-2.0) - - PKG_CHECK_MODULES(GIO, gio-2.0 >= 2.36 $gio_os) - --PKG_CHECK_MODULES(CAIRO, cairo >= 1.2.0) -- - PKG_CHECK_MODULES(GTHREAD, gthread-2.0) - - PKG_CHECK_MODULES(JSON, json-glib-1.0) --- -2.28.0 - -From f5b9472449fca5cba417ea8ada5194e8c28ceedc Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Wed, 24 Apr 2019 18:44:05 -0700 -Subject: [PATCH 2/3] coroutine: added support for libucontext - ---- - configure.ac | 3 +++ - src/Makefile.am | 1 + - src/continuation.h | 9 +++++++++ - 3 files changed, 13 insertions(+) - -diff --git a/configure.ac b/configure.ac -index e835eeb..2c7cf77 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -434,6 +434,9 @@ AM_CONDITIONAL(WITH_WINFIBER, [test "x$WITH_WINFIBER" = "x1"]) - AC_DEFINE_UNQUOTED([WITH_GTHREAD],[$WITH_GTHREAD], [Whether to use gthread coroutine impl]) - AM_CONDITIONAL(WITH_GTHREAD, [test "x$WITH_GTHREAD" = "x1"]) - -+AC_CHECK_LIB(ucontext, libucontext_makecontext, UCONTEXT_LIBS='-lucontext' AC_DEFINE([HAVE_LIBUCONTEXT], 1, [Use libucontext?]), []) -+AC_SUBST(UCONTEXT_LIBS) -+ - AM_CONDITIONAL([HAVE_INTROSPECTION], [test "0" = "1"]) - m4_ifdef([GOBJECT_INTROSPECTION_CHECK],[ - PKG_CHECK_EXISTS([GOBJECT_INTROSPECTION], -diff --git a/src/Makefile.am b/src/Makefile.am -index a9617d4..8f60ea4 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -201,6 +201,7 @@ libspice_client_glib_impl_la_LIBADD = \ - $(USBREDIR_LIBS) \ - $(GUDEV_LIBS) \ - $(PHODAV_LIBS) \ -+ $(UCONTEXT_LIBS) \ - $(NULL) - - if WITH_POLKIT -diff --git a/src/continuation.h b/src/continuation.h -index d1fd137..e75c479 100644 ---- a/src/continuation.h -+++ b/src/continuation.h -@@ -23,7 +23,16 @@ - - #include "spice-common.h" - #include -+#ifdef HAVE_LIBUCONTEXT -+#include -+#define ucontext_t libucontext_ucontext_t -+#define getcontext libucontext_getcontext -+#define setcontext libucontext_setcontext -+#define swapcontext libucontext_swapcontext -+#define makecontext libucontext_makecontext -+#else - #include -+#endif - #include - - struct continuation --- -2.28.0 - -From 607a4d1bbc9965e7a055bdeb6238592339ef51ac Mon Sep 17 00:00:00 2001 -From: osy <50960678+osy@users.noreply.github.com> -Date: Wed, 24 Apr 2019 18:45:38 -0700 -Subject: [PATCH 3/3] spice-glib: removed usage of default GMainContext - -Libraries should not use the default glib main context because it might be owned by another thread. -See: https://developer.gnome.org/programming-guidelines/stable/main-contexts.html.en#using-gmaincontext-in-a-library ---- - src/channel-display-gst.c | 10 +-- - src/channel-display-mjpeg.c | 6 +- - src/channel-display.c | 6 +- - src/channel-main.c | 30 ++++---- - src/channel-usbredir.c | 2 +- - src/channel-webdav.c | 6 +- - src/gio-coroutine.c | 13 ++-- - src/map-file | 1 + - src/smartcard-manager.c | 5 +- - src/spice-channel.c | 14 ++-- - src/spice-glib-sym-file | 1 + - src/spice-gstaudio.c | 6 +- - src/spice-session.c | 8 +-- - src/spice-util-priv.h | 8 +++ - src/spice-util.c | 139 ++++++++++++++++++++++++++++++++++++ - src/spice-util.h | 1 + - src/spice-widget.c | 8 +-- - src/usb-acl-helper.c | 2 +- - src/usb-device-manager.c | 3 +- - src/vmcstream.c | 2 +- - 20 files changed, 212 insertions(+), 59 deletions(-) - -diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c -index 0b871a7..7d40349 100644 ---- a/src/channel-display-gst.c -+++ b/src/channel-display-gst.c -@@ -183,13 +183,13 @@ static void schedule_frame(SpiceGstDecoder *decoder) - } - - if (spice_mmtime_diff(now, gstframe->frame->mm_time) < 0) { -- decoder->timer_id = g_timeout_add(gstframe->frame->mm_time - now, -- display_frame, decoder); -+ decoder->timer_id = g_spice_timeout_add(gstframe->frame->mm_time - now, -+ display_frame, decoder); - } else if (decoder->display_frame && !decoder->pending_samples) { - /* Still attempt to display the least out of date frame so the - * video is not completely frozen for an extended period of time. - */ -- decoder->timer_id = g_timeout_add(0, display_frame, decoder); -+ decoder->timer_id = g_spice_timeout_add(0, display_frame, decoder); - } else { - SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping", - __FUNCTION__, now - gstframe->frame->mm_time, -@@ -515,7 +515,7 @@ static void spice_gst_decoder_reschedule(VideoDecoder *video_decoder) - g_mutex_unlock(&decoder->queues_mutex); - - if (timer_id != 0) { -- g_source_remove(timer_id); -+ g_spice_source_remove(timer_id); - } - schedule_frame(decoder); - } -@@ -535,7 +535,7 @@ static void spice_gst_decoder_destroy(VideoDecoder *video_decoder) - * scheduled display_frame() call and drop the queued frames. - */ - if (decoder->timer_id) { -- g_source_remove(decoder->timer_id); -+ g_spice_source_remove(decoder->timer_id); - } - g_mutex_clear(&decoder->queues_mutex); - g_queue_free_full(decoder->decoding_queue, (GDestroyNotify)free_gst_frame); -diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c -index e79fd86..18ace75 100644 ---- a/src/channel-display-mjpeg.c -+++ b/src/channel-display-mjpeg.c -@@ -194,7 +194,7 @@ static void mjpeg_decoder_schedule(MJpegDecoder *decoder) - if (spice_mmtime_diff(time, frame->mm_time) <= 0) { - guint32 d = frame->mm_time - time; - decoder->cur_frame = frame; -- decoder->timer_id = g_timeout_add(d, mjpeg_decoder_decode_frame, decoder); -+ decoder->timer_id = g_spice_timeout_add(d, mjpeg_decoder_decode_frame, decoder); - break; - } - -@@ -218,7 +218,7 @@ static void _msg_in_unref_func(gpointer data, gpointer user_data) - static void mjpeg_decoder_drop_queue(MJpegDecoder *decoder) - { - if (decoder->timer_id != 0) { -- g_source_remove(decoder->timer_id); -+ g_spice_source_remove(decoder->timer_id); - decoder->timer_id = 0; - } - if (decoder->cur_frame) { -@@ -270,7 +270,7 @@ static void mjpeg_decoder_reschedule(VideoDecoder *video_decoder) - - SPICE_DEBUG("%s", __FUNCTION__); - if (decoder->timer_id != 0) { -- g_source_remove(decoder->timer_id); -+ g_spice_source_remove(decoder->timer_id); - decoder->timer_id = 0; - } - mjpeg_decoder_schedule(decoder); -diff --git a/src/channel-display.c b/src/channel-display.c -index ae949eb..db94d1d 100644 ---- a/src/channel-display.c -+++ b/src/channel-display.c -@@ -147,7 +147,7 @@ static void spice_display_channel_dispose(GObject *object) - SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(object)->priv; - - if (c->mark_false_event_id != 0) { -- g_source_remove(c->mark_false_event_id); -+ g_spice_source_remove(c->mark_false_event_id); - c->mark_false_event_id = 0; - } - -@@ -1900,7 +1900,7 @@ static void display_handle_surface_create(SpiceChannel *channel, SpiceMsgIn *in) - surface->primary = true; - create_canvas(channel, surface); - if (c->mark_false_event_id != 0) { -- g_source_remove(c->mark_false_event_id); -+ g_spice_source_remove(c->mark_false_event_id); - c->mark_false_event_id = FALSE; - } - } else { -@@ -1941,7 +1941,7 @@ static void display_handle_surface_destroy(SpiceChannel *channel, SpiceMsgIn *in - CHANNEL_DEBUG(channel, "%d: FIXME primary destroy, but is display really disabled?", id); - /* this is done with a timeout in spicec as well, it's *ugly* */ - if (id != 0 && c->mark_false_event_id == 0) { -- c->mark_false_event_id = g_timeout_add_seconds(1, display_mark_false, channel); -+ c->mark_false_event_id = g_spice_timeout_add_seconds(1, display_mark_false, channel); - } - c->primary = NULL; - g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0); -diff --git a/src/channel-main.c b/src/channel-main.c -index f8be9ff..9b77c20 100644 ---- a/src/channel-main.c -+++ b/src/channel-main.c -@@ -357,17 +357,17 @@ static void spice_main_channel_dispose(GObject *obj) - SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv; - - if (c->timer_id) { -- g_source_remove(c->timer_id); -+ g_spice_source_remove(c->timer_id); - c->timer_id = 0; - } - - if (c->switch_host_delayed_id) { -- g_source_remove(c->switch_host_delayed_id); -+ g_spice_source_remove(c->switch_host_delayed_id); - c->switch_host_delayed_id = 0; - } - - if (c->migrate_delayed_id) { -- g_source_remove(c->migrate_delayed_id); -+ g_spice_source_remove(c->migrate_delayed_id); - c->migrate_delayed_id = 0; - } - -@@ -1157,7 +1157,7 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel) - - spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE); - if (c->timer_id != 0) { -- g_source_remove(c->timer_id); -+ g_spice_source_remove(c->timer_id); - c->timer_id = 0; - } - -@@ -1529,16 +1529,16 @@ static void update_display_timer(SpiceMainChannel *channel, guint seconds) - SpiceMainChannelPrivate *c = channel->priv; - - if (c->timer_id) -- g_source_remove(c->timer_id); -+ g_spice_source_remove(c->timer_id); - - if (seconds != 0) { -- c->timer_id = g_timeout_add_seconds(seconds, timer_set_display, channel); -+ c->timer_id = g_spice_timeout_add_seconds(seconds, timer_set_display, channel); - } else { - /* We need to special case 0, as we want the callback to fire as soon - * as possible. g_timeout_add_seconds(0) would set up a timer which would fire - * at the next second boundary, which might be nearly 1 full second later. - */ -- c->timer_id = g_timeout_add(0, timer_set_display, channel); -+ c->timer_id = g_spice_timeout_add(0, timer_set_display, channel); - } - - } -@@ -1759,7 +1759,7 @@ static void main_handle_channels_list(SpiceChannel *channel, SpiceMsgIn *in) - /* no need to explicitely switch to main context, since - synchronous call is not needed. */ - /* no need to track idle, session is refed */ -- g_idle_add((GSourceFunc)_channel_new, c); -+ g_spice_idle_add((GSourceFunc)_channel_new, c); - } - } - -@@ -2187,7 +2187,7 @@ static void spice_main_channel_send_migration_handshake(SpiceChannel *channel) - - if (!spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEAMLESS_MIGRATE)) { - c->migrate_data->do_seamless = false; -- g_idle_add(main_migrate_handshake_done, c->migrate_data); -+ g_spice_idle_add(main_migrate_handshake_done, c->migrate_data); - } else { - SpiceMsgcMainMigrateDstDoSeamless msg_data; - SpiceMsgOut *msg_out; -@@ -2373,7 +2373,7 @@ static void main_migrate_connect(SpiceChannel *channel, - main_priv->migrate_data = &mig; - - /* no need to track idle, call is sync for this coroutine */ -- g_idle_add(migrate_connect, &mig); -+ g_spice_idle_add(migrate_connect, &mig); - - /* switch to main loop and wait for connections */ - coroutine_yield(NULL); -@@ -2422,7 +2422,7 @@ static void main_handle_migrate_dst_seamless_ack(SpiceChannel *channel, SpiceMsg - - g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE); - main_priv->migrate_data->do_seamless = true; -- g_idle_add(main_migrate_handshake_done, main_priv->migrate_data); -+ g_spice_idle_add(main_migrate_handshake_done, main_priv->migrate_data); - } - - static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMsgIn *in) -@@ -2432,7 +2432,7 @@ static void main_handle_migrate_dst_seamless_nack(SpiceChannel *channel, SpiceMs - - g_return_if_fail(c->state == SPICE_CHANNEL_STATE_MIGRATION_HANDSHAKE); - main_priv->migrate_data->do_seamless = false; -- g_idle_add(main_migrate_handshake_done, main_priv->migrate_data); -+ g_spice_idle_add(main_migrate_handshake_done, main_priv->migrate_data); - } - - /* main context */ -@@ -2459,7 +2459,7 @@ static void main_handle_migrate_end(SpiceChannel *channel, SpiceMsgIn *in) - g_return_if_fail(c->migrate_delayed_id == 0); - g_return_if_fail(spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)); - -- c->migrate_delayed_id = g_idle_add(migrate_delayed, channel); -+ c->migrate_delayed_id = g_spice_idle_add(migrate_delayed, channel); - } - - /* main context */ -@@ -2501,7 +2501,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i - - if (c->switch_host_delayed_id != 0) { - g_warning("Switching host already in progress, aborting it"); -- g_warn_if_fail(g_source_remove(c->switch_host_delayed_id)); -+ g_warn_if_fail(g_spice_source_remove(c->switch_host_delayed_id)); - c->switch_host_delayed_id = 0; - } - -@@ -2514,7 +2514,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i - spice_session_set_port(session, mig->port, FALSE); - spice_session_set_port(session, mig->sport, TRUE); - -- c->switch_host_delayed_id = g_idle_add(switch_host_delayed, channel); -+ c->switch_host_delayed_id = g_spice_idle_add(switch_host_delayed, channel); - } - - /* coroutine context */ -diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c -index 182edc4..adc3944 100644 ---- a/src/channel-usbredir.c -+++ b/src/channel-usbredir.c -@@ -942,7 +942,7 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in) - err_data.spice_device = g_boxed_copy(spice_usb_device_get_type(), spice_device); - err_data.error = err; - spice_usbredir_channel_unlock(channel); -- g_idle_add(device_error, &err_data); -+ g_spice_idle_add(device_error, &err_data); - coroutine_yield(NULL); - - g_boxed_free(spice_usb_device_get_type(), err_data.spice_device); -diff --git a/src/channel-webdav.c b/src/channel-webdav.c -index 8e4db1a..82a3ebb 100644 ---- a/src/channel-webdav.c -+++ b/src/channel-webdav.c -@@ -98,7 +98,7 @@ static void output_queue_free(OutputQueue *queue) - g_queue_free_full(queue->queue, g_free); - g_clear_object(&queue->output); - if (queue->idle_id) -- g_source_remove(queue->idle_id); -+ g_spice_source_remove(queue->idle_id); - g_free(queue); - } - -@@ -121,7 +121,7 @@ static void output_queue_flush_cb(GObject *source_object, - g_clear_error(&error); - - if (!q->idle_id) -- q->idle_id = g_idle_add(output_queue_idle, q); -+ q->idle_id = g_spice_idle_add(output_queue_idle, q); - - g_free(e); - } -@@ -176,7 +176,7 @@ static void output_queue_push(OutputQueue *q, const guint8 *buf, gsize size, - g_queue_push_tail(q->queue, e); - - if (!q->idle_id && !q->flushing) -- q->idle_id = g_idle_add(output_queue_idle, q); -+ q->idle_id = g_spice_idle_add(output_queue_idle, q); - } - - typedef struct Client -diff --git a/src/gio-coroutine.c b/src/gio-coroutine.c -index 59ae06c..9f4e3be 100644 ---- a/src/gio-coroutine.c -+++ b/src/gio-coroutine.c -@@ -21,6 +21,7 @@ - #include "config.h" - - #include "gio-coroutine.h" -+#include "spice-util-priv.h" - - typedef struct _GConditionWaitSource - { -@@ -57,14 +58,14 @@ GIOCondition g_coroutine_socket_wait(GCoroutine *self, - - src = g_socket_create_source(sock, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, NULL); - g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, self, NULL); -- self->wait_id = g_source_attach(src, NULL); -+ self->wait_id = g_source_attach(src, spice_main_context()); - ret = coroutine_yield(NULL); - g_source_unref(src); - - if (ret != NULL) - val = *ret; - else -- g_source_remove(self->wait_id); -+ g_spice_source_remove(self->wait_id); - - self->wait_id = 0; - return val; -@@ -77,7 +78,7 @@ void g_coroutine_condition_cancel(GCoroutine *coroutine) - if (coroutine->condition_id == 0) - return; - -- g_source_remove(coroutine->condition_id); -+ g_spice_source_remove(coroutine->condition_id); - coroutine->condition_id = 0; - } - -@@ -167,7 +168,7 @@ gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, g - vsrc->func = func; - vsrc->data = data; - -- self->condition_id = g_source_attach(src, NULL); -+ self->condition_id = g_source_attach(src, spice_main_context()); - g_source_set_callback(src, g_condition_wait_helper, self, NULL); - coroutine_yield(NULL); - g_source_unref(src); -@@ -221,7 +222,7 @@ g_coroutine_signal_emit(gpointer instance, guint signal_id, - g_signal_emit_valist(instance, signal_id, detail, data.var_args); - } else { - g_object_ref(instance); -- g_idle_add(emit_main_context, &data); -+ g_spice_idle_add(emit_main_context, &data); - coroutine_yield(NULL); - g_warn_if_fail(data.notified); - g_object_unref(instance); -@@ -258,7 +259,7 @@ void g_coroutine_object_notify(GObject *object, - data.propname = (gpointer)property_name; - data.notified = FALSE; - -- g_idle_add(notify_main_context, &data); -+ g_spice_idle_add(notify_main_context, &data); - - /* This switches to the system coroutine context, lets - * the idle function run to dispatch the signal, and -diff --git a/src/map-file b/src/map-file -index 500683c..e063f0e 100644 ---- a/src/map-file -+++ b/src/map-file -@@ -187,6 +187,7 @@ spice_util_get_version_string; - spice_util_set_debug; - spice_uuid_to_string; - spice_webdav_channel_get_type; -+spice_util_set_main_context; - local: - *; - }; -diff --git a/src/smartcard-manager.c b/src/smartcard-manager.c -index ceecfdc..be437dd 100644 ---- a/src/smartcard-manager.c -+++ b/src/smartcard-manager.c -@@ -28,6 +28,7 @@ - #include "smartcard-manager.h" - #include "smartcard-manager-priv.h" - #include "spice-marshal.h" -+#include "spice-util-priv.h" - - /** - * SECTION:smartcard-manager -@@ -110,7 +111,7 @@ static void spice_smartcard_manager_finalize(GObject *gobject) - SpiceSmartcardManagerPrivate *priv = manager->priv; - - if (priv->monitor_id != 0) { -- g_source_remove(priv->monitor_id); -+ g_spice_source_remove(priv->monitor_id); - priv->monitor_id = 0; - } - -@@ -363,7 +364,7 @@ static guint smartcard_monitor_add(SmartcardSourceFunc callback, - - source = smartcard_monitor_source_new(); - g_source_set_callback(source, (GSourceFunc)callback, user_data, NULL); -- id = g_source_attach(source, NULL); -+ id = g_source_attach(source, spice_main_context()); - g_source_unref(source); - - return id; -diff --git a/src/spice-channel.c b/src/spice-channel.c -index 61de177..c2926bb 100644 ---- a/src/spice-channel.c -+++ b/src/spice-channel.c -@@ -743,9 +743,9 @@ void spice_msg_out_send(SpiceMsgOut *out) - if (was_empty && !c->xmit_queue_wakeup_id) { - c->xmit_queue_wakeup_id = - /* Use g_timeout_add_full so that can specify the priority */ -- g_timeout_add_full(G_PRIORITY_HIGH, 0, -- spice_channel_idle_wakeup, -- out->channel, NULL); -+ g_spice_timeout_add_full(G_PRIORITY_HIGH, 0, -+ spice_channel_idle_wakeup, -+ out->channel, NULL); - } - - end: -@@ -2692,7 +2692,7 @@ cleanup: - c->event = SPICE_CHANNEL_ERROR_CONNECT; - } - -- g_idle_add(spice_channel_delayed_unref, channel); -+ g_spice_idle_add(spice_channel_delayed_unref, channel); - /* Co-routine exits now - the SpiceChannel object may no longer exist, - so don't do anything else now unless you like SEGVs */ - return NULL; -@@ -2752,7 +2752,7 @@ static gboolean channel_connect(SpiceChannel *channel, gboolean tls) - g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */ - - /* we connect in idle, to let previous coroutine exit, if present */ -- c->connect_delayed_id = g_idle_add(connect_delayed, channel); -+ c->connect_delayed_id = g_spice_idle_add(connect_delayed, channel); - - return true; - } -@@ -2818,7 +2818,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating) - - CHANNEL_DEBUG(channel, "channel reset"); - if (c->connect_delayed_id) { -- g_source_remove(c->connect_delayed_id); -+ g_spice_source_remove(c->connect_delayed_id); - c->connect_delayed_id = 0; - } - -@@ -2850,7 +2850,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating) - g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL); - g_queue_clear(&c->xmit_queue); - if (c->xmit_queue_wakeup_id) { -- g_source_remove(c->xmit_queue_wakeup_id); -+ g_spice_source_remove(c->xmit_queue_wakeup_id); - c->xmit_queue_wakeup_id = 0; - } - g_mutex_unlock(&c->xmit_queue_lock); -diff --git a/src/spice-glib-sym-file b/src/spice-glib-sym-file -index 2df1cc0..1f7f25d 100644 ---- a/src/spice-glib-sym-file -+++ b/src/spice-glib-sym-file -@@ -164,3 +164,4 @@ spice_util_get_version_string - spice_util_set_debug - spice_uuid_to_string - spice_webdav_channel_get_type -+spice_util_set_main_context -diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c -index 98c1f4f..d68057f 100644 ---- a/src/spice-gstaudio.c -+++ b/src/spice-gstaudio.c -@@ -25,7 +25,7 @@ - #include "spice-gstaudio.h" - #include "spice-common.h" - #include "spice-session.h" --#include "spice-util.h" -+#include "spice-util-priv.h" - - struct stream { - GstElement *pipe; -@@ -243,7 +243,7 @@ static void playback_stop(SpiceGstaudio *gstaudio) - if (p->playback.pipe) - gst_element_set_state(p->playback.pipe, GST_STATE_READY); - if (p->mmtime_id != 0) { -- g_source_remove(p->mmtime_id); -+ g_spice_source_remove(p->mmtime_id); - p->mmtime_id = 0; - } - } -@@ -320,7 +320,7 @@ cleanup: - - if (!p->playback.fake && p->mmtime_id == 0) { - update_mmtime_timeout_cb(gstaudio); -- p->mmtime_id = g_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio); -+ p->mmtime_id = g_spice_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio); - } - } - -diff --git a/src/spice-session.c b/src/spice-session.c -index 5609c9b..c4d9703 100644 ---- a/src/spice-session.c -+++ b/src/spice-session.c -@@ -1828,7 +1828,7 @@ end: - - s->migrate_wait_init = FALSE; - if (s->after_main_init) { -- g_source_remove(s->after_main_init); -+ g_spice_source_remove(s->after_main_init); - s->after_main_init = 0; - } - -@@ -1903,7 +1903,7 @@ gboolean spice_session_migrate_after_main_init(SpiceSession *self) - g_return_val_if_fail(s->after_main_init == 0, FALSE); - - s->migrate_wait_init = FALSE; -- s->after_main_init = g_idle_add(after_main_init, self); -+ s->after_main_init = g_spice_idle_add(after_main_init, self); - - return TRUE; - } -@@ -1996,7 +1996,7 @@ void spice_session_disconnect(SpiceSession *session) - return; - - g_object_ref(session); -- s->disconnecting = g_idle_add((GSourceFunc)session_disconnect_idle, session); -+ s->disconnecting = g_spice_idle_add((GSourceFunc)session_disconnect_idle, session); - } - - /** -@@ -2238,7 +2238,7 @@ GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceC - g_socket_client_set_enable_proxy(open_host.client, s->proxy != NULL); - g_socket_client_set_timeout(open_host.client, SOCKET_TIMEOUT); - -- g_idle_add(open_host_idle_cb, &open_host); -+ g_spice_idle_add(open_host_idle_cb, &open_host); - /* switch to main loop and wait for connection */ - coroutine_yield(NULL); - -diff --git a/src/spice-util-priv.h b/src/spice-util-priv.h -index 38b0deb..8a24742 100644 ---- a/src/spice-util-priv.h -+++ b/src/spice-util-priv.h -@@ -32,6 +32,14 @@ gchar* spice_unix2dos(const gchar *str, gssize len); - gchar* spice_dos2unix(const gchar *str, gssize len); - void spice_mono_edge_highlight(unsigned width, unsigned hight, - const guint8 *and, const guint8 *xor, guint8 *dest); -+GMainContext *spice_main_context(void); -+guint g_spice_timeout_add (guint interval, GSourceFunc function, gpointer data); -+guint g_spice_timeout_add_seconds (guint interval, GSourceFunc function, gpointer data); -+guint g_spice_timeout_add_full (gint priority, guint interval, GSourceFunc function, -+ gpointer data, GDestroyNotify notify); -+guint g_spice_idle_add (GSourceFunc function, gpointer data); -+guint g_spice_child_watch_add (GPid pid, GChildWatchFunc function, gpointer data); -+gboolean g_spice_source_remove (guint tag); - - G_END_DECLS - -diff --git a/src/spice-util.c b/src/spice-util.c -index f5a35ed..950be6b 100644 ---- a/src/spice-util.c -+++ b/src/spice-util.c -@@ -476,3 +476,142 @@ void spice_mono_edge_highlight(unsigned width, unsigned height, - xor += bpl; - } - } -+ -+static GMainContext *spice_context = NULL; -+ -+/** -+ * spice_util_set_main_context: -+ * @context: Main context for spice-gtk -+ * -+ * Main context for events and sources. -+ **/ -+void spice_util_set_main_context(GMainContext *context) -+{ -+ spice_context = context; -+} -+ -+G_GNUC_INTERNAL -+GMainContext *spice_main_context(void) -+{ -+ return spice_context; -+} -+ -+G_GNUC_INTERNAL -+guint -+g_spice_timeout_add (guint interval, -+ GSourceFunc function, -+ gpointer data) -+{ -+ return g_spice_timeout_add_full (G_PRIORITY_DEFAULT, -+ interval, function, data, NULL); -+} -+ -+G_GNUC_INTERNAL -+guint -+g_spice_timeout_add_seconds (guint interval, -+ GSourceFunc function, -+ gpointer data) -+{ -+ GSource *source = NULL; -+ GMainContext *context; -+ guint id; -+ -+ g_return_val_if_fail (function != NULL, 0); -+ -+ context = spice_main_context(); -+ -+ source = g_timeout_source_new_seconds (interval); -+ g_source_set_callback (source, function, data, NULL); -+ id = g_source_attach (source, context); -+ g_source_unref (source); -+ -+ return id; -+} -+ -+G_GNUC_INTERNAL -+guint -+g_spice_timeout_add_full (gint priority, -+ guint interval, -+ GSourceFunc function, -+ gpointer data, -+ GDestroyNotify notify) -+{ -+ GSource *source; -+ GMainContext *context; -+ guint id; -+ -+ g_return_val_if_fail (function != NULL, 0); -+ -+ context = spice_main_context(); -+ source = g_timeout_source_new (interval); -+ -+ if (priority != G_PRIORITY_DEFAULT) -+ g_source_set_priority (source, priority); -+ -+ g_source_set_callback (source, function, data, notify); -+ id = g_source_attach (source, context); -+ -+ g_source_unref (source); -+ -+ return id; -+} -+ -+G_GNUC_INTERNAL -+guint -+g_spice_idle_add (GSourceFunc function, -+ gpointer data) -+{ -+ GSource *source = NULL; -+ GMainContext *context; -+ guint id; -+ -+ g_return_val_if_fail (function != NULL, 0); -+ -+ context = spice_main_context(); -+ -+ source = g_idle_source_new (); -+ g_source_set_callback (source, function, data, NULL); -+ id = g_source_attach (source, context); -+ g_source_unref (source); -+ -+ return id; -+} -+ -+G_GNUC_INTERNAL -+guint -+g_spice_child_watch_add (GPid pid, -+ GChildWatchFunc function, -+ gpointer data) -+{ -+ GSource *source = NULL; -+ GMainContext *context; -+ guint id; -+ -+ g_return_val_if_fail (function != NULL, 0); -+ -+ context = spice_main_context(); -+ -+ source = g_child_watch_source_new (pid); -+ g_source_set_callback (source, (GSourceFunc) function, data, NULL); -+ id = g_source_attach (source, context); -+ g_source_unref (source); -+ -+ return id; -+} -+ -+G_GNUC_INTERNAL -+gboolean -+g_spice_source_remove (guint tag) -+{ -+ GSource *source; -+ -+ g_return_val_if_fail (tag > 0, FALSE); -+ -+ source = g_main_context_find_source_by_id (spice_main_context(), tag); -+ if (source) -+ g_source_destroy (source); -+ else -+ g_critical ("Source ID %u was not found when attempting to remove it", tag); -+ -+ return source != NULL; -+} -diff --git a/src/spice-util.h b/src/spice-util.h -index 1d80f1c..65cadb1 100644 ---- a/src/spice-util.h -+++ b/src/spice-util.h -@@ -31,6 +31,7 @@ gulong spice_g_signal_connect_object(gpointer instance, - gpointer gobject, - GConnectFlags connect_flags); - gchar* spice_uuid_to_string(const guint8 uuid[16]); -+void spice_util_set_main_context(GMainContext *context); - - #define SPICE_DEBUG(fmt, ...) \ - do { \ -diff --git a/src/spice-widget.c b/src/spice-widget.c -index 8adcc38..202d6cd 100644 ---- a/src/spice-widget.c -+++ b/src/spice-widget.c -@@ -446,7 +446,7 @@ static void spice_display_dispose(GObject *obj) - d->gtk_session = NULL; - - if (d->key_delayed_id) { -- g_source_remove(d->key_delayed_id); -+ g_spice_source_remove(d->key_delayed_id); - d->key_delayed_id = 0; - } - -@@ -1351,7 +1351,7 @@ static void key_press_and_release(SpiceDisplay *display) - d->key_delayed_scancode = 0; - - if (d->key_delayed_id) { -- g_source_remove(d->key_delayed_id); -+ g_spice_source_remove(d->key_delayed_id); - d->key_delayed_id = 0; - } - } -@@ -1368,7 +1368,7 @@ static gboolean key_press_delayed(gpointer data) - d->key_delayed_scancode = 0; - - if (d->key_delayed_id) { -- g_source_remove(d->key_delayed_id); -+ g_spice_source_remove(d->key_delayed_id); - d->key_delayed_id = 0; - } - -@@ -1421,7 +1421,7 @@ static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboo - d->keypress_delay != 0 && - !(d->key_state[i] & m)) { - g_warn_if_fail(d->key_delayed_id == 0); -- d->key_delayed_id = g_timeout_add(d->keypress_delay, key_press_delayed, display); -+ d->key_delayed_id = g_spice_timeout_add(d->keypress_delay, key_press_delayed, display); - d->key_delayed_scancode = scancode; - } else - spice_inputs_channel_key_press(d->inputs, scancode); -diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c -index 186b86e..ab788ac 100644 ---- a/src/usb-acl-helper.c -+++ b/src/usb-acl-helper.c -@@ -209,7 +209,7 @@ void spice_usb_acl_helper_open_acl_async(SpiceUsbAclHelper *self, - g_task_return_error(task, err); - goto done; - } -- g_child_watch_add(helper_pid, helper_child_watch_cb, NULL); -+ g_spice_child_watch_add(helper_pid, helper_child_watch_cb, NULL); - - priv->in_ch = g_io_channel_unix_new(in); - g_io_channel_set_close_on_unref(priv->in_ch, TRUE); -diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c -index 55b672b..4e1ea87 100644 ---- a/src/usb-device-manager.c -+++ b/src/usb-device-manager.c -@@ -45,6 +45,7 @@ - #include "spice-client.h" - #include "spice-marshal.h" - #include "usb-device-manager-priv.h" -+#include "spice-util-priv.h" - - #include - -@@ -1142,7 +1143,7 @@ static int spice_usb_device_manager_hotplug_cb(libusb_context *ctx, - args->self = g_object_ref(self); - args->device = libusb_ref_device(device); - args->event = event; -- g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args); -+ g_spice_idle_add(spice_usb_device_manager_hotplug_idle_cb, args); - return 0; - } - #endif // USE_USBREDIR -diff --git a/src/vmcstream.c b/src/vmcstream.c -index 0634bce..1891806 100644 ---- a/src/vmcstream.c -+++ b/src/vmcstream.c -@@ -163,7 +163,7 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, - cb_data = g_new(complete_in_idle_cb_data , 1); - cb_data->task = g_object_ref(self->task); - cb_data->pos = self->pos; -- g_idle_add(complete_in_idle_cb, cb_data); -+ g_spice_idle_add(complete_in_idle_cb, cb_data); - - g_clear_object(&self->task); - } --- -2.28.0 - diff --git a/patches/spice-gtk-0.40.patch b/patches/spice-gtk-0.40.patch new file mode 100644 index 00000000..50960388 --- /dev/null +++ b/patches/spice-gtk-0.40.patch @@ -0,0 +1,1141 @@ +From 2f16f6d4b0d6dde0d1d518f61c01f5f972caa008 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 13:15:16 -0800 +Subject: [PATCH 1/5] meson: move cairo dependency to GTK build only + +Cairo is only used in SpiceDisplay which is part of the GTK client. If +we are building the GLib only client, it should be optional. +--- + meson.build | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/meson.build b/meson.build +index 11173fd..ecc9d6d 100644 +--- a/meson.build ++++ b/meson.build +@@ -107,8 +107,8 @@ foreach dep, version : deps + endforeach + + # mandatory dependencies, without specific version requirement +-# TODO: specify minimum version for cairo, jpeg and zlib? +-deps = ['cairo', 'libjpeg', 'zlib', 'json-glib-1.0'] ++# TODO: specify minimum version for jpeg and zlib? ++deps = ['libjpeg', 'zlib', 'json-glib-1.0'] + if host_machine.system() == 'windows' + deps += 'gio-windows-2.0' + else +@@ -149,6 +149,8 @@ d = dependency('gtk+-3.0', version : '>= @0@'.format(gtk_version_required), + summary_info += {'gtk': d.found()} + if d.found() + spice_gtk_deps += d ++ # TODO: specify minimum version for cairo? ++ spice_gtk_deps += dependency('cairo') + if host_machine.system() != 'windows' + spice_gtk_deps += dependency('epoxy') + spice_gtk_deps += dependency('x11') +-- +2.32.0 (Apple Git-132) + +From 312a1fc6cf4a8d839639dce411107537e1791045 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 15:52:48 -0800 +Subject: [PATCH 2/5] coroutine: add support for libucontext + +libucontext is a lightweight implementation of ucontext for platforms +that do not have a built-in implementation. This allows us to use the +same code to support libucontext as ucontext. +--- + meson.build | 7 +++++++ + meson_options.txt | 2 +- + src/continuation.c | 12 +++++++++++- + src/meson.build | 2 +- + 4 files changed, 20 insertions(+), 3 deletions(-) + +diff --git a/meson.build b/meson.build +index ecc9d6d..29615b1 100644 +--- a/meson.build ++++ b/meson.build +@@ -319,6 +319,13 @@ if spice_gtk_coroutine == 'ucontext' + endif + endif + ++if spice_gtk_coroutine == 'libucontext' ++ d = dependency('libucontext') ++ spice_glib_deps += d ++ spice_gtk_config_data.set('WITH_UCONTEXT', '1') ++ spice_gtk_config_data.set('HAVE_LIBUCONTEXT', '1') ++endif ++ + if spice_gtk_coroutine == 'gthread' + spice_gtk_config_data.set('WITH_GTHREAD', '1') + endif +diff --git a/meson_options.txt b/meson_options.txt +index 3cbc7c6..5acfc9a 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -45,7 +45,7 @@ option('usb-ids-path', + option('coroutine', + type : 'combo', + value : 'auto', +- choices : ['auto', 'ucontext', 'gthread', 'winfiber'], ++ choices : ['auto', 'ucontext', 'libucontext', 'gthread', 'winfiber'], + description : 'Use ucontext or GThread for coroutines') + + option('introspection', +diff --git a/src/continuation.c b/src/continuation.c +index 65527ac..400169a 100644 +--- a/src/continuation.c ++++ b/src/continuation.c +@@ -25,11 +25,21 @@ + #endif + + #include +-#include + #include + + #include "continuation.h" + ++#ifdef HAVE_LIBUCONTEXT ++#include ++#define ucontext_t libucontext_ucontext_t ++#define getcontext libucontext_getcontext ++#define setcontext libucontext_setcontext ++#define swapcontext libucontext_swapcontext ++#define makecontext libucontext_makecontext ++#else ++#include ++#endif ++ + /* + * va_args to makecontext() must be type 'int', so passing + * the pointer we need may require several int args. This +diff --git a/src/meson.build b/src/meson.build +index a9dfc57..961779f 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -146,7 +146,7 @@ endif + + if spice_gtk_coroutine == 'gthread' + spice_client_glib_sources += 'coroutine_gthread.c' +-elif spice_gtk_coroutine == 'ucontext' ++elif spice_gtk_coroutine in ['ucontext', 'libucontext'] + spice_client_glib_sources += ['continuation.c', + 'continuation.h', + 'coroutine_ucontext.c'] +-- +2.32.0 (Apple Git-132) + +From fb47817a4963a6e64d76bccb562cf5dbe2f628c1 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 16:35:26 -0800 +Subject: [PATCH 3/5] spice-util: support for non-default GMainContext + +When spice-gtk is used in an application with its own GMainContext, the +wrong context will be used leading to various issues. + +https://developer-old.gnome.org/programming-guidelines/stable/main-contexts.html.en + +We add a new API spice_util_set_main_context() which allows the caller +to pass in the main context for a main loop that the caller controls and +is responsible for. +--- + doc/reference/spice-gtk-sections.txt | 2 + + src/map-file | 1 + + src/spice-glib-sym-file | 1 + + src/spice-util-priv.h | 8 ++ + src/spice-util.c | 160 +++++++++++++++++++++++++++ + src/spice-util.h | 1 + + 6 files changed, 173 insertions(+) + +diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt +index 5cd6686..2163de2 100644 +--- a/doc/reference/spice-gtk-sections.txt ++++ b/doc/reference/spice-gtk-sections.txt +@@ -458,11 +458,13 @@ SpiceUsbDeviceWidgetPrivate + spice_util_set_debug + spice_util_get_version_string + spice_uuid_to_string ++spice_util_set_main_context + + SPICE_DEBUG + spice_util_get_debug + SPICE_RESERVED_PADDING + spice_g_signal_connect_object ++spice_main_context + + +
+diff --git a/src/map-file b/src/map-file +index c0d8ca6..e5f75f1 100644 +--- a/src/map-file ++++ b/src/map-file +@@ -191,6 +191,7 @@ spice_usbredir_channel_get_type; + spice_util_get_debug; + spice_util_get_version_string; + spice_util_set_debug; ++spice_util_set_main_context; + spice_uuid_to_string; + spice_webdav_channel_get_type; + local: +diff --git a/src/spice-glib-sym-file b/src/spice-glib-sym-file +index ccaad1a..acb5961 100644 +--- a/src/spice-glib-sym-file ++++ b/src/spice-glib-sym-file +@@ -165,5 +165,6 @@ spice_usbredir_channel_get_type + spice_util_get_debug + spice_util_get_version_string + spice_util_set_debug ++spice_util_set_main_context + spice_uuid_to_string + spice_webdav_channel_get_type +diff --git a/src/spice-util-priv.h b/src/spice-util-priv.h +index 98389f7..e156469 100644 +--- a/src/spice-util-priv.h ++++ b/src/spice-util-priv.h +@@ -30,5 +30,13 @@ gchar* spice_unix2dos(const gchar *str, gssize len); + gchar* spice_dos2unix(const gchar *str, gssize len); + void spice_mono_edge_highlight(unsigned width, unsigned hight, + const guint8 *and, const guint8 *xor, guint8 *dest); ++GMainContext *spice_main_context(void); ++guint g_spice_timeout_add(guint interval, GSourceFunc function, gpointer data); ++guint g_spice_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data); ++guint g_spice_timeout_add_full(gint priority, guint interval, GSourceFunc function, ++ gpointer data, GDestroyNotify notify); ++guint g_spice_idle_add(GSourceFunc function, gpointer data); ++guint g_spice_child_watch_add(GPid pid, GChildWatchFunc function, gpointer data); ++gboolean g_spice_source_remove(guint tag); + + G_END_DECLS +diff --git a/src/spice-util.c b/src/spice-util.c +index 30d83c8..fc238ae 100644 +--- a/src/spice-util.c ++++ b/src/spice-util.c +@@ -475,3 +475,163 @@ void spice_mono_edge_highlight(unsigned width, unsigned height, + xor += bpl; + } + } ++ ++static GMainContext *spice_context = NULL; ++ ++/** ++ * spice_util_set_main_context: ++ * @context: Main context for SPICE ++ * ++ * Main context for events and sources. This must be called first if the ++ * application uses multiple GLib based libraries. In that case, the ++ * caller is responsible for setting up a separate main context and main loop ++ * for SPICE. The context will be retained. To prevent memory leaks, ++ * spice_util_set_main_context(NULL) should be called when finished which sets ++ * the main context back to the default. ++ * ++ * Since: 0.41 ++ **/ ++void spice_util_set_main_context(GMainContext *context) ++{ ++ if (spice_context) { ++ g_main_context_unref(spice_context); ++ } ++ spice_context = context; ++ if (spice_context) { ++ g_main_context_ref(spice_context); ++ } ++} ++ ++/** ++ * spice_main_context: ++ * ++ * Returns: either the main context set by spice_util_set_main_context() or ++ * NULL indicating the default main context. ++ * ++ * Since: 0.41 ++ **/ ++G_GNUC_INTERNAL ++GMainContext *spice_main_context(void) ++{ ++ return spice_context; ++} ++ ++G_GNUC_INTERNAL ++guint ++g_spice_timeout_add(guint interval, ++ GSourceFunc function, ++ gpointer data) ++{ ++ return g_spice_timeout_add_full(G_PRIORITY_DEFAULT, ++ interval, function, data, NULL); ++} ++ ++G_GNUC_INTERNAL ++guint ++g_spice_timeout_add_seconds(guint interval, ++ GSourceFunc function, ++ gpointer data) ++{ ++ GSource *source = NULL; ++ GMainContext *context; ++ guint id; ++ ++ g_return_val_if_fail(function != NULL, 0); ++ ++ context = spice_main_context(); ++ ++ source = g_timeout_source_new_seconds(interval); ++ g_source_set_callback(source, function, data, NULL); ++ id = g_source_attach(source, context); ++ g_source_unref(source); ++ ++ return id; ++} ++ ++G_GNUC_INTERNAL ++guint ++g_spice_timeout_add_full (gint priority, ++ guint interval, ++ GSourceFunc function, ++ gpointer data, ++ GDestroyNotify notify) ++{ ++ GSource *source; ++ GMainContext *context; ++ guint id; ++ ++ g_return_val_if_fail(function != NULL, 0); ++ ++ context = spice_main_context(); ++ source = g_timeout_source_new(interval); ++ ++ if (priority != G_PRIORITY_DEFAULT) ++ g_source_set_priority(source, priority); ++ ++ g_source_set_callback(source, function, data, notify); ++ id = g_source_attach(source, context); ++ ++ g_source_unref(source); ++ ++ return id; ++} ++ ++G_GNUC_INTERNAL ++guint ++g_spice_idle_add(GSourceFunc function, ++ gpointer data) ++{ ++ GSource *source = NULL; ++ GMainContext *context; ++ guint id; ++ ++ g_return_val_if_fail(function != NULL, 0); ++ ++ context = spice_main_context(); ++ ++ source = g_idle_source_new(); ++ g_source_set_callback(source, function, data, NULL); ++ id = g_source_attach(source, context); ++ g_source_unref(source); ++ ++ return id; ++} ++ ++G_GNUC_INTERNAL ++guint ++g_spice_child_watch_add(GPid pid, ++ GChildWatchFunc function, ++ gpointer data) ++{ ++ GSource *source = NULL; ++ GMainContext *context; ++ guint id; ++ ++ g_return_val_if_fail(function != NULL, 0); ++ ++ context = spice_main_context(); ++ ++ source = g_child_watch_source_new(pid); ++ g_source_set_callback(source, (GSourceFunc) function, data, NULL); ++ id = g_source_attach(source, context); ++ g_source_unref(source); ++ ++ return id; ++} ++ ++G_GNUC_INTERNAL ++gboolean ++g_spice_source_remove(guint tag) ++{ ++ GSource *source; ++ ++ g_return_val_if_fail(tag > 0, FALSE); ++ ++ source = g_main_context_find_source_by_id(spice_main_context(), tag); ++ if (source) ++ g_source_destroy(source); ++ else ++ g_critical("Source ID %u was not found when attempting to remove it", tag); ++ ++ return source != NULL; ++} +diff --git a/src/spice-util.h b/src/spice-util.h +index 421b4b0..e161c83 100644 +--- a/src/spice-util.h ++++ b/src/spice-util.h +@@ -30,6 +30,7 @@ gulong spice_g_signal_connect_object(gpointer instance, + gpointer gobject, + GConnectFlags connect_flags); + gchar* spice_uuid_to_string(const guint8 uuid[16]); ++void spice_util_set_main_context(GMainContext *context); + + #define SPICE_DEBUG(fmt, ...) \ + do { \ +-- +2.32.0 (Apple Git-132) + +From a02df4084ff43c5796f1ead29ab9d67da48dff1e Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 16:44:20 -0800 +Subject: [PATCH 4/5] spice-gtk: user specified GMainContext for events + +Following the previous commit, this replaces all GLib calls that +implicitly uses the default main context with versions that can use the +main context set by spice_util_set_main_context(). +--- + src/channel-display-gst.c | 10 +++++----- + src/channel-display-mjpeg.c | 6 +++--- + src/channel-display.c | 6 +++--- + src/channel-main.c | 22 +++++++++++----------- + src/channel-usbredir.c | 2 +- + src/channel-webdav.c | 6 +++--- + src/gio-coroutine.c | 13 +++++++------ + src/smartcard-manager.c | 5 +++-- + src/spice-channel.c | 14 +++++++------- + src/spice-gstaudio.c | 10 +++++----- + src/spice-gtk-session.c | 8 ++++---- + src/spice-session.c | 8 ++++---- + src/spice-widget.c | 9 +++++---- + src/usb-acl-helper.c | 3 ++- + src/usb-device-manager.c | 3 ++- + src/vmcstream.c | 2 +- + 16 files changed, 66 insertions(+), 61 deletions(-) + +diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c +index 36db3a3..800c41a 100644 +--- a/src/channel-display-gst.c ++++ b/src/channel-display-gst.c +@@ -297,13 +297,13 @@ static void schedule_frame(SpiceGstDecoder *decoder) + } + + if (spice_mmtime_diff(gstframe->encoded_frame->mm_time, now) >= 0) { +- decoder->timer_id = g_timeout_add(gstframe->encoded_frame->mm_time - now, +- display_frame, decoder); ++ decoder->timer_id = g_spice_timeout_add(gstframe->encoded_frame->mm_time - now, ++ display_frame, decoder); + } else if (decoder->display_frame && !decoder->pending_samples) { + /* Still attempt to display the least out of date frame so the + * video is not completely frozen for an extended period of time. + */ +- decoder->timer_id = g_timeout_add(0, display_frame, decoder); ++ decoder->timer_id = g_spice_timeout_add(0, display_frame, decoder); + } else { + SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping", + __FUNCTION__, now - gstframe->encoded_frame->mm_time, +@@ -605,7 +605,7 @@ static void spice_gst_decoder_reschedule(VideoDecoder *video_decoder) + g_mutex_unlock(&decoder->queues_mutex); + + if (timer_id != 0) { +- g_source_remove(timer_id); ++ g_spice_source_remove(timer_id); + } + schedule_frame(decoder); + } +@@ -625,7 +625,7 @@ static void spice_gst_decoder_destroy(VideoDecoder *video_decoder) + * scheduled display_frame() call and drop the queued frames. + */ + if (decoder->timer_id) { +- g_source_remove(decoder->timer_id); ++ g_spice_source_remove(decoder->timer_id); + } + g_mutex_clear(&decoder->queues_mutex); + g_queue_free_full(decoder->decoding_queue, (GDestroyNotify)free_gst_frame); +diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c +index 558d9f8..e63eb18 100644 +--- a/src/channel-display-mjpeg.c ++++ b/src/channel-display-mjpeg.c +@@ -183,7 +183,7 @@ static void mjpeg_decoder_schedule(MJpegDecoder *decoder) + if (spice_mmtime_diff(time, frame->mm_time) <= 0) { + guint32 d = frame->mm_time - time; + decoder->cur_frame = frame; +- decoder->timer_id = g_timeout_add(d, mjpeg_decoder_decode_frame, decoder); ++ decoder->timer_id = g_spice_timeout_add(d, mjpeg_decoder_decode_frame, decoder); + break; + } + +@@ -207,7 +207,7 @@ static void spice_frame_unref_func(gpointer data, gpointer user_data) + static void mjpeg_decoder_drop_queue(MJpegDecoder *decoder) + { + if (decoder->timer_id != 0) { +- g_source_remove(decoder->timer_id); ++ g_spice_source_remove(decoder->timer_id); + decoder->timer_id = 0; + } + g_clear_pointer(&decoder->cur_frame, spice_frame_free); +@@ -255,7 +255,7 @@ static void mjpeg_decoder_reschedule(VideoDecoder *video_decoder) + + SPICE_DEBUG("%s", __FUNCTION__); + if (decoder->timer_id != 0) { +- g_source_remove(decoder->timer_id); ++ g_spice_source_remove(decoder->timer_id); + decoder->timer_id = 0; + } + mjpeg_decoder_schedule(decoder); +diff --git a/src/channel-display.c b/src/channel-display.c +index e47fc3f..a9b604f 100644 +--- a/src/channel-display.c ++++ b/src/channel-display.c +@@ -147,7 +147,7 @@ static void spice_display_channel_dispose(GObject *object) + SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(object)->priv; + + if (c->mark_false_event_id != 0) { +- g_source_remove(c->mark_false_event_id); ++ g_spice_source_remove(c->mark_false_event_id); + c->mark_false_event_id = 0; + } + +@@ -1970,7 +1970,7 @@ static void display_handle_surface_create(SpiceChannel *channel, SpiceMsgIn *in) + surface->primary = true; + create_canvas(channel, surface); + if (c->mark_false_event_id != 0) { +- g_source_remove(c->mark_false_event_id); ++ g_spice_source_remove(c->mark_false_event_id); + c->mark_false_event_id = 0; + } + } else { +@@ -2011,7 +2011,7 @@ static void display_handle_surface_destroy(SpiceChannel *channel, SpiceMsgIn *in + CHANNEL_DEBUG(channel, "%d: FIXME primary destroy, but is display really disabled?", id); + /* this is done with a timeout in spicec as well, it's *ugly* */ + if (id != 0 && c->mark_false_event_id == 0) { +- c->mark_false_event_id = g_timeout_add_seconds(1, display_mark_false, channel); ++ c->mark_false_event_id = g_spice_timeout_add_seconds(1, display_mark_false, channel); + } + c->primary = NULL; + g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0); +diff --git a/src/channel-main.c b/src/channel-main.c +index f502ca3..7830f6f 100644 +--- a/src/channel-main.c ++++ b/src/channel-main.c +@@ -361,17 +361,17 @@ static void spice_main_channel_dispose(GObject *obj) + SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv; + + if (c->timer_id) { +- g_source_remove(c->timer_id); ++ g_spice_source_remove(c->timer_id); + c->timer_id = 0; + } + + if (c->switch_host_delayed_id) { +- g_source_remove(c->switch_host_delayed_id); ++ g_spice_source_remove(c->switch_host_delayed_id); + c->switch_host_delayed_id = 0; + } + + if (c->migrate_delayed_id) { +- g_source_remove(c->migrate_delayed_id); ++ g_spice_source_remove(c->migrate_delayed_id); + c->migrate_delayed_id = 0; + } + +@@ -1188,7 +1188,7 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel) + + spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE); + if (c->timer_id != 0) { +- g_source_remove(c->timer_id); ++ g_spice_source_remove(c->timer_id); + c->timer_id = 0; + } + +@@ -1568,16 +1568,16 @@ static void update_display_timer(SpiceMainChannel *channel, guint seconds) + SpiceMainChannelPrivate *c = channel->priv; + + if (c->timer_id) +- g_source_remove(c->timer_id); ++ g_spice_source_remove(c->timer_id); + + if (seconds != 0) { +- c->timer_id = g_timeout_add_seconds(seconds, timer_set_display, channel); ++ c->timer_id = g_spice_timeout_add_seconds(seconds, timer_set_display, channel); + } else { + /* We need to special case 0, as we want the callback to fire as soon + * as possible. g_timeout_add_seconds(0) would set up a timer which would fire + * at the next second boundary, which might be nearly 1 full second later. + */ +- c->timer_id = g_timeout_add(0, timer_set_display, channel); ++ c->timer_id = g_spice_timeout_add(0, timer_set_display, channel); + } + + } +@@ -1798,7 +1798,7 @@ static void main_handle_channels_list(SpiceChannel *channel, SpiceMsgIn *in) + /* no need to explicitly switch to main context, since + synchronous call is not needed. */ + /* no need to track idle, session is refed */ +- g_idle_add((GSourceFunc)_channel_new, c); ++ g_spice_idle_add((GSourceFunc)_channel_new, c); + } + } + +@@ -2578,7 +2578,7 @@ static void main_handle_migrate_end(SpiceChannel *channel, SpiceMsgIn *in) + g_return_if_fail(c->migrate_delayed_id == 0); + g_return_if_fail(spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE)); + +- c->migrate_delayed_id = g_idle_add(migrate_delayed, channel); ++ c->migrate_delayed_id = g_spice_idle_add(migrate_delayed, channel); + } + + /* main context */ +@@ -2622,7 +2622,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i + + if (c->switch_host_delayed_id != 0) { + g_warning("Switching host already in progress, aborting it"); +- g_warn_if_fail(g_source_remove(c->switch_host_delayed_id)); ++ g_warn_if_fail(g_spice_source_remove(c->switch_host_delayed_id)); + c->switch_host_delayed_id = 0; + } + +@@ -2635,7 +2635,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i + spice_session_set_port(session, mig->port, FALSE); + spice_session_set_port(session, mig->sport, TRUE); + +- c->switch_host_delayed_id = g_idle_add(switch_host_delayed, channel); ++ c->switch_host_delayed_id = g_spice_idle_add(switch_host_delayed, channel); + } + + /* coroutine context */ +diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c +index b81d666..0aa6fff 100644 +--- a/src/channel-usbredir.c ++++ b/src/channel-usbredir.c +@@ -709,7 +709,7 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in) + err_data.device = spice_usb_backend_device_ref(device); + err_data.error = err; + spice_usbredir_channel_unlock(channel); +- g_idle_add(device_error, &err_data); ++ g_spice_idle_add(device_error, &err_data); + coroutine_yield(NULL); + + spice_usb_backend_device_unref(err_data.device); +diff --git a/src/channel-webdav.c b/src/channel-webdav.c +index 7de5495..5f3af1c 100644 +--- a/src/channel-webdav.c ++++ b/src/channel-webdav.c +@@ -97,7 +97,7 @@ static void output_queue_free(OutputQueue *queue) + g_queue_free_full(queue->queue, g_free); + g_clear_object(&queue->output); + if (queue->idle_id) +- g_source_remove(queue->idle_id); ++ g_spice_source_remove(queue->idle_id); + g_free(queue); + } + +@@ -120,7 +120,7 @@ static void output_queue_flush_cb(GObject *source_object, + g_clear_error(&error); + + if (!q->idle_id) +- q->idle_id = g_idle_add(output_queue_idle, q); ++ q->idle_id = g_spice_idle_add(output_queue_idle, q); + + g_free(e); + } +@@ -175,7 +175,7 @@ static void output_queue_push(OutputQueue *q, const guint8 *buf, gsize size, + g_queue_push_tail(q->queue, e); + + if (!q->idle_id && !q->flushing) +- q->idle_id = g_idle_add(output_queue_idle, q); ++ q->idle_id = g_spice_idle_add(output_queue_idle, q); + } + #endif + +diff --git a/src/gio-coroutine.c b/src/gio-coroutine.c +index e8fe029..61a6cef 100644 +--- a/src/gio-coroutine.c ++++ b/src/gio-coroutine.c +@@ -20,6 +20,7 @@ + #include "config.h" + + #include "gio-coroutine.h" ++#include "spice-util-priv.h" + + typedef struct _GConditionWaitSource + { +@@ -56,14 +57,14 @@ GIOCondition g_coroutine_socket_wait(GCoroutine *self, + + src = g_socket_create_source(sock, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, NULL); + g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, self, NULL); +- self->wait_id = g_source_attach(src, NULL); ++ self->wait_id = g_source_attach(src, spice_main_context()); + ret = coroutine_yield(NULL); + g_source_unref(src); + + if (ret != NULL) + val = *ret; + else +- g_source_remove(self->wait_id); ++ g_spice_source_remove(self->wait_id); + + self->wait_id = 0; + return val; +@@ -76,7 +77,7 @@ void g_coroutine_condition_cancel(GCoroutine *coroutine) + if (coroutine->condition_id == 0) + return; + +- g_source_remove(coroutine->condition_id); ++ g_spice_source_remove(coroutine->condition_id); + coroutine->condition_id = 0; + } + +@@ -166,7 +167,7 @@ gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, g + vsrc->func = func; + vsrc->data = data; + +- self->condition_id = g_source_attach(src, NULL); ++ self->condition_id = g_source_attach(src, spice_main_context()); + g_source_set_callback(src, g_condition_wait_helper, self, NULL); + coroutine_yield(NULL); + g_source_unref(src); +@@ -220,7 +221,7 @@ g_coroutine_signal_emit(gpointer instance, guint signal_id, + g_signal_emit_valist(instance, signal_id, detail, data.var_args); + } else { + g_object_ref(instance); +- g_idle_add(emit_main_context, &data); ++ g_spice_idle_add(emit_main_context, &data); + coroutine_yield(NULL); + g_warn_if_fail(data.notified); + g_object_unref(instance); +@@ -257,7 +258,7 @@ void g_coroutine_object_notify(GObject *object, + data.propname = (gpointer)property_name; + data.notified = FALSE; + +- g_idle_add(notify_main_context, &data); ++ g_spice_idle_add(notify_main_context, &data); + + /* This switches to the system coroutine context, lets + * the idle function run to dispatch the signal, and +diff --git a/src/smartcard-manager.c b/src/smartcard-manager.c +index bb97ad7..8cc2dd1 100644 +--- a/src/smartcard-manager.c ++++ b/src/smartcard-manager.c +@@ -27,6 +27,7 @@ + #include "smartcard-manager.h" + #include "smartcard-manager-priv.h" + #include "spice-marshal.h" ++#include "spice-util-priv.h" + + /** + * SECTION:smartcard-manager +@@ -111,7 +112,7 @@ static void spice_smartcard_manager_finalize(GObject *gobject) + SpiceSmartcardManagerPrivate *priv = manager->priv; + + if (priv->monitor_id != 0) { +- g_source_remove(priv->monitor_id); ++ g_spice_source_remove(priv->monitor_id); + priv->monitor_id = 0; + } + +@@ -364,7 +365,7 @@ static guint smartcard_monitor_add(SmartcardSourceFunc callback, + + source = smartcard_monitor_source_new(); + g_source_set_callback(source, (GSourceFunc)callback, user_data, NULL); +- id = g_source_attach(source, NULL); ++ id = g_source_attach(source, spice_main_context()); + g_source_unref(source); + + return id; +diff --git a/src/spice-channel.c b/src/spice-channel.c +index d6199a5..d5070a9 100644 +--- a/src/spice-channel.c ++++ b/src/spice-channel.c +@@ -744,9 +744,9 @@ void spice_msg_out_send(SpiceMsgOut *out) + if (was_empty && !c->xmit_queue_wakeup_id) { + c->xmit_queue_wakeup_id = + /* Use g_timeout_add_full so that can specify the priority */ +- g_timeout_add_full(G_PRIORITY_HIGH, 0, +- spice_channel_idle_wakeup, +- out->channel, NULL); ++ g_spice_timeout_add_full(G_PRIORITY_HIGH, 0, ++ spice_channel_idle_wakeup, ++ out->channel, NULL); + } + + end: +@@ -2703,7 +2703,7 @@ cleanup: + c->event = SPICE_CHANNEL_ERROR_CONNECT; + } + +- g_idle_add(spice_channel_delayed_unref, channel); ++ g_spice_idle_add(spice_channel_delayed_unref, channel); + /* Co-routine exits now - the SpiceChannel object may no longer exist, + so don't do anything else now unless you like SEGVs */ + return NULL; +@@ -2762,7 +2762,7 @@ static gboolean channel_connect(SpiceChannel *channel, gboolean tls) + g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */ + + /* we connect in idle, to let previous coroutine exit, if present */ +- c->connect_delayed_id = g_idle_add(connect_delayed, channel); ++ c->connect_delayed_id = g_spice_idle_add(connect_delayed, channel); + + return true; + } +@@ -2828,7 +2828,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating) + + CHANNEL_DEBUG(channel, "channel reset"); + if (c->connect_delayed_id) { +- g_source_remove(c->connect_delayed_id); ++ g_spice_source_remove(c->connect_delayed_id); + c->connect_delayed_id = 0; + } + +@@ -2860,7 +2860,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating) + g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL); + g_queue_clear(&c->xmit_queue); + if (c->xmit_queue_wakeup_id) { +- g_source_remove(c->xmit_queue_wakeup_id); ++ g_spice_source_remove(c->xmit_queue_wakeup_id); + c->xmit_queue_wakeup_id = 0; + } + g_mutex_unlock(&c->xmit_queue_lock); +diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c +index d67727f..b6fc4eb 100644 +--- a/src/spice-gstaudio.c ++++ b/src/spice-gstaudio.c +@@ -24,7 +24,7 @@ + #include "spice-gstaudio.h" + #include "spice-common.h" + #include "spice-session.h" +-#include "spice-util.h" ++#include "spice-util-priv.h" + + struct stream { + GstElement *pipe; +@@ -79,7 +79,7 @@ static void spice_gstaudio_dispose(GObject *obj) + + stream_dispose(&p->playback); + if (p->rbus_watch_id > 0) { +- g_source_remove(p->rbus_watch_id); ++ g_spice_source_remove(p->rbus_watch_id); + p->rbus_watch_id = 0; + } + stream_dispose(&p->record); +@@ -197,7 +197,7 @@ static void record_start(SpiceRecordChannel *channel, gint format, gint channels + p->record.channels != channels)) { + gst_element_set_state(p->record.pipe, GST_STATE_NULL); + if (p->rbus_watch_id > 0) { +- g_source_remove(p->rbus_watch_id); ++ g_spice_source_remove(p->rbus_watch_id); + p->rbus_watch_id = 0; + } + g_clear_pointer(&p->record.pipe, gst_object_unref); +@@ -251,7 +251,7 @@ static void playback_stop(SpiceGstaudio *gstaudio) + if (p->playback.pipe) + gst_element_set_state(p->playback.pipe, GST_STATE_READY); + if (p->mmtime_id != 0) { +- g_source_remove(p->mmtime_id); ++ g_spice_source_remove(p->mmtime_id); + p->mmtime_id = 0; + } + } +@@ -328,7 +328,7 @@ cleanup: + + if (!p->playback.fake && p->mmtime_id == 0) { + update_mmtime_timeout_cb(gstaudio); +- p->mmtime_id = g_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio); ++ p->mmtime_id = g_spice_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio); + } + } + +diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c +index 72b0168..6ec3a16 100644 +--- a/src/spice-gtk-session.c ++++ b/src/spice-gtk-session.c +@@ -285,7 +285,7 @@ static void clipboard_release_delay_remove(SpiceGtkSession *self, guint selectio + clipboard_release(self, selection); + } + +- g_source_remove(s->clipboard_release_delay[selection]); ++ g_spice_source_remove(s->clipboard_release_delay[selection]); + s->clipboard_release_delay[selection] = 0; + } + +@@ -865,7 +865,7 @@ static void clipboard_get(GtkClipboard *clipboard, + + ri.selection_data = selection_data; + ri.info = info; +- ri.loop = g_main_loop_new(NULL, FALSE); ++ ri.loop = g_main_loop_new(spice_main_context(), FALSE); + ri.selection = selection; + ri.self = self; + +@@ -1548,8 +1548,8 @@ static void clipboard_release_delay(SpiceMainChannel *main, guint selection, + rel->self = self; + rel->selection = selection; + s->clipboard_release_delay[selection] = +- g_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY, +- clipboard_release_timeout, rel, g_free); ++ g_spice_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY, ++ clipboard_release_timeout, rel, g_free); + + } + +diff --git a/src/spice-session.c b/src/spice-session.c +index bb3c6cd..9d161ee 100644 +--- a/src/spice-session.c ++++ b/src/spice-session.c +@@ -1861,7 +1861,7 @@ end: + + s->migrate_wait_init = FALSE; + if (s->after_main_init) { +- g_source_remove(s->after_main_init); ++ g_spice_source_remove(s->after_main_init); + s->after_main_init = 0; + } + +@@ -1936,7 +1936,7 @@ gboolean spice_session_migrate_after_main_init(SpiceSession *self) + g_return_val_if_fail(s->after_main_init == 0, FALSE); + + s->migrate_wait_init = FALSE; +- s->after_main_init = g_idle_add(after_main_init, self); ++ s->after_main_init = g_spice_idle_add(after_main_init, self); + + return TRUE; + } +@@ -2029,7 +2029,7 @@ void spice_session_disconnect(SpiceSession *session) + return; + + g_object_ref(session); +- s->disconnecting = g_idle_add((GSourceFunc)session_disconnect_idle, session); ++ s->disconnecting = g_spice_idle_add((GSourceFunc)session_disconnect_idle, session); + } + + /** +@@ -2271,7 +2271,7 @@ GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceC + g_socket_client_set_enable_proxy(open_host.client, s->proxy != NULL); + g_socket_client_set_timeout(open_host.client, SOCKET_TIMEOUT); + +- g_idle_add(open_host_idle_cb, &open_host); ++ g_spice_idle_add(open_host_idle_cb, &open_host); + /* switch to main loop and wait for connection */ + coroutine_yield(NULL); + +diff --git a/src/spice-widget.c b/src/spice-widget.c +index 5f7c061..3e3fe05 100644 +--- a/src/spice-widget.c ++++ b/src/spice-widget.c +@@ -55,6 +55,7 @@ + #include "spice-gtk-session-priv.h" + #include "vncdisplaykeymap.h" + #include "spice-grabsequence-priv.h" ++#include "spice-util-priv.h" + + + /** +@@ -465,7 +466,7 @@ static void spice_display_dispose(GObject *obj) + d->gtk_session = NULL; + + if (d->key_delayed_id) { +- g_source_remove(d->key_delayed_id); ++ g_spice_source_remove(d->key_delayed_id); + d->key_delayed_id = 0; + } + +@@ -1530,7 +1531,7 @@ static void key_press_and_release(SpiceDisplay *display) + d->key_delayed_scancode = 0; + + if (d->key_delayed_id) { +- g_source_remove(d->key_delayed_id); ++ g_spice_source_remove(d->key_delayed_id); + d->key_delayed_id = 0; + } + } +@@ -1547,7 +1548,7 @@ static gboolean key_press_delayed(gpointer data) + d->key_delayed_scancode = 0; + + if (d->key_delayed_id) { +- g_source_remove(d->key_delayed_id); ++ g_spice_source_remove(d->key_delayed_id); + d->key_delayed_id = 0; + } + +@@ -1600,7 +1601,7 @@ static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboo + d->keypress_delay != 0 && + !(d->key_state[i] & m)) { + g_warn_if_fail(d->key_delayed_id == 0); +- d->key_delayed_id = g_timeout_add(d->keypress_delay, key_press_delayed, display); ++ d->key_delayed_id = g_spice_timeout_add(d->keypress_delay, key_press_delayed, display); + d->key_delayed_scancode = scancode; + } else + spice_inputs_channel_key_press(d->inputs, scancode); +diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c +index 0edad2a..88b4295 100644 +--- a/src/usb-acl-helper.c ++++ b/src/usb-acl-helper.c +@@ -25,6 +25,7 @@ + #include + + #include "usb-acl-helper.h" ++#include "spice-util-priv.h" + + struct _SpiceUsbAclHelperPrivate { + GTask *task; +@@ -208,7 +209,7 @@ void spice_usb_acl_helper_open_acl_async(SpiceUsbAclHelper *self, + g_task_return_error(task, err); + goto done; + } +- g_child_watch_add(helper_pid, helper_child_watch_cb, NULL); ++ g_spice_child_watch_add(helper_pid, helper_child_watch_cb, NULL); + + priv->in_ch = g_io_channel_unix_new(in); + g_io_channel_set_close_on_unref(priv->in_ch, TRUE); +diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c +index 24b6727..c7e1431 100644 +--- a/src/usb-device-manager.c ++++ b/src/usb-device-manager.c +@@ -38,6 +38,7 @@ + #include "spice-client.h" + #include "spice-marshal.h" + #include "usb-device-manager-priv.h" ++#include "spice-util-priv.h" + + #include + +@@ -865,7 +866,7 @@ static void spice_usb_device_manager_hotplug_cb(void *user_data, + args->manager = g_object_ref(manager); + args->device = spice_usb_backend_device_ref(dev); + args->added = added; +- g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args); ++ g_spice_idle_add(spice_usb_device_manager_hotplug_idle_cb, args); + } + + static void spice_usb_device_manager_channel_connect_cb(GObject *gobject, +diff --git a/src/vmcstream.c b/src/vmcstream.c +index e26b939..6054f3e 100644 +--- a/src/vmcstream.c ++++ b/src/vmcstream.c +@@ -161,7 +161,7 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream *self, + cb_data = g_new(complete_in_idle_cb_data , 1); + cb_data->task = g_object_ref(self->task); + cb_data->pos = self->pos; +- g_idle_add(complete_in_idle_cb, cb_data); ++ g_spice_idle_add(complete_in_idle_cb, cb_data); + + g_clear_object(&self->task); + } +-- +2.32.0 (Apple Git-132) + +From d43ef94e21f4ea5d4c34684dd4af06ee52ddbc74 Mon Sep 17 00:00:00 2001 +From: osy +Date: Fri, 4 Mar 2022 21:23:51 -0800 +Subject: [PATCH 5/5] usb-device-cd: option to disable CD emulation + +On iOS, there is no "sys/disk.h" header and cannot build the CD +emulation code. This should not prevent the rest of USB redirection from +working. +--- + meson.build | 10 ++++++++++ + meson_options.txt | 4 ++++ + src/meson.build | 7 ++++++- + src/usb-device-manager.c | 2 +- + tests/meson.build | 2 +- + 5 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/meson.build b/meson.build +index 29615b1..457aec8 100644 +--- a/meson.build ++++ b/meson.build +@@ -217,6 +217,7 @@ summary_info += {'builtin-mjpeg': get_option('builtin-mjpeg')} + + # usbredir + spice_gtk_has_usbredir = false ++spice_gtk_has_usb_cd = get_option('usb-cd').enabled() + usbredir_version = '0.7.1' + usbredir_version_info = '>= @0@'.format(usbredir_version) + d1 = dependency('libusbredirparser-0.5', version: usbredir_version_info, required : get_option('usbredir')) +@@ -228,11 +229,20 @@ if d1.found() and d2.found() and d3.found() + spice_glib_deps += [d1, d2, d3] + spice_gtk_config_data.set('USE_USBREDIR', '1') + spice_gtk_has_usbredir = true ++ spice_gtk_has_usb_cd = get_option('usb-cd').allowed() ++ if spice_gtk_has_usb_cd ++ spice_gtk_config_data.set('USE_USB_CD', '1') ++ endif + else + warning('USB redirection disabled on big endian machine as ' + + 'usbredir only support little endian') + endif + endif ++summary_info += {'usb-cd': spice_gtk_has_usb_cd} ++ ++if spice_gtk_has_usb_cd and not spice_gtk_has_usbredir ++ error('USB CD cannot be enabled without USB redirection support!') ++endif + + d = dependency('libcap-ng', required : get_option('libcap-ng')) + summary_info += {'libcap-ng': d.found()} +diff --git a/meson_options.txt b/meson_options.txt +index 5acfc9a..0849a84 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -19,6 +19,10 @@ option('usbredir', + type : 'feature', + description : 'Enable usbredir support') + ++option('usb-cd', ++ type : 'feature', ++ description : 'Enable usb-cd emulation') ++ + option('libcap-ng', + type : 'feature', + description: 'Enable libcap-ng support for the USB acl helper') +diff --git a/src/meson.build b/src/meson.build +index 961779f..0b32124 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -159,8 +159,13 @@ if spice_gtk_has_usbredir + 'usbutil.c', + 'usbutil.h', + 'usb-backend.c', +- 'usb-emulation.h', + 'usb-backend.h', ++ ] ++endif ++ ++if spice_gtk_has_usb_cd ++ spice_client_glib_sources += [ ++ 'usb-emulation.h', + 'usb-device-cd.c', + 'usb-device-cd.h', + 'cd-scsi.c', +diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c +index c7e1431..8029892 100644 +--- a/src/usb-device-manager.c ++++ b/src/usb-device-manager.c +@@ -1479,7 +1479,7 @@ spice_usb_device_manager_create_shared_cd_device(SpiceUsbDeviceManager *manager, + gchar *filename, + GError **err) + { +-#ifdef USE_USBREDIR ++#if defined(USE_USBREDIR) && defined(USE_USB_CD) + SpiceUsbDeviceManagerPrivate *priv = manager->priv; + + CdEmulationParams cd_params = { +diff --git a/tests/meson.build b/tests/meson.build +index 8dccb42..9248aea 100644 +--- a/tests/meson.build ++++ b/tests/meson.build +@@ -10,7 +10,7 @@ if spice_gtk_has_phodav + tests_sources += 'pipe.c' + endif + +-if spice_gtk_has_usbredir ++if spice_gtk_has_usb_cd + tests_sources += 'cd-emu.c' + endif + +-- +2.32.0 (Apple Git-132) + diff --git a/scripts/build_dependencies.sh b/scripts/build_dependencies.sh index 92d6ded3..c069fb44 100755 --- a/scripts/build_dependencies.sh +++ b/scripts/build_dependencies.sh @@ -442,8 +442,11 @@ build_qemu_dependencies () { build $PIXMAN_SRC build_openssl $OPENSSL_SRC build $OPUS_SRC - build $SPICE_PROTOCOL_SRC - build $SPICE_SERVER_SRC + meson_build $GST_SRC -Dtests=disabled -Ddefault_library=both -Dregistry=false + meson_build $GST_BASE_SRC -Dtests=disabled -Ddefault_library=both + meson_build $GST_GOOD_SRC -Dtests=disabled -Ddefault_library=both + meson_build $SPICE_PROTOCOL_SRC + meson_build $SPICE_SERVER_SRC -Dlz4=false -Dsasl=false # USB support if [ -z "$SKIP_USB_BUILD" ]; then build $USB_SRC @@ -470,13 +473,10 @@ build_qemu () { build_spice_client () { meson_build "$QEMU_DIR/subprojects/libucontext" -Ddefault_library=static -Dfreestanding=true build $JSON_GLIB_SRC - meson_build $GST_SRC -Dtests=disabled -Ddefault_library=both -Dregistry=false - meson_build $GST_BASE_SRC -Dtests=disabled -Ddefault_library=both - meson_build $GST_GOOD_SRC -Dtests=disabled -Ddefault_library=both build $XML2_SRC --enable-shared=no --without-python build $SOUP_SRC --without-gnome --without-krb5-config --enable-shared=no --disable-tls-check build $PHODAV_SRC - build $SPICE_CLIENT_SRC --with-gtk=no + meson_build $SPICE_CLIENT_SRC -Dcoroutine=libucontext -Dusb-cd=disabled } fixup () {