зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1732737 - Add VirtualDesktop handling to window occlusion on Windows r=gfx-reviewers,bradwerth
Implementation of WindowOcclusionCalculator::Initialize() is borrowed from InitializeVirtualDesktopManagerTask::Run(). And implementation of WindowOcclusionCalculator::IsWindowOnCurrentVirtualDesktop() is borrowed from chromium's WindowOcclusionCalculator::IsWindowOnCurrentVirtualDesktop() Differential Revision: https://phabricator.services.mozilla.com/D133327
This commit is contained in:
Родитель
85788740ea
Коммит
2daf591edf
|
@ -108,6 +108,8 @@ class WinWindowOcclusionTrackerInteractiveTest : public ::testing::Test {
|
|||
RefPtr<MockWinWidget> window = MockWinWidget::Create(
|
||||
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* aExStyle */ 0, aBounds);
|
||||
EXPECT_NE(nullptr, window.get());
|
||||
HWND hwnd = window->GetWnd();
|
||||
::ShowWindow(hwnd, SW_SHOWNORMAL);
|
||||
WinWindowOcclusionTracker::Get()->Enable(window, window->GetWnd());
|
||||
return window;
|
||||
}
|
||||
|
@ -132,6 +134,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, SimpleOcclusion) {
|
|||
window->SetExpectation(widget::OcclusionState::OCCLUDED);
|
||||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -140,10 +143,11 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, SimpleOcclusion) {
|
|||
// Simple test partially covering a tracked window with a native window.
|
||||
TEST_F(WinWindowOcclusionTrackerInteractiveTest, PartialOcclusion) {
|
||||
RefPtr<MockWinWidget> window =
|
||||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 200, 200));
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(0, 0, 50, 50));
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -163,6 +167,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, OffscreenOcclusion) {
|
|||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(screenLeft, 0, 50, 100));
|
||||
window->SetExpectation(widget::OcclusionState::OCCLUDED);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -175,6 +180,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, SimpleVisible) {
|
|||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(200, 0, 100, 100));
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -189,6 +196,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, SimpleHidden) {
|
|||
::CloseWindow(window->GetWnd());
|
||||
window->SetExpectation(widget::OcclusionState::HIDDEN);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -203,6 +211,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest,
|
|||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -214,6 +223,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest,
|
|||
::CloseWindow(window->GetWnd());
|
||||
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -235,6 +245,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest,
|
|||
::OpenIcon(window->GetWnd());
|
||||
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -242,6 +253,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest,
|
|||
window->SetExpectation(widget::OcclusionState::OCCLUDED);
|
||||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
@ -253,6 +265,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenVisibleOcclusion) {
|
|||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -266,6 +279,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenVisibleOcclusion) {
|
|||
WTS_SESSION_LOCK, currentSessionId);
|
||||
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
MSG msg;
|
||||
bool gotMessage =
|
||||
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
|
||||
|
@ -287,6 +302,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenHiddenOcclusion) {
|
|||
::CloseWindow(window->GetWnd());
|
||||
window->SetExpectation(widget::OcclusionState::HIDDEN);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -304,6 +320,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenHiddenOcclusion) {
|
|||
WTS_SESSION_LOCK, currentSessionId);
|
||||
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
MSG msg;
|
||||
bool gotMessage =
|
||||
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
|
||||
|
@ -321,9 +339,11 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenHiddenOcclusion) {
|
|||
// as occluded.
|
||||
TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenDifferentSession) {
|
||||
RefPtr<MockWinWidget> window =
|
||||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 200, 200));
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -341,6 +361,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenDifferentSession) {
|
|||
// Create a native window to trigger occlusion calculation.
|
||||
CreateNativeWindowWithBounds(LayoutDeviceIntRect(0, 0, 50, 50));
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
MSG msg;
|
||||
bool gotMessage =
|
||||
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
|
||||
|
@ -361,6 +383,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, DisplayOnOffHandling) {
|
|||
CreateTrackedWindowWithBounds(LayoutDeviceIntRect(0, 0, 100, 100));
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
|
@ -369,12 +393,16 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, DisplayOnOffHandling) {
|
|||
// Turning display off and on isn't feasible, so send a notification.
|
||||
OnDisplayStateChanged(/* aDisplayOn */ false);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
|
||||
window->SetExpectation(widget::OcclusionState::VISIBLE);
|
||||
OnDisplayStateChanged(/* aDisplayOn */ true);
|
||||
while (window->IsExpectingCall()) {
|
||||
WinWindowOcclusionTracker::Get()->TriggerCalculation();
|
||||
|
||||
NS_ProcessNextEvent(nullptr, /* aMayWait = */ true);
|
||||
}
|
||||
EXPECT_FALSE(window->IsExpectingCall());
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/StaticPrefs_widget.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsBaseWidget.h"
|
||||
#include "nsWindow.h"
|
||||
#include "transport/runnable_utils.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
|
@ -99,6 +100,8 @@ class SerializedTaskDispatcher {
|
|||
bool IsOnCurrentThread();
|
||||
|
||||
private:
|
||||
friend class DelayedTaskRunnable;
|
||||
|
||||
~SerializedTaskDispatcher();
|
||||
|
||||
struct Data {
|
||||
|
@ -119,6 +122,24 @@ class SerializedTaskDispatcher {
|
|||
DataMutex<Data> mData;
|
||||
};
|
||||
|
||||
class DelayedTaskRunnable : public Runnable {
|
||||
public:
|
||||
DelayedTaskRunnable(SerializedTaskDispatcher* aSerializedTaskDispatcher,
|
||||
already_AddRefed<Runnable> aTask)
|
||||
: Runnable("DelayedTaskRunnable"),
|
||||
mSerializedTaskDispatcher(aSerializedTaskDispatcher),
|
||||
mTask(aTask) {}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
mSerializedTaskDispatcher->HandleDelayedTask(mTask.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
RefPtr<SerializedTaskDispatcher> mSerializedTaskDispatcher;
|
||||
RefPtr<Runnable> mTask;
|
||||
};
|
||||
|
||||
SerializedTaskDispatcher::SerializedTaskDispatcher()
|
||||
: mData("SerializedTaskDispatcher::mData") {
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
@ -183,9 +204,8 @@ void SerializedTaskDispatcher::PostDelayedTaskToCalculator(
|
|||
CALC_LOG(LogLevel::Debug,
|
||||
"SerializedTaskDispatcher::PostDelayedTaskToCalculator()");
|
||||
|
||||
RefPtr<Runnable> runnable = WrapRunnable(
|
||||
RefPtr<SerializedTaskDispatcher>(this),
|
||||
&SerializedTaskDispatcher::HandleDelayedTask, std::move(aTask));
|
||||
RefPtr<DelayedTaskRunnable> runnable =
|
||||
new DelayedTaskRunnable(this, std::move(aTask));
|
||||
MessageLoop* targetLoop =
|
||||
WinWindowOcclusionTracker::OcclusionCalculatorLoop();
|
||||
targetLoop->PostDelayedTask(runnable.forget(), aDelayMs);
|
||||
|
@ -265,6 +285,9 @@ void SerializedTaskDispatcher::HandleTasks() {
|
|||
// Get next task
|
||||
{
|
||||
auto data = mData.Lock();
|
||||
if (data->mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
frontTask = nullptr;
|
||||
data->mTasks.pop();
|
||||
|
@ -322,6 +345,12 @@ void WinWindowOcclusionTracker::Ensure() {
|
|||
|
||||
sTracker = new WinWindowOcclusionTracker(thread);
|
||||
WindowOcclusionCalculator::CreateInstance();
|
||||
|
||||
RefPtr<Runnable> runnable =
|
||||
WrapRunnable(RefPtr<WindowOcclusionCalculator>(
|
||||
WindowOcclusionCalculator::GetInstance()),
|
||||
&WindowOcclusionCalculator::Initialize);
|
||||
sTracker->mSerializedTaskDispatcher->PostTaskToCalculator(runnable.forget());
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -343,6 +372,8 @@ void WinWindowOcclusionTracker::ShutDown() {
|
|||
OcclusionCalculatorLoop()->PostTask(runnable.forget());
|
||||
task.Wait();
|
||||
|
||||
sTracker->mThread->Stop();
|
||||
|
||||
WindowOcclusionCalculator::ClearInstance();
|
||||
sTracker = nullptr;
|
||||
}
|
||||
|
@ -706,6 +737,14 @@ void WinWindowOcclusionTracker::MarkNonIconicWindowsOccluded() {
|
|||
}
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::TriggerCalculation() {
|
||||
RefPtr<Runnable> runnable =
|
||||
WrapRunnable(RefPtr<WindowOcclusionCalculator>(
|
||||
WindowOcclusionCalculator::GetInstance()),
|
||||
&WindowOcclusionCalculator::HandleTriggerCalculation);
|
||||
mSerializedTaskDispatcher->PostTaskToCalculator(runnable.forget());
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL WinWindowOcclusionTracker::DumpOccludingWindowsCallback(HWND aHWnd,
|
||||
LPARAM aLParam) {
|
||||
|
@ -765,6 +804,27 @@ void WinWindowOcclusionTracker::WindowOcclusionCalculator::ClearInstance() {
|
|||
sCalculator = nullptr;
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::WindowOcclusionCalculator::Initialize() {
|
||||
MOZ_ASSERT(IsInWinWindowOcclusionThread());
|
||||
MOZ_ASSERT(!mVirtualDesktopManager);
|
||||
CALC_LOG(LogLevel::Info, "Initialize()");
|
||||
|
||||
#ifndef __MINGW32__
|
||||
if (!IsWin10OrLater()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<IVirtualDesktopManager> desktopManager;
|
||||
HRESULT hr = ::CoCreateInstance(
|
||||
CLSID_VirtualDesktopManager, NULL, CLSCTX_INPROC_SERVER,
|
||||
__uuidof(IVirtualDesktopManager), getter_AddRefs(desktopManager));
|
||||
if (FAILED(hr)) {
|
||||
return;
|
||||
}
|
||||
mVirtualDesktopManager = desktopManager;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::WindowOcclusionCalculator::Shutdown(
|
||||
layers::SynchronousTask* aTask) {
|
||||
MOZ_ASSERT(IsInWinWindowOcclusionThread());
|
||||
|
@ -777,6 +837,7 @@ void WinWindowOcclusionTracker::WindowOcclusionCalculator::Shutdown(
|
|||
mOcclusionUpdateRunnable->Cancel();
|
||||
mOcclusionUpdateRunnable = nullptr;
|
||||
}
|
||||
mVirtualDesktopManager = nullptr;
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::WindowOcclusionCalculator::
|
||||
|
@ -837,6 +898,15 @@ void WinWindowOcclusionTracker::WindowOcclusionCalculator::
|
|||
}
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::WindowOcclusionCalculator::
|
||||
HandleTriggerCalculation() {
|
||||
MOZ_ASSERT(IsInWinWindowOcclusionThread());
|
||||
CALC_LOG(LogLevel::Info, "HandleTriggerCalculation()");
|
||||
|
||||
MaybeRegisterEventHooks();
|
||||
ScheduleOcclusionCalculationIfNeeded();
|
||||
}
|
||||
|
||||
void WinWindowOcclusionTracker::WindowOcclusionCalculator::
|
||||
MaybeRegisterEventHooks() {
|
||||
if (mGlobalEventHooks.empty()) {
|
||||
|
@ -1288,9 +1358,40 @@ Maybe<bool> WinWindowOcclusionTracker::WindowOcclusionCalculator::
|
|||
return Some(true);
|
||||
}
|
||||
|
||||
// XXX VirtualDesktopManager is going to be handled by Bug 1732737.
|
||||
BOOL onCurrentDesktop;
|
||||
HRESULT hr = mVirtualDesktopManager->IsWindowOnCurrentVirtualDesktop(
|
||||
aHwnd, &onCurrentDesktop);
|
||||
if (FAILED(hr)) {
|
||||
// In this case, we do not know the window is in which virtual desktop.
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Nothing();
|
||||
if (onCurrentDesktop) {
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
GUID workspaceGuid;
|
||||
hr = mVirtualDesktopManager->GetWindowDesktopId(aHwnd, &workspaceGuid);
|
||||
if (FAILED(hr)) {
|
||||
// In this case, we do not know the window is in which virtual desktop.
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
// IsWindowOnCurrentVirtualDesktop() is flaky for newly opened windows,
|
||||
// which causes test flakiness. Occasionally, it incorrectly says a window
|
||||
// is not on the current virtual desktop when it is. In this situation,
|
||||
// it also returns GUID_NULL for the desktop id.
|
||||
if (workspaceGuid == GUID_NULL) {
|
||||
// In this case, we do not know if the window is in which virtual desktop.
|
||||
// But we hanle it as on current virtual desktop.
|
||||
// It does not cause a problem to window occlusion.
|
||||
// Since if window is not on current virtual desktop, window size becomes
|
||||
// (0, 0, 0, 0). It makes window occlusion handling explicit. It is
|
||||
// necessary for gtest.
|
||||
return Some(true);
|
||||
}
|
||||
|
||||
return Some(false);
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
|
|
|
@ -75,6 +75,8 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener,
|
|||
return mSerializedTaskDispatcher;
|
||||
}
|
||||
|
||||
void TriggerCalculation();
|
||||
|
||||
void DumpOccludingWindows(HWND aHWnd);
|
||||
|
||||
private:
|
||||
|
@ -99,6 +101,7 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener,
|
|||
// Returns existing WindowOcclusionCalculator instance.
|
||||
static WindowOcclusionCalculator* GetInstance() { return sCalculator; }
|
||||
|
||||
void Initialize();
|
||||
void Shutdown(layers::SynchronousTask* aTask);
|
||||
|
||||
void EnableOcclusionTrackingForWindow(HWND hwnd);
|
||||
|
@ -107,6 +110,8 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener,
|
|||
// If a window becomes visible, makes sure event hooks are registered.
|
||||
void HandleVisibilityChanged(bool aVisible);
|
||||
|
||||
void HandleTriggerCalculation();
|
||||
|
||||
private:
|
||||
WindowOcclusionCalculator();
|
||||
~WindowOcclusionCalculator();
|
||||
|
@ -236,7 +241,6 @@ class WinWindowOcclusionTracker final : public DisplayStatusListener,
|
|||
HWND mMovingWindow = 0;
|
||||
|
||||
// Only used on Win10+.
|
||||
// XXX VirtualDesktopManager is going to be handled by Bug 1732737.
|
||||
RefPtr<IVirtualDesktopManager> mVirtualDesktopManager;
|
||||
|
||||
// Used to serialize tasks related to mRootWindowHwndsOcclusionState.
|
||||
|
|
Загрузка…
Ссылка в новой задаче