wm: Avoid leak if a duplicate login window is mapped.

This is just a guess at a possible cause for a failed assert
that I've noticed on the crash server.  If a second WebUI,
background, or wizard/guest window gets mapped,
LoginController should unregister its interest in the
earlier window.

BUG=chromium-os:18809
TEST=added a test for the duplicate-wizard-window case

Change-Id: I46ec5b1c3277dcc2f87e6a3b0a4e30d1bc448335
Reviewed-on: http://gerrit.chromium.org/gerrit/5495
Tested-by: Daniel Erat <[email protected]>
Reviewed-by: Daniel Erat <[email protected]>
diff --git a/login/login_controller.cc b/login/login_controller.cc
index 702770d..90dbfa0 100644
--- a/login/login_controller.cc
+++ b/login/login_controller.cc
@@ -241,8 +241,10 @@
 
   switch (win->type()) {
     case chromeos::WM_IPC_WINDOW_LOGIN_GUEST: {
-      if (wizard_window_)
+      if (wizard_window_) {
         LOG(WARNING) << "Two wizard windows encountered";
+        registrar_.UnregisterForWindowEvents(wizard_window_->xid());
+      }
       wizard_window_ = win;
       wm_->focus_manager()->UseClickToFocusForWindow(
           wizard_window_, FocusManager::PASS_CLICKS_THROUGH);
@@ -275,8 +277,10 @@
       break;
     }
     case chromeos::WM_IPC_WINDOW_LOGIN_BACKGROUND: {
-      if (background_window_)
+      if (background_window_) {
         LOG(WARNING) << "Two background windows encountered";
+        registrar_.UnregisterForWindowEvents(background_window_->xid());
+      }
       background_window_ = win;
       wm_->focus_manager()->UseClickToFocusForWindow(
           background_window_, FocusManager::PASS_CLICKS_THROUGH);
@@ -284,8 +288,10 @@
       break;
     }
     case chromeos::WM_IPC_WINDOW_LOGIN_WEBUI: {
-      if (webui_window_)
+      if (webui_window_) {
         LOG(WARNING) << "Two webui browser windows encountered";
+        registrar_.UnregisterForWindowEvents(webui_window_->xid());
+      }
       webui_window_ = win;
       wm_->focus_manager()->UseClickToFocusForWindow(
           webui_window_, FocusManager::PASS_CLICKS_THROUGH);
diff --git a/login/login_controller_test.cc b/login/login_controller_test.cc
index 3d3753f..281c7a1 100644
--- a/login/login_controller_test.cc
+++ b/login/login_controller_test.cc
@@ -1295,6 +1295,31 @@
   EXPECT_EQ(webui_window_xid_, GetActiveWindowProperty());
 }
 
+// Check that when we see duplicate wizard windows, we unregister our interest
+// in the first one when the second one is mapped so that we won't fail an
+// assert if the first window is destroyed later.  This is just a shot in the
+// dark as a possible cause of http://crosbug.com/18809.
+TEST_F(LoginControllerTest, HandleDuplicateWindows) {
+  CreateWebUILoginWindow();
+
+  XWindow wizard_xid1 = CreateSimpleWindow();
+  wm_->wm_ipc()->SetWindowType(
+      wizard_xid1, chromeos::WM_IPC_WINDOW_LOGIN_GUEST, NULL);
+  SendInitialEventsForWindow(wizard_xid1);
+
+  XWindow wizard_xid2 = CreateSimpleWindow();
+  wm_->wm_ipc()->SetWindowType(
+      wizard_xid2, chromeos::WM_IPC_WINDOW_LOGIN_GUEST, NULL);
+  SendInitialEventsForWindow(wizard_xid2);
+
+  XEvent event;
+  xconn_->UnmapWindow(wizard_xid1);
+  xconn_->InitUnmapEvent(&event, wizard_xid1);
+  wm_->HandleEvent(&event);
+  xconn_->InitDestroyWindowEvent(&event, wizard_xid1);
+  wm_->HandleEvent(&event);
+}
+
 // Test that we focus the first controls window as soon as we map it.
 TEST_F(LoginControllerTest, FocusFirstControlsWindowImmediately) {
   // Create just a background window.