home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2005 March / PCpro_2005_03.ISO / files / systools / speedswitchxp / sswitchxp14.exe / Typical / SpeedswitchXPDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-01-14  |  65.5 KB  |  2,313 lines

  1. /*
  2.    SpeedswitchXP V1.4
  3.    - Windows XP CPU Frequency Control for Notebooks -
  4.  
  5.    Copyright(c) 2002-2004 Christian Diefer
  6.  
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License version 2 as 
  9.    published by the Free Software Foundation.
  10.    
  11.    This program is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.    
  16.    You should have received a copy of the GNU General Public License
  17.    along with this program; if not, write to the Free Software
  18.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include "stdafx.h"
  22. #include "AtlBase.h"
  23. #include "TOptions.h"
  24. #include "SpeedswitchXP.h"
  25. #include "SpeedswitchXPDlg.h"
  26. #include <wtsapi32.h>
  27. #include <stdarg.h>
  28. #include "speedswitch.h"
  29. #include "SpeedswitchXPOptions.h"
  30. #include "Hyperlink.h"
  31. #include "cpuid.h"
  32. #include "speed.h"
  33. #include "CPUData.h"
  34. #include "PowerCapabilities.h"
  35. #include "SystemInfo.h"
  36. #include "htspeed.h"
  37. #include <time.h>
  38.  
  39. #ifdef _DEBUG
  40. #define new DEBUG_NEW
  41. #endif
  42.  
  43. #define IDM_MAXPERF  300
  44. #define IDM_BATTOPT  301
  45. #define IDM_MAXBATT  302
  46. #define IDM_DYNAMIC  303
  47. #define IDM_SHOWMAIN 304
  48.  
  49. const UINT WM_TASKBARCREATED = ::RegisterWindowMessage( _T("TaskbarCreated") );
  50.  
  51. TOptions options;
  52. static UINT timerID = 1;
  53.  
  54. // CAboutDlg-Dialogfeld fⁿr Anwendungsbefehl 'Info'
  55.  
  56. class CAboutDlg : public CDialog
  57. {
  58. public:
  59.     CAboutDlg();
  60.  
  61. // Dialogfelddaten
  62.     enum { IDD = IDD_ABOUTBOX };
  63.     CHyperLink    m_gplLink;
  64.     CHyperLink    m_homeLink;
  65.     CHyperLink    m_faqLink;
  66.  
  67.     protected:
  68.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV-Unterstⁿtzung
  69.   virtual BOOL OnInitDialog();
  70.  
  71. // Implementierung
  72. protected:
  73.     DECLARE_MESSAGE_MAP()
  74. };
  75.  
  76. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  77. { }
  78.  
  79. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  80. {
  81.   CDialog::DoDataExchange(pDX);
  82.   DDX_Control(pDX, IDC_GPLLINK, m_gplLink);
  83.   DDX_Control(pDX, IDC_URLTEXT1, m_homeLink);
  84.   DDX_Control(pDX, IDC_URLTEXT4, m_faqLink);
  85. }
  86.  
  87. //////////////////
  88. // Initialize dialog: subclass static controls
  89. BOOL CAboutDlg::OnInitDialog() 
  90. {
  91.   m_gplLink.SetURL( _T("http://www.fsf.org/licenses/gpl.txt") );
  92.   m_gplLink.SetUnderline( TRUE );
  93.  
  94.   m_homeLink.SetURL( _T("http://www.diefer.de/speedswitchxp/index.html") );
  95.   m_homeLink.SetUnderline( TRUE );
  96.  
  97.   m_faqLink.SetURL( _T("http://www.diefer.de/speedswitchxp/faq.html") );
  98.   m_faqLink.SetUnderline( TRUE );
  99.  
  100.   return CDialog::OnInitDialog();
  101. }
  102.  
  103. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  104. END_MESSAGE_MAP()
  105.  
  106. // CSpeedswitchXPDlg Dialogfeld
  107.  
  108.  
  109. //**************************************************************
  110. // Constructor for main class
  111. //**************************************************************
  112. CSpeedswitchXPDlg::CSpeedswitchXPDlg(CWnd* pParent /*=NULL*/)
  113.     : CDialog(CSpeedswitchXPDlg::IDD, pParent)
  114.   , m_iACState(0)
  115.   , m_iDCState(0)
  116.   , m_szCPULoad(_T("---"))
  117.   , m_szCPUSpeed(_T("---"))
  118.   , m_szMaxCPUSpeed(_T(""))
  119. {
  120.   getRegKeys();   // read configuration from registry
  121.  
  122.   diagramOffset = 0;
  123.  
  124.   if( options.debugMode )
  125.     DeleteFile( "SpeedswitchXP.log" );
  126.  
  127.   log( "Constructor: Starting" );
  128.   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  129.   iBattOpt = AfxGetApp()->LoadIcon(IDR_BATTOPT);
  130.   iMaxPerf = AfxGetApp()->LoadIcon(IDR_MAXPERF);
  131.   iMaxBatt = AfxGetApp()->LoadIcon(IDR_MAXBATT);
  132.   iDynamic = AfxGetApp()->LoadIcon(IDR_DYNAMIC);
  133.   iTrayBattery = AfxGetApp()->LoadIcon(IDI_TRAYBATT);
  134.   iBattCharge = AfxGetApp()->LoadIcon(IDI_CHARGEICON);
  135.  
  136.   int i;
  137.   for( i=0; i<32*32/8; i++ )
  138.     and[i] = xor[i] = 0x00;
  139.  
  140.   cpuDataIcon = CreateIcon( AfxGetApp()->m_hInstance, 32, 32, 1, 1, and, xor );
  141.  
  142.   loadIndex = 0;
  143.   speedIndex = 0;
  144.   tickCounterCPU = 0;
  145.   tickCounterCheck = 0;
  146.   batteryIconActive = FALSE;
  147.   batteryIconCharge = FALSE;
  148.   batteryValue = -2;
  149.   cpuDataIconActive = FALSE;
  150.   cpuIconVal1 = -2;
  151.   cpuIconVal2 = -2;
  152.   curSpeed = 0;
  153.   curLoad = 0;
  154.  
  155.   for( int i=0; i<1200; i++ )   // init history arrays
  156.     loadArr[i] = speedArr[i] = 0;
  157.  
  158.   trayIcon = FALSE;
  159.  
  160.   log( "Constructor: Creating dialog" );
  161.   Create( CSpeedswitchXPDlg::IDD, pParent );
  162.  
  163.   // compute diagram offsets
  164.   frameStart = (CWnd*)GetDlgItem(IDC_FRAMESTART);
  165.   RECT r1, r2;
  166.   frameStart->GetWindowRect( &r1 );
  167.   ScreenToClient( &r1 );
  168.   frameEnd = (CWnd*)GetDlgItem(IDC_DIAGRAM2);
  169.   frameEnd->GetWindowRect( &r2 );
  170.   ScreenToClient( &r2 );
  171.   legendLine = r2.bottom;
  172.  
  173.   if( (r2.bottom - r1.top) > 120 )
  174.     ybaseoffset = (r2.bottom-r1.top-120) / 2;
  175.   else
  176.     ybaseoffset = 0;
  177.  
  178.   if( (r2.right - r1.left) > 385 )
  179.     xbaseoffset = (r2.right-r1.left-385) / 2;
  180.   else
  181.     xbaseoffset = 0;
  182.  
  183.   log( "Constructor: Complete" );
  184. }
  185.  
  186. void CSpeedswitchXPDlg::DoDataExchange(CDataExchange* pDX)
  187. {
  188.   CDialog::DoDataExchange(pDX);
  189.   DDX_CBIndex(pDX, IDC_COMBO1, m_iACState);
  190.   DDX_CBIndex(pDX, IDC_COMBO2, m_iDCState);
  191.   DDX_Text(pDX, IDC_EDIT1, m_szCPULoad);
  192.   DDX_Text(pDX, IDC_EDIT2, m_szCPUSpeed);
  193.   DDX_Text(pDX, IDC_EDIT3, m_szMaxCPUSpeed);
  194.   DDX_Control(pDX, IDC_COMBO3, m_cDisplayAC);
  195.   DDX_Control(pDX, IDC_COMBO7, m_cDisplayDC);
  196.   DDX_Control(pDX, IDC_COMBO4, m_cDiskAC);
  197.   DDX_Control(pDX, IDC_COMBO8, m_cDiskDC);
  198.   DDX_Control(pDX, IDC_COMBO5, m_cStandbyAC);
  199.   DDX_Control(pDX, IDC_COMBO9, m_cStandbyDC);
  200.   DDX_Control(pDX, IDC_COMBO6, m_cHibernationAC);
  201.   DDX_Control(pDX, IDC_COMBO10, m_cHibernationDC);
  202. }
  203.  
  204. BEGIN_MESSAGE_MAP(CSpeedswitchXPDlg, CDialog)
  205.   ON_WM_SYSCOMMAND()
  206.   ON_WM_PAINT()
  207.   ON_WM_QUERYDRAGICON()
  208.   ON_WM_CLOSE()
  209.   ON_WM_TIMER()
  210.   ON_WM_HSCROLL()
  211.   ON_BN_CLICKED(IDC_TRAYBUTTON, OnTraybutton)
  212.   ON_MESSAGE(WM_ICONNOTIFY, OnIconNotify)
  213.   ON_MESSAGE(WM_POWERBROADCAST, OnPowerBroadCast)
  214.   ON_BN_CLICKED(IDC_CLOSE, OnBnClickedClose)
  215.   ON_BN_CLICKED(IDC_ABOUT, OnAbout)
  216.   ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1)
  217.   ON_CBN_SELCHANGE(IDC_COMBO2, OnCbnSelchangeCombo2)
  218.   ON_BN_CLICKED(IDC_OPTBUTTON, OnBnClickedOptbutton)
  219.   ON_COMMAND(IDM_MAXPERF, OnMaxPerfMenu)
  220.   ON_COMMAND(IDM_BATTOPT, OnBattOptMenu)
  221.   ON_COMMAND(IDM_MAXBATT, OnMaxBattMenu)
  222.   ON_COMMAND(IDM_DYNAMIC, OnDynamicMenu)
  223.   ON_COMMAND(IDM_SHOWMAIN, OnShowMainMenu)
  224.   ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2)
  225.   ON_WM_SETCURSOR()
  226.   ON_CBN_SELCHANGE(IDC_COMBO3, OnCbnSelchangeDisplayAC)
  227.   ON_CBN_SELCHANGE(IDC_COMBO7, OnCbnSelchangeDisplayDC)
  228.   ON_CBN_SELCHANGE(IDC_COMBO4, OnCbnSelchangeDiskAC)
  229.   ON_CBN_SELCHANGE(IDC_COMBO8, OnCbnSelchangeDiskDC)
  230.   ON_CBN_SELCHANGE(IDC_COMBO5, OnCbnSelchangeStandbyAC)
  231.   ON_CBN_SELCHANGE(IDC_COMBO9, OnCbnSelchangeStandbyDC)
  232.   ON_CBN_SELCHANGE(IDC_COMBO6, OnCbnSelchangeHibAC)
  233.   ON_CBN_SELCHANGE(IDC_COMBO10, OnCbnSelchangeHibDC)
  234.   ON_BN_CLICKED(IDC_BUTTON3, OnBnClickedCPUData)
  235.   ON_REGISTERED_MESSAGE(WM_TASKBARCREATED, OnTaskBarCreated)
  236.   ON_BN_CLICKED(IDC_BUTTON4, OnBnClickedButton4)
  237. END_MESSAGE_MAP()
  238.  
  239.  
  240. // CSpeedswitchXPDlg Meldungshandler
  241.  
  242. //**************************************************************
  243. // redisplay tray icon(s)
  244. //**************************************************************
  245. LRESULT CSpeedswitchXPDlg::OnTaskBarCreated( WPARAM wp, LPARAM lp )
  246. {
  247.   displayTrayIcon( NIM_ADD );
  248.  
  249.   if( batteryIconActive )
  250.   {
  251.     batteryIconActive = batteryIconCharge = FALSE;
  252.     batteryDisplay( NULL );
  253.   }
  254.  
  255.   if( cpuDataIconActive )
  256.     displayCPUDataIcon( NIM_ADD );
  257.  
  258.   return 0;
  259. }
  260.  
  261. //**************************************************************
  262. // initialize dialog window
  263. //**************************************************************
  264. BOOL CSpeedswitchXPDlg::OnInitDialog()
  265. {
  266.   log( "InitDialog: Start" );
  267.   CDialog::OnInitDialog();
  268.  
  269.     // Hinzufⁿgen des Menⁿbefehls "Info..." zum Systemmenⁿ.
  270.  
  271.     // IDM_ABOUTBOX muss sich im Bereich der Systembefehle befinden.
  272.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  273.     ASSERT(IDM_ABOUTBOX < 0xF000);
  274.  
  275.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  276.     if (pSysMenu != NULL)
  277.     {
  278.         CString strAboutMenu;
  279.         strAboutMenu.LoadString(IDS_ABOUTBOX);
  280.         if (!strAboutMenu.IsEmpty())
  281.         {
  282.             pSysMenu->AppendMenu(MF_SEPARATOR);
  283.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  284.         }
  285.     }
  286.  
  287.     // Symbol fⁿr dieses Dialogfeld festlegen. Wird automatisch erledigt
  288.     //  wenn das Hauptfenster der Anwendung kein Dialogfeld ist
  289.     SetIcon( m_hIcon, TRUE );            // Gro▀es Symbol verwenden
  290.     SetIcon( m_hIcon, FALSE );        // Kleines Symbol verwenden
  291.  
  292.     // TODO: Hier zusΣtzliche Initialisierung einfⁿgen
  293.     OSVERSIONINFO ovi;
  294.  
  295.     ovi.dwOSVersionInfoSize = sizeof( ovi );
  296.  
  297.     if( GetVersionEx(&ovi) == 0 )
  298.         return FALSE;        // this should never happen !
  299.  
  300.   log( "Running on %s Version %d.%d Build %d (%s)",
  301.        ovi.dwPlatformId==VER_PLATFORM_WIN32_NT 
  302.            ? "Windows NT"
  303.            : (ovi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS
  304.            ? "Windows 9x" : "Windows 3.1 (?)"),
  305.        ovi.dwMajorVersion,
  306.        ovi.dwMinorVersion,
  307.        ovi.dwBuildNumber,
  308.        ovi.szCSDVersion );
  309.  
  310.     // not running on XP or higher => terminate
  311.     if( ovi.dwPlatformId!=VER_PLATFORM_WIN32_NT || ovi.dwBuildNumber<2600 )
  312.   {
  313.     log( "/aError" );
  314.     MessageBox( "This program can only work under Windows XP or higher", "Error", MB_OK|MB_ICONEXCLAMATION ); 
  315.     PostMessage( WM_CLOSE );
  316.     return FALSE;
  317.   }
  318.  
  319.   if( !initPowerValues() )    // set box contents on main window
  320.     return FALSE;
  321.  
  322.   UpdateData( FALSE );
  323.  
  324.   log( "InitDialog: Complete" );
  325.  
  326.     return TRUE;
  327. }
  328.  
  329. //**************************************************************
  330. // read keys from registry
  331. //**************************************************************
  332. void CSpeedswitchXPDlg::getRegKeys()
  333. {
  334.   if( !options.getRegKeys() )
  335.     MessageBox( "Can't get registry values", "Error", MB_ICONEXCLAMATION|MB_OK );
  336. }
  337.  
  338. //**************************************************************
  339. // write keys to registry
  340. //**************************************************************
  341. void CSpeedswitchXPDlg::setRegKeys()
  342. {
  343.   if( !options.setRegKeys() )
  344.     MessageBox( "Can't set registry values", "Error", MB_ICONEXCLAMATION|MB_OK );
  345. }
  346.  
  347. //**************************************************************
  348. // evaluate command line options (used here to indicate program 
  349. // start, thus displaying the tray icon)
  350. //**************************************************************
  351. void CSpeedswitchXPDlg::setCmdLine( char* cl )
  352. {
  353.   log( "setCmdLine: Start" );
  354.   displayTrayIcon( NIM_ADD );
  355.   trayIcon = TRUE;
  356.   OnTraybutton();
  357.   log( "setCmdLine: Complete" );
  358. }
  359.  
  360. //**************************************************************
  361. // evaluate commands from the system menu
  362. //**************************************************************
  363. void CSpeedswitchXPDlg::OnSysCommand(UINT nID, LPARAM lParam)
  364. {
  365.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  366.     {
  367.         CAboutDlg dlgAbout;
  368.         dlgAbout.DoModal();
  369.     }
  370.     else
  371.     {
  372.         CDialog::OnSysCommand(nID, lParam);
  373.     }
  374. }
  375.  
  376. // Wenn Sie dem Dialogfeld eine SchaltflΣche "Minimieren" hinzufⁿgen, ben÷tigen Sie 
  377. //  den nachstehenden Code, um das Symbol zu zeichnen. Fⁿr MFC-Anwendungen, die das 
  378. //  Dokument/Ansicht-Modell verwenden, wird dies automatisch ausgefⁿhrt.
  379.  
  380. void CSpeedswitchXPDlg::OnPaint() 
  381. {
  382.     if (IsIconic())
  383.     {
  384.         CPaintDC dc(this); // GerΣtekontext zum Zeichnen
  385.  
  386.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
  387.  
  388.         // Symbol in Clientrechteck zentrieren
  389.         int cxIcon = GetSystemMetrics(SM_CXICON);
  390.         int cyIcon = GetSystemMetrics(SM_CYICON);
  391.         CRect rect;
  392.         GetClientRect(&rect);
  393.         int x = (rect.Width() - cxIcon + 1) / 2;
  394.         int y = (rect.Height() - cyIcon + 1) / 2;
  395.  
  396.         // Symbol zeichnen
  397.         dc.DrawIcon(x, y, m_hIcon);
  398.     }
  399.     else
  400.     {
  401.       drawDiagram();
  402.         CDialog::OnPaint();
  403.     }
  404. }
  405.  
  406. // Die System ruft diese Funktion auf, um den Cursor abzufragen, der angezeigt wird, wΣhrend der Benutzer
  407. //  das minimierte Fenster mit der Maus zieht.
  408. HCURSOR CSpeedswitchXPDlg::OnQueryDragIcon()
  409. {
  410.     return static_cast<HCURSOR>(m_hIcon);
  411. }
  412.  
  413. //**************************************************************
  414. // process events from the tray icon
  415. //**************************************************************
  416. LRESULT CSpeedswitchXPDlg::OnIconNotify( WPARAM w, LPARAM l )
  417. {
  418.   switch( l )
  419.   {
  420.     case WM_LBUTTONUP:
  421.           ShowWindow( SW_SHOW );
  422.           SetForegroundWindow();
  423.           break;
  424.  
  425.     case WM_RBUTTONUP:
  426.           {
  427.             CMenu menu;
  428.             menu.CreatePopupMenu();
  429.  
  430.             int cur = options.ac ? acThrottle : dcThrottle;
  431.  
  432.             for( int i=0; i<4; i++ )
  433.               menu.AppendMenu( MF_STRING | (i==cur ? MF_CHECKED : 0),
  434.                                IDM_MAXPERF+i, 
  435.                                throttleString(i) );
  436.  
  437.             menu.AppendMenu( MF_SEPARATOR );
  438.             menu.AppendMenu( MF_STRING, IDM_SHOWMAIN, "Main window" );
  439.             SetMenuDefaultItem( menu, IDM_SHOWMAIN, FALSE );
  440.  
  441.             POINT Point;
  442.             GetCursorPos( &Point );
  443.             SetForegroundWindow();
  444.  
  445.             menu.TrackPopupMenu( TPM_LEFTALIGN|TPM_BOTTOMALIGN|TPM_NONOTIFY,
  446.                                  Point.x,
  447.                                  Point.y,
  448.                                  this );
  449.             menu.Detach();
  450.           }
  451.           break;
  452.   }
  453.  
  454.   return 0;
  455. }
  456.  
  457. //**************************************************************
  458. // enter autostart string in the user's autostart registry area
  459. //**************************************************************
  460. void CSpeedswitchXPDlg::setAutoStartRegistry()
  461. {
  462.   LONG lReturn = 0;
  463.   char path[264];
  464.   CRegKey key;
  465.  
  466.   if( GetModuleFileName(NULL,path,255) == 0 )
  467.   {
  468.     MessageBox( "Can't get module name", "Error", MB_OK|MB_ICONEXCLAMATION );
  469.     return;
  470.   }
  471.  
  472.   lReturn = key.Create( HKEY_CURRENT_USER,
  473.                         "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" );
  474.  
  475.   if( lReturn == ERROR_SUCCESS )
  476.   {
  477.     if( key.SetValue("SpeedswitchXP",REG_SZ,path,(ULONG)strlen(path)) != ERROR_SUCCESS )
  478.     {
  479.       MessageBox( "Can't set registry", "Error", MB_ICONEXCLAMATION|MB_OK );
  480.       key.Close();
  481.       return;
  482.     }
  483.   }
  484.   else
  485.     MessageBox( "Can't set registry", "Error", MB_ICONEXCLAMATION|MB_OK );
  486.  
  487.   key.Close();
  488. }
  489.  
  490. //**************************************************************
  491. // ... and delete it if the user asks for it
  492. //**************************************************************
  493. void CSpeedswitchXPDlg::deleteAutoStartRegistry()
  494. {
  495.   CRegKey key;
  496.   LONG result = key.Open( HKEY_CURRENT_USER,
  497.                           "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" );
  498.  
  499.   if( result == ERROR_SUCCESS )
  500.     key.DeleteValue( "SpeedswitchXP");
  501.   else
  502.     MessageBox( "Can't delete autostart registry entry", "Error", MB_ICONERROR );
  503.   
  504.   key.Close();
  505. }
  506.  
  507. //**************************************************************
  508. // last method to be called during this class' lifetime
  509. //**************************************************************
  510. void CSpeedswitchXPDlg::PostNcDestroy()
  511. {
  512.     delete this;
  513. }
  514.  
  515. //**************************************************************
  516. // show the 'About' dialog
  517. //**************************************************************
  518. void CSpeedswitchXPDlg::OnAbout() 
  519. {
  520.     CAboutDlg dlgAbout;
  521.     dlgAbout.DoModal();    
  522. }
  523.  
  524. //**************************************************************
  525. // handler for 'Minimize to tray' button
  526. //**************************************************************
  527. void CSpeedswitchXPDlg::OnTraybutton()
  528. {
  529.   ShowWindow( SW_HIDE );
  530. }
  531.  
  532. void CSpeedswitchXPDlg::OnBnClickedClose()
  533. {
  534.   if( options.minimizeOnClose )
  535.   {
  536.     OnTraybutton();
  537.     return;
  538.   }
  539.  
  540.   OnClose();
  541. }
  542.  
  543. //**************************************************************
  544. // process the Close request
  545. //**************************************************************
  546. void CSpeedswitchXPDlg::OnClose()
  547. {
  548.   log( "--------------------------------" );
  549.   log( "Begin termination" );
  550.  
  551.   if( closeQuery() )
  552.   {
  553.     setRegKeys();
  554.  
  555.     if( activeTimer )
  556.     {
  557.       log( "/bKilling timer (%d)...", timerID );
  558.       if( KillTimer(timerID) == 0 )
  559.         log( "/aError" );
  560.       else
  561.         log( "/aOK" );
  562.       tickCounterCPU = 0;
  563.       tickCounterCheck = 0;
  564.     }
  565.  
  566.     log( "/bClosing main window..." );
  567.     DestroyWindow();
  568.     log( "/aOK" );
  569.  
  570.     if( options.reactivate )
  571.     {
  572.       log( "/bRestoring previous power scheme ..." );
  573.       SetActivePwrScheme( options.originalScheme, NULL, NULL );
  574.       log( "/aOK" );
  575.     }
  576.   }
  577. }
  578.  
  579. //**************************************************************
  580. // CloseQuery taken from I8kfanGUI; only used here to remove the
  581. // tray icon
  582. //**************************************************************
  583. bool CSpeedswitchXPDlg::closeQuery()
  584. {
  585.   if( trayIcon )
  586.   {
  587.     log( "removing tray icon..." );
  588.     NOTIFYICONDATA nid;
  589.     nid.cbSize = sizeof( NOTIFYICONDATA );
  590.     nid.hWnd = m_hWnd;
  591.     nid.uID = 700;
  592.     nid.uCallbackMessage = WM_ICONNOTIFY;
  593.     nid.hIcon = curIcon;
  594.     Shell_NotifyIcon( NIM_DELETE, &nid );
  595.   }
  596.  
  597.   if( batteryIconActive )
  598.     removeBatteryIcon();
  599.  
  600.   if( cpuDataIconActive )
  601.     removeCPUDataIcon();
  602.  
  603.   return true;
  604. }
  605.  
  606. //**************************************************************
  607. // display/modify/remove the tray icon
  608. //**************************************************************
  609. void CSpeedswitchXPDlg::displayTrayIcon( DWORD msg )
  610. {
  611.   NOTIFYICONDATA nid;
  612.   static char tp[128];
  613.  
  614.   nid.cbSize = sizeof( NOTIFYICONDATA );
  615.   nid.hWnd = m_hWnd;
  616.   nid.uID = 700;
  617.   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  618.   nid.uCallbackMessage = WM_ICONNOTIFY;
  619.  
  620.   wsprintf( tp, "AC: %s%s\nDC: %s%s",
  621.                 throttleString(acThrottle),
  622.                 options.ac ? " <-" : "",
  623.                 throttleString(dcThrottle),
  624.                 options.ac ? "" : " <-" );
  625.   
  626.   if( options.readCPUSpeed )
  627.     wsprintf( &tp[strlen(tp)],
  628.                 "\nCur. speed:%s MHz",
  629.                 m_szCPUSpeed );
  630.  
  631.   if( options.readCPULoad )
  632.     wsprintf( &tp[strlen(tp)],
  633.                 "\nCPU load:%s %%",
  634.                 m_szCPULoad );
  635.   
  636.   lstrcpy( nid.szTip, tp );
  637.   nid.hIcon = curIcon;
  638.  
  639.   Shell_NotifyIcon( msg, &nid );
  640. }
  641.  
  642. //**************************************************************
  643. // select the 'flag' icon corresponding to the current CPU policy
  644. //**************************************************************
  645. void CSpeedswitchXPDlg::setCPUIcon( int policy )
  646. {
  647.   switch( policy )
  648.   {
  649.     case PO_THROTTLE_NONE:      curIcon = iMaxPerf;
  650.                                 break;
  651.  
  652.     case PO_THROTTLE_ADAPTIVE:  curIcon = iDynamic;
  653.                                 break;
  654.         
  655.     case PO_THROTTLE_CONSTANT:  curIcon = iBattOpt;
  656.                                 break;
  657.  
  658.     case PO_THROTTLE_DEGRADE:   curIcon = iMaxBatt;
  659.                                 break;
  660.   }
  661. }
  662.  
  663. //**************************************************************
  664. // process AC policy change by user
  665. //**************************************************************
  666. void CSpeedswitchXPDlg::OnCbnSelchangeCombo1()
  667. {
  668.   int i = acThrottle;
  669.  
  670.   UpdateData();
  671. //  if( i != m_iACState )
  672.   {
  673.     log( "changing AC from %d to %d", i, m_iACState );
  674.  
  675.     // Workaround for high load situations when switching from batt.opt/max.batt to
  676.     // dynamic switching: the CPU speed stays at lower speed for duration of high
  677.     // load 
  678.     // => take a short step to max.performance to reset XP's internal idle timer
  679.     if( options.ac )   // really on battery ?
  680.     {
  681.       if( i!=PO_THROTTLE_NONE && m_iACState==PO_THROTTLE_ADAPTIVE )
  682.         setState( TRUE, PO_THROTTLE_NONE );    // take a short step to 'Max.Performance'
  683.     }
  684.  
  685.     if( !setState(TRUE,m_iACState) )
  686.     {
  687.       log( "*** change failed ***" );
  688.       m_iACState = i;
  689.       UpdateData( FALSE );
  690.       MessageBox( "Policy change failed", "Error", MB_OK|MB_ICONEXCLAMATION );
  691.       return;
  692.     }
  693.  
  694.     if( options.ac )
  695.       setCPUIcon( m_iACState );
  696.  
  697.     displayTrayIcon( NIM_MODIFY );
  698.   }
  699. }
  700.  
  701. //**************************************************************
  702. // process DC policy change by user
  703. //**************************************************************
  704. void CSpeedswitchXPDlg::OnCbnSelchangeCombo2()
  705. {
  706.   int i = dcThrottle;
  707.  
  708.   UpdateData();
  709. //  if( i != m_iDCState )
  710.   {
  711.     log( "changing DC from %d to %d", i, m_iDCState );
  712.  
  713.     // Workaround for high load situations when switching from batt.opt/max.batt to
  714.     // dynamic switching: the CPU speed stays at lower speed for duration of high
  715.     // load 
  716.     // => take a short step to max.performance to reset XP's internal idle timer
  717.     if( !options.ac )   // really on battery ?
  718.     {
  719.       if( i!=PO_THROTTLE_NONE && m_iDCState==PO_THROTTLE_ADAPTIVE )
  720.         setState( FALSE, PO_THROTTLE_NONE );    // take a short step to 'Max.Performance'
  721.     }
  722.  
  723.     if( !setState(FALSE,m_iDCState) )
  724.     {
  725.       log( "*** change failed ***" );
  726.       m_iDCState = i;
  727.       UpdateData( FALSE );
  728.       MessageBox( "Policy change failed", "Error", MB_OK|MB_ICONEXCLAMATION );
  729.       return;
  730.     }
  731.  
  732.     if( !options.ac )
  733.       setCPUIcon( m_iDCState );
  734.  
  735.     displayTrayIcon( NIM_MODIFY );
  736.   }
  737. }
  738.  
  739. //**************************************************************
  740. // process power status change event from system
  741. //**************************************************************
  742. LRESULT CSpeedswitchXPDlg::OnPowerBroadCast( WPARAM wp, LPARAM lp )
  743. {
  744.   if( wp == PBT_APMPOWERSTATUSCHANGE )
  745.   {
  746.     log( "Powerstatus change detected !" );
  747.     if( GetSystemPowerStatus(&pwrStatus) )
  748.     {
  749.       BOOL x = (pwrStatus.ACLineStatus!=0);
  750.    
  751.       if( x != options.ac )
  752.       {
  753.         log( "change from %s to %s", options.ac?"AC":"DC", x?"AC":"DC" );
  754.         options.ac = x;
  755.         setCPUIcon( options.ac ? acThrottle : dcThrottle );
  756.         displayTrayIcon( NIM_MODIFY );
  757.  
  758.         if( options.showBattery )
  759.           batteryDisplay( &pwrStatus );
  760.       }
  761.     }
  762.   }
  763.   
  764.   return 0;
  765. }
  766.  
  767. //**************************************************************
  768. // handler for 'Options' button
  769. //**************************************************************
  770. void CSpeedswitchXPDlg::OnBnClickedOptbutton()
  771. {
  772.   CSpeedswitchXPOptions dlg;
  773.  
  774.   dlg.setVars( options );
  775.  
  776.     if( dlg.DoModal() == IDOK )
  777.   {
  778.     dlg.getVars( options );
  779.  
  780.     if( dlg.power || dlg.cpu )
  781.     {
  782.       log( "writing new power policies:%d %d", dlg.power, dlg.cpu );
  783.       writePolicies( dlg.power, dlg.cpu );
  784.     }
  785.  
  786.     setRegKeys();
  787.  
  788.     if( options.autoStart )
  789.       setAutoStartRegistry();
  790.     else
  791.       deleteAutoStartRegistry();
  792.  
  793.     if( !options.readCPUSpeed )
  794.       m_szCPUSpeed = "---";
  795.  
  796.     if( !options.readCPULoad )
  797.       m_szCPULoad = "---";
  798.  
  799.     if( activeTimer 
  800.     && !(options.checkStatus || options.readCPUSpeed || options.readCPULoad || options.showBattery) )
  801.     {
  802.       log( "Killing existing timer" );
  803.       KillTimer( timerID );
  804.       activeTimer = FALSE;
  805.     }
  806.  
  807.     if( !activeTimer 
  808.     && (options.checkStatus || options.readCPUSpeed || options.readCPULoad || options.showBattery) )
  809.     {
  810.       log( "Creating new timer" );
  811.       SetTimer( timerID, 1000, NULL );
  812.       activeTimer = TRUE;
  813.     }
  814.  
  815.     displayTrayIcon( NIM_MODIFY );
  816.  
  817.     if( !GetSystemPowerStatus(&pwrStatus) )
  818.       MessageBox( "Can't detect current power status", "SpeedswitchXP error", MB_ICONEXCLAMATION|MB_OK );
  819.     else
  820.     {
  821.       // check battery options for changes:
  822.       // 1. battery option off & icon shown => remove icon
  823.       if( !options.showBattery && batteryIconActive )
  824.         removeBatteryIcon();
  825.       // 2. battery option on => show/update/remove icon
  826.       else if( options.showBattery )
  827.         batteryDisplay( &pwrStatus );
  828.     }
  829.  
  830.     if( !options.speedIcon && !options.loadIcon && cpuDataIconActive )
  831.       removeCPUDataIcon();
  832.     else if( options.speedIcon || options.loadIcon )
  833.       displayCPUDataIcon( cpuDataIconActive ? NIM_MODIFY : NIM_ADD );
  834.  
  835.     initPowerBoxes();
  836.          
  837.     UpdateData( FALSE );
  838.   }
  839. }
  840.  
  841.  
  842. //**************************************************************
  843. // handlers for tray icon menu
  844. //**************************************************************
  845. void CSpeedswitchXPDlg::OnMaxPerfMenu( void )
  846. { MenuSpeedHandler(PO_THROTTLE_NONE); }
  847.  
  848. void CSpeedswitchXPDlg::OnBattOptMenu( void )
  849. { MenuSpeedHandler(PO_THROTTLE_CONSTANT); }
  850.  
  851. void CSpeedswitchXPDlg::OnMaxBattMenu( void )
  852. { MenuSpeedHandler(PO_THROTTLE_DEGRADE); }
  853.  
  854. void CSpeedswitchXPDlg::OnDynamicMenu( void )
  855. { MenuSpeedHandler(PO_THROTTLE_ADAPTIVE); }
  856.  
  857. void CSpeedswitchXPDlg::OnShowMainMenu( void )
  858. { ShowWindow(SW_SHOW); }
  859.  
  860. void CSpeedswitchXPDlg::MenuSpeedHandler( int throttle )
  861. {
  862.   if( options.ac )
  863.   {
  864.     UpdateData();
  865.     int x = m_iACState;
  866.     m_iACState = throttle;
  867.     UpdateData( FALSE );
  868.     m_iACState = x;
  869.     OnCbnSelchangeCombo1();
  870.   }
  871.   else
  872.   {
  873.     UpdateData();
  874.     int x = m_iDCState;
  875.     m_iDCState = throttle;
  876.     UpdateData( FALSE );
  877.     m_iDCState = x;
  878.     OnCbnSelchangeCombo2();
  879.   }
  880. }
  881.  
  882. //**************************************************************
  883. // perform user requested scrolling in the history diagram
  884. //**************************************************************
  885. void CSpeedswitchXPDlg::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
  886. {
  887.   if( pScrollBar != ((CScrollBar*)GetDlgItem(IDC_SCROLLBAR1)) )
  888.     return;
  889.  
  890.   int curpos = pScrollBar->GetScrollPos();
  891.   int newpos = curpos;
  892.  
  893.   switch( nSBCode )
  894.   {
  895.     case SB_THUMBPOSITION:
  896.     case SB_THUMBTRACK:
  897.            newpos = nPos;
  898.            break;
  899.  
  900.     case SB_LEFT:
  901.            newpos = 0;
  902.            break;
  903.  
  904.     case SB_RIGHT:
  905.            newpos = 90;
  906.            break;
  907.  
  908.     case SB_LINELEFT:
  909.     case SB_PAGELEFT:
  910.            if( curpos > 0 )
  911.              newpos = curpos-1;
  912.            break;
  913.  
  914.     case SB_LINERIGHT:
  915.     case SB_PAGERIGHT:
  916.            if( curpos < 90 )
  917.              newpos = curpos+1;
  918.            break;
  919.  
  920.     case SB_ENDSCROLL:
  921.            break;
  922.   }
  923.  
  924.   if( newpos != curpos )
  925.   {
  926.     pScrollBar->SetScrollPos( newpos, TRUE );
  927.     diagramOffset = (90-newpos) * 12;
  928.  
  929.     frameStart = (CWnd*)GetDlgItem(IDC_FRAMESTART);
  930.     RECT r1;
  931.     frameStart->GetWindowRect( &r1 );
  932.     ScreenToClient( &r1 );
  933.     int ybase = r1.top + ybaseoffset;
  934.     int xbase = r1.left + xbaseoffset;
  935.  
  936.     RECT r;
  937.     r.left = xbase+1;
  938.     r.top = ybase-1;
  939.     r.right = xbase+352;
  940.     r.bottom = ybase+151;
  941.     InvalidateRect( &r, FALSE );
  942.   }
  943.  
  944.   CDialog::OnHScroll( nSBCode, nPos, pScrollBar );
  945. }
  946.  
  947. //**************************************************************
  948. // perform timer dependend tasks (read CPU speed/load etc.)
  949. //**************************************************************
  950. void CSpeedswitchXPDlg::OnTimer( UINT nIDEvent ) 
  951. {
  952.     if( nIDEvent == timerID )
  953.   {
  954.     if( (options.readCPUSpeed || options.readCPULoad || options.showBattery) && (int)tickCounterCPU>=options.cpuInterval )
  955.     {
  956.       UpdateData();
  957.  
  958.       CString sp = m_szCPUSpeed;
  959.       CString lo = m_szCPULoad;
  960.  
  961.       if( options.readCPUSpeed )
  962.         readCPUSpeed();
  963.       else
  964.       {
  965.         speedArr[speedIndex++] = 0;
  966.         if( speedIndex >= 1200 )
  967.           speedIndex = 0;
  968.       }
  969.  
  970.       if( options.readCPULoad )
  971.         readCPULoad();
  972.       else
  973.       {
  974.         loadArr[loadIndex++] = 0;
  975.         if( loadIndex >= 1200 )
  976.           loadIndex = 0;
  977.       }
  978.  
  979.       if( sp!=m_szCPUSpeed || lo!=m_szCPULoad )
  980.       {
  981.         displayTrayIcon( NIM_MODIFY );
  982.  
  983.         if( cpuDataIconActive )
  984.           displayCPUDataIcon( NIM_MODIFY );
  985.       }
  986.  
  987.       if( options.showBattery )
  988.         batteryDisplay( NULL );
  989.  
  990.       tickCounterCPU = 0;
  991.  
  992.       UpdateData( FALSE );
  993.  
  994.       if( options.showDiagram )   // update history diagram
  995.       {
  996.         frameStart = (CWnd*)GetDlgItem(IDC_FRAMESTART);
  997.         RECT r1;
  998.         frameStart->GetWindowRect( &r1 );
  999.         ScreenToClient( &r1 );
  1000.         int ybase = r1.top + ybaseoffset;
  1001.         int xbase = r1.left + xbaseoffset;
  1002.  
  1003.         RECT r;
  1004.         r.left = xbase+1;
  1005.         r.top = ybase-1;
  1006.         r.right = xbase+352;
  1007.         r.bottom = ybase+151;
  1008.         InvalidateRect( &r, FALSE );
  1009.       }
  1010.     }
  1011.  
  1012.     if( (int)tickCounterCheck >= (options.checkInterval*60) ) 
  1013.     {
  1014.       UpdateData();
  1015.       
  1016.       checkProfile( 3 );
  1017.  
  1018.       tickCounterCheck = 0;
  1019.       UpdateData( FALSE );
  1020.     }
  1021.  
  1022.     tickCounterCPU++;
  1023.     tickCounterCheck++;
  1024.   }
  1025.  
  1026.     CDialog::OnTimer( nIDEvent );
  1027. }
  1028.  
  1029. //**************************************************************
  1030. // get the current CPU speed dependend on the chosen method
  1031. //**************************************************************
  1032. void CSpeedswitchXPDlg::readCPUSpeed() 
  1033. {
  1034.   switch( options.speedMethod )
  1035.   {
  1036.     case 0: {
  1037.               DWORD speed;
  1038.               PROCESSOR_POWER_INFORMATION ppi;
  1039.               BOOL x = (CallNtPowerInformation(ProcessorInformation,
  1040.                                                NULL,
  1041.                                                0,
  1042.                                                &ppi,
  1043.                                                sizeof(ppi)) == ERROR_SUCCESS);
  1044.               if( x )
  1045.               {
  1046. /*
  1047.                 log( "curspeed:%d maxspeed:%d limit:%d Maxidlestate:%d Currentidlestate:%d",
  1048.                      ppi.CurrentMhz, 
  1049.                      ppi.MaxMhz, 
  1050.                      ppi.MhzLimit, 
  1051.                      ppi.MaxIdleState, 
  1052.                      ppi.CurrentIdleState );
  1053. */
  1054.                 speed = ppi.CurrentMhz;
  1055.                 char intbuf[16];
  1056.                 wsprintf( intbuf, "%d", speed );
  1057.                 m_szCPUSpeed = intbuf;
  1058.               }
  1059.               else
  1060.               {
  1061.                 m_szCPUSpeed = "???";
  1062.                 speed = 0;
  1063.               }
  1064.  
  1065.               BYTE z = (BYTE)(speed / 100);
  1066.               if( speed%100 >= 90 )
  1067.                 z++;
  1068.  
  1069.               speedArr[speedIndex++] = z;
  1070.               if( speedIndex >= 1200 )
  1071.                 speedIndex = 0;
  1072.  
  1073.               curSpeed = speed;
  1074.             }
  1075.             break;
  1076.  
  1077.     case 1:
  1078.             {
  1079.               char speed[16];
  1080.               int x = cpuSpeedHT();
  1081.               if( x == 0 )
  1082.                 strcpy( speed, "???" );
  1083.               else
  1084.                 wsprintf( speed, "%d", x );
  1085.               m_szCPUSpeed = speed;
  1086.  
  1087.               BYTE z = (BYTE)(x / 100);
  1088.               if( (x)%100 >= 90 )
  1089.                 z++;
  1090.  
  1091.               speedArr[speedIndex++] = z;
  1092.               if( speedIndex >= 1200 )
  1093.                 speedIndex = 0;
  1094.               
  1095.               curSpeed = x;
  1096.             }
  1097.             break;
  1098.  
  1099.  
  1100.  /*
  1101.     case 1:
  1102.             {
  1103.               char speed[16];
  1104.               FREQ_INFO fi = cpuspeed( NULL );
  1105.               wsprintf( speed, "%d", fi.raw_freq );
  1106.               m_szCPUSpeed = speed;
  1107.  
  1108.               BYTE z = (BYTE)(fi.raw_freq / 100);
  1109.               if( (fi.raw_freq)%100 >= 90 )
  1110.                 z++;
  1111.  
  1112.               speedArr[speedIndex++] = z;
  1113.               if( speedIndex >= 1200 )
  1114.                 speedIndex = 0;
  1115.             }
  1116.             break;
  1117. */
  1118.  
  1119.   }
  1120. }
  1121.  
  1122. //**************************************************************
  1123. // read the current CPU load
  1124. //**************************************************************
  1125. void CSpeedswitchXPDlg::readCPULoad() 
  1126. {
  1127.   DWORD t = cpuUsageNT();
  1128.   static DWORD oldUsage = 0;
  1129.   char intbuf[16];
  1130.  
  1131.   if( t > 100 )
  1132.     t = oldUsage;
  1133.  
  1134.   itoa( t, intbuf, 10 );
  1135.   m_szCPULoad = intbuf;
  1136.  
  1137.   loadArr[loadIndex++] = (BYTE)t;
  1138.   if( loadIndex >= 1200 )
  1139.     loadIndex = 0;
  1140.  
  1141.   curLoad = t;
  1142. }
  1143.  
  1144. //**************************************************************
  1145. // draw the history diagram
  1146. //**************************************************************
  1147. void CSpeedswitchXPDlg::drawDiagram()
  1148. {
  1149.   CPaintDC dc( this );
  1150.   CBrush bWhite(RGB(255,255,255));            // White
  1151.   CPen bRed(PS_SOLID,1,RGB(255,0,0));         // Red
  1152.   CPen bBlue(PS_SOLID,1,RGB(0,0,255));        // Blue
  1153.   CPen bBlack(PS_DOT,1,RGB(0,0,0));           // Black (dotted)
  1154.   CPen bSolidBlack(PS_SOLID,1,RGB(0,0,0));    // Black (solid)
  1155.   CPen bGreen(PS_SOLID,1,RGB(0,255,0));       // Green
  1156.   RECT r;
  1157.   int xbase, ybase;
  1158.  
  1159.   // FIX: get a relative y position in the dialog
  1160.   // for proper diagram display
  1161.   frameStart = (CWnd*)GetDlgItem(IDC_FRAMESTART);
  1162.   RECT r1;
  1163.   frameStart->GetWindowRect( &r1 );
  1164.   ScreenToClient( &r1 );
  1165.  
  1166.   ybase = r1.top + ybaseoffset;
  1167.   xbase = r1.left + xbaseoffset;
  1168.  
  1169.   dc.MoveTo( xbase, ybase );
  1170.   dc.LineTo( xbase+351, ybase );
  1171.   dc.LineTo( xbase+351, ybase+101 );
  1172.   dc.LineTo( xbase, ybase+101 );
  1173.   dc.LineTo( xbase, ybase );
  1174.  
  1175.   r.left = xbase+1;
  1176.   r.top = ybase+1;
  1177.   r.right = xbase+351;
  1178.   r.bottom = ybase+101;
  1179.   dc.FillRect( &r, &bWhite );
  1180.  
  1181.   dc.SelectObject( &bBlack );
  1182.   dc.MoveTo( xbase+1, ybase+50 );
  1183.   dc.LineTo( xbase+351, ybase+50 );
  1184.   dc.MoveTo( xbase+1, ybase+50+25 );
  1185.   dc.LineTo( xbase+351, ybase+50+25 );
  1186.   dc.MoveTo( xbase+1, ybase+50-25 );
  1187.   dc.LineTo( xbase+351, ybase+50-25 );
  1188.  
  1189.   if( options.showDiagram )
  1190.   {
  1191.     int x = loadIndex-117-diagramOffset;
  1192.     int run = 0;
  1193.  
  1194.     if( options.readCPULoad )
  1195.     {
  1196.       x = loadIndex-117-diagramOffset;
  1197.       run = 0;
  1198.  
  1199.       dc.SelectObject( &bBlue );
  1200.    
  1201.       while( run <= 348 )
  1202.       {
  1203.         while( x < 0 )
  1204.           x = 1200+x;
  1205.  
  1206.         int a=loadArr[x];
  1207.         if( run == 0 )
  1208.           dc.MoveTo( xbase+1+run+1, ybase+100-a );
  1209.  
  1210.         dc.LineTo( xbase+1+run+1, ybase+100-a );
  1211.  
  1212.         x++;
  1213.         run += 3;
  1214.  
  1215.         if( x >= 1200 )
  1216.           x = 0;
  1217.       }
  1218.     }
  1219.  
  1220.     if( options.readCPUSpeed )
  1221.     {
  1222.       x = loadIndex-117-diagramOffset;
  1223.       run = 0;
  1224.  
  1225.       dc.SelectObject( &bGreen );
  1226.    
  1227.       while( run <= 348 )
  1228.       {
  1229.         while( x < 0 )
  1230.           x = 1200+x;
  1231.  
  1232.         int a=speedArr[x] * options.freqScaling;
  1233.         if( a > 100 )
  1234.           a = 100;
  1235.  
  1236.         if( run == 0 )
  1237.           dc.MoveTo( xbase+1+run+1, ybase+100-a );
  1238.  
  1239.         dc.LineTo( xbase+1+run+1, ybase+100-a );
  1240.  
  1241.         x++;
  1242.         run += 3;
  1243.  
  1244.         if( x >= 1200 )
  1245.           x = 0;
  1246.       }
  1247.     }
  1248.   }
  1249.  
  1250.   dc.SetBkMode( TRANSPARENT );
  1251.   dc.TextOut( xbase+352, ybase-5, "100" );
  1252.   dc.TextOut( xbase+352, ybase+40, "50" );
  1253.   dc.TextOut( xbase+352, ybase+90, "0" );
  1254.  
  1255.     dc.SetTextColor( RGB(0,255,0) );
  1256.   dc.TextOut( xbase+71, legendLine, "CPU speed" );
  1257.     dc.SetTextColor( RGB(0,0,255) );
  1258.   dc.TextOut( xbase+221, legendLine, "CPU load" );
  1259. }
  1260.  
  1261. //**************************************************************
  1262. // retrieve string for a particular windows error code
  1263. //**************************************************************
  1264. char* CSpeedswitchXPDlg::getWinErr( DWORD errcode )
  1265. {
  1266.   static char msg[256];
  1267.   
  1268.   FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
  1269.                  NULL,
  1270.                  errcode,
  1271.                  MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  1272.                  msg,
  1273.                  255,
  1274.                  NULL );
  1275.  
  1276.   char* t = msg + strlen(msg) - 1;
  1277.  
  1278.   while( t > msg )
  1279.   {
  1280.     if( isspace(*t) )
  1281.       t--;
  1282.     else
  1283.       break;
  1284.   }
  1285.  
  1286.   t[1]='\0';
  1287.   return msg;  
  1288. }
  1289.  
  1290. //**************************************************************
  1291. // handler for 'Detect max speed' button
  1292. //**************************************************************
  1293. void CSpeedswitchXPDlg::OnBnClickedButton2()
  1294. {
  1295.   AfxGetApp()->DoWaitCursor(1);
  1296.  
  1297.   int aktuell = options.ac ? acThrottle : dcThrottle;
  1298.  
  1299.   // switch to max performance:
  1300.   setState( options.ac, PO_THROTTLE_NONE );
  1301.  
  1302.   // wait for 2 seconds to make sure switching took place (this causes 100% CPU load)
  1303.   time_t x = time(NULL) + 2;
  1304.   while( time(NULL) < x )     
  1305.     ;
  1306.  
  1307.   int f = cpuSpeedHT();
  1308.   options.maxSpeed = f;
  1309.  
  1310.   char buf[16];
  1311.   wsprintf( buf, "~%d", options.maxSpeed );
  1312.   m_szMaxCPUSpeed = buf;
  1313.  
  1314.   setRegKeys();
  1315.  
  1316.   // switch back to original policy:
  1317.   setState( options.ac, aktuell );
  1318.  
  1319.   UpdateData( FALSE );
  1320.   AfxGetApp()->DoWaitCursor(-1);
  1321. }
  1322.  
  1323. //**************************************************************
  1324. // control battery icon display
  1325. //**************************************************************
  1326. void CSpeedswitchXPDlg::batteryDisplay( SYSTEM_POWER_STATUS* sps )
  1327. {
  1328.   if( sps == NULL )
  1329.   {
  1330.     if( !GetSystemPowerStatus(&pwrStatus) )
  1331.     {  
  1332.       options.showBattery = FALSE;
  1333.       setRegKeys();
  1334.       MessageBox( "Can't detect current power status", "SpeedswitchXP error", MB_ICONEXCLAMATION|MB_OK );
  1335.       return;
  1336.     }
  1337.  
  1338.     sps = &pwrStatus;
  1339.   }
  1340.  
  1341.   log( "AC-Status:%d batteryIcon:%d chargeIcon:%d method:%d "
  1342.        "chargeIndicator:%d batteryFlag:%d",
  1343.        sps->ACLineStatus, batteryIconActive, batteryIconCharge, options.batteryMethod,
  1344.        options.chargeIndicator, sps->BatteryFlag );
  1345.  
  1346.   if( sps->ACLineStatus == 0 )    // running on battery
  1347.   {
  1348.     if( !batteryIconActive )
  1349.       showBatteryIcon( NIM_ADD, iTrayBattery, sps );
  1350.     else
  1351.       showBatteryIcon( NIM_MODIFY, iTrayBattery, sps );
  1352.   }
  1353.   else                            // running on AC
  1354.   {
  1355.     if( options.batteryMethod == 0 )    // show only on DC
  1356.     {
  1357.       if( !options.chargeIndicator && batteryIconActive )
  1358.         removeBatteryIcon();
  1359.       else if( options.chargeIndicator )    // show charging status
  1360.       {
  1361.         if( sps->BatteryFlag & 8 )   // it is charging
  1362.         {  
  1363.           if( !batteryIconActive )
  1364.             showBatteryIcon( NIM_ADD, iBattCharge, sps );
  1365.           else 
  1366.             showBatteryIcon( NIM_MODIFY, iBattCharge, sps );
  1367.         }
  1368.         else                          // not charging
  1369.         {
  1370.           if( batteryIconActive )
  1371.             removeBatteryIcon();
  1372.         }
  1373.       }
  1374.     }
  1375.     else        // show always
  1376.     {
  1377.       if( !options.chargeIndicator )      // no charge showing
  1378.       {
  1379.         if( !batteryIconActive )
  1380.           showBatteryIcon( NIM_ADD, iTrayBattery, sps );
  1381.         else
  1382.           showBatteryIcon( NIM_MODIFY, iTrayBattery, sps );
  1383.       }
  1384.       else        // show charging status
  1385.       {
  1386.         if( sps->BatteryFlag & 8 )     // now charging
  1387.         {
  1388.           if( !batteryIconActive )
  1389.             showBatteryIcon( NIM_ADD, iBattCharge, sps );
  1390.           else
  1391.             showBatteryIcon( NIM_MODIFY, iBattCharge, sps );
  1392.         }
  1393.         else                            // not charging now
  1394.         {
  1395.           if( !batteryIconActive )
  1396.             showBatteryIcon( NIM_ADD, iTrayBattery, sps );
  1397.           else
  1398.             showBatteryIcon( NIM_MODIFY, iTrayBattery, sps );
  1399.         }
  1400.       }
  1401.     }
  1402.   }
  1403. }
  1404.  
  1405. //**************************************************************
  1406. // remove battery icon from tray area
  1407. //**************************************************************
  1408. void CSpeedswitchXPDlg::removeBatteryIcon()
  1409. {
  1410.   NOTIFYICONDATA nid;
  1411.   nid.cbSize = sizeof( NOTIFYICONDATA );
  1412.   nid.hWnd = m_hWnd;
  1413.   nid.uID = 701;
  1414.   nid.uCallbackMessage = WM_ICONNOTIFY;
  1415.   nid.hIcon = modBatteryIcon;
  1416.   Shell_NotifyIcon( NIM_DELETE, &nid );
  1417.   DestroyIcon( modBatteryIcon );
  1418.   batteryIconActive = FALSE;
  1419.   batteryIconCharge = FALSE;
  1420.   batteryValue = -2;
  1421. }
  1422.  
  1423. // 10 digits (0-9) α 16 bytes: 2 bytes per row (16 pixels) * 8 rows = 16x8 matrix
  1424. // + 2 digits for a compressed '100' (special case for CPU usage)
  1425. // + 1 digit for '-' as unreported fan speed digits
  1426. static unsigned char digits[17][16] = 
  1427. {
  1428.   // digits 0-9:
  1429.   { 0xf0,0x0f,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xf0,0x0f },
  1430.   { 0xfc,0xff,0xf0,0xff,0xc0,0xff,0xfc,0xff,0xfc,0xff,0xfc,0xff,0xfc,0xff,0xc0,0x0f },
  1431.   { 0xf0,0x0f,0xcf,0xf3,0xff,0xf3,0xff,0xcf,0xff,0x3f,0xfc,0xff,0xf3,0xff,0xc0,0x03 },
  1432.   { 0xf0,0x0f,0xcf,0xf3,0xff,0xf3,0xff,0x0f,0xff,0xf3,0xff,0xf3,0xcf,0xf3,0xf0,0x0f },
  1433.   { 0xff,0x3f,0xfc,0x3f,0xf3,0x3f,0xcf,0x3f,0x00,0x03,0xff,0x3f,0xff,0x3f,0xf0,0x03 },
  1434.   { 0xc0,0x03,0xcf,0xff,0xcf,0xff,0xc0,0x0f,0xff,0xf3,0xff,0xf3,0xcf,0xf3,0xf0,0x0f },
  1435.   { 0xfc,0x0f,0xf3,0xff,0xcf,0xff,0xc0,0x0f,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xf0,0x0f },
  1436.   { 0xc0,0x0f,0xcf,0xcf,0xff,0x3f,0xff,0x3f,0xfc,0xff,0xfc,0xff,0xf3,0xff,0xf3,0xff },
  1437.   { 0xf0,0x0f,0xcf,0xf3,0xcf,0xf3,0xf0,0x0f,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xf0,0x0f },
  1438.   { 0xf0,0x0f,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xf0,0x03,0xff,0xf3,0xff,0xcf,0xf0,0x3f },
  1439.  
  1440.   // 2 additional digits for '100':
  1441.   { 0xf3,0xf0,0xc3,0xcf,0x03,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0x00,0x30 },
  1442.   { 0x3f,0x03,0xcc,0xfc,0xcc,0xfc,0xcc,0xfc,0xcc,0xfc,0xcc,0xfc,0xcc,0xfc,0x3f,0x03 },
  1443.  
  1444.   // 1 additional character for '-':
  1445.   { 0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0x03,0xc0,0x03,0xff,0xff,0xff,0xff,0xff,0xff },
  1446.  
  1447.   // 4 additional characters for 'Sl' and 'Hi':
  1448.   { 0xf0,0x03,0xcf,0xff,0xcf,0xff,0xcf,0xff,0xf0,0x0f,0xff,0xf3,0xff,0xf3,0xc0,0x0f },
  1449.   { 0xcf,0xff,0xcf,0xff,0xcf,0xff,0xcf,0xff,0xcf,0xff,0xcf,0xff,0xcf,0xff,0xf0,0x0f },
  1450.   { 0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xc0,0x03,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3 },
  1451.   { 0xff,0xff,0xff,0xff,0xfc,0xff,0xff,0xff,0xfc,0xff,0xfc,0xff,0xfc,0xff,0xf0,0x3f }
  1452. };
  1453.  
  1454. // 10 digits (0-9) α 8 bytes: 1 byte per row (8 pixels) * 8 rows = 8x8 matrix
  1455. static unsigned char digits2[10][8] = 
  1456. {
  1457.   { 0x3c,0x42,0x42,0x42,0x42,0x42,0x42,0x3c },
  1458.   { 0x10,0x30,0x70,0x10,0x10,0x10,0x10,0x7c },
  1459.   { 0x3c,0x42,0x02,0x04,0x08,0x10,0x20,0x7e },
  1460.   { 0x3c,0x42,0x02,0x0c,0x02,0x02,0x42,0x3c },
  1461.   { 0x0c,0x1c,0x2c,0x4c,0xfe,0x0c,0x0c,0x3e },
  1462.   { 0x7e,0x40,0x40,0x7c,0x02,0x02,0x42,0x3c },
  1463.   { 0x1c,0x20,0x40,0x7c,0x42,0x42,0x42,0x3c },
  1464.   { 0x7c,0x44,0x08,0x08,0x10,0x10,0x20,0x20 },
  1465.   { 0x3c,0x42,0x42,0x3c,0x42,0x42,0x42,0x3c },
  1466.   { 0x3c,0x42,0x42,0x42,0x3e,0x02,0x04,0x38 }
  1467. };
  1468.  
  1469. //**************************************************************
  1470. // create battery icon and show/modify it
  1471. //**************************************************************
  1472. void CSpeedswitchXPDlg::showBatteryIcon( int msg, HICON icon, SYSTEM_POWER_STATUS* sps )
  1473. {
  1474.   int newval;
  1475.   int chargeLeft;
  1476.   int timeLeft;
  1477.   BOOL chargeIconNow = FALSE;
  1478.  
  1479.   chargeLeft = sps->BatteryLifePercent;
  1480.   if( chargeLeft<0 || chargeLeft>100 )
  1481.     chargeLeft = 999;
  1482.  
  1483.   if( sps->ACLineStatus == 0 )    // running on battery
  1484.   {
  1485.     timeLeft = sps->BatteryLifeTime;
  1486.     if( timeLeft < 0 )
  1487.       timeLeft = 999;
  1488.     else
  1489.       timeLeft /= 60;
  1490.   }
  1491.   else                            // on AC
  1492.     timeLeft = 999;
  1493.  
  1494.   if( icon == iBattCharge )
  1495.     chargeIconNow = TRUE;
  1496.  
  1497.   if( options.batteryIndicator==0 || chargeIconNow )     // show percentage
  1498.     newval = (chargeLeft==999 ? -3 : chargeLeft);
  1499.   else                                    // show time left
  1500.     newval = (timeLeft==999 ? -3 : timeLeft);
  1501.  
  1502.   if( msg==NIM_MODIFY && newval==batteryValue && batteryIconCharge==chargeIconNow )
  1503.   {
  1504.     NOTIFYICONDATA nid;
  1505.     static char tp[128];
  1506.  
  1507.     nid.cbSize = sizeof( NOTIFYICONDATA );
  1508.     nid.hWnd = m_hWnd;
  1509.     nid.uID = 701;
  1510.     nid.uFlags = NIF_TIP;
  1511.  
  1512.     char temp[32];
  1513.     itoa( chargeLeft, temp, 10 );
  1514.     strcat( temp, "%" );
  1515.  
  1516.     wsprintf( tp, "Remaining charge:%s",
  1517.               chargeLeft==999 ? "unknown" : temp );
  1518.  
  1519.     if( timeLeft != 999 )
  1520.       wsprintf( &tp[strlen(tp)], "\nRemaining time:%d min", timeLeft );
  1521.  
  1522.     lstrcpy( nid.szTip, tp );
  1523.  
  1524.     Shell_NotifyIcon( msg, &nid );
  1525.     return;
  1526.   }
  1527.  
  1528.   if( msg == NIM_MODIFY )
  1529.     DestroyIcon( modBatteryIcon );
  1530.  
  1531.   // create new icon:
  1532.   ICONINFO iconinfo;
  1533.   ICONINFO d2;
  1534.  
  1535.   GetIconInfo( icon, &d2 );
  1536.  
  1537.   iconinfo.hbmMask = d2.hbmMask;
  1538.   iconinfo.hbmColor = d2.hbmColor;
  1539.  
  1540.   CBitmap* mask = CBitmap::FromHandle( iconinfo.hbmMask );
  1541.   BITMAP maskMap;
  1542.   mask->GetBitmap( &maskMap );
  1543.   int size = maskMap.bmHeight * maskMap.bmWidthBytes;   // 128 Bytes (32x32 monochrom)
  1544.   mask->GetBitmapBits( size, bitmap );
  1545.  
  1546.   int num0 = (newval/100)%10;   // first decimal digit
  1547.   int num1 = (newval/10)%10;    // second decimal digit
  1548.   int num2 = newval%10;         // third decimal digit
  1549.   int j=0;
  1550.  
  1551.   if( newval == -3 )     // special value for deactivated ("--")
  1552.   {
  1553.     num0 = 0;
  1554.     num1 = 12;
  1555.     num2 = 12;
  1556.   }
  1557.  
  1558.   if( num0 != 0 )   // for displaying fahrenheit values
  1559.   {
  1560.     for( int i=16; i<31; i+=2 )
  1561.     {
  1562.       for( int m=0; m<2; m++ )   // each loop = 1 icon row
  1563.       {
  1564.         bitmap[(i+m)*4] = 0xff ^ (digits2[num0][j]>>2);
  1565.         bitmap[(i+m)*4+1] = 0xff ^ (digits2[num0][j]<<6 | digits2[num1][j]>>4);
  1566.         bitmap[(i+m)*4+2] = 0xff ^ (digits2[num1][j]<<4 | digits2[num2][j]>>6); 
  1567.         bitmap[(i+m)*4+3] = 0xff ^ (digits2[num2][j]<<2);
  1568.       }
  1569.  
  1570.       j++;   // advance in digits2 array
  1571.     }
  1572.   }
  1573.   else              // standard values (celsius)
  1574.   {
  1575.     for( int i=16; i<=31; i+=2 )    // fill icon region
  1576.     {
  1577.       for( int m=0; m<2; m++ )   // each loop = 1 icon row
  1578.       {
  1579.         bitmap[(i+m)*4] = digits[num1][j];
  1580.         bitmap[(i+m)*4+1] = digits[num1][j+1];
  1581.         bitmap[(i+m)*4+2] = digits[num2][j];
  1582.         bitmap[(i+m)*4+3] = digits[num2][j+1];
  1583.       }
  1584.  
  1585.       j+=2;   // advance in digits array
  1586.     }
  1587.   }
  1588.  
  1589.   maskMap.bmBits = bitmap;
  1590.  
  1591.   CBitmap newMask;
  1592.   newMask.CreateBitmapIndirect( &maskMap );
  1593.  
  1594.   iconinfo.hbmMask = (HBITMAP)newMask.m_hObject;
  1595.   iconinfo.fIcon = TRUE;
  1596.  
  1597.   modBatteryIcon = ::CreateIconIndirect( &iconinfo );    
  1598.  
  1599.   NOTIFYICONDATA nid;
  1600.   static char tp[128];
  1601.  
  1602.   nid.cbSize = sizeof( NOTIFYICONDATA );
  1603.   nid.hWnd = m_hWnd;
  1604.   nid.uID = 701;
  1605.   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  1606.   nid.uCallbackMessage = WM_ICONNOTIFY;
  1607.  
  1608.   char temp[32];
  1609.   itoa( chargeLeft, temp, 10 );
  1610.   strcat( temp, "%" );
  1611.  
  1612.   wsprintf( tp, "Remaining charge:%s",
  1613.             chargeLeft==999 ? "unknown" : temp );
  1614.  
  1615.   if( timeLeft != 999 )
  1616.     wsprintf( &tp[strlen(tp)], "\nRemaining time:%d min", timeLeft );
  1617.  
  1618.   lstrcpy( nid.szTip, tp );
  1619.   nid.hIcon = modBatteryIcon;
  1620.  
  1621.   Shell_NotifyIcon( msg, &nid );
  1622.  
  1623.   batteryIconActive = TRUE;
  1624.   batteryIconCharge = chargeIconNow;
  1625.   batteryValue = newval;
  1626. }
  1627.  
  1628. //**************************************************************
  1629. // fill combo boxes on main window with current values
  1630. //**************************************************************
  1631. void CSpeedswitchXPDlg::initPowerBoxes()
  1632. {
  1633.   m_cDiskAC.SetCurSel( findDiskIndex(internalPolicy.user.SpindownTimeoutAc) );
  1634.   m_cDiskDC.SetCurSel( findDiskIndex(internalPolicy.user.SpindownTimeoutDc) );
  1635.   m_cDisplayAC.SetCurSel( findDefaultIndex(internalPolicy.user.VideoTimeoutAc) );
  1636.   m_cDisplayDC.SetCurSel( findDefaultIndex(internalPolicy.user.VideoTimeoutDc) );
  1637.  
  1638.   log( "ACAction: %d", internalPolicy.user.IdleAc.Action );
  1639.   log( "ACIdletimeout:%d min", internalPolicy.user.IdleTimeoutAc/60 );
  1640.   log( "ACHibtimeout:%d min", internalPolicy.mach.DozeS4TimeoutAc );
  1641.  
  1642.   if( internalPolicy.user.IdleAc.Action == PowerActionHibernate )
  1643.   {
  1644.     m_cStandbyAC.SetCurSel( 15 );
  1645.     maxHibIndexAC = fillHibernationTimes( &m_cHibernationAC, hibernationTimesAC, 15 );
  1646.     m_cHibernationAC.SetCurSel( 
  1647.                       findHibernationIndex(hibernationTimesAC,
  1648.                                            internalPolicy.user.IdleTimeoutAc,
  1649.                                            maxHibIndexAC) );
  1650.   }
  1651.   else
  1652.   {
  1653.     int sIdxAC = findDefaultIndex( internalPolicy.user.IdleTimeoutAc );
  1654.     m_cStandbyAC.SetCurSel( sIdxAC );
  1655.     maxHibIndexAC = fillHibernationTimes( &m_cHibernationAC, hibernationTimesAC, sIdxAC );
  1656.     int timeout = internalPolicy.mach.DozeS4TimeoutAc;
  1657.     if( timeout > 0 )
  1658.       timeout += internalPolicy.user.IdleTimeoutAc;
  1659.  
  1660.     m_cHibernationAC.SetCurSel( 
  1661.                       findHibernationIndex(hibernationTimesAC,
  1662.                                            timeout,
  1663.                                            maxHibIndexAC) );
  1664.   }
  1665.  
  1666.   log( "DCAction: %d", internalPolicy.user.IdleDc.Action );
  1667.   log( "DCIdletimeout:%d min", internalPolicy.user.IdleTimeoutDc/60 );
  1668.   log( "DCHibtimeout:%d min", internalPolicy.mach.DozeS4TimeoutDc/60 );
  1669.  
  1670.   if( internalPolicy.user.IdleDc.Action == PowerActionHibernate )
  1671.   {
  1672.     m_cStandbyDC.SetCurSel( 15 );
  1673.     maxHibIndexDC = fillHibernationTimes( &m_cHibernationDC, hibernationTimesDC, 15 );
  1674.     m_cHibernationDC.SetCurSel( 
  1675.                       findHibernationIndex(hibernationTimesDC,
  1676.                                            internalPolicy.user.IdleTimeoutDc,
  1677.                                            maxHibIndexDC) );
  1678.   }
  1679.   else
  1680.   {
  1681.     int sIdxDC = findDefaultIndex( internalPolicy.user.IdleTimeoutDc );
  1682.     m_cStandbyDC.SetCurSel( sIdxDC );
  1683.     maxHibIndexDC = fillHibernationTimes( &m_cHibernationDC, hibernationTimesDC, sIdxDC );
  1684.  
  1685.     int timeout = internalPolicy.mach.DozeS4TimeoutDc;
  1686.     if( timeout > 0 )
  1687.       timeout += internalPolicy.user.IdleTimeoutDc;
  1688.  
  1689.     m_cHibernationDC.SetCurSel( 
  1690.                       findHibernationIndex(hibernationTimesDC,
  1691.                                            timeout,
  1692.                                            maxHibIndexDC) );
  1693.  
  1694.   }
  1695. }
  1696.  
  1697. int CSpeedswitchXPDlg::findDefaultIndex( int val )
  1698. {
  1699.   for( int i=0; i<16; i++ )
  1700.     if( defaultTimes[i] == val )
  1701.       return i;
  1702.  
  1703.   return -1;    // return -1 as default if not found
  1704. }
  1705.  
  1706. int CSpeedswitchXPDlg::findDiskIndex( int val )
  1707. {
  1708.   for( int i=0; i<14; i++ )
  1709.     if( diskTimes[i] == val )
  1710.       return i;
  1711.  
  1712.   return -1;    // return -1 as default if not found
  1713. }
  1714.  
  1715. int CSpeedswitchXPDlg::findHibernationIndex( int* hibernation, int val, int maxIndex )
  1716. {
  1717.   for( int i=0; i<maxIndex; i++ )
  1718.     if( hibernation[i] == val )
  1719.       return i;
  1720.  
  1721.   return -1;    // return -1 as default if not found
  1722. }
  1723.  
  1724. int CSpeedswitchXPDlg::fillHibernationTimes( CComboBox* box, int* hibernation, int idx )
  1725. {
  1726.   int val;
  1727.   char* str;
  1728.   int j=0;
  1729.  
  1730.   if( idx == 15 )
  1731.     idx = -1;   // start at 0
  1732.  
  1733.   box->ResetContent();
  1734.  
  1735.   for( int i=idx+1; i<17; i++ )
  1736.   {
  1737.     switch( i )
  1738.     {
  1739.       case 0: val = 60;
  1740.               str = "After 1 min";
  1741.               break;
  1742.  
  1743.       case 1: val = 120;
  1744.               str = "After 2 min";
  1745.               break;
  1746.  
  1747.       case 2: val = 180;
  1748.               str = "After 3 min";
  1749.               break;
  1750.  
  1751.       case 3: val = 300;
  1752.               str = "After 5 min";
  1753.               break;
  1754.  
  1755.       case 4: val = 600;
  1756.               str = "After 10 min";
  1757.               break;
  1758.  
  1759.       case 5: val = 900;
  1760.               str = "After 15 min";
  1761.               break;
  1762.  
  1763.       case 6: val = 1200;
  1764.               str = "After 20 min";
  1765.               break;
  1766.  
  1767.       case 7: val = 1500;
  1768.               str = "After 25 min";
  1769.               break;
  1770.  
  1771.       case 8: val = 1800;
  1772.               str = "After 30 min";
  1773.               break;
  1774.  
  1775.       case 9: val = 2700;
  1776.               str = "After 45 min";
  1777.               break;
  1778.  
  1779.       case 10:val = 3600;
  1780.               str = "After 1 hr";
  1781.               break;
  1782.  
  1783.       case 11:val = 3600*2;
  1784.               str = "After 2 hrs";
  1785.               break;
  1786.  
  1787.       case 12:val = 3600*3;
  1788.               str = "After 3 hrs";
  1789.               break;
  1790.  
  1791.       case 13:val = 3600*4;
  1792.               str = "After 4 hrs";
  1793.               break;
  1794.  
  1795.       case 14:val = 3600*5;
  1796.               str = "After 5 hrs";
  1797.               break;
  1798.  
  1799.       case 15:val = 3600*6;
  1800.               str = "After 6 hrs";
  1801.               break;
  1802.  
  1803.       case 16:val = 0;
  1804.               str = "Never";
  1805.               break;
  1806.     }
  1807.  
  1808.     hibernation[j++] = val;
  1809.     box->AddString( str );
  1810.   }
  1811.  
  1812.   return j;
  1813. }
  1814.  
  1815. //**************************************************************
  1816. // handlers for selecting values from power combo boxes on main 
  1817. // window
  1818. //**************************************************************
  1819. void CSpeedswitchXPDlg::OnCbnSelchangeDisplayAC()
  1820. {
  1821.   internalPolicy.user.VideoTimeoutAc = defaultTimes[m_cDisplayAC.GetCurSel()];
  1822.   writePolicies( true, false );
  1823. }
  1824.  
  1825. void CSpeedswitchXPDlg::OnCbnSelchangeDisplayDC()
  1826. {
  1827.   internalPolicy.user.VideoTimeoutDc = defaultTimes[m_cDisplayDC.GetCurSel()];
  1828.   writePolicies( true, false );
  1829. }
  1830.  
  1831. void CSpeedswitchXPDlg::OnCbnSelchangeDiskAC()
  1832. {
  1833.   internalPolicy.user.SpindownTimeoutAc = diskTimes[m_cDiskAC.GetCurSel()];
  1834.   writePolicies( true, false );
  1835. }
  1836.  
  1837. void CSpeedswitchXPDlg::OnCbnSelchangeDiskDC()
  1838. {
  1839.   internalPolicy.user.SpindownTimeoutDc = diskTimes[m_cDiskDC.GetCurSel()];
  1840.   writePolicies( true, false );
  1841. }
  1842.  
  1843. void CSpeedswitchXPDlg::OnCbnSelchangeHibAC()
  1844. {
  1845.   log( "------------------------------" );
  1846.   log( "Start of 'OnCbnSelchangeHibAC'" );
  1847.  
  1848.   int n = hibernationTimesAC[m_cHibernationAC.GetCurSel()];
  1849.  
  1850.   log( "new ACHib val: %d min", n/60 );
  1851.   log( "current ACIdletimeout: %d min", internalPolicy.user.IdleTimeoutAc/60 );
  1852.   log( "GUI AC Standby selection: %d min", defaultTimes[m_cStandbyAC.GetCurSel()]/60 );
  1853.  
  1854.   if( n!=0 && internalPolicy.user.IdleAc.Action!=PowerActionHibernate )
  1855.     n -= internalPolicy.user.IdleTimeoutAc;
  1856.  
  1857.   if( defaultTimes[m_cStandbyAC.GetCurSel()] == 0 )
  1858.   {
  1859.     internalPolicy.user.IdleTimeoutAc = n;
  1860.     internalPolicy.mach.DozeS4TimeoutAc = 0;
  1861.     internalPolicy.user.IdleAc.Action = PowerActionHibernate;
  1862.   }
  1863.   else
  1864.     internalPolicy.mach.DozeS4TimeoutAc = n;
  1865.  
  1866.   log( "new ACIdletimeout: %d min", internalPolicy.user.IdleTimeoutAc/60 );
  1867.   log( "new ACHibtimeout: %d min", internalPolicy.mach.DozeS4TimeoutAc/60 );
  1868.  
  1869.   writePolicies( true, false );
  1870.   log( "End of 'OnCbnSelchangeHibAC'" );
  1871. }
  1872.  
  1873. void CSpeedswitchXPDlg::OnCbnSelchangeHibDC()
  1874. {
  1875.   log( "------------------------------" );
  1876.   log( "Start of 'OnCbnSelchangeHibDC'" );
  1877.  
  1878.   int n = hibernationTimesDC[m_cHibernationDC.GetCurSel()];
  1879.  
  1880.   log( "new DCHib val: %d min", n/60 );
  1881.   log( "current DCIdletimeout: %d min", internalPolicy.user.IdleTimeoutDc/60 );
  1882.   log( "GUI DC Standby selection: %d min", defaultTimes[m_cStandbyDC.GetCurSel()]/60 );
  1883.  
  1884.   if( n!=0 && internalPolicy.user.IdleDc.Action!=PowerActionHibernate )
  1885.     n -= internalPolicy.user.IdleTimeoutDc;
  1886.  
  1887.   if( defaultTimes[m_cStandbyDC.GetCurSel()] == 0 )
  1888.   {
  1889.     internalPolicy.user.IdleTimeoutDc = n;
  1890.     internalPolicy.mach.DozeS4TimeoutDc = 0;
  1891.     internalPolicy.user.IdleDc.Action = PowerActionHibernate;
  1892.   }
  1893.   else
  1894.     internalPolicy.mach.DozeS4TimeoutDc = n;
  1895.  
  1896.   log( "new DCIdletimeout: %d min", internalPolicy.user.IdleTimeoutDc/60 );
  1897.   log( "new DCHibtimeout: %d min", internalPolicy.mach.DozeS4TimeoutDc/60 );
  1898.  
  1899.   writePolicies( true, false );
  1900.   log( "End of 'OnCbnSelchangeHibDC'" );
  1901. }
  1902.  
  1903. void CSpeedswitchXPDlg::OnCbnSelchangeStandbyAC()
  1904. {
  1905.   int last;
  1906.  
  1907.   if( internalPolicy.user.IdleAc.Action == PowerActionHibernate )
  1908.     last = internalPolicy.user.IdleTimeoutAc;
  1909.   else
  1910.   {
  1911.     last = internalPolicy.mach.DozeS4TimeoutAc;
  1912.     if( last != 0 )
  1913.       last += internalPolicy.user.IdleTimeoutAc;
  1914.   }
  1915.  
  1916.   int n = defaultTimes[m_cStandbyAC.GetCurSel()];
  1917.  
  1918.   internalPolicy.user.IdleTimeoutAc = n;
  1919.  
  1920.   maxHibIndexAC = fillHibernationTimes( &m_cHibernationAC, hibernationTimesAC, m_cStandbyAC.GetCurSel() );
  1921.   log( "Searching for %d (%d) (max:%d)", last, last/60, maxHibIndexAC );
  1922.   int x = findHibernationIndex( hibernationTimesAC, last, maxHibIndexAC );
  1923.   log( "Found:%d", x );
  1924.   if( x == -1 )
  1925.     x = 0;
  1926.  
  1927.   n = hibernationTimesAC[x];
  1928.   if( n != 0 )
  1929.     n -= internalPolicy.user.IdleTimeoutAc;
  1930.  
  1931.   internalPolicy.mach.DozeS4TimeoutAc = n;
  1932.  
  1933.   m_cHibernationAC.SetCurSel( x );
  1934.  
  1935.   if( internalPolicy.user.IdleTimeoutAc==0 && internalPolicy.mach.DozeS4TimeoutAc!=0 )
  1936.   {
  1937.     internalPolicy.user.IdleTimeoutAc = internalPolicy.mach.DozeS4TimeoutAc;
  1938.     internalPolicy.mach.DozeS4TimeoutAc = 0;
  1939.     internalPolicy.user.IdleAc.Action = PowerActionHibernate;
  1940.   }
  1941.   else
  1942.     internalPolicy.user.IdleAc.Action = PowerActionSleep;
  1943.  
  1944.   writePolicies( true, false );
  1945. }
  1946.  
  1947. void CSpeedswitchXPDlg::OnCbnSelchangeStandbyDC()
  1948. {
  1949.   int last;
  1950.  
  1951.   if( internalPolicy.user.IdleDc.Action == PowerActionHibernate )
  1952.     last = internalPolicy.user.IdleTimeoutDc;
  1953.   else
  1954.   {
  1955.     last = internalPolicy.mach.DozeS4TimeoutDc;
  1956.     if( last != 0 )
  1957.       last += internalPolicy.user.IdleTimeoutDc;
  1958.   }
  1959.  
  1960.   int n = defaultTimes[m_cStandbyDC.GetCurSel()];
  1961.  
  1962.   internalPolicy.user.IdleTimeoutDc = n;
  1963.  
  1964.   maxHibIndexDC = fillHibernationTimes( &m_cHibernationDC, hibernationTimesDC, m_cStandbyDC.GetCurSel() );
  1965.   int x = findHibernationIndex( hibernationTimesDC, last, maxHibIndexDC );
  1966.   if( x == -1 )
  1967.     x = 0;
  1968.  
  1969.   n = hibernationTimesDC[x];
  1970.   if( n != 0 )
  1971.     n -= internalPolicy.user.IdleTimeoutDc;
  1972.  
  1973.   internalPolicy.mach.DozeS4TimeoutDc = n;
  1974.  
  1975.   m_cHibernationDC.SetCurSel( x );
  1976.  
  1977.   if( internalPolicy.user.IdleTimeoutDc==0 && internalPolicy.mach.DozeS4TimeoutDc!=0 )
  1978.   {
  1979.     internalPolicy.user.IdleTimeoutDc = internalPolicy.mach.DozeS4TimeoutDc;
  1980.     internalPolicy.mach.DozeS4TimeoutDc = 0;
  1981.     internalPolicy.user.IdleDc.Action = PowerActionHibernate;
  1982.   }
  1983.   else
  1984.     internalPolicy.user.IdleDc.Action = PowerActionSleep;
  1985.  
  1986.   writePolicies( true, false );
  1987. }
  1988.  
  1989. //**************************************************************
  1990. // handler for 'System Info' button
  1991. //**************************************************************
  1992. void CSpeedswitchXPDlg::OnBnClickedCPUData()
  1993. {
  1994.   CSystemInfo si;
  1995.   si.setVars();
  1996.   si.DoModal();
  1997. }
  1998.  
  1999. //**************************************************************
  2000. // handler for hidden 'Update' button (only used during development)
  2001. //**************************************************************
  2002. void CSpeedswitchXPDlg::OnBnClickedButton4()
  2003. {
  2004.   initPowerValues();
  2005. }
  2006.  
  2007. //**************************************************************
  2008. // read current power and CPU policy from registry
  2009. //**************************************************************
  2010. BOOL CSpeedswitchXPDlg::initPowerValues()
  2011. {
  2012.   static char msg[1024];   // fⁿr diverse Fehlertexte
  2013.  
  2014.   if( !CanUserWritePwrScheme() )
  2015.   {
  2016.     DWORD x = GetLastError();
  2017.     wsprintf( msg, "You don't have sufficient privileges to write a power scheme.\nCode:%d (%s)\n\n"
  2018.       "You need write access to the following registry keys:\n\n"
  2019.       "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\GlobalPowerPolicy\n"
  2020.       "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion\\Controls Folder\\PowerCfg\\PowerPolicies",
  2021.       x, getWinErr(x) );
  2022.     MessageBox( msg, "Error", MB_OK|MB_ICONEXCLAMATION );
  2023.     PostMessage( WM_CLOSE );
  2024.     return FALSE;
  2025.   }
  2026.  
  2027.   UINT origScheme;
  2028.   if( !GetActivePwrScheme(&origScheme) )
  2029.   {
  2030.     DWORD x = GetLastError();
  2031.     wsprintf( msg, "Error reading active power scheme no.\nCode:%d (%s)", x, getWinErr(x) );
  2032.     MessageBox( msg, "Error", MB_OK|MB_ICONEXCLAMATION );
  2033.     PostMessage( WM_CLOSE );
  2034.     return FALSE;
  2035.   }
  2036.  
  2037.   log( "Current power scheme no: %d", origScheme );
  2038.  
  2039.   options.originalScheme = origScheme;
  2040.   options.setRegKeys();
  2041.  
  2042.   int x = detectProfile();
  2043.  
  2044.   log( "profile detect rc: %d", x );
  2045.  
  2046.   if( x == -2 )
  2047.   {
  2048.     int y = createProfile();
  2049.     if( y != 0 )
  2050.     {
  2051.       DWORD x = GetLastError();
  2052.       wsprintf( msg, "Profile creation failed\nRC:%d; Code:%d (%s)", y, x, getWinErr(x) );
  2053.       MessageBox( msg, "Error", MB_OK|MB_ICONEXCLAMATION );
  2054.       PostMessage( WM_CLOSE );
  2055.       return FALSE;
  2056.     }
  2057.   }
  2058.   else if( x < 0 )
  2059.   {
  2060.     DWORD z = GetLastError();
  2061.     wsprintf( msg, "Profile detection failed\nRC:%d; Code:%d (%s)", x, z, getWinErr(z) );
  2062.     MessageBox( msg, "Error", MB_OK|MB_ICONEXCLAMATION );
  2063.     PostMessage( WM_CLOSE );
  2064.     return FALSE;
  2065.   }
  2066.  
  2067.   if( !GetSystemPowerStatus(&pwrStatus) )
  2068.     MessageBox( "Can't detect current power status", "SpeedswitchXP error", MB_ICONEXCLAMATION|MB_OK );
  2069.   else
  2070.     options.ac = (pwrStatus.ACLineStatus!=0);
  2071.  
  2072.   setCPUIcon( options.ac ? acThrottle : dcThrottle );
  2073.  
  2074.   if( options.showBattery )
  2075.     batteryDisplay( &pwrStatus );
  2076.  
  2077.   if( options.speedIcon || options.loadIcon )
  2078.     displayCPUDataIcon( NIM_ADD );
  2079.  
  2080.   m_iACState = acThrottle;
  2081.   m_iDCState = dcThrottle;
  2082.  
  2083.   if( options.autoStart )
  2084.     setAutoStartRegistry();
  2085.  
  2086.   ((CScrollBar*)GetDlgItem(IDC_SCROLLBAR1))->SetScrollRange( 0, 90, FALSE );
  2087.   ((CScrollBar*)GetDlgItem(IDC_SCROLLBAR1))->SetScrollPos( 90, TRUE );
  2088.  
  2089.   if( options.checkStatus || options.readCPUSpeed || options.readCPULoad || options.showBattery )
  2090.   {
  2091.     if( SetTimer(timerID,1000,NULL) == timerID )
  2092.       activeTimer = TRUE;
  2093.     else
  2094.     {
  2095.       MessageBox( "Can't create timer", "Error", MB_ICONERROR|MB_OK );
  2096.       PostMessage( WM_CLOSE );
  2097.       return FALSE;
  2098.     }
  2099.   }
  2100.  
  2101.   cpuUsageNT();     // let it run once to initialize itself (?)
  2102.  
  2103.   if( options.maxSpeed <= 0 )
  2104.     m_szMaxCPUSpeed = "???";
  2105.   else
  2106.   {
  2107.     char intbuf[16];
  2108.     wsprintf( intbuf, "~%d", options.maxSpeed );
  2109.     m_szMaxCPUSpeed = intbuf;
  2110.   }
  2111.  
  2112.   defaultTimes[0] = 60;                       // 1 min
  2113.   defaultTimes[1] = 120;                      // 2 min
  2114.   defaultTimes[2] = diskTimes[0] = 180;       // 3 min
  2115.   defaultTimes[3] = diskTimes[1] = 300;       // 5 min
  2116.   defaultTimes[4] = diskTimes[2] = 600;       // 10 min
  2117.   defaultTimes[5] = diskTimes[3] = 900;       // 15 min
  2118.   defaultTimes[6] = diskTimes[4] = 1200;      // 20 min
  2119.   defaultTimes[7] = diskTimes[5] = 1500;      // 25 min
  2120.   defaultTimes[8] = diskTimes[6] = 1800;      // 30 min
  2121.   defaultTimes[9] = diskTimes[7] = 2700;      // 45 min
  2122.   defaultTimes[10] = diskTimes[8] = 3600;     // 1 hr
  2123.   defaultTimes[11] = diskTimes[9] = 7200;     // 2 hrs
  2124.   defaultTimes[12] = diskTimes[10] = 10800;   // 3 hrs
  2125.   defaultTimes[13] = diskTimes[11] = 14400;   // 4 hrs
  2126.   defaultTimes[14] = diskTimes[12] = 18000;   // 5 hrs
  2127.   defaultTimes[15] = diskTimes[13] = 0;       // Never
  2128.  
  2129.   initPowerBoxes();
  2130.  
  2131.   return TRUE;
  2132. }
  2133.  
  2134. //**************************************************************
  2135. // show/modify the CPU data tray icon
  2136. //**************************************************************
  2137. void CSpeedswitchXPDlg::displayCPUDataIcon( int msg )
  2138. {
  2139.   NOTIFYICONDATA_CD nid;
  2140.   BOOL prev = FALSE;
  2141.   char tp[192];
  2142.   int val1, val2, val3;
  2143.  
  2144.   if( !options.speedIcon || !options.readCPUSpeed )
  2145.     val1 = -3;
  2146.   else
  2147.   {
  2148.     val1 = curSpeed/100;
  2149.  
  2150.     int t = curSpeed%100;
  2151.     if( t >= 90 )
  2152.       val1++;
  2153.   }
  2154.  
  2155.   val3 = val1;    // use val3 for tooltip only
  2156.   if( val3 != -3 )
  2157.     val3 = curSpeed;
  2158.  
  2159.   if( !options.loadIcon || !options.readCPULoad )
  2160.     val2 = -3;
  2161.   else
  2162.     val2 = curLoad;
  2163.  
  2164.   if( msg==NIM_MODIFY && cpuIconVal1==val1 && cpuIconVal2==val2 )
  2165.     return;
  2166.   
  2167.   nid.cbSize = sizeof( NOTIFYICONDATA );
  2168.   nid.hWnd = m_hWnd;
  2169.   nid.uID = 702;
  2170.   nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
  2171.   nid.uCallbackMessage = WM_ICONNOTIFY;
  2172.  
  2173.   *tp = '\0';
  2174.  
  2175.   if( val1 != -3 )
  2176.   {
  2177.     prev = true;
  2178.     wsprintf( tp, "CPU Speed: %d MHz", val3 );
  2179.   }
  2180.  
  2181.   if( val2 != -3 )
  2182.   {
  2183.     if( prev )
  2184.       strcat( tp, "\n" );
  2185.  
  2186.     prev = true;
  2187.     wsprintf( &tp[strlen(tp)], "CPU load: %d %%", val2 );
  2188.   } 
  2189.  
  2190.   lstrcpy( nid.szTip, tp );
  2191.  
  2192.   if( options.speedIcon && options.loadIcon )
  2193.   {
  2194.     createTempIcon( val1, 1, and );
  2195.     createTempIcon( val2, 2, and );
  2196.   }
  2197.   else if( options.speedIcon )
  2198.     createTempIcon( val1, 0, and );
  2199.   else
  2200.     createTempIcon( val2, 0, and );
  2201.  
  2202.   DestroyIcon( cpuDataIcon );    // we're not going to waste resources, so destroy old icon resource !
  2203.   cpuDataIcon = CreateIcon( AfxGetApp()->m_hInstance, 32, 32, 1, 1, and, xor );
  2204.  
  2205.   nid.hIcon = cpuDataIcon;
  2206.  
  2207.   if( msg==NIM_MODIFY && !cpuDataIconActive )
  2208.     msg = NIM_ADD;
  2209.  
  2210.   Shell_NotifyIcon( msg, (PNOTIFYICONDATA)&nid );
  2211.  
  2212.   cpuDataIconActive = TRUE;
  2213.   cpuIconVal1 = val1; 
  2214.   cpuIconVal2 = val2;
  2215. }
  2216.  
  2217. //**************************************************************
  2218. // remove the CPU data tray icon
  2219. //**************************************************************
  2220. void CSpeedswitchXPDlg::removeCPUDataIcon()
  2221. {
  2222.   NOTIFYICONDATA_CD nid;
  2223.   nid.cbSize = sizeof( NOTIFYICONDATA );
  2224.   nid.hWnd = m_hWnd;
  2225.   nid.uID = 702;
  2226.   nid.uCallbackMessage = WM_ICONNOTIFY;
  2227.   nid.hIcon = cpuDataIcon;
  2228.   Shell_NotifyIcon( NIM_DELETE, (PNOTIFYICONDATA)&nid );
  2229.   DestroyIcon( cpuDataIcon );
  2230.   cpuDataIconActive = FALSE;
  2231.   cpuIconVal1 = -2;
  2232.   cpuIconVal2 = -2;
  2233. }
  2234.  
  2235. //**************************************************************
  2236. // Fill icon bitmap area with a specific value
  2237. //
  2238. // temp: 0-200 = normal temperature or load (0-100)
  2239. //       -3    = display '--'
  2240. //**************************************************************
  2241. void CSpeedswitchXPDlg::createTempIcon( int temp, int where, BYTE* and )
  2242. {
  2243.   int num0 = (temp/100)%100;  // first decimal digit
  2244.   int num1 = (temp/10)%10;    // second decimal digit
  2245.   int num2 = temp%10;         // third decimal digit
  2246.   int j=0;
  2247.   int lstart, lend, yscaling;
  2248.  
  2249.   if( temp == 100 )     // 100 only at CPU usage (hopefully ;-) )
  2250.   {
  2251.     num0 = 0;
  2252.     num1 = 10;    // select the two additional digits
  2253.     num2 = 11;
  2254.   }
  2255.  
  2256.   if( temp == -3 )     // special value for deactivated ("--")
  2257.   {
  2258.     num0 = 0;
  2259.     num1 = 12;
  2260.     num2 = 12;
  2261.   }
  2262.  
  2263.   if( where == 0 )        // only one value in icon
  2264.   {
  2265.     lstart = 0;     // fill entire icon bitmap
  2266.     lend = 31;
  2267.     yscaling = 4;   // expand each digit to 32 lines
  2268.   }
  2269.   else if( where == 1 )   // fill upper part of two-value-icon
  2270.   {
  2271.     lstart = 0;     // fill only upper half of icon bitmap
  2272.     lend = 15;
  2273.     yscaling = 2;   // expand each digit to 16 lines
  2274.   }
  2275.   else if( where == 2 )   // fill lower part of two-value-icon
  2276.   {
  2277.     lstart = 16;     // fill only lower half of icon bitmap
  2278.     lend = 31;
  2279.     yscaling = 2;   // expand each digit to 16 lines
  2280.   }
  2281.  
  2282.   if( num0 != 0 )   // for displaying values above 99
  2283.   {
  2284.     for( int i=lstart; i<lend; i+=yscaling )
  2285.     {
  2286.       for( int m=0; m<yscaling; m++ )   // each loop = 1 icon row
  2287.       {
  2288.         and[(i+m)*4] = 0xff ^ (digits2[num0][j]>>2);
  2289.         and[(i+m)*4+1] = 0xff ^ (digits2[num0][j]<<6 | digits2[num1][j]>>4);
  2290.         and[(i+m)*4+2] = 0xff ^ (digits2[num1][j]<<4 | digits2[num2][j]>>6);
  2291.         and[(i+m)*4+3] = 0xff ^ (digits2[num2][j]<<2);
  2292.       }
  2293.  
  2294.       j++;   // advance in digits2 array
  2295.     }
  2296.   }
  2297.   else              // two digits
  2298.   {
  2299.     for( int i=lstart; i<=lend; i+=yscaling )    // fill icon region
  2300.     {
  2301.       for( int m=0; m<yscaling; m++ )   // each loop = 1 icon row
  2302.       {
  2303.         and[(i+m)*4] = digits[num1][j];
  2304.         and[(i+m)*4+1] = digits[num1][j+1];
  2305.         and[(i+m)*4+2] = digits[num2][j];
  2306.         and[(i+m)*4+3] = digits[num2][j+1];
  2307.       }
  2308.  
  2309.       j+=2;   // advance in digits array
  2310.     }
  2311.   }
  2312. }
  2313.