Skip to content

Commit

Permalink
[STOBJECT] Improvements to the power notification icon
Browse files Browse the repository at this point in the history
- Use GetSystemPowerStatus() instead of querying each battery.
- Add an ugly AC power icon. Should be fixed or replaced.
- Display AC power, battery charging, battery depleting and error cases. The AC power case was missing.
- Update some strings because we are no longer using float for the charge percentage.

@Turkish translators: Please check and update the translation of IDS_PWR_CHARGING!
  • Loading branch information
EricKohl committed Apr 19, 2019
1 parent 0263151 commit 453e5bc
Show file tree
Hide file tree
Showing 17 changed files with 59 additions and 176 deletions.
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/cs-CZ.rc
Expand Up @@ -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á %.2f%%"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "zbývá %u%%"
IDS_PWR_CHARGING "%u%% 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!%%)"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/de-DE.rc
Expand Up @@ -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 "%.2f%% verbleibend"
IDS_PWR_CHARGING "%.2f%% und wird geladen"
IDS_PWR_PERCENT_REMAINING "%u%% verbleibend"
IDS_PWR_CHARGING "%u%% und wird geladen"
IDS_PWR_UNKNOWN_REMAINING "Unbekannt verbleibend"
IDS_PWR_AC "Mit Wechselstrom"
IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! Stunden (%3!u!%%) verbleibend"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/en-US.rc
Expand Up @@ -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 "%.2f%% remaining"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "%u%% remaining"
IDS_PWR_CHARGING "%u%% 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"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/es-ES.rc
Expand Up @@ -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 %.2f%%"
IDS_PWR_CHARGING "%.2f%% y cargando"
IDS_PWR_PERCENT_REMAINING "Queda un %u%%"
IDS_PWR_CHARGING "%u%% y cargando"
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!%%)"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/fr-FR.rc
Expand Up @@ -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 "%.2f%% remaining"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "%u%% remaining"
IDS_PWR_CHARGING "%u%% 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"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/hi-IN.rc
Expand Up @@ -25,8 +25,8 @@ BEGIN
IDS_PWR_PROPERTIES "पावर &गुण समायोजित करें"
IDS_PWR_METER "पावर मीटर &खोलें"
IDS_PWR_RUN "shell32.dll,Control_RunDLL PowerCfg.cpl"
IDS_PWR_PERCENT_REMAINING "%.2f%% शेष"
IDS_PWR_CHARGING "%.2f%% और चार्ज"
IDS_PWR_PERCENT_REMAINING "%u%% शेष"
IDS_PWR_CHARGING "%u%% और चार्ज"
IDS_PWR_UNKNOWN_REMAINING "अज्ञात शेष"
IDS_PWR_AC "On AC power"
IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! घंटे (%3!u!%%) शेष"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/it-IT.rc
Expand Up @@ -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 "%.2f%% rimanenti"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "%u%% rimanenti"
IDS_PWR_CHARGING "%u%% 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"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/pl-PL.rc
Expand Up @@ -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 %.2f%%"
IDS_PWR_CHARGING "%.2f%% i ładuje"
IDS_PWR_PERCENT_REMAINING "Pozostało %u%%"
IDS_PWR_CHARGING "%u%% i ładuje"
IDS_PWR_UNKNOWN_REMAINING "Stan naładowania nieznany"
IDS_PWR_AC "Podłączony do zasilania"
IDS_PWR_HOURS_REMAINING "Pozostało %1!u!:%2!02u! godzin (%3!u!%%)"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/ro-RO.rc
Expand Up @@ -20,8 +20,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 %.2f%%"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "Au mai rămas %u%%"
IDS_PWR_CHARGING "%u%% 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!%%)"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/ru-RU.rc
Expand Up @@ -20,8 +20,8 @@ BEGIN
IDS_PWR_PROPERTIES "&Настройка параметров электропитания"
IDS_PWR_METER "&Открыть показатели питания"
IDS_PWR_RUN "shell32.dll,Control_RunDLL PowerCfg.cpl"
IDS_PWR_PERCENT_REMAINING "%.2f%% осталось"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "%u%% осталось"
IDS_PWR_CHARGING "%u%% and charging"
IDS_PWR_UNKNOWN_REMAINING "Неизвестно"
IDS_PWR_AC "От сети переменного тока"
IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! часов (%3!u!%%) осталось"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/tr-TR.rc
Expand Up @@ -20,8 +20,8 @@ BEGIN
IDS_PWR_PROPERTIES "&Güç Özelliklerini Düzenle"
IDS_PWR_METER "G&üç Ölçücüsünü Aç"
IDS_PWR_RUN "shell32.dll,Control_RunDLL PowerCfg.cpl"
IDS_PWR_PERCENT_REMAINING "%%%1!u! kaldı."
IDS_PWR_CHARGING " (Yükleniyor)"
IDS_PWR_PERCENT_REMAINING "%%%u kaldı."
IDS_PWR_CHARGING "%%%u (Yükleniyor)"
IDS_PWR_UNKNOWN_REMAINING "Bilinmeyen kalan."
IDS_PWR_AC "Dalgalı akımda."
IDS_PWR_HOURS_REMAINING "%1!u!.%2!02u! saat (%%%3!u!) kalan"
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/zh-CN.rc
Expand Up @@ -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 "剩余 %.2f%%"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "剩余 %u%%"
IDS_PWR_CHARGING "%u%% and charging"
IDS_PWR_UNKNOWN_REMAINING "未知剩余"
IDS_PWR_AC "交流电源"
IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! 小时 剩余 (%3!u!%%) "
Expand Down
4 changes: 2 additions & 2 deletions dll/shellext/stobject/lang/zh-TW.rc
Expand Up @@ -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 "剩餘 %.2f%%"
IDS_PWR_CHARGING "%.2f%% and charging"
IDS_PWR_PERCENT_REMAINING "剩餘 %u%%"
IDS_PWR_CHARGING "%u%% and charging"
IDS_PWR_UNKNOWN_REMAINING "未知剩餘"
IDS_PWR_AC "交流電源"
IDS_PWR_HOURS_REMAINING "%1!u!:%2!02u! 小時 剩餘 (%3!u!%%) "
Expand Down
181 changes: 31 additions & 150 deletions dll/shellext/stobject/power.cpp
Expand Up @@ -16,9 +16,6 @@
#include <windows.h>
#include <batclass.h>

#define GBS_HASBATTERY 0x1
#define GBS_ONBATTERY 0x2

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.

Expand All @@ -30,126 +27,9 @@ typedef struct _PWRSCHEMECONTEXT
} 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;

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
Expand All @@ -158,31 +38,29 @@ static HRESULT GetBatteryState(float& cap, DWORD& dwResult)
*
* @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)
{
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)
*/
*--*/
static UINT Quantize(BYTE p)
{
if (p <= 12)
return 0;
else if (p > 12 && p <= 37)
return 1;
else if (p > 37 && p <= 62)
return 2;
else if (p > 62 && p <= 87)
return 3;
else
return 4;
}

/*++
Expand All @@ -198,35 +76,38 @@ static UINT Quantize(float p, UINT lvl = 10)
*
*--*/
static HICON DynamicLoadIcon(HINSTANCE hinst)
{
{
SYSTEM_POWER_STATUS PowerStatus;
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
if (!GetSystemPowerStatus(&PowerStatus) ||
PowerStatus.ACLineStatus == AC_LINE_UNKNOWN ||
PowerStatus.BatteryFlag == BATTERY_FLAG_UNKNOWN)
{
g_batCap = 0;
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_BATTCAP_ERR));
g_strTooltip.LoadStringW(IDS_PWR_UNKNOWN_REMAINING);
return hBatIcon;
}

if (dw & GBS_ONBATTERY)
if (((PowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0) &&
((PowerStatus.BatteryFlag & BATTERY_FLAG_CHARGING) == BATTERY_FLAG_CHARGING))
{
index = Quantize(PowerStatus.BatteryLifePercent);
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(bc_icons[index]));
g_strTooltip.Format(IDS_PWR_CHARGING, PowerStatus.BatteryLifePercent);
}
else if (((PowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0) &&
((PowerStatus.BatteryFlag & BATTERY_FLAG_CHARGING) == 0))
{
index = Quantize(PowerStatus.BatteryLifePercent);
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(br_icons[index]));
g_strTooltip.Format(IDS_PWR_PERCENT_REMAINING, cap);
g_strTooltip.Format(IDS_PWR_PERCENT_REMAINING, PowerStatus.BatteryLifePercent);
}
else
{
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(bc_icons[index]));
g_strTooltip.Format(IDS_PWR_CHARGING, cap);
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_POWER_AC));
g_strTooltip.LoadStringW(IDS_PWR_AC);
}

return hBatIcon;
Expand Down
1 change: 1 addition & 0 deletions dll/shellext/stobject/resource.h
Expand Up @@ -51,6 +51,7 @@
#define IDI_BATTCHA3 409
#define IDI_BATTCHA4 410
#define IDI_BATTCAP_ERR 412
#define IDI_POWER_AC 413

#define IDI_HOTPLUG_ERR 420
#define IDI_HOTPLUG_OK 421
Expand Down
Binary file added dll/shellext/stobject/resources/battery/ac.ico
Binary file not shown.
1 change: 1 addition & 0 deletions dll/shellext/stobject/stobject.rc
Expand Up @@ -25,6 +25,7 @@ IDI_BATTCHA3 ICON "resources/battery/charging3.ico"
IDI_BATTCHA4 ICON "resources/battery/charging4.ico"

IDI_BATTCAP_ERR ICON "resources/battery/error.ico"
IDI_POWER_AC ICON "resources/battery/ac.ico"

IDI_HOTPLUG_ERR ICON "resources/hotplug/0.ico"
IDI_HOTPLUG_OK ICON "resources/hotplug/1.ico"
Expand Down

0 comments on commit 453e5bc

Please sign in to comment.