Tests for WindowFinder
This change adds several tests for WindowFinder implmenetations. One of the tests uses ScreenDrawer to create a foreground window or console window (on Windows) and ensures WindowFinder can return its window_id(). The other ensures WindowFinder always returns kNullWindowId if the |pos| is out of the screens. Bug: webrtc:7950 Change-Id: I0cc8794e201c2fa042ea8e693434f1b0fa05b47a Reviewed-on: https://chromium-review.googlesource.com/639591 Reviewed-by: Jamie Walch <jamiewalch@chromium.org> Commit-Queue: Zijie He <zijiehe@chromium.org> Cr-Commit-Position: refs/heads/master@{#19676}
This commit is contained in:
parent
7fdf857d26
commit
77b7a1da2d
@ -58,6 +58,7 @@ if (rtc_include_tests) {
|
||||
sources += [
|
||||
"screen_capturer_integration_test.cc",
|
||||
"screen_drawer_unittest.cc",
|
||||
"window_finder_unittest.cc",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/rgba_color.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -49,7 +50,8 @@ class ScreenDrawer {
|
||||
// Returns the region inside which DrawRectangle() function are expected to
|
||||
// work, in capturer coordinates (assuming ScreenCapturer::SelectScreen has
|
||||
// not been called). This region may exclude regions of the screen reserved by
|
||||
// the OS for things like menu bars or app launchers.
|
||||
// the OS for things like menu bars or app launchers. The DesktopRect is in
|
||||
// system coordinate, i.e. the primary monitor always starts from (0, 0).
|
||||
virtual DesktopRect DrawableRegion() = 0;
|
||||
|
||||
// Draws a rectangle to cover |rect| with |color|. Note, rect.bottom() and
|
||||
@ -70,6 +72,10 @@ class ScreenDrawer {
|
||||
// shapes will eventually be drawn on the screen, due to some OS limitations,
|
||||
// these shapes may be partially appeared sometimes.
|
||||
virtual bool MayDrawIncompleteShapes() = 0;
|
||||
|
||||
// Returns the id of the drawer window. This function returns kNullWindowId if
|
||||
// the implementation does not draw on a window of the system.
|
||||
virtual WindowId window_id() const = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -36,6 +36,7 @@ class ScreenDrawerLinux : public ScreenDrawer {
|
||||
void Clear() override;
|
||||
void WaitForPendingDraws() override;
|
||||
bool MayDrawIncompleteShapes() override;
|
||||
WindowId window_id() const override;
|
||||
|
||||
private:
|
||||
// Bring the window to the front, this can help to avoid the impact from other
|
||||
@ -136,6 +137,10 @@ bool ScreenDrawerLinux::MayDrawIncompleteShapes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
WindowId ScreenDrawerLinux::window_id() const {
|
||||
return window_;
|
||||
}
|
||||
|
||||
void ScreenDrawerLinux::BringToFront() {
|
||||
Atom state_above = XInternAtom(display_->display(), "_NET_WM_STATE_ABOVE", 1);
|
||||
Atom window_state = XInternAtom(display_->display(), "_NET_WM_STATE", 1);
|
||||
|
||||
@ -82,6 +82,7 @@ class ScreenDrawerWin : public ScreenDrawer {
|
||||
void Clear() override;
|
||||
void WaitForPendingDraws() override;
|
||||
bool MayDrawIncompleteShapes() override;
|
||||
WindowId window_id() const override;
|
||||
|
||||
private:
|
||||
// Bring the window to the front, this can help to avoid the impact from other
|
||||
@ -158,6 +159,10 @@ bool ScreenDrawerWin::MayDrawIncompleteShapes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
WindowId ScreenDrawerWin::window_id() const {
|
||||
return reinterpret_cast<WindowId>(window_);
|
||||
}
|
||||
|
||||
void ScreenDrawerWin::DrawLine(DesktopVector start,
|
||||
DesktopVector end,
|
||||
RgbaColor color) {
|
||||
|
||||
@ -11,11 +11,17 @@
|
||||
#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_FINDER_H_
|
||||
#define WEBRTC_MODULES_DESKTOP_CAPTURE_WINDOW_FINDER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#if defined(USE_X11)
|
||||
class XAtomCache;
|
||||
#endif
|
||||
|
||||
// An interface to return the id of the visible window under a certain point.
|
||||
class WindowFinder {
|
||||
public:
|
||||
@ -28,6 +34,17 @@ class WindowFinder {
|
||||
// |point| is always in system coordinate, i.e. the primary monitor always
|
||||
// starts from (0, 0).
|
||||
virtual WindowId GetWindowUnderPoint(DesktopVector point) = 0;
|
||||
|
||||
struct Options {
|
||||
#if defined(USE_X11)
|
||||
XAtomCache* cache = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Creates a platform-independent WindowFinder implementation. This function
|
||||
// returns nullptr if |options| does not contain enough information or
|
||||
// WindowFinder does not support current platform.
|
||||
static std::unique_ptr<WindowFinder> Create(const Options& options);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
|
||||
#include "webrtc/rtc_base/ptr_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -33,4 +34,10 @@ WindowId WindowFinderMac::GetWindowUnderPoint(DesktopVector point) {
|
||||
return id;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<WindowFinder> WindowFinder::Create(
|
||||
const WindowFinder::Options& options) {
|
||||
return rtc::MakeUnique<WindowFinderMac>();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
161
webrtc/modules/desktop_capture/window_finder_unittest.cc
Normal file
161
webrtc/modules/desktop_capture/window_finder_unittest.cc
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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 "webrtc/modules/desktop_capture/window_finder.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/desktop_geometry.h"
|
||||
#include "webrtc/modules/desktop_capture/screen_drawer.h"
|
||||
#include "webrtc/rtc_base/logging.h"
|
||||
#include "webrtc/test/gtest.h"
|
||||
|
||||
#if defined(USE_X11)
|
||||
#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
|
||||
#include "webrtc/modules/desktop_capture/x11/x_atom_cache.h"
|
||||
#include "webrtc/rtc_base/ptr_util.h"
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
#include <windows.h>
|
||||
|
||||
#include "webrtc/modules/desktop_capture/window_finder_win.h"
|
||||
#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(WEBRTC_WIN)
|
||||
// ScreenDrawerWin does not have a message loop, so it's unresponsive to user
|
||||
// inputs. WindowFinderWin cannot detect this kind of unresponsive windows.
|
||||
// Instead, console window is used to test WindowFinderWin.
|
||||
TEST(WindowFinderTest, FindConsoleWindow) {
|
||||
// Creates a ScreenDrawer to avoid this test from conflicting with
|
||||
// ScreenCapturerIntegrationTest: both tests require its window to be in
|
||||
// foreground.
|
||||
//
|
||||
// In ScreenCapturer related tests, this is controlled by
|
||||
// ScreenDrawer, which has a global lock to ensure only one ScreenDrawer
|
||||
// window is active. So even we do not use ScreenDrawer for Windows test,
|
||||
// creating an instance can block ScreenCapturer related tests until this test
|
||||
// finishes.
|
||||
//
|
||||
// Usually the test framework should take care of this "isolated test"
|
||||
// requirement, but unfortunately WebRTC trybots do not support this.
|
||||
std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
|
||||
const int kMaxSize = 10000;
|
||||
// Enlarges current console window.
|
||||
system("mode 1000,1000");
|
||||
const HWND console_window = GetConsoleWindow();
|
||||
MoveWindow(console_window, 0, 0, kMaxSize, kMaxSize, true);
|
||||
|
||||
// Brings console window to top.
|
||||
SetWindowPos(
|
||||
console_window, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
|
||||
BringWindowToTop(console_window);
|
||||
|
||||
WindowFinderWin finder;
|
||||
for (int i = 0; i < kMaxSize; i++) {
|
||||
const DesktopVector spot(i, i);
|
||||
const HWND id = reinterpret_cast<HWND>(finder.GetWindowUnderPoint(spot));
|
||||
if (id == console_window) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FAIL();
|
||||
}
|
||||
|
||||
#else
|
||||
TEST(WindowFinderTest, FindDrawerWindow) {
|
||||
WindowFinder::Options options;
|
||||
#if defined(USE_X11)
|
||||
std::unique_ptr<XAtomCache> cache;
|
||||
const auto shared_x_display = SharedXDisplay::CreateDefault();
|
||||
if (shared_x_display) {
|
||||
cache = rtc::MakeUnique<XAtomCache>(shared_x_display->display());
|
||||
options.cache = cache.get();
|
||||
}
|
||||
#endif
|
||||
std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options);
|
||||
if (!finder) {
|
||||
LOG(LS_WARNING) << "No WindowFinder implementation for current platform.";
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create();
|
||||
if (!drawer) {
|
||||
LOG(LS_WARNING) << "No ScreenDrawer implementation for current platform.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (drawer->window_id() == kNullWindowId) {
|
||||
// TODO(zijiehe): WindowFinderTest can use a dedicated window without
|
||||
// relying on ScreenDrawer.
|
||||
LOG(LS_WARNING) << "ScreenDrawer implementation for current platform does "
|
||||
"create a window.";
|
||||
return;
|
||||
}
|
||||
|
||||
// ScreenDrawer may not be able to bring the window to the top. So we test
|
||||
// several spots, at least one of them should succeed.
|
||||
const DesktopRect region = drawer->DrawableRegion();
|
||||
if (region.is_empty()) {
|
||||
LOG(LS_WARNING) << "ScreenDrawer::DrawableRegion() is too small for the "
|
||||
"WindowFinderTest.";
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < region.width(); i++) {
|
||||
const DesktopVector spot(
|
||||
region.left() + i, region.top() + i * region.height() / region.width());
|
||||
const WindowId id = finder->GetWindowUnderPoint(spot);
|
||||
if (id == drawer->window_id()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FAIL();
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(WindowFinderTest, ShouldReturnNullWindowIfSpotIsOutOfScreen) {
|
||||
WindowFinder::Options options;
|
||||
#if defined(USE_X11)
|
||||
std::unique_ptr<XAtomCache> cache;
|
||||
const auto shared_x_display = SharedXDisplay::CreateDefault();
|
||||
if (shared_x_display) {
|
||||
cache = rtc::MakeUnique<XAtomCache>(shared_x_display->display());
|
||||
options.cache = cache.get();
|
||||
}
|
||||
#endif
|
||||
std::unique_ptr<WindowFinder> finder = WindowFinder::Create(options);
|
||||
if (!finder) {
|
||||
LOG(LS_WARNING) << "No WindowFinder implementation for current platform.";
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_EQ(kNullWindowId, finder->GetWindowUnderPoint(
|
||||
DesktopVector(INT16_MAX, INT16_MAX)));
|
||||
ASSERT_EQ(kNullWindowId, finder->GetWindowUnderPoint(
|
||||
DesktopVector(INT16_MAX, INT16_MIN)));
|
||||
ASSERT_EQ(kNullWindowId, finder->GetWindowUnderPoint(
|
||||
DesktopVector(INT16_MIN, INT16_MAX)));
|
||||
ASSERT_EQ(kNullWindowId, finder->GetWindowUnderPoint(
|
||||
DesktopVector(INT16_MIN, INT16_MIN)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace webrtc
|
||||
@ -12,6 +12,8 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "webrtc/rtc_base/ptr_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
WindowFinderWin::WindowFinderWin() = default;
|
||||
@ -35,4 +37,10 @@ WindowId WindowFinderWin::GetWindowUnderPoint(DesktopVector point) {
|
||||
return reinterpret_cast<WindowId>(window);
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<WindowFinder> WindowFinder::Create(
|
||||
const WindowFinder::Options& options) {
|
||||
return rtc::MakeUnique<WindowFinderWin>();
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include "webrtc/modules/desktop_capture/x11/window_list_utils.h"
|
||||
#include "webrtc/rtc_base/checks.h"
|
||||
#include "webrtc/rtc_base/ptr_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -37,4 +38,14 @@ WindowId WindowFinderX11::GetWindowUnderPoint(DesktopVector point) {
|
||||
return id;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<WindowFinder> WindowFinder::Create(
|
||||
const WindowFinder::Options& options) {
|
||||
if (options.cache == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return rtc::MakeUnique<WindowFinderX11>(options.cache);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user