diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn index b63ebb6915..43324d13d1 100644 --- a/modules/desktop_capture/BUILD.gn +++ b/modules/desktop_capture/BUILD.gn @@ -293,6 +293,7 @@ rtc_static_library("desktop_capture_generic") { "win/window_capture_utils.cc", "win/window_capture_utils.h", "window_capturer_win.cc", + "window_finder.cc", "window_finder.h", "window_finder_win.cc", "window_finder_win.h", diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc index 005b1c64b2..f73193ef3e 100644 --- a/modules/desktop_capture/mac/window_list_utils.cc +++ b/modules/desktop_capture/mac/window_list_utils.cc @@ -12,6 +12,9 @@ #include +#include +#include + #include "rtc_base/checks.h" #include "rtc_base/macutils.h" @@ -57,6 +60,37 @@ bool GetWindowRef(CGWindowID id, return result; } +// Scales the |rect| according to the DIP to physical pixel scale of |rect|. +// |rect| is in unscaled system coordinate, i.e. it's device-independent and the +// primary monitor starts from (0, 0). If |rect| overlaps multiple monitors, the +// returned size may not be accurate when monitors have different DIP settings. +// If |rect| is entirely out of the display, this function returns |rect|. +DesktopRect ApplyScaleFactorOfRect( + const MacDesktopConfiguration& desktop_config, + DesktopRect rect) { + // TODO(http://crbug.com/778049): How does Mac OSX decide the scale factor + // if one window is across two monitors with different DPIs. + float scales[] = { + GetScaleFactorAtPosition(desktop_config, rect.top_left()), + GetScaleFactorAtPosition(desktop_config, + DesktopVector(rect.left() + rect.width() / 2, + rect.top() + rect.height() / 2)), + GetScaleFactorAtPosition( + desktop_config, DesktopVector(rect.right(), rect.bottom())), + }; + // Since GetScaleFactorAtPosition() returns 1 if the position is out of the + // display, we always prefer a value which not equals to 1. + float scale = *std::max_element(std::begin(scales), std::end(scales)); + if (scale == 1) { + scale = *std::min_element(std::begin(scales), std::end(scales)); + } + + return DesktopRect::MakeXYWH(rect.left() * scale, + rect.top() * scale, + rect.width() * scale, + rect.height() * scale); +} + } // namespace bool GetWindowList(rtc::FunctionView on_window, @@ -227,6 +261,19 @@ WindowId GetWindowId(CFDictionaryRef window) { return id; } +float GetScaleFactorAtPosition(const MacDesktopConfiguration& desktop_config, + DesktopVector position) { + // Find the dpi to physical pixel scale for the screen where the mouse cursor + // is. + for (auto it = desktop_config.displays.begin(); + it != desktop_config.displays.end(); ++it) { + if (it->bounds.Contains(position)) { + return it->dip_to_pixel_scale; + } + } + return 1; +} + DesktopRect GetWindowBounds(CFDictionaryRef window) { CFDictionaryRef window_bounds = reinterpret_cast( CFDictionaryGetValue(window, kCGWindowBounds)); @@ -245,6 +292,12 @@ DesktopRect GetWindowBounds(CFDictionaryRef window) { gc_window_rect.size.height); } +DesktopRect GetWindowBounds(const MacDesktopConfiguration& desktop_config, + CFDictionaryRef window) { + DesktopRect rect = GetWindowBounds(window); + return ApplyScaleFactorOfRect(desktop_config, rect); +} + DesktopRect GetWindowBounds(CGWindowID id) { DesktopRect result; if (GetWindowRef(id, @@ -256,4 +309,10 @@ DesktopRect GetWindowBounds(CGWindowID id) { return DesktopRect(); } +DesktopRect GetWindowBounds(const MacDesktopConfiguration& desktop_config, + CGWindowID id) { + DesktopRect rect = GetWindowBounds(id); + return ApplyScaleFactorOfRect(desktop_config, rect); +} + } // namespace webrtc diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h index 7fb0ceec9f..8a79f7ecd5 100644 --- a/modules/desktop_capture/mac/window_list_utils.h +++ b/modules/desktop_capture/mac/window_list_utils.h @@ -52,17 +52,38 @@ std::string GetWindowTitle(CFDictionaryRef window); // be retrieved, this function returns kNullWindowId. WindowId GetWindowId(CFDictionaryRef window); +// Returns the DIP to physical pixel scale at |position|. |position| is in +// *unscaled* system coordinate, i.e. it's device-independent and the primary +// monitor starts from (0, 0). If |position| is out of the system display, this +// function returns 1. +float GetScaleFactorAtPosition(const MacDesktopConfiguration& desktop_config, + DesktopVector position); + // Returns the bounds of |window|. If |window| is not a window or the bounds // cannot be retrieved, this function returns an empty DesktopRect. The returned // DesktopRect is in system coordinate, i.e. the primary monitor always starts // from (0, 0). +// Deprecated: This function should be avoided in favor of the overload with +// MacDesktopConfiguration. DesktopRect GetWindowBounds(CFDictionaryRef window); +// Same as GetWindowBounds(CFDictionaryRef), but this function stretches the +// result with the scale factor. +DesktopRect GetWindowBounds(const MacDesktopConfiguration& desktop_config, + CFDictionaryRef window); + // Returns the bounds of window with |id|. If |id| does not represent a window // or the bounds cannot be retrieved, this function returns an empty // DesktopRect. The returned DesktopRect is in system coordinates. +// Deprecated: This function should be avoided in favor of the overload with +// MacDesktopConfiguration. DesktopRect GetWindowBounds(CGWindowID id); +// Same as GetWindowBounds(CGWindowID), but this function stretches the result +// with the scale factor. +DesktopRect GetWindowBounds(const MacDesktopConfiguration& desktop_config, + CGWindowID id); + } // namespace webrtc #endif // MODULES_DESKTOP_CAPTURE_MAC_WINDOW_LIST_UTILS_H_ diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/desktop_capture/mouse_cursor_monitor_mac.mm index da995a2548..b4a80e9c34 100644 --- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm +++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm @@ -24,6 +24,7 @@ #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" #include "rtc_base/macutils.h" #include "rtc_base/scoped_ref_ptr.h" @@ -122,17 +123,7 @@ void MouseCursorMonitorMac::Capture() { MacDesktopConfiguration configuration = configuration_monitor_->desktop_configuration(); configuration_monitor_->Unlock(); - float scale = 1.0f; - - // Find the dpi to physical pixel scale for the screen where the mouse cursor - // is. - for (MacDisplayConfigurations::iterator it = configuration.displays.begin(); - it != configuration.displays.end(); ++it) { - if (it->bounds.Contains(position)) { - scale = it->dip_to_pixel_scale; - break; - } - } + float scale = GetScaleFactorAtPosition(configuration, position); CaptureImage(scale); diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm index a6b5bf99b9..aa55fd5de9 100644 --- a/modules/desktop_capture/window_capturer_mac.mm +++ b/modules/desktop_capture/window_capturer_mac.mm @@ -83,7 +83,8 @@ WindowCapturerMac::WindowCapturerMac( rtc::scoped_refptr configuration_monitor) : full_screen_chrome_window_detector_( std::move(full_screen_chrome_window_detector)), - configuration_monitor_(std::move(configuration_monitor)) {} + configuration_monitor_(std::move(configuration_monitor)), + window_finder_(configuration_monitor_) {} WindowCapturerMac::~WindowCapturerMac() {} @@ -204,12 +205,15 @@ void WindowCapturerMac::CaptureFrame() { frame->mutable_updated_region()->SetRect( DesktopRect::MakeSize(frame->size())); - DesktopVector top_left = GetWindowBounds(on_screen_window).top_left(); + DesktopVector top_left; if (configuration_monitor_) { configuration_monitor_->Lock(); auto configuration = configuration_monitor_->desktop_configuration(); configuration_monitor_->Unlock(); + top_left = GetWindowBounds(configuration, on_screen_window).top_left(); top_left = top_left.subtract(configuration.bounds.top_left()); + } else { + top_left = GetWindowBounds(on_screen_window).top_left(); } frame->set_top_left(top_left); diff --git a/modules/desktop_capture/window_finder.cc b/modules/desktop_capture/window_finder.cc new file mode 100644 index 0000000000..86127d4c05 --- /dev/null +++ b/modules/desktop_capture/window_finder.cc @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017 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/window_finder.h" + +namespace webrtc { + +WindowFinder::Options::Options() = default; +WindowFinder::Options::~Options() = default; +WindowFinder::Options::Options(const WindowFinder::Options& other) = default; +WindowFinder::Options::Options(WindowFinder::Options&& other) = default; + +} // namespace webrtc diff --git a/modules/desktop_capture/window_finder.h b/modules/desktop_capture/window_finder.h index 360278a6db..1a78145a63 100644 --- a/modules/desktop_capture/window_finder.h +++ b/modules/desktop_capture/window_finder.h @@ -15,6 +15,11 @@ #include "modules/desktop_capture/desktop_capture_types.h" #include "modules/desktop_capture/desktop_geometry.h" +#include "rtc_base/scoped_ref_ptr.h" + +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) +#include "modules/desktop_capture/mac/desktop_configuration_monitor.h" +#endif namespace webrtc { @@ -35,9 +40,17 @@ class WindowFinder { // starts from (0, 0). virtual WindowId GetWindowUnderPoint(DesktopVector point) = 0; - struct Options { + struct Options final { + Options(); + ~Options(); + Options(const Options& other); + Options(Options&& other); + #if defined(USE_X11) XAtomCache* cache = nullptr; +#endif +#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) + rtc::scoped_refptr configuration_monitor; #endif }; diff --git a/modules/desktop_capture/window_finder_mac.h b/modules/desktop_capture/window_finder_mac.h index 30c841b17f..db6e926d3c 100644 --- a/modules/desktop_capture/window_finder_mac.h +++ b/modules/desktop_capture/window_finder_mac.h @@ -12,17 +12,24 @@ #define MODULES_DESKTOP_CAPTURE_WINDOW_FINDER_MAC_H_ #include "modules/desktop_capture/window_finder.h" +#include "rtc_base/scoped_ref_ptr.h" namespace webrtc { +class DesktopConfigurationMonitor; + // The implementation of WindowFinder for Mac OSX. class WindowFinderMac final : public WindowFinder { public: - WindowFinderMac(); + explicit WindowFinderMac( + rtc::scoped_refptr configuration_monitor); ~WindowFinderMac() override; // WindowFinder implementation. WindowId GetWindowUnderPoint(DesktopVector point) override; + + private: + const rtc::scoped_refptr configuration_monitor_; }; } // namespace webrtc diff --git a/modules/desktop_capture/window_finder_mac.mm b/modules/desktop_capture/window_finder_mac.mm index 94f30e519d..6df0d4d9b7 100644 --- a/modules/desktop_capture/window_finder_mac.mm +++ b/modules/desktop_capture/window_finder_mac.mm @@ -12,18 +12,37 @@ #include +#include + #include "modules/desktop_capture/mac/window_list_utils.h" +#include "modules/desktop_capture/mac/desktop_configuration.h" +#include "modules/desktop_capture/mac/desktop_configuration_monitor.h" #include "rtc_base/ptr_util.h" namespace webrtc { -WindowFinderMac::WindowFinderMac() = default; +WindowFinderMac::WindowFinderMac( + rtc::scoped_refptr configuration_monitor) + : configuration_monitor_(std::move(configuration_monitor)) {} WindowFinderMac::~WindowFinderMac() = default; WindowId WindowFinderMac::GetWindowUnderPoint(DesktopVector point) { WindowId id = kNullWindowId; - GetWindowList([&id, point](CFDictionaryRef window) { - DesktopRect bounds = GetWindowBounds(window); + MacDesktopConfiguration configuration_holder; + MacDesktopConfiguration* configuration = nullptr; + if (configuration_monitor_) { + configuration_monitor_->Lock(); + configuration_holder = configuration_monitor_->desktop_configuration(); + configuration_monitor_->Unlock(); + configuration = &configuration_holder; + } + GetWindowList([&id, point, configuration](CFDictionaryRef window) { + DesktopRect bounds; + if (configuration) { + bounds = GetWindowBounds(*configuration, window); + } else { + bounds = GetWindowBounds(window); + } if (bounds.Contains(point)) { id = GetWindowId(window); return false; @@ -37,7 +56,7 @@ WindowId WindowFinderMac::GetWindowUnderPoint(DesktopVector point) { // static std::unique_ptr WindowFinder::Create( const WindowFinder::Options& options) { - return rtc::MakeUnique(); + return rtc::MakeUnique(options.configuration_monitor); } } // namespace webrtc