Backed out 2 changesets (bug 1915665) for causing failures at WinEventObserver.cpp. CLOSED TREE

Backed out changeset a3d4ad8b9ad8 (bug 1915665)
Backed out changeset 1428595baef7 (bug 1915665)
This commit is contained in:
Butkovits Atila 2024-09-12 10:59:44 +03:00
Родитель c8281fa1c6
Коммит 171a4c7e85
5 изменённых файлов: 366 добавлений и 193 удалений

Просмотреть файл

@ -36,8 +36,8 @@ class WinWindowOcclusionTrackerInteractiveTest : public ::testing::Test {
WinWindowOcclusionTracker::Ensure();
EXPECT_NE(nullptr, WinWindowOcclusionTracker::Get());
Preferences::SetBool(PREF_DISPLAY_STATE, true);
Preferences::SetBool(PREF_SESSION_LOCK, true);
WinWindowOcclusionTracker::Get()->EnsureDisplayStatusObserver();
WinWindowOcclusionTracker::Get()->EnsureSessionChangeObserver();
}
void TearDown() override {
@ -264,19 +264,19 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenVisibleOcclusion) {
window->SetExpectation(widget::OcclusionState::OCCLUDED);
// Unfortunately, this relies on knowing that NativeWindowOcclusionTracker
// uses WinEventWindow to listen for WM_WTSSESSION_CHANGE messages, but
// uses SessionChangeObserver to listen for WM_WTSSESSION_CHANGE messages, but
// actually locking the screen isn't feasible.
DWORD currentSessionId = 0;
::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId);
::PostMessage(WinEventWindow::GetHwndForTestingOnly(), WM_WTSSESSION_CHANGE,
::PostMessage(WinEventHub::Get()->GetWnd(), WM_WTSSESSION_CHANGE,
WTS_SESSION_LOCK, currentSessionId);
while (window->IsExpectingCall()) {
WinWindowOcclusionTracker::Get()->TriggerCalculation();
MSG msg;
bool gotMessage = ::PeekMessageW(
&msg, WinEventWindow::GetHwndForTestingOnly(), 0, 0, PM_REMOVE);
bool gotMessage =
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
if (gotMessage) {
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
@ -305,19 +305,19 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenHiddenOcclusion) {
window->SetExpectation(widget::OcclusionState::HIDDEN);
// Unfortunately, this relies on knowing that NativeWindowOcclusionTracker
// uses WinEventWindow to listen for WM_WTSSESSION_CHANGE messages, but
// uses SessionChangeObserver to listen for WM_WTSSESSION_CHANGE messages, but
// actually locking the screen isn't feasible.
DWORD currentSessionId = 0;
::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId);
PostMessage(WinEventWindow::GetHwndForTestingOnly(), WM_WTSSESSION_CHANGE,
PostMessage(WinEventHub::Get()->GetWnd(), WM_WTSSESSION_CHANGE,
WTS_SESSION_LOCK, currentSessionId);
while (window->IsExpectingCall()) {
WinWindowOcclusionTracker::Get()->TriggerCalculation();
MSG msg;
bool gotMessage = ::PeekMessageW(
&msg, WinEventWindow::GetHwndForTestingOnly(), 0, 0, PM_REMOVE);
bool gotMessage =
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
if (gotMessage) {
::TranslateMessage(&msg);
::DispatchMessageW(&msg);
@ -347,7 +347,7 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenDifferentSession) {
// currentSessionId.
DWORD currentSessionId = 0;
::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId);
::PostMessage(WinEventWindow::GetHwndForTestingOnly(), WM_WTSSESSION_CHANGE,
::PostMessage(WinEventHub::Get()->GetWnd(), WM_WTSSESSION_CHANGE,
WTS_SESSION_LOCK, currentSessionId + 1);
window->SetExpectation(widget::OcclusionState::VISIBLE);
@ -357,8 +357,8 @@ TEST_F(WinWindowOcclusionTrackerInteractiveTest, LockScreenDifferentSession) {
WinWindowOcclusionTracker::Get()->TriggerCalculation();
MSG msg;
bool gotMessage = ::PeekMessageW(
&msg, WinEventWindow::GetHwndForTestingOnly(), 0, 0, PM_REMOVE);
bool gotMessage =
::PeekMessageW(&msg, WinEventHub::Get()->GetWnd(), 0, 0, PM_REMOVE);
if (gotMessage) {
::TranslateMessage(&msg);
::DispatchMessageW(&msg);

Просмотреть файл

@ -4,171 +4,220 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <corecrt_memcpy_s.h>
#include <windows.h>
#include <winternl.h>
#include <winuser.h>
#include <wtsapi32.h>
#include "WinEventObserver.h"
#include "WinWindowOcclusionTracker.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Logging.h"
#include "nsWindowDbg.h"
#include "mozilla/StaticPtr.h"
#include "nsHashtablesFwd.h"
#include "nsdefs.h"
#include "nsXULAppAPI.h"
// borrowed from devblogs.microsoft.com/oldnewthing/20041025-00/?p=37483, by way
// of the Chromium sandboxing code's "current_module.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
#define CURRENT_MODULE() reinterpret_cast<HMODULE>(&__ImageBase)
// N.B.: if and when we eliminate the existing `WindowType::Invisible` hidden
// window, we must switch to use of `kClassNameHidden` for the class name. (See
// commentary therebeside.)
const wchar_t kClassNameHidden2[] = L"MozillaHiddenWindowClass2";
namespace mozilla::widget {
LazyLogModule gWinEventWindowLog("WinEventWindow");
#define OBS_LOG(...) \
MOZ_LOG(gWinEventWindowLog, ::mozilla::LogLevel::Info, (__VA_ARGS__))
namespace {
static HWND sHiddenWindow = nullptr;
}
/* static */
void WinEventWindow::Ensure() {
if (sHiddenWindow) return;
MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
MOZ_RELEASE_ASSERT(NS_IsMainThread());
HMODULE const hSelf = CURRENT_MODULE();
WNDCLASSW const wc = {.lpfnWndProc = WinEventWindow::WndProc,
.hInstance = hSelf,
.lpszClassName = kClassNameHidden2};
ATOM const atom = ::RegisterClassW(&wc);
if (!atom) {
// This is known to be possible when the atom table no longer has free
// entries, which unfortunately happens more often than one might expect.
// See bug 1571516.
auto volatile const err [[maybe_unused]] = ::GetLastError();
MOZ_CRASH("could not register broadcast-receiver window-class");
}
sHiddenWindow =
::CreateWindowW((LPCWSTR)(uintptr_t)atom, L"WinEventWindow", 0, 0, 0, 0,
0, nullptr, nullptr, hSelf, nullptr);
if (!sHiddenWindow) {
MOZ_CRASH("could not create broadcast-receiver window");
}
};
/* static */
HWND WinEventWindow::GetHwndForTestingOnly() { return sHiddenWindow; }
// Callbacks for individual event types. These are private and internal
// implementation details of WinEventWindow.
namespace {
namespace evtwin_details {
static void OnSessionChange(WPARAM wParam, LPARAM lParam) {
if (wParam == WTS_SESSION_LOCK || wParam == WTS_SESSION_UNLOCK) {
DWORD currentSessionId;
BOOL const rv =
::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId);
if (rv) {
// A process should always have the relevant access privileges for itself,
// but the above call could still fail if, e.g., someone's playing games
// with function imports. If so, just assert and/or skip out.
//
// Should this turn out to somehow be a real concern, we could do
// ```
// DWORD const currentSessionId =
// ::NtCurrentTeb()->ProcessEnvironmentBlock->SessionId;
// ```
// instead, which is actually documented (albeit abjured against).
MOZ_ASSERT(false, "::ProcessIdToSessionId() failed");
return;
}
OBS_LOG("WinEventWindow OnSessionChange(): wParam=%zu lParam=%" PRIdLPTR
" currentSessionId=%lu",
wParam, lParam, currentSessionId);
// Ignore lock/unlock messages for other sessions -- which Windows actually
// _does_ send in some scenarios; see review of Chromium changeset 1929489:
//
// https://chromium-review.googlesource.com/c/chromium/src/+/1929489
if (currentSessionId != (DWORD)lParam) {
return;
}
if (auto* wwot = WinWindowOcclusionTracker::Get()) {
wwot->OnSessionChange(wParam);
}
}
}
static void OnPowerBroadcast(WPARAM wParam, LPARAM lParam) {
if (wParam == PBT_POWERSETTINGCHANGE) {
POWERBROADCAST_SETTING* setting = (POWERBROADCAST_SETTING*)lParam;
MOZ_ASSERT(setting);
if (::IsEqualGUID(setting->PowerSetting, GUID_SESSION_DISPLAY_STATUS) &&
setting->DataLength == sizeof(DWORD)) {
MONITOR_DISPLAY_STATE state{};
errno_t const err =
::memcpy_s(&state, sizeof(state), setting->Data, setting->DataLength);
if (err) {
MOZ_ASSERT(false, "bad data in POWERBROADCAST_SETTING in lParam");
return;
}
bool const displayOn = MONITOR_DISPLAY_STATE::PowerMonitorOff != state;
OBS_LOG("WinEventWindow OnPowerBroadcast(): displayOn=%d",
int(displayOn ? 1 : 0));
if (auto* wwot = WinWindowOcclusionTracker::Get()) {
wwot->OnDisplayStateChanged(displayOn);
}
}
}
}
} // namespace evtwin_details
} // namespace
LazyLogModule gWinEventObserverLog("WinEventObserver");
#define LOG(...) MOZ_LOG(gWinEventObserverLog, LogLevel::Info, (__VA_ARGS__))
// static
LRESULT CALLBACK WinEventWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam) {
NativeEventLogger eventLogger("WinEventWindow", hwnd, msg, wParam, lParam);
StaticRefPtr<WinEventHub> WinEventHub::sInstance;
switch (msg) {
case WM_WINDOWPOSCHANGING: {
// prevent rude external programs from making hidden window visible
LPWINDOWPOS info = (LPWINDOWPOS)lParam;
info->flags &= ~SWP_SHOWWINDOW;
} break;
case WM_WTSSESSION_CHANGE: {
evtwin_details::OnSessionChange(wParam, lParam);
} break;
case WM_POWERBROADCAST: {
evtwin_details::OnPowerBroadcast(wParam, lParam);
} break;
// static
bool WinEventHub::Ensure() {
if (sInstance) {
return true;
}
LRESULT ret = ::DefWindowProcW(hwnd, msg, wParam, lParam);
eventLogger.SetResult(ret, false);
return ret;
LOG("WinEventHub::Ensure()");
RefPtr<WinEventHub> instance = new WinEventHub();
if (!instance->Initialize()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
sInstance = instance;
ClearOnShutdown(&sInstance);
return true;
}
#undef OBS_LOG
WinEventHub::WinEventHub() {
MOZ_ASSERT(NS_IsMainThread());
LOG("WinEventHub::WinEventHub()");
}
WinEventHub::~WinEventHub() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mObservers.IsEmpty());
LOG("WinEventHub::~WinEventHub()");
if (mHWnd) {
::DestroyWindow(mHWnd);
mHWnd = nullptr;
}
}
bool WinEventHub::Initialize() {
WNDCLASSW wc;
HMODULE hSelf = ::GetModuleHandle(nullptr);
if (!GetClassInfoW(hSelf, L"MozillaWinEventHubClass", &wc)) {
ZeroMemory(&wc, sizeof(WNDCLASSW));
wc.hInstance = hSelf;
wc.lpfnWndProc = WinEventProc;
wc.lpszClassName = L"MozillaWinEventHubClass";
RegisterClassW(&wc);
}
mHWnd = ::CreateWindowW(L"MozillaWinEventHubClass", L"WinEventHub", 0, 0, 0,
0, 0, nullptr, nullptr, hSelf, nullptr);
if (!mHWnd) {
return false;
}
return true;
}
// static
LRESULT CALLBACK WinEventHub::WinEventProc(HWND aHwnd, UINT aMsg,
WPARAM aWParam, LPARAM aLParam) {
if (sInstance) {
sInstance->ProcessWinEventProc(aHwnd, aMsg, aWParam, aLParam);
}
return ::DefWindowProc(aHwnd, aMsg, aWParam, aLParam);
}
void WinEventHub::ProcessWinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
LPARAM aLParam) {
for (const auto& observer : mObservers) {
observer->OnWinEventProc(aHwnd, aMsg, aWParam, aLParam);
}
}
void WinEventHub::AddObserver(WinEventObserver* aObserver) {
LOG("WinEventHub::AddObserver() aObserver %p", aObserver);
mObservers.Insert(aObserver);
}
void WinEventHub::RemoveObserver(WinEventObserver* aObserver) {
LOG("WinEventHub::RemoveObserver() aObserver %p", aObserver);
mObservers.Remove(aObserver);
}
WinEventObserver::~WinEventObserver() {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mDestroyed);
}
void WinEventObserver::Destroy() {
LOG("WinEventObserver::Destroy() this %p", this);
WinEventHub::Get()->RemoveObserver(this);
mDestroyed = true;
}
// static
already_AddRefed<DisplayStatusObserver> DisplayStatusObserver::Create(
DisplayStatusListener* aListener) {
if (!WinEventHub::Ensure()) {
return nullptr;
}
RefPtr<DisplayStatusObserver> observer = new DisplayStatusObserver(aListener);
WinEventHub::Get()->AddObserver(observer);
return observer.forget();
}
DisplayStatusObserver::DisplayStatusObserver(DisplayStatusListener* aListener)
: mListener(aListener) {
MOZ_ASSERT(NS_IsMainThread());
LOG("DisplayStatusObserver::DisplayStatusObserver() this %p", this);
mDisplayStatusHandle = ::RegisterPowerSettingNotification(
WinEventHub::Get()->GetWnd(), &GUID_SESSION_DISPLAY_STATUS,
DEVICE_NOTIFY_WINDOW_HANDLE);
}
DisplayStatusObserver::~DisplayStatusObserver() {
MOZ_ASSERT(NS_IsMainThread());
LOG("DisplayStatusObserver::~DisplayStatusObserver() this %p", this);
if (mDisplayStatusHandle) {
::UnregisterPowerSettingNotification(mDisplayStatusHandle);
mDisplayStatusHandle = nullptr;
}
}
void DisplayStatusObserver::OnWinEventProc(HWND aHwnd, UINT aMsg,
WPARAM aWParam, LPARAM aLParam) {
if (aMsg == WM_POWERBROADCAST && aWParam == PBT_POWERSETTINGCHANGE) {
POWERBROADCAST_SETTING* setting = (POWERBROADCAST_SETTING*)aLParam;
if (setting &&
::IsEqualGUID(setting->PowerSetting, GUID_SESSION_DISPLAY_STATUS) &&
setting->DataLength == sizeof(DWORD)) {
bool displayOn = PowerMonitorOff !=
static_cast<MONITOR_DISPLAY_STATE>(setting->Data[0]);
LOG("DisplayStatusObserver::OnWinEventProc() displayOn %d this %p",
displayOn, this);
mListener->OnDisplayStateChanged(displayOn);
}
}
}
// static
already_AddRefed<SessionChangeObserver> SessionChangeObserver::Create(
SessionChangeListener* aListener) {
if (!WinEventHub::Ensure()) {
return nullptr;
}
RefPtr<SessionChangeObserver> observer = new SessionChangeObserver(aListener);
WinEventHub::Get()->AddObserver(observer);
return observer.forget();
}
SessionChangeObserver::SessionChangeObserver(SessionChangeListener* aListener)
: mListener(aListener) {
MOZ_ASSERT(NS_IsMainThread());
LOG("SessionChangeObserver::SessionChangeObserver() this %p", this);
auto hwnd = WinEventHub::Get()->GetWnd();
DebugOnly<BOOL> wtsRegistered =
::WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_THIS_SESSION);
NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
}
SessionChangeObserver::~SessionChangeObserver() {
MOZ_ASSERT(NS_IsMainThread());
LOG("SessionChangeObserver::~SessionChangeObserver() this %p", this);
auto hwnd = WinEventHub::Get()->GetWnd();
// Unregister notifications from terminal services
::WTSUnRegisterSessionNotification(hwnd);
}
void SessionChangeObserver::OnWinEventProc(HWND aHwnd, UINT aMsg,
WPARAM aWParam, LPARAM aLParam) {
if (aMsg == WM_WTSSESSION_CHANGE &&
(aWParam == WTS_SESSION_LOCK || aWParam == WTS_SESSION_UNLOCK)) {
Maybe<bool> isCurrentSession;
DWORD currentSessionId = 0;
if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId)) {
isCurrentSession = Nothing();
} else {
LOG("SessionChangeObserver::OnWinEventProc() aWParam %zu aLParam "
"%" PRIdLPTR
" "
"currentSessionId %lu this %p",
aWParam, aLParam, currentSessionId, this);
isCurrentSession = Some(static_cast<DWORD>(aLParam) == currentSessionId);
}
mListener->OnSessionChange(aWParam, isCurrentSession);
}
}
#undef LOG
} // namespace mozilla::widget

Просмотреть файл

@ -7,27 +7,109 @@
#ifndef widget_windows_WinEventObserver_h
#define widget_windows_WinEventObserver_h
#include <windef.h>
#include <windows.h>
namespace mozilla::widget {
#include "mozilla/Maybe.h"
#include "nsISupportsImpl.h"
#include "nsTHashSet.h"
class WinEventWindow {
namespace mozilla {
namespace widget {
class WinEventObserver {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WinEventObserver)
public:
// Create the hidden window. This window will persist for the lifetime of the
// process: we do not destroy it, but neither does it keep the process alive.
//
// Must be called in the parent process and on the main thread. Crashes on
// failure.
static void Ensure();
virtual void OnWinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
LPARAM aLParam) {}
virtual void Destroy();
// (Do not call in real code.)
static HWND GetHwndForTestingOnly();
protected:
virtual ~WinEventObserver();
private:
// the hidden window's WNDPROC
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
bool mDestroyed = false;
};
} // namespace mozilla::widget
// Uses singleton window to observe events like display status and session
// change.
class WinEventHub final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WinEventHub)
public:
// Returns true if the singleton exists (or was created). Will return
// false if the singleton couldn't be created, in which case a call
// to Get() will return a nullptr. It is safe to call this function
// repeatedly.
static bool Ensure();
static RefPtr<WinEventHub> Get() { return sInstance; }
void AddObserver(WinEventObserver* aObserver);
void RemoveObserver(WinEventObserver* aObserver);
HWND GetWnd() { return mHWnd; }
private:
WinEventHub();
~WinEventHub();
static LRESULT CALLBACK WinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
LPARAM aLParam);
bool Initialize();
void ProcessWinEventProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND mHWnd = nullptr;
nsTHashSet<nsRefPtrHashKey<WinEventObserver>> mObservers;
static StaticRefPtr<WinEventHub> sInstance;
};
class DisplayStatusListener {
public:
virtual void OnDisplayStateChanged(bool aDisplayOn) = 0;
};
// Observe Display on/off event
class DisplayStatusObserver final : public WinEventObserver {
public:
static already_AddRefed<DisplayStatusObserver> Create(
DisplayStatusListener* aListener);
private:
explicit DisplayStatusObserver(DisplayStatusListener* aListener);
virtual ~DisplayStatusObserver();
void OnWinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
LPARAM aLParam) override;
DisplayStatusListener* mListener;
HPOWERNOTIFY mDisplayStatusHandle = nullptr;
};
class SessionChangeListener {
public:
virtual void OnSessionChange(WPARAM aStatusCode,
Maybe<bool> aIsCurrentSession) = 0;
};
// Observe session lock/unlock event
class SessionChangeObserver : public WinEventObserver {
public:
static already_AddRefed<SessionChangeObserver> Create(
SessionChangeListener* aListener);
private:
explicit SessionChangeObserver(SessionChangeListener* aListener);
virtual ~SessionChangeObserver();
void Initialize();
void OnWinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
LPARAM aLParam) override;
SessionChangeListener* mListener;
};
} // namespace widget
} // namespace mozilla
#endif // widget_windows_WinEventObserver_h

Просмотреть файл

@ -25,7 +25,6 @@
#include "nsBaseWidget.h"
#include "nsWindow.h"
#include "transport/runnable_utils.h"
#include "WinEventObserver.h"
#include "WinUtils.h"
namespace mozilla::widget {
@ -342,6 +341,12 @@ void WinWindowOcclusionTracker::Ensure() {
if (sTracker->mThread->StartWithOptions(options)) {
// Success!
sTracker->mHasAttemptedShutdown = false;
// Take this opportunity to ensure that mDisplayStatusObserver and
// mSessionChangeObserver exist. They might have failed to be
// created when sTracker was created.
sTracker->EnsureDisplayStatusObserver();
sTracker->EnsureSessionChangeObserver();
return;
}
// Restart failed, so null out our sTracker and try again with a new
@ -423,6 +428,14 @@ void WinWindowOcclusionTracker::ShutDown() {
}
void WinWindowOcclusionTracker::Destroy() {
if (mDisplayStatusObserver) {
mDisplayStatusObserver->Destroy();
mDisplayStatusObserver = nullptr;
}
if (mSessionChangeObserver) {
mSessionChangeObserver->Destroy();
mSessionChangeObserver = nullptr;
}
if (mSerializedTaskDispatcher) {
mSerializedTaskDispatcher->Destroy();
}
@ -439,6 +452,26 @@ bool WinWindowOcclusionTracker::IsInWinWindowOcclusionThread() {
sTracker->mThread->thread_id() == PlatformThread::CurrentId();
}
void WinWindowOcclusionTracker::EnsureDisplayStatusObserver() {
if (mDisplayStatusObserver) {
return;
}
if (StaticPrefs::
widget_windows_window_occlusion_tracking_display_state_enabled()) {
mDisplayStatusObserver = DisplayStatusObserver::Create(this);
}
}
void WinWindowOcclusionTracker::EnsureSessionChangeObserver() {
if (mSessionChangeObserver) {
return;
}
if (StaticPrefs::
widget_windows_window_occlusion_tracking_session_lock_enabled()) {
mSessionChangeObserver = SessionChangeObserver::Create(this);
}
}
void WinWindowOcclusionTracker::Enable(nsBaseWidget* aWindow, HWND aHwnd) {
MOZ_ASSERT(NS_IsMainThread());
LOG(LogLevel::Info, "WinWindowOcclusionTracker::Enable() aWindow %p aHwnd %p",
@ -500,7 +533,8 @@ WinWindowOcclusionTracker::WinWindowOcclusionTracker(
MOZ_ASSERT(NS_IsMainThread());
LOG(LogLevel::Info, "WinWindowOcclusionTracker::WinWindowOcclusionTracker()");
WinEventWindow::Ensure();
EnsureDisplayStatusObserver();
EnsureSessionChangeObserver();
mSerializedTaskDispatcher = new SerializedTaskDispatcher();
}
@ -703,10 +737,11 @@ void WinWindowOcclusionTracker::UpdateOcclusionState(
}
}
void WinWindowOcclusionTracker::OnSessionChange(WPARAM aStatusCode) {
void WinWindowOcclusionTracker::OnSessionChange(WPARAM aStatusCode,
Maybe<bool> aIsCurrentSession) {
MOZ_ASSERT(NS_IsMainThread());
if (!StaticPrefs::
widget_windows_window_occlusion_tracking_session_lock_enabled()) {
if (aIsCurrentSession.isNothing() || !*aIsCurrentSession) {
return;
}
@ -728,11 +763,6 @@ void WinWindowOcclusionTracker::OnSessionChange(WPARAM aStatusCode) {
void WinWindowOcclusionTracker::OnDisplayStateChanged(bool aDisplayOn) {
MOZ_ASSERT(NS_IsMainThread());
if (!StaticPrefs::
widget_windows_window_occlusion_tracking_display_state_enabled()) {
return;
}
LOG(LogLevel::Info,
"WinWindowOcclusionTracker::OnDisplayStateChanged() aDisplayOn %d",
aDisplayOn);

Просмотреть файл

@ -7,8 +7,7 @@
#ifndef widget_windows_WinWindowOcclusionTracker_h
#define widget_windows_WinWindowOcclusionTracker_h
#include <windef.h>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@ -16,7 +15,10 @@
#include "nsIWeakReferenceUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/WindowsVersion.h"
#include "mozilla/ThreadSafeWeakPtr.h"
#include "mozilla/widget/WindowOcclusionState.h"
#include "mozilla/widget/WinEventObserver.h"
#include "Units.h"
#include "nsThreadUtils.h"
@ -39,7 +41,8 @@ class UpdateOcclusionStateRunnable;
// This class handles window occlusion tracking by using HWND.
// Implementation is borrowed from chromium's NativeWindowOcclusionTrackerWin.
class WinWindowOcclusionTracker final {
class WinWindowOcclusionTracker final : public DisplayStatusListener,
public SessionChangeListener {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WinWindowOcclusionTracker)
@ -58,6 +61,12 @@ class WinWindowOcclusionTracker final {
/// Can be called from any thread.
static bool IsInWinWindowOcclusionThread();
/// Can only be called from the main thread.
void EnsureDisplayStatusObserver();
/// Can only be called from the main thread.
void EnsureSessionChangeObserver();
// Enables notifying to widget via NotifyOcclusionState() when the occlusion
// state has been computed.
void Enable(nsBaseWidget* aWindow, HWND aHwnd);
@ -271,16 +280,15 @@ class WinWindowOcclusionTracker final {
void UpdateOcclusionState(std::unordered_map<HWND, OcclusionState>* aMap,
bool aShowAllWindows);
public:
// This is called with session changed notifications. If the screen is locked
// by the current session, it marks app windows as occluded.
void OnSessionChange(WPARAM aStatusCode);
void OnSessionChange(WPARAM aStatusCode,
Maybe<bool> aIsCurrentSession) override;
// This is called when the display is put to sleep. If the display is sleeping
// it marks app windows as occluded.
void OnDisplayStateChanged(bool aDisplayOn);
void OnDisplayStateChanged(bool aDisplayOn) override;
private:
// Marks all root windows as either occluded, or if hwnd IsIconic, hidden.
void MarkNonIconicWindowsOccluded();
@ -308,6 +316,10 @@ class WinWindowOcclusionTracker final {
// If the display is off, windows are considered occluded.
bool mDisplayOn = true;
RefPtr<DisplayStatusObserver> mDisplayStatusObserver;
RefPtr<SessionChangeObserver> mSessionChangeObserver;
// Used to serialize tasks related to mRootWindowHwndsOcclusionState.
RefPtr<SerializedTaskDispatcher> mSerializedTaskDispatcher;