After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 683042 - Boxes goes out of fullscreen right after starting a box fullscreen
Boxes goes out of fullscreen right after starting a box fullscreen
Status: RESOLVED FIXED
Product: gnome-boxes
Classification: Applications
Component: general
3.5.x (unsupported)
Other Linux
: Normal normal
: --
Assigned To: GNOME Boxes maintainer(s)
GNOME Boxes maintainer(s)
Depends on: 683561
Blocks:
 
 
Reported: 2012-08-30 15:48 UTC by Christophe Fergeau
Modified: 2016-03-31 14:00 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
libvirt-machine: remove reconnect_display() (1.60 KB, patch)
2012-09-04 11:09 UTC, Marc-Andre Lureau
needs-work Details | Review
Fix going out of fullscreen right after starting a box (1.90 KB, patch)
2012-09-04 13:05 UTC, Marc-Andre Lureau
accepted-commit_now Details | Review
Fix going out of fullscreen right after starting a box (2.02 KB, patch)
2012-09-05 15:30 UTC, Marc-Andre Lureau
reviewed Details | Review
Only reconnect after initial connect succeds (1.37 KB, patch)
2012-09-07 14:35 UTC, Alexander Larsson
committed Details | Review
Fix multiple connections on startup (2.56 KB, patch)
2012-09-21 13:58 UTC, Alexander Larsson
accepted-commit_now Details | Review
Ensure that you can only connect a Display once (2.23 KB, patch)
2012-09-21 14:06 UTC, Alexander Larsson
reviewed Details | Review
Ensure that you can only connect a Display once (2.23 KB, patch)
2012-09-24 14:29 UTC, Alexander Larsson
committed Details | Review
Fix multiple connections on startup (2.56 KB, patch)
2012-09-24 14:29 UTC, Alexander Larsson
committed Details | Review

Description Christophe Fergeau 2012-08-30 15:48:01 UTC
1) create a new box with an installer ISO which cannot be auto-installed (I've used a rhel6 dvd
2) upon creation, the display is fullscreened (expected behaviour)
3) right after zooming to fullscreen, it goes back to being minimized in the collection view

This does not happen always, but most of the time. When I don't hit it, deleting the box, restarting boxes and retrying makes it happen. I've reproduced this in 3.5.5 and with git master, with spice-gtk 0.12.102 and spice-gtk 0.13. This looks like a race condition, and seems to have been there for quite some time now.
Comment 1 Alexander Larsson 2012-08-31 14:07:23 UTC
I've seen this just starting a STOPPED vm from the collection view.
Comment 2 Christophe Fergeau 2012-08-31 14:12:57 UTC
Yup, me too, but seems to be recent.
Comment 3 Christophe Fergeau 2012-09-03 15:58:20 UTC
Hmm today I can't reproduce the issue with starting a STOPPED vm from the collection view, but I'm still hitting the initial issue.
Comment 4 Marc-Andre Lureau 2012-09-04 11:09:08 UTC
Created attachment 223409 [details] [review]
libvirt-machine: remove reconnect_display()

This handler was a poor-man attempt at dealing with async domain
starting events. It now races with initial display.connect_it(), since
LibvirtMachine.connect_display() is now fully async.

This causes spice server to disconnect the session and Boxes goes out of
fullscreen display.
Comment 5 Marc-Andre Lureau 2012-09-04 11:10:47 UTC
Review of attachment 223409 [details] [review]:

i have to think a bit more about this, the patch I propose may break the "stay-on-display" behaviour, as I can't see who is reconnecting to display when it is rebooted...
Comment 6 Marc-Andre Lureau 2012-09-04 13:05:36 UTC
Created attachment 223422 [details] [review]
Fix going out of fullscreen right after starting a box

When the VM is started, there is an additional handler
reconnect_display() racing with connect_display(), and the spice
server disconnect clients if multi-client isn't enabled.

reconnect_display() is still needed for the "stay on display across
reboots" functionnality. If the VM is actually resumed/started, rely
on it.
Comment 7 Christophe Fergeau 2012-09-05 10:30:46 UTC
Review of attachment 223422 [details] [review]:

A bit worried that variations on this issue will come back to byte us later, but we'll see... ACK with the small changes in the comment folded in.

::: src/libvirt-machine.vala
@@ +31,3 @@
+        if (yield start ())
+            // in which case, reconnect_display() is called when the
+            // machine is running, no need to connect again

// in *this* case, reconnect_display() *will be* called...
Comment 8 Marc-Andre Lureau 2012-09-05 10:36:16 UTC
(In reply to comment #7)
> Review of attachment 223422 [details] [review]:
> 
> A bit worried that variations on this issue will come back to byte us later,
> but we'll see... ACK with the small changes in the comment folded in.
> 
> ::: src/libvirt-machine.vala
> @@ +31,3 @@
> +        if (yield start ())
> +            // in which case, reconnect_display() is called when the
> +            // machine is running, no need to connect again
> 
> // in *this* case, reconnect_display() *will be* called...

my experience with that commit is that it will rely even more on libvirt-glib events.. and that's still very much broken...

Perhaps we want to disable reconnect_display() when !stay_on_display, and still continue here... I'll update thr patch
Comment 9 Alexander Larsson 2012-09-05 11:49:07 UTC
Something like this would also fix it:

    diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
    index e59f380..7f63d4a 100644
    --- a/src/libvirt-machine.vala
    +++ b/src/libvirt-machine.vala
    @@ -27,11 +27,11 @@ public override async void connect_display () {
    if (_connect_display)
    return;
    - _connect_display = true;
    yield start ();
    update_display ();
    display.connect_it ();
    + _connect_display = true;
    }
    struct MachineStat {
Comment 10 Marc-Andre Lureau 2012-09-05 12:07:05 UTC
(In reply to comment #9)
> Something like this would also fix it:
> 
>     diff --git a/src/libvirt-machine.vala b/src/libvirt-machine.vala
>     index e59f380..7f63d4a 100644
>     --- a/src/libvirt-machine.vala
>     +++ b/src/libvirt-machine.vala
>     @@ -27,11 +27,11 @@ public override async void connect_display () {
>     if (_connect_display)
>     return;
>     - _connect_display = true;
>     yield start ();
>     update_display ();
>     display.connect_it ();
>     + _connect_display = true;
>     }
>     struct MachineStat {

Iirc, we used to have connect_display() reentered, but this is no longer the case. So we can probably move _connect_display = true at the end. Though it would no longer prevent correctly several consecutive ongoing connect_display()... It's probably fine too.
Comment 11 Marc-Andre Lureau 2012-09-05 15:30:01 UTC
Created attachment 223551 [details] [review]
Fix going out of fullscreen right after starting a box

When the VM is started, there is an additional handler
reconnect_display() racing with connect_display(), and the spice
server disconnect clients if multi-client isn't enabled.

reconnect_display() is still needed for the "stay on display across
reboots" functionnality.

Since the libvirt-glib events are not so reliable, we still need to
call display.connect_it() right after starting the VM. However,
update_display() is creating a new display widget and a new client
connexion unconditionnaly. With this change, it now verify if the
display is the same to avoid creating multiple racing clients.
Comment 12 Christophe Fergeau 2012-09-06 09:09:25 UTC
Review of attachment 223551 [details] [review]:

I'm currently testing a potential fix for this event issue, dunno if we should differ this patch for a bit longer, or if it's better to just have an additional cleanup patch after libvirt no longer has this issue. Apart from this patch looks good
Comment 13 Christophe Fergeau 2012-09-06 09:11:49 UTC
Review of attachment 223551 [details] [review]:

Hmm let's wait a bit on this, I applied it to test it for a bit, and got a Boxes segfault when trying to connect to a suspended VM. I'll test it more.
Comment 14 Christophe Fergeau 2012-09-06 09:13:54 UTC
Review of attachment 223551 [details] [review]:

Happened a second time on a suspended WinXP VM (out of 2 tests):
(gdb) thread apply all bt

Thread 1 (Thread 0x7fffefe6ba00 (LWP 7209))

  • #0 __GI_raise
    at ../nptl/sysdeps/unix/sysv/linux/raise.c line 64
  • #1 __GI_abort
    at abort.c line 91
  • #2 __libc_message
    at ../sysdeps/unix/sysv/linux/libc_fatal.c line 198
  • #3 malloc_printerr
    at malloc.c line 5027
  • #4 malloc_consolidate
    at malloc.c line 4272
  • #5 _int_malloc
    at malloc.c line 3544
  • #6 __GI___libc_malloc
    at malloc.c line 2928
  • #7 standard_malloc
    at gmem.c line 85
  • #8 g_malloc
    at gmem.c line 159
  • #9 g_slice_alloc
    at gslice.c line 1003
  • #10 g_slice_alloc0
    at gslice.c line 1029
  • #11 boxes_libvirt_machine_update_stats
    at libvirt-machine.c line 2105
  • #12 ___lambda74_
    at libvirt-machine.c line 2392
  • #13 ____lambda74__gsource_func
    at libvirt-machine.c line 2400
  • #14 g_timeout_dispatch
    at gmain.c line 4026
  • #15 g_main_dispatch
    at gmain.c line 2715
  • #16 g_main_context_dispatch
    at gmain.c line 3219
  • #17 g_main_context_iterate
    at gmain.c line 3290
  • #18 g_main_context_iteration
    at gmain.c line 3351
  • #19 g_application_run
    at gapplication.c line 1607
  • #20 boxes_app_run
    at app.c line 1210
  • #21 _vala_main
    at main.c line 936
  • #22 main
    at main.c line 947

Comment 15 Marc-Andre Lureau 2012-09-06 12:59:13 UTC
I can't reproduce that crash, and never got any crash with that patch so far (restoring or not, from wizard creation etc).
Comment 16 Marc-Andre Lureau 2012-09-06 13:09:40 UTC
running with valgrind or MALLOC_CHECK_=2 doesn't detect double-free either
Comment 17 Christophe Fergeau 2012-09-06 14:00:34 UTC
I'm in the opposite situation, I cannot get it not to crash with this VM :( valgrind gives me:

==14963== Invalid read of size 1
==14963==    at 0xA734F2C: g_pointer_bit_lock (gbitlock.c:404)
==14963==    by 0xA745BB4: g_datalist_lock (gdataset.c:213)
==14963==    by 0xA745FFF: g_data_set_internal (gdataset.c:358)
==14963==    by 0xA746618: g_datalist_id_set_data_full (gdataset.c:674)
==14963==    by 0xA2D486E: g_object_real_dispose (gobject.c:1011)
==14963==    by 0x77A8533: spice_channel_dispose (spice-channel.c:154)
==14963==    by 0x77BA803: spice_main_channel_dispose (channel-main.c:272)
==14963==    by 0xA2D994B: g_object_unref (gobject.c:2986)
==14963==    by 0x77ADBF2: spice_channel_delayed_unref (spice-channel.c:2085)
==14963==    by 0xA767ED0: g_idle_dispatch (gmain.c:4806)
==14963==    by 0xA76588C: g_main_dispatch (gmain.c:2715)
==14963==    by 0xA76643C: g_main_context_dispatch (gmain.c:3219)
==14963==  Address 0x17c4c4b0 is 16 bytes inside a block of size 2,960 free'd
==14963==    at 0x4A079AE: free (vg_replace_malloc.c:427)
==14963==    by 0xA76D9EE: standard_free (gmem.c:98)
==14963==    by 0xA76DBB1: g_free (gmem.c:252)
==14963==    by 0xA7864CB: g_slice_free1 (gslice.c:1111)
==14963==    by 0xA2F0115: g_type_free_instance (gtype.c:1935)
==14963==    by 0xA2D9AF7: g_object_unref (gobject.c:3036)
==14963==    by 0x46BE00: block33_data_unref (spice-display.c:545)
==14963==    by 0xA2CBB4C: closure_invoke_notifiers (gclosure.c:249)
==14963==    by 0xA2CD113: g_closure_unref (gclosure.c:599)
==14963==    by 0xA2E39DD: handler_unref_R (gsignal.c:645)
==14963==    by 0xA2E8621: g_signal_handlers_destroy (gsignal.c:2639)
==14963==    by 0xA2D484F: g_object_real_dispose (gobject.c:1010)
==14963==
==14963== Invalid read of size 8
==14963==    at 0xA746007: g_data_set_internal (gdataset.c:360)
==14963==    by 0xA746618: g_datalist_id_set_data_full (gdataset.c:674)
==14963==    by 0xA2D486E: g_object_real_dispose (gobject.c:1011)
==14963==    by 0x77A8533: spice_channel_dispose (spice-channel.c:154)
==14963==    by 0x77BA803: spice_main_channel_dispose (channel-main.c:272)
==14963==    by 0xA2D994B: g_object_unref (gobject.c:2986)
==14963==    by 0x77ADBF2: spice_channel_delayed_unref (spice-channel.c:2085)
==14963==    by 0xA767ED0: g_idle_dispatch (gmain.c:4806)
==14963==    by 0xA76588C: g_main_dispatch (gmain.c:2715)
==14963==    by 0xA76643C: g_main_context_dispatch (gmain.c:3219)
==14963==    by 0xA76661F: g_main_context_iterate (gmain.c:3290)
==14963==    by 0xA7666E3: g_main_context_iteration (gmain.c:3351)
==14963==  Address 0x17c4c4b0 is 16 bytes inside a block of size 2,960 free'd
==14963==    at 0x4A079AE: free (vg_replace_malloc.c:427)
==14963==    by 0xA76D9EE: standard_free (gmem.c:98)
==14963==    by 0xA76DBB1: g_free (gmem.c:252)
==14963==    by 0xA7864CB: g_slice_free1 (gslice.c:1111)
==14963==    by 0xA2F0115: g_type_free_instance (gtype.c:1935)
==14963==    by 0xA2D9AF7: g_object_unref (gobject.c:3036)
==14963==    by 0x46BE00: block33_data_unref (spice-display.c:545)
==14963==    by 0xA2CBB4C: closure_invoke_notifiers (gclosure.c:249)
==14963==    by 0xA2CD113: g_closure_unref (gclosure.c:599)
==14963==    by 0xA2E39DD: handler_unref_R (gsignal.c:645)
==14963==    by 0xA2E8621: g_signal_handlers_destroy (gsignal.c:2639)
==14963==    by 0xA2D484F: g_object_real_dispose (gobject.c:1010)
==14963==
==14963== Invalid read of size 4
==14963==    at 0xA746038: g_data_set_internal (gdataset.c:367)
==14963==    by 0xA746618: g_datalist_id_set_data_full (gdataset.c:674)
==14963==    by 0xA2D486E: g_object_real_dispose (gobject.c:1011)
==14963==    by 0x77A8533: spice_channel_dispose (spice-channel.c:154)
==14963==    by 0x77BA803: spice_main_channel_dispose (channel-main.c:272)
==14963==    by 0xA2D994B: g_object_unref (gobject.c:2986)
==14963==    by 0x77ADBF2: spice_channel_delayed_unref (spice-channel.c:2085)
==14963==    by 0xA767ED0: g_idle_dispatch (gmain.c:4806)
==14963==    by 0xA76588C: g_main_dispatch (gmain.c:2715)
==14963==    by 0xA76643C: g_main_context_dispatch (gmain.c:3219)
==14963==    by 0xA76661F: g_main_context_iterate (gmain.c:3290)
==14963==    by 0xA7666E3: g_main_context_iteration (gmain.c:3351)
==14963==  Address 0xaaaaaaaaaaaaaaa8 is not stack'd, malloc'd or (recently) free'd
==14963==
==14963==
==14963== Process terminating with default action of signal 11 (SIGSEGV)
==14963==  General Protection Fault
==14963==    at 0xA746038: g_data_set_internal (gdataset.c:367)
==14963==    by 0xA746618: g_datalist_id_set_data_full (gdataset.c:674)
==14963==    by 0xA2D486E: g_object_real_dispose (gobject.c:1011)
==14963==    by 0x77A8533: spice_channel_dispose (spice-channel.c:154)
==14963==    by 0x77BA803: spice_main_channel_dispose (channel-main.c:272)
==14963==    by 0xA2D994B: g_object_unref (gobject.c:2986)
==14963==    by 0x77ADBF2: spice_channel_delayed_unref (spice-channel.c:2085)
==14963==    by 0xA767ED0: g_idle_dispatch (gmain.c:4806)
==14963==    by 0xA76588C: g_main_dispatch (gmain.c:2715)
==14963==    by 0xA76643C: g_main_context_dispatch (gmain.c:3219)
==14963==    by 0xA76661F: g_main_context_iterate (gmain.c:3290)
==14963==    by 0xA7666E3: g_main_context_iteration (gmain.c:3351)

Not much clue as to what to do next :(
Comment 18 Marc-Andre Lureau 2012-09-07 10:46:31 UTC
please retest the second patch with patch from 683561
Comment 19 Alexander Larsson 2012-09-07 13:23:11 UTC
Woa, this one is iffy.

The patch causes us to create a new SpiceDisplay, notice that its the same as the old one, yet we still call session.connect () but not on the new SpiceDisplay but the old one. This will cause it to first disconnect, and the connect again.

spice_session_disconnect() calls spice_channel_destroy() on the old channel, but does not remove them from the session->channels ring, instead it relies on that happening in spice_session_channel_destroy which is called from spice_channel_dispose().

However, since we've connected to the main channel the spice_channel_coroutine is running (or at least scheduled), which has a ref on the channel. So, it doesn't actually dispose the channel yet, so its not removed from the session->channels list. Its also not told to stop connecting, so we end up with two main channel coroutines in the session, both connecting to the same spice server.

The first succeeds, then the second, then the first gets kicked off by the second, so we get a disconnected error. This results in the SpiceSession object
disconnection code running again, which correctly destroys the second channel (which is now correctly connected) and then the first channel. However, when the first channel is destroyed using spice_channel_destroy() the *second* time it unrefs the spice channel *again*, essentially stealing the ref that the coroutine for that channel owns, and then when we eventually schedule back to that corouting we crash as it has been freed.

I tried to add a g_object_run_dispose() call to spice_channel_destroy() to ensure that we correctly remove the channel from session->channels, but this leads to other problems, as it NULLs out channel->session which later causes the running coroutine to crash.

I think boxes shouldn't be  calling connect twice on the same display anyway, which would fix this. But its also bad that we can end up with two main channels in a session.
Comment 20 Alexander Larsson 2012-09-07 14:32:00 UTC
Also, i don't see how the patch in 683561 would help things. There is still a ref from spice-channel.c:channel_connect() that will make the channel_destroy not dispose => not remove from session. So, you will still get two connecting channels.

Additionally, even if the disconnect did work, it would still connect, disconnect and then connect again, which seems pretty stupid.
Comment 21 Alexander Larsson 2012-09-07 14:35:17 UTC
Created attachment 223767 [details] [review]
Only reconnect after initial connect succeds

Otherwise we race with connect_display() which causes us to
connect twice during startup.
Comment 22 Alexander Larsson 2012-09-07 14:42:56 UTC
Attachment 223767 [details] pushed as 7fb07ef - Only reconnect after initial connect succeds
Comment 23 Marc-Andre Lureau 2012-09-07 17:30:03 UTC
Although I thought also it would work, sadly, the last patch doesn't, we still get a 2nd reconnect when the VM is started: the event is received later on, not necessarily during yield start() time.

I guess your libvirt was broken and you didn't receive all events when you tested your patch, or just some other raciness..
Comment 24 Alexander Larsson 2012-09-21 11:33:58 UTC
Also, the patch seems to have regressed password support.
Machine.set_password_needed() does:
        if (needed) {
            password_entry.grab_focus ();
            machine.display = null;
        }

And then on enter we machine.connect_display.begin () again, but now _connect_display is true so we ignore this :/
Comment 25 Alexander Larsson 2012-09-21 13:58:09 UTC
Created attachment 224927 [details] [review]
Fix multiple connections on startup

This is a better fix for bug 683042 (where we connect twice
when clicking on a box). It fixes the race where we connect twice
as well as fix the regression where password authentication was
broken.

We now handle the race by making connect_display() safe to run
multiple times by:
 * Making update_display() only create a display if needed.
   This is safe as we always clear the display property before
   reconnecting.
 * The Display.connect_it() method was changed to only connect
   once.

Additionally we make reconnect_display() only reconnect if there
is already a display. This means that if we hit reconnect_display() before
the initial connect_display() has started connecting we don't connect.
This ensures connect_display() does the actual connection, so that it
can properly report any errors.
Comment 26 Alexander Larsson 2012-09-21 14:06:47 UTC
Created attachment 224928 [details] [review]
Ensure that you can only connect a Display once

We currently handle reconnecting by creating a new Display object
anyway. But we make Display.connect_it() callable mutlpiple
times (all but first are ignored) so that we can handle
some activation races better.
Comment 27 Alexander Larsson 2012-09-21 14:07:19 UTC
I got these in the wrong order, the second one should be applied first.
Comment 28 Christophe Fergeau 2012-09-24 09:18:28 UTC
Review of attachment 224928 [details] [review]:

The approach looks good to me, however 'connected' should be reset to false in disconnect_it()
'mutlpiple' typo in the commit log.

::: src/vnc-display.vala
@@ +117,3 @@
+        if (connected)
+            return;
+        connected = true;

This can throw so resetting 'connected' to false when there's a exception would look better. However, if it's reset to 'false' in disconnect_it(), this might not be strictly required.
Comment 29 Christophe Fergeau 2012-09-24 09:18:31 UTC
Review of attachment 224928 [details] [review]:

The approach looks good to me, however 'connected' should be reset to false in disconnect_it()
'mutlpiple' typo in the commit log.

::: src/vnc-display.vala
@@ +117,3 @@
+        if (connected)
+            return;
+        connected = true;

This can throw so resetting 'connected' to false when there's a exception would look better. However, if it's reset to 'false' in disconnect_it(), this might not be strictly required.
Comment 30 Christophe Fergeau 2012-09-24 09:23:30 UTC
Review of attachment 224927 [details] [review]:

Looks good, would be nice to get this in for 3.6 if we get freeze break approval.
Comment 31 Alexander Larsson 2012-09-24 13:06:57 UTC
> The approach looks good to me, however 'connected' should be reset to false in
> disconnect_it()

The whole point is that we should not really re-use a single Display instance for connecting multiple times, but rather create a new one, because of issues with reusing the Display, *including* once its disconnected. (i.e. in comment 19 above we call disconnect and then connect on the same display and it breaks shit).
Comment 32 Christophe Fergeau 2012-09-24 13:34:12 UTC
(In reply to comment #31)
> > The approach looks good to me, however 'connected' should be reset to false in
> > disconnect_it()
> 
> The whole point is that we should not really re-use a single Display instance
> for connecting multiple times, but rather create a new one, because of issues
> with reusing the Display, *including* once its disconnected. (i.e. in comment
> 19 above we call disconnect and then connect on the same display and it breaks
> shit).

It seems we are missing error handling in some cases: LibvirtMachine::connect_display() sets display to non-null in update_display(), and then calls display.connect_it() which can fail in VncDisplay. In this case we'd end up with a non-null Display, but not being connected. I didn't see anything handling errors from connect_display()
Comment 33 Alexander Larsson 2012-09-24 14:22:53 UTC
App.select_item calls connect_display and handles errors, which is the main way this runs.

However, it is correct that we fail to report errors in some cases, like when entering a password or when reconnecting. The reconnecting part will no longer race with the initial connect_display with the patch, but it may fail to report a connection error in the stay_on_display case.

Neither of these report any errors currently though, so this is not really a regression.
Comment 34 Alexander Larsson 2012-09-24 14:29:14 UTC
Created attachment 225067 [details] [review]
Ensure that you can only connect a Display once

We currently handle reconnecting by creating a new Display object
anyway. But we make Display.connect_it() callable multiple
times (all but first are ignored) so that we can handle
some activation races better.
Comment 35 Alexander Larsson 2012-09-24 14:29:18 UTC
Created attachment 225068 [details] [review]
Fix multiple connections on startup

This is a better fix for bug 683042 (where we connect twice
when clicking on a box). It fixes the race where we connect twice
as well as fix the regression where password authentication was
broken.

We now handle the race by making connect_display() safe to run
multiple times by:
 * Making update_display() only create a display if needed.
   This is safe as we always clear the display property before
   reconnecting.
 * The Display.connect_it() method was changed to only connect
   once.

Additionally we make reconnect_display() only reconnect if there
is already a display. This means that if we hit reconnect_display() before
the initial connect_display() has started connecting we don't connect.
This ensures connect_display() does the actual connection, so that it
can properly report any errors.
Comment 36 Alexander Larsson 2012-09-24 14:29:43 UTC
New patches in right order with typos fixed.
Comment 37 Christophe Fergeau 2012-09-24 14:36:33 UTC
Review of attachment 225067 [details] [review]:

Needs break request
Comment 38 Christophe Fergeau 2012-09-24 14:40:46 UTC
Review of attachment 225068 [details] [review]:

.
Comment 39 Alexander Larsson 2012-09-25 09:23:50 UTC
Attachment 225067 [details] pushed as 36589a3 - Ensure that you can only connect a Display once
Attachment 225068 [details] pushed as 0d5f162 - Fix multiple connections on startup