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/. */
11 #include "WinEventObserver.h"
13 #include "mozilla/ClearOnShutdown.h"
14 #include "mozilla/Logging.h"
15 #include "mozilla/StaticPtr.h"
16 #include "nsHashtablesFwd.h"
19 namespace mozilla::widget
{
21 LazyLogModule
gWinEventObserverLog("WinEventObserver");
22 #define LOG(...) MOZ_LOG(gWinEventObserverLog, LogLevel::Info, (__VA_ARGS__))
25 StaticRefPtr
<WinEventHub
> WinEventHub::sInstance
;
28 bool WinEventHub::Ensure() {
33 LOG("WinEventHub::Ensure()");
35 RefPtr
<WinEventHub
> instance
= new WinEventHub();
36 if (!instance
->Initialize()) {
37 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
41 ClearOnShutdown(&sInstance
);
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()");
56 ::DestroyWindow(mHWnd
);
61 bool WinEventHub::Initialize() {
63 HMODULE hSelf
= ::GetModuleHandle(nullptr);
65 if (!GetClassInfoW(hSelf
, L
"MozillaWinEventHubClass", &wc
)) {
66 ZeroMemory(&wc
, sizeof(WNDCLASSW
));
68 wc
.lpfnWndProc
= WinEventProc
;
69 wc
.lpszClassName
= L
"MozillaWinEventHubClass";
73 mHWnd
= ::CreateWindowW(L
"MozillaWinEventHubClass", L
"WinEventHub", 0, 0, 0,
74 0, 0, nullptr, nullptr, hSelf
, nullptr);
83 LRESULT CALLBACK
WinEventHub::WinEventProc(HWND aHwnd
, UINT aMsg
,
84 WPARAM aWParam
, LPARAM aLParam
) {
86 sInstance
->ProcessWinEventProc(aHwnd
, aMsg
, aWParam
, aLParam
);
88 return ::DefWindowProc(aHwnd
, aMsg
, aWParam
, aLParam
);
91 void WinEventHub::ProcessWinEventProc(HWND aHwnd
, UINT aMsg
, WPARAM aWParam
,
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);
123 already_AddRefed
<DisplayStatusObserver
> DisplayStatusObserver::Create(
124 DisplayStatusListener
* aListener
) {
125 if (!WinEventHub::Ensure()) {
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
;
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",
165 mListener
->OnDisplayStateChanged(displayOn
);
171 already_AddRefed
<SessionChangeObserver
> SessionChangeObserver::Create(
172 SessionChangeListener
* aListener
) {
173 if (!WinEventHub::Ensure()) {
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(), ¤tSessionId
)) {
207 isCurrentSession
= Nothing();
209 LOG("SessionChangeObserver::OnWinEventProc() aWParam %zu aLParam "
212 "currentSessionId %lu this %p",
213 aWParam
, aLParam
, currentSessionId
, this);
215 isCurrentSession
= Some(static_cast<DWORD
>(aLParam
) == currentSessionId
);
217 mListener
->OnSessionChange(aWParam
, isCurrentSession
);
223 } // namespace mozilla::widget