From 7fbc5f42302be64db4d3383060e3c14bcc1dfac6 Mon Sep 17 00:00:00 2001 From: Shriraj Sawant Date: Mon, 16 Oct 2017 17:11:10 +0300 Subject: [PATCH] [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 .../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(-) create mode 100644 dll/shellext/stobject/resources/battery/0.ico create mode 100644 dll/shellext/stobject/resources/battery/1.ico create mode 100644 dll/shellext/stobject/resources/battery/2.ico create mode 100644 dll/shellext/stobject/resources/battery/3.ico create mode 100644 dll/shellext/stobject/resources/battery/4.ico create mode 100644 dll/shellext/stobject/resources/battery/5.ico create mode 100644 dll/shellext/stobject/resources/battery/charging0.ico create mode 100644 dll/shellext/stobject/resources/battery/charging1.ico create mode 100644 dll/shellext/stobject/resources/battery/charging2.ico create mode 100644 dll/shellext/stobject/resources/battery/charging3.ico create mode 100644 dll/shellext/stobject/resources/battery/charging4.ico create mode 100644 dll/shellext/stobject/resources/battery/error.ico create mode 100644 dll/shellext/stobject/resources/hotplug/0.ico create mode 100644 dll/shellext/stobject/resources/hotplug/1.ico diff --git a/dll/shellext/stobject/CMakeLists.txt b/dll/shellext/stobject/CMakeLists.txt index 2fa34e61446..341fe672ae2 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 8551fbcf233..e4a2afe4035 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 +* Shriraj Sawant a.k.a SR13 */ #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 04f7c1e2920..b95cd65577f 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 + * Shriraj Sawant a.k.a SR13 */ #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 fbc22ea0780..4b17a1baf27 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 - * David Quintana + * PURPOSE: Removable devices notification icon handler + * PROGRAMMERS: Shriraj Sawant a.k.a SR13 */ - +#include #include "precomp.h" +#include +#include +#include +#include +#include +#include +#include WINE_DEFAULT_DEBUG_CHANNEL(stobject); +#define DISPLAY_NAME_LEN 40 + +//BOOL WINAPI UnregisterDeviceNotification(HDEVNOTIFY Handle); +CSimpleArray 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 &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 84fe3d4fb11..57ec1bca55e 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 1563baf1729..cdb3aa2d48d 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 e10c25c3cc8..ea1f17ffcd2 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 c7a3d0d6b22..ac008f2dd9b 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 273cb83b896..de393af36f3 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 a4d715427c8..628466edbe1 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 0a2889edc46..def32499469 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 0de2e8de7cd..bb19bd1d74a 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 572f1613fd6..af307d3024b 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 6ba1f37f4bd..1d402493d04 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 35ae8c4a6f5..3d9a5265b8c 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 24b5feb4162..5853b2bdbf3 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 + Shriraj Sawant a.k.a SR13 * David Quintana */ +#include +#include +#include +#include + #include "precomp.h" #include "powrprof.h" +#include +#include +#include + +#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 fd2ea78836a..64824ba8254 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 2637a12aeaf..a7466f77d31 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 0000000000000000000000000000000000000000..1610499aa35496aff49d5019872e808f08f4a8ca GIT binary patch literal 9062 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 E0n%bsPyhe` literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/2.ico b/dll/shellext/stobject/resources/battery/2.ico new file mode 100644 index 0000000000000000000000000000000000000000..f1dc98aa7fc4f71154019714c951b665c5a58347 GIT binary patch literal 9062 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 literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/4.ico b/dll/shellext/stobject/resources/battery/4.ico new file mode 100644 index 0000000000000000000000000000000000000000..edc24a071e93fe13cd934586a52dfd7185c49494 GIT binary patch literal 9062 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 literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/5.ico b/dll/shellext/stobject/resources/battery/5.ico new file mode 100644 index 0000000000000000000000000000000000000000..cd4e3b8ee791bea614e39e8c659ffc790b8731eb GIT binary patch literal 9062 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 T`kc8(`(m~~+Sb6%&_?|ecUA65 literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/charging0.ico b/dll/shellext/stobject/resources/battery/charging0.ico new file mode 100644 index 0000000000000000000000000000000000000000..75041624234d4460e66829f57259fc2b156d005b GIT binary patch literal 2550 zcmeHJTT4_?6#nL@qgk1D8SOq=nOz*6lNw!Kf_f;T0txFeDv}E7rMIBzB?!VIN`mM@ z66Q-P5_E+@Q87?3BWvn%s4j9PJ z2KNk9rvZgP)OMpf6{w-FNPL8wkho;aIC>pEpARYAFSq@~?Y=OSQh54q1eJH+;zjT; zUJr)RJTQ)ea}Ut_!@}c$h0~1#I8)z)o2`SWuIs|trU5jz_u=733$^bpT0d{+VOHEYFQw%lbeI#!6i zc!|rEo0qrLMF(v-=4UO)&dFK0NK(iJ9O)TzGBfASb4G1AQc}~>Qh6LXmk=)Sh6cuR zfgnA8!WR#w_DusneL>~S_n;sor0No~nfY?>b7vQH}ZNjsi>eiDBsTlm6d|4qu*b?9B^OUBo+ zvTNu&O~+^dSM2|>`XwgWioRv6e$A(T#B%80jo&4w=1Tq4N&EiseCkguhr|nCFX0MD zxU%G%+NP*&irS{AZHn5asBLx*iI*k2fOp D)Zhzp literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/charging1.ico b/dll/shellext/stobject/resources/battery/charging1.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a6210c19a17e191e8e817b0f1371cbdea9c2bd1 GIT binary patch literal 2550 zcmeHJTS!z<6kT)G(d=cf>0N4NPqn$JmGu+UM-dfBSf5dmR8T+t1x-Iu5EYdYL=TcM zp|Y@|Ck!Jd1{qfLFh7RMB8i9~N}IX6wXbuAaWd&Y4=m2z=j^rToCCAg20XBkl?Bcj zs7M3yfLNT3id5hT*JkM&kxgh`f5X~%6oEhhDV+B=d_m>2C`1HTpLU|`^dsB}|HA#Z zQCx5DLhi0}X#MQqVw;2Qb?w+u(}Lrnx2ULY#?EW)sB3(N^RFCKJ$G=R=^OUkeviEm zKH*_UH|oO<>RUhHWXpHdwngx`Gm21$gPJ!E&b)MR_+A^ztAaT8_&W+}x^U@r1Wg|u zG<qT|2&!L3QGPdyU@(ZX^7U9-{{#D)Be-(&7LHY(z`+|& zP<#0bf}s#LZ`+E}m1|JEd{uu>F|arA0{`C&EU|6NUP@JQhh1t}mOlo-UbNWqGVTHF z;*y2#x8GfZJ#RsgjT`Ud0%LfF4jY~|V#LT%T0$@2NzWLR znK^ifHx|Q_lA4y5%I%(gP2m7nZkqM-h|Gxh2E{33g|#;lZ{RLzrD;4jg9>Y2;YJOwqd-&pJ9+jfC+sfi9X z(aopM_u~I8R=#qntr2RgP+R-tn{$}i)H8hQw@{~rIvwYmT%8Tfo%-Ta|AqP==W9-X zBlec=`Ste=pZ*cAVSYDp)|!T^=ci9fGN1kvuc7(MH$%C~QLYaCrnd>bP3UbxZxec( z(A(S^ny*7=1^w<1KD|@uokH&vdZ*AkgH_Yus0F*CN9{Y2>TPI^?Hj$zJ8OxTF=FPN7(NO`yChht!Fpq nH+7QvCT5L7Jxc=Gbj{Q-v*w3WlJtdZ0R?sBZ!lW(lR3Wumi`qe literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/charging2.ico b/dll/shellext/stobject/resources/battery/charging2.ico new file mode 100644 index 0000000000000000000000000000000000000000..7c1c919a352b5f999448b863ccbd95ed44ff9e30 GIT binary patch literal 2550 zcmeHJS7;Pb6g@jh)~>OwvBwsBbjR3x`%pv$k?5zW7*x<7{{+_`Q4kGwjSX9jm>7wQ z6@~capbkHU+=M3x_xN%{_PDJlJzC;Dd$KRB&yHoD?7f zsLRullML+Q-Vog*(h03=F0AFd5ekKn#C2=gSL}Zlg@~Z&X%&{_J;06dZ`^(x#pTLs z^xtp-PrkS~Tj65urAn;Je}p}yZ;^Al9P5iKap~?eoP6ctz;hSd?tjOo>+iAo&S%{F zP=k`Ni;^cFvG36j6jVg;uquku4=(cGxH$IG#m-w5$Ufj8_u&s@=2zqV>j>_Da#8lt zh4ZcktB&8rj+PZlI*1@xb9$4$xm!4k6?3o6z7VHk-L8{ zwqJRSvxP-Cn0Ewc&gY}>>NQ*_x`@Naj-udVA)L}utX#7iljbeN*g5l?yQ=^1{@=jA zcLTF++p_0SRlKlgS(X*717OdXY5AGg0`}Bt)4k`Qw+DOD6_j!(4YB$ftvT|8SsJ| zy)^IAH4x~QmexJM4d(E*Yu_QYW5-UNwS|6wuSLsNty{Ng>#xh)M23x3w1cgH?_JNm~TqtQ`3c-F4XiGUu&9+y1VqwPmd6KgwP{|9uezd zem8#Ao`$REr%wv~N9aF7{}K9+(0^h*v|jlpl&c)&YUne)P3UbxZxec((A$LG=Jn8e z4P6!Vy9RuEr_eiv-YN7>p?3Ob@eaeK;vWU$_@iP)C}A(VAbZ`2zu_Bjf-8 literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/battery/charging3.ico b/dll/shellext/stobject/resources/battery/charging3.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb92ab621303ea1c0f5518ce49a1573b2f7cd819 GIT binary patch literal 2550 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 literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/hotplug/0.ico b/dll/shellext/stobject/resources/hotplug/0.ico new file mode 100644 index 0000000000000000000000000000000000000000..83025a942d16ee34744ad68b470ca303e190c865 GIT binary patch literal 2550 zcmeHJOGs2v82;|$q)w$~Sw2dqv6q!S?CE3F+4)$wHzF4aLQp|OxGNIIp_)ZZMNg6z zLFp){xKc2|$M_lrb)%5Tgjk@^rj>u+IX1(fy@uN558wRvKmYmeIrrYV-**86CL|<) zIR-UmU_bD^wxT8qaC7XS8Y8TPn)j=?eC-PSem{nWhA=uhiiU;;3=R%rWMqW2diZ=k zSS(MFmDP>t=!a3>>ME9g~`cDT)%k(u6uWplF|&XH-NFRF;rDmp}F}ZQd3(nJUoo~ z`FYO2kIKp^1OlHiJ3GsMGtQr%!pzJJrl+SdF)@Mo_zv{;e!}A7A}T5>(AW2gyhq&U z1X@}a(B8hl9KfqrlN|RDEkql!9_x4DKfMD*#g3IIE;3Z)=H(aI3+)B@dAY`koSdAK zr%sqy$Mb4OBgieYSt(-EJrH6cDOk@L+fVcE3VY*zg5wK;|d;k6pyXc$q!{!eOC zcx=#@6aKUM34dKZ5J63;Tcxws2-s?>XPo-Ov$XvJs_z-6M&BYN92Uz1p{@yaO{igqIlFvp-zTSTiYs$i5)_{6zZkW1B9BXv#P0`x?fOKtJkFt3w2zm z=^B3jv^X4Zgc>Z=WT7StHCbm>t8u&iwNzcYs`>O2&8OZA^58-e)UPxJ4ztCHR-XioCT{|2vh5i!a)1PQhYon*<1J`O2 zdX~_$bhcXGN>h_h=v^T`eNX6nYjCH|DTPIKQdsz2=!H6~T8+~eLwvP=dg~A2c0U)J z?WxdXB_rdpxZTh6JbLdR@zr^&t3AAz_jL}g6A3@a3D5iv2(8a=gCFiaeE#a=f5}(> d&q%>L;7UKW_ literal 0 HcmV?d00001 diff --git a/dll/shellext/stobject/resources/hotplug/1.ico b/dll/shellext/stobject/resources/hotplug/1.ico new file mode 100644 index 0000000000000000000000000000000000000000..f615f0ebd3cc0b9c8a07200455a8e89ae38abcb6 GIT binary patch literal 2550 zcmeHJ&1(}u9DS{uw$^H*#`mo_p$%D84QCSx!rVi=gc3?n|m_YsVxlSmgo!o&CJPcQHw z_XhsNIXwIN9+wtVc=_!EZrr+wp}8x#xHyAIdK`}m859ZybUeR+=`XJ^KR=JLw@LVJ zpT$fng@sH8q4;^6esT>;DO9UfB<`C?zI%!@sjJ9lvzSWULq4BJ{LUmE&dp+S>MnA* z9LnV~DwPUKr4ow8B9@nzn{8>UZ|elMPN2mT@HRjs-l1qTIy@XAyi)fM1P2Erk;q^$ zsOyuVVE7afuGN9#CxSKT{v$_?V;X&ZQhN^c8isN35OJ7w*Y@sS!q`vvz1Y#yy^pYJ zU(fD6g1v@cp!;_cyNvZ8sr8)%eXa&iM diff --git a/dll/shellext/stobject/volume.cpp b/dll/shellext/stobject/volume.cpp index f82e6e0eeeb..b7cb3ff049c 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); -} -- 2.17.1