https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7fbc5f42302be64db4d3383060e3c14bcc1dfac6

commit 7fbc5f42302be64db4d3383060e3c14bcc1dfac6
Author: Shriraj Sawant <sr.offic...@hotmail.com>
AuthorDate: Mon Oct 16 17:11:10 2017 +0300

    [STOBJECT] Implement the hotplug and the power icons in the system tray
---
 dll/shellext/stobject/CMakeLists.txt               |   4 +
 dll/shellext/stobject/csystray.cpp                 |  53 ++--
 dll/shellext/stobject/csystray.h                   |   3 +-
 dll/shellext/stobject/hotplug.cpp                  | 315 ++++++++++++++++-----
 dll/shellext/stobject/lang/cs-CZ.rc                |   4 +-
 dll/shellext/stobject/lang/de-DE.rc                |   4 +-
 dll/shellext/stobject/lang/en-US.rc                |   4 +-
 dll/shellext/stobject/lang/es-ES.rc                |   4 +-
 dll/shellext/stobject/lang/fr-FR.rc                |   4 +-
 dll/shellext/stobject/lang/it-IT.rc                |   4 +-
 dll/shellext/stobject/lang/pl-PL.rc                |   4 +-
 dll/shellext/stobject/lang/ro-RO.rc                |   4 +-
 dll/shellext/stobject/lang/ru-RU.rc                |   4 +-
 dll/shellext/stobject/lang/zh-CN.rc                |   4 +-
 dll/shellext/stobject/lang/zh-TW.rc                |   4 +-
 dll/shellext/stobject/power.cpp                    | 301 ++++++++++++++++----
 dll/shellext/stobject/precomp.h                    |   3 -
 dll/shellext/stobject/resource.h                   |  16 ++
 dll/shellext/stobject/resources/battery/0.ico      | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/battery/1.ico      | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/battery/2.ico      | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/battery/3.ico      | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/battery/4.ico      | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/battery/5.ico      | Bin 0 -> 9062 bytes
 .../stobject/resources/battery/charging0.ico       | Bin 0 -> 2550 bytes
 .../stobject/resources/battery/charging1.ico       | Bin 0 -> 2550 bytes
 .../stobject/resources/battery/charging2.ico       | Bin 0 -> 2550 bytes
 .../stobject/resources/battery/charging3.ico       | Bin 0 -> 2550 bytes
 .../stobject/resources/battery/charging4.ico       | Bin 0 -> 2550 bytes
 dll/shellext/stobject/resources/battery/error.ico  | Bin 0 -> 9062 bytes
 dll/shellext/stobject/resources/hotplug/0.ico      | Bin 0 -> 2550 bytes
 dll/shellext/stobject/resources/hotplug/1.ico      | Bin 0 -> 2550 bytes
 dll/shellext/stobject/stobject.rc                  |  19 ++
 dll/shellext/stobject/volume.cpp                   |  29 +-
 34 files changed, 592 insertions(+), 195 deletions(-)

diff --git a/dll/shellext/stobject/CMakeLists.txt 
b/dll/shellext/stobject/CMakeLists.txt
index 2fa34e6144..341fe672ae 100644
--- a/dll/shellext/stobject/CMakeLists.txt
+++ b/dll/shellext/stobject/CMakeLists.txt
@@ -12,6 +12,9 @@ include_directories(
     ${REACTOS_SOURCE_DIR}/sdk/lib/atl
     ${REACTOS_SOURCE_DIR})
 
+add_definitions(
+    -D_ATL_NO_EXCEPTIONS)
+
 spec2def(stobject.dll stobject.spec)
 
 file(GLOB_RECURSE stobject_rc_deps resources/*.*)
@@ -30,6 +33,7 @@ set_module_type(stobject win32dll UNICODE)
 target_link_libraries(stobject uuid wine atlnew)
 
 add_importlibs(stobject
+    setupapi
     advapi32
     winmm
     ole32
diff --git a/dll/shellext/stobject/csystray.cpp 
b/dll/shellext/stobject/csystray.cpp
index 8551fbcf23..e4a2afe403 100644
--- a/dll/shellext/stobject/csystray.cpp
+++ b/dll/shellext/stobject/csystray.cpp
@@ -4,6 +4,7 @@
 * FILE:        dll/shellext/stobject/csystray.cpp
 * PURPOSE:     Systray shell service object implementation
 * PROGRAMMERS: David Quintana <gigah...@gmail.com>
+*              Shriraj Sawant a.k.a SR13 <sr.offic...@hotmail.com>
 */
 
 #include "precomp.h"
@@ -97,7 +98,27 @@ HRESULT CSysTray::ProcessIconMessage(UINT uMsg, WPARAM 
wParam, LPARAM lParam, LR
     return S_FALSE;
 }
 
-HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip)
+/*++
+* @name NotifyIcon
+*
+* Basically a Shell_NotifyIcon wrapper.
+* Based on the parameters provided, it changes the current state of the 
notification icon.
+*
+* @param code
+*        Determines whether to add, delete or modify the notification icon 
(represented by uId).
+* @param uId
+*        Represents the particular notification icon.
+* @param hIcon
+*        A handle to an icon for the notification object.
+* @param szTip
+*        A string for the tooltip of the notification.
+* @param dwstate
+*        Determines whether to show or hide the notification icon.
+*
+* @return The error code.
+*
+*--*/
+HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, 
DWORD dwstate)
 {
     NOTIFYICONDATA nim = { 0 };
 
@@ -108,8 +129,8 @@ HRESULT CSysTray::NotifyIcon(INT code, UINT uId, HICON 
hIcon, LPCWSTR szTip)
     nim.hIcon = hIcon;
     nim.uID = uId;
     nim.uCallbackMessage = uId;
-    nim.dwState = 0;
-    nim.dwStateMask = 0;
+    nim.dwState = dwstate;
+    nim.dwStateMask = NIS_HIDDEN;
     nim.hWnd = m_hWnd;
     nim.uVersion = NOTIFYICON_VERSION;
     if (szTip)
@@ -219,30 +240,8 @@ BOOL CSysTray::ProcessWindowMessage(HWND hWnd, UINT uMsg, 
WPARAM wParam, LPARAM
         return TRUE;
 
     case WM_TIMER:
-        switch (wParam)
-        {
-            case 1:
-                UpdateIcons();
-                return TRUE;
-
-            case POWER_TIMER_ID:
-                Power_OnTimer(hWnd);
-                break;
-
-            case VOLUME_TIMER_ID:
-                Volume_OnTimer(hWnd);
-                break;
-
-            case HOTPLUG_TIMER_ID:
-                Hotplug_OnTimer(hWnd);
-                break;
-        }
-        break;
-
-    case WM_DEVICECHANGE:
-        ERR("WM_DEVICECHANGE\n");
-        break;
-
+        UpdateIcons();
+        return TRUE;
     case WM_DESTROY:
         KillTimer(1);
         ShutdownIcons();
diff --git a/dll/shellext/stobject/csystray.h b/dll/shellext/stobject/csystray.h
index 04f7c1e292..b95cd65577 100644
--- a/dll/shellext/stobject/csystray.h
+++ b/dll/shellext/stobject/csystray.h
@@ -5,6 +5,7 @@
  * PURPOSE:     Systray shell service object
  * PROGRAMMERS: Robert Naumann
  *              David Quintana <gigah...@gmail.com>
+ *              Shriraj Sawant a.k.a SR13 <sr.offic...@hotmail.com>
  */
 #pragma once
 
@@ -43,7 +44,7 @@ class CSysTray :
     HRESULT ShutdownNetShell();
 
 public:
-    HRESULT NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip);
+    HRESULT NotifyIcon(INT code, UINT uId, HICON hIcon, LPCWSTR szTip, DWORD 
dwstate = 0);
 
     HWND GetHWnd() { return m_hWnd; }
 
diff --git a/dll/shellext/stobject/hotplug.cpp 
b/dll/shellext/stobject/hotplug.cpp
index fbc22ea078..4b17a1baf2 100644
--- a/dll/shellext/stobject/hotplug.cpp
+++ b/dll/shellext/stobject/hotplug.cpp
@@ -2,38 +2,152 @@
  * PROJECT:     ReactOS system libraries
  * LICENSE:     GPL - See COPYING in the top level directory
  * FILE:        dll/shellext/stobject/hotplug.cpp
- * PURPOSE:     Hotplug notification icon handler
- * PROGRAMMERS: Eric Kohl <eric.k...@reactos.org>
- *              David Quintana <gigah...@gmail.com>
+ * PURPOSE:     Removable devices notification icon handler
+ * PROGRAMMERS: Shriraj Sawant a.k.a SR13 <sr.offic...@hotmail.com> 
  */
-
+#include <windows.h>
 #include "precomp.h"
+#include <mmsystem.h>
+#include <mmddk.h>
+#include <atlstr.h>
+#include <atlsimpcoll.h>
+#include <dbt.h>
+#include <setupapi.h>
+#include <cfgmgr32.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(stobject);
+#define DISPLAY_NAME_LEN 40
+
+//BOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle);
 
+CSimpleArray<DEVINST> g_devList;
+/*static HDEVNOTIFY g_hDevNotify = NULL;*/
 static HICON g_hIconHotplug = NULL;
+static LPCWSTR g_strTooltip = L"Safely Remove Hardware and Eject Media";
+static WCHAR g_strMenuSel[DISPLAY_NAME_LEN];
 static BOOL g_IsRunning = FALSE;
-
-
-HRESULT STDMETHODCALLTYPE Hotplug_Init(_In_ CSysTray * pSysTray)
+static BOOL g_IsRemoving = FALSE;
+
+/*++
+* @name EnumHotpluggedDevices
+*
+* Enumerates the connected safely removable devices.
+*
+* @param devList
+*        List of device instances, representing the currently attached devices.
+*
+* @return The error code.
+*
+*--*/
+HRESULT EnumHotpluggedDevices(CSimpleArray<DEVINST> &devList)
 {
-    WCHAR strTooltip[128];
+    devList.RemoveAll(); // Clear current devList
+    HDEVINFO hdev = SetupDiGetClassDevs(NULL, NULL, 0, DIGCF_ALLCLASSES | 
DIGCF_PRESENT);
+    if (INVALID_HANDLE_VALUE == hdev)
+        return E_HANDLE;
+    SP_DEVINFO_DATA did = { 0 };
+    did.cbSize = sizeof(did);
+
+    // Enumerate all the attached devices.
+    for (int idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); idev++)
+    {
+        DWORD dwCapabilities = 0, dwSize = sizeof(dwCapabilities);
+        WCHAR dispName[DISPLAY_NAME_LEN];
+        ULONG ulStatus = 0, ulPnum = 0, ulLength = DISPLAY_NAME_LEN * 
sizeof(WCHAR);
+        CONFIGRET cr = CM_Get_DevNode_Status(&ulStatus, &ulPnum, did.DevInst, 
0);
+        if (cr != CR_SUCCESS)
+            continue;
+        cr = CM_Get_DevNode_Registry_Property(did.DevInst, CM_DRP_DEVICEDESC, 
NULL, dispName, &ulLength, 0);
+        if (cr != CR_SUCCESS)
+            continue;
+        cr = CM_Get_DevNode_Registry_Property(did.DevInst, 
CM_DRP_CAPABILITIES, NULL, &dwCapabilities, &dwSize, 0);
+        if (cr != CR_SUCCESS)
+            continue;
+
+        // Filter and make list of only the appropriate safely removable 
devices.
+        if ( (dwCapabilities & CM_DEVCAP_REMOVABLE) &&
+            !(dwCapabilities & CM_DEVCAP_DOCKDEVICE) &&
+            !(dwCapabilities & CM_DEVCAP_SURPRISEREMOVALOK) &&
+            ((dwCapabilities & CM_DEVCAP_EJECTSUPPORTED) || (ulStatus & 
DN_DISABLEABLE)) &&
+            !ulPnum)
+        {
+            devList.Add(did.DevInst);
+        }
+    }
+    SetupDiDestroyDeviceInfoList(hdev);
 
-    TRACE("Hotplug_Init\n");
+    if (NO_ERROR != GetLastError() && ERROR_NO_MORE_ITEMS != GetLastError())
+    {
+        return E_UNEXPECTED;
+    }
 
-    g_hIconHotplug = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_EXTRACT));
+    return S_OK;
+}
 
-    LoadStringW(g_hInstance, IDS_HOTPLUG_REMOVE_1, strTooltip, 
_countof(strTooltip));
+/*++
+* @name NotifyBalloon
+*
+* Pops the balloon notification of the given notification icon.
+*
+* @param pSysTray
+*        Provides interface for acquiring CSysTray information as required.
+* @param szTitle
+*        Title for the balloon notification.
+* @param szInfo
+*        Main content for the balloon notification.
+* @param uId
+*        Represents the particular notification icon.
+*
+* @return The error code.
+*
+*--*/
+HRESULT NotifyBalloon(CSysTray* pSysTray, LPCWSTR szTitle = NULL, LPCWSTR 
szInfo = NULL, UINT uId = ID_ICON_HOTPLUG)
+{
+    NOTIFYICONDATA nim = { 0 };
+    nim.cbSize = sizeof(NOTIFYICONDATA);
+    nim.uID = uId;
+    nim.hWnd = pSysTray->GetHWnd();
+
+    nim.uFlags = NIF_INFO;
+    nim.uTimeout = 10;
+    nim.dwInfoFlags = NIIF_INFO;
+
+    StringCchCopy(nim.szInfoTitle, _countof(nim.szInfoTitle), szTitle);
+    StringCchCopy(nim.szInfo, _countof(nim.szInfo), szInfo);
+    BOOL ret = Shell_NotifyIcon(NIM_MODIFY, &nim);
+
+    Sleep(10000); /* As per windows, the balloon notification remains visible 
for atleast 10 sec.
+                     This timer maintains the same condition.
+                     Also it is required so that the icon doesn't hide 
instantly after last device is removed,
+                     as that will prevent popping of notification.
+                  */
+    StringCchCopy(nim.szInfoTitle, _countof(nim.szInfoTitle), L"");
+    StringCchCopy(nim.szInfo, _countof(nim.szInfo), L"");
+    ret = Shell_NotifyIcon(NIM_MODIFY, &nim);
+    g_IsRemoving = FALSE; /* This flag is used to prevent instant icon hiding 
after last device is removed.
+                             The above timer maintains the required state for 
the same.
+                          */
+    return ret ? S_OK : E_FAIL;
+}
 
+HRESULT STDMETHODCALLTYPE Hotplug_Init(_In_ CSysTray * pSysTray)
+{ 
+    TRACE("Hotplug_Init\n");
+    g_hIconHotplug = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_HOTPLUG_OK));
     g_IsRunning = TRUE;
+    EnumHotpluggedDevices(g_devList);
 
-    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, 
strTooltip);
+    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_HOTPLUG, g_hIconHotplug, 
g_strTooltip, NIS_HIDDEN);
 }
 
 HRESULT STDMETHODCALLTYPE Hotplug_Update(_In_ CSysTray * pSysTray)
 {
     TRACE("Hotplug_Update\n");
-    return S_OK;
+
+    if(g_devList.GetSize() || g_IsRemoving)
+        return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, 
g_hIconHotplug, g_strTooltip);
+    else
+        return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_HOTPLUG, 
g_hIconHotplug, g_strTooltip, NIS_HIDDEN);
 }
 
 HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray * pSysTray)
@@ -45,79 +159,112 @@ HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray 
* pSysTray)
     return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_HOTPLUG, NULL, NULL);
 }
 
-static void RunHotplug()
+static void _RunHotplug(CSysTray * pSysTray)
 {
-    ShellExecuteW(NULL, NULL, L"rundll32.exe", L"shell32.dll,Control_RunDLL 
hotplug.dll", NULL, SW_SHOWNORMAL);
+    ShellExecuteW(pSysTray->GetHWnd(), L"open", L"rundll32.exe 
shell32.dll,Control_RunDLL hotplug.dll", NULL, NULL, SW_SHOWNORMAL);
 }
 
-static void ShowContextMenu(CSysTray *pSysTray)
+static void _ShowContextMenu(CSysTray * pSysTray)
 {
-    WCHAR szBuffer[128];
-    DWORD id, msgPos;
-    HMENU hPopup;
-
-    LoadStringW(g_hInstance, IDS_HOTPLUG_REMOVE_2, szBuffer, 
_countof(szBuffer));
+    HMENU hPopup = CreatePopupMenu();
+    ULONG ulLength = DISPLAY_NAME_LEN * sizeof(WCHAR);
 
-    hPopup = CreatePopupMenu();
-    AppendMenuW(hPopup, MF_STRING, 1, szBuffer);
+    for (INT index = 0; index < g_devList.GetSize(); index++)
+    {
+        WCHAR dispName[DISPLAY_NAME_LEN], menuName[DISPLAY_NAME_LEN + 10];
+        CONFIGRET cr = CM_Get_DevNode_Registry_Property(g_devList[index], 
CM_DRP_DEVICEDESC, NULL, dispName, &ulLength, 0);
+        if (cr != CR_SUCCESS)
+            StrCpyW(dispName, L"Unknown Device");
 
-    msgPos = GetMessagePos();
+        swprintf(menuName, L"Eject %wS", dispName);
+        AppendMenuW(hPopup, MF_STRING, index+1, menuName);
+    }
 
     SetForegroundWindow(pSysTray->GetHWnd());
-    id = TrackPopupMenuEx(hPopup,
-                          TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN,
-                          GET_X_LPARAM(msgPos),
-                          GET_Y_LPARAM(msgPos),
-                          pSysTray->GetHWnd(),
-                          NULL);
+    DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN;
+    POINT pt;
+    GetCursorPos(&pt);
 
-    DestroyMenu(hPopup);
+    DWORD id = TrackPopupMenuEx(hPopup, flags,
+        pt.x, pt.y,
+        pSysTray->GetHWnd(), NULL);
+
+    if (id > 0)
+    {
+        id--; // since array indices starts from zero.
+        CONFIGRET cr = CM_Get_DevNode_Registry_Property(g_devList[id], 
CM_DRP_DEVICEDESC, NULL, g_strMenuSel, &ulLength, 0);
+        if (cr != CR_SUCCESS)
+            StrCpyW(g_strMenuSel, L"Unknown Device");
+
+        cr = CM_Request_Device_Eject_Ex(g_devList[id], 0, 0, 0, 0, 0);
+        if (cr != CR_SUCCESS)
+        {
+            WCHAR strInfo[128];
+            swprintf(strInfo, L"Problem Ejecting %wS", g_strMenuSel);
+            MessageBox(0, L"The device cannot be stopped right now! Try 
stopping it again later!", strInfo, MB_OKCANCEL | MB_ICONEXCLAMATION);
+        }
+        else
+        {
+            //MessageBox(0, L"Device ejected successfully!! You can safely 
remove the device now!", L"Safely Remove Hardware", MB_OKCANCEL | 
MB_ICONINFORMATION);
+            g_IsRemoving = TRUE;
+            g_devList.RemoveAt(id); /* thing is.. even after removing id at 
this point, the devnode_change occurs after some seconds of sucessful removal
+                                       and since pendrive is still plugged in 
it gets enumerated, if problem number is not filtered.
+                                    */
+        }
+    }
 
-    if (id == 1)
-        RunHotplug();
+    DestroyMenu(hPopup);
 }
 
-static
-VOID
-ShowHotplugPopupMenu(
-    HWND hWnd)
+static void _ShowContextMenuR(CSysTray * pSysTray)
 {
-#if 0
-    DWORD id, msgPos;
-
+    CString strMenu((LPWSTR)IDS_HOTPLUG_REMOVE_2);
     HMENU hPopup = CreatePopupMenu();
+    AppendMenuW(hPopup, MF_STRING, IDS_HOTPLUG_REMOVE_2, strMenu);
 
-    // FIXME
-    AppendMenuW(hPopup, MF_STRING, IDS_VOL_OPEN, strOpen);
-
-    msgPos = GetMessagePos();
-
-    SetForegroundWindow(hWnd);
-    id = TrackPopupMenuEx(hPopup,
-                          TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN,
-                          GET_X_LPARAM(msgPos),
-                          GET_Y_LPARAM(msgPos),
-                          hWnd,
-                          NULL);
+    SetForegroundWindow(pSysTray->GetHWnd());
+    DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN;
+    POINT pt;
+    GetCursorPos(&pt);
 
-    DestroyMenu(hPopup);
+    DWORD id = TrackPopupMenuEx(hPopup, flags,
+        pt.x, pt.y,
+        pSysTray->GetHWnd(), NULL);
 
-    if (id != 0)
+    if (id == IDS_HOTPLUG_REMOVE_2)
     {
-        // FIXME
+        _RunHotplug(pSysTray);
     }
-#endif
+
+    DestroyMenu(hPopup);
 }
 
-HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray *pSysTray, UINT uMsg, 
WPARAM wParam, LPARAM lParam, LRESULT &lResult)
+HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray * pSysTray, UINT uMsg, 
WPARAM wParam, LPARAM lParam, LRESULT &lResult)
 {
+    HRESULT hr = E_FAIL;
     TRACE("Hotplug_Message uMsg=%d, wParam=%x, lParam=%x\n", uMsg, wParam, 
lParam);
 
     switch (uMsg)
     {
+        /*case WM_CREATE:
+            TRACE("Hotplug_Message: WM_CREATE\n");
+            DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
+
+            ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
+            NotificationFilter.dbcc_size = 
sizeof(DEV_BROADCAST_DEVICEINTERFACE);
+            NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+
+            g_hDevNotify = RegisterDeviceNotification(pSysTray->GetHWnd(), 
&NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE | 
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
+            if (g_hDevNotify != NULL)
+            {
+                lResult = true;
+                return S_OK;
+            }
+            return S_FALSE;*/
+
         case WM_USER + 220:
             TRACE("Hotplug_Message: WM_USER+220\n");
-            if (wParam == 2)
+            if (wParam == 1)
             {
                 if (lParam == FALSE)
                     return Hotplug_Init(pSysTray);
@@ -128,7 +275,7 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray 
*pSysTray, UINT uMsg, WP
 
         case WM_USER + 221:
             TRACE("Hotplug_Message: WM_USER+221\n");
-            if (wParam == 2)
+            if (wParam == 1)
             {
                 lResult = (LRESULT)g_IsRunning;
                 return S_OK;
@@ -141,22 +288,21 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray 
*pSysTray, UINT uMsg, WP
             switch (lParam)
             {
                 case WM_LBUTTONDOWN:
-                    SetTimer(pSysTray->GetHWnd(), HOTPLUG_TIMER_ID, 500, NULL);
                     break;
 
                 case WM_LBUTTONUP:
+                    _ShowContextMenu(pSysTray);
                     break;
 
                 case WM_LBUTTONDBLCLK:
-                    KillTimer(pSysTray->GetHWnd(), HOTPLUG_TIMER_ID);
-                    RunHotplug();
+                    _RunHotplug(pSysTray);
                     break;
 
                 case WM_RBUTTONDOWN:
                     break;
 
                 case WM_RBUTTONUP:
-                    ShowContextMenu(pSysTray);
+                    _ShowContextMenuR(pSysTray);
                     break;
 
                 case WM_RBUTTONDBLCLK:
@@ -167,6 +313,41 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray 
*pSysTray, UINT uMsg, WP
             }
             return S_OK;
 
+        case WM_DEVICECHANGE:
+            switch (wParam)
+            {
+                case DBT_DEVNODES_CHANGED:
+                    hr = EnumHotpluggedDevices(g_devList);
+                    if (FAILED(hr))
+                        return hr;
+
+                    lResult = true;
+                    break;
+                case DBT_DEVICEARRIVAL:
+                    break;
+                case DBT_DEVICEQUERYREMOVE:
+                    break;
+                case DBT_DEVICEQUERYREMOVEFAILED:
+                    break;
+                case DBT_DEVICEREMOVECOMPLETE:
+                    WCHAR strInfo[128];
+                    swprintf(strInfo, L"The %wS can now be safely removed from 
the system.", g_strMenuSel);
+                    NotifyBalloon(pSysTray, L"Safe to Remove Hardware", 
strInfo);
+
+                    lResult = true;
+                    break;
+                case DBT_DEVICEREMOVEPENDING:
+                    break;
+            }
+            return S_OK;
+
+        /*case WM_CLOSE:
+            if (!UnregisterDeviceNotification(hDeviceNotify))
+            {
+                return S_FALSE;
+            }
+            return S_OK;*/
+
         default:
             TRACE("Hotplug_Message received for unknown ID %d, ignoring.\n");
             return S_FALSE;
@@ -174,11 +355,3 @@ HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray 
*pSysTray, UINT uMsg, WP
 
     return S_FALSE;
 }
-
-VOID
-Hotplug_OnTimer(HWND hWnd)
-{
-    TRACE("Hotplug_OnTimer\n!");
-    KillTimer(hWnd, HOTPLUG_TIMER_ID);
-    ShowHotplugPopupMenu(hWnd);
-}
diff --git a/dll/shellext/stobject/lang/cs-CZ.rc 
b/dll/shellext/stobject/lang/cs-CZ.rc
index 84fe3d4fb1..57ec1bca55 100644
--- a/dll/shellext/stobject/lang/cs-CZ.rc
+++ b/dll/shellext/stobject/lang/cs-CZ.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Upravit možnosti napájení"
     IDS_PWR_METER             "&Otevřít ukazatel spotřeby"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "zbývá %1!u!%%"
-    IDS_PWR_CHARGING          " (nabíjení)"
+    IDS_PWR_PERCENT_REMAINING "zbývá %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Zbývá neznámo"
     IDS_PWR_AC "On AC power"
     IDS_PWR_HOURS_REMAINING "zbývá %1!u!:%2!02u! hodin (%3!u!%%)"
diff --git a/dll/shellext/stobject/lang/de-DE.rc 
b/dll/shellext/stobject/lang/de-DE.rc
index 1563baf172..cdb3aa2d48 100644
--- a/dll/shellext/stobject/lang/de-DE.rc
+++ b/dll/shellext/stobject/lang/de-DE.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Energieverwaltungseigenschaften einstellen"
     IDS_PWR_METER             "Batterieanzeige ö&ffnen"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "%1!u!%% verbleibend"
-    IDS_PWR_CHARGING          " (wird aufgeladen)"
+    IDS_PWR_PERCENT_REMAINING "%.2f%% verbleibend"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Unbekannt verbleibend"
     IDS_PWR_AC "Mit Wechselstrom"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! Stunden (%3!u!%%) verbleibend"
diff --git a/dll/shellext/stobject/lang/en-US.rc 
b/dll/shellext/stobject/lang/en-US.rc
index e10c25c3cc..ea1f17ffcd 100644
--- a/dll/shellext/stobject/lang/en-US.rc
+++ b/dll/shellext/stobject/lang/en-US.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Adjust Power Properties"
     IDS_PWR_METER             "&Open Power Meter"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "%1!u!%% remaining"
-    IDS_PWR_CHARGING          " (charging)"
+    IDS_PWR_PERCENT_REMAINING "%.2f%% remaining"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Unknown remaining"
     IDS_PWR_AC "On AC power"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! hours (%3!u!%%) remaining"
diff --git a/dll/shellext/stobject/lang/es-ES.rc 
b/dll/shellext/stobject/lang/es-ES.rc
index c7a3d0d6b2..ac008f2dd9 100644
--- a/dll/shellext/stobject/lang/es-ES.rc
+++ b/dll/shellext/stobject/lang/es-ES.rc
@@ -19,8 +19,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Ajustar propiedades de energía"
     IDS_PWR_METER             "Abrir &medidor de energía"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "Queda un %1!u!%%"
-    IDS_PWR_CHARGING          " (cargando)"
+    IDS_PWR_PERCENT_REMAINING "Queda un %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Estado de batería desconocido"
     IDS_PWR_AC "En corriente alterna"
     IDS_PWR_HOURS_REMAINING "Quedan %1!u!:%2!02u! horas (%3!u!%%)"
diff --git a/dll/shellext/stobject/lang/fr-FR.rc 
b/dll/shellext/stobject/lang/fr-FR.rc
index 273cb83b89..de393af36f 100644
--- a/dll/shellext/stobject/lang/fr-FR.rc
+++ b/dll/shellext/stobject/lang/fr-FR.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Adjust Power Properties"
     IDS_PWR_METER             "&Open Power Meter"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "%1!u!%% remaining"
-    IDS_PWR_CHARGING          " (charging)"
+    IDS_PWR_PERCENT_REMAINING "%.2f%% remaining"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Unknown remaining"
     IDS_PWR_AC "On AC power"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! hours (%3!u!%%) remaining"
diff --git a/dll/shellext/stobject/lang/it-IT.rc 
b/dll/shellext/stobject/lang/it-IT.rc
index a4d715427c..628466edbe 100644
--- a/dll/shellext/stobject/lang/it-IT.rc
+++ b/dll/shellext/stobject/lang/it-IT.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Modifica proprietà alimentazione"
     IDS_PWR_METER             "&Apri misuratore alimentazione"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "%1!u!%% rimanenti"
-    IDS_PWR_CHARGING          " (in carica)"
+    IDS_PWR_PERCENT_REMAINING "%.2f%% rimanenti"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Autonomia sconosciuta"
     IDS_PWR_AC                "Alimentazione da rete AC"
     IDS_PWR_HOURS_REMAINING   "%1!u!:%2!02u! ore (%3!u!%%) rimanenti"
diff --git a/dll/shellext/stobject/lang/pl-PL.rc 
b/dll/shellext/stobject/lang/pl-PL.rc
index 0a2889edc4..def3249946 100644
--- a/dll/shellext/stobject/lang/pl-PL.rc
+++ b/dll/shellext/stobject/lang/pl-PL.rc
@@ -18,8 +18,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Opcje zasilania"
     IDS_PWR_METER             "&Otwórz miernik baterii"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "Pozostało %1!u!%%"
-    IDS_PWR_CHARGING          " (ładowanie)"
+    IDS_PWR_PERCENT_REMAINING "Pozostało %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Stan naładowania nieznany"
     IDS_PWR_AC "Podłączony do zasilacza"
     IDS_PWR_HOURS_REMAINING "Pozostało %1!u!:%2!02u! godzin (%3!u!%%)"
diff --git a/dll/shellext/stobject/lang/ro-RO.rc 
b/dll/shellext/stobject/lang/ro-RO.rc
index 0de2e8de7c..bb19bd1d74 100644
--- a/dll/shellext/stobject/lang/ro-RO.rc
+++ b/dll/shellext/stobject/lang/ro-RO.rc
@@ -19,8 +19,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Ajustare proprietăți de consum energie"
     IDS_PWR_METER             "&Deschide Contor de energie"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "Au mai rămas %1!u!%%"
-    IDS_PWR_CHARGING          " (în încărcare)"
+    IDS_PWR_PERCENT_REMAINING "Au mai rămas %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Nu este disponibil cât a mai rămas"
     IDS_PWR_AC "În rețea de CA"
     IDS_PWR_HOURS_REMAINING "Au mai rămas %1!u!:%2!02u! ore (%3!u!%%)"
diff --git a/dll/shellext/stobject/lang/ru-RU.rc 
b/dll/shellext/stobject/lang/ru-RU.rc
index 572f1613fd..af307d3024 100644
--- a/dll/shellext/stobject/lang/ru-RU.rc
+++ b/dll/shellext/stobject/lang/ru-RU.rc
@@ -20,8 +20,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "&Настройка параметров электропитания"
     IDS_PWR_METER             "&Открыть показатели питания"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "%1!u!%% осталось"
-    IDS_PWR_CHARGING          " (зарядка)"
+    IDS_PWR_PERCENT_REMAINING "%.2f%% осталось"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "Неизвестно"
     IDS_PWR_AC "От сети переменного тока"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! часов (%3!u!%%) осталось"
diff --git a/dll/shellext/stobject/lang/zh-CN.rc 
b/dll/shellext/stobject/lang/zh-CN.rc
index 6ba1f37f4b..1d402493d0 100644
--- a/dll/shellext/stobject/lang/zh-CN.rc
+++ b/dll/shellext/stobject/lang/zh-CN.rc
@@ -20,8 +20,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "调整电源属性(&A)"
     IDS_PWR_METER             "开放式电源表(&O)"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "剩余 %1!u!%%"
-    IDS_PWR_CHARGING          " (充电中)"
+    IDS_PWR_PERCENT_REMAINING "剩余 %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "未知剩余"
     IDS_PWR_AC "交流电源"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! 小时 剩余 (%3!u!%%) "
diff --git a/dll/shellext/stobject/lang/zh-TW.rc 
b/dll/shellext/stobject/lang/zh-TW.rc
index 35ae8c4a6f..3d9a5265b8 100644
--- a/dll/shellext/stobject/lang/zh-TW.rc
+++ b/dll/shellext/stobject/lang/zh-TW.rc
@@ -20,8 +20,8 @@ BEGIN
     IDS_PWR_PROPERTIES        "調整電源屬性(&A)"
     IDS_PWR_METER             "開放式電源表(&O)"
     IDS_PWR_RUN               "shell32.dll,Control_RunDLL PowerCfg.cpl"
-    IDS_PWR_PERCENT_REMAINING "剩餘 %1!u!%%"
-    IDS_PWR_CHARGING          " (充電中)"
+    IDS_PWR_PERCENT_REMAINING "剩餘 %.2f%%"
+    IDS_PWR_CHARGING          "%.2f%% and charging"
     IDS_PWR_UNKNOWN_REMAINING "未知剩餘"
     IDS_PWR_AC "交流電源"
     IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! 小時 剩餘 (%3!u!%%) "
diff --git a/dll/shellext/stobject/power.cpp b/dll/shellext/stobject/power.cpp
index 24b5feb416..5853b2bdbf 100644
--- a/dll/shellext/stobject/power.cpp
+++ b/dll/shellext/stobject/power.cpp
@@ -4,14 +4,30 @@
  * FILE:        dll/shellext/stobject/power.cpp
  * PURPOSE:     Power notification icon handler
  * PROGRAMMERS: Eric Kohl <eric.k...@reactos.org>
+                Shriraj Sawant a.k.a SR13 <sr.offic...@hotmail.com>
  *              David Quintana <gigah...@gmail.com>
  */
 
+#include <Windows.h>
+#include <SetupAPI.h>
+#include <devguid.h>
+#include <BatClass.h> 
+
 #include "precomp.h"
 #include "powrprof.h"
 
+#include <mmsystem.h>
+#include <mmddk.h>
+#include <atlstr.h>
+
+#define GBS_HASBATTERY 0x1
+#define GBS_ONBATTERY  0x2
+
 WINE_DEFAULT_DEBUG_CHANNEL(stobject);
 
+int br_icons[5] = { IDI_BATTCAP0, IDI_BATTCAP1, IDI_BATTCAP2, IDI_BATTCAP3, 
IDI_BATTCAP4 }; // battery mode icons.
+int bc_icons[5] = { IDI_BATTCHA0, IDI_BATTCHA1, IDI_BATTCHA2, IDI_BATTCHA3, 
IDI_BATTCHA4 }; // charging mode icons.
+
 typedef struct _PWRSCHEMECONTEXT
 {
     HMENU hPopup;
@@ -19,71 +35,261 @@ typedef struct _PWRSCHEMECONTEXT
     UINT uiLast;
 } PWRSCHEMECONTEXT, *PPWRSCHEMECONTEXT;
 
+CString  g_strTooltip;
+static float g_batCap = 0;
 static HICON g_hIconBattery = NULL;
 static BOOL g_IsRunning = FALSE;
 
+/*++
+* @name GetBatteryState
+*
+* Enumerates the available battery devices and provides the remaining capacity.
+*
+* @param cap
+*        If no error occurs, then this will contain average remaining capacity.
+* @param dwResult
+*        Helps in making battery type checks.
+*       {
+*           Returned value includes GBS_HASBATTERY if the system has a non-UPS 
battery,
+*           and GBS_ONBATTERY if the system is running on a battery.
+*           dwResult & GBS_ONBATTERY means we have not yet found AC power.
+*           dwResult & GBS_HASBATTERY means we have found a non-UPS battery.
+*       }
+*
+* @return The error code.
+*
+*--*/
+static HRESULT GetBatteryState(float& cap, DWORD& dwResult)
+{
+    cap = 0;
+    dwResult = GBS_ONBATTERY;
 
-HRESULT STDMETHODCALLTYPE Power_Init(_In_ CSysTray * pSysTray)
+    HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, 
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+    if (INVALID_HANDLE_VALUE == hdev)
+        return E_HANDLE;
+
+    // Limit search to 100 batteries max
+    for (int idev = 0, count = 0; idev < 100; idev++)
+    {
+        SP_DEVICE_INTERFACE_DATA did = { 0 };
+        did.cbSize = sizeof(did);
+
+        if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, idev, 
&did))
+        {
+            DWORD cbRequired = 0;
+
+            SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
+            if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
+            {
+                PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = 
(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
+                if (pdidd)
+                {
+                    pdidd->cbSize = sizeof(*pdidd);
+                    if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, 
cbRequired, &cbRequired, 0))
+                    {
+                        // Enumerated a battery.  Ask it for information.
+                        HANDLE hBattery = CreateFile(pdidd->DevicePath, 
GENERIC_READ | GENERIC_WRITE,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+                        if (INVALID_HANDLE_VALUE != hBattery)
+                        {
+                            // Ask the battery for its tag.
+                            BATTERY_QUERY_INFORMATION bqi = { 0 };
+
+                            DWORD dwWait = 0;
+                            DWORD dwOut;
+
+                            if (DeviceIoControl(hBattery, 
IOCTL_BATTERY_QUERY_TAG, &dwWait, sizeof(dwWait), &bqi.BatteryTag,
+                                sizeof(bqi.BatteryTag), &dwOut, NULL) && 
bqi.BatteryTag)
+                            {
+                                // With the tag, you can query the battery 
info.
+                                BATTERY_INFORMATION bi = { 0 };
+                                bqi.InformationLevel = BatteryInformation;
+
+                                if (DeviceIoControl(hBattery, 
IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi,
+                                    sizeof(bi), &dwOut, NULL))
+                                {
+                                    // Only non-UPS system batteries count
+                                    if (bi.Capabilities & 
BATTERY_SYSTEM_BATTERY)
+                                    {
+                                        if (!(bi.Capabilities & 
BATTERY_IS_SHORT_TERM))
+                                            dwResult |= GBS_HASBATTERY;
+
+                                        // Query the battery status.
+                                        BATTERY_WAIT_STATUS bws = { 0 };
+                                        bws.BatteryTag = bqi.BatteryTag;
+
+                                        BATTERY_STATUS bs;
+                                        if (DeviceIoControl(hBattery, 
IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws),
+                                            &bs, sizeof(bs), &dwOut, NULL))
+                                        {
+                                            if (bs.PowerState & 
BATTERY_POWER_ON_LINE)
+                                                dwResult &= ~GBS_ONBATTERY;
+
+                                            // Take average of total capacity 
of batteries detected!
+                                            cap = 
cap*(count)+(float)bs.Capacity / bi.FullChargedCapacity * 100;
+                                            cap /= count + 1;
+                                            count++;
+                                        }
+                                    }
+                                }
+                            }
+                            CloseHandle(hBattery);
+                        }
+                    }
+                    LocalFree(pdidd);
+                }
+            }
+        }
+        else  if (ERROR_NO_MORE_ITEMS == GetLastError())
+        {
+            break;  // Enumeration failed - perhaps we're out of items
+        }
+    }
+    SetupDiDestroyDeviceInfoList(hdev);
+
+    //  Final cleanup:  If we didn't find a battery, then presume that we
+    //  are on AC power.
+
+    if (!(dwResult & GBS_HASBATTERY))
+        dwResult &= ~GBS_ONBATTERY;
+
+    return S_OK;
+}
+
+/*++
+* @name Quantize
+* 
+* This function quantizes the mentioned quantity to nearest level.
+* 
+* @param p
+*        Should be a quantity in percentage.
+* @param lvl
+*        Quantization level (this excludes base level 0, which will always be 
present), default is 10.
+*
+* @return Nearest quantized level, can be directly used as array index based 
on context.
+*
+*--*/
+static UINT Quantize(float p, UINT lvl = 10)
 {
-    WCHAR strTooltip[128];
+    int i = 0;
+    float f, q = (float)100 / lvl, d = q / 2;
+    for (f = 0; f < p; f += q, i++);
+
+    if ((f - d) <= p)
+        return i;
+    else
+        return i - 1;
+/* 
+ @remarks This function uses centred/symmetric logic for quantization.
+ For the case of lvl = 4, You will get following integer levels if given (p) 
value falls in between the range partitions:
+     0    <= p <  12.5 : returns 0; (corresponding to 0% centre)
+     12.5 <= p <  37.5 : returns 1; (corresponding to 25% centre)
+     37.5 <= p <  62.5 : returns 2; (corresponding to 50% centre)
+     62.5 <= p <  87.5 : returns 3; (corresponding to 75% centre)
+     87.5 <= p <= 100  : returns 4; (corresponding to 100% centre)
+*/
+}
 
-    TRACE("Power_Init\n");
+/*++
+* @name DynamicLoadIcon
+*
+* Returns the respective icon as per the current battery capacity.
+* It also does the work of setting global parameters of battery capacity and 
tooltips.
+*
+* @param hinst
+*        A handle to a instance of the module.
+*
+* @return The handle to respective battery icon.
+*
+*--*/
+static HICON DynamicLoadIcon(HINSTANCE hinst)
+{    
+    HICON hBatIcon;
+    float cap = 0;
+    DWORD dw = 0;
+    UINT index = -1;
+    HRESULT hr = GetBatteryState(cap, dw);
+
+    if (!FAILED(hr) && (dw & GBS_HASBATTERY))
+    {
+        index = Quantize(cap, 4);
+        g_batCap = cap;
+    }
+    else
+    {
+        g_batCap = 0;
+        hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_BATTCAP_ERR));
+        g_strTooltip.LoadStringW(IDS_PWR_UNKNOWN_REMAINING);
+        return hBatIcon;
+    }
 
-    g_hIconBattery = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_BATTERY));
+    if (dw & GBS_ONBATTERY)
+    {
+        hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(br_icons[index]));
+        g_strTooltip.Format(IDS_PWR_PERCENT_REMAINING, cap);
+    }
+    else
+    {
+        hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(bc_icons[index])); 
+        g_strTooltip.Format(IDS_PWR_CHARGING, cap);
+    }
 
-    LoadStringW(g_hInstance, IDS_PWR_AC, strTooltip, _countof(strTooltip));
+    return hBatIcon;
+}
 
+HRESULT STDMETHODCALLTYPE Power_Init(_In_ CSysTray * pSysTray)
+{ 
+    TRACE("Power_Init\n");
+    g_hIconBattery = DynamicLoadIcon(g_hInstance);
     g_IsRunning = TRUE;
 
-    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_POWER, g_hIconBattery, 
strTooltip);
+    return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_POWER, g_hIconBattery, 
g_strTooltip);
 }
 
 HRESULT STDMETHODCALLTYPE Power_Update(_In_ CSysTray * pSysTray)
 {
     TRACE("Power_Update\n");
-    return S_OK;
+    g_hIconBattery = DynamicLoadIcon(g_hInstance);
+
+    return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_POWER, g_hIconBattery, 
g_strTooltip);
 }
 
 HRESULT STDMETHODCALLTYPE Power_Shutdown(_In_ CSysTray * pSysTray)
 {
     TRACE("Power_Shutdown\n");
-
     g_IsRunning = FALSE;
 
     return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_POWER, NULL, NULL);
 }
 
-static void RunPower()
+static void _RunPower()
 {
-    ShellExecuteW(NULL, NULL, L"rundll32.exe", L"shell32.dll,Control_RunDLL 
powercfg.cpl", NULL, SW_SHOWNORMAL);
+    ShellExecuteW(NULL, NULL, L"powercfg.cpl", NULL, NULL, SW_SHOWNORMAL);
 }
 
-static void ShowContextMenu(CSysTray * pSysTray)
+static void _ShowContextMenu(CSysTray * pSysTray)
 {
-    WCHAR szBuffer[128];
-    DWORD id, msgPos;
-    HMENU hPopup;
-
-    LoadStringW(g_hInstance, IDS_PWR_PROPERTIES, szBuffer, _countof(szBuffer));
-
-    hPopup = CreatePopupMenu();
-    AppendMenuW(hPopup, MF_STRING, IDS_PWR_PROPERTIES, szBuffer);
-    SetMenuDefaultItem(hPopup, IDS_PWR_PROPERTIES, FALSE);
-
-    msgPos = GetMessagePos();
+    CString strOpen((LPCSTR)IDS_PWR_PROPERTIES);
+    HMENU hPopup = CreatePopupMenu();
+    AppendMenuW(hPopup, MF_STRING, IDS_PWR_PROPERTIES, strOpen);
 
     SetForegroundWindow(pSysTray->GetHWnd());
-    id = TrackPopupMenuEx(hPopup,
-                          TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN,
-                          GET_X_LPARAM(msgPos),
-                          GET_Y_LPARAM(msgPos),
-                          pSysTray->GetHWnd(),
-                          NULL);
+    DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN;
+    POINT pt;
+    GetCursorPos(&pt);
 
-    DestroyMenu(hPopup);
+    DWORD id = TrackPopupMenuEx(hPopup, flags,
+        pt.x, pt.y,
+        pSysTray->GetHWnd(), NULL);
 
-    if (id == IDS_PWR_PROPERTIES)
-        RunPower();
+    switch (id)
+    {
+        case IDS_PWR_PROPERTIES:
+            _RunPower();
+            break;
+    }
+    DestroyMenu(hPopup);
 }
 
 static
@@ -114,12 +320,12 @@ PowerSchemesEnumProc(
 static
 VOID
 ShowPowerSchemesPopupMenu(
-    HWND hWnd)
+    CSysTray *pSysTray)
 {
     PWRSCHEMECONTEXT PowerSchemeContext = {NULL, 0, 0};
     UINT uiActiveScheme;
-    DWORD id, msgPos;
-
+    DWORD id;
+    POINT pt;
     PowerSchemeContext.hPopup = CreatePopupMenu();
     EnumPwrSchemes(PowerSchemesEnumProc, (LPARAM)&PowerSchemeContext);
 
@@ -132,14 +338,14 @@ ShowPowerSchemesPopupMenu(
                            MF_BYCOMMAND);
     }
 
-    msgPos = GetMessagePos();
-
-    SetForegroundWindow(hWnd);
+    SetForegroundWindow(pSysTray->GetHWnd());
+    GetCursorPos(&pt);
+    
     id = TrackPopupMenuEx(PowerSchemeContext.hPopup,
                           TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN,
-                          GET_X_LPARAM(msgPos),
-                          GET_Y_LPARAM(msgPos),
-                          hWnd,
+                          pt.x,
+                          pt.y,
+                          pSysTray->GetHWnd(),
                           NULL);
 
     DestroyMenu(PowerSchemeContext.hPopup);
@@ -180,22 +386,21 @@ HRESULT STDMETHODCALLTYPE Power_Message(_In_ CSysTray * 
pSysTray, UINT uMsg, WPA
             switch (lParam)
             {
                 case WM_LBUTTONDOWN:
-                    SetTimer(pSysTray->GetHWnd(), POWER_TIMER_ID, 500, NULL);
                     break;
 
                 case WM_LBUTTONUP:
+                    ShowPowerSchemesPopupMenu(pSysTray);
                     break;
 
                 case WM_LBUTTONDBLCLK:
-                    KillTimer(pSysTray->GetHWnd(), POWER_TIMER_ID);
-                    RunPower();
+                    _RunPower();
                     break;
 
                 case WM_RBUTTONDOWN:
                     break;
 
                 case WM_RBUTTONUP:
-                    ShowContextMenu(pSysTray);
+                    _ShowContextMenu(pSysTray);
                     break;
 
                 case WM_RBUTTONDBLCLK:
@@ -213,11 +418,3 @@ HRESULT STDMETHODCALLTYPE Power_Message(_In_ CSysTray * 
pSysTray, UINT uMsg, WPA
 
     return S_FALSE;
 }
-
-VOID
-Power_OnTimer(HWND hWnd)
-{
-    TRACE("Power_OnTimer\n!");
-    KillTimer(hWnd, POWER_TIMER_ID);
-    ShowPowerSchemesPopupMenu(hWnd);
-}
diff --git a/dll/shellext/stobject/precomp.h b/dll/shellext/stobject/precomp.h
index fd2ea78836..64824ba825 100644
--- a/dll/shellext/stobject/precomp.h
+++ b/dll/shellext/stobject/precomp.h
@@ -69,19 +69,16 @@ extern HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray 
* pSysTray);
 extern HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * pSysTray, UINT 
uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult);
-extern VOID Volume_OnTimer(HWND hWnd);
 
 extern HRESULT STDMETHODCALLTYPE Hotplug_Init(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Hotplug_Shutdown(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Hotplug_Update(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Hotplug_Message(_In_ CSysTray * pSysTray, 
UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult);
-extern VOID Hotplug_OnTimer(HWND hWnd);
 
 extern HRESULT STDMETHODCALLTYPE Power_Init(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Power_Shutdown(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Power_Update(_In_ CSysTray * pSysTray);
 extern HRESULT STDMETHODCALLTYPE Power_Message(_In_ CSysTray * pSysTray, UINT 
uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult);
-extern VOID Power_OnTimer(HWND hWnd);
 
 #define POWER_TIMER_ID   2
 #define VOLUME_TIMER_ID  3
diff --git a/dll/shellext/stobject/resource.h b/dll/shellext/stobject/resource.h
index 2637a12aea..a7466f77d3 100644
--- a/dll/shellext/stobject/resource.h
+++ b/dll/shellext/stobject/resource.h
@@ -39,4 +39,20 @@
 #define IDS_KEYS_MOUSE            331
 #define IDS_KEYS_FILTER           332
 
+#define IDI_BATTCAP0              400
+#define IDI_BATTCAP1              401
+#define IDI_BATTCAP2              402
+#define IDI_BATTCAP3              403
+#define IDI_BATTCAP4              404
+#define IDI_BATTCAP5              405
+#define IDI_BATTCHA0              406
+#define IDI_BATTCHA1              407
+#define IDI_BATTCHA2              408
+#define IDI_BATTCHA3              409
+#define IDI_BATTCHA4              410
+#define IDI_BATTCAP_ERR           412
+
+#define IDI_HOTPLUG_ERR           420
+#define IDI_HOTPLUG_OK            421
+
 #define IDR_SYSTRAY               11001
diff --git a/dll/shellext/stobject/resources/battery/0.ico 
b/dll/shellext/stobject/resources/battery/0.ico
new file mode 100644
index 0000000000..1610499aa3
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/0.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/1.ico 
b/dll/shellext/stobject/resources/battery/1.ico
new file mode 100644
index 0000000000..9c2f526f9e
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/1.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/2.ico 
b/dll/shellext/stobject/resources/battery/2.ico
new file mode 100644
index 0000000000..f1dc98aa7f
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/2.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/3.ico 
b/dll/shellext/stobject/resources/battery/3.ico
new file mode 100644
index 0000000000..59fabc2ef3
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/3.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/4.ico 
b/dll/shellext/stobject/resources/battery/4.ico
new file mode 100644
index 0000000000..edc24a071e
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/4.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/5.ico 
b/dll/shellext/stobject/resources/battery/5.ico
new file mode 100644
index 0000000000..cd4e3b8ee7
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/5.ico 
differ
diff --git a/dll/shellext/stobject/resources/battery/charging0.ico 
b/dll/shellext/stobject/resources/battery/charging0.ico
new file mode 100644
index 0000000000..7504162423
Binary files /dev/null and 
b/dll/shellext/stobject/resources/battery/charging0.ico differ
diff --git a/dll/shellext/stobject/resources/battery/charging1.ico 
b/dll/shellext/stobject/resources/battery/charging1.ico
new file mode 100644
index 0000000000..3a6210c19a
Binary files /dev/null and 
b/dll/shellext/stobject/resources/battery/charging1.ico differ
diff --git a/dll/shellext/stobject/resources/battery/charging2.ico 
b/dll/shellext/stobject/resources/battery/charging2.ico
new file mode 100644
index 0000000000..7c1c919a35
Binary files /dev/null and 
b/dll/shellext/stobject/resources/battery/charging2.ico differ
diff --git a/dll/shellext/stobject/resources/battery/charging3.ico 
b/dll/shellext/stobject/resources/battery/charging3.ico
new file mode 100644
index 0000000000..fb92ab6213
Binary files /dev/null and 
b/dll/shellext/stobject/resources/battery/charging3.ico differ
diff --git a/dll/shellext/stobject/resources/battery/charging4.ico 
b/dll/shellext/stobject/resources/battery/charging4.ico
new file mode 100644
index 0000000000..bd1f495c9a
Binary files /dev/null and 
b/dll/shellext/stobject/resources/battery/charging4.ico differ
diff --git a/dll/shellext/stobject/resources/battery/error.ico 
b/dll/shellext/stobject/resources/battery/error.ico
new file mode 100644
index 0000000000..6afba7759d
Binary files /dev/null and b/dll/shellext/stobject/resources/battery/error.ico 
differ
diff --git a/dll/shellext/stobject/resources/hotplug/0.ico 
b/dll/shellext/stobject/resources/hotplug/0.ico
new file mode 100644
index 0000000000..83025a942d
Binary files /dev/null and b/dll/shellext/stobject/resources/hotplug/0.ico 
differ
diff --git a/dll/shellext/stobject/resources/hotplug/1.ico 
b/dll/shellext/stobject/resources/hotplug/1.ico
new file mode 100644
index 0000000000..f615f0ebd3
Binary files /dev/null and b/dll/shellext/stobject/resources/hotplug/1.ico 
differ
diff --git a/dll/shellext/stobject/stobject.rc 
b/dll/shellext/stobject/stobject.rc
index f7844dead4..4d7e6da69f 100644
--- a/dll/shellext/stobject/stobject.rc
+++ b/dll/shellext/stobject/stobject.rc
@@ -11,6 +11,25 @@ IDI_EXTRACT ICON "resources/2.ico"
 IDI_VOLUME  ICON "resources/3.ico"
 IDI_VOLMUTE ICON "resources/4.ico"
 
+IDI_BATTCAP0 ICON "resources/battery/0.ico"
+IDI_BATTCAP1 ICON "resources/battery/1.ico"
+IDI_BATTCAP2 ICON "resources/battery/2.ico"
+IDI_BATTCAP3 ICON "resources/battery/3.ico"
+IDI_BATTCAP4 ICON "resources/battery/4.ico"
+IDI_BATTCAP5 ICON "resources/battery/5.ico"
+
+IDI_BATTCHA0 ICON "resources/battery/charging0.ico"
+IDI_BATTCHA1 ICON "resources/battery/charging1.ico"
+IDI_BATTCHA2 ICON "resources/battery/charging2.ico"
+IDI_BATTCHA3 ICON "resources/battery/charging3.ico"
+IDI_BATTCHA4 ICON "resources/battery/charging4.ico"
+
+IDI_BATTCAP_ERR ICON "resources/battery/error.ico"
+
+IDI_HOTPLUG_ERR ICON "resources/hotplug/0.ico"
+IDI_HOTPLUG_OK ICON  "resources/hotplug/1.ico"
+
+
 IDR_SYSTRAY REGISTRY "resources/rgs/systray.rgs"
 
 #include <reactos/manifest_dll.rc>
diff --git a/dll/shellext/stobject/volume.cpp b/dll/shellext/stobject/volume.cpp
index f82e6e0eee..b7cb3ff049 100644
--- a/dll/shellext/stobject/volume.cpp
+++ b/dll/shellext/stobject/volume.cpp
@@ -113,7 +113,7 @@ static HRESULT __stdcall Volume_FindMixerControl(CSysTray * 
pSysTray)
     return S_OK;
 }
 
-HRESULT Volume_IsMute(VOID)
+HRESULT Volume_IsMute()
 {
 #if 0
     MIXERCONTROLDETAILS mixerControlDetails;
@@ -217,10 +217,10 @@ HRESULT Volume_OnDeviceChange(_In_ CSysTray * pSysTray, 
WPARAM wParam, LPARAM lP
     return Volume_FindMixerControl(pSysTray);
 }
 
-static void _RunVolume(BOOL bSmall)
+static void _RunVolume()
 {
     // FIXME: ensure we are loading the right one
-    ShellExecuteW(NULL, NULL, L"sndvol32.exe", bSmall ? L"/t" : NULL, NULL, 
SW_SHOWNORMAL);
+    ShellExecuteW(NULL, NULL, L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL);
 }
 
 static void _RunMMCpl()
@@ -238,14 +238,14 @@ static void _ShowContextMenu(CSysTray * pSysTray)
     HMENU hPopup = CreatePopupMenu();
     AppendMenuW(hPopup, MF_STRING, IDS_VOL_OPEN, strOpen);
     AppendMenuW(hPopup, MF_STRING, IDS_VOL_ADJUST, strAdjust);
-    SetMenuDefaultItem(hPopup, IDS_VOL_OPEN, FALSE);
 
     DWORD flags = TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTALIGN | 
TPM_BOTTOMALIGN;
-    DWORD msgPos = GetMessagePos();
-
+    POINT pt;
     SetForegroundWindow(pSysTray->GetHWnd());
+    GetCursorPos(&pt);
+
     DWORD id = TrackPopupMenuEx(hPopup, flags,
-        GET_X_LPARAM(msgPos), GET_Y_LPARAM(msgPos),
+        pt.x, pt.y,
         pSysTray->GetHWnd(), NULL);
 
     DestroyMenu(hPopup);
@@ -253,7 +253,7 @@ static void _ShowContextMenu(CSysTray * pSysTray)
     switch (id)
     {
     case IDS_VOL_OPEN:
-        _RunVolume(FALSE);
+        _RunVolume();
         break;
     case IDS_VOL_ADJUST:
         _RunMMCpl();
@@ -296,15 +296,14 @@ HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * 
pSysTray, UINT uMsg, WP
             switch (lParam)
             {
                 case WM_LBUTTONDOWN:
-                    SetTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID, 500, NULL);
                     break;
 
                 case WM_LBUTTONUP:
+                    TRACE("TODO: display volume slider\n");
                     break;
 
                 case WM_LBUTTONDBLCLK:
-                    KillTimer(pSysTray->GetHWnd(), VOLUME_TIMER_ID);
-                    _RunVolume(FALSE);
+                    _RunVolume();
                     break;
 
                 case WM_RBUTTONDOWN:
@@ -329,11 +328,3 @@ HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * 
pSysTray, UINT uMsg, WP
 
     return S_FALSE;
 }
-
-VOID
-Volume_OnTimer(HWND hWnd)
-{
-    TRACE("Volume_OnTimer\n!");
-    KillTimer(hWnd, VOLUME_TIMER_ID);
-    _RunVolume(TRUE);
-}

Reply via email to