spice-gtk-0.42.patch 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  1. From 07ba2d801b4a03125dee3f9d5f4a13cad8d62008 Mon Sep 17 00:00:00 2001
  2. From: osy <osy@turing.llc>
  3. Date: Fri, 4 Mar 2022 16:35:26 -0800
  4. Subject: [PATCH 1/2] spice-util: support for non-default GMainContext
  5. When spice-gtk is used in an application with its own GMainContext, the
  6. wrong context will be used leading to various issues.
  7. https://developer-old.gnome.org/programming-guidelines/stable/main-contexts.html.en
  8. We add a new API spice_util_set_main_context() which allows the caller
  9. to pass in the main context for a main loop that the caller controls and
  10. is responsible for.
  11. ---
  12. doc/reference/spice-gtk-sections.txt | 2 +
  13. src/map-file | 1 +
  14. src/spice-glib-sym-file | 1 +
  15. src/spice-util-priv.h | 8 ++
  16. src/spice-util.c | 160 +++++++++++++++++++++++++++
  17. src/spice-util.h | 1 +
  18. 6 files changed, 173 insertions(+)
  19. diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
  20. index 5cd6686..2163de2 100644
  21. --- a/doc/reference/spice-gtk-sections.txt
  22. +++ b/doc/reference/spice-gtk-sections.txt
  23. @@ -458,11 +458,13 @@ SpiceUsbDeviceWidgetPrivate
  24. spice_util_set_debug
  25. spice_util_get_version_string
  26. spice_uuid_to_string
  27. +spice_util_set_main_context
  28. <SUBSECTION Private>
  29. SPICE_DEBUG
  30. spice_util_get_debug
  31. SPICE_RESERVED_PADDING
  32. spice_g_signal_connect_object
  33. +spice_main_context
  34. </SECTION>
  35. <SECTION>
  36. diff --git a/src/map-file b/src/map-file
  37. index c0d8ca6..e5f75f1 100644
  38. --- a/src/map-file
  39. +++ b/src/map-file
  40. @@ -191,6 +191,7 @@ spice_usbredir_channel_get_type;
  41. spice_util_get_debug;
  42. spice_util_get_version_string;
  43. spice_util_set_debug;
  44. +spice_util_set_main_context;
  45. spice_uuid_to_string;
  46. spice_webdav_channel_get_type;
  47. local:
  48. diff --git a/src/spice-glib-sym-file b/src/spice-glib-sym-file
  49. index ccaad1a..acb5961 100644
  50. --- a/src/spice-glib-sym-file
  51. +++ b/src/spice-glib-sym-file
  52. @@ -165,5 +165,6 @@ spice_usbredir_channel_get_type
  53. spice_util_get_debug
  54. spice_util_get_version_string
  55. spice_util_set_debug
  56. +spice_util_set_main_context
  57. spice_uuid_to_string
  58. spice_webdav_channel_get_type
  59. diff --git a/src/spice-util-priv.h b/src/spice-util-priv.h
  60. index 98389f7..e156469 100644
  61. --- a/src/spice-util-priv.h
  62. +++ b/src/spice-util-priv.h
  63. @@ -30,5 +30,13 @@ gchar* spice_unix2dos(const gchar *str, gssize len);
  64. gchar* spice_dos2unix(const gchar *str, gssize len);
  65. void spice_mono_edge_highlight(unsigned width, unsigned hight,
  66. const guint8 *and, const guint8 *xor, guint8 *dest);
  67. +GMainContext *spice_main_context(void);
  68. +guint g_spice_timeout_add(guint interval, GSourceFunc function, gpointer data);
  69. +guint g_spice_timeout_add_seconds(guint interval, GSourceFunc function, gpointer data);
  70. +guint g_spice_timeout_add_full(gint priority, guint interval, GSourceFunc function,
  71. + gpointer data, GDestroyNotify notify);
  72. +guint g_spice_idle_add(GSourceFunc function, gpointer data);
  73. +guint g_spice_child_watch_add(GPid pid, GChildWatchFunc function, gpointer data);
  74. +gboolean g_spice_source_remove(guint tag);
  75. G_END_DECLS
  76. diff --git a/src/spice-util.c b/src/spice-util.c
  77. index 30d83c8..fc238ae 100644
  78. --- a/src/spice-util.c
  79. +++ b/src/spice-util.c
  80. @@ -475,3 +475,163 @@ void spice_mono_edge_highlight(unsigned width, unsigned height,
  81. xor += bpl;
  82. }
  83. }
  84. +
  85. +static GMainContext *spice_context = NULL;
  86. +
  87. +/**
  88. + * spice_util_set_main_context:
  89. + * @context: Main context for SPICE
  90. + *
  91. + * Main context for events and sources. This must be called first if the
  92. + * application uses multiple GLib based libraries. In that case, the
  93. + * caller is responsible for setting up a separate main context and main loop
  94. + * for SPICE. The context will be retained. To prevent memory leaks,
  95. + * spice_util_set_main_context(NULL) should be called when finished which sets
  96. + * the main context back to the default.
  97. + *
  98. + * Since: 0.41
  99. + **/
  100. +void spice_util_set_main_context(GMainContext *context)
  101. +{
  102. + if (spice_context) {
  103. + g_main_context_unref(spice_context);
  104. + }
  105. + spice_context = context;
  106. + if (spice_context) {
  107. + g_main_context_ref(spice_context);
  108. + }
  109. +}
  110. +
  111. +/**
  112. + * spice_main_context:
  113. + *
  114. + * Returns: either the main context set by spice_util_set_main_context() or
  115. + * NULL indicating the default main context.
  116. + *
  117. + * Since: 0.41
  118. + **/
  119. +G_GNUC_INTERNAL
  120. +GMainContext *spice_main_context(void)
  121. +{
  122. + return spice_context;
  123. +}
  124. +
  125. +G_GNUC_INTERNAL
  126. +guint
  127. +g_spice_timeout_add(guint interval,
  128. + GSourceFunc function,
  129. + gpointer data)
  130. +{
  131. + return g_spice_timeout_add_full(G_PRIORITY_DEFAULT,
  132. + interval, function, data, NULL);
  133. +}
  134. +
  135. +G_GNUC_INTERNAL
  136. +guint
  137. +g_spice_timeout_add_seconds(guint interval,
  138. + GSourceFunc function,
  139. + gpointer data)
  140. +{
  141. + GSource *source = NULL;
  142. + GMainContext *context;
  143. + guint id;
  144. +
  145. + g_return_val_if_fail(function != NULL, 0);
  146. +
  147. + context = spice_main_context();
  148. +
  149. + source = g_timeout_source_new_seconds(interval);
  150. + g_source_set_callback(source, function, data, NULL);
  151. + id = g_source_attach(source, context);
  152. + g_source_unref(source);
  153. +
  154. + return id;
  155. +}
  156. +
  157. +G_GNUC_INTERNAL
  158. +guint
  159. +g_spice_timeout_add_full (gint priority,
  160. + guint interval,
  161. + GSourceFunc function,
  162. + gpointer data,
  163. + GDestroyNotify notify)
  164. +{
  165. + GSource *source;
  166. + GMainContext *context;
  167. + guint id;
  168. +
  169. + g_return_val_if_fail(function != NULL, 0);
  170. +
  171. + context = spice_main_context();
  172. + source = g_timeout_source_new(interval);
  173. +
  174. + if (priority != G_PRIORITY_DEFAULT)
  175. + g_source_set_priority(source, priority);
  176. +
  177. + g_source_set_callback(source, function, data, notify);
  178. + id = g_source_attach(source, context);
  179. +
  180. + g_source_unref(source);
  181. +
  182. + return id;
  183. +}
  184. +
  185. +G_GNUC_INTERNAL
  186. +guint
  187. +g_spice_idle_add(GSourceFunc function,
  188. + gpointer data)
  189. +{
  190. + GSource *source = NULL;
  191. + GMainContext *context;
  192. + guint id;
  193. +
  194. + g_return_val_if_fail(function != NULL, 0);
  195. +
  196. + context = spice_main_context();
  197. +
  198. + source = g_idle_source_new();
  199. + g_source_set_callback(source, function, data, NULL);
  200. + id = g_source_attach(source, context);
  201. + g_source_unref(source);
  202. +
  203. + return id;
  204. +}
  205. +
  206. +G_GNUC_INTERNAL
  207. +guint
  208. +g_spice_child_watch_add(GPid pid,
  209. + GChildWatchFunc function,
  210. + gpointer data)
  211. +{
  212. + GSource *source = NULL;
  213. + GMainContext *context;
  214. + guint id;
  215. +
  216. + g_return_val_if_fail(function != NULL, 0);
  217. +
  218. + context = spice_main_context();
  219. +
  220. + source = g_child_watch_source_new(pid);
  221. + g_source_set_callback(source, (GSourceFunc) function, data, NULL);
  222. + id = g_source_attach(source, context);
  223. + g_source_unref(source);
  224. +
  225. + return id;
  226. +}
  227. +
  228. +G_GNUC_INTERNAL
  229. +gboolean
  230. +g_spice_source_remove(guint tag)
  231. +{
  232. + GSource *source;
  233. +
  234. + g_return_val_if_fail(tag > 0, FALSE);
  235. +
  236. + source = g_main_context_find_source_by_id(spice_main_context(), tag);
  237. + if (source)
  238. + g_source_destroy(source);
  239. + else
  240. + g_critical("Source ID %u was not found when attempting to remove it", tag);
  241. +
  242. + return source != NULL;
  243. +}
  244. diff --git a/src/spice-util.h b/src/spice-util.h
  245. index 421b4b0..e161c83 100644
  246. --- a/src/spice-util.h
  247. +++ b/src/spice-util.h
  248. @@ -30,6 +30,7 @@ gulong spice_g_signal_connect_object(gpointer instance,
  249. gpointer gobject,
  250. GConnectFlags connect_flags);
  251. gchar* spice_uuid_to_string(const guint8 uuid[16]);
  252. +void spice_util_set_main_context(GMainContext *context);
  253. #define SPICE_DEBUG(fmt, ...) \
  254. do { \
  255. --
  256. 2.41.0
  257. From 92ac46d9328afa036e2e3aebf0f7218ba5b2910f Mon Sep 17 00:00:00 2001
  258. From: osy <osy@turing.llc>
  259. Date: Fri, 4 Mar 2022 16:44:20 -0800
  260. Subject: [PATCH 2/2] spice-gtk: user specified GMainContext for events
  261. Following the previous commit, this replaces all GLib calls that
  262. implicitly uses the default main context with versions that can use the
  263. main context set by spice_util_set_main_context().
  264. ---
  265. src/channel-display-gst.c | 10 +++++-----
  266. src/channel-display-mjpeg.c | 6 +++---
  267. src/channel-display.c | 6 +++---
  268. src/channel-main.c | 22 +++++++++++-----------
  269. src/channel-usbredir.c | 2 +-
  270. src/channel-webdav.c | 6 +++---
  271. src/gio-coroutine.c | 13 +++++++------
  272. src/smartcard-manager.c | 5 +++--
  273. src/spice-channel.c | 14 +++++++-------
  274. src/spice-gstaudio.c | 10 +++++-----
  275. src/spice-gtk-session.c | 8 ++++----
  276. src/spice-session.c | 8 ++++----
  277. src/spice-widget.c | 9 +++++----
  278. src/usb-acl-helper.c | 3 ++-
  279. src/usb-device-manager.c | 3 ++-
  280. src/vmcstream.c | 2 +-
  281. 16 files changed, 66 insertions(+), 61 deletions(-)
  282. diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
  283. index 36db3a3..800c41a 100644
  284. --- a/src/channel-display-gst.c
  285. +++ b/src/channel-display-gst.c
  286. @@ -297,13 +297,13 @@ static void schedule_frame(SpiceGstDecoder *decoder)
  287. }
  288. if (spice_mmtime_diff(gstframe->encoded_frame->mm_time, now) >= 0) {
  289. - decoder->timer_id = g_timeout_add(gstframe->encoded_frame->mm_time - now,
  290. - display_frame, decoder);
  291. + decoder->timer_id = g_spice_timeout_add(gstframe->encoded_frame->mm_time - now,
  292. + display_frame, decoder);
  293. } else if (decoder->display_frame && !decoder->pending_samples) {
  294. /* Still attempt to display the least out of date frame so the
  295. * video is not completely frozen for an extended period of time.
  296. */
  297. - decoder->timer_id = g_timeout_add(0, display_frame, decoder);
  298. + decoder->timer_id = g_spice_timeout_add(0, display_frame, decoder);
  299. } else {
  300. SPICE_DEBUG("%s: rendering too late by %u ms (ts: %u, mmtime: %u), dropping",
  301. __FUNCTION__, now - gstframe->encoded_frame->mm_time,
  302. @@ -605,7 +605,7 @@ static void spice_gst_decoder_reschedule(VideoDecoder *video_decoder)
  303. g_mutex_unlock(&decoder->queues_mutex);
  304. if (timer_id != 0) {
  305. - g_source_remove(timer_id);
  306. + g_spice_source_remove(timer_id);
  307. }
  308. schedule_frame(decoder);
  309. }
  310. @@ -625,7 +625,7 @@ static void spice_gst_decoder_destroy(VideoDecoder *video_decoder)
  311. * scheduled display_frame() call and drop the queued frames.
  312. */
  313. if (decoder->timer_id) {
  314. - g_source_remove(decoder->timer_id);
  315. + g_spice_source_remove(decoder->timer_id);
  316. }
  317. g_mutex_clear(&decoder->queues_mutex);
  318. g_queue_free_full(decoder->decoding_queue, (GDestroyNotify)free_gst_frame);
  319. diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c
  320. index 558d9f8..e63eb18 100644
  321. --- a/src/channel-display-mjpeg.c
  322. +++ b/src/channel-display-mjpeg.c
  323. @@ -183,7 +183,7 @@ static void mjpeg_decoder_schedule(MJpegDecoder *decoder)
  324. if (spice_mmtime_diff(time, frame->mm_time) <= 0) {
  325. guint32 d = frame->mm_time - time;
  326. decoder->cur_frame = frame;
  327. - decoder->timer_id = g_timeout_add(d, mjpeg_decoder_decode_frame, decoder);
  328. + decoder->timer_id = g_spice_timeout_add(d, mjpeg_decoder_decode_frame, decoder);
  329. break;
  330. }
  331. @@ -207,7 +207,7 @@ static void spice_frame_unref_func(gpointer data, gpointer user_data)
  332. static void mjpeg_decoder_drop_queue(MJpegDecoder *decoder)
  333. {
  334. if (decoder->timer_id != 0) {
  335. - g_source_remove(decoder->timer_id);
  336. + g_spice_source_remove(decoder->timer_id);
  337. decoder->timer_id = 0;
  338. }
  339. g_clear_pointer(&decoder->cur_frame, spice_frame_free);
  340. @@ -255,7 +255,7 @@ static void mjpeg_decoder_reschedule(VideoDecoder *video_decoder)
  341. SPICE_DEBUG("%s", __FUNCTION__);
  342. if (decoder->timer_id != 0) {
  343. - g_source_remove(decoder->timer_id);
  344. + g_spice_source_remove(decoder->timer_id);
  345. decoder->timer_id = 0;
  346. }
  347. mjpeg_decoder_schedule(decoder);
  348. diff --git a/src/channel-display.c b/src/channel-display.c
  349. index e47fc3f..a9b604f 100644
  350. --- a/src/channel-display.c
  351. +++ b/src/channel-display.c
  352. @@ -147,7 +147,7 @@ static void spice_display_channel_dispose(GObject *object)
  353. SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(object)->priv;
  354. if (c->mark_false_event_id != 0) {
  355. - g_source_remove(c->mark_false_event_id);
  356. + g_spice_source_remove(c->mark_false_event_id);
  357. c->mark_false_event_id = 0;
  358. }
  359. @@ -1970,7 +1970,7 @@ static void display_handle_surface_create(SpiceChannel *channel, SpiceMsgIn *in)
  360. surface->primary = true;
  361. create_canvas(channel, surface);
  362. if (c->mark_false_event_id != 0) {
  363. - g_source_remove(c->mark_false_event_id);
  364. + g_spice_source_remove(c->mark_false_event_id);
  365. c->mark_false_event_id = 0;
  366. }
  367. } else {
  368. @@ -2011,7 +2011,7 @@ static void display_handle_surface_destroy(SpiceChannel *channel, SpiceMsgIn *in
  369. CHANNEL_DEBUG(channel, "%d: FIXME primary destroy, but is display really disabled?", id);
  370. /* this is done with a timeout in spicec as well, it's *ugly* */
  371. if (id != 0 && c->mark_false_event_id == 0) {
  372. - c->mark_false_event_id = g_timeout_add_seconds(1, display_mark_false, channel);
  373. + c->mark_false_event_id = g_spice_timeout_add_seconds(1, display_mark_false, channel);
  374. }
  375. c->primary = NULL;
  376. g_coroutine_signal_emit(channel, signals[SPICE_DISPLAY_PRIMARY_DESTROY], 0);
  377. diff --git a/src/channel-main.c b/src/channel-main.c
  378. index f502ca3..7830f6f 100644
  379. --- a/src/channel-main.c
  380. +++ b/src/channel-main.c
  381. @@ -361,17 +361,17 @@ static void spice_main_channel_dispose(GObject *obj)
  382. SpiceMainChannelPrivate *c = SPICE_MAIN_CHANNEL(obj)->priv;
  383. if (c->timer_id) {
  384. - g_source_remove(c->timer_id);
  385. + g_spice_source_remove(c->timer_id);
  386. c->timer_id = 0;
  387. }
  388. if (c->switch_host_delayed_id) {
  389. - g_source_remove(c->switch_host_delayed_id);
  390. + g_spice_source_remove(c->switch_host_delayed_id);
  391. c->switch_host_delayed_id = 0;
  392. }
  393. if (c->migrate_delayed_id) {
  394. - g_source_remove(c->migrate_delayed_id);
  395. + g_spice_source_remove(c->migrate_delayed_id);
  396. c->migrate_delayed_id = 0;
  397. }
  398. @@ -1188,7 +1188,7 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel)
  399. spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
  400. if (c->timer_id != 0) {
  401. - g_source_remove(c->timer_id);
  402. + g_spice_source_remove(c->timer_id);
  403. c->timer_id = 0;
  404. }
  405. @@ -1568,16 +1568,16 @@ static void update_display_timer(SpiceMainChannel *channel, guint seconds)
  406. SpiceMainChannelPrivate *c = channel->priv;
  407. if (c->timer_id)
  408. - g_source_remove(c->timer_id);
  409. + g_spice_source_remove(c->timer_id);
  410. if (seconds != 0) {
  411. - c->timer_id = g_timeout_add_seconds(seconds, timer_set_display, channel);
  412. + c->timer_id = g_spice_timeout_add_seconds(seconds, timer_set_display, channel);
  413. } else {
  414. /* We need to special case 0, as we want the callback to fire as soon
  415. * as possible. g_timeout_add_seconds(0) would set up a timer which would fire
  416. * at the next second boundary, which might be nearly 1 full second later.
  417. */
  418. - c->timer_id = g_timeout_add(0, timer_set_display, channel);
  419. + c->timer_id = g_spice_timeout_add(0, timer_set_display, channel);
  420. }
  421. }
  422. @@ -1798,7 +1798,7 @@ static void main_handle_channels_list(SpiceChannel *channel, SpiceMsgIn *in)
  423. /* no need to explicitly switch to main context, since
  424. synchronous call is not needed. */
  425. /* no need to track idle, session is refed */
  426. - g_idle_add((GSourceFunc)_channel_new, c);
  427. + g_spice_idle_add((GSourceFunc)_channel_new, c);
  428. }
  429. }
  430. @@ -2578,7 +2578,7 @@ static void main_handle_migrate_end(SpiceChannel *channel, SpiceMsgIn *in)
  431. g_return_if_fail(c->migrate_delayed_id == 0);
  432. g_return_if_fail(spice_channel_test_capability(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE));
  433. - c->migrate_delayed_id = g_idle_add(migrate_delayed, channel);
  434. + c->migrate_delayed_id = g_spice_idle_add(migrate_delayed, channel);
  435. }
  436. /* main context */
  437. @@ -2622,7 +2622,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i
  438. if (c->switch_host_delayed_id != 0) {
  439. g_warning("Switching host already in progress, aborting it");
  440. - g_warn_if_fail(g_source_remove(c->switch_host_delayed_id));
  441. + g_warn_if_fail(g_spice_source_remove(c->switch_host_delayed_id));
  442. c->switch_host_delayed_id = 0;
  443. }
  444. @@ -2635,7 +2635,7 @@ static void main_handle_migrate_switch_host(SpiceChannel *channel, SpiceMsgIn *i
  445. spice_session_set_port(session, mig->port, FALSE);
  446. spice_session_set_port(session, mig->sport, TRUE);
  447. - c->switch_host_delayed_id = g_idle_add(switch_host_delayed, channel);
  448. + c->switch_host_delayed_id = g_spice_idle_add(switch_host_delayed, channel);
  449. }
  450. /* coroutine context */
  451. diff --git a/src/channel-usbredir.c b/src/channel-usbredir.c
  452. index b81d666..0aa6fff 100644
  453. --- a/src/channel-usbredir.c
  454. +++ b/src/channel-usbredir.c
  455. @@ -709,7 +709,7 @@ static void usbredir_handle_msg(SpiceChannel *c, SpiceMsgIn *in)
  456. err_data.device = spice_usb_backend_device_ref(device);
  457. err_data.error = err;
  458. spice_usbredir_channel_unlock(channel);
  459. - g_idle_add(device_error, &err_data);
  460. + g_spice_idle_add(device_error, &err_data);
  461. coroutine_yield(NULL);
  462. spice_usb_backend_device_unref(err_data.device);
  463. diff --git a/src/channel-webdav.c b/src/channel-webdav.c
  464. index 7de5495..5f3af1c 100644
  465. --- a/src/channel-webdav.c
  466. +++ b/src/channel-webdav.c
  467. @@ -97,7 +97,7 @@ static void output_queue_free(OutputQueue *queue)
  468. g_queue_free_full(queue->queue, g_free);
  469. g_clear_object(&queue->output);
  470. if (queue->idle_id)
  471. - g_source_remove(queue->idle_id);
  472. + g_spice_source_remove(queue->idle_id);
  473. g_free(queue);
  474. }
  475. @@ -120,7 +120,7 @@ static void output_queue_flush_cb(GObject *source_object,
  476. g_clear_error(&error);
  477. if (!q->idle_id)
  478. - q->idle_id = g_idle_add(output_queue_idle, q);
  479. + q->idle_id = g_spice_idle_add(output_queue_idle, q);
  480. g_free(e);
  481. }
  482. @@ -175,7 +175,7 @@ static void output_queue_push(OutputQueue *q, const guint8 *buf, gsize size,
  483. g_queue_push_tail(q->queue, e);
  484. if (!q->idle_id && !q->flushing)
  485. - q->idle_id = g_idle_add(output_queue_idle, q);
  486. + q->idle_id = g_spice_idle_add(output_queue_idle, q);
  487. }
  488. #endif
  489. diff --git a/src/gio-coroutine.c b/src/gio-coroutine.c
  490. index e8fe029..61a6cef 100644
  491. --- a/src/gio-coroutine.c
  492. +++ b/src/gio-coroutine.c
  493. @@ -20,6 +20,7 @@
  494. #include "config.h"
  495. #include "gio-coroutine.h"
  496. +#include "spice-util-priv.h"
  497. typedef struct _GConditionWaitSource
  498. {
  499. @@ -56,14 +57,14 @@ GIOCondition g_coroutine_socket_wait(GCoroutine *self,
  500. src = g_socket_create_source(sock, cond | G_IO_HUP | G_IO_ERR | G_IO_NVAL, NULL);
  501. g_source_set_callback(src, (GSourceFunc)g_io_wait_helper, self, NULL);
  502. - self->wait_id = g_source_attach(src, NULL);
  503. + self->wait_id = g_source_attach(src, spice_main_context());
  504. ret = coroutine_yield(NULL);
  505. g_source_unref(src);
  506. if (ret != NULL)
  507. val = *ret;
  508. else
  509. - g_source_remove(self->wait_id);
  510. + g_spice_source_remove(self->wait_id);
  511. self->wait_id = 0;
  512. return val;
  513. @@ -76,7 +77,7 @@ void g_coroutine_condition_cancel(GCoroutine *coroutine)
  514. if (coroutine->condition_id == 0)
  515. return;
  516. - g_source_remove(coroutine->condition_id);
  517. + g_spice_source_remove(coroutine->condition_id);
  518. coroutine->condition_id = 0;
  519. }
  520. @@ -166,7 +167,7 @@ gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, g
  521. vsrc->func = func;
  522. vsrc->data = data;
  523. - self->condition_id = g_source_attach(src, NULL);
  524. + self->condition_id = g_source_attach(src, spice_main_context());
  525. g_source_set_callback(src, g_condition_wait_helper, self, NULL);
  526. coroutine_yield(NULL);
  527. g_source_unref(src);
  528. @@ -220,7 +221,7 @@ g_coroutine_signal_emit(gpointer instance, guint signal_id,
  529. g_signal_emit_valist(instance, signal_id, detail, data.var_args);
  530. } else {
  531. g_object_ref(instance);
  532. - g_idle_add(emit_main_context, &data);
  533. + g_spice_idle_add(emit_main_context, &data);
  534. coroutine_yield(NULL);
  535. g_warn_if_fail(data.notified);
  536. g_object_unref(instance);
  537. @@ -257,7 +258,7 @@ void g_coroutine_object_notify(GObject *object,
  538. data.propname = (gpointer)property_name;
  539. data.notified = FALSE;
  540. - g_idle_add(notify_main_context, &data);
  541. + g_spice_idle_add(notify_main_context, &data);
  542. /* This switches to the system coroutine context, lets
  543. * the idle function run to dispatch the signal, and
  544. diff --git a/src/smartcard-manager.c b/src/smartcard-manager.c
  545. index bb97ad7..8cc2dd1 100644
  546. --- a/src/smartcard-manager.c
  547. +++ b/src/smartcard-manager.c
  548. @@ -27,6 +27,7 @@
  549. #include "smartcard-manager.h"
  550. #include "smartcard-manager-priv.h"
  551. #include "spice-marshal.h"
  552. +#include "spice-util-priv.h"
  553. /**
  554. * SECTION:smartcard-manager
  555. @@ -111,7 +112,7 @@ static void spice_smartcard_manager_finalize(GObject *gobject)
  556. SpiceSmartcardManagerPrivate *priv = manager->priv;
  557. if (priv->monitor_id != 0) {
  558. - g_source_remove(priv->monitor_id);
  559. + g_spice_source_remove(priv->monitor_id);
  560. priv->monitor_id = 0;
  561. }
  562. @@ -364,7 +365,7 @@ static guint smartcard_monitor_add(SmartcardSourceFunc callback,
  563. source = smartcard_monitor_source_new();
  564. g_source_set_callback(source, (GSourceFunc)callback, user_data, NULL);
  565. - id = g_source_attach(source, NULL);
  566. + id = g_source_attach(source, spice_main_context());
  567. g_source_unref(source);
  568. return id;
  569. diff --git a/src/spice-channel.c b/src/spice-channel.c
  570. index 3fd42c5..813923a 100644
  571. --- a/src/spice-channel.c
  572. +++ b/src/spice-channel.c
  573. @@ -744,9 +744,9 @@ void spice_msg_out_send(SpiceMsgOut *out)
  574. if (was_empty && !c->xmit_queue_wakeup_id) {
  575. c->xmit_queue_wakeup_id =
  576. /* Use g_timeout_add_full so that can specify the priority */
  577. - g_timeout_add_full(G_PRIORITY_HIGH, 0,
  578. - spice_channel_idle_wakeup,
  579. - out->channel, NULL);
  580. + g_spice_timeout_add_full(G_PRIORITY_HIGH, 0,
  581. + spice_channel_idle_wakeup,
  582. + out->channel, NULL);
  583. }
  584. end:
  585. @@ -2748,7 +2748,7 @@ cleanup:
  586. c->event = SPICE_CHANNEL_ERROR_CONNECT;
  587. }
  588. - g_idle_add(spice_channel_delayed_unref, channel);
  589. + g_spice_idle_add(spice_channel_delayed_unref, channel);
  590. /* Co-routine exits now - the SpiceChannel object may no longer exist,
  591. so don't do anything else now unless you like SEGVs */
  592. return NULL;
  593. @@ -2807,7 +2807,7 @@ static gboolean channel_connect(SpiceChannel *channel, gboolean tls)
  594. g_object_ref(G_OBJECT(channel)); /* Unref'd when co-routine exits */
  595. /* we connect in idle, to let previous coroutine exit, if present */
  596. - c->connect_delayed_id = g_idle_add(connect_delayed, channel);
  597. + c->connect_delayed_id = g_spice_idle_add(connect_delayed, channel);
  598. return true;
  599. }
  600. @@ -2873,7 +2873,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
  601. CHANNEL_DEBUG(channel, "channel reset");
  602. if (c->connect_delayed_id) {
  603. - g_source_remove(c->connect_delayed_id);
  604. + g_spice_source_remove(c->connect_delayed_id);
  605. c->connect_delayed_id = 0;
  606. }
  607. @@ -2905,7 +2905,7 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
  608. g_queue_foreach(&c->xmit_queue, (GFunc)spice_msg_out_unref, NULL);
  609. g_queue_clear(&c->xmit_queue);
  610. if (c->xmit_queue_wakeup_id) {
  611. - g_source_remove(c->xmit_queue_wakeup_id);
  612. + g_spice_source_remove(c->xmit_queue_wakeup_id);
  613. c->xmit_queue_wakeup_id = 0;
  614. }
  615. g_mutex_unlock(&c->xmit_queue_lock);
  616. diff --git a/src/spice-gstaudio.c b/src/spice-gstaudio.c
  617. index d67727f..b6fc4eb 100644
  618. --- a/src/spice-gstaudio.c
  619. +++ b/src/spice-gstaudio.c
  620. @@ -24,7 +24,7 @@
  621. #include "spice-gstaudio.h"
  622. #include "spice-common.h"
  623. #include "spice-session.h"
  624. -#include "spice-util.h"
  625. +#include "spice-util-priv.h"
  626. struct stream {
  627. GstElement *pipe;
  628. @@ -79,7 +79,7 @@ static void spice_gstaudio_dispose(GObject *obj)
  629. stream_dispose(&p->playback);
  630. if (p->rbus_watch_id > 0) {
  631. - g_source_remove(p->rbus_watch_id);
  632. + g_spice_source_remove(p->rbus_watch_id);
  633. p->rbus_watch_id = 0;
  634. }
  635. stream_dispose(&p->record);
  636. @@ -197,7 +197,7 @@ static void record_start(SpiceRecordChannel *channel, gint format, gint channels
  637. p->record.channels != channels)) {
  638. gst_element_set_state(p->record.pipe, GST_STATE_NULL);
  639. if (p->rbus_watch_id > 0) {
  640. - g_source_remove(p->rbus_watch_id);
  641. + g_spice_source_remove(p->rbus_watch_id);
  642. p->rbus_watch_id = 0;
  643. }
  644. g_clear_pointer(&p->record.pipe, gst_object_unref);
  645. @@ -251,7 +251,7 @@ static void playback_stop(SpiceGstaudio *gstaudio)
  646. if (p->playback.pipe)
  647. gst_element_set_state(p->playback.pipe, GST_STATE_READY);
  648. if (p->mmtime_id != 0) {
  649. - g_source_remove(p->mmtime_id);
  650. + g_spice_source_remove(p->mmtime_id);
  651. p->mmtime_id = 0;
  652. }
  653. }
  654. @@ -328,7 +328,7 @@ cleanup:
  655. if (!p->playback.fake && p->mmtime_id == 0) {
  656. update_mmtime_timeout_cb(gstaudio);
  657. - p->mmtime_id = g_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio);
  658. + p->mmtime_id = g_spice_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio);
  659. }
  660. }
  661. diff --git a/src/spice-gtk-session.c b/src/spice-gtk-session.c
  662. index 72b0168..6ec3a16 100644
  663. --- a/src/spice-gtk-session.c
  664. +++ b/src/spice-gtk-session.c
  665. @@ -285,7 +285,7 @@ static void clipboard_release_delay_remove(SpiceGtkSession *self, guint selectio
  666. clipboard_release(self, selection);
  667. }
  668. - g_source_remove(s->clipboard_release_delay[selection]);
  669. + g_spice_source_remove(s->clipboard_release_delay[selection]);
  670. s->clipboard_release_delay[selection] = 0;
  671. }
  672. @@ -865,7 +865,7 @@ static void clipboard_get(GtkClipboard *clipboard,
  673. ri.selection_data = selection_data;
  674. ri.info = info;
  675. - ri.loop = g_main_loop_new(NULL, FALSE);
  676. + ri.loop = g_main_loop_new(spice_main_context(), FALSE);
  677. ri.selection = selection;
  678. ri.self = self;
  679. @@ -1548,8 +1548,8 @@ static void clipboard_release_delay(SpiceMainChannel *main, guint selection,
  680. rel->self = self;
  681. rel->selection = selection;
  682. s->clipboard_release_delay[selection] =
  683. - g_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY,
  684. - clipboard_release_timeout, rel, g_free);
  685. + g_spice_timeout_add_full(G_PRIORITY_DEFAULT, CLIPBOARD_RELEASE_DELAY,
  686. + clipboard_release_timeout, rel, g_free);
  687. }
  688. diff --git a/src/spice-session.c b/src/spice-session.c
  689. index bb3c6cd..9d161ee 100644
  690. --- a/src/spice-session.c
  691. +++ b/src/spice-session.c
  692. @@ -1861,7 +1861,7 @@ end:
  693. s->migrate_wait_init = FALSE;
  694. if (s->after_main_init) {
  695. - g_source_remove(s->after_main_init);
  696. + g_spice_source_remove(s->after_main_init);
  697. s->after_main_init = 0;
  698. }
  699. @@ -1936,7 +1936,7 @@ gboolean spice_session_migrate_after_main_init(SpiceSession *self)
  700. g_return_val_if_fail(s->after_main_init == 0, FALSE);
  701. s->migrate_wait_init = FALSE;
  702. - s->after_main_init = g_idle_add(after_main_init, self);
  703. + s->after_main_init = g_spice_idle_add(after_main_init, self);
  704. return TRUE;
  705. }
  706. @@ -2029,7 +2029,7 @@ void spice_session_disconnect(SpiceSession *session)
  707. return;
  708. g_object_ref(session);
  709. - s->disconnecting = g_idle_add((GSourceFunc)session_disconnect_idle, session);
  710. + s->disconnecting = g_spice_idle_add((GSourceFunc)session_disconnect_idle, session);
  711. }
  712. /**
  713. @@ -2271,7 +2271,7 @@ GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceC
  714. g_socket_client_set_enable_proxy(open_host.client, s->proxy != NULL);
  715. g_socket_client_set_timeout(open_host.client, SOCKET_TIMEOUT);
  716. - g_idle_add(open_host_idle_cb, &open_host);
  717. + g_spice_idle_add(open_host_idle_cb, &open_host);
  718. /* switch to main loop and wait for connection */
  719. coroutine_yield(NULL);
  720. diff --git a/src/spice-widget.c b/src/spice-widget.c
  721. index 6311115..19dff68 100644
  722. --- a/src/spice-widget.c
  723. +++ b/src/spice-widget.c
  724. @@ -55,6 +55,7 @@
  725. #include "spice-gtk-session-priv.h"
  726. #include "vncdisplaykeymap.h"
  727. #include "spice-grabsequence-priv.h"
  728. +#include "spice-util-priv.h"
  729. /**
  730. @@ -465,7 +466,7 @@ static void spice_display_dispose(GObject *obj)
  731. d->gtk_session = NULL;
  732. if (d->key_delayed_id) {
  733. - g_source_remove(d->key_delayed_id);
  734. + g_spice_source_remove(d->key_delayed_id);
  735. d->key_delayed_id = 0;
  736. }
  737. @@ -1530,7 +1531,7 @@ static void key_press_and_release(SpiceDisplay *display)
  738. d->key_delayed_scancode = 0;
  739. if (d->key_delayed_id) {
  740. - g_source_remove(d->key_delayed_id);
  741. + g_spice_source_remove(d->key_delayed_id);
  742. d->key_delayed_id = 0;
  743. }
  744. }
  745. @@ -1547,7 +1548,7 @@ static gboolean key_press_delayed(gpointer data)
  746. d->key_delayed_scancode = 0;
  747. if (d->key_delayed_id) {
  748. - g_source_remove(d->key_delayed_id);
  749. + g_spice_source_remove(d->key_delayed_id);
  750. d->key_delayed_id = 0;
  751. }
  752. @@ -1600,7 +1601,7 @@ static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboo
  753. d->keypress_delay != 0 &&
  754. !(d->key_state[i] & m)) {
  755. g_warn_if_fail(d->key_delayed_id == 0);
  756. - d->key_delayed_id = g_timeout_add(d->keypress_delay, key_press_delayed, display);
  757. + d->key_delayed_id = g_spice_timeout_add(d->keypress_delay, key_press_delayed, display);
  758. d->key_delayed_scancode = scancode;
  759. } else
  760. spice_inputs_channel_key_press(d->inputs, scancode);
  761. diff --git a/src/usb-acl-helper.c b/src/usb-acl-helper.c
  762. index 0edad2a..88b4295 100644
  763. --- a/src/usb-acl-helper.c
  764. +++ b/src/usb-acl-helper.c
  765. @@ -25,6 +25,7 @@
  766. #include <string.h>
  767. #include "usb-acl-helper.h"
  768. +#include "spice-util-priv.h"
  769. struct _SpiceUsbAclHelperPrivate {
  770. GTask *task;
  771. @@ -208,7 +209,7 @@ void spice_usb_acl_helper_open_acl_async(SpiceUsbAclHelper *self,
  772. g_task_return_error(task, err);
  773. goto done;
  774. }
  775. - g_child_watch_add(helper_pid, helper_child_watch_cb, NULL);
  776. + g_spice_child_watch_add(helper_pid, helper_child_watch_cb, NULL);
  777. priv->in_ch = g_io_channel_unix_new(in);
  778. g_io_channel_set_close_on_unref(priv->in_ch, TRUE);
  779. diff --git a/src/usb-device-manager.c b/src/usb-device-manager.c
  780. index 24b6727..c7e1431 100644
  781. --- a/src/usb-device-manager.c
  782. +++ b/src/usb-device-manager.c
  783. @@ -38,6 +38,7 @@
  784. #include "spice-client.h"
  785. #include "spice-marshal.h"
  786. #include "usb-device-manager-priv.h"
  787. +#include "spice-util-priv.h"
  788. #include <glib/gi18n-lib.h>
  789. @@ -865,7 +866,7 @@ static void spice_usb_device_manager_hotplug_cb(void *user_data,
  790. args->manager = g_object_ref(manager);
  791. args->device = spice_usb_backend_device_ref(dev);
  792. args->added = added;
  793. - g_idle_add(spice_usb_device_manager_hotplug_idle_cb, args);
  794. + g_spice_idle_add(spice_usb_device_manager_hotplug_idle_cb, args);
  795. }
  796. static void spice_usb_device_manager_channel_connect_cb(GObject *gobject,
  797. diff --git a/src/vmcstream.c b/src/vmcstream.c
  798. index e26b939..6054f3e 100644
  799. --- a/src/vmcstream.c
  800. +++ b/src/vmcstream.c
  801. @@ -161,7 +161,7 @@ spice_vmc_input_stream_co_data(SpiceVmcInputStream *self,
  802. cb_data = g_new(complete_in_idle_cb_data , 1);
  803. cb_data->task = g_object_ref(self->task);
  804. cb_data->pos = self->pos;
  805. - g_idle_add(complete_in_idle_cb, cb_data);
  806. + g_spice_idle_add(complete_in_idle_cb, cb_data);
  807. g_clear_object(&self->task);
  808. }
  809. --
  810. 2.41.0
  811. From f648e0730b8ddbb03f2f9e45c121a5bbcc3ba00f Mon Sep 17 00:00:00 2001
  812. From: osy <osy@turing.llc>
  813. Date: Sun, 6 Aug 2023 01:11:31 -0700
  814. Subject: [PATCH] meson: disable version script
  815. Fails to build on Xcode 15
  816. ---
  817. src/meson.build | 2 +-
  818. 1 file changed, 1 insertion(+), 1 deletion(-)
  819. diff --git a/src/meson.build b/src/meson.build
  820. index daff1aa..61e60fa 100644
  821. --- a/src/meson.build
  822. +++ b/src/meson.build
  823. @@ -205,7 +205,7 @@ spice_client_glib_lib = library('spice-client-glib-2.0', spice_client_glib_sourc
  824. version : spice_client_glib_so_version,
  825. install : true,
  826. include_directories : spice_gtk_include,
  827. - link_args : [spice_gtk_version_script],
  828. +# link_args : [spice_gtk_version_script],
  829. link_depends : spice_client_glib_syms,
  830. dependencies : spice_glib_deps)
  831. --
  832. 2.41.0
  833. From 00cdb145ca1f34e47a1c8ba0d933595709318f85 Mon Sep 17 00:00:00 2001
  834. From: osy <osy@turing.llc>
  835. Date: Sun, 17 Aug 2025 19:32:49 -0700
  836. Subject: [PATCH] main: only send physical size when used
  837. Since introducing physical size support four years ago, the
  838. feature has been broken on Linux. In VDAgent, there is a
  839. check on the size of VDAgentMonitorsConfig that does not
  840. account for FLAG_PHYSICAL_SIZE. This was fixed in VDAgent
  841. in commit 3660acfcbaaca9c66dca5ef09205bd7c1d70b98c but until
  842. that fix is released and all the Linux distros pick it up,
  843. the feature will still be broken.
  844. In the meantime, this change will ignore monitor physical
  845. size config if it is not used and the client can implement
  846. logic to detect when it is safe to send it.
  847. ---
  848. src/channel-main.c | 41 ++++++++++++++++++++++++++++-------------
  849. 1 file changed, 28 insertions(+), 13 deletions(-)
  850. diff --git a/src/channel-main.c b/src/channel-main.c
  851. index 7830f6f..d4d1a1e 100644
  852. --- a/src/channel-main.c
  853. +++ b/src/channel-main.c
  854. @@ -1119,6 +1119,7 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel)
  855. VDAgentMonitorsConfig *mon;
  856. int i, j, monitors;
  857. size_t size;
  858. + gboolean has_physical_size;
  859. g_return_val_if_fail(SPICE_IS_MAIN_CHANNEL(channel), FALSE);
  860. c = channel->priv;
  861. @@ -1134,8 +1135,18 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel)
  862. }
  863. }
  864. - size = sizeof(VDAgentMonitorsConfig) +
  865. - (sizeof(VDAgentMonConfig) + sizeof(VDAgentMonitorMM)) * monitors;
  866. + /* only enable sending physical size if needed */
  867. + has_physical_size = FALSE;
  868. + for (i = 0; i < SPICE_N_ELEMENTS(c->display); i++) {
  869. + if (c->display[i].width_mm || c->display[i].height_mm) {
  870. + has_physical_size = TRUE;
  871. + }
  872. + }
  873. +
  874. + size = sizeof(VDAgentMonitorsConfig) + sizeof(VDAgentMonConfig) * monitors;
  875. + if (has_physical_size) {
  876. + size += sizeof(VDAgentMonitorMM) * monitors;
  877. + }
  878. mon = g_malloc0(size);
  879. mon->num_of_monitors = monitors;
  880. @@ -1143,7 +1154,9 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel)
  881. c->disable_display_align == FALSE)
  882. mon->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_USE_POS;
  883. - mon->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE;
  884. + if (has_physical_size) {
  885. + mon->flags |= VD_AGENT_CONFIG_MONITORS_FLAG_PHYSICAL_SIZE;
  886. + }
  887. CHANNEL_DEBUG(channel, "sending new monitors config to guest");
  888. j = 0;
  889. @@ -1166,18 +1179,20 @@ gboolean spice_main_channel_send_monitor_config(SpiceMainChannel *channel)
  890. j++;
  891. }
  892. - VDAgentMonitorMM *mm = (void *)&mon->monitors[monitors];
  893. - for (i = 0, j = 0; i < SPICE_N_ELEMENTS(c->display); i++) {
  894. - if (c->display[i].display_state != DISPLAY_ENABLED) {
  895. - if (spice_main_channel_agent_test_capability(channel,
  896. - VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) {
  897. - j++;
  898. + if (has_physical_size) {
  899. + VDAgentMonitorMM *mm = (void *)&mon->monitors[monitors];
  900. + for (i = 0, j = 0; i < SPICE_N_ELEMENTS(c->display); i++) {
  901. + if (c->display[i].display_state != DISPLAY_ENABLED) {
  902. + if (spice_main_channel_agent_test_capability(channel,
  903. + VD_AGENT_CAP_SPARSE_MONITORS_CONFIG)) {
  904. + j++;
  905. + }
  906. + continue;
  907. }
  908. - continue;
  909. + mm[j].width = c->display[i].width_mm;
  910. + mm[j].height = c->display[i].height_mm;
  911. + j++;
  912. }
  913. - mm[j].width = c->display[i].width_mm;
  914. - mm[j].height = c->display[i].height_mm;
  915. - j++;
  916. }
  917. if (c->disable_display_align == FALSE)
  918. --
  919. 2.41.0