mirror of
https://github.com/sol1/rustguac.git
synced 2026-09-10 01:26:06 +00:00
fix(multimon): correct SPICE layout when the guest rearranges a secondary head
For a multi-channel SPICE guest (each head is a separate display channel, e.g. a Windows multi-QXL guest), publish_layout positioned each monitor at origin_x + the guest-reported config->x/y. But config->x/y is the guest's own virtual-desktop arrangement, not an offset within the channel's surface: once the guest rearranges a secondary head (which happens as soon as the primary is resized, e.g. by fit-on-connect), it reports config->x = primary width, so the monitor was placed at origin_x + config->x (double-counted) and clamped to a sliver off-canvas. This is exactly where the compositor already blits the surface (at origin_x), so publish each channel's whole surface at its origin and ignore the guest x/y. Single-channel guests (one combined surface with several monitor regions) still split by the reported regions.
This commit is contained in:
@@ -9666,10 +9666,10 @@ index 00000000..f6638394
|
||||
+
|
||||
diff --git a/src/protocols/spice/display.c b/src/protocols/spice/display.c
|
||||
new file mode 100644
|
||||
index 00000000..c00e0e7e
|
||||
index 00000000..55970c69
|
||||
--- /dev/null
|
||||
+++ b/src/protocols/spice/display.c
|
||||
@@ -0,0 +1,619 @@
|
||||
@@ -0,0 +1,646 @@
|
||||
+/*
|
||||
+ * Licensed to the Apache Software Foundation (ASF) under one
|
||||
+ * or more contributor license agreements. See the NOTICE file
|
||||
@@ -9910,6 +9910,17 @@ index 00000000..c00e0e7e
|
||||
+ int written = 0;
|
||||
+ int index = 0;
|
||||
+
|
||||
+ /* Count active display channels. Multiple channels means each channel's
|
||||
+ * surface is a single monitor (e.g. a Windows multi-QXL guest); a single
|
||||
+ * channel may instead carry several monitor regions within one combined
|
||||
+ * surface (e.g. a Linux multi-head QXL). These need opposite positioning. */
|
||||
+ int active = 0;
|
||||
+ for (int i = 0; i < GUAC_SPICE_MAX_MONITORS; i++) {
|
||||
+ guac_spice_display_state* d = &spice_client->displays[i];
|
||||
+ if (d->channel != NULL && d->data != NULL && d->width > 0 && d->height > 0)
|
||||
+ active++;
|
||||
+ }
|
||||
+
|
||||
+ json[pos++] = '{';
|
||||
+
|
||||
+ for (int i = 0; i < GUAC_SPICE_MAX_MONITORS; i++) {
|
||||
@@ -9919,8 +9930,24 @@ index 00000000..c00e0e7e
|
||||
+ || display->width <= 0 || display->height <= 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Prefer the guest's actual monitor regions within this channel's
|
||||
+ * surface, but only once a surface exists to validate them against */
|
||||
+ /* Multiple display channels: each channel's surface IS one monitor,
|
||||
+ * placed at its composited origin (exactly where the compositor blits
|
||||
+ * it). The guest's per-channel monitor x/y describe its OWN desktop
|
||||
+ * arrangement, which need not match our left-to-right tiling and can
|
||||
+ * even fall outside the channel's own surface — adding them on top of
|
||||
+ * the origin sends a rearranged secondary head far off-canvas with a
|
||||
+ * clamped sliver width. So publish the whole surface at the origin. */
|
||||
+ if (active > 1) {
|
||||
+ int next = guac_spice_layout_append(json, pos, sizeof(json),
|
||||
+ written, index, display->origin_x, display->origin_y,
|
||||
+ display->width, display->height);
|
||||
+ if (next >= 0) { pos = next; written++; index++; }
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* Single display channel: its combined surface may itself hold several
|
||||
+ * monitor regions — split it using the guest-reported regions, which in
|
||||
+ * this case ARE offsets within this one surface. */
|
||||
+ GArray* monitors = NULL;
|
||||
+ g_object_get(SPICE_DISPLAY_CHANNEL(display->channel), "monitors",
|
||||
+ &monitors, NULL);
|
||||
|
||||
Reference in New Issue
Block a user