Implement handling for MS PowerPoint Presentation Mode.

* Introduce a FullScreenWindowDetector to manage routines for updating the list of sources being application agnostic, inspired by FullScreenChromeWindowDetector.
* Introduce a FullScreenApplicationHandler to make a decision about changing window to share in application specific way, inspired by FullScreenChromeWindowDetector.
* Remove FullScreenChromeWindowDetector as redundant.
* Add FullScreenApplicationHandler for MS PowerPoint and Apple Keynote on MacOS.
* Add FullScreenApplicationHandler for MS PowerPoint on Windows.

Bug: webrtc:3852
Change-Id: I06507d929308e85b882b2f8210a025afef7f26a9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156020
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Reviewed-by: Justin Uberti <juberti@webrtc.org>
Reviewed-by: Wez <wez@google.com>
Cr-Commit-Position: refs/heads/master@{#29993}
This commit is contained in:
Roman Gaiu 2019-10-07 11:57:01 -07:00 committed by Commit Bot
parent 831ce5f171
commit b588353543
21 changed files with 798 additions and 260 deletions

View File

@ -101,6 +101,7 @@ NVIDIA Corporation <*@nvidia.com>
Opera Software ASA <*@opera.com>
Optical Tone Ltd <*@opticaltone.com>
Pengutronix e.K. <*@pengutronix.de>
RingCentral, Inc. <*@ringcentral.com>
Sinch AB <*@sinch.com>
struktur AG <*@struktur.de>
Telenor Digital AS <*@telenor.com>

View File

@ -300,6 +300,10 @@ rtc_library("desktop_capture_generic") {
"fake_desktop_capturer.h",
"fallback_desktop_capturer_wrapper.cc",
"fallback_desktop_capturer_wrapper.h",
"full_screen_application_handler.cc",
"full_screen_application_handler.h",
"full_screen_window_detector.cc",
"full_screen_window_detector.h",
"mouse_cursor.cc",
"mouse_cursor.h",
"mouse_cursor_monitor.h",
@ -319,8 +323,8 @@ rtc_library("desktop_capture_generic") {
"mac/desktop_configuration.h",
"mac/desktop_configuration_monitor.cc",
"mac/desktop_configuration_monitor.h",
"mac/full_screen_chrome_window_detector.cc",
"mac/full_screen_chrome_window_detector.h",
"mac/full_screen_mac_application_handler.cc",
"mac/full_screen_mac_application_handler.h",
"mac/window_list_utils.cc",
"mac/window_list_utils.h",
]
@ -431,6 +435,8 @@ rtc_library("desktop_capture_generic") {
"win/dxgi_texture_mapping.h",
"win/dxgi_texture_staging.cc",
"win/dxgi_texture_staging.h",
"win/full_screen_win_application_handler.cc",
"win/full_screen_win_application_handler.h",
"win/scoped_gdi_object.h",
"win/scoped_thread_desktop.cc",
"win/scoped_thread_desktop.h",
@ -470,6 +476,7 @@ rtc_library("desktop_capture_generic") {
"../../system_wrappers:cpu_features_api",
"../../system_wrappers:metrics",
"//third_party/abseil-cpp/absl/memory",
"//third_party/abseil-cpp/absl/strings",
]
if (build_with_mozilla) {

View File

@ -68,6 +68,7 @@ class RTC_EXPORT CroppingWindowCapturer : public DesktopCapturer,
WindowId selected_window() const { return selected_window_; }
WindowId excluded_window() const { return excluded_window_; }
DesktopCapturer* window_capturer() const { return window_capturer_.get(); }
private:
DesktopCaptureOptions options_;

View File

@ -98,26 +98,53 @@ BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) {
class CroppingWindowCapturerWin : public CroppingWindowCapturer {
public:
CroppingWindowCapturerWin(const DesktopCaptureOptions& options)
: CroppingWindowCapturer(options) {}
explicit CroppingWindowCapturerWin(const DesktopCaptureOptions& options)
: CroppingWindowCapturer(options),
full_screen_window_detector_(options.full_screen_window_detector()) {}
void CaptureFrame() override;
private:
bool ShouldUseScreenCapturer() override;
DesktopRect GetWindowRectInVirtualScreen() override;
// Returns either selected by user sourceId or sourceId provided by
// FullScreenWindowDetector
WindowId GetWindowToCapture() const;
// The region from GetWindowRgn in the desktop coordinate if the region is
// rectangular, or the rect from GetWindowRect if the region is not set.
DesktopRect window_region_rect_;
WindowCaptureHelperWin window_capture_helper_;
rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
};
void CroppingWindowCapturerWin::CaptureFrame() {
DesktopCapturer* win_capturer = window_capturer();
if (win_capturer) {
// Update the list of available sources and override source to capture if
// FullScreenWindowDetector returns not zero
if (full_screen_window_detector_) {
full_screen_window_detector_->UpdateWindowListIfNeeded(
selected_window(),
[win_capturer](DesktopCapturer::SourceList* sources) {
return win_capturer->GetSourceList(sources);
});
}
win_capturer->SelectSource(GetWindowToCapture());
}
CroppingWindowCapturer::CaptureFrame();
}
bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
if (!rtc::IsWindows8OrLater() && window_capture_helper_.IsAeroEnabled()) {
return false;
}
const HWND selected = reinterpret_cast<HWND>(selected_window());
const HWND selected = reinterpret_cast<HWND>(GetWindowToCapture());
// Check if the window is visible on current desktop.
if (!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(selected)) {
return false;
@ -207,7 +234,7 @@ DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() {
TRACE_EVENT0("webrtc",
"CroppingWindowCapturerWin::GetWindowRectInVirtualScreen");
DesktopRect window_rect;
HWND hwnd = reinterpret_cast<HWND>(selected_window());
HWND hwnd = reinterpret_cast<HWND>(GetWindowToCapture());
if (!GetCroppedWindowRect(hwnd, /*avoid_cropping_border*/ false, &window_rect,
/*original_rect*/ nullptr)) {
RTC_LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
@ -222,6 +249,15 @@ DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() {
return window_rect;
}
WindowId CroppingWindowCapturerWin::GetWindowToCapture() const {
const auto selected_source = selected_window();
const auto full_screen_source =
full_screen_window_detector_
? full_screen_window_detector_->FindFullScreenWindow(selected_source)
: 0;
return full_screen_source ? full_screen_source : selected_source;
}
} // namespace
// static

View File

@ -9,6 +9,11 @@
*/
#include "modules/desktop_capture/desktop_capture_options.h"
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
#include "modules/desktop_capture/mac/full_screen_mac_application_handler.h"
#elif defined(WEBRTC_WIN)
#include "modules/desktop_capture/win/full_screen_win_application_handler.h"
#endif
namespace webrtc {
@ -32,8 +37,11 @@ DesktopCaptureOptions DesktopCaptureOptions::CreateDefault() {
#endif
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
result.set_configuration_monitor(new DesktopConfigurationMonitor());
result.set_full_screen_chrome_window_detector(
new FullScreenChromeWindowDetector());
result.set_full_screen_window_detector(
new FullScreenWindowDetector(CreateFullScreenMacApplicationHandler));
#elif defined(WEBRTC_WIN)
result.set_full_screen_window_detector(
new FullScreenWindowDetector(CreateFullScreenWinApplicationHandler));
#endif
return result;
}

View File

@ -19,9 +19,10 @@
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
#include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#endif
#include "modules/desktop_capture/full_screen_window_detector.h"
namespace webrtc {
// An object that stores initialization parameters for screen and window
@ -62,21 +63,18 @@ class RTC_EXPORT DesktopCaptureOptions {
configuration_monitor_ = m;
}
// TODO(zijiehe): Instead of FullScreenChromeWindowDetector, provide a
// FullScreenWindowDetector for external consumers to detect the target
// fullscreen window.
FullScreenChromeWindowDetector* full_screen_chrome_window_detector() const {
return full_screen_window_detector_;
}
void set_full_screen_chrome_window_detector(
rtc::scoped_refptr<FullScreenChromeWindowDetector> detector) {
full_screen_window_detector_ = detector;
}
bool allow_iosurface() const { return allow_iosurface_; }
void set_allow_iosurface(bool allow) { allow_iosurface_ = allow; }
#endif
FullScreenWindowDetector* full_screen_window_detector() const {
return full_screen_window_detector_;
}
void set_full_screen_window_detector(
rtc::scoped_refptr<FullScreenWindowDetector> detector) {
full_screen_window_detector_ = detector;
}
// Flag indicating that the capturer should use screen change notifications.
// Enables/disables use of XDAMAGE in the X11 capturer.
bool use_update_notifications() const { return use_update_notifications_; }
@ -142,11 +140,11 @@ class RTC_EXPORT DesktopCaptureOptions {
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_window_detector_;
bool allow_iosurface_ = false;
#endif
rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
#if defined(WEBRTC_WIN)
bool allow_use_magnification_api_ = false;
bool allow_directx_capturer_ = false;

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2019 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 "modules/desktop_capture/full_screen_application_handler.h"
#include "rtc_base/logging.h"
namespace webrtc {
FullScreenApplicationHandler::FullScreenApplicationHandler(
DesktopCapturer::SourceId sourceId)
: source_id_(sourceId) {}
DesktopCapturer::SourceId FullScreenApplicationHandler::FindFullScreenWindow(
const DesktopCapturer::SourceList&,
int64_t) const {
return 0;
}
DesktopCapturer::SourceId FullScreenApplicationHandler::GetSourceId() const {
return source_id_;
}
} // namespace webrtc

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2019 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 MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_
#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_
#include <memory>
#include "modules/desktop_capture/desktop_capturer.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
// Base class for application specific handler to check criteria for switch to
// full-screen mode and find if possible the full-screen window to share.
// Supposed to be created and owned by platform specific
// FullScreenWindowDetector.
class FullScreenApplicationHandler {
public:
virtual ~FullScreenApplicationHandler() {}
explicit FullScreenApplicationHandler(DesktopCapturer::SourceId sourceId);
// Returns the full-screen window in place of the original window if all the
// criteria are met, or 0 if no such window found.
virtual DesktopCapturer::SourceId FindFullScreenWindow(
const DesktopCapturer::SourceList& window_list,
int64_t timestamp) const;
// Returns source id of original window associated with
// FullScreenApplicationHandler
DesktopCapturer::SourceId GetSourceId() const;
private:
const DesktopCapturer::SourceId source_id_;
RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenApplicationHandler);
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2019 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 "modules/desktop_capture/full_screen_window_detector.h"
#include "modules/desktop_capture/full_screen_application_handler.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
FullScreenWindowDetector::FullScreenWindowDetector(
ApplicationHandlerFactory application_handler_factory)
: application_handler_factory_(application_handler_factory),
last_update_time_ms_(0),
previous_source_id_(0),
no_handler_source_id_(0) {}
DesktopCapturer::SourceId FullScreenWindowDetector::FindFullScreenWindow(
DesktopCapturer::SourceId original_source_id) {
if (app_handler_ == nullptr ||
app_handler_->GetSourceId() != original_source_id) {
return 0;
}
return app_handler_->FindFullScreenWindow(window_list_, last_update_time_ms_);
}
void FullScreenWindowDetector::UpdateWindowListIfNeeded(
DesktopCapturer::SourceId original_source_id,
rtc::FunctionView<bool(DesktopCapturer::SourceList*)> get_sources) {
const bool skip_update = previous_source_id_ != original_source_id;
previous_source_id_ = original_source_id;
// Here is an attempt to avoid redundant creating application handler in case
// when an instance of WindowCapturer is used to generate a thumbnail to show
// in picker by calling SelectSource and CaptureFrame for every available
// source.
if (skip_update) {
return;
}
CreateApplicationHandlerIfNeeded(original_source_id);
if (app_handler_ == nullptr) {
// There is no FullScreenApplicationHandler specific for
// current application
return;
}
constexpr int64_t kUpdateIntervalMs = 500;
if ((rtc::TimeMillis() - last_update_time_ms_) <= kUpdateIntervalMs) {
return;
}
DesktopCapturer::SourceList window_list;
if (get_sources(&window_list)) {
last_update_time_ms_ = rtc::TimeMillis();
window_list_.swap(window_list);
}
}
void FullScreenWindowDetector::CreateApplicationHandlerIfNeeded(
DesktopCapturer::SourceId source_id) {
if (no_handler_source_id_ == source_id) {
return;
}
if (app_handler_ == nullptr || app_handler_->GetSourceId() != source_id) {
app_handler_ = application_handler_factory_
? application_handler_factory_(source_id)
: nullptr;
}
if (app_handler_ == nullptr) {
no_handler_source_id_ = source_id;
}
}
} // namespace webrtc

View File

@ -0,0 +1,80 @@
/*
* 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 MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_
#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_
#include <memory>
#include "api/function_view.h"
#include "api/ref_counted_base.h"
#include "api/scoped_refptr.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "modules/desktop_capture/full_screen_application_handler.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
// This is a way to handle switch to full-screen mode for application in some
// specific cases:
// - Chrome on MacOS creates a new window in full-screen mode to
// show a tab full-screen and minimizes the old window.
// - PowerPoint creates new windows in full-screen mode when user goes to
// presentation mode (Slide Show Window, Presentation Window).
//
// To continue capturing in these cases, we try to find the new full-screen
// window using criteria provided by application specific
// FullScreenApplicationHandler.
class FullScreenWindowDetector : public rtc::RefCountedBase {
public:
using ApplicationHandlerFactory =
std::function<std::unique_ptr<FullScreenApplicationHandler>(
DesktopCapturer::SourceId sourceId)>;
FullScreenWindowDetector(
ApplicationHandlerFactory application_handler_factory);
// Returns the full-screen window in place of the original window if all the
// criteria provided by FullScreenApplicationHandler are met, or 0 if no such
// window found.
DesktopCapturer::SourceId FindFullScreenWindow(
DesktopCapturer::SourceId original_source_id);
// The caller should call this function periodically, implementation will
// update internal state no often than twice per second
void UpdateWindowListIfNeeded(
DesktopCapturer::SourceId original_source_id,
rtc::FunctionView<bool(DesktopCapturer::SourceList*)> get_sources);
static rtc::scoped_refptr<FullScreenWindowDetector>
CreateFullScreenWindowDetector();
protected:
std::unique_ptr<FullScreenApplicationHandler> app_handler_;
private:
void CreateApplicationHandlerIfNeeded(DesktopCapturer::SourceId source_id);
ApplicationHandlerFactory application_handler_factory_;
int64_t last_update_time_ms_;
DesktopCapturer::SourceId previous_source_id_;
// Save the source id when we fail to create an instance of
// CreateApplicationHandlerIfNeeded to avoid redundant attempt to do it again.
DesktopCapturer::SourceId no_handler_source_id_;
DesktopCapturer::SourceList window_list_;
RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenWindowDetector);
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_

View File

@ -1,135 +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 "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#include <libproc.h>
#include <string>
#include "modules/desktop_capture/mac/window_list_utils.h"
#include "rtc_base/logging.h"
#include "rtc_base/time_utils.h"
namespace webrtc {
namespace {
const int64_t kUpdateIntervalMs = 500;
// Returns the window that is full-screen and has the same title and owner pid
// as the input window.
CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) {
const int pid = GetWindowOwnerPid(id);
std::string title = GetWindowTitle(id);
if (title.empty())
return kCGNullWindowID;
// 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));
CGWindowID window_id = GetWindowId(window);
if (window_id == kNullWindowId)
continue;
if (GetWindowOwnerPid(window) != pid)
continue;
std::string window_title = GetWindowTitle(window);
if (window_title != title)
continue;
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()
: last_update_time_ns_(0) {}
FullScreenChromeWindowDetector::~FullScreenChromeWindowDetector() {}
CGWindowID FullScreenChromeWindowDetector::FindFullScreenWindow(
CGWindowID original_window) {
if (!IsChromeWindow(original_window) || IsWindowOnScreen(original_window))
return kCGNullWindowID;
CGWindowID full_screen_window_id =
FindFullScreenWindowWithSamePidAndTitle(original_window);
if (full_screen_window_id == kCGNullWindowID)
return kCGNullWindowID;
for (const auto& window : previous_window_list_) {
if (static_cast<CGWindowID>(window.id) != full_screen_window_id)
continue;
RTC_LOG(LS_WARNING) << "The full-screen window exists in the list.";
return kCGNullWindowID;
}
return full_screen_window_id;
}
void FullScreenChromeWindowDetector::UpdateWindowListIfNeeded(
CGWindowID original_window) {
if (IsChromeWindow(original_window) &&
(rtc::TimeNanos() - last_update_time_ns_) / rtc::kNumNanosecsPerMillisec >
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 (!IsWindowOnScreen(original_window)) {
previous_window_list_.clear();
return;
}
GetWindowList(&current_window_list_, false);
last_update_time_ns_ = rtc::TimeNanos();
}
}
} // namespace webrtc

View File

@ -1,62 +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.
*/
#ifndef MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
#include <ApplicationServices/ApplicationServices.h>
#include "api/ref_counted_base.h"
#include "modules/desktop_capture/desktop_capturer.h"
#include "rtc_base/constructor_magic.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 rtc::RefCountedBase {
public:
FullScreenChromeWindowDetector();
// 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);
protected:
~FullScreenChromeWindowDetector() override;
private:
// 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.
DesktopCapturer::SourceList current_window_list_;
DesktopCapturer::SourceList previous_window_list_;
int64_t last_update_time_ns_;
RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenChromeWindowDetector);
};
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2019 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 "modules/desktop_capture/mac/full_screen_mac_application_handler.h"
#include <libproc.h>
#include <algorithm>
#include <functional>
#include <string>
#include "absl/strings/match.h"
#include "modules/desktop_capture/mac/window_list_utils.h"
namespace webrtc {
namespace {
static constexpr const char* kPowerPointSlideShowTitles[] = {
u8"PowerPoint-Bildschirmpräsentation",
u8"Προβολή παρουσίασης PowerPoint",
u8"PowerPoint スライド ショー",
u8"PowerPoint Slide Show",
u8"PowerPoint 幻灯片放映",
u8"Presentación de PowerPoint",
u8"PowerPoint-slideshow",
u8"Presentazione di PowerPoint",
u8"Prezentácia programu PowerPoint",
u8"Apresentação do PowerPoint",
u8"PowerPoint-bildspel",
u8"Prezentace v aplikaci PowerPoint",
u8"PowerPoint 슬라이드 쇼",
u8"PowerPoint-lysbildefremvisning",
u8"PowerPoint-vetítés",
u8"PowerPoint Slayt Gösterisi",
u8"Pokaz slajdów programu PowerPoint",
u8"PowerPoint 投影片放映",
u8"Демонстрация PowerPoint",
u8"Diaporama PowerPoint",
u8"PowerPoint-diaesitys",
u8"Peragaan Slide PowerPoint",
u8"PowerPoint-diavoorstelling",
u8"การนำเสนอสไลด์ PowerPoint",
u8"Apresentação de slides do PowerPoint",
u8"הצגת שקופיות של PowerPoint",
u8"عرض شرائح في PowerPoint"};
class FullScreenMacApplicationHandler : public FullScreenApplicationHandler {
public:
using TitlePredicate =
std::function<bool(const std::string&, const std::string&)>;
FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId,
TitlePredicate title_predicate)
: FullScreenApplicationHandler(sourceId),
title_predicate_(title_predicate),
owner_pid_(GetWindowOwnerPid(sourceId)) {}
void InvalidateCacheIfNeeded(const DesktopCapturer::SourceList& source_list,
int64_t timestamp) const {
// Copy only sources with the same pid
if (timestamp != cache_timestamp_) {
cache_sources_.clear();
std::copy_if(source_list.begin(), source_list.end(),
std::back_inserter(cache_sources_),
[&](const DesktopCapturer::Source& src) {
return src.id != GetSourceId() &&
GetWindowOwnerPid(src.id) == owner_pid_;
});
cache_timestamp_ = timestamp;
}
}
WindowId FindFullScreenWindowWithSamePid(
const DesktopCapturer::SourceList& source_list,
int64_t timestamp) const {
InvalidateCacheIfNeeded(source_list, timestamp);
if (cache_sources_.empty())
return kCGNullWindowID;
const auto original_window = GetSourceId();
const std::string title = GetWindowTitle(original_window);
// We can ignore any windows with empty titles cause regardless type of
// application it's impossible to verify that full screen window and
// original window are related to the same document.
if (title.empty())
return kCGNullWindowID;
MacDesktopConfiguration desktop_config =
MacDesktopConfiguration::GetCurrent(
MacDesktopConfiguration::TopLeftOrigin);
const auto it = std::find_if(
cache_sources_.begin(), cache_sources_.end(),
[&](const DesktopCapturer::Source& src) {
const std::string window_title = GetWindowTitle(src.id);
if (window_title.empty())
return false;
if (title_predicate_ && !title_predicate_(title, window_title))
return false;
return IsWindowFullScreen(desktop_config, src.id);
});
return it != cache_sources_.end() ? it->id : 0;
}
DesktopCapturer::SourceId FindFullScreenWindow(
const DesktopCapturer::SourceList& source_list,
int64_t timestamp) const override {
return IsWindowOnScreen(GetSourceId())
? 0
: FindFullScreenWindowWithSamePid(source_list, timestamp);
}
private:
const TitlePredicate title_predicate_;
const int owner_pid_;
mutable int64_t cache_timestamp_ = 0;
mutable DesktopCapturer::SourceList cache_sources_;
};
bool equal_title_predicate(const std::string& original_title,
const std::string& title) {
return original_title == title;
}
bool slide_show_title_predicate(const std::string& original_title,
const std::string& title) {
if (title.find(original_title) == std::string::npos)
return false;
for (const char* pp_slide_title : kPowerPointSlideShowTitles) {
if (absl::StartsWith(title, pp_slide_title))
return true;
}
return false;
}
} // namespace
std::unique_ptr<FullScreenApplicationHandler>
CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId) {
std::unique_ptr<FullScreenApplicationHandler> result;
int pid = GetWindowOwnerPid(sourceId);
char buffer[PROC_PIDPATHINFO_MAXSIZE];
int path_length = proc_pidpath(pid, buffer, sizeof(buffer));
if (path_length > 0) {
const char* last_slash = strrchr(buffer, '/');
const std::string name{last_slash ? last_slash + 1 : buffer};
FullScreenMacApplicationHandler::TitlePredicate predicate = nullptr;
if (name.find("Google Chrome") == 0 || name == "Chromium") {
predicate = equal_title_predicate;
} else if (name == "Microsoft PowerPoint") {
predicate = slide_show_title_predicate;
} else if (name == "Keynote") {
predicate = equal_title_predicate;
}
if (predicate) {
result.reset(new FullScreenMacApplicationHandler(sourceId, predicate));
}
}
return result;
}
} // namespace webrtc

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2019 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 MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_
#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_
#include <memory>
#include "modules/desktop_capture/full_screen_application_handler.h"
namespace webrtc {
std::unique_ptr<FullScreenApplicationHandler>
CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId);
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_

View File

@ -15,8 +15,11 @@
#include <algorithm>
#include <cmath>
#include <iterator>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <utility>
#include "rtc_base/checks.h"
@ -78,7 +81,8 @@ bool GetWindowRef(CGWindowID id,
} // namespace
bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
bool ignore_minimized) {
bool ignore_minimized,
bool only_zero_layer) {
RTC_DCHECK(on_window);
// Only get on screen, non-desktop windows.
@ -122,7 +126,7 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
if (!CFNumberGetValue(window_layer, kCFNumberIntType, &layer)) {
continue;
}
if (layer != 0) {
if (only_zero_layer && layer != 0) {
continue;
}
@ -151,7 +155,8 @@ bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
}
bool GetWindowList(DesktopCapturer::SourceList* windows,
bool ignore_minimized) {
bool ignore_minimized,
bool only_zero_layer) {
// Use a std::list so that iterators are preversed upon insertion and
// deletion.
std::list<DesktopCapturer::Source> sources;
@ -201,7 +206,7 @@ bool GetWindowList(DesktopCapturer::SourceList* windows,
}
return true;
},
ignore_minimized);
ignore_minimized, only_zero_layer);
if (!ret)
return false;
@ -239,6 +244,15 @@ bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
return fullscreen;
}
bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
CGWindowID id) {
bool fullscreen = false;
GetWindowRef(id, [&](CFDictionaryRef window) {
fullscreen = IsWindowFullScreen(desktop_config, window);
});
return fullscreen;
}
bool IsWindowOnScreen(CFDictionaryRef window) {
CFBooleanRef on_screen = reinterpret_cast<CFBooleanRef>(
CFDictionaryGetValue(window, kCGWindowIsOnscreen));

View File

@ -13,6 +13,7 @@
#include <ApplicationServices/ApplicationServices.h>
#include <string>
#include "api/function_view.h"
#include "modules/desktop_capture/desktop_capture_types.h"
#include "modules/desktop_capture/desktop_capturer.h"
@ -24,18 +25,26 @@ namespace webrtc {
// Iterates all on-screen windows in decreasing z-order and sends them
// one-by-one to |on_window| function. If |on_window| returns false, this
// function returns immediately. GetWindowList() returns false if native APIs
// failed. Menus, dock, minimized windows (if |ignore_minimized| is true) and
// any windows which do not have a valid window id or title will be ignored.
// failed. Menus, dock (if |only_zero_layer|), minimized windows (if
// |ignore_minimized| is true) and any windows which do not have a valid window
// id or title will be ignored.
bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
bool ignore_minimized);
bool ignore_minimized,
bool only_zero_layer);
// Another helper function to get the on-screen windows.
bool GetWindowList(DesktopCapturer::SourceList* windows, bool ignore_minimized);
bool GetWindowList(DesktopCapturer::SourceList* windows,
bool ignore_minimized,
bool only_zero_layer);
// Returns true if the window is occupying a full screen.
bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
CFDictionaryRef window);
// Returns true if the window is occupying a full screen.
bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
CGWindowID id);
// Returns true if the |window| is on screen. This function returns false if
// native APIs fail.
bool IsWindowOnScreen(CFDictionaryRef window);

View File

@ -24,7 +24,6 @@
#include "modules/desktop_capture/desktop_frame.h"
#include "modules/desktop_capture/mac/desktop_configuration.h"
#include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#include "modules/desktop_capture/mac/window_list_utils.h"
#include "modules/desktop_capture/mouse_cursor.h"
@ -79,21 +78,16 @@ class MouseCursorMonitorMac : public MouseCursorMonitor {
Callback* callback_;
Mode mode_;
__strong NSImage* last_cursor_;
rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_chrome_window_detector_;
};
MouseCursorMonitorMac::MouseCursorMonitorMac(
const DesktopCaptureOptions& options,
CGWindowID window_id,
ScreenId screen_id)
MouseCursorMonitorMac::MouseCursorMonitorMac(const DesktopCaptureOptions& options,
CGWindowID window_id,
ScreenId screen_id)
: configuration_monitor_(options.configuration_monitor()),
window_id_(window_id),
screen_id_(screen_id),
callback_(NULL),
mode_(SHAPE_AND_POSITION),
full_screen_chrome_window_detector_(
options.full_screen_chrome_window_detector()) {
mode_(SHAPE_AND_POSITION) {
assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId);
}

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2019 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 "modules/desktop_capture/win/full_screen_win_application_handler.h"
#include <algorithm>
#include <cwctype>
#include <memory>
#include <string>
#include <vector>
#include "rtc_base/arraysize.h"
#include "rtc_base/logging.h" // For RTC_LOG_GLE
#include "rtc_base/string_utils.h"
namespace webrtc {
namespace {
std::string WindowText(HWND window) {
size_t len = ::GetWindowTextLength(window);
if (len == 0)
return std::string();
std::vector<wchar_t> buffer(len + 1, 0);
size_t copied = ::GetWindowTextW(window, buffer.data(), buffer.size());
if (copied == 0)
return std::string();
return rtc::ToUtf8(buffer.data(), copied);
}
DWORD WindowProcessId(HWND window) {
DWORD dwProcessId = 0;
::GetWindowThreadProcessId(window, &dwProcessId);
return dwProcessId;
}
std::wstring FileNameFromPath(const std::wstring& path) {
auto found = path.rfind(L"\\");
if (found == std::string::npos)
return path;
return path.substr(found + 1);
}
// Returns windows which belong to given process id
// |sources| is a full list of available windows
// |processId| is a process identifier (window owner)
// |window_to_exclude| is a window to be exluded from result
DesktopCapturer::SourceList GetProcessWindows(
const DesktopCapturer::SourceList& sources,
DWORD processId,
HWND window_to_exclude) {
DesktopCapturer::SourceList result;
std::copy_if(sources.begin(), sources.end(), std::back_inserter(result),
[&](DesktopCapturer::Source source) {
const HWND source_hwnd = reinterpret_cast<HWND>(source.id);
return window_to_exclude != source_hwnd &&
WindowProcessId(source_hwnd) == processId;
});
return result;
}
class FullScreenPowerPointHandler : public FullScreenApplicationHandler {
public:
explicit FullScreenPowerPointHandler(DesktopCapturer::SourceId sourceId)
: FullScreenApplicationHandler(sourceId) {}
~FullScreenPowerPointHandler() override {}
DesktopCapturer::SourceId FindFullScreenWindow(
const DesktopCapturer::SourceList& window_list,
int64_t timestamp) const override {
if (window_list.empty())
return 0;
HWND original_window = reinterpret_cast<HWND>(GetSourceId());
DWORD process_id = WindowProcessId(original_window);
DesktopCapturer::SourceList powerpoint_windows =
GetProcessWindows(window_list, process_id, original_window);
if (powerpoint_windows.empty())
return 0;
if (GetWindowType(original_window) != WindowType::kEditor)
return 0;
const auto original_document = GetDocumentFromEditorTitle(original_window);
for (const auto& source : powerpoint_windows) {
HWND window = reinterpret_cast<HWND>(source.id);
// Looking for slide show window for the same document
if (GetWindowType(window) != WindowType::kSlideShow ||
GetDocumentFromSlideShowTitle(window) != original_document) {
continue;
}
return source.id;
}
return 0;
}
private:
enum class WindowType { kEditor, kSlideShow, kOther };
WindowType GetWindowType(HWND window) const {
if (IsEditorWindow(window))
return WindowType::kEditor;
else if (IsSlideShowWindow(window))
return WindowType::kSlideShow;
else
return WindowType::kOther;
}
constexpr static char kDocumentTitleSeparator[] = " - ";
std::string GetDocumentFromEditorTitle(HWND window) const {
std::string title = WindowText(window);
auto position = title.find(kDocumentTitleSeparator);
return rtc::string_trim(title.substr(0, position));
}
std::string GetDocumentFromSlideShowTitle(HWND window) const {
std::string title = WindowText(window);
auto left_pos = title.find(kDocumentTitleSeparator);
auto right_pos = title.rfind(kDocumentTitleSeparator);
constexpr size_t kSeparatorLength = arraysize(kDocumentTitleSeparator) - 1;
if (left_pos == std::string::npos || right_pos == std::string::npos)
return title;
if (right_pos > left_pos + kSeparatorLength) {
auto result_len = right_pos - left_pos - kSeparatorLength;
auto document = title.substr(left_pos + kSeparatorLength, result_len);
return rtc::string_trim(document);
} else {
auto document =
title.substr(left_pos + kSeparatorLength, std::wstring::npos);
return rtc::string_trim(document);
}
}
bool IsEditorWindow(HWND window) const {
constexpr WCHAR kScreenClassName[] = L"PPTFrameClass";
constexpr size_t kScreenClassNameLength = arraysize(kScreenClassName) - 1;
// We need to verify that window class is equal to |kScreenClassName|.
// To do that we need a buffer large enough to include a null terminated
// string one code point bigger than |kScreenClassName|. It will help us to
// check that size of class name string returned by GetClassNameW is equal
// to |kScreenClassNameLength| not being limited by size of buffer (case
// when |kScreenClassName| is a prefix for class name string).
WCHAR buffer[arraysize(kScreenClassName) + 3];
const int length = ::GetClassNameW(window, buffer, arraysize(buffer));
if (length != kScreenClassNameLength)
return false;
return wcsncmp(buffer, kScreenClassName, kScreenClassNameLength) == 0;
}
bool IsSlideShowWindow(HWND window) const {
const LONG style = ::GetWindowLong(window, GWL_STYLE);
const bool min_box = WS_MINIMIZEBOX & style;
const bool max_box = WS_MAXIMIZEBOX & style;
return !min_box && !max_box;
}
};
std::wstring GetPathByWindowId(HWND window_id) {
DWORD process_id = WindowProcessId(window_id);
HANDLE process =
::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
if (process == NULL)
return L"";
DWORD path_len = MAX_PATH;
WCHAR path[MAX_PATH];
std::wstring result;
if (::QueryFullProcessImageNameW(process, 0, path, &path_len))
result = std::wstring(path, path_len);
else
RTC_LOG_GLE(LS_ERROR) << "QueryFullProcessImageName failed.";
::CloseHandle(process);
return result;
}
} // namespace
std::unique_ptr<FullScreenApplicationHandler>
CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId source_id) {
std::unique_ptr<FullScreenApplicationHandler> result;
std::wstring exe_path = GetPathByWindowId(reinterpret_cast<HWND>(source_id));
std::wstring file_name = FileNameFromPath(exe_path);
std::transform(file_name.begin(), file_name.end(), file_name.begin(),
std::towupper);
if (file_name == L"POWERPNT.EXE") {
result = std::make_unique<FullScreenPowerPointHandler>(source_id);
}
return result;
}
} // namespace webrtc

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2019 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 MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_
#define MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_
#include <memory>
#include "modules/desktop_capture/full_screen_application_handler.h"
namespace webrtc {
std::unique_ptr<FullScreenApplicationHandler>
CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId sourceId);
} // namespace webrtc
#endif // MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_

View File

@ -22,7 +22,6 @@
#include "modules/desktop_capture/mac/desktop_configuration.h"
#include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
#include "modules/desktop_capture/mac/desktop_frame_cgimage.h"
#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
#include "modules/desktop_capture/mac/window_list_utils.h"
#include "modules/desktop_capture/window_finder_mac.h"
#include "rtc_base/constructor_magic.h"
@ -48,10 +47,9 @@ bool IsWindowValid(CGWindowID id) {
class WindowCapturerMac : public DesktopCapturer {
public:
explicit WindowCapturerMac(rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_chrome_window_detector,
rtc::scoped_refptr<DesktopConfigurationMonitor>
configuration_monitor);
explicit WindowCapturerMac(
rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector,
rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor);
~WindowCapturerMac() override;
// DesktopCapturer interface.
@ -68,8 +66,7 @@ class WindowCapturerMac : public DesktopCapturer {
// The window being captured.
CGWindowID window_id_ = 0;
const rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_chrome_window_detector_;
rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
const rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
@ -79,18 +76,16 @@ class WindowCapturerMac : public DesktopCapturer {
};
WindowCapturerMac::WindowCapturerMac(
rtc::scoped_refptr<FullScreenChromeWindowDetector>
full_screen_chrome_window_detector,
rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector,
rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor)
: full_screen_chrome_window_detector_(
std::move(full_screen_chrome_window_detector)),
: full_screen_window_detector_(std::move(full_screen_window_detector)),
configuration_monitor_(std::move(configuration_monitor)),
window_finder_(configuration_monitor_) {}
WindowCapturerMac::~WindowCapturerMac() {}
bool WindowCapturerMac::GetSourceList(SourceList* sources) {
return webrtc::GetWindowList(sources, true);
return webrtc::GetWindowList(sources, true, true);
}
bool WindowCapturerMac::SelectSource(SourceId id) {
@ -163,12 +158,15 @@ void WindowCapturerMac::CaptureFrame() {
}
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_detector_) {
full_screen_window_detector_->UpdateWindowListIfNeeded(
window_id_, [](DesktopCapturer::SourceList* sources) {
return webrtc::GetWindowList(sources, true, false);
});
if (full_screen_window != kCGNullWindowID)
on_screen_window = full_screen_window;
CGWindowID full_screen_window = full_screen_window_detector_->FindFullScreenWindow(window_id_);
if (full_screen_window != kCGNullWindowID) on_screen_window = full_screen_window;
}
std::unique_ptr<DesktopFrame> frame = DesktopFrameCGImage::CreateForWindow(on_screen_window);
@ -186,9 +184,6 @@ void WindowCapturerMac::CaptureFrame() {
frame->set_dpi(DesktopVector(kStandardDPI * scale_factor, kStandardDPI * scale_factor));
callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
if (full_screen_chrome_window_detector_)
full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
}
} // namespace
@ -196,9 +191,8 @@ void WindowCapturerMac::CaptureFrame() {
// static
std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
const DesktopCaptureOptions& options) {
return std::unique_ptr<DesktopCapturer>(
new WindowCapturerMac(options.full_screen_chrome_window_detector(),
options.configuration_monitor()));
return std::unique_ptr<DesktopCapturer>(new WindowCapturerMac(
options.full_screen_window_detector(), options.configuration_monitor()));
}
} // namespace webrtc

View File

@ -38,6 +38,7 @@ WindowId WindowFinderMac::GetWindowUnderPoint(DesktopVector point) {
}
return true;
},
true,
true);
return id;
}