mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +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 {
|
||||
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<HWND>(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<HWND>(excluded_window()), content_rect);
|
||||
TopWindowVerifierContext context(selected,
|
||||
reinterpret_cast<HWND>(excluded_window()),
|
||||
content_rect, &window_capture_helper_);
|
||||
const LPARAM enum_param = reinterpret_cast<LPARAM>(&context);
|
||||
EnumWindows(&TopWindowVerifier, enum_param);
|
||||
if (!context.is_top_window) {
|
||||
|
|
|
@ -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<DwmIsCompositionEnabledFunc>(
|
||||
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
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <shlobj.h>
|
||||
#include <windows.h>
|
||||
#include <wrl/client.h>
|
||||
|
||||
#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<IVirtualDesktopManager> virtual_desktop_manager_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(WindowCaptureHelperWin);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -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<HWND>(it->id))) {
|
||||
it = result.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
sources->swap(result);
|
||||
|
||||
std::map<HWND, DesktopSize> 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<DesktopFrame> 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue