/*******************************************************************************
*
*  (C) COPYRIGHT MICROSOFT CORP., 1996
*
*  TITLE:       BATMTRCF.C
*
*  VERSION:     2.0
*
*  AUTHOR:      ReedB
*
*  DATE:        17 Oct, 1996
*
*  DESCRIPTION:
*   Support for the battery meter configuration page of PowerCfg.Cpl.
*
*******************************************************************************/

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>

#include <windows.h>
#include <commctrl.h>
#include <powercfp.h>
#include <dbt.h>

#include <objbase.h>
#include <initguid.h>
#include <ntpoapi.h>
#include <poclass.h>

#include "powercfg.h"
#include "pwrresid.h"
#include "PwrMn_cs.h"

/*******************************************************************************
*
*                     G L O B A L    D A T A
*
*******************************************************************************/

extern UINT g_uiEnableSysTrayFlag;

// A systary change requires PowerSchemeDlgProc re-init.
extern BOOL g_bSystrayChange;

// Persistant storage of this data is managed by POWRPROF.DLL API's.
extern GLOBAL_POWER_POLICY  g_gpp;

// Subclass variables:
WNDPROC g_fnOldPropShtProc;

// BatMeter creation parameters.
HWND    g_hwndBatMeter;
BOOL    g_bShowMulti;
HWND    g_hwndBatMeterFrame;

// Show/hide multi-bat display check box.
DWORD g_dwShowMultiBatDispOpt = CONTROL_ENABLE;

// Static flags:
UINT g_uiEnableMultiFlag = EnableMultiBatteryDisplay;

#ifdef WINNT
// Used to track registration for WM_DEVICECHANGED message.
HDEVNOTIFY g_hDevNotify;
#endif

// Battery meter policies dialog controls descriptions:
#define NUM_BATMETERCFG_CONTROLS 1

POWER_CONTROLS g_pcBatMeterCfg[NUM_BATMETERCFG_CONTROLS] =
{// Control ID          Control Type    Data Address                  Data Size                         Parameter Pointer       Enable/Visible State Pointer
    IDC_ENABLEMULTI,    CHECK_BOX,      &(g_gpp.user.GlobalFlags),    sizeof(g_gpp.user.GlobalFlags),   &g_uiEnableMultiFlag,   &g_dwShowMultiBatDispOpt,
};

// "Battery Meter" Dialog Box (IDD_BATMETERCFG == 102) help arrays:

const DWORD g_BatMeterCfgHelpIDs[]=
{
    IDC_ENABLEMULTI,    IDH_102_1204,   // Battery Meter: "Show the status of all &batteries." (Button)
    IDC_STATIC_FRAME_BATMETER,  IDH_102_1205,   // Battery Meter: "Batmeter frame" (Static)
    IDC_POWERSTATUSGROUPBOX,    IDH_102_1201,   // Battery Meter: "Power status" (Button)
    0, 0
};

#ifdef WINNT
// Private function prototypes
BOOL RegisterForDeviceNotification(HWND hWnd);
void UnregisterForDeviceNotification(void);
#endif

/*******************************************************************************
*
*               P U B L I C   E N T R Y   P O I N T S
*
*******************************************************************************/

/*******************************************************************************
*
*  PropShtSubclassProc
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

LRESULT PropShtSubclassProc(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
   LRESULT lRet;

   lRet = CallWindowProc(g_fnOldPropShtProc, hWnd, uiMsg, wParam, lParam);

   if ((uiMsg == WM_POWERBROADCAST) && (wParam == PBT_APMPOWERSTATUSCHANGE)) {
      UpdateBatMeter(g_hwndBatMeter, g_bShowMulti, TRUE, NULL);
   }
   return lRet;
}

/*******************************************************************************
*
*  BatMeterCfgDlgProc
*
*  DESCRIPTION:
*
*  PARAMETERS:
*
*******************************************************************************/

INT_PTR CALLBACK BatMeterCfgDlgProc
(
    HWND hWnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam
)
{
    static BOOL bDirty = FALSE;
#ifdef WINNT
    static BOOL bRegisteredForDC = FALSE;
#endif

    NMHDR *lpnm;

    switch (uMsg)
    {
        case WM_INITDIALOG:
            // If we can't read the global power policies
            // disable the controls on this page.
            if (!GetGlobalPwrPolicy(&g_gpp))
            {
                DisableControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
            }
            else
            {
                if (g_gpp.user.GlobalFlags & EnableMultiBatteryDisplay)
                {
                    g_bShowMulti = TRUE;
                }
                else
                {
                    g_bShowMulti = FALSE;
                }

                // If we can't write the global power policies disable
                // the controls this page.
                if (!WriteGlobalPwrPolicyReport(hWnd, &g_gpp, FALSE))
                {
                    HideControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
                }

                SetControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
            }
            g_hwndBatMeterFrame = GetDlgItem(hWnd, IDC_STATIC_FRAME_BATMETER);
            g_hwndBatMeter = CreateBatMeter(hWnd,
                                            g_hwndBatMeterFrame,
                                            g_bShowMulti,
                                            NULL);

            // The top level window must be subclassed to receive
            // the WM_POWERBROADCAST message.
            if (g_hwndBatMeter) {
                g_fnOldPropShtProc =
                    (WNDPROC) SetWindowLongPtr(GetParent(hWnd), DWLP_DLGPROC,
                                            (LONG_PTR)PropShtSubclassProc);

#ifdef WINNT
                // Do onetime registration for WM_DEVICECHANGED.
                if (!bRegisteredForDC) {
                   bRegisteredForDC = RegisterForDeviceNotification(hWnd);
                }
#endif
            }
            return TRUE;

        case WM_NOTIFY:
            lpnm = (NMHDR FAR *)lParam;
            switch(lpnm->code)
            {
                case PSN_APPLY:
                    if (bDirty)
                    {
                        GetControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
                        WriteGlobalPwrPolicyReport(hWnd, &g_gpp, TRUE);
                        bDirty = FALSE;
                    }
                    break;
            }
            break;

        case WM_COMMAND:
            switch (wParam) {
                case IDC_ENABLEMULTI:
                    GetControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
                    if (g_gpp.user.GlobalFlags & EnableMultiBatteryDisplay) {
                        g_bShowMulti = TRUE;
                    }
                    else {
                        g_bShowMulti = FALSE;
                    }

                    UpdateBatMeter(g_hwndBatMeter, g_bShowMulti, TRUE, NULL);

                    // Enable the parent dialog Apply button on change.
                    MarkSheetDirty(hWnd, &bDirty);
                    break;

                default:
                    // Notify battery meter of enter key events.
                    if (HIWORD(wParam) == BN_CLICKED) {
                        SendMessage(g_hwndBatMeter, uMsg, wParam, lParam);
                    }
            }
            break;

        case PCWM_NOTIFYPOWER:
            // Systray changed something. Get the flags and update controls.
            if (GetGlobalPwrPolicy(&g_gpp)) {
                SetControls(hWnd, NUM_BATMETERCFG_CONTROLS, g_pcBatMeterCfg);
            }
            g_bSystrayChange = TRUE;
            break;

        case WM_DEVICECHANGE:
            if ((wParam == DBT_DEVICEARRIVAL) ||
#ifndef WINNT
                (wParam == DBT_DEVICEREMOVECOMPLETE) ||
#endif
                (wParam == DBT_DEVICEQUERYREMOVEFAILED)) {

               if (g_hwndBatMeter) {
                  g_hwndBatMeter = DestroyBatMeter(g_hwndBatMeter);
               }
               g_hwndBatMeter = CreateBatMeter(hWnd,
                                               g_hwndBatMeterFrame,
                                               g_bShowMulti,
                                               NULL);
               InvalidateRect(hWnd, NULL, TRUE);
            }
            return TRUE;

#ifdef WINNT
        case WM_DESTROY:
            UnregisterForDeviceNotification();
            break;
#endif

        case WM_HELP:             // F1
            WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_BatMeterCfgHelpIDs);
            return TRUE;

        case WM_CONTEXTMENU:      // right mouse click
            WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_BatMeterCfgHelpIDs);
            return TRUE;
    }

    return FALSE;
}

/*******************************************************************************
*
*                 P R I V A T E   F U N C T I O N S
*
*******************************************************************************/

#ifdef WINNT
/*******************************************************************************
*
*  RegisterForDeviceNotification
*
*  DESCRIPTION:
*    Do onetime registration for WM_DEVICECHANGED.
*
*  PARAMETERS:
*
*******************************************************************************/

BOOL RegisterForDeviceNotification(HWND hWnd)
{
   DEV_BROADCAST_DEVICEINTERFACE dbc;

   memset(&dbc, 0, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
   dbc.dbcc_size         = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
   dbc.dbcc_devicetype   = DBT_DEVTYP_DEVICEINTERFACE;
   dbc.dbcc_classguid    = GUID_DEVICE_BATTERY;
   g_hDevNotify = RegisterDeviceNotification(hWnd,
                                             &dbc,
                                             DEVICE_NOTIFY_WINDOW_HANDLE);
   if (!g_hDevNotify) {
      DebugPrint( "RegisterForDeviceNotification failed");
      return FALSE;
   }
   return TRUE;
}

/*******************************************************************************
*
*  UnregisterForDeviceNotification
*
*  DESCRIPTION:
*
*
*  PARAMETERS:
*
*******************************************************************************/

void UnregisterForDeviceNotification(void)
{
   if (g_hDevNotify) {
      UnregisterDeviceNotification(g_hDevNotify);
      g_hDevNotify = NULL;
   }
}
#endif