aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjiayl@webrtc.org <jiayl@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-07-08 22:05:24 +0000
committerjiayl@webrtc.org <jiayl@webrtc.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-07-08 22:05:24 +0000
commit12b4efefddc0ce727f228fd1a5024e70b4687ac4 (patch)
tree6b430fa07aa3420261a5ab78f597109a83a2a7b3
parente55641d4f70024118a0af989fbf46a77ccd1a241 (diff)
downloadwebrtc-12b4efefddc0ce727f228fd1a5024e70b4687ac4.tar.gz
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
-rw-r--r--webrtc/modules/desktop_capture/BUILD.gn6
-rw-r--r--webrtc/modules/desktop_capture/OWNERS1
-rw-r--r--webrtc/modules/desktop_capture/desktop_capture.gypi6
-rw-r--r--webrtc/modules/desktop_capture/desktop_capture_options.h10
-rw-r--r--webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc244
-rw-r--r--webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h69
-rw-r--r--webrtc/modules/desktop_capture/mac/osx_version.cc54
-rw-r--r--webrtc/modules/desktop_capture/mac/window_list_utils.cc62
-rw-r--r--webrtc/modules/desktop_capture/mac/window_list_utils.h (renamed from webrtc/modules/desktop_capture/mac/osx_version.h)12
-rw-r--r--webrtc/modules/desktop_capture/mouse_cursor_monitor_mac.mm29
-rw-r--r--webrtc/modules/desktop_capture/screen_capturer_mac.mm19
-rw-r--r--webrtc/modules/desktop_capture/window_capturer_mac.mm62
12 files changed, 472 insertions, 102 deletions
diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn
index bb219e2b90..be9658f8b0 100644
--- a/webrtc/modules/desktop_capture/BUILD.gn
+++ b/webrtc/modules/desktop_capture/BUILD.gn
@@ -37,10 +37,12 @@ source_set("desktop_capture") {
"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 4c0340d6da..67d2fa1959 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 6f4a083015..a0195d664e 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 c6aabd4529..030cb2b777 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 @@ class DesktopCaptureOptions {
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 @@ class DesktopCaptureOptions {
#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 0000000000..23c432f60f
--- /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 0000000000..b24fc997e4
--- /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 7466f20342..0000000000
--- 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/window_list_utils.cc b/webrtc/modules/desktop_capture/mac/window_list_utils.cc
new file mode 100644
index 0000000000..0c3eaa3abd
--- /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/osx_version.h b/webrtc/modules/desktop_capture/mac/window_list_utils.h
index 0ba49a4e69..7be38506bb 100644
--- a/webrtc/modules/desktop_capture/mac/osx_version.h
+++ b/webrtc/modules/desktop_capture/mac/window_list_utils.h
@@ -8,9 +8,17 @@
* 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 {
-// Returns true if the OS version >= OSX 10.7.
-bool IsOSLionOrLater();
+// 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 e880633819..f33720d100 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 @@ class MouseCursorMonitorMac : public MouseCursorMonitor {
Callback* callback_;
Mode mode_;
scoped_ptr<MouseCursor> last_cursor_;
+ scoped_refptr<FullScreenChromeWindowDetector>
+ full_screen_chrome_window_detector_;
};
MouseCursorMonitorMac::MouseCursorMonitorMac(
@@ -62,9 +65,12 @@ MouseCursorMonitorMac::MouseCursorMonitorMac(
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 @@ void MouseCursorMonitorMac::Capture() {
// 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 @@ void MouseCursorMonitorMac::Capture() {
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 2d5733906f..be05bd9968 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 @@ void ScreenCapturerMac::Capture(const DesktopRegion& region_to_capture) {
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 @@ void ScreenCapturerMac::SetMouseShapeObserver(
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::GetScreenList(ScreenList* screens) {
}
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 @@ void ScreenCapturerMac::ScreenConfigurationChanged() {
// 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 @@ void ScreenCapturerMac::ScreenConfigurationChanged() {
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 d177fc40c7..f60be5d694 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 @@ bool IsWindowValid(CGWindowID id) {
class WindowCapturerMac : public WindowCapturer {
public:
- WindowCapturerMac();
+ explicit WindowCapturerMac(
+ scoped_refptr<FullScreenChromeWindowDetector>
+ full_screen_chrome_window_detector);
virtual ~WindowCapturerMac();
// WindowCapturer interface.
@@ -70,14 +60,22 @@ class WindowCapturerMac : public WindowCapturer {
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 @@ bool WindowCapturerMac::GetWindowList(WindowList* windows) {
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 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
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 @@ void WindowCapturerMac::Capture(const DesktopRegion& region) {
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