Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / widget / windows / WinEventObserver.cpp
blob7abac8a59a439d0060a7c7999eb0734544e65649
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <windows.h>
8 #include <winuser.h>
9 #include <wtsapi32.h>
11 #include "WinEventObserver.h"
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/Logging.h"
15 #include "mozilla/StaticPtr.h"
16 #include "nsHashtablesFwd.h"
17 #include "nsdefs.h"
19 namespace mozilla::widget {
21 LazyLogModule gWinEventObserverLog("WinEventObserver");
22 #define LOG(...) MOZ_LOG(gWinEventObserverLog, LogLevel::Info, (__VA_ARGS__))
24 // static
25 StaticRefPtr<WinEventHub> WinEventHub::sInstance;
27 // static
28 bool WinEventHub::Ensure() {
29 if (sInstance) {
30 return true;
33 LOG("WinEventHub::Ensure()");
35 RefPtr<WinEventHub> instance = new WinEventHub();
36 if (!instance->Initialize()) {
37 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
38 return false;
40 sInstance = instance;
41 ClearOnShutdown(&sInstance);
42 return true;
45 WinEventHub::WinEventHub() {
46 MOZ_ASSERT(NS_IsMainThread());
47 LOG("WinEventHub::WinEventHub()");
50 WinEventHub::~WinEventHub() {
51 MOZ_ASSERT(NS_IsMainThread());
52 MOZ_ASSERT(mObservers.IsEmpty());
53 LOG("WinEventHub::~WinEventHub()");
55 if (mHWnd) {
56 ::DestroyWindow(mHWnd);
57 mHWnd = nullptr;
61 bool WinEventHub::Initialize() {
62 WNDCLASSW wc;
63 HMODULE hSelf = ::GetModuleHandle(nullptr);
65 if (!GetClassInfoW(hSelf, L"MozillaWinEventHubClass", &wc)) {
66 ZeroMemory(&wc, sizeof(WNDCLASSW));
67 wc.hInstance = hSelf;
68 wc.lpfnWndProc = WinEventProc;
69 wc.lpszClassName = L"MozillaWinEventHubClass";
70 RegisterClassW(&wc);
73 mHWnd = ::CreateWindowW(L"MozillaWinEventHubClass", L"WinEventHub", 0, 0, 0,
74 0, 0, nullptr, nullptr, hSelf, nullptr);
75 if (!mHWnd) {
76 return false;
79 return true;
82 // static
83 LRESULT CALLBACK WinEventHub::WinEventProc(HWND aHwnd, UINT aMsg,
84 WPARAM aWParam, LPARAM aLParam) {
85 if (sInstance) {
86 sInstance->ProcessWinEventProc(aHwnd, aMsg, aWParam, aLParam);
88 return ::DefWindowProc(aHwnd, aMsg, aWParam, aLParam);
91 void WinEventHub::ProcessWinEventProc(HWND aHwnd, UINT aMsg, WPARAM aWParam,
92 LPARAM aLParam) {
93 for (const auto& observer : mObservers) {
94 observer->OnWinEventProc(aHwnd, aMsg, aWParam, aLParam);
98 void WinEventHub::AddObserver(WinEventObserver* aObserver) {
99 LOG("WinEventHub::AddObserver() aObserver %p", aObserver);
101 mObservers.Insert(aObserver);
104 void WinEventHub::RemoveObserver(WinEventObserver* aObserver) {
105 LOG("WinEventHub::RemoveObserver() aObserver %p", aObserver);
107 mObservers.Remove(aObserver);
110 WinEventObserver::~WinEventObserver() {
111 MOZ_ASSERT(NS_IsMainThread());
112 MOZ_ASSERT(mDestroyed);
115 void WinEventObserver::Destroy() {
116 LOG("WinEventObserver::Destroy() this %p", this);
118 WinEventHub::Get()->RemoveObserver(this);
119 mDestroyed = true;
122 // static
123 already_AddRefed<DisplayStatusObserver> DisplayStatusObserver::Create(
124 DisplayStatusListener* aListener) {
125 if (!WinEventHub::Ensure()) {
126 return nullptr;
128 RefPtr<DisplayStatusObserver> observer = new DisplayStatusObserver(aListener);
129 WinEventHub::Get()->AddObserver(observer);
130 return observer.forget();
133 DisplayStatusObserver::DisplayStatusObserver(DisplayStatusListener* aListener)
134 : mListener(aListener) {
135 MOZ_ASSERT(NS_IsMainThread());
136 LOG("DisplayStatusObserver::DisplayStatusObserver() this %p", this);
138 mDisplayStatusHandle = ::RegisterPowerSettingNotification(
139 WinEventHub::Get()->GetWnd(), &GUID_SESSION_DISPLAY_STATUS,
140 DEVICE_NOTIFY_WINDOW_HANDLE);
143 DisplayStatusObserver::~DisplayStatusObserver() {
144 MOZ_ASSERT(NS_IsMainThread());
145 LOG("DisplayStatusObserver::~DisplayStatusObserver() this %p", this);
147 if (mDisplayStatusHandle) {
148 ::UnregisterPowerSettingNotification(mDisplayStatusHandle);
149 mDisplayStatusHandle = nullptr;
153 void DisplayStatusObserver::OnWinEventProc(HWND aHwnd, UINT aMsg,
154 WPARAM aWParam, LPARAM aLParam) {
155 if (aMsg == WM_POWERBROADCAST && aWParam == PBT_POWERSETTINGCHANGE) {
156 POWERBROADCAST_SETTING* setting = (POWERBROADCAST_SETTING*)aLParam;
157 if (setting &&
158 ::IsEqualGUID(setting->PowerSetting, GUID_SESSION_DISPLAY_STATUS) &&
159 setting->DataLength == sizeof(DWORD)) {
160 bool displayOn = PowerMonitorOff !=
161 static_cast<MONITOR_DISPLAY_STATE>(setting->Data[0]);
163 LOG("DisplayStatusObserver::OnWinEventProc() displayOn %d this %p",
164 displayOn, this);
165 mListener->OnDisplayStateChanged(displayOn);
170 // static
171 already_AddRefed<SessionChangeObserver> SessionChangeObserver::Create(
172 SessionChangeListener* aListener) {
173 if (!WinEventHub::Ensure()) {
174 return nullptr;
176 RefPtr<SessionChangeObserver> observer = new SessionChangeObserver(aListener);
177 WinEventHub::Get()->AddObserver(observer);
178 return observer.forget();
181 SessionChangeObserver::SessionChangeObserver(SessionChangeListener* aListener)
182 : mListener(aListener) {
183 MOZ_ASSERT(NS_IsMainThread());
184 LOG("SessionChangeObserver::SessionChangeObserver() this %p", this);
186 auto hwnd = WinEventHub::Get()->GetWnd();
187 DebugOnly<BOOL> wtsRegistered =
188 ::WTSRegisterSessionNotification(hwnd, NOTIFY_FOR_THIS_SESSION);
189 NS_ASSERTION(wtsRegistered, "WTSRegisterSessionNotification failed!\n");
191 SessionChangeObserver::~SessionChangeObserver() {
192 MOZ_ASSERT(NS_IsMainThread());
193 LOG("SessionChangeObserver::~SessionChangeObserver() this %p", this);
195 auto hwnd = WinEventHub::Get()->GetWnd();
196 // Unregister notifications from terminal services
197 ::WTSUnRegisterSessionNotification(hwnd);
200 void SessionChangeObserver::OnWinEventProc(HWND aHwnd, UINT aMsg,
201 WPARAM aWParam, LPARAM aLParam) {
202 if (aMsg == WM_WTSSESSION_CHANGE &&
203 (aWParam == WTS_SESSION_LOCK || aWParam == WTS_SESSION_UNLOCK)) {
204 Maybe<bool> isCurrentSession;
205 DWORD currentSessionId = 0;
206 if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &currentSessionId)) {
207 isCurrentSession = Nothing();
208 } else {
209 LOG("SessionChangeObserver::OnWinEventProc() aWParam %zu aLParam "
210 "%" PRIdLPTR
212 "currentSessionId %lu this %p",
213 aWParam, aLParam, currentSessionId, this);
215 isCurrentSession = Some(static_cast<DWORD>(aLParam) == currentSessionId);
217 mListener->OnSessionChange(aWParam, isCurrentSession);
221 #undef LOG
223 } // namespace mozilla::widget