diff --git a/webrtc/modules/desktop_capture/BUILD.gn b/webrtc/modules/desktop_capture/BUILD.gn index bb219e2b9..be9658f8b 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 4c0340d6d..67d2fa195 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 6f4a08301..a0195d664 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 c6aabd452..030cb2b77 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 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 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 configuration_monitor_; + scoped_refptr 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 000000000..23c432f60 --- /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 +#include +#include + +#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(&id), 1, NULL); + CFArrayRef window_array = + CGWindowListCreateDescriptionFromArray(window_id_array); + bool minimized = false; + + if (window_array && CFArrayGetCount(window_array)) { + CFDictionaryRef window = reinterpret_cast( + CFArrayGetValueAtIndex(window_array, 0)); + CFBooleanRef on_screen = reinterpret_cast( + 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( + 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(&id), 1, NULL); + CFArrayRef window_array = + CGWindowListCreateDescriptionFromArray(window_id_array); + std::string title; + + if (window_array && CFArrayGetCount(window_array)) { + CFDictionaryRef window = reinterpret_cast( + CFArrayGetValueAtIndex(window_array, 0)); + CFStringRef title_ref = reinterpret_cast( + 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(&id), 1, NULL); + CFArrayRef window_array = + CGWindowListCreateDescriptionFromArray(window_id_array); + int pid = 0; + + if (window_array && CFArrayGetCount(window_array)) { + CFDictionaryRef window = reinterpret_cast( + CFArrayGetValueAtIndex(window_array, 0)); + CFNumberRef pid_ref = reinterpret_cast( + 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( + CFArrayGetValueAtIndex(window_array, i)); + CFStringRef window_title_ref = reinterpret_cast( + CFDictionaryGetValue(window, kCGWindowName)); + CFNumberRef window_id_ref = reinterpret_cast( + CFDictionaryGetValue(window, kCGWindowNumber)); + CFNumberRef window_pid_ref = reinterpret_cast( + 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(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(¤t_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 000000000..b24fc997e --- /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 + +#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 7466f2034..000000000 --- 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 - -#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 000000000..0c3eaa3ab --- /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 + +#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( + CFArrayGetValueAtIndex(window_array, i)); + CFStringRef window_title = reinterpret_cast( + CFDictionaryGetValue(window, kCGWindowName)); + CFNumberRef window_id = reinterpret_cast( + CFDictionaryGetValue(window, kCGWindowNumber)); + CFNumberRef window_layer = reinterpret_cast( + 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 similarity index 56% rename from webrtc/modules/desktop_capture/mac/osx_version.h rename to webrtc/modules/desktop_capture/mac/window_list_utils.h index 0ba49a4e6..7be38506b 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 e88063381..f33720d10 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 #include +#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 last_cursor_; + scoped_refptr + 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 2d5733906..be05bd996 100644 --- a/webrtc/modules/desktop_capture/screen_capturer_mac.mm +++ b/webrtc/modules/desktop_capture/screen_capturer_mac.mm @@ -20,13 +20,13 @@ #include #include +#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 d177fc40c..f60be5d69 100644 --- a/webrtc/modules/desktop_capture/window_capturer_mac.mm +++ b/webrtc/modules/desktop_capture/window_capturer_mac.mm @@ -15,33 +15,21 @@ #include #include +#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(&*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(&id), 1, NULL); @@ -56,7 +44,9 @@ bool IsWindowValid(CGWindowID id) { class WindowCapturerMac : public WindowCapturer { public: - WindowCapturerMac(); + explicit WindowCapturerMac( + scoped_refptr + 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 + full_screen_chrome_window_detector_; + DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac); }; -WindowCapturerMac::WindowCapturerMac() +WindowCapturerMac::WindowCapturerMac( + scoped_refptr + 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