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}
diff --git a/AUTHORS b/AUTHORS
index df32313..b11ca9a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -101,6 +101,7 @@
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>
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index 88a10a1..789aac4 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -300,6 +300,10 @@
"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 @@
"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 @@
"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 @@
"../../system_wrappers:cpu_features_api",
"../../system_wrappers:metrics",
"//third_party/abseil-cpp/absl/memory",
+ "//third_party/abseil-cpp/absl/strings",
]
if (build_with_mozilla) {
diff --git a/modules/desktop_capture/cropping_window_capturer.h b/modules/desktop_capture/cropping_window_capturer.h
index f9ad36c..272a196 100644
--- a/modules/desktop_capture/cropping_window_capturer.h
+++ b/modules/desktop_capture/cropping_window_capturer.h
@@ -68,6 +68,7 @@
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_;
diff --git a/modules/desktop_capture/cropping_window_capturer_win.cc b/modules/desktop_capture/cropping_window_capturer_win.cc
index ce93ca3..e67f4f4 100644
--- a/modules/desktop_capture/cropping_window_capturer_win.cc
+++ b/modules/desktop_capture/cropping_window_capturer_win.cc
@@ -98,26 +98,53 @@
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 @@
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 @@
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
diff --git a/modules/desktop_capture/desktop_capture_options.cc b/modules/desktop_capture/desktop_capture_options.cc
index 8a33807..ee1e477 100644
--- a/modules/desktop_capture/desktop_capture_options.cc
+++ b/modules/desktop_capture/desktop_capture_options.cc
@@ -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 @@
#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;
}
diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h
index 11e5f4c..d7dac1f 100644
--- a/modules/desktop_capture/desktop_capture_options.h
+++ b/modules/desktop_capture/desktop_capture_options.h
@@ -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 @@
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 @@
#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;
diff --git a/modules/desktop_capture/full_screen_application_handler.cc b/modules/desktop_capture/full_screen_application_handler.cc
new file mode 100644
index 0000000..e097557
--- /dev/null
+++ b/modules/desktop_capture/full_screen_application_handler.cc
@@ -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
diff --git a/modules/desktop_capture/full_screen_application_handler.h b/modules/desktop_capture/full_screen_application_handler.h
new file mode 100644
index 0000000..849cb2c
--- /dev/null
+++ b/modules/desktop_capture/full_screen_application_handler.h
@@ -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_
diff --git a/modules/desktop_capture/full_screen_window_detector.cc b/modules/desktop_capture/full_screen_window_detector.cc
new file mode 100644
index 0000000..d0bc9c7
--- /dev/null
+++ b/modules/desktop_capture/full_screen_window_detector.cc
@@ -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
diff --git a/modules/desktop_capture/full_screen_window_detector.h b/modules/desktop_capture/full_screen_window_detector.h
new file mode 100644
index 0000000..46fb607
--- /dev/null
+++ b/modules/desktop_capture/full_screen_window_detector.h
@@ -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_
diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc b/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
deleted file mode 100644
index f2c8fd4..0000000
--- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
+++ /dev/null
@@ -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(¤t_window_list_, false);
- last_update_time_ns_ = rtc::TimeNanos();
- }
-}
-
-} // namespace webrtc
diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h b/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
deleted file mode 100644
index 2ee99ad..0000000
--- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
+++ /dev/null
@@ -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_
diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.cc b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc
new file mode 100644
index 0000000..9e6eacc
--- /dev/null
+++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc
@@ -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
diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.h b/modules/desktop_capture/mac/full_screen_mac_application_handler.h
new file mode 100644
index 0000000..f795a22
--- /dev/null
+++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.h
@@ -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_
diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc
index 3f0a9b0..67cf81c 100644
--- a/modules/desktop_capture/mac/window_list_utils.cc
+++ b/modules/desktop_capture/mac/window_list_utils.cc
@@ -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 @@
} // 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 @@
if (!CFNumberGetValue(window_layer, kCFNumberIntType, &layer)) {
continue;
}
- if (layer != 0) {
+ if (only_zero_layer && layer != 0) {
continue;
}
@@ -151,7 +155,8 @@
}
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 @@
}
return true;
},
- ignore_minimized);
+ ignore_minimized, only_zero_layer);
if (!ret)
return false;
@@ -239,6 +244,15 @@
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));
diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h
index ff9ad14..f1c0601 100644
--- a/modules/desktop_capture/mac/window_list_utils.h
+++ b/modules/desktop_capture/mac/window_list_utils.h
@@ -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 @@
// 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);
diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
index afc4497..31ad428 100644
--- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -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 @@
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);
}
diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.cc b/modules/desktop_capture/win/full_screen_win_application_handler.cc
new file mode 100644
index 0000000..0b7e3fc
--- /dev/null
+++ b/modules/desktop_capture/win/full_screen_win_application_handler.cc
@@ -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
diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.h b/modules/desktop_capture/win/full_screen_win_application_handler.h
new file mode 100644
index 0000000..c97cbe2
--- /dev/null
+++ b/modules/desktop_capture/win/full_screen_win_application_handler.h
@@ -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_
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index 828122b..96f89eb 100644
--- a/modules/desktop_capture/window_capturer_mac.mm
+++ b/modules/desktop_capture/window_capturer_mac.mm
@@ -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 @@
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 @@
// 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 @@
};
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 @@
}
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 @@
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 @@
// 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
diff --git a/modules/desktop_capture/window_finder_mac.mm b/modules/desktop_capture/window_finder_mac.mm
index 64979c6..e1d0316 100644
--- a/modules/desktop_capture/window_finder_mac.mm
+++ b/modules/desktop_capture/window_finder_mac.mm
@@ -38,6 +38,7 @@
}
return true;
},
+ true,
true);
return id;
}