Implement a work around for Chrome full-screen tab switch on Mac.

Chrome creates a new window in full-screen and minimizes the old window when a tab is switched to full-screen.
We try to find the new window to continue capturing for window sharing.

BUG=crbug/385294
R=sergeyu@chromium.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6629 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn
index bb219e2..be9658f 100644
--- a/webrtc/modules/desktop_capture/BUILD.gn
+++ b/webrtc/modules/desktop_capture/BUILD.gn
@@ -37,10 +37,12 @@
     "mac/desktop_configuration.mm",
     "mac/desktop_configuration_monitor.h",
     "mac/desktop_configuration_monitor.cc",
-    "mac/osx_version.h",
-    "mac/osx_version.cc",
+    "mac/full_screen_chrome_window_detector.cc",
+    "mac/full_screen_chrome_window_detector.h",
     "mac/scoped_pixel_buffer_object.cc",
     "mac/scoped_pixel_buffer_object.h",
+    "mac/window_list_utils.cc",
+    "mac/window_list_utils.h",
     "mouse_cursor.cc",
     "mouse_cursor.h",
     "mouse_cursor_monitor.h",
diff --git a/webrtc/modules/desktop_capture/OWNERS b/webrtc/modules/desktop_capture/OWNERS
index 4c0340d..67d2fa1 100644
--- a/webrtc/modules/desktop_capture/OWNERS
+++ b/webrtc/modules/desktop_capture/OWNERS
@@ -1,4 +1,5 @@
 alexeypa@chromium.org
+jiayl@webrtc.org
 sergeyu@chromium.org
 wez@chromium.org
 
diff --git a/webrtc/modules/desktop_capture/desktop_capture.gypi b/webrtc/modules/desktop_capture/desktop_capture.gypi
index 6f4a083..a0195d6 100644
--- a/webrtc/modules/desktop_capture/desktop_capture.gypi
+++ b/webrtc/modules/desktop_capture/desktop_capture.gypi
@@ -38,10 +38,12 @@
         "mac/desktop_configuration.mm",
         "mac/desktop_configuration_monitor.h",
         "mac/desktop_configuration_monitor.cc",
-        "mac/osx_version.h",
-        "mac/osx_version.cc",
+        "mac/full_screen_chrome_window_detector.cc",
+        "mac/full_screen_chrome_window_detector.h",
         "mac/scoped_pixel_buffer_object.cc",
         "mac/scoped_pixel_buffer_object.h",
+        "mac/window_list_utils.cc",
+        "mac/window_list_utils.h",
         "mouse_cursor.cc",
         "mouse_cursor.h",
         "mouse_cursor_monitor.h",
diff --git a/webrtc/modules/desktop_capture/desktop_capture_options.h b/webrtc/modules/desktop_capture/desktop_capture_options.h
index c6aabd4..030cb2b 100644
--- a/webrtc/modules/desktop_capture/desktop_capture_options.h
+++ b/webrtc/modules/desktop_capture/desktop_capture_options.h
@@ -19,6 +19,7 @@
 
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
+#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
 #endif
 
 namespace webrtc {
@@ -50,6 +51,14 @@
   void set_configuration_monitor(scoped_refptr<DesktopConfigurationMonitor> m) {
     configuration_monitor_ = m;
   }
+
+  FullScreenChromeWindowDetector* full_screen_chrome_window_detector() const {
+    return full_screen_window_detector_;
+  }
+  void set_full_screen_chrome_window_detector(
+      scoped_refptr<FullScreenChromeWindowDetector> detector) {
+    full_screen_window_detector_ = detector;
+  }
 #endif
 
   // Flag indicating that the capturer should use screen change notifications.
@@ -82,6 +91,7 @@
 
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
   scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
+  scoped_refptr<FullScreenChromeWindowDetector> full_screen_window_detector_;
 #endif
 
 #if defined(WEBRTC_WIN)
diff --git a/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc b/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
new file mode 100644
index 0000000..23c432f
--- /dev/null
+++ b/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
@@ -0,0 +1,244 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
+
+#include <assert.h>
+#include <libproc.h>
+#include <string>
+
+#include "webrtc/base/macutils.h"
+#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
+#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
+#include "webrtc/system_wrappers/interface/logging.h"
+
+
+namespace webrtc {
+
+namespace {
+
+const int64_t kUpdateIntervalMs = 500;
+
+// Returns true if the window is minimized.
+bool IsWindowMinimized(CGWindowID id) {
+  CFArrayRef window_id_array =
+      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
+  CFArrayRef window_array =
+      CGWindowListCreateDescriptionFromArray(window_id_array);
+  bool minimized = false;
+
+  if (window_array && CFArrayGetCount(window_array)) {
+    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, 0));
+    CFBooleanRef on_screen =  reinterpret_cast<CFBooleanRef>(
+        CFDictionaryGetValue(window, kCGWindowIsOnscreen));
+
+    minimized = !on_screen;
+  }
+
+  CFRelease(window_id_array);
+  CFRelease(window_array);
+
+  return minimized;
+}
+
+// Returns true if the window is occupying a full screen.
+bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
+                        CFDictionaryRef window) {
+  bool fullscreen = false;
+
+  CFDictionaryRef bounds_ref = reinterpret_cast<CFDictionaryRef>(
+      CFDictionaryGetValue(window, kCGWindowBounds));
+
+  CGRect bounds;
+  if (bounds_ref &&
+      CGRectMakeWithDictionaryRepresentation(bounds_ref, &bounds)) {
+    for (MacDisplayConfigurations::const_iterator it =
+             desktop_config.displays.begin();
+         it != desktop_config.displays.end(); ++it) {
+      if (it->bounds.equals(DesktopRect::MakeXYWH(bounds.origin.x,
+                                                  bounds.origin.y,
+                                                  bounds.size.width,
+                                                  bounds.size.height))) {
+        fullscreen = true;
+        break;
+      }
+    }
+  }
+
+  return fullscreen;
+}
+
+std::string GetWindowTitle(CGWindowID id) {
+  CFArrayRef window_id_array =
+      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
+  CFArrayRef window_array =
+      CGWindowListCreateDescriptionFromArray(window_id_array);
+  std::string title;
+
+  if (window_array && CFArrayGetCount(window_array)) {
+    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, 0));
+    CFStringRef title_ref =  reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(window, kCGWindowName));
+
+    if (title_ref)
+      rtc::ToUtf8(title_ref, &title);
+  }
+  CFRelease(window_id_array);
+  CFRelease(window_array);
+
+  return title;
+}
+
+int GetWindowOwnerPid(CGWindowID id) {
+  CFArrayRef window_id_array =
+      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
+  CFArrayRef window_array =
+      CGWindowListCreateDescriptionFromArray(window_id_array);
+  int pid = 0;
+
+  if (window_array && CFArrayGetCount(window_array)) {
+    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, 0));
+    CFNumberRef pid_ref =  reinterpret_cast<CFNumberRef>(
+        CFDictionaryGetValue(window, kCGWindowOwnerPID));
+
+    if (pid_ref)
+      CFNumberGetValue(pid_ref, kCFNumberIntType, &pid);
+  }
+  CFRelease(window_id_array);
+  CFRelease(window_array);
+
+  return pid;
+}
+
+// Returns the window that is full-screen and has the same title and owner pid
+// as the input window.
+CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) {
+  int pid = GetWindowOwnerPid(id);
+  std::string title = GetWindowTitle(id);
+
+  // Only get on screen, non-desktop windows.
+  CFArrayRef window_array = CGWindowListCopyWindowInfo(
+      kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
+      kCGNullWindowID);
+  if (!window_array)
+    return kCGNullWindowID;
+
+  CGWindowID full_screen_window = kCGNullWindowID;
+
+  MacDesktopConfiguration desktop_config = MacDesktopConfiguration::GetCurrent(
+      MacDesktopConfiguration::TopLeftOrigin);
+
+  // Check windows to make sure they have an id, title, and use window layer
+  // other than 0.
+  CFIndex count = CFArrayGetCount(window_array);
+  for (CFIndex i = 0; i < count; ++i) {
+    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, i));
+    CFStringRef window_title_ref = reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(window, kCGWindowName));
+    CFNumberRef window_id_ref = reinterpret_cast<CFNumberRef>(
+        CFDictionaryGetValue(window, kCGWindowNumber));
+    CFNumberRef window_pid_ref =  reinterpret_cast<CFNumberRef>(
+        CFDictionaryGetValue(window, kCGWindowOwnerPID));
+
+    if (!window_title_ref || !window_id_ref || !window_pid_ref)
+      continue;
+
+    int window_pid = 0;
+    CFNumberGetValue(window_pid_ref, kCFNumberIntType, &window_pid);
+    if (window_pid != pid)
+      continue;
+
+    std::string window_title;
+    if (!rtc::ToUtf8(window_title_ref, &window_title) ||
+        window_title != title) {
+      continue;
+    }
+
+    CGWindowID window_id;
+    CFNumberGetValue(window_id_ref, kCFNumberIntType, &window_id);
+    if (IsWindowFullScreen(desktop_config, window)) {
+      full_screen_window = window_id;
+      break;
+    }
+  }
+
+  CFRelease(window_array);
+  return full_screen_window;
+}
+
+bool IsChromeWindow(CGWindowID id) {
+  int pid = GetWindowOwnerPid(id);
+  char buffer[PROC_PIDPATHINFO_MAXSIZE];
+  int path_length = proc_pidpath(pid, buffer, sizeof(buffer));
+  if (path_length <= 0)
+    return false;
+
+  const char* last_slash = strrchr(buffer, '/');
+  std::string name(last_slash ? last_slash + 1 : buffer);
+  return name.find("Google Chrome") == 0 || name == "Chromium";
+}
+
+}  // namespace
+
+FullScreenChromeWindowDetector::FullScreenChromeWindowDetector()
+    : ref_count_(0) {}
+
+FullScreenChromeWindowDetector::~FullScreenChromeWindowDetector() {}
+
+CGWindowID FullScreenChromeWindowDetector::FindFullScreenWindow(
+    CGWindowID original_window) {
+  if (!IsChromeWindow(original_window) || !IsWindowMinimized(original_window))
+    return kCGNullWindowID;
+
+  CGWindowID full_screen_window_id =
+      FindFullScreenWindowWithSamePidAndTitle(original_window);
+
+  if (full_screen_window_id == kCGNullWindowID)
+    return kCGNullWindowID;
+
+  for (WindowCapturer::WindowList::iterator it = previous_window_list_.begin();
+       it != previous_window_list_.end(); ++it) {
+    if (static_cast<CGWindowID>(it->id) != full_screen_window_id)
+      continue;
+
+    int64_t time_interval =
+        (TickTime::Now() - last_udpate_time_).Milliseconds();
+    LOG(LS_WARNING) << "The full-screen window exists in the list, "
+                    << "which was updated " << time_interval << "ms ago.";
+    return kCGNullWindowID;
+  }
+
+  return full_screen_window_id;
+}
+
+void FullScreenChromeWindowDetector::UpdateWindowListIfNeeded(
+    CGWindowID original_window) {
+  if (IsChromeWindow(original_window) &&
+      (TickTime::Now() - last_udpate_time_).Milliseconds()
+          > kUpdateIntervalMs) {
+    previous_window_list_.clear();
+    previous_window_list_.swap(current_window_list_);
+
+    // No need to update the window list when the window is minimized.
+    if (IsWindowMinimized(original_window)) {
+      previous_window_list_.clear();
+      return;
+    }
+
+    GetWindowList(&current_window_list_);
+    last_udpate_time_ = TickTime::Now();
+  }
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h b/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
new file mode 100644
index 0000000..b24fc99
--- /dev/null
+++ b/webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "webrtc/modules/desktop_capture/window_capturer.h"
+#include "webrtc/system_wrappers/interface/atomic32.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+
+namespace webrtc {
+
+// This is a work around for the Chrome tab full-screen behavior: Chrome
+// creates a new window in full-screen mode to show a tab full-screen and
+// minimizes the old window. To continue capturing in this case, we try to
+// find the new full-screen window using these criteria:
+// 0. The original shared window is minimized.
+// 1. The original shared window's owner application name is "Google Chrome".
+// 2. The original window and the new window have the same title and owner
+// pid.
+// 3. The new window is full-screen.
+// 4. The new window didn't exist at least 500 millisecond ago.
+
+class FullScreenChromeWindowDetector {
+ public:
+  FullScreenChromeWindowDetector();
+
+  void AddRef() { ++ref_count_; }
+  void Release() {
+    if (--ref_count_ == 0)
+      delete this;
+  }
+
+  // Returns the full-screen window in place of the original window if all the
+  // criteria are met, or kCGNullWindowID if no such window found.
+  CGWindowID FindFullScreenWindow(CGWindowID original_window);
+
+  // The caller should call this function periodically, no less than twice per
+  // second.
+  void UpdateWindowListIfNeeded(CGWindowID original_window);
+
+ private:
+  ~FullScreenChromeWindowDetector();
+
+  Atomic32 ref_count_;
+
+  // We cache the last two results of the window list, so
+  // |previous_window_list_| is taken at least 500ms before the next Capture()
+  // call. If we only save the last result, we may get false positive (i.e.
+  // full-screen window exists in the list) if Capture() is called too soon.
+  WindowCapturer::WindowList current_window_list_;
+  WindowCapturer::WindowList previous_window_list_;
+  TickTime last_udpate_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(FullScreenChromeWindowDetector);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
diff --git a/webrtc/modules/desktop_capture/mac/osx_version.cc b/webrtc/modules/desktop_capture/mac/osx_version.cc
deleted file mode 100644
index 7466f20..0000000
--- a/webrtc/modules/desktop_capture/mac/osx_version.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <sys/utsname.h>
-
-#include "webrtc/system_wrappers/interface/logging.h"
-
-namespace webrtc {
-
-namespace {
-
-int GetDarwinVersion() {
-  struct utsname uname_info;
-  if (uname(&uname_info) != 0) {
-    LOG(LS_ERROR) << "uname failed";
-    return 0;
-  }
-
-  if (strcmp(uname_info.sysname, "Darwin") != 0)
-    return 0;
-
-  char* dot;
-  int result = strtol(uname_info.release, &dot, 10);
-  if (*dot != '.') {
-    LOG(LS_ERROR) << "Failed to parse version";
-    return 0;
-  }
-
-  return result;
-}
-
-}  // namespace
-
-bool IsOSLionOrLater() {
-  static int darwin_version = GetDarwinVersion();
-
-  // Verify that the version has been parsed correctly.
-  if (darwin_version < 6) {
-    LOG_F(LS_ERROR) << "Invalid Darwin version: " << darwin_version;
-    abort();
-  }
-
-  // Darwin major version 11 corresponds to OSX 10.7.
-  return darwin_version >= 11;
-}
-
-}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/mac/osx_version.h b/webrtc/modules/desktop_capture/mac/osx_version.h
deleted file mode 100644
index 0ba49a4..0000000
--- a/webrtc/modules/desktop_capture/mac/osx_version.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-namespace webrtc {
-
-// Returns true if the OS version >= OSX 10.7.
-bool IsOSLionOrLater();
-
-}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/mac/window_list_utils.cc b/webrtc/modules/desktop_capture/mac/window_list_utils.cc
new file mode 100644
index 0000000..0c3eaa3
--- /dev/null
+++ b/webrtc/modules/desktop_capture/mac/window_list_utils.cc
@@ -0,0 +1,62 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "webrtc/base/macutils.h"
+
+namespace webrtc {
+
+bool GetWindowList(WindowCapturer::WindowList* windows) {
+  // Only get on screen, non-desktop windows.
+  CFArrayRef window_array = CGWindowListCopyWindowInfo(
+      kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
+      kCGNullWindowID);
+  if (!window_array)
+    return false;
+
+  // Check windows to make sure they have an id, title, and use window layer
+  // other than 0.
+  CFIndex count = CFArrayGetCount(window_array);
+  for (CFIndex i = 0; i < count; ++i) {
+    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
+        CFArrayGetValueAtIndex(window_array, i));
+    CFStringRef window_title = reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(window, kCGWindowName));
+    CFNumberRef window_id = reinterpret_cast<CFNumberRef>(
+        CFDictionaryGetValue(window, kCGWindowNumber));
+    CFNumberRef window_layer = reinterpret_cast<CFNumberRef>(
+        CFDictionaryGetValue(window, kCGWindowLayer));
+    if (window_title && window_id && window_layer) {
+      // Skip windows with layer=0 (menu, dock).
+      int layer;
+      CFNumberGetValue(window_layer, kCFNumberIntType, &layer);
+      if (layer != 0)
+        continue;
+
+      int id;
+      CFNumberGetValue(window_id, kCFNumberIntType, &id);
+      WindowCapturer::Window window;
+      window.id = id;
+      if (!rtc::ToUtf8(window_title, &(window.title)) ||
+          window.title.empty()) {
+        continue;
+      }
+      windows->push_back(window);
+    }
+  }
+
+  CFRelease(window_array);
+  return true;
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/mac/window_list_utils.h b/webrtc/modules/desktop_capture/mac/window_list_utils.h
new file mode 100644
index 0000000..7be3850
--- /dev/null
+++ b/webrtc/modules/desktop_capture/mac/window_list_utils.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
+
+#include "webrtc/modules/desktop_capture/window_capturer.h"
+
+namespace webrtc {
+
+// A helper function to get the on-screen windows.
+bool GetWindowList(WindowCapturer::WindowList* windows);
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_LIST_UTILS_H_
+
diff --git a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
index e880633..f33720d 100644
--- a/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -15,11 +15,12 @@
 #include <Cocoa/Cocoa.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+#include "webrtc/base/macutils.h"
 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "webrtc/modules/desktop_capture/desktop_frame.h"
 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
-#include "webrtc/modules/desktop_capture/mac/osx_version.h"
+#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
 #include "webrtc/modules/desktop_capture/mouse_cursor.h"
 #include "webrtc/system_wrappers/interface/logging.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
@@ -52,6 +53,8 @@
   Callback* callback_;
   Mode mode_;
   scoped_ptr<MouseCursor> last_cursor_;
+  scoped_refptr<FullScreenChromeWindowDetector>
+      full_screen_chrome_window_detector_;
 };
 
 MouseCursorMonitorMac::MouseCursorMonitorMac(
@@ -62,9 +65,12 @@
       window_id_(window_id),
       screen_id_(screen_id),
       callback_(NULL),
-      mode_(SHAPE_AND_POSITION) {
+      mode_(SHAPE_AND_POSITION),
+      full_screen_chrome_window_detector_(
+          options.full_screen_chrome_window_detector()) {
   assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId);
-  if (screen_id != kInvalidScreenId && !IsOSLionOrLater()) {
+  if (screen_id != kInvalidScreenId &&
+      rtc::GetOSVersionName() < rtc::kMacOSLion) {
     // Single screen capture is not supported on pre OS X 10.7.
     screen_id_ = kFullDesktopScreenId;
   }
@@ -115,14 +121,23 @@
   // if the current mouse position is covered by another window and also adjust
   // |position| to make it relative to the window origin.
   if (window_id_ != kCGNullWindowID) {
-    // Get list of windows that may be covering parts of |window_id_|.
+    CGWindowID on_screen_window = window_id_;
+    if (full_screen_chrome_window_detector_) {
+      CGWindowID full_screen_window =
+          full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_);
+
+      if (full_screen_window != kCGNullWindowID)
+        on_screen_window = full_screen_window;
+    }
+
+    // Get list of windows that may be covering parts of |on_screen_window|.
     // CGWindowListCopyWindowInfo() returns windows in order from front to back,
-    // so |window_id_| is expected to be the last in the list.
+    // so |on_screen_window| is expected to be the last in the list.
     CFArrayRef window_array =
         CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly |
                                        kCGWindowListOptionOnScreenAboveWindow |
                                        kCGWindowListOptionIncludingWindow,
-                                   window_id_);
+                                   on_screen_window);
     bool found_window = false;
     if (window_array) {
       CFIndex count = CFArrayGetCount(window_array);
@@ -158,7 +173,7 @@
           if (!CFNumberGetValue(window_number, kCFNumberIntType, &window_id))
             continue;
 
-          if (window_id == window_id_) {
+          if (window_id == on_screen_window) {
             found_window = true;
             if (!window_rect.Contains(position))
               state = OUTSIDE;
diff --git a/webrtc/modules/desktop_capture/screen_capturer_mac.mm b/webrtc/modules/desktop_capture/screen_capturer_mac.mm
index 2d57339..be05bd9 100644
--- a/webrtc/modules/desktop_capture/screen_capturer_mac.mm
+++ b/webrtc/modules/desktop_capture/screen_capturer_mac.mm
@@ -20,13 +20,13 @@
 #include <OpenGL/CGLMacro.h>
 #include <OpenGL/OpenGL.h>
 
+#include "webrtc/base/macutils.h"
 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "webrtc/modules/desktop_capture/desktop_frame.h"
 #include "webrtc/modules/desktop_capture/desktop_geometry.h"
 #include "webrtc/modules/desktop_capture/desktop_region.h"
 #include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
 #include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h"
-#include "webrtc/modules/desktop_capture/mac/osx_version.h"
 #include "webrtc/modules/desktop_capture/mac/scoped_pixel_buffer_object.h"
 #include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
 #include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
@@ -425,7 +425,7 @@
   DesktopFrame* current_frame = queue_.current_frame();
 
   bool flip = false;  // GL capturers need flipping.
-  if (IsOSLionOrLater()) {
+  if (rtc::GetOSVersionName() >= rtc::kMacOSLion) {
     // Lion requires us to use their new APIs for doing screen capture. These
     // APIS currently crash on 10.6.8 if there is no monitor attached.
     if (!CgBlitPostLion(*current_frame, region)) {
@@ -478,7 +478,7 @@
 
 bool ScreenCapturerMac::GetScreenList(ScreenList* screens) {
   assert(screens->size() == 0);
-  if (!IsOSLionOrLater()) {
+  if (rtc::GetOSVersionName() < rtc::kMacOSLion) {
     // Single monitor cast is not supported on pre OS X 10.7.
     Screen screen;
     screen.id = kFullDesktopScreenId;
@@ -496,7 +496,7 @@
 }
 
 bool ScreenCapturerMac::SelectScreen(ScreenId id) {
-  if (!IsOSLionOrLater()) {
+  if (rtc::GetOSVersionName() < rtc::kMacOSLion) {
     // Ignore the screen selection on unsupported OS.
     assert(!current_display_);
     return id == kFullDesktopScreenId;
@@ -874,7 +874,7 @@
   // contents. Although the API exists in OS 10.6, it crashes the caller if
   // the machine has no monitor connected, so we fall back to depcreated APIs
   // when running on 10.6.
-  if (IsOSLionOrLater()) {
+  if (rtc::GetOSVersionName() >= rtc::kMacOSLion) {
     LOG(LS_INFO) << "Using CgBlitPostLion.";
     // No need for any OpenGL support on Lion
     return;
@@ -922,10 +922,11 @@
   LOG(LS_INFO) << "Using GlBlit";
 
   CGLPixelFormatAttribute attributes[] = {
-    // This function does an early return if IsOSLionOrLater(), this code only
-    // runs on 10.6 and can be deleted once 10.6 support is dropped.  So just
-    // keep using kCGLPFAFullScreen even though it was deprecated in 10.6 --
-    // it's still functional there, and it's not used on newer OS X versions.
+    // This function does an early return if GetOSVersionName() >= kMacOSLion,
+    // this code only runs on 10.6 and can be deleted once 10.6 support is
+    // dropped.  So just keep using kCGLPFAFullScreen even though it was
+    // deprecated in 10.6 -- it's still functional there, and it's not used on
+    // newer OS X versions.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
     kCGLPFAFullScreen,
diff --git a/webrtc/modules/desktop_capture/window_capturer_mac.mm b/webrtc/modules/desktop_capture/window_capturer_mac.mm
index d177fc4..f60be5d 100644
--- a/webrtc/modules/desktop_capture/window_capturer_mac.mm
+++ b/webrtc/modules/desktop_capture/window_capturer_mac.mm
@@ -15,33 +15,21 @@
 #include <Cocoa/Cocoa.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+#include "webrtc/base/macutils.h"
+#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
 #include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
+#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
+#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
 #include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/scoped_refptr.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
 
 namespace webrtc {
 
 namespace {
 
-bool CFStringRefToUtf8(const CFStringRef string, std::string* str_utf8) {
-  assert(string);
-  assert(str_utf8);
-  CFIndex length = CFStringGetLength(string);
-  size_t max_length_utf8 =
-      CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
-  str_utf8->resize(max_length_utf8);
-  CFIndex used_bytes;
-  int result = CFStringGetBytes(
-      string, CFRangeMake(0, length), kCFStringEncodingUTF8, 0, false,
-      reinterpret_cast<UInt8*>(&*str_utf8->begin()), max_length_utf8,
-      &used_bytes);
-  if (result != length) {
-    str_utf8->clear();
-    return false;
-  }
-  str_utf8->resize(used_bytes);
-  return true;
-}
-
+// Returns true if the window exists.
 bool IsWindowValid(CGWindowID id) {
   CFArrayRef window_id_array =
       CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
@@ -56,7 +44,9 @@
 
 class WindowCapturerMac : public WindowCapturer {
  public:
-  WindowCapturerMac();
+  explicit WindowCapturerMac(
+      scoped_refptr<FullScreenChromeWindowDetector>
+          full_screen_chrome_window_detector);
   virtual ~WindowCapturerMac();
 
   // WindowCapturer interface.
@@ -70,14 +60,22 @@
 
  private:
   Callback* callback_;
+
+  // The window being captured.
   CGWindowID window_id_;
 
+  scoped_refptr<FullScreenChromeWindowDetector>
+      full_screen_chrome_window_detector_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
 };
 
-WindowCapturerMac::WindowCapturerMac()
+WindowCapturerMac::WindowCapturerMac(
+    scoped_refptr<FullScreenChromeWindowDetector>
+        full_screen_chrome_window_detector)
     : callback_(NULL),
-      window_id_(0) {
+      window_id_(0),
+      full_screen_chrome_window_detector_(full_screen_chrome_window_detector) {
 }
 
 WindowCapturerMac::~WindowCapturerMac() {
@@ -114,7 +112,7 @@
       CFNumberGetValue(window_id, kCFNumberIntType, &id);
       WindowCapturer::Window window;
       window.id = id;
-      if (!CFStringRefToUtf8(window_title, &(window.title)) ||
+      if (!rtc::ToUtf8(window_title, &(window.title)) ||
           window.title.empty()) {
         continue;
       }
@@ -183,9 +181,18 @@
     return;
   }
 
+  CGWindowID on_screen_window = window_id_;
+  if (full_screen_chrome_window_detector_) {
+    CGWindowID full_screen_window =
+        full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_);
+
+    if (full_screen_window != kCGNullWindowID)
+      on_screen_window = full_screen_window;
+  }
+
   CGImageRef window_image = CGWindowListCreateImage(
       CGRectNull, kCGWindowListOptionIncludingWindow,
-      window_id_, kCGWindowImageBoundsIgnoreFraming);
+      on_screen_window, kCGWindowImageBoundsIgnoreFraming);
 
   if (!window_image) {
     callback_->OnCaptureCompleted(NULL);
@@ -218,13 +225,16 @@
   CFRelease(window_image);
 
   callback_->OnCaptureCompleted(frame);
+
+  if (full_screen_chrome_window_detector_)
+    full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
 }
 
 }  // namespace
 
 // static
 WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
-  return new WindowCapturerMac();
+  return new WindowCapturerMac(options.full_screen_chrome_window_detector());
 }
 
 }  // namespace webrtc