Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

786 lines
23 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1993-1995
  4. *
  5. * TITLE: POWER.C
  6. *
  7. * VERSION: 2.0
  8. *
  9. * AUTHOR: TCS/RAL
  10. *
  11. * DATE: 08 Feb 1994
  12. *
  13. ********************************************************************************
  14. *
  15. * CHANGE LOG:
  16. *
  17. * DATE REV DESCRIPTION
  18. * ----------- --- -------------------------------------------------------------
  19. * 08 Feb 1994 TCS Original implementation.
  20. * 11 Nov 1994 RAL Converted from batmeter to systray
  21. * 11 Aug 1995 JEM Split batmeter functions into power.c & minor enahncements
  22. * 23 Oct 1995 Shawnb UNICODE Enabled
  23. * 24 Jan 1997 Reedb ACPI power management, common battery meter code.
  24. *
  25. *******************************************************************************/
  26. #include "stdafx.h"
  27. #include <nt.h>
  28. #include <ntrtl.h>
  29. #include <nturtl.h>
  30. #include <initguid.h>
  31. #include <ntpoapi.h>
  32. #include <poclass.h>
  33. #include "systray.h"
  34. #include "batmeter.h"
  35. #include "powrprof.h"
  36. #include "powercfp.h"
  37. #define UPDATE_REGISTRY TRUE
  38. #define NO_REGISTRY_UPDATE FALSE
  39. // Structure to manage the power profile enum proc parameters.
  40. typedef struct _POWER_PROFILE_ENUM_PROC_PARAMS
  41. {
  42. UINT uiCurActiveIndex;
  43. HMENU hMenu;
  44. UINT uiCurActiveID;
  45. } POWER_PROFILE_ENUM_PROC_PARAMS, *PPOWER_PROFILE_ENUM_PROC_PARAMS;
  46. // G L O B A L D A T A -------------------------------------------------------
  47. BOOL g_bPowerEnabled; // Tracks the power service state.
  48. UINT g_uiPowerSchemeCount; // Number of power schemes, left context menu.
  49. HMENU g_hMenu[2]; // Context menus.
  50. // BatMeter creation parameters.
  51. HWND g_hwndBatMeter;
  52. BOOL g_bShowMulti;
  53. HWND g_hwndBatMeterFrame;
  54. GLOBAL_POWER_POLICY g_gpp;
  55. // Context sensitive help must be added to the windows.hlp file,
  56. // for now we will use this dummy array define. Remove when windows.hlp updated.
  57. #define IDH_POWERCFG_ENABLEMULTI IDH_POWERCFG_POWERSTATUSBAR
  58. const DWORD g_ContextMenuHelpIDs[] = {
  59. IDC_POWERSTATUSGROUPBOX, IDH_COMM_GROUPBOX,
  60. IDC_ENABLEMETER, IDH_POWERCFG_ENABLEMETER,
  61. IDC_ENABLEMULTI, IDH_POWERCFG_ENABLEMULTI,
  62. 0, 0
  63. };
  64. // Used to track registration for WM_DEVICECHANGED message.
  65. HDEVNOTIFY g_hDevNotify;
  66. /*******************************************************************************
  67. *
  68. * RunningOffLine
  69. *
  70. * DESCRIPTION:
  71. *
  72. * PARAMETERS:
  73. *
  74. *******************************************************************************/
  75. BOOLEAN RunningOffLine(void)
  76. {
  77. SYSTEM_POWER_STATUS sps;
  78. BOOLEAN bRet = FALSE;
  79. if (GetSystemPowerStatus(&sps)) {
  80. if (sps.ACLineStatus == 0) {
  81. bRet = TRUE;
  82. }
  83. }
  84. return bRet;
  85. }
  86. /*----------------------------------------------------------------------------
  87. * Power_OnCommand
  88. *
  89. * Process WM_COMMAND msgs for the battery meter dialog.
  90. *
  91. *----------------------------------------------------------------------------*/
  92. void
  93. Power_OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  94. {
  95. BOOL Checked;
  96. DWORD dwMask;
  97. UINT uiCommandID = GET_WM_COMMAND_ID(wParam, lParam);
  98. switch (uiCommandID) {
  99. case IDC_ENABLEMETER:
  100. dwMask = EnableSysTrayBatteryMeter;
  101. goto DoUpdateFlags;
  102. case IDC_ENABLEMULTI:
  103. dwMask = EnableMultiBatteryDisplay;
  104. goto DoUpdateFlags;
  105. DoUpdateFlags:
  106. Checked = (IsDlgButtonChecked(hWnd, uiCommandID) == BST_CHECKED);
  107. Update_PowerFlags(dwMask, Checked);
  108. if (uiCommandID == IDC_ENABLEMETER) {
  109. PowerCfg_Notify();
  110. SysTray_EnableService(STSERVICE_POWER, g_gpp.user.GlobalFlags & EnableSysTrayBatteryMeter);
  111. }
  112. else {
  113. g_bShowMulti = Checked;
  114. Power_UpdateStatus(hWnd, NIM_MODIFY, TRUE);
  115. }
  116. break;
  117. case IDCANCEL:
  118. EndDialog(hWnd, wParam);
  119. break;
  120. default:
  121. // Notify battery meter of enter key events.
  122. if (HIWORD(wParam) == BN_CLICKED) {
  123. SendMessage(g_hwndBatMeter, WM_COMMAND, wParam, lParam);
  124. }
  125. }
  126. }
  127. /*******************************************************************************
  128. *
  129. * Power_OnPowerBroadcast
  130. *
  131. * DESCRIPTION:
  132. * Process WM_POWERBROADCAS message for the battery meter dialog.
  133. *
  134. * PARAMETERS:
  135. *
  136. *******************************************************************************/
  137. void Power_OnPowerBroadcast(HWND hWnd, WPARAM wParam, LPARAM lParam)
  138. {
  139. if (wParam == PBT_APMPOWERSTATUSCHANGE) {
  140. // If the power icon is not showing (power service disabled) and
  141. // we are running on batteries, enable the systray power service.
  142. if (!g_bPowerEnabled && RunningOffLine()) {
  143. PostMessage(hWnd, STWM_ENABLESERVICE, STSERVICE_POWER, TRUE);
  144. } else
  145. // If the power icon is showing (power service enabled) and
  146. // we are not running on batteries, disable the systray power service.
  147. if (g_bPowerEnabled && !RunningOffLine()) {
  148. PostMessage(hWnd, STWM_ENABLESERVICE, STSERVICE_POWER, FALSE);
  149. }
  150. // Don't change the state of the power service, just update the icon.
  151. Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE);
  152. }
  153. }
  154. /*******************************************************************************
  155. *
  156. * Power_OnDeviceChange
  157. *
  158. * DESCRIPTION:
  159. * Process WM_DEVICECHANGE message for the battery meter dialog.
  160. *
  161. * PARAMETERS:
  162. *
  163. *******************************************************************************/
  164. void Power_OnDeviceChange(HWND hWnd, WPARAM wParam, LPARAM lParam)
  165. {
  166. //
  167. // Only listen to the WM_DEVICECHANGE if it is for GUID_DEVICE_BATTERY and
  168. // it is a DBT_DEVICEARRIVAL, DBT_DEVICEREMOVECOMPLETE, or DBT_DEVICEQUERYREMOVEFAILED.
  169. //
  170. if (((wParam == DBT_DEVICEARRIVAL) ||
  171. (wParam == DBT_DEVICEREMOVECOMPLETE) ||
  172. (wParam == DBT_DEVICEQUERYREMOVEFAILED)) &&
  173. (lParam) &&
  174. (((PDEV_BROADCAST_DEVICEINTERFACE)lParam)->dbcc_devicetype == DBT_DEVTYP_DEVICEINTERFACE) &&
  175. (IsEqualGUID(&((PDEV_BROADCAST_DEVICEINTERFACE)lParam)->dbcc_classguid, &GUID_DEVICE_BATTERY))) {
  176. // Make sure BatMeter has been initialized.
  177. if (g_hwndBatMeterFrame) {
  178. if (g_hwndBatMeter) {
  179. g_hwndBatMeter = DestroyBatMeter(g_hwndBatMeter);
  180. }
  181. g_hwndBatMeter = CreateBatMeter(hWnd,
  182. g_hwndBatMeterFrame,
  183. g_bShowMulti,
  184. NULL);
  185. InvalidateRect(hWnd, NULL, TRUE);
  186. }
  187. }
  188. }
  189. /*******************************************************************************
  190. *
  191. * Power_OnActivate
  192. *
  193. * DESCRIPTION:
  194. *
  195. * PARAMETERS:
  196. *
  197. *******************************************************************************/
  198. BOOLEAN Power_OnActivate(HWND hWnd, WPARAM wParam, LPARAM lParam)
  199. {
  200. if (g_hwndBatMeter) {
  201. SendMessage(g_hwndBatMeter, WM_ACTIVATE, wParam, lParam);
  202. return TRUE;
  203. }
  204. return FALSE;
  205. }
  206. /*******************************************************************************
  207. *
  208. * PowerProfileEnumProc
  209. *
  210. * DESCRIPTION:
  211. *
  212. * PARAMETERS:
  213. *
  214. *******************************************************************************/
  215. #define POWERMENU_SCHEME 300
  216. BOOLEAN CALLBACK PowerProfileEnumProc(
  217. UINT uiID,
  218. DWORD dwNameSize,
  219. LPTSTR lpszName,
  220. DWORD dwDescSize,
  221. LPTSTR lpszDesc,
  222. PPOWER_POLICY ppp,
  223. LPARAM lParam
  224. )
  225. {
  226. PPOWER_PROFILE_ENUM_PROC_PARAMS pppepp;
  227. MENUITEMINFO mii;
  228. if ((pppepp = (PPOWER_PROFILE_ENUM_PROC_PARAMS) lParam) == NULL) {
  229. return FALSE;
  230. }
  231. AppendMenu(pppepp->hMenu, MF_STRING,
  232. POWERMENU_SCHEME + g_uiPowerSchemeCount, lpszName);
  233. // Store the power scheme ID in the menu info.
  234. mii.cbSize = sizeof(mii);
  235. mii.fMask = MIIM_DATA;
  236. mii.dwItemData = uiID;
  237. SetMenuItemInfo(pppepp->hMenu,
  238. POWERMENU_SCHEME + g_uiPowerSchemeCount,
  239. FALSE, &mii);
  240. if (uiID == pppepp->uiCurActiveID) {
  241. pppepp->uiCurActiveIndex = POWERMENU_SCHEME + g_uiPowerSchemeCount;
  242. }
  243. g_uiPowerSchemeCount++;
  244. return TRUE;
  245. }
  246. /*----------------------------------------------------------------------------
  247. * GetPowerMenu()
  248. *
  249. * Build a menu containing battery meter/power selections.
  250. *
  251. *----------------------------------------------------------------------------*/
  252. #define POWERMENU_OPEN 100
  253. #define POWERMENU_PROPERTIES 101
  254. #define POWERMENU_ENABLEWARN 200
  255. #define POWERMENU_SHOWTIME 201
  256. #define POWERMENU_SHOWPERCENT 202
  257. HMENU
  258. GetPowerMenu(LONG l)
  259. {
  260. LPTSTR lpszMenu;
  261. UINT uiCurActiveID;
  262. POWER_PROFILE_ENUM_PROC_PARAMS ppepp;
  263. if (l > 0)
  264. {
  265. // Right button menu -- can change, rebuild each time.
  266. if (g_hMenu[0])
  267. {
  268. DestroyMenu(g_hMenu[0]);
  269. }
  270. g_hMenu[1] = CreatePopupMenu();
  271. // Properties for Power, PowerCfg.
  272. if ((lpszMenu = LoadDynamicString(IDS_PROPFORPOWER)) != NULL)
  273. {
  274. AppendMenu(g_hMenu[1], MF_STRING, POWERMENU_PROPERTIES, lpszMenu);
  275. DeleteDynamicString(lpszMenu);
  276. }
  277. // If we have a battery meter, add it's menu item and set as default.
  278. if (g_hwndBatMeter) {
  279. if ((lpszMenu = LoadDynamicString(IDS_OPEN)) != NULL)
  280. {
  281. AppendMenu(g_hMenu[1], MF_STRING, POWERMENU_OPEN, lpszMenu);
  282. DeleteDynamicString(lpszMenu);
  283. }
  284. // Open BatMeter is default (double click action)
  285. SetMenuDefaultItem(g_hMenu[1], POWERMENU_OPEN, FALSE);
  286. }
  287. else {
  288. // Use open PowerCfg as default (double click action)
  289. SetMenuDefaultItem(g_hMenu[1], POWERMENU_PROPERTIES, FALSE);
  290. }
  291. }
  292. // Left button menu -- can change, rebuild each time.
  293. if (g_hMenu[0])
  294. {
  295. DestroyMenu(g_hMenu[0]);
  296. }
  297. g_hMenu[0] = CreatePopupMenu();
  298. // Get the currently active power policies.
  299. if (GetActivePwrScheme(&uiCurActiveID)) {
  300. g_uiPowerSchemeCount = 0;
  301. ppepp.hMenu = g_hMenu[0];
  302. ppepp.uiCurActiveID = uiCurActiveID;
  303. EnumPwrSchemes(PowerProfileEnumProc, (LPARAM)&ppepp);
  304. // Check the currently active menu item.
  305. CheckMenuRadioItem(g_hMenu[0],
  306. POWERMENU_SCHEME,
  307. POWERMENU_SCHEME + g_uiPowerSchemeCount - 1,
  308. ppepp.uiCurActiveIndex,
  309. MF_BYCOMMAND);
  310. }
  311. return g_hMenu[l];
  312. }
  313. /*----------------------------------------------------------------------------
  314. * Power_Open
  315. *
  316. * Update and display the battery meter dialog
  317. *
  318. *----------------------------------------------------------------------------*/
  319. void
  320. Power_Open(HWND hWnd)
  321. {
  322. if (g_hwndBatMeter) {
  323. SetFocus(GetDlgItem(hWnd, IDC_ENABLEMETER));
  324. CheckDlgButton(hWnd, IDC_ENABLEMULTI,
  325. (g_gpp.user.GlobalFlags & EnableMultiBatteryDisplay) ?
  326. BST_CHECKED : BST_UNCHECKED);
  327. CheckDlgButton(hWnd, IDC_ENABLEMETER,
  328. (g_gpp.user.GlobalFlags & EnableSysTrayBatteryMeter) ?
  329. BST_CHECKED : BST_UNCHECKED);
  330. Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE); // show current info
  331. ShowWindow(hWnd, SW_SHOW);
  332. SetForegroundWindow(hWnd);
  333. }
  334. else {
  335. SysTray_RunProperties(IDS_RUNPOWERPROPERTIES);
  336. }
  337. }
  338. /*----------------------------------------------------------------------------
  339. * DoPowerMenu
  340. *
  341. * Create and process a right or left button menu.
  342. *
  343. *----------------------------------------------------------------------------*/
  344. void
  345. DoPowerMenu(HWND hwnd, UINT uMenuNum, UINT uButton)
  346. {
  347. POINT pt;
  348. UINT iCmd;
  349. MENUITEMINFO mii;
  350. SetForegroundWindow(hwnd);
  351. GetCursorPos(&pt);
  352. iCmd = (UINT)TrackPopupMenu(GetPowerMenu(uMenuNum),
  353. uButton | TPM_RETURNCMD | TPM_NONOTIFY,
  354. pt.x, pt.y, 0, hwnd, NULL);
  355. if (iCmd >= POWERMENU_SCHEME) {
  356. mii.cbSize = sizeof(mii);
  357. mii.fMask = MIIM_DATA;
  358. if (GetMenuItemInfo(g_hMenu[uMenuNum], iCmd, FALSE, &mii)) {
  359. SetActivePwrScheme((UINT)mii.dwItemData, NULL, NULL);
  360. PowerCfg_Notify();
  361. }
  362. }
  363. else {
  364. switch (iCmd) {
  365. case POWERMENU_OPEN:
  366. Power_Open(hwnd);
  367. break;
  368. case POWERMENU_PROPERTIES:
  369. SysTray_RunProperties(IDS_RUNPOWERPROPERTIES);
  370. break;
  371. case 0:
  372. // The user cancelled the menu without choosing.
  373. SetIconFocus(hwnd, STWM_NOTIFYPOWER);
  374. break;
  375. }
  376. }
  377. }
  378. /*----------------------------------------------------------------------------
  379. * Power_Notify
  380. *
  381. * Handle a notification from the power tray icon.
  382. *
  383. *----------------------------------------------------------------------------*/
  384. #define PN_TIMER_CLEAR 0
  385. #define PN_TIMER_SET 1
  386. #define PN_DBLCLK 2
  387. UINT g_uiTimerSet = PN_TIMER_CLEAR;
  388. LARGE_INTEGER g_liHoverUpdateTime = {0,0};
  389. void Power_Notify(HWND hWnd, WPARAM wParam, LPARAM lParam)
  390. {
  391. LARGE_INTEGER liPerformanceFrequency;
  392. LARGE_INTEGER liPerformanceCount;
  393. switch (lParam)
  394. {
  395. case WM_RBUTTONUP:
  396. DoPowerMenu(hWnd, 1, TPM_RIGHTBUTTON); // right button menu
  397. break;
  398. case WM_LBUTTONUP:
  399. // start timing for left button menu
  400. if (g_uiTimerSet == PN_TIMER_CLEAR) {
  401. SetTimer(hWnd, POWER_TIMER_ID, GetDoubleClickTime()+100, NULL);
  402. g_uiTimerSet = PN_TIMER_SET;
  403. }
  404. break;
  405. case WM_LBUTTONDBLCLK:
  406. g_uiTimerSet = PN_DBLCLK;
  407. Power_Open(hWnd); // show battery meter dialog
  408. break;
  409. case WM_MOUSEMOVE:
  410. if (QueryPerformanceFrequency (&liPerformanceFrequency)) {
  411. if (QueryPerformanceCounter (&liPerformanceCount)) {
  412. // Update no more than once a second
  413. if ((liPerformanceCount.QuadPart - g_liHoverUpdateTime.QuadPart) >
  414. liPerformanceFrequency.QuadPart) {
  415. g_liHoverUpdateTime = liPerformanceCount;
  416. Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE);
  417. }
  418. }
  419. }
  420. break;
  421. }
  422. }
  423. /*-----------------------------------------------------------------------------
  424. * Power_Timer
  425. *
  426. * Execute the left button menu on WM_LBUTTONDOWN time-out.
  427. *
  428. *----------------------------------------------------------------------------*/
  429. void Power_Timer(HWND hwnd)
  430. {
  431. KillTimer(hwnd, POWER_TIMER_ID);
  432. if (g_uiTimerSet != PN_DBLCLK) {
  433. DoPowerMenu(hwnd, 0, TPM_LEFTBUTTON);
  434. }
  435. g_uiTimerSet = PN_TIMER_CLEAR;
  436. }
  437. /*----------------------------------------------------------------------------
  438. * Update_PowerFlags
  439. *
  440. * Set power flags using powrprof.dll API's.
  441. *
  442. *----------------------------------------------------------------------------*/
  443. void Update_PowerFlags(DWORD dwMask, BOOL bEnable)
  444. {
  445. if (bEnable) {
  446. g_gpp.user.GlobalFlags |= dwMask;
  447. }
  448. else {
  449. g_gpp.user.GlobalFlags &= ~dwMask;
  450. }
  451. WriteGlobalPwrPolicy(&g_gpp);
  452. }
  453. /*----------------------------------------------------------------------------
  454. * Get_PowerFlags
  455. *
  456. * Get power flags using powrprof.dll API's.
  457. *
  458. *----------------------------------------------------------------------------*/
  459. DWORD Get_PowerFlags(void)
  460. {
  461. ReadGlobalPwrPolicy(&g_gpp);
  462. return g_gpp.user.GlobalFlags;
  463. }
  464. /*******************************************************************************
  465. *
  466. * BatteryMeterInit
  467. *
  468. * DESCRIPTION:
  469. * NOTE: Can be called multiple times. Simply re-init.
  470. *
  471. * PARAMETERS:
  472. * (returns), TRUE if the Battery Meter could be enabled
  473. *
  474. *******************************************************************************/
  475. BOOL PASCAL BatteryMeterInit(HWND hWnd)
  476. {
  477. PUINT puiBatCount = NULL;
  478. if (!BatMeterCapabilities(&puiBatCount)) {
  479. return FALSE;
  480. }
  481. if (!g_hwndBatMeter) {
  482. g_hwndBatMeterFrame = GetDlgItem(hWnd, IDC_STATIC_FRAME_BATMETER);
  483. g_bShowMulti = g_gpp.user.GlobalFlags & EnableMultiBatteryDisplay;
  484. g_hwndBatMeter = CreateBatMeter(hWnd,
  485. g_hwndBatMeterFrame,
  486. g_bShowMulti,
  487. NULL);
  488. }
  489. return TRUE;
  490. }
  491. /*******************************************************************************
  492. *
  493. * Power_UpdateStatus
  494. *
  495. * DESCRIPTION:
  496. *
  497. * PARAMETERS:
  498. *
  499. *******************************************************************************/
  500. VOID PASCAL Power_UpdateStatus(
  501. HWND hWnd,
  502. DWORD NotifyIconMessage,
  503. BOOL bForceUpdate
  504. )
  505. {
  506. static TCHAR szTipCache[64];
  507. static HICON hIconCache;
  508. TCHAR szTip[64];
  509. LPTSTR lpsz;
  510. BATTERY_STATE bs;
  511. UINT uiHour, uiMin;
  512. *szTip = 0;
  513. bs.ulSize = sizeof(BATTERY_STATE);
  514. UpdateBatMeter(g_hwndBatMeter,
  515. g_bShowMulti,
  516. bForceUpdate,
  517. &bs);
  518. // Build up a new tool tip.
  519. if (g_hwndBatMeter &&
  520. !(((bs.ulPowerState & BATTERY_POWER_ON_LINE) &&
  521. !(bs.ulPowerState & BATTERY_CHARGING)))) {
  522. if (bs.ulBatLifePercent <= 100) {
  523. if (bs.ulBatLifeTime != (UINT) -1) {
  524. uiHour = bs.ulBatLifeTime / 3600;
  525. uiMin = (bs.ulBatLifeTime % 3600) / 60;
  526. if (uiHour) {
  527. lpsz = LoadDynamicString(IDS_TIMEREMFORMATHOUR,
  528. uiHour, uiMin,
  529. bs.ulBatLifePercent);
  530. }
  531. else {
  532. lpsz = LoadDynamicString(IDS_TIMEREMFORMATMIN, uiMin,
  533. bs.ulBatLifePercent);
  534. }
  535. if (lpsz) {
  536. StrCpyN(szTip, lpsz, ARRAYSIZE(szTip));
  537. LocalFree(lpsz);
  538. if (bs.ulPowerState & BATTERY_CHARGING) {
  539. if ((lpsz = LoadDynamicString(IDS_CHARGING)) != NULL) {
  540. StrCatBuff(szTip, lpsz, ARRAYSIZE(szTip));
  541. LocalFree(lpsz);
  542. }
  543. }
  544. }
  545. }
  546. else {
  547. if ((lpsz = LoadDynamicString(IDS_REMAINING,
  548. bs.ulBatLifePercent)) != NULL) {
  549. StrCpyN(szTip, lpsz, ARRAYSIZE(szTip));
  550. LocalFree(lpsz);
  551. if (bs.ulPowerState & BATTERY_CHARGING) {
  552. if ((lpsz = LoadDynamicString(IDS_CHARGING)) != NULL) {
  553. StrCatBuff(szTip, lpsz, ARRAYSIZE(szTip));
  554. LocalFree(lpsz);
  555. }
  556. }
  557. }
  558. }
  559. }
  560. else {
  561. lpsz = LoadDynamicString(IDS_UNKNOWN);
  562. StrCpyN(szTip, lpsz, ARRAYSIZE(szTip));
  563. LocalFree(lpsz);
  564. }
  565. }
  566. else {
  567. lpsz = LoadDynamicString(IDS_ACPOWER);
  568. StrCpyN(szTip, lpsz, ARRAYSIZE(szTip));
  569. LocalFree(lpsz);
  570. }
  571. if ((NotifyIconMessage == NIM_ADD) ||
  572. (hIconCache != bs.hIconCache16) ||
  573. (lstrcmp(szTip, szTipCache))) {
  574. hIconCache = bs.hIconCache16;
  575. StrCpyN(szTipCache, szTip, ARRAYSIZE(szTipCache));
  576. SysTray_NotifyIcon(hWnd, STWM_NOTIFYPOWER, NotifyIconMessage,
  577. hIconCache, szTipCache);
  578. }
  579. }
  580. /*******************************************************************************
  581. *
  582. * RegisterForDeviceNotification
  583. *
  584. * DESCRIPTION:
  585. * Do onetime registration for WM_DEVICECHANGED.
  586. *
  587. * PARAMETERS:
  588. *
  589. *******************************************************************************/
  590. BOOL RegisterForDeviceNotification(HWND hWnd)
  591. {
  592. DEV_BROADCAST_DEVICEINTERFACE dbc;
  593. memset(&dbc, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  594. dbc.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  595. dbc.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  596. dbc.dbcc_classguid = GUID_DEVICE_BATTERY;
  597. g_hDevNotify = RegisterDeviceNotification(hWnd,
  598. &dbc,
  599. DEVICE_NOTIFY_WINDOW_HANDLE);
  600. if (!g_hDevNotify) {
  601. return FALSE;
  602. }
  603. return TRUE;
  604. }
  605. /*******************************************************************************
  606. *
  607. * Power_WmDestroy
  608. *
  609. * DESCRIPTION:
  610. *
  611. *
  612. * PARAMETERS:
  613. *
  614. *******************************************************************************/
  615. void Power_WmDestroy(HWND hWnd)
  616. {
  617. if (g_hDevNotify) {
  618. UnregisterDeviceNotification(g_hDevNotify);
  619. g_hDevNotify = NULL;
  620. }
  621. }
  622. /*******************************************************************************
  623. *
  624. * Power_CheckEnable
  625. *
  626. * DESCRIPTION:
  627. * Return TRUE if the power service icon was enabled.
  628. * Can be called multiple times. Simply re-init.
  629. *
  630. * PARAMETERS:
  631. * bSvcEnabled - Request to enable/disable power service on tray.
  632. *
  633. *******************************************************************************/
  634. BOOL Power_CheckEnable(HWND hWnd, BOOL bSvcEnable)
  635. {
  636. static BOOL bRegisteredForDC = FALSE;
  637. // Is there any reason to display the systray power icon?
  638. if (!PowerCapabilities()) {
  639. return FALSE;
  640. }
  641. // Do onetime registration for WM_DEVICECHANGED.
  642. if (!bRegisteredForDC) {
  643. bRegisteredForDC = RegisterForDeviceNotification(hWnd);
  644. }
  645. // Get current battery meter flags from the registry
  646. Get_PowerFlags();
  647. // Are we running on battery power or has the user set
  648. // the systray power icon to always on? If so, force enable.
  649. if ((g_gpp.user.GlobalFlags & EnableSysTrayBatteryMeter) ||
  650. (RunningOffLine())) {
  651. bSvcEnable = TRUE;
  652. }
  653. else {
  654. bSvcEnable = FALSE;
  655. }
  656. // Set the power service state.
  657. if (bSvcEnable) {
  658. if (g_bPowerEnabled) {
  659. Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE);
  660. }
  661. else {
  662. BatteryMeterInit(hWnd);
  663. Power_UpdateStatus(hWnd, NIM_ADD, FALSE);
  664. }
  665. g_bPowerEnabled = TRUE;
  666. }
  667. else {
  668. SysTray_NotifyIcon(hWnd, STWM_NOTIFYPOWER, NIM_DELETE, NULL, NULL);
  669. g_bPowerEnabled = FALSE;
  670. }
  671. return g_bPowerEnabled;
  672. }