1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 #include "mozilla/Preferences.h"
10 #include "mozilla/dom/battery/Constants.h"
11 #include "nsComponentManagerUtils.h"
14 #include "mozilla/WindowsVersion.h"
16 using namespace mozilla::dom::battery
;
21 static nsCOMPtr
<nsITimer
> sUpdateTimer
;
23 /* Power Event API is Vista or later */
24 static decltype(RegisterPowerSettingNotification
)* sRegisterPowerSettingNotification
= nullptr;
25 static decltype(UnregisterPowerSettingNotification
)* sUnregisterPowerSettingNotification
= nullptr;
26 static HPOWERNOTIFY sPowerHandle
= nullptr;
27 static HPOWERNOTIFY sCapacityHandle
= nullptr;
28 static HWND sHWnd
= nullptr;
31 UpdateHandler(nsITimer
* aTimer
, void* aClosure
) {
32 NS_ASSERTION(!IsVistaOrLater(),
33 "We shouldn't call this function for Vista or later version!");
35 static hal::BatteryInformation sLastInfo
;
36 hal::BatteryInformation currentInfo
;
38 hal_impl::GetCurrentBatteryInformation(¤tInfo
);
39 if (sLastInfo
.level() != currentInfo
.level() ||
40 sLastInfo
.charging() != currentInfo
.charging() ||
41 sLastInfo
.remainingTime() != currentInfo
.remainingTime()) {
42 hal::NotifyBatteryChange(currentInfo
);
43 sLastInfo
= currentInfo
;
49 BatteryWindowProc(HWND hwnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
) {
50 if (msg
!= WM_POWERBROADCAST
|| wParam
!= PBT_POWERSETTINGCHANGE
) {
51 return DefWindowProc(hwnd
, msg
, wParam
, lParam
);
54 hal::BatteryInformation currentInfo
;
56 // Since we need update remainingTime, we cannot use LPARAM.
57 hal_impl::GetCurrentBatteryInformation(¤tInfo
);
59 hal::NotifyBatteryChange(currentInfo
);
64 EnableBatteryNotifications()
66 if (IsVistaOrLater()) {
67 // RegisterPowerSettingNotification is from Vista or later.
68 // Use this API if available.
69 HMODULE hUser32
= GetModuleHandleW(L
"USER32.DLL");
70 if (!sRegisterPowerSettingNotification
)
71 sRegisterPowerSettingNotification
= (decltype(RegisterPowerSettingNotification
)*)
72 GetProcAddress(hUser32
, "RegisterPowerSettingNotification");
73 if (!sUnregisterPowerSettingNotification
)
74 sUnregisterPowerSettingNotification
= (decltype(UnregisterPowerSettingNotification
)*)
75 GetProcAddress(hUser32
, "UnregisterPowerSettingNotification");
77 if (!sRegisterPowerSettingNotification
||
78 !sUnregisterPowerSettingNotification
) {
79 NS_ASSERTION(false, "Canot find PowerSettingNotification functions.");
83 // Create custom window to watch battery event
84 // If we can get Gecko's window handle, this is unnecessary.
86 if (sHWnd
== nullptr) {
88 HMODULE hSelf
= GetModuleHandle(nullptr);
90 if (!GetClassInfoW(hSelf
, L
"MozillaBatteryClass", &wc
)) {
91 ZeroMemory(&wc
, sizeof(WNDCLASSW
));
93 wc
.lpfnWndProc
= BatteryWindowProc
;
94 wc
.lpszClassName
= L
"MozillaBatteryClass";
98 sHWnd
= CreateWindowW(L
"MozillaBatteryClass", L
"Battery Watcher",
100 nullptr, nullptr, hSelf
, nullptr);
103 if (sHWnd
== nullptr) {
108 sRegisterPowerSettingNotification(sHWnd
,
109 &GUID_ACDC_POWER_SOURCE
,
110 DEVICE_NOTIFY_WINDOW_HANDLE
);
112 sRegisterPowerSettingNotification(sHWnd
,
113 &GUID_BATTERY_PERCENTAGE_REMAINING
,
114 DEVICE_NOTIFY_WINDOW_HANDLE
);
117 // for Windows XP. If we remove Windows XP support,
118 // we should remove timer-based power notification
119 sUpdateTimer
= do_CreateInstance(NS_TIMER_CONTRACTID
);
121 sUpdateTimer
->InitWithFuncCallback(UpdateHandler
,
123 Preferences::GetInt("dom.battery.timer",
125 nsITimer::TYPE_REPEATING_SLACK
);
131 DisableBatteryNotifications()
133 if (IsVistaOrLater()) {
135 sUnregisterPowerSettingNotification(sPowerHandle
);
136 sPowerHandle
= nullptr;
139 if (sCapacityHandle
) {
140 sUnregisterPowerSettingNotification(sCapacityHandle
);
141 sCapacityHandle
= nullptr;
145 DestroyWindow(sHWnd
);
151 sUpdateTimer
->Cancel();
152 sUpdateTimer
= nullptr;
158 GetCurrentBatteryInformation(hal::BatteryInformation
* aBatteryInfo
)
160 SYSTEM_POWER_STATUS status
;
161 if (!GetSystemPowerStatus(&status
)) {
162 aBatteryInfo
->level() = kDefaultLevel
;
163 aBatteryInfo
->charging() = kDefaultCharging
;
164 aBatteryInfo
->remainingTime() = kDefaultRemainingTime
;
168 aBatteryInfo
->level() =
169 status
.BatteryLifePercent
== 255 ? kDefaultLevel
170 : ((double)status
.BatteryLifePercent
) / 100.0;
171 aBatteryInfo
->charging() = (status
.ACLineStatus
!= 0);
172 if (status
.ACLineStatus
!= 0) {
173 if (aBatteryInfo
->level() == 1.0) {
174 // GetSystemPowerStatus API may returns -1 for BatteryFullLifeTime.
175 // So, if battery is 100%, set kDefaultRemainingTime at force.
176 aBatteryInfo
->remainingTime() = kDefaultRemainingTime
;
178 aBatteryInfo
->remainingTime() =
179 status
.BatteryFullLifeTime
== (DWORD
)-1 ? kUnknownRemainingTime
180 : status
.BatteryFullLifeTime
;
183 aBatteryInfo
->remainingTime() =
184 status
.BatteryLifeTime
== (DWORD
)-1 ? kUnknownRemainingTime
185 : status
.BatteryLifeTime
;