<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>