|
|
|
|
@ -14,14 +14,11 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
|
|
|
|
#define TRAY_ICON_ID 1001
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
int width;
|
|
|
|
|
int height;
|
|
|
|
|
int refresh;
|
|
|
|
|
DWORD width;
|
|
|
|
|
DWORD height;
|
|
|
|
|
DWORD refresh;
|
|
|
|
|
} DISPLAY_MODE;
|
|
|
|
|
|
|
|
|
|
static DISPLAY_MODE modeBatt = { 0 };
|
|
|
|
|
static DISPLAY_MODE modeAC = { 0 };
|
|
|
|
|
|
|
|
|
|
BOOL DisplayModeEquals(const DISPLAY_MODE* a, const DISPLAY_MODE* b) {
|
|
|
|
|
return a->width == b->width && a->height == b->height && a->refresh == b->refresh;
|
|
|
|
|
}
|
|
|
|
|
@ -29,9 +26,8 @@ BOOL DisplayModeEquals(const DISPLAY_MODE* a, const DISPLAY_MODE* b) {
|
|
|
|
|
#define MODE_SELECTED(mode) (!DisplayModeEquals(&mode, &(DISPLAY_MODE) { 0 }))
|
|
|
|
|
|
|
|
|
|
// I hate parsing the string here, but the alternative requires extra memory management.
|
|
|
|
|
static DISPLAY_MODE GetModeFromCB(HWND hDlg, int nIDDlgItem) {
|
|
|
|
|
static DISPLAY_MODE GetModeFromCB(HWND hComboBox) {
|
|
|
|
|
DISPLAY_MODE mode = { 0 };
|
|
|
|
|
HWND hComboBox = GetDlgItem(hDlg, nIDDlgItem);
|
|
|
|
|
size_t selectedIndex = SendMessage(hComboBox, CB_GETCURSEL, 0, 0);
|
|
|
|
|
if (selectedIndex != CB_ERR) {
|
|
|
|
|
LRESULT len = SendMessage(hComboBox, CB_GETLBTEXTLEN, selectedIndex, 0);
|
|
|
|
|
@ -125,12 +121,96 @@ static void TestDisplayMode(HWND hDlg, DISPLAY_MODE* mode) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
DISPLAY_MODE modeBatt;
|
|
|
|
|
DISPLAY_MODE modeAC;
|
|
|
|
|
DWORD disableBatteryWarning;
|
|
|
|
|
BOOL runAtStartup;
|
|
|
|
|
} WINPOWERDMS_PREFS;
|
|
|
|
|
|
|
|
|
|
static WINPOWERDMS_PREFS userPrefs = { 0 };
|
|
|
|
|
|
|
|
|
|
// Save user preferences to registry.
|
|
|
|
|
static BOOL SavePrefs(void) {
|
|
|
|
|
BOOL saved = FALSE;
|
|
|
|
|
|
|
|
|
|
HKEY regKey;
|
|
|
|
|
if (!RegCreateKeyEx(
|
|
|
|
|
HKEY_CURRENT_USER, L"SOFTWARE\\WinPowerDMS", 0, NULL,
|
|
|
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, ®Key, NULL
|
|
|
|
|
)) {
|
|
|
|
|
RegSetKeyValue(regKey, L"Battery", L"Width", REG_DWORD, &userPrefs.modeBatt.width, sizeof(userPrefs.modeBatt.width));
|
|
|
|
|
RegSetKeyValue(regKey, L"Battery", L"Height", REG_DWORD, &userPrefs.modeBatt.height, sizeof(userPrefs.modeBatt.height));
|
|
|
|
|
RegSetKeyValue(regKey, L"Battery", L"Refresh Rate", REG_DWORD, &userPrefs.modeBatt.refresh, sizeof(userPrefs.modeBatt.refresh));
|
|
|
|
|
RegSetKeyValue(regKey, L"AC Power", L"Width", REG_DWORD, &userPrefs.modeAC.width, sizeof(userPrefs.modeAC.width));
|
|
|
|
|
RegSetKeyValue(regKey, L"AC Power", L"Height", REG_DWORD, &userPrefs.modeAC.height, sizeof(userPrefs.modeAC.height));
|
|
|
|
|
RegSetKeyValue(regKey, L"AC Power", L"Refresh Rate", REG_DWORD, &userPrefs.modeAC.refresh, sizeof(userPrefs.modeAC.refresh));
|
|
|
|
|
RegSetValueEx(regKey, L"Disable Battery Warning", 0, REG_DWORD, &userPrefs.disableBatteryWarning, sizeof(userPrefs.disableBatteryWarning));
|
|
|
|
|
RegCloseKey(regKey);
|
|
|
|
|
saved = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the startup entry
|
|
|
|
|
if (userPrefs.runAtStartup) {
|
|
|
|
|
WCHAR exePath[MAX_PATH];
|
|
|
|
|
DWORD exePathLen = GetModuleFileName(NULL, exePath, sizeof(exePath) / sizeof(exePath[0])) + 1;
|
|
|
|
|
RegSetKeyValue(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", L"WinPowerDMS", REG_SZ, exePath, exePathLen);
|
|
|
|
|
}
|
|
|
|
|
else { // Delete the startup entry
|
|
|
|
|
RegDeleteKeyValue(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", L"WinPowerDMS");
|
|
|
|
|
}
|
|
|
|
|
return saved;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load user preferences from registry.
|
|
|
|
|
static BOOL LoadPrefs(void) {
|
|
|
|
|
BOOL loaded = FALSE;
|
|
|
|
|
|
|
|
|
|
HKEY regKey;
|
|
|
|
|
if (!RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\WinPowerDMS", 0, KEY_READ, ®Key)) {
|
|
|
|
|
DWORD keySize = sizeof(userPrefs.modeBatt.width);
|
|
|
|
|
RegGetValue(regKey, L"Battery", L"Width", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.width, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.modeBatt.height);
|
|
|
|
|
RegGetValue(regKey, L"Battery", L"Height", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.height, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.modeBatt.refresh);
|
|
|
|
|
RegGetValue(regKey, L"Battery", L"Refresh Rate", RRF_RT_REG_DWORD, NULL, &userPrefs.modeBatt.refresh, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.modeAC.width);
|
|
|
|
|
RegGetValue(regKey, L"AC Power", L"Width", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.width, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.modeAC.height);
|
|
|
|
|
RegGetValue(regKey, L"AC Power", L"Height", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.height, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.modeAC.refresh);
|
|
|
|
|
RegGetValue(regKey, L"AC Power", L"Refresh Rate", RRF_RT_REG_DWORD, NULL, &userPrefs.modeAC.refresh, &keySize);
|
|
|
|
|
keySize = sizeof(userPrefs.disableBatteryWarning);
|
|
|
|
|
RegGetValue(regKey, NULL, L"Disable Battery Warning", RRF_RT_REG_DWORD, NULL, &userPrefs.disableBatteryWarning, &keySize);
|
|
|
|
|
RegCloseKey(regKey);
|
|
|
|
|
loaded = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Figure out if application has a startup entry
|
|
|
|
|
if (!RegGetValue(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", L"WinPowerDMS", RRF_RT_ANY, NULL, NULL, NULL))
|
|
|
|
|
userPrefs.runAtStartup = TRUE;
|
|
|
|
|
|
|
|
|
|
return loaded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DISPLAY_MODE GetCurrentDisplayMode(void) {
|
|
|
|
|
DEVMODE currentMode = { .dmSize = sizeof(currentMode) };
|
|
|
|
|
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, ¤tMode);
|
|
|
|
|
return (DISPLAY_MODE) {
|
|
|
|
|
.width = currentMode.dmPelsWidth,
|
|
|
|
|
.height = currentMode.dmPelsHeight,
|
|
|
|
|
.refresh = currentMode.dmDisplayFrequency
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
|
|
|
HWND hComboBatt = GetDlgItem(hDlg, IDC_COMBO_BATT);
|
|
|
|
|
HWND hComboAC = GetDlgItem(hDlg, IDC_COMBO_AC);
|
|
|
|
|
HWND hCheckBattWarning = GetDlgItem(hDlg, IDC_CHECK_BATT_WARNING);
|
|
|
|
|
HWND hCheckStartup = GetDlgItem(hCheckBattWarning, IDC_CHECK_STARTUP);
|
|
|
|
|
|
|
|
|
|
switch (message) {
|
|
|
|
|
case WM_INITDIALOG: {
|
|
|
|
|
HWND hComboBatt = GetDlgItem(hDlg, IDC_COMBO_BATT);
|
|
|
|
|
HWND hComboAC = GetDlgItem(hDlg, IDC_COMBO_AC);
|
|
|
|
|
|
|
|
|
|
// devMode object that will be enumerated
|
|
|
|
|
DEVMODE devMode;
|
|
|
|
|
ZeroMemory(&devMode, sizeof(devMode));
|
|
|
|
|
@ -154,11 +234,11 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam,
|
|
|
|
|
|
|
|
|
|
// Add to both combo boxes and check if this is the mode that was set.
|
|
|
|
|
SendMessage(hComboBatt, CB_ADDSTRING, 0, (LPARAM)resText);
|
|
|
|
|
if (DisplayModeEquals(&modeBatt, ¤tMode))
|
|
|
|
|
if (DisplayModeEquals(&userPrefs.modeBatt, ¤tMode))
|
|
|
|
|
SendMessage(hComboBatt, CB_SETCURSEL, modeCount, 0);
|
|
|
|
|
|
|
|
|
|
SendMessage(hComboAC, CB_ADDSTRING, 0, (LPARAM)resText);
|
|
|
|
|
if (DisplayModeEquals(&modeAC, ¤tMode))
|
|
|
|
|
if (DisplayModeEquals(&userPrefs.modeAC, ¤tMode))
|
|
|
|
|
SendMessage(hComboAC, CB_SETCURSEL, modeCount, 0);
|
|
|
|
|
|
|
|
|
|
++modeCount;
|
|
|
|
|
@ -166,9 +246,8 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// select the highest display mode if one hasn't been selected yet
|
|
|
|
|
if (!MODE_SELECTED(modeBatt)) SendMessage(hComboBatt, CB_SETCURSEL, modeCount - 1, 0);
|
|
|
|
|
if (!MODE_SELECTED(modeAC)) SendMessage(hComboAC, CB_SETCURSEL, modeCount - 1, 0);
|
|
|
|
|
SendMessage(hCheckBattWarning, BM_SETCHECK, userPrefs.disableBatteryWarning ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
|
SendMessage(hCheckStartup, BM_SETCHECK, userPrefs.runAtStartup ? BST_CHECKED : BST_UNCHECKED, 0);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -176,8 +255,11 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam,
|
|
|
|
|
switch (LOWORD(wParam)) {
|
|
|
|
|
case IDC_BUTTON_APPLY:
|
|
|
|
|
case IDOK: {
|
|
|
|
|
modeBatt = GetModeFromCB(hDlg, IDC_COMBO_BATT);
|
|
|
|
|
modeAC = GetModeFromCB(hDlg, IDC_COMBO_AC);
|
|
|
|
|
userPrefs.modeBatt = GetModeFromCB(hComboBatt);
|
|
|
|
|
userPrefs.modeAC = GetModeFromCB(hComboAC);
|
|
|
|
|
userPrefs.disableBatteryWarning = SendMessage(hCheckBattWarning, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
|
userPrefs.runAtStartup = SendMessage(hCheckStartup, BM_GETCHECK, 0, 0) == BST_CHECKED;
|
|
|
|
|
SavePrefs();
|
|
|
|
|
if (LOWORD(wParam) == IDC_BUTTON_APPLY) return TRUE;
|
|
|
|
|
}
|
|
|
|
|
case IDCANCEL: {
|
|
|
|
|
@ -185,12 +267,12 @@ static INT_PTR CALLBACK PrefsDialogProc(HWND hDlg, UINT message, WPARAM wParam,
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
case IDC_BUTTON_TEST_BATT: {
|
|
|
|
|
DISPLAY_MODE mode = GetModeFromCB(hDlg, IDC_COMBO_BATT);
|
|
|
|
|
DISPLAY_MODE mode = GetModeFromCB(hComboBatt);
|
|
|
|
|
TestDisplayMode(hDlg, &mode);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
case IDC_BUTTON_TEST_AC: {
|
|
|
|
|
DISPLAY_MODE mode = GetModeFromCB(hDlg, IDC_COMBO_AC);
|
|
|
|
|
DISPLAY_MODE mode = GetModeFromCB(hComboAC);
|
|
|
|
|
TestDisplayMode(hDlg, &mode);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
@ -208,18 +290,17 @@ enum TRAY_IDS {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static NOTIFYICONDATA nid;
|
|
|
|
|
static HWND hWnd;
|
|
|
|
|
static HMENU hMenu;
|
|
|
|
|
|
|
|
|
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
|
|
|
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
|
|
|
switch (uMsg) {
|
|
|
|
|
case WM_TRAYICON:
|
|
|
|
|
if (lParam == WM_RBUTTONUP) {
|
|
|
|
|
POINT pt;
|
|
|
|
|
GetCursorPos(&pt);
|
|
|
|
|
SetForegroundWindow(hwnd); // Required for menu to disappear correctly
|
|
|
|
|
SetForegroundWindow(hWnd); // Required for menu to disappear correctly
|
|
|
|
|
|
|
|
|
|
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
|
|
|
|
|
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, NULL);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
@ -229,10 +310,10 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|
|
|
|
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_PREFSDIALOG), hWnd, PrefsDialogProc);
|
|
|
|
|
break;
|
|
|
|
|
case ID_TRAY_ABOUT:
|
|
|
|
|
MessageBoxW(NULL, L"WinPowerDMS\nA utility for switching the resolution of your laptop's display based on the current power state.", L"About", MB_OK | MB_ICONINFORMATION);
|
|
|
|
|
MessageBoxW(hWnd, L"WinPowerDMS\nA utility for switching the resolution of your laptop's display based on the current power state.", L"About", MB_OK | MB_ICONINFORMATION);
|
|
|
|
|
break;
|
|
|
|
|
case ID_TRAY_EXIT:
|
|
|
|
|
DestroyWindow(hwnd);
|
|
|
|
|
DestroyWindow(hWnd);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@ -245,19 +326,28 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|
|
|
|
case WM_POWERBROADCAST:
|
|
|
|
|
if (LOWORD(wParam) == PBT_POWERSETTINGCHANGE) {
|
|
|
|
|
OutputDebugString(L"Power status changed\n");
|
|
|
|
|
DISPLAY_MODE currentMode = GetCurrentDisplayMode();
|
|
|
|
|
SYSTEM_POWER_STATUS powerStatus;
|
|
|
|
|
if (GetSystemPowerStatus(&powerStatus)) {
|
|
|
|
|
ChangeDisplayMode(powerStatus.ACLineStatus ? &modeAC : &modeBatt, CDS_UPDATEREGISTRY);
|
|
|
|
|
// Change display mode only if the current display mode is one of the configured options.
|
|
|
|
|
if (GetSystemPowerStatus(&powerStatus) &&
|
|
|
|
|
(DisplayModeEquals(¤tMode, &userPrefs.modeBatt) || DisplayModeEquals(¤tMode, &userPrefs.modeAC)))
|
|
|
|
|
{
|
|
|
|
|
ChangeDisplayMode(powerStatus.ACLineStatus ? &userPrefs.modeAC : &userPrefs.modeBatt, CDS_UPDATEREGISTRY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
|
|
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
|
|
|
|
// Initialize the controls
|
|
|
|
|
InitCommonControls();
|
|
|
|
|
if (!LoadPrefs()) { // set both battery and AC to current display mode if there are no preferences set
|
|
|
|
|
DISPLAY_MODE currentMode = GetCurrentDisplayMode();
|
|
|
|
|
userPrefs.modeAC = currentMode;
|
|
|
|
|
userPrefs.modeBatt = currentMode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InitCommonControls(); // Initialize modern controls
|
|
|
|
|
|
|
|
|
|
WNDCLASS wc = { 0 };
|
|
|
|
|
wc.lpfnWndProc = WindowProc;
|
|
|
|
|
@ -266,9 +356,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|
|
|
|
|
|
|
|
|
RegisterClass(&wc);
|
|
|
|
|
|
|
|
|
|
hWnd = CreateWindowEx(0, L"TrayAppClass", NULL, 0, 0, 0, 0, 0,
|
|
|
|
|
HWND hWnd = CreateWindowEx(0, L"TrayAppClass", NULL, 0, 0, 0, 0, 0,
|
|
|
|
|
HWND_MESSAGE, NULL, hInstance, NULL);
|
|
|
|
|
RegisterPowerSettingNotification(hWnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
|
|
|
|
|
|
|
|
// Check if there is a battery in the system and display a warning message if there isn't one.
|
|
|
|
|
SYSTEM_POWER_STATUS powerStatus;
|
|
|
|
|
if (!userPrefs.disableBatteryWarning && GetSystemPowerStatus(&powerStatus) && powerStatus.BatteryFlag == 128)
|
|
|
|
|
MessageBox(hWnd, L"There is no battery present in the system. The program will start and set your display mode to what you have set for AC power, but do nothing else afterwards.", L"WinPowerDMS", MB_OK | MB_ICONWARNING);
|
|
|
|
|
|
|
|
|
|
// Create context menu
|
|
|
|
|
hMenu = CreatePopupMenu();
|
|
|
|
|
|