Returns a NULL frame on all platforms if the captured window is closed.
Part of the fix for crbug/360181.
On Mac/Linux, it previously continues capturing even if the window is closed.
Now it stops by returning a NULL frame.
On Windows, it used to stop capturing when the window is minimized. Now fixed to match other platforms.
Note: the crbug still needs a chrome side fix to close the notification bar.
This fix only stops the stream (i.e. stream onended event fired).

BUG=crbug/360181
TESTED=manually tested in Chrome
R=sergeyu@chromium.org

Review URL: https://webrtc-codereview.appspot.com/12329007

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@5977 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index 3ceae31..d177fc4 100644
--- a/modules/desktop_capture/window_capturer_mac.mm
+++ b/modules/desktop_capture/window_capturer_mac.mm
@@ -42,6 +42,18 @@
   return true;
 }
 
+bool IsWindowValid(CGWindowID id) {
+  CFArrayRef window_id_array =
+      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
+  CFArrayRef window_array =
+      CGWindowListCreateDescriptionFromArray(window_id_array);
+  bool valid = window_array && CFArrayGetCount(window_array);
+  CFRelease(window_id_array);
+  CFRelease(window_array);
+
+  return valid;
+}
+
 class WindowCapturerMac : public WindowCapturer {
  public:
   WindowCapturerMac();
@@ -115,22 +127,8 @@
 }
 
 bool WindowCapturerMac::SelectWindow(WindowId id) {
-  // Request description for the specified window to make sure |id| is valid.
-  CGWindowID ids[1];
-  ids[0] = id;
-  CFArrayRef window_id_array =
-      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
-  CFArrayRef window_array =
-      CGWindowListCreateDescriptionFromArray(window_id_array);
-  int results_count = window_array ? CFArrayGetCount(window_array) : 0;
-  CFRelease(window_id_array);
-  CFRelease(window_array);
-
-  if (results_count == 0) {
-    // Could not find the window. It might have been closed.
+  if (!IsWindowValid(id))
     return false;
-  }
-
   window_id_ = id;
   return true;
 }
@@ -180,6 +178,11 @@
 }
 
 void WindowCapturerMac::Capture(const DesktopRegion& region) {
+  if (!IsWindowValid(window_id_)) {
+    callback_->OnCaptureCompleted(NULL);
+    return;
+  }
+
   CGImageRef window_image = CGWindowListCreateImage(
       CGRectNull, kCGWindowListOptionIncludingWindow,
       window_id_, kCGWindowImageBoundsIgnoreFraming);
diff --git a/modules/desktop_capture/window_capturer_win.cc b/modules/desktop_capture/window_capturer_win.cc
index b9764b3..a002185 100644
--- a/modules/desktop_capture/window_capturer_win.cc
+++ b/modules/desktop_capture/window_capturer_win.cc
@@ -182,8 +182,8 @@
     return;
   }
 
-  // Stop capturing if the window has been minimized or hidden.
-  if (IsIconic(window_) || !IsWindowVisible(window_)) {
+  // Stop capturing if the window has been closed or hidden.
+  if (!IsWindow(window_) || !IsWindowVisible(window_)) {
     callback_->OnCaptureCompleted(NULL);
     return;
   }
diff --git a/modules/desktop_capture/window_capturer_x11.cc b/modules/desktop_capture/window_capturer_x11.cc
index baeb894..b641c93 100755
--- a/modules/desktop_capture/window_capturer_x11.cc
+++ b/modules/desktop_capture/window_capturer_x11.cc
@@ -278,6 +278,12 @@
 }
 
 void WindowCapturerLinux::Capture(const DesktopRegion& region) {
+  if (!x_server_pixel_buffer_.IsWindowValid()) {
+    LOG(LS_INFO) << "The window is no longer valid.";
+    callback_->OnCaptureCompleted(NULL);
+    return;
+  }
+
   x_display_->ProcessPendingXEvents();
 
   if (!has_composite_extension_) {
diff --git a/modules/desktop_capture/x11/x_server_pixel_buffer.cc b/modules/desktop_capture/x11/x_server_pixel_buffer.cc
index 6983a6d..be00fa7 100644
--- a/modules/desktop_capture/x11/x_server_pixel_buffer.cc
+++ b/modules/desktop_capture/x11/x_server_pixel_buffer.cc
@@ -213,6 +213,18 @@
   return true;
 }
 
+bool XServerPixelBuffer::IsWindowValid() const {
+  XWindowAttributes attributes;
+  {
+    XErrorTrap error_trap(display_);
+    if (!XGetWindowAttributes(display_, window_, &attributes) ||
+        error_trap.GetLastErrorAndDisable() != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
 void XServerPixelBuffer::Synchronize() {
   if (shm_segment_info_ && !shm_pixmap_) {
     // XShmGetImage can fail if the display is being reconfigured.
diff --git a/modules/desktop_capture/x11/x_server_pixel_buffer.h b/modules/desktop_capture/x11/x_server_pixel_buffer.h
index b81096c..98f263f 100644
--- a/modules/desktop_capture/x11/x_server_pixel_buffer.h
+++ b/modules/desktop_capture/x11/x_server_pixel_buffer.h
@@ -40,6 +40,9 @@
   // Returns the size of the window the buffer was initialized for.
   const DesktopSize& window_size() { return window_size_; }
 
+  // Returns true if the window can be found.
+  bool IsWindowValid() const;
+
   // If shared memory is being used without pixmaps, synchronize this pixel
   // buffer with the root window contents (otherwise, this is a no-op).
   // This is to avoid doing a full-screen capture for each individual