<div dir="ltr"><div><div>Hi<br><br></div>Using a timer for monitor configuration to take place will lead to all kind of issues. (and 2 second is to short for wan, to slow for local, somehow short even for lan)<br><br></div>Instead there should probably be a more robust solution involving the agent to monitor the initial configuration taking place, while the client wouldn't send further monitor configuration. The agent wouldn't have a timer either, it would either succeed or fail to manage this initial configuration and resume client auto-conf.<br><br>nack from me.<br> <br></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Apr 21, 2015 at 10:34 PM, Jonathon Jongsma <span dir="ltr"><<a href="mailto:jjongsma@redhat.com" target="_blank">jjongsma@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">When doing fullscreen auto-conf, we send down a new configuration to the<br>
server before the display chanels are connected. Due to race conditions<br>
in the server, we sometimes get an initial monitors-config message with<br>
the guest's old display state. If the guest happened to have more<br>
displays enabled than we need for auto-conf, those extra displays<br>
windows will remain open, and the auto-conf will not succeed. To avoid<br>
this, we delay creating any windows and displays until the guest<br>
responds with a monitor config equal to the one we sent down for<br>
auto-conf. This allows the server some time to "settle", and prevents us<br>
from opening more windows on the client than we want. If for some reason<br>
the guest cannot be configured properly within a certain time frame, the<br>
client will go ahead and open displays to match the current state of the<br>
server.<br>
<br>
Resolves: rhbz#1200750<br>
---<br>
src/virt-viewer-session-spice.c | 121 +++++++++++++++++++++++++++++++++++++++-<br>
1 file changed, 118 insertions(+), 3 deletions(-)<br>
<br>
diff --git a/src/virt-viewer-session-spice.c b/src/virt-viewer-session-spice.c<br>
index 4620bba..d0a7ab5 100644<br>
--- a/src/virt-viewer-session-spice.c<br>
+++ b/src/virt-viewer-session-spice.c<br>
@@ -66,6 +66,7 @@ struct _VirtViewerSessionSpicePrivate {<br>
AutoConfState auto_conf_state;<br>
GList *display_channels;<br>
GArray *fullscreen_config;<br>
+ guint auto_conf_timer;<br>
};<br>
<br>
#define VIRT_VIEWER_SESSION_SPICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), VIRT_VIEWER_TYPE_SESSION_SPICE, VirtViewerSessionSpicePrivate))<br>
@@ -704,9 +705,8 @@ destroy_display(gpointer data)<br>
}<br>
<br>
static void<br>
-virt_viewer_session_spice_display_monitors(SpiceChannel *channel,<br>
- GParamSpec *pspec G_GNUC_UNUSED,<br>
- VirtViewerSessionSpice *self)<br>
+virt_viewer_session_spice_process_monitors_for_display_channel(VirtViewerSessionSpice *self,<br>
+ SpiceChannel *channel)<br>
{<br>
GArray *monitors = NULL;<br>
GPtrArray *displays = NULL;<br>
@@ -759,6 +759,105 @@ virt_viewer_session_spice_display_monitors(SpiceChannel *channel,<br>
<br>
}<br>
<br>
+static gboolean<br>
+virt_viewer_session_spice_displays_match_initial_config(VirtViewerSessionSpice *self)<br>
+{<br>
+ cairo_region_t *region1, *region2;<br>
+ GList *l;<br>
+ int i;<br>
+ GArray *rects = g_array_new(FALSE, TRUE, sizeof(GdkRectangle));<br>
+ VirtViewerApp *app = virt_viewer_session_get_app(VIRT_VIEWER_SESSION(self));<br>
+ GList *initial_displays = virt_viewer_app_get_initial_displays(app);<br>
+ gboolean match = FALSE;<br>
+<br>
+ if (!virt_viewer_app_get_fullscreen(app))<br>
+ goto cleanup;<br>
+<br>
+ for (l = self->priv->display_channels; l != NULL; l = l->next) {<br>
+ GArray *monitors = NULL;<br>
+ g_object_get(l->data,<br>
+ "monitors", &monitors,<br>
+ NULL);<br>
+<br>
+ if (!monitors)<br>
+ continue;<br>
+<br>
+ for (i = 0; i < monitors->len; i++) {<br>
+ SpiceDisplayMonitorConfig *monitor = &g_array_index(monitors, SpiceDisplayMonitorConfig, i);<br>
+<br>
+ if (monitor->width == 0 || monitor->height == 0)<br>
+ continue;<br>
+<br>
+ GdkRectangle rect = {<br>
+ .x = monitor->x,<br>
+ .y = monitor->y,<br>
+ .width = monitor->width,<br>
+ .height = monitor->height<br>
+ };<br>
+ g_array_append_val(rects, rect);<br>
+ }<br>
+ }<br>
+<br>
+ if (rects->len != g_list_length(initial_displays))<br>
+ goto cleanup;<br>
+<br>
+ region1 = cairo_region_create_rectangles((cairo_rectangle_int_t*)rects->data,<br>
+ rects->len);<br>
+ region2 = cairo_region_create_rectangles((cairo_rectangle_int_t*)self->priv->fullscreen_config->data,<br>
+ self->priv->fullscreen_config->len);<br>
+<br>
+ match = cairo_region_equal(region1, region2);<br>
+<br>
+ cairo_region_destroy(region1);<br>
+ cairo_region_destroy(region2);<br>
+<br>
+cleanup:<br>
+ g_list_free(initial_displays);<br>
+ g_array_unref(rects);<br>
+<br>
+ return match;<br>
+}<br>
+<br>
+static void<br>
+virt_viewer_session_spice_auto_conf_complete(VirtViewerSessionSpice *self)<br>
+{<br>
+ GList *l;<br>
+<br>
+ if (self->priv->auto_conf_timer) {<br>
+ g_source_remove(self->priv->auto_conf_timer);<br>
+ self->priv->auto_conf_timer = 0;<br>
+ }<br>
+<br>
+ self->priv->auto_conf_state = AUTO_CONF_STATE_COMPLETE;<br>
+<br>
+ /* now process all pending display channels, creating displays, etc */<br>
+ for (l = self->priv->display_channels; l != NULL; l = l->next)<br>
+ virt_viewer_session_spice_process_monitors_for_display_channel(self, l->data);<br>
+}<br>
+<br>
+static void<br>
+virt_viewer_session_spice_display_monitors(SpiceChannel *channel,<br>
+ GParamSpec *pspec G_GNUC_UNUSED,<br>
+ VirtViewerSessionSpice *self)<br>
+{<br>
+ if (self->priv->auto_conf_state == AUTO_CONF_STATE_SENT) {<br>
+<br>
+ /* At startup, the server can sometimes send up old monitor<br>
+ * configurations even if we've sent the initial auto conf. This will<br>
+ * generally be followed by another monitor update with the correct<br>
+ * configuration. So if we've sent our auto-conf configuration, check<br>
+ * whether this is the correct config and process all pending updates.<br>
+ * If not, wait for the next update. */<br>
+ if (virt_viewer_session_spice_displays_match_initial_config(self))<br>
+ virt_viewer_session_spice_auto_conf_complete(self);<br>
+ else<br>
+ g_debug("Displays don't match initial config. Waiting for next monitor config update");<br>
+ return;<br>
+ }<br>
+<br>
+ virt_viewer_session_spice_process_monitors_for_display_channel(self, channel);<br>
+}<br>
+<br>
static void<br>
virt_viewer_session_spice_channel_new(SpiceSession *s,<br>
SpiceChannel *channel,<br>
@@ -832,6 +931,16 @@ property_notify_do_auto_conf(GObject *gobject G_GNUC_UNUSED,<br>
}<br>
<br>
static gboolean<br>
+timeout_complete_auto_conf(gpointer data)<br>
+{<br>
+ VirtViewerSessionSpice *self = VIRT_VIEWER_SESSION_SPICE(data);<br>
+ g_debug("Guest wasn't configured in time, completing auto-conf");<br>
+ virt_viewer_session_spice_auto_conf_complete(self);<br>
+<br>
+ return FALSE;<br>
+}<br>
+<br>
+static gboolean<br>
virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self)<br>
{<br>
GdkScreen *screen = gdk_screen_get_default();<br>
@@ -901,6 +1010,12 @@ virt_viewer_session_spice_fullscreen_auto_conf(VirtViewerSessionSpice *self)<br>
spice_main_send_monitor_config(cmain);<br>
self->priv->auto_conf_state = AUTO_CONF_STATE_SENT;<br>
<br>
+ /* Wait for the guest to respond with the exact configuration we just sent<br>
+ * down. If the configuration doesn't happen before the timeout, just show<br>
+ * the current displays */<br>
+ self->priv->auto_conf_timer =<br>
+ g_timeout_add_seconds(2, timeout_complete_auto_conf, self);<br>
+<br>
self->priv->fullscreen_config = config;<br>
return TRUE;<br>
}<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.1.0<br>
<br>
_______________________________________________<br>
virt-tools-list mailing list<br>
<a href="mailto:virt-tools-list@redhat.com">virt-tools-list@redhat.com</a><br>
<a href="https://www.redhat.com/mailman/listinfo/virt-tools-list" target="_blank">https://www.redhat.com/mailman/listinfo/virt-tools-list</a><br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br><div class="gmail_signature">Marc-André Lureau</div>
</div>