mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 13:50:40 +01:00
[desktopCaptuer Win] exclude windows not on current virtual desktop
Since Windows 10, Windows starts to support virtual desktops. The problem is when one virtual desktop is not the current one, we can still enumerate the windows on it, which are still marked as visible by OS. This causes troubles to decide if a window is on top to be cropped out. This cl is to utilize a COM API, IsWindowOnCurrentVirtualDesktop of VirtualDesktopManager, to make sure only the windows on current desktop will be enumerated. Bug: chromium:796112 Change-Id: I6e0546e90fbdb37365a8d98694ded0e30791628e Reviewed-on: https://webrtc-review.googlesource.com/65882 Reviewed-by: Jamie Walch <jamiewalch@chromium.org> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org> Commit-Queue: Brave Yao <braveyao@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22842}
This commit is contained in:
parent
44bf6a909b
commit
8944f6a3f5
5 changed files with 80 additions and 23 deletions
|
@ -24,10 +24,12 @@ namespace {
|
||||||
struct TopWindowVerifierContext {
|
struct TopWindowVerifierContext {
|
||||||
TopWindowVerifierContext(HWND selected_window,
|
TopWindowVerifierContext(HWND selected_window,
|
||||||
HWND excluded_window,
|
HWND excluded_window,
|
||||||
DesktopRect selected_window_rect)
|
DesktopRect selected_window_rect,
|
||||||
|
WindowCaptureHelperWin* window_capture_helper)
|
||||||
: selected_window(selected_window),
|
: selected_window(selected_window),
|
||||||
excluded_window(excluded_window),
|
excluded_window(excluded_window),
|
||||||
selected_window_rect(selected_window_rect),
|
selected_window_rect(selected_window_rect),
|
||||||
|
window_capture_helper(window_capture_helper),
|
||||||
is_top_window(false) {
|
is_top_window(false) {
|
||||||
RTC_DCHECK_NE(selected_window, excluded_window);
|
RTC_DCHECK_NE(selected_window, excluded_window);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +37,7 @@ struct TopWindowVerifierContext {
|
||||||
const HWND selected_window;
|
const HWND selected_window;
|
||||||
const HWND excluded_window;
|
const HWND excluded_window;
|
||||||
const DesktopRect selected_window_rect;
|
const DesktopRect selected_window_rect;
|
||||||
|
WindowCaptureHelperWin* window_capture_helper;
|
||||||
bool is_top_window;
|
bool is_top_window;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,8 +57,8 @@ BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore hidden or minimized window.
|
// Ignore invisible window on current desktop.
|
||||||
if (IsIconic(hwnd) || !IsWindowVisible(hwnd)) {
|
if (!context->window_capture_helper->IsWindowVisibleOnCurrentDesktop(hwnd)) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,17 +143,17 @@ class CroppingWindowCapturerWin : public CroppingWindowCapturer {
|
||||||
// rectangular, or the rect from GetWindowRect if the region is not set.
|
// rectangular, or the rect from GetWindowRect if the region is not set.
|
||||||
DesktopRect window_region_rect_;
|
DesktopRect window_region_rect_;
|
||||||
|
|
||||||
AeroChecker aero_checker_;
|
WindowCaptureHelperWin window_capture_helper_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
|
bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
|
||||||
if (!rtc::IsWindows8OrLater() && aero_checker_.IsAeroEnabled()) {
|
if (!rtc::IsWindows8OrLater() && window_capture_helper_.IsAeroEnabled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HWND selected = reinterpret_cast<HWND>(selected_window());
|
const HWND selected = reinterpret_cast<HWND>(selected_window());
|
||||||
// Check if the window is hidden or minimized.
|
// Check if the window is visible on current desktop.
|
||||||
if (IsIconic(selected) || !IsWindowVisible(selected)) {
|
if (!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(selected)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +226,9 @@ bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
|
||||||
// windows, context menus, and |excluded_window_|.
|
// windows, context menus, and |excluded_window_|.
|
||||||
// |content_rect| is preferred, see the comments in TopWindowVerifier()
|
// |content_rect| is preferred, see the comments in TopWindowVerifier()
|
||||||
// function.
|
// function.
|
||||||
TopWindowVerifierContext context(
|
TopWindowVerifierContext context(selected,
|
||||||
selected, reinterpret_cast<HWND>(excluded_window()), content_rect);
|
reinterpret_cast<HWND>(excluded_window()),
|
||||||
|
content_rect, &window_capture_helper_);
|
||||||
const LPARAM enum_param = reinterpret_cast<LPARAM>(&context);
|
const LPARAM enum_param = reinterpret_cast<LPARAM>(&context);
|
||||||
EnumWindows(&TopWindowVerifier, enum_param);
|
EnumWindows(&TopWindowVerifier, enum_param);
|
||||||
if (!context.is_top_window) {
|
if (!context.is_top_window) {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "modules/desktop_capture/win/scoped_gdi_object.h"
|
#include "modules/desktop_capture/win/scoped_gdi_object.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
#include "rtc_base/logging.h"
|
||||||
#include "rtc_base/win32.h"
|
#include "rtc_base/win32.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
@ -130,22 +131,34 @@ bool IsWindowMaximized(HWND window, bool* result) {
|
||||||
return true;
|
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.
|
// Try to load dwmapi.dll dynamically since it is not available on XP.
|
||||||
dwmapi_library_ = LoadLibrary(L"dwmapi.dll");
|
dwmapi_library_ = LoadLibrary(L"dwmapi.dll");
|
||||||
if (dwmapi_library_) {
|
if (dwmapi_library_) {
|
||||||
func_ = reinterpret_cast<DwmIsCompositionEnabledFunc>(
|
func_ = reinterpret_cast<DwmIsCompositionEnabledFunc>(
|
||||||
GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled"));
|
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_) {
|
if (dwmapi_library_) {
|
||||||
FreeLibrary(dwmapi_library_);
|
FreeLibrary(dwmapi_library_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AeroChecker::IsAeroEnabled() {
|
bool WindowCaptureHelperWin::IsAeroEnabled() {
|
||||||
BOOL result = FALSE;
|
BOOL result = FALSE;
|
||||||
if (func_) {
|
if (func_) {
|
||||||
func_(&result);
|
func_(&result);
|
||||||
|
@ -153,4 +166,22 @@ bool AeroChecker::IsAeroEnabled() {
|
||||||
return result != FALSE;
|
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
|
} // namespace webrtc
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <wrl/client.h>
|
||||||
|
|
||||||
#include "modules/desktop_capture/desktop_geometry.h"
|
#include "modules/desktop_capture/desktop_geometry.h"
|
||||||
#include "rtc_base/constructormagic.h"
|
#include "rtc_base/constructormagic.h"
|
||||||
|
@ -58,18 +60,23 @@ bool GetDcSize(HDC hdc, DesktopSize* size);
|
||||||
bool IsWindowMaximized(HWND window, bool* result);
|
bool IsWindowMaximized(HWND window, bool* result);
|
||||||
|
|
||||||
typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled);
|
typedef HRESULT (WINAPI *DwmIsCompositionEnabledFunc)(BOOL* enabled);
|
||||||
class AeroChecker {
|
class WindowCaptureHelperWin {
|
||||||
public:
|
public:
|
||||||
AeroChecker();
|
WindowCaptureHelperWin();
|
||||||
~AeroChecker();
|
~WindowCaptureHelperWin();
|
||||||
|
|
||||||
bool IsAeroEnabled();
|
bool IsAeroEnabled();
|
||||||
|
bool IsWindowOnCurrentDesktop(HWND hwnd);
|
||||||
|
bool IsWindowVisibleOnCurrentDesktop(HWND hwnd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMODULE dwmapi_library_;
|
HMODULE dwmapi_library_;
|
||||||
DwmIsCompositionEnabledFunc func_;
|
DwmIsCompositionEnabledFunc func_;
|
||||||
|
|
||||||
RTC_DISALLOW_COPY_AND_ASSIGN(AeroChecker);
|
// Only used on Win10+.
|
||||||
|
Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager_;
|
||||||
|
|
||||||
|
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCaptureHelperWin);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
|
@ -131,7 +131,7 @@ class WindowCapturerWin : public DesktopCapturer {
|
||||||
|
|
||||||
DesktopSize previous_size_;
|
DesktopSize previous_size_;
|
||||||
|
|
||||||
AeroChecker aero_checker_;
|
WindowCaptureHelperWin window_capture_helper_;
|
||||||
|
|
||||||
// This map is used to avoid flickering for the case when SelectWindow() calls
|
// This map is used to avoid flickering for the case when SelectWindow() calls
|
||||||
// are interleaved with Capture() calls.
|
// are interleaved with Capture() calls.
|
||||||
|
@ -151,6 +151,15 @@ bool WindowCapturerWin::GetSourceList(SourceList* sources) {
|
||||||
// EnumWindows only enumerates root windows.
|
// EnumWindows only enumerates root windows.
|
||||||
if (!EnumWindows(&WindowsEnumerationHandler, param))
|
if (!EnumWindows(&WindowsEnumerationHandler, param))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (auto it = result.begin(); it != result.end();) {
|
||||||
|
if (!window_capture_helper_.IsWindowOnCurrentDesktop(
|
||||||
|
reinterpret_cast<HWND>(it->id))) {
|
||||||
|
it = result.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
sources->swap(result);
|
sources->swap(result);
|
||||||
|
|
||||||
std::map<HWND, DesktopSize> new_map;
|
std::map<HWND, DesktopSize> new_map;
|
||||||
|
@ -220,12 +229,11 @@ void WindowCapturerWin::CaptureFrame() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a 1x1 black frame if the window is minimized or invisible, to match
|
// Return a 1x1 black frame if the window is minimized or invisible on current
|
||||||
// behavior on mace. Window can be temporarily invisible during the
|
// desktop, to match behavior on mace. Window can be temporarily invisible
|
||||||
// transition of full screen mode on/off.
|
// during the transition of full screen mode on/off.
|
||||||
if (original_rect.is_empty() ||
|
if (original_rect.is_empty() ||
|
||||||
IsIconic(window_) ||
|
!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(window_)) {
|
||||||
!IsWindowVisible(window_)) {
|
|
||||||
std::unique_ptr<DesktopFrame> frame(
|
std::unique_ptr<DesktopFrame> frame(
|
||||||
new BasicDesktopFrame(DesktopSize(1, 1)));
|
new BasicDesktopFrame(DesktopSize(1, 1)));
|
||||||
memset(frame->data(), 0, frame->stride() * frame->size().height());
|
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
|
// capturing - it somehow affects what we get from BitBlt() on the subsequent
|
||||||
// captures.
|
// 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);
|
result = PrintWindow(window_, mem_dc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename);
|
||||||
enum WindowsMajorVersions {
|
enum WindowsMajorVersions {
|
||||||
kWindows2000 = 5,
|
kWindows2000 = 5,
|
||||||
kWindowsVista = 6,
|
kWindowsVista = 6,
|
||||||
|
kWindows10 = 10,
|
||||||
};
|
};
|
||||||
bool GetOsVersion(int* major, int* minor, int* build);
|
bool GetOsVersion(int* major, int* minor, int* build);
|
||||||
|
|
||||||
|
@ -74,6 +75,11 @@ inline bool IsWindows8OrLater() {
|
||||||
(major > kWindowsVista || (major == kWindowsVista && minor >= 2)));
|
(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.
|
// Determine the current integrity level of the process.
|
||||||
bool GetCurrentProcessIntegrityLevel(int* level);
|
bool GetCurrentProcessIntegrityLevel(int* level);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue