|
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/. */ |
|
5 |
|
6 #include "Hal.h" |
|
7 #include "HalImpl.h" |
|
8 #include "nsITimer.h" |
|
9 #include "mozilla/Preferences.h" |
|
10 #include "mozilla/dom/battery/Constants.h" |
|
11 #include "nsComponentManagerUtils.h" |
|
12 |
|
13 #include <windows.h> |
|
14 #include "mozilla/WindowsVersion.h" |
|
15 |
|
16 using namespace mozilla::dom::battery; |
|
17 |
|
18 namespace mozilla { |
|
19 namespace hal_impl { |
|
20 |
|
21 static nsCOMPtr<nsITimer> sUpdateTimer; |
|
22 |
|
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; |
|
29 |
|
30 static void |
|
31 UpdateHandler(nsITimer* aTimer, void* aClosure) { |
|
32 NS_ASSERTION(!IsVistaOrLater(), |
|
33 "We shouldn't call this function for Vista or later version!"); |
|
34 |
|
35 static hal::BatteryInformation sLastInfo; |
|
36 hal::BatteryInformation currentInfo; |
|
37 |
|
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; |
|
44 } |
|
45 } |
|
46 |
|
47 static |
|
48 LRESULT CALLBACK |
|
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); |
|
52 } |
|
53 |
|
54 hal::BatteryInformation currentInfo; |
|
55 |
|
56 // Since we need update remainingTime, we cannot use LPARAM. |
|
57 hal_impl::GetCurrentBatteryInformation(¤tInfo); |
|
58 |
|
59 hal::NotifyBatteryChange(currentInfo); |
|
60 return TRUE; |
|
61 } |
|
62 |
|
63 void |
|
64 EnableBatteryNotifications() |
|
65 { |
|
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"); |
|
76 |
|
77 if (!sRegisterPowerSettingNotification || |
|
78 !sUnregisterPowerSettingNotification) { |
|
79 NS_ASSERTION(false, "Canot find PowerSettingNotification functions."); |
|
80 return; |
|
81 } |
|
82 |
|
83 // Create custom window to watch battery event |
|
84 // If we can get Gecko's window handle, this is unnecessary. |
|
85 |
|
86 if (sHWnd == nullptr) { |
|
87 WNDCLASSW wc; |
|
88 HMODULE hSelf = GetModuleHandle(nullptr); |
|
89 |
|
90 if (!GetClassInfoW(hSelf, L"MozillaBatteryClass", &wc)) { |
|
91 ZeroMemory(&wc, sizeof(WNDCLASSW)); |
|
92 wc.hInstance = hSelf; |
|
93 wc.lpfnWndProc = BatteryWindowProc; |
|
94 wc.lpszClassName = L"MozillaBatteryClass"; |
|
95 RegisterClassW(&wc); |
|
96 } |
|
97 |
|
98 sHWnd = CreateWindowW(L"MozillaBatteryClass", L"Battery Watcher", |
|
99 0, 0, 0, 0, 0, |
|
100 nullptr, nullptr, hSelf, nullptr); |
|
101 } |
|
102 |
|
103 if (sHWnd == nullptr) { |
|
104 return; |
|
105 } |
|
106 |
|
107 sPowerHandle = |
|
108 sRegisterPowerSettingNotification(sHWnd, |
|
109 &GUID_ACDC_POWER_SOURCE, |
|
110 DEVICE_NOTIFY_WINDOW_HANDLE); |
|
111 sCapacityHandle = |
|
112 sRegisterPowerSettingNotification(sHWnd, |
|
113 &GUID_BATTERY_PERCENTAGE_REMAINING, |
|
114 DEVICE_NOTIFY_WINDOW_HANDLE); |
|
115 } else |
|
116 { |
|
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); |
|
120 if (sUpdateTimer) { |
|
121 sUpdateTimer->InitWithFuncCallback(UpdateHandler, |
|
122 nullptr, |
|
123 Preferences::GetInt("dom.battery.timer", |
|
124 30000 /* 30s */), |
|
125 nsITimer::TYPE_REPEATING_SLACK); |
|
126 } |
|
127 } |
|
128 } |
|
129 |
|
130 void |
|
131 DisableBatteryNotifications() |
|
132 { |
|
133 if (IsVistaOrLater()) { |
|
134 if (sPowerHandle) { |
|
135 sUnregisterPowerSettingNotification(sPowerHandle); |
|
136 sPowerHandle = nullptr; |
|
137 } |
|
138 |
|
139 if (sCapacityHandle) { |
|
140 sUnregisterPowerSettingNotification(sCapacityHandle); |
|
141 sCapacityHandle = nullptr; |
|
142 } |
|
143 |
|
144 if (sHWnd) { |
|
145 DestroyWindow(sHWnd); |
|
146 sHWnd = nullptr; |
|
147 } |
|
148 } else |
|
149 { |
|
150 if (sUpdateTimer) { |
|
151 sUpdateTimer->Cancel(); |
|
152 sUpdateTimer = nullptr; |
|
153 } |
|
154 } |
|
155 } |
|
156 |
|
157 void |
|
158 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) |
|
159 { |
|
160 SYSTEM_POWER_STATUS status; |
|
161 if (!GetSystemPowerStatus(&status)) { |
|
162 aBatteryInfo->level() = kDefaultLevel; |
|
163 aBatteryInfo->charging() = kDefaultCharging; |
|
164 aBatteryInfo->remainingTime() = kDefaultRemainingTime; |
|
165 return; |
|
166 } |
|
167 |
|
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; |
|
177 } else { |
|
178 aBatteryInfo->remainingTime() = |
|
179 status.BatteryFullLifeTime == (DWORD)-1 ? kUnknownRemainingTime |
|
180 : status.BatteryFullLifeTime; |
|
181 } |
|
182 } else { |
|
183 aBatteryInfo->remainingTime() = |
|
184 status.BatteryLifeTime == (DWORD)-1 ? kUnknownRemainingTime |
|
185 : status.BatteryLifeTime; |
|
186 } |
|
187 } |
|
188 |
|
189 } // hal_impl |
|
190 } // mozilla |