forked from mirrors/gecko-dev
		
	 f047620639
			
		
	
	
		f047620639
		
	
	
	
	
		
			
			Unfortunately, while with MSVC one would use the `I` modifier to format LPARAM/LONG_PTR, it doesn't work with clang-cl on 32-bits, because LONG_PTR there is long, but `I` expects an int. Differential Revision: https://phabricator.services.mozilla.com/D144916
		
			
				
	
	
		
			217 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * 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 <windows.h>
 | |
| #include <winuser.h>
 | |
| #include <wtsapi32.h>
 | |
| 
 | |
| #include "WinEventObserver.h"
 | |
| 
 | |
| #include "mozilla/ClearOnShutdown.h"
 | |
| #include "mozilla/Logging.h"
 | |
| #include "mozilla/StaticPtr.h"
 | |
| #include "nsHashtablesFwd.h"
 | |
| 
 | |
| namespace mozilla::widget {
 | |
| 
 | |
| LazyLogModule gWinEventObserverLog("WinEventObserver");
 | |
| #define LOG(...) MOZ_LOG(gWinEventObserverLog, LogLevel::Info, (__VA_ARGS__))
 | |
| 
 | |
| // static
 | |
| StaticRefPtr<WinEventHub> WinEventHub::sInstance;
 | |
| 
 | |
| // static
 | |
| void WinEventHub::Ensure() {
 | |
|   if (sInstance) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   LOG("WinEventHub::Ensure()");
 | |
| 
 | |
|   RefPtr<WinEventHub> instance = new WinEventHub();
 | |
|   if (!instance->Initialize()) {
 | |
|     MOZ_ASSERT_UNREACHABLE("unexpected to be called");
 | |
|     return;
 | |
|   }
 | |
|   sInstance = instance;
 | |
|   ClearOnShutdown(&sInstance);
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   WinEventHub::Ensure();
 | |
|   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) {
 | |
|   WinEventHub::Ensure();
 | |
|   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(), ¤tSessionId)) {
 | |
|       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
 |