diff --git a/modules/desktop_capture/cropping_window_capturer_win.cc b/modules/desktop_capture/cropping_window_capturer_win.cc index 6707236b3e..2c504a002a 100644 --- a/modules/desktop_capture/cropping_window_capturer_win.cc +++ b/modules/desktop_capture/cropping_window_capturer_win.cc @@ -24,10 +24,12 @@ namespace { struct TopWindowVerifierContext { TopWindowVerifierContext(HWND selected_window, HWND excluded_window, - DesktopRect selected_window_rect) + DesktopRect selected_window_rect, + WindowCaptureHelperWin* window_capture_helper) : selected_window(selected_window), excluded_window(excluded_window), selected_window_rect(selected_window_rect), + window_capture_helper(window_capture_helper), is_top_window(false) { RTC_DCHECK_NE(selected_window, excluded_window); } @@ -35,6 +37,7 @@ struct TopWindowVerifierContext { const HWND selected_window; const HWND excluded_window; const DesktopRect selected_window_rect; + WindowCaptureHelperWin* window_capture_helper; bool is_top_window; }; @@ -54,8 +57,8 @@ BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) { return TRUE; } - // Ignore hidden or minimized window. - if (IsIconic(hwnd) || !IsWindowVisible(hwnd)) { + // Ignore invisible window on current desktop. + if (!context->window_capture_helper->IsWindowVisibleOnCurrentDesktop(hwnd)) { return TRUE; } @@ -140,17 +143,17 @@ class CroppingWindowCapturerWin : public CroppingWindowCapturer { // rectangular, or the rect from GetWindowRect if the region is not set. DesktopRect window_region_rect_; - AeroChecker aero_checker_; + WindowCaptureHelperWin window_capture_helper_; }; bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { - if (!rtc::IsWindows8OrLater() && aero_checker_.IsAeroEnabled()) { + if (!rtc::IsWindows8OrLater() && window_capture_helper_.IsAeroEnabled()) { return false; } const HWND selected = reinterpret_cast(selected_window()); - // Check if the window is hidden or minimized. - if (IsIconic(selected) || !IsWindowVisible(selected)) { + // Check if the window is visible on current desktop. + if (!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(selected)) { return false; } @@ -223,8 +226,9 @@ bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() { // windows, context menus, and |excluded_window_|. // |content_rect| is preferred, see the comments in TopWindowVerifier() // function. - TopWindowVerifierContext context( - selected, reinterpret_cast(excluded_window()), content_rect); + TopWindowVerifierContext context(selected, + reinterpret_cast(excluded_window()), + content_rect, &window_capture_helper_); const LPARAM enum_param = reinterpret_cast(&context); EnumWindows(&TopWindowVerifier, enum_param); if (!context.is_top_window) { diff --git a/modules/desktop_capture/win/window_capture_utils.cc b/modules/desktop_capture/win/window_capture_utils.cc index 41c62dca59..8929bb7de3 100644 --- a/modules/desktop_capture/win/window_capture_utils.cc +++ b/modules/desktop_capture/win/window_capture_utils.cc @@ -12,6 +12,7 @@ #include "modules/desktop_capture/win/scoped_gdi_object.h" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" #include "rtc_base/win32.h" namespace webrtc { @@ -130,22 +131,34 @@ bool IsWindowMaximized(HWND window, bool* result) { return true; } -AeroChecker::AeroChecker() : dwmapi_library_(nullptr), func_(nullptr) { +// WindowCaptureHelperWin implementation. +WindowCaptureHelperWin::WindowCaptureHelperWin() + : dwmapi_library_(nullptr), + func_(nullptr), + virtual_desktop_manager_(nullptr) { // Try to load dwmapi.dll dynamically since it is not available on XP. dwmapi_library_ = LoadLibrary(L"dwmapi.dll"); if (dwmapi_library_) { func_ = reinterpret_cast( GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled")); } + + if (rtc::IsWindows10OrLater()) { + if (FAILED(::CoCreateInstance(__uuidof(VirtualDesktopManager), nullptr, + CLSCTX_ALL, + IID_PPV_ARGS(&virtual_desktop_manager_)))) { + RTC_LOG(LS_WARNING) << "Fail to create instance of VirtualDesktopManager"; + } + } } -AeroChecker::~AeroChecker() { +WindowCaptureHelperWin::~WindowCaptureHelperWin() { if (dwmapi_library_) { FreeLibrary(dwmapi_library_); } } -bool AeroChecker::IsAeroEnabled() { +bool WindowCaptureHelperWin::IsAeroEnabled() { BOOL result = FALSE; if (func_) { func_(&result); @@ -153,4 +166,22 @@ bool AeroChecker::IsAeroEnabled() { return result != FALSE; } +bool WindowCaptureHelperWin::IsWindowOnCurrentDesktop(HWND hwnd) { + // Make sure the window is on the current virtual desktop. + if (virtual_desktop_manager_) { + BOOL on_current_desktop; + if (SUCCEEDED(virtual_desktop_manager_->IsWindowOnCurrentVirtualDesktop( + hwnd, &on_current_desktop)) && + !on_current_desktop) { + return false; + } + } + return true; +} + +bool WindowCaptureHelperWin::IsWindowVisibleOnCurrentDesktop(HWND hwnd) { + return !::IsIconic(hwnd) && ::IsWindowVisible(hwnd) && + IsWindowOnCurrentDesktop(hwnd); +} + } // namespace webrtc diff --git a/modules/desktop_capture/win/window_capture_utils.h b/modules/desktop_capture/win/window_capture_utils.h index c38995a82a..7cb5097aa3 100644 --- a/modules/desktop_capture/win/window_capture_utils.h +++ b/modules/desktop_capture/win/window_capture_utils.h @@ -8,7 +8,9 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include #include +#include #include "modules/desktop_capture/desktop_geometry.h" #include "rtc_base/constructormagic.h" @@ -58,18 +60,23 @@ bool GetDcSize(HDC hdc, DesktopSize* size); bool IsWindowMaximized(HWND window, bool* result); typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled); -class AeroChecker { +class WindowCaptureHelperWin { public: - AeroChecker(); - ~AeroChecker(); + WindowCaptureHelperWin(); + ~WindowCaptureHelperWin(); bool IsAeroEnabled(); + bool IsWindowOnCurrentDesktop(HWND hwnd); + bool IsWindowVisibleOnCurrentDesktop(HWND hwnd); private: HMODULE dwmapi_library_; DwmIsCompositionEnabledFunc func_; - RTC_DISALLOW_COPY_AND_ASSIGN(AeroChecker); + // Only used on Win10+. + Microsoft::WRL::ComPtr virtual_desktop_manager_; + + RTC_DISALLOW_COPY_AND_ASSIGN(WindowCaptureHelperWin); }; } // namespace webrtc diff --git a/modules/desktop_capture/window_capturer_win.cc b/modules/desktop_capture/window_capturer_win.cc index 414eddf64b..d1a672b66f 100644 --- a/modules/desktop_capture/window_capturer_win.cc +++ b/modules/desktop_capture/window_capturer_win.cc @@ -131,7 +131,7 @@ class WindowCapturerWin : public DesktopCapturer { DesktopSize previous_size_; - AeroChecker aero_checker_; + WindowCaptureHelperWin window_capture_helper_; // This map is used to avoid flickering for the case when SelectWindow() calls // are interleaved with Capture() calls. @@ -151,6 +151,15 @@ bool WindowCapturerWin::GetSourceList(SourceList* sources) { // EnumWindows only enumerates root windows. if (!EnumWindows(&WindowsEnumerationHandler, param)) return false; + + for (auto it = result.begin(); it != result.end();) { + if (!window_capture_helper_.IsWindowOnCurrentDesktop( + reinterpret_cast(it->id))) { + it = result.erase(it); + } else { + ++it; + } + } sources->swap(result); std::map new_map; @@ -220,12 +229,11 @@ void WindowCapturerWin::CaptureFrame() { return; } - // Return a 1x1 black frame if the window is minimized or invisible, to match - // behavior on mace. Window can be temporarily invisible during the - // transition of full screen mode on/off. + // Return a 1x1 black frame if the window is minimized or invisible on current + // desktop, to match behavior on mace. Window can be temporarily invisible + // during the transition of full screen mode on/off. if (original_rect.is_empty() || - IsIconic(window_) || - !IsWindowVisible(window_)) { + !window_capture_helper_.IsWindowVisibleOnCurrentDesktop(window_)) { std::unique_ptr frame( new BasicDesktopFrame(DesktopSize(1, 1))); memset(frame->data(), 0, frame->stride() * frame->size().height()); @@ -295,7 +303,8 @@ void WindowCapturerWin::CaptureFrame() { // capturing - it somehow affects what we get from BitBlt() on the subsequent // captures. - if (!aero_checker_.IsAeroEnabled() || !previous_size_.equals(frame->size())) { + if (!window_capture_helper_.IsAeroEnabled() || + !previous_size_.equals(frame->size())) { result = PrintWindow(window_, mem_dc, 0); } diff --git a/rtc_base/win32.h b/rtc_base/win32.h index 78f66a77de..4e91687132 100644 --- a/rtc_base/win32.h +++ b/rtc_base/win32.h @@ -54,6 +54,7 @@ bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename); enum WindowsMajorVersions { kWindows2000 = 5, kWindowsVista = 6, + kWindows10 = 10, }; bool GetOsVersion(int* major, int* minor, int* build); @@ -74,6 +75,11 @@ inline bool IsWindows8OrLater() { (major > kWindowsVista || (major == kWindowsVista && minor >= 2))); } +inline bool IsWindows10OrLater() { + int major; + return (GetOsVersion(&major, nullptr, nullptr) && (major >= kWindows10)); +} + // Determine the current integrity level of the process. bool GetCurrentProcessIntegrityLevel(int* level);