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
This commit is contained in:
parent
e55641d4f7
commit
12b4efefdd
@ -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",
|
||||
|
@ -1,4 +1,5 @@
|
||||
alexeypa@chromium.org
|
||||
jiayl@webrtc.org
|
||||
sergeyu@chromium.org
|
||||
wez@chromium.org
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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(¤t_window_list_);
|
||||
last_udpate_time_ = TickTime::Now();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -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_
|
@ -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
|
62
webrtc/modules/desktop_capture/mac/window_list_utils.cc
Normal file
62
webrtc/modules/desktop_capture/mac/window_list_utils.cc
Normal file
@ -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
|
@ -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_
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user