[Spice-devel] [RFC PATCH vd_agent v2 20/20] vdagent: Use guest_output_id from VDAgentMonitorsConfigV2
Lukáš Hrázký
lhrazky at redhat.com
Thu Aug 16 16:26:49 UTC 2018
Instead of relying on the order, the VDAgentMonitorsConfigV2 message
contains the guest_output_id field, which identifies the output head to
which the config belongs.
Update the monitors_config algorithm to use the guest_output_id instead
of the index. Any output that does not have it's monitors_config with
it's guest_output_id in the list is disabled. The order of items in the
list no longer matters, the guest_output_id is used now.
Signed-off-by: Lukáš Hrázký <lhrazky at redhat.com>
---
src/vdagent/x11-randr.c | 138 +++++++++++++++++++++++++---------------
1 file changed, 86 insertions(+), 52 deletions(-)
diff --git a/src/vdagent/x11-randr.c b/src/vdagent/x11-randr.c
index 1c33c86..e2b02a9 100644
--- a/src/vdagent/x11-randr.c
+++ b/src/vdagent/x11-randr.c
@@ -629,19 +629,28 @@ static int enabled_monitors(VDAgentMonitorsConfigV2 *mon)
static int same_monitor_configs(VDAgentMonitorsConfigV2 *conf1,
VDAgentMonitorsConfigV2 *conf2)
{
- int i;
-
if (conf1 == NULL || conf2 == NULL ||
conf1->num_of_monitors != conf2->num_of_monitors)
return 0;
- for (i = 0; i < conf1->num_of_monitors; i++) {
+ for (size_t i = 0; i < conf1->num_of_monitors; i++) {
VDAgentMonConfigV2 *mon1 = &conf1->monitors[i];
- VDAgentMonConfigV2 *mon2 = &conf2->monitors[i];
- /* NOTE: we don't compare depth. */
- if (mon1->x != mon2->x || mon1->y != mon2->y ||
- mon1->width != mon2->width || mon1->height != mon2->height)
+ int found = 0;
+
+ for (size_t j = 0; j < conf1->num_of_monitors; j++) {
+ VDAgentMonConfigV2 *mon2 = &conf2->monitors[j];
+ /* NOTE: we don't compare depth. */
+ if (mon1->guest_output_id == mon2->guest_output_id &&
+ mon1->x == mon2->x && mon1->y == mon2->y &&
+ mon1->width == mon2->width && mon1->height == mon2->height) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
return 0;
+ }
}
return 1;
}
@@ -688,6 +697,7 @@ static VDAgentMonitorsConfigV2 *get_current_mon_config(struct vdagent_x11 *x11)
mon_config->monitors[i].y = crtc->y;
mon_config->monitors[i].width = mode->width;
mon_config->monitors[i].height = mode->height;
+ mon_config->monitors[i].guest_output_id = i;
num_of_monitors = i + 1;
}
mon_config->num_of_monitors = num_of_monitors;
@@ -713,8 +723,8 @@ static void dump_monitors_config(struct vdagent_x11 *x11,
m = &mon_config->monitors[i];
if (!monitor_enabled(m))
continue;
- syslog(LOG_DEBUG, " monitor %d, config %dx%d+%d+%d",
- i, m->width, m->height, m->x, m->y);
+ syslog(LOG_DEBUG, " monitor guest_output_id: %d, config %dx%d+%d+%d",
+ m->guest_output_id, m->width, m->height, m->x, m->y);
}
}
@@ -733,7 +743,7 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
int fallback)
{
int primary_w, primary_h;
- int i, real_num_of_monitors = 0;
+ int i;
VDAgentMonitorsConfigV2 *curr = NULL;
if (!x11->has_xrandr)
@@ -748,43 +758,63 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
dump_monitors_config(x11, mon_config, "from guest");
}
- for (i = 0; i < mon_config->num_of_monitors; i++) {
- if (monitor_enabled(&mon_config->monitors[i]))
- real_num_of_monitors = i + 1;
- }
- mon_config->num_of_monitors = real_num_of_monitors;
+ // a boolean mask of present monitor configs for given ID (index in the array)
+ uint8_t presence_mask[MONITOR_SIZE_COUNT] = { 0 };
+
+ // Filter the incoming monitor configs, removing those with an invalid
+ // guest_output_id, so that from now on we have a clean list of configs to
+ // work with.
+ VDAgentMonitorsConfigV2 *filtered_mc = g_malloc(config_size(mon_config->num_of_monitors));
+ filtered_mc->num_of_monitors = 0;
+ filtered_mc->flags = mon_config->flags;
update_randr_res(x11, 0);
- if (mon_config->num_of_monitors > x11->randr.res->noutput) {
- syslog(LOG_WARNING,
- "warning unexpected client request: #mon %d > driver output %d",
- mon_config->num_of_monitors, x11->randr.res->noutput);
- mon_config->num_of_monitors = x11->randr.res->noutput;
+
+ for (i = 0; i < mon_config->num_of_monitors; i++) {
+ if (mon_config->monitors[i].guest_output_id >= x11->randr.res->noutput) {
+ syslog(LOG_WARNING, "Received monitor config guest_output_id %d"
+ " > driver max output nr %d, skipping",
+ mon_config->monitors[i].guest_output_id, x11->randr.res->noutput - 1);
+ continue;
+ }
+
+ if (mon_config->monitors[i].guest_output_id >= MONITOR_SIZE_COUNT) {
+ syslog(LOG_WARNING, "Received monitor config guest_output_id %d"
+ " > monitor count limit %d, skipping",
+ mon_config->monitors[i].guest_output_id, MONITOR_SIZE_COUNT - 1);
+ continue;
+ }
+
+ memcpy(&filtered_mc->monitors[filtered_mc->num_of_monitors],
+ &mon_config->monitors[i],
+ sizeof(VDAgentMonConfigV2));
+
+ presence_mask[mon_config->monitors[i].guest_output_id] = 1;
+
+ filtered_mc->num_of_monitors++;
}
- if (mon_config->num_of_monitors > MONITOR_SIZE_COUNT) {
- syslog(LOG_WARNING, "warning: client send %d monitors, capping at %d",
- mon_config->num_of_monitors, MONITOR_SIZE_COUNT);
- mon_config->num_of_monitors = MONITOR_SIZE_COUNT;
+ if (x11->debug) {
+ dump_monitors_config(x11, filtered_mc, "filtered");
}
- zero_base_monitors(x11, mon_config, &primary_w, &primary_h);
+ zero_base_monitors(x11, filtered_mc, &primary_w, &primary_h);
constrain_to_screen(x11, &primary_w, &primary_h);
if (x11->debug) {
- dump_monitors_config(x11, mon_config, "after zeroing");
+ dump_monitors_config(x11, filtered_mc, "after zeroing");
}
curr = get_current_mon_config(x11);
if (!curr)
goto exit;
- if (same_monitor_configs(mon_config, curr) &&
+ if (same_monitor_configs(filtered_mc, curr) &&
x11->width[0] == primary_w && x11->height[0] == primary_h) {
goto exit;
}
- if (same_monitor_configs(mon_config, x11->randr.failed_conf)) {
+ if (same_monitor_configs(filtered_mc, x11->randr.failed_conf)) {
syslog(LOG_WARNING, "Ignoring previous failed client monitor config");
goto exit;
}
@@ -793,16 +823,20 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
g_unlink(config);
g_free(config);
- for (i = mon_config->num_of_monitors; i < x11->randr.res->noutput; i++)
- xrandr_disable_output(x11, i);
-
- /* First, disable disabled CRTCs... */
- for (i = 0; i < mon_config->num_of_monitors; ++i) {
- if (!monitor_enabled(&mon_config->monitors[i])) {
+ // disable all outputs which we don't have a config for
+ for (i = 0; i < MIN(sizeof(presence_mask), x11->randr.res->noutput); i++) {
+ if (!presence_mask[i]) {
xrandr_disable_output(x11, i);
}
}
+ // disable outputs that are disabled in the monitor configs
+ for (i = 0; i < filtered_mc->num_of_monitors; ++i) {
+ if (!monitor_enabled(&filtered_mc->monitors[i])) {
+ xrandr_disable_output(x11, filtered_mc->monitors[i].guest_output_id);
+ }
+ }
+
/* ... and disable the ones that would be bigger than
* the new RandR screen once it is resized. If they are enabled the
* XRRSetScreenSize call will fail with BadMatch. They will be
@@ -820,9 +854,10 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
if ((x + width > primary_w) || (y + height > primary_h)) {
if (x11->debug)
syslog(LOG_DEBUG, "Disabling monitor %d: %dx%d+%d+%d > (%d,%d)",
- i, width, height, x, y, primary_w, primary_h);
+ curr->monitors[i].guest_output_id,
+ width, height, x, y, primary_w, primary_h);
- xrandr_disable_output(x11, i);
+ xrandr_disable_output(x11, curr->monitors[i].guest_output_id);
}
}
@@ -848,10 +883,10 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
fullscreen it will keep sending the failing config. */
free(x11->randr.failed_conf);
x11->randr.failed_conf =
- malloc(config_size(mon_config->num_of_monitors));
+ malloc(config_size(filtered_mc->num_of_monitors));
if (x11->randr.failed_conf)
- memcpy(x11->randr.failed_conf, mon_config,
- config_size(mon_config->num_of_monitors));
+ memcpy(x11->randr.failed_conf, filtered_mc,
+ config_size(filtered_mc->num_of_monitors));
return;
}
}
@@ -859,34 +894,33 @@ void vdagent_x11_set_monitor_config(struct vdagent_x11 *x11,
/* Finally, we set the new resolutions on RandR CRTCs now that the
* RandR screen is big enough to hold these. */
- for (i = 0; i < mon_config->num_of_monitors; ++i) {
+ for (i = 0; i < filtered_mc->num_of_monitors; ++i) {
int width, height;
int x, y;
- if (!monitor_enabled(&mon_config->monitors[i])) {
+ if (!monitor_enabled(&filtered_mc->monitors[i])) {
continue;
}
/* Try to create the requested resolution */
- width = mon_config->monitors[i].width;
- height = mon_config->monitors[i].height;
- x = mon_config->monitors[i].x;
- y = mon_config->monitors[i].y;
+ width = filtered_mc->monitors[i].width;
+ height = filtered_mc->monitors[i].height;
+ x = filtered_mc->monitors[i].x;
+ y = filtered_mc->monitors[i].y;
if (x11->debug) {
syslog(LOG_DEBUG, "Setting resolution for monitor %d: %dx%d+%d+%d)",
- i, width, height, x, y);
+ filtered_mc->monitors[i].guest_output_id, width, height, x, y);
}
- if (!xrandr_add_and_set(x11, i, x, y, width, height) &&
- enabled_monitors(mon_config) == 1) {
- set_screen_to_best_size(x11, width, height,
- &primary_w, &primary_h);
+ if (!xrandr_add_and_set(x11, filtered_mc->monitors[i].guest_output_id, x, y, width, height) &&
+ enabled_monitors(filtered_mc) == 1)
+ {
+ set_screen_to_best_size(x11, width, height, &primary_w, &primary_h);
break;
}
}
- update_randr_res(x11,
- x11->randr.num_monitors != enabled_monitors(mon_config));
+ update_randr_res(x11, x11->randr.num_monitors != enabled_monitors(filtered_mc));
x11->width[0] = primary_w;
x11->height[0] = primary_h;
--
2.18.0
More information about the Spice-devel
mailing list