windows-nt/Source/XPSP1/NT/shell/osshell/cpls/powercfg/pwrswtch.c
2020-09-26 16:20:57 +08:00

559 lines
20 KiB
C

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1996
*
* TITLE: PWRSWTCH.C
*
* VERSION: 2.0
*
* AUTHOR: ReedB
*
* DATE: 17 Oct, 1996
*
* DESCRIPTION:
* Support for Advanced page of PowerCfg.Cpl.
*
*******************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <commctrl.h>
#include <systrayp.h>
#include <help.h>
#include <powercfp.h>
#include "powercfg.h"
#include "pwrresid.h"
#include "PwrMn_cs.h"
/*******************************************************************************
*
* G L O B A L D A T A
*
*******************************************************************************/
// This structure is filled in by the Power Policy Manager at CPL_INIT time.
extern SYSTEM_POWER_CAPABILITIES g_SysPwrCapabilities;
extern BOOL g_bRunningUnderNT;
// Machine is currently capable of hibernate, managed by code in hibernat.c.
extern UINT g_uiPwrActIDs[];
extern UINT g_uiLidActIDs[];
// A systary change requires PowerSchemeDlgProc re-init.
extern BOOL g_bSystrayChange;
// Persistant storage of this data is managed by POWRPROF.DLL API's.
GLOBAL_POWER_POLICY g_gpp;
// Show/hide UI state variables.
DWORD g_dwShowPowerButtonUI;
DWORD g_dwShowSleepButtonUI;
DWORD g_dwShowLidUI;
DWORD g_dwShowPwrButGrpUI;
DWORD g_dwShowEnableSysTray;
DWORD g_uiPasswordState;
DWORD g_uiVideoDimState;
// Static flags:
UINT g_uiEnableSysTrayFlag = EnableSysTrayBatteryMeter;
UINT g_uiEnablePWLogonFlag = EnablePasswordLogon;
UINT g_uiEnableVideoDimDisplay = EnableVideoDimDisplay;
// Indicies into combobox selections
UINT g_uiDoNothing;
UINT g_uiAskMeWhatToDo;
UINT g_uiShutdown;
// Global marking whether sheet is dirty
BOOL g_bDirty;
// Button policies dialog controls descriptions:
#define NUM_BUTTON_POL_CONTROLS 10
// Handy indicies into our g_pcButtonPol control array:
#define ID_LIDCLOSETEXT 0
#define ID_LIDCLOSEACTION 1
#define ID_PWRBUTTONTEXT 2
#define ID_PWRBUTACTION 3
#define ID_SLPBUTTONTEXT 4
#define ID_SLPBUTACTION 5
#define ID_ENABLEMETER 6
#define ID_PASSWORD 7
#define ID_VIDEODIM 8
#define ID_POWERBUTGROUP 9
POWER_CONTROLS g_pcButtonPol[NUM_BUTTON_POL_CONTROLS] =
{// Control ID Control Type Data Address Data Size Parameter Pointer Enable/Visible State Pointer
IDC_LIDCLOSETEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowLidUI,
IDC_LIDCLOSEACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.LidCloseDc.Action), (LPDWORD)&g_gpp.user.LidCloseDc.Action, &g_dwShowLidUI,
IDC_PWRBUTTONTEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowPowerButtonUI,
IDC_PWRBUTACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.PowerButtonDc.Action), (LPDWORD)&g_gpp.user.PowerButtonDc.Action, &g_dwShowPowerButtonUI,
IDC_SLPBUTTONTEXT, STATIC_TEXT, NULL, 0, NULL, &g_dwShowSleepButtonUI,
IDC_SLPBUTACTION, COMBO_BOX, NULL, sizeof(g_gpp.user.SleepButtonDc.Action), (LPDWORD)&g_gpp.user.SleepButtonDc.Action, &g_dwShowSleepButtonUI,
IDC_ENABLEMETER, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnableSysTrayFlag, &g_dwShowEnableSysTray,
IDC_PASSWORD, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnablePWLogonFlag, &g_uiPasswordState,
IDC_VIDEODIM, CHECK_BOX, &g_gpp.user.GlobalFlags, sizeof(g_gpp.user.GlobalFlags), &g_uiEnableVideoDimDisplay, &g_uiVideoDimState,
IDC_POWERBUTGROUP, STATIC_TEXT, NULL, 0, NULL, &g_dwShowPwrButGrpUI,
};
// "Power Switches" Dialog Box (IDD_BUTTONPOLICY == 104) help array:
const DWORD g_PowerSwitchHelpIDs[]=
{
IDC_OPTIONSGROUPBOX,IDH_COMM_GROUPBOX,
IDC_POWERBUTGROUP, IDH_COMM_GROUPBOX,
IDC_LIDCLOSEACTION, IDH_104_1301, // "Lid close action dropdown" (ComboBox)
IDC_LIDCLOSETEXT, IDH_104_1301,
IDC_PWRBUTACTION, IDH_104_1303, // "Power button action dropdown" (ComboBox)
IDC_PWRBUTTONTEXT, IDH_104_1303,
IDC_SLPBUTACTION, IDH_104_1304, // "Sleep button action dropdown" (ComboBox)
IDC_SLPBUTTONTEXT, IDH_104_1304,
IDC_ENABLEMETER, IDH_102_1203, // "&Show meter on taskbar." (Button)
IDC_PASSWORD, IDH_107_1500, // "Prompt for &password when bringing computer out of standby." (Button)
IDC_VIDEODIM, IDH_108_1503, // "&Dim display when running on batteries." (Button)
IDI_PWRMNG, NO_HELP,
IDC_NO_HELP_5, NO_HELP,
0, 0
};
void ActionEventCodeToSelection (HWND hwnd, int iDlgItem, const POWER_ACTION_POLICY *pPAP)
{
ULONG ulEventCode;
DWORD dwSelection;
// Special case PowerActionNone. This could be:
// "Shut Down"
// "Ask me what to do"
// "Do nothing"
if (pPAP->Action == PowerActionNone)
{
ulEventCode = pPAP->EventCode & (POWER_USER_NOTIFY_BUTTON | POWER_USER_NOTIFY_SHUTDOWN);
if ((ulEventCode & POWER_USER_NOTIFY_SHUTDOWN) != 0)
{
dwSelection = g_uiShutdown;
}
else if ((ulEventCode & POWER_USER_NOTIFY_BUTTON) != 0)
{
dwSelection = g_uiAskMeWhatToDo;
}
else
{
dwSelection = g_uiDoNothing;
}
(LRESULT)SendDlgItemMessage(hwnd, iDlgItem, CB_SETCURSEL, dwSelection, 0);
}
}
void SelectionToActionEventCode (HWND hwnd, int iDlgItem, DWORD dwMissingItems, POWER_ACTION_POLICY *pPAP)
{
ULONG ulEventCode;
DWORD dwSelection;
// Special case the "Power Switch" UI. Always turn off the POWER_USER_NOTIFY_POWER_BUTTON
// and POWER_USER_NOTIFY_SLEEP_BUTTON flag because it doesn't mean anything for action
// other than PowerActionNone. Turn it on for PowerActionNone otherwise the SAS
// window will not get the message posted. The SAS window has the logic to check
// the registry setting.
pPAP->EventCode &= ~(POWER_USER_NOTIFY_BUTTON | POWER_USER_NOTIFY_SHUTDOWN | POWER_FORCE_TRIGGER_RESET);
if (pPAP->Action == PowerActionNone)
{
dwSelection = (DWORD)SendDlgItemMessage(hwnd, iDlgItem, CB_GETCURSEL, 0, 0);
// dwMissingItems is a special variable that's used SOLELY for the purpose of
// getting the lid switch to work. The other switches have 5 options available:
//
// Do nothing
// Ask me what to do
// Sleep
// Hibernate
// Shut Down
//
// The lid switch doesn't allow "Ask me what to do" so all of the items get
// shifted by one and the comparisons are wrong. What the lid switch selection
// extractor passes in to this function is the "fudge factor" to get this right.
// Note because "Do nothing" is always available there's no need to compromise
// for it. Just keep doing the same old same old.
if (dwSelection == g_uiDoNothing)
{
ulEventCode = POWER_FORCE_TRIGGER_RESET;
}
else if ((dwSelection + dwMissingItems) == g_uiAskMeWhatToDo)
{
ulEventCode = POWER_USER_NOTIFY_BUTTON;
}
else if ((dwSelection + dwMissingItems) == g_uiShutdown)
{
ulEventCode = POWER_USER_NOTIFY_SHUTDOWN;
}
else
{
ulEventCode = 0;
}
pPAP->EventCode |= ulEventCode;
}
}
/*******************************************************************************
*
* SetAdvancedDlgProcData
*
* DESCRIPTION:
* Set up the data pointers in g_pcButtonPol depending on hibernate state.
* Set the data to the controls. If bPreserve is TRUE get the current
* values UI values and restore them after updating the listboxes.
*
* PARAMETERS:
*
*******************************************************************************/
VOID SetAdvancedDlgProcData(HWND hWnd, BOOL bRestoreCurrent)
{
UINT ii;
UINT jj;
// Set the state of the show/hide UI state variables.
if (g_SysPwrCapabilities.SystemS1 ||
g_SysPwrCapabilities.SystemS2 ||
g_SysPwrCapabilities.SystemS3 ||
(g_SysPwrCapabilities.SystemS4 &&
g_SysPwrCapabilities.HiberFilePresent)) {
int err;
HKEY hPowerPolicy;
DWORD Value;
DWORD dwType ;
DWORD dwSize ;
g_uiPasswordState = CONTROL_ENABLE;
//
// Check for policy forcing the password always on
//
err = RegOpenKeyEx( HKEY_CURRENT_USER,
POWER_POLICY_KEY,
0,
KEY_READ,
&hPowerPolicy );
if (err == 0) {
dwSize = sizeof(Value);
err = RegQueryValueEx(hPowerPolicy,
LOCK_ON_RESUME,
NULL,
&dwType,
(LPBYTE)&Value,
&dwSize);
if ( (err == 0) && (dwType == REG_DWORD) && (Value != 0)) {
g_uiPasswordState = CONTROL_DISABLE;
g_gpp.user.GlobalFlags |= EnablePasswordLogon;
}
}
RegCloseKey( hPowerPolicy );
}
else {
g_uiPasswordState = CONTROL_HIDE;
}
if (bRestoreCurrent) {
GetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
}
//
// Build the Action ID's for the Lid, Power Button and/or Sleep Button
//
ii=0;
jj=0;
g_uiLidActIDs[jj++] = IDS_DONOTHING;
g_uiLidActIDs[jj++] = PowerActionNone;
g_uiDoNothing = ii / 2;
g_uiPwrActIDs[ii++] = IDS_DONOTHING;
g_uiPwrActIDs[ii++] = PowerActionNone;
g_uiAskMeWhatToDo = ii / 2;
g_uiPwrActIDs[ii++] = IDS_PROMPT;
g_uiPwrActIDs[ii++] = PowerActionNone;
if (g_SysPwrCapabilities.SystemS1 ||
g_SysPwrCapabilities.SystemS2 || g_SysPwrCapabilities.SystemS3) {
g_uiPwrActIDs[ii++] = IDS_STANDBY;
g_uiPwrActIDs[ii++] = PowerActionSleep;
g_uiLidActIDs[jj++] = IDS_STANDBY;
g_uiLidActIDs[jj++] = PowerActionSleep;
}
if (g_SysPwrCapabilities.HiberFilePresent) {
g_uiPwrActIDs[ii++] = IDS_HIBERNATE;
g_uiPwrActIDs[ii++] = PowerActionHibernate;
g_uiLidActIDs[jj++] = IDS_HIBERNATE;
g_uiLidActIDs[jj++] = PowerActionHibernate;
}
g_uiShutdown = ii / 2;
g_uiPwrActIDs[ii++] = IDS_POWEROFF;
g_uiPwrActIDs[ii++] = PowerActionNone;
//g_uiLidActIDs[jj++] = IDS_POWEROFF; WinBug 5.1 #352752 - "Shutdown" isn't valid for
//g_uiLidActIDs[jj++] = PowerActionNone; closing the lid.
g_uiPwrActIDs[ii++] = 0;
g_uiPwrActIDs[ii++] = 0;
g_uiLidActIDs[jj++] = 0;
g_uiLidActIDs[jj++] = 0;
g_pcButtonPol[ID_LIDCLOSEACTION].lpvData = g_uiLidActIDs;
g_pcButtonPol[ID_PWRBUTACTION].lpvData = g_uiPwrActIDs;
g_pcButtonPol[ID_SLPBUTACTION].lpvData = g_uiPwrActIDs;
// Special case PowerActionShutdownOff. This is no longer
// supported in the UI. Convert this to "Shut Down".
if (g_gpp.user.PowerButtonDc.Action == PowerActionShutdownOff)
{
g_gpp.user.PowerButtonDc.Action = PowerActionNone;
g_gpp.user.PowerButtonDc.EventCode = POWER_USER_NOTIFY_SHUTDOWN;
g_bDirty = TRUE;
}
if (g_gpp.user.SleepButtonDc.Action == PowerActionShutdownOff)
{
g_gpp.user.SleepButtonDc.Action = PowerActionNone;
g_gpp.user.SleepButtonDc.EventCode = POWER_USER_NOTIFY_SHUTDOWN;
g_bDirty = TRUE;
}
// Map power actions to allowed UI values.
MapPwrAct(&g_gpp.user.LidCloseDc.Action, TRUE);
MapPwrAct(&g_gpp.user.PowerButtonDc.Action, TRUE);
MapPwrAct(&g_gpp.user.SleepButtonDc.Action, TRUE);
// Only update the list boxes.
SetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
// Map action and event code group to combobox selection.
ActionEventCodeToSelection(hWnd, IDC_PWRBUTACTION, &g_gpp.user.PowerButtonDc);
ActionEventCodeToSelection(hWnd, IDC_SLPBUTACTION, &g_gpp.user.SleepButtonDc);
ActionEventCodeToSelection(hWnd, IDC_LIDCLOSEACTION, &g_gpp.user.LidCloseDc);
}
/*******************************************************************************
*
* InitAdvancedDlg
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
BOOLEAN InitAdvancedDlg(HWND hWnd)
{
// Start off with the page not dirty.
g_bDirty = FALSE;
// If we can't read the global power policies hide
// the controls on this page.
if (!GetGlobalPwrPolicy(&g_gpp)) {
HideControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
return TRUE;
}
// Get the enable systray icon mask based on AC online/offline.
g_uiEnableSysTrayFlag = EnableSysTrayBatteryMeter;
if (g_SysPwrCapabilities.VideoDimPresent) {
g_uiVideoDimState = CONTROL_ENABLE;
}
else {
g_uiVideoDimState = CONTROL_HIDE;
}
g_dwShowEnableSysTray = CONTROL_ENABLE;
g_dwShowPwrButGrpUI = CONTROL_HIDE;
if (g_SysPwrCapabilities.LidPresent) {
g_dwShowLidUI = CONTROL_ENABLE;
g_dwShowPwrButGrpUI = CONTROL_ENABLE;
}
else {
g_dwShowLidUI = CONTROL_HIDE;
}
//
// Don't show the Power Button if S5 is not supported on the system
//
if (g_SysPwrCapabilities.PowerButtonPresent && g_SysPwrCapabilities.SystemS5) {
g_dwShowPowerButtonUI = CONTROL_ENABLE;
g_dwShowPwrButGrpUI = CONTROL_ENABLE;
}
else {
g_dwShowPowerButtonUI = CONTROL_HIDE;
}
//
// Sleep Button - Don't show the sleep button if there are not any actions.
//
if (g_SysPwrCapabilities.SleepButtonPresent &&
(g_SysPwrCapabilities.SystemS1 ||
g_SysPwrCapabilities.SystemS2 ||
g_SysPwrCapabilities.SystemS3 ||
(g_SysPwrCapabilities.SystemS4 && g_SysPwrCapabilities.HiberFilePresent)))
{
g_dwShowSleepButtonUI = CONTROL_ENABLE;
g_dwShowPwrButGrpUI = CONTROL_ENABLE;
}
else {
g_dwShowSleepButtonUI = CONTROL_HIDE;
}
SetAdvancedDlgProcData(hWnd, FALSE);
// If we can't write the global power policies disable
// the controls this page.
if (!WriteGlobalPwrPolicyReport(hWnd, &g_gpp, FALSE))
{
DisableControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
}
return TRUE;
}
/*******************************************************************************
*
* P U B L I C E N T R Y P O I N T S
*
*******************************************************************************/
/*******************************************************************************
*
* AdvancedDlgProc
*
* DESCRIPTION:
*
* PARAMETERS:
*
*******************************************************************************/
INT_PTR CALLBACK AdvancedDlgProc(
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
NMHDR FAR *lpnm;
UINT uiID;
switch (uMsg)
{
case WM_INITDIALOG:
return InitAdvancedDlg(hWnd);
#ifdef WINNT
case WM_CHILDACTIVATE:
// Reinitialize since the hibernate tab may have changed
// the hibernate state, NT only.
SetAdvancedDlgProcData(hWnd, TRUE);
break;
#endif
case WM_NOTIFY:
lpnm = (NMHDR FAR *)lParam;
switch(lpnm->code)
{
case PSN_APPLY:
// Fetch data from dialog controls.
if (g_bDirty)
{
GetControls(hWnd, NUM_BUTTON_POL_CONTROLS, g_pcButtonPol);
// Map combobox selection to action and event code group.
SelectionToActionEventCode(hWnd, IDC_PWRBUTACTION, 0, &g_gpp.user.PowerButtonDc);
SelectionToActionEventCode(hWnd, IDC_SLPBUTACTION, 0, &g_gpp.user.SleepButtonDc);
SelectionToActionEventCode(hWnd, IDC_LIDCLOSEACTION, 1, &g_gpp.user.LidCloseDc);
g_gpp.user.LidCloseAc.Action =
g_gpp.user.LidCloseDc.Action;
g_gpp.user.LidCloseAc.EventCode =
g_gpp.user.LidCloseDc.EventCode;
g_gpp.user.PowerButtonAc.Action =
g_gpp.user.PowerButtonDc.Action;
g_gpp.user.PowerButtonAc.EventCode =
g_gpp.user.PowerButtonDc.EventCode;
g_gpp.user.SleepButtonAc.Action =
g_gpp.user.SleepButtonDc.Action;
g_gpp.user.SleepButtonAc.EventCode =
g_gpp.user.SleepButtonDc.EventCode;
if (WriteGlobalPwrPolicyReport(hWnd, &g_gpp, TRUE))
{
GetActivePwrScheme(&uiID);
SetActivePwrSchemeReport(hWnd, uiID, &g_gpp, NULL);
// Enable or disable battery meter service on systray.
SysTray_EnableService(STSERVICE_POWER,
g_gpp.user.GlobalFlags &
g_uiEnableSysTrayFlag);
g_bDirty = FALSE;
}
}
break;
case PSN_SETACTIVE:
// Hibernate page may have changed the hibernate state,
// reinitialize the dependent part of Advanced page.
SetAdvancedDlgProcData(hWnd, TRUE);
break;
}
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_SLPBUTACTION:
case IDC_PWRBUTACTION:
case IDC_LIDCLOSEACTION:
if (HIWORD(wParam) == LBN_SELCHANGE) {
// Let parent know something changed.
MarkSheetDirty(hWnd, &g_bDirty);
}
break;
case IDC_VIDEODIM:
case IDC_PASSWORD:
case IDC_ENABLEMETER:
// Enable the parent dialog Apply button on change.
MarkSheetDirty(hWnd, &g_bDirty);
break;
}
break;
case PCWM_NOTIFYPOWER:
// Notification from systray, user has changed a PM UI setting.
g_bSystrayChange = TRUE;
break;
case WM_HELP: // F1
WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_PowerSwitchHelpIDs);
return TRUE;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_PowerSwitchHelpIDs);
return TRUE;
}
return FALSE;
}