Implement resolution and color depth selection.

Applying new settings doesn't work due to unimplemented NtUserChangeDisplaySettings

svn path=/trunk/; revision=14147
This commit is contained in:
Hervé Poussineau 2005-03-16 22:19:12 +00:00
parent 4dde3a1c21
commit 96b374677d
3 changed files with 569 additions and 18 deletions

View file

@ -42,8 +42,20 @@ STYLE DS_SHELLFONT | WS_CHILD | WS_DISABLED | WS_CAPTION
CAPTION "Settings"
FONT 8, "MS Shell Dlg"
BEGIN
LTEXT "This space is intentionally left blank",IDC_STATIC,66,
110,112,8
LTEXT "&Display:",1820,3,140,30,8
LTEXT "<none>",IDC_SETTINGS_DEVICE,9,149,224,8
GROUPBOX "&Screen area",1818,3,160,115,43
CONTROL "",IDC_SETTINGS_RESOLUTION,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,
30,170,58,17
LTEXT "Less",1815,9,170,15,8,NOT WS_GROUP
LTEXT "More",1816,93,170,21,8,NOT WS_GROUP
LTEXT "",IDC_SETTINGS_RESOLUTION_TEXT,10,190,100,10,NOT WS_GROUP
GROUPBOX "&Colors",1817,125,160,115,43
COMBOBOX IDC_SETTINGS_BPP,131,170,103,80,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
WS_VSCROLL | WS_TABSTOP
CONTROL "",1813,"Static",SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN,
131,188,103,9
PUSHBUTTON "Ad&vanced...",IDC_SETTINGS_ADVANCED,306,205,56,14
END
STRINGTABLE

View file

@ -36,5 +36,11 @@
#define IDS_STRETCH 2004
#define IDS_TILE 2005
#define IDC_SETTINGS_DEVICE 201
#define IDC_SETTINGS_BPP 202
#define IDC_SETTINGS_RESOLUTION 203
#define IDC_SETTINGS_RESOLUTION_TEXT 204
#define IDC_SETTINGS_ADVANCED 205
#endif /* __CPL_DESK_RESOURCE_H__ */

View file

@ -6,29 +6,562 @@
* PURPOSE: Settings property page
*
* PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
* Hervé Poussineau (poussine@freesurf.fr)
*/
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <tchar.h>
#include "resource.h"
INT_PTR CALLBACK SettingsPageProc(HWND hwndDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
/* As slider control can't contain user data, we have to keep an
* array of RESOLUTION_INFO to have our own associated data.
*/
typedef struct _RESOLUTION_INFO
{
switch(uMsg)
{
case WM_INITDIALOG:
{
} break;
case WM_COMMAND:
{
} break;
}
return FALSE;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
} RESOLUTION_INFO, *PRESOLUTION_INFO;
typedef struct _SETTINGS_ENTRY
{
struct _SETTINGS_ENTRY *Blink;
struct _SETTINGS_ENTRY *Flink;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
} SETTINGS_ENTRY, *PSETTINGS_ENTRY;
typedef struct _DISPLAY_DEVICE_ENTRY
{
struct _DISPLAY_DEVICE_ENTRY *Flink;
LPTSTR DeviceDescription;
LPTSTR DeviceName;
PSETTINGS_ENTRY Settings; /* sorted by increasing dmPelsHeight, BPP */
DWORD SettingsCount;
PRESOLUTION_INFO Resolutions;
DWORD ResolutionsCount;
PSETTINGS_ENTRY CurrentSettings; /* Points into Settings list */
SETTINGS_ENTRY InitialSettings;
} DISPLAY_DEVICE_ENTRY, *PDISPLAY_DEVICE_ENTRY;
static PDISPLAY_DEVICE_ENTRY DisplayDeviceList = NULL;
static PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice = NULL;
static VOID
UpdateDisplay(IN HWND hwndDlg)
{
TCHAR Buffer[64];
DWORD index;
_stprintf(Buffer, TEXT("%lux%lu"), CurrentDisplayDevice->CurrentSettings->dmPelsWidth, CurrentDisplayDevice->CurrentSettings->dmPelsHeight);
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT, WM_SETTEXT, 0, (LPARAM)Buffer);
for (index = 0; index < CurrentDisplayDevice->ResolutionsCount; index++)
if (CurrentDisplayDevice->Resolutions[index].dmPelsWidth == CurrentDisplayDevice->CurrentSettings->dmPelsWidth &&
CurrentDisplayDevice->Resolutions[index].dmPelsHeight == CurrentDisplayDevice->CurrentSettings->dmPelsHeight)
{
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETPOS, TRUE, index);
break;
}
_stprintf(Buffer, TEXT("%d bits"), CurrentDisplayDevice->CurrentSettings->dmBitsPerPel);
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SELECTSTRING, -1, (LPARAM)Buffer);
}
static PSETTINGS_ENTRY
GetPossibleSettings(IN LPTSTR DeviceName, OUT DWORD* pSettingsCount, OUT PSETTINGS_ENTRY* CurrentSettings)
{
DEVMODE devmode;
DWORD NbSettings = 0;
DWORD iMode = 0;
DWORD dwFlags = 0;
PSETTINGS_ENTRY Settings = NULL;
HDC hDC;
PSETTINGS_ENTRY Current;
DWORD bpp, xres, yres;
/* Get current settings */
*CurrentSettings = NULL;
hDC = CreateIC(NULL, DeviceName, NULL, NULL);
bpp = GetDeviceCaps(hDC, PLANES);
bpp *= GetDeviceCaps(hDC, BITSPIXEL);
xres = GetDeviceCaps(hDC, HORZRES);
yres = GetDeviceCaps(hDC, VERTRES);
DeleteDC(hDC);
/* List all settings */
devmode.dmSize = (WORD)sizeof(DEVMODE);
devmode.dmDriverExtra = 0;
while (EnumDisplaySettingsEx(DeviceName, NbSettings, &devmode, dwFlags))
{
Current = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY));
if (Current != NULL)
{
/* Sort resolutions by increasing height, and BPP */
PSETTINGS_ENTRY Previous = NULL;
PSETTINGS_ENTRY Next = Settings;
Current->dmPelsWidth = devmode.dmPelsWidth;
Current->dmPelsHeight = devmode.dmPelsHeight;
Current->dmBitsPerPel = devmode.dmBitsPerPel;
while (Next != NULL && (
Next->dmPelsHeight < Current->dmPelsHeight ||
(Next->dmPelsHeight == Current->dmPelsHeight && Next->dmBitsPerPel < Current->dmBitsPerPel)))
{
Previous = Next;
Next = Next->Flink;
}
Current->Blink = Previous;
Current->Flink = Next;
if (Previous == NULL)
Settings = Current;
else
Previous->Flink = Current;
if (Next != NULL)
Next->Blink = Current;
if (devmode.dmPelsWidth == xres && devmode.dmPelsHeight == yres && devmode.dmBitsPerPel == bpp)
{
*CurrentSettings = Current;
}
NbSettings++;
}
iMode++;
}
*pSettingsCount = NbSettings;
return Settings;
}
static VOID
AddDisplayDevice(IN LPTSTR Description, IN LPTSTR DeviceName)
{
PDISPLAY_DEVICE_ENTRY newEntry = NULL;
LPTSTR description = NULL;
LPTSTR name = NULL;
DWORD descriptionSize;
DWORD nameSize;
PSETTINGS_ENTRY Current;
DWORD ResolutionsCount = 1;
DWORD i;
newEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(DISPLAY_DEVICE_ENTRY));
if (!newEntry) goto ByeBye;
newEntry->Settings = GetPossibleSettings(DeviceName, &newEntry->SettingsCount, &newEntry->CurrentSettings);
if (!newEntry->Settings) goto ByeBye;
newEntry->InitialSettings.dmPelsWidth = newEntry->CurrentSettings->dmPelsWidth;
newEntry->InitialSettings.dmPelsHeight = newEntry->CurrentSettings->dmPelsHeight;
newEntry->InitialSettings.dmBitsPerPel = newEntry->CurrentSettings->dmBitsPerPel;
/* Count different resolutions */
for (Current = newEntry->Settings; Current != NULL; Current = Current->Flink)
if (Current->Flink != NULL &&
((Current->dmPelsWidth != Current->Flink->dmPelsWidth) || (Current->dmPelsHeight != Current->Flink->dmPelsHeight)))
ResolutionsCount++;
newEntry->Resolutions = HeapAlloc(GetProcessHeap(), 0, ResolutionsCount * sizeof(RESOLUTION_INFO));
if (!newEntry->Resolutions) goto ByeBye;
newEntry->ResolutionsCount = ResolutionsCount;
/* Fill resolutions infos */
for (Current = newEntry->Settings, i = 0; Current != NULL; Current = Current->Flink)
if (Current->Flink == NULL || (Current->Flink != NULL &&
((Current->dmPelsWidth != Current->Flink->dmPelsWidth) || (Current->dmPelsHeight != Current->Flink->dmPelsHeight))))
{
newEntry->Resolutions[i].dmPelsWidth = Current->dmPelsWidth;
newEntry->Resolutions[i].dmPelsHeight = Current->dmPelsHeight;
i++;
}
descriptionSize = (_tcslen(Description) + 1) * sizeof(TCHAR);
description = HeapAlloc(GetProcessHeap(), 0, descriptionSize);
if (!description) goto ByeBye;
nameSize = (_tcslen(DeviceName) + 1) * sizeof(TCHAR);
name = HeapAlloc(GetProcessHeap(), 0, nameSize);
if (!name) goto ByeBye;
memcpy(description, Description, descriptionSize);
memcpy(name, DeviceName, nameSize);
newEntry->DeviceDescription = description;
newEntry->DeviceName = name;
newEntry->Flink = DisplayDeviceList;
DisplayDeviceList = newEntry;
return;
ByeBye:
if (newEntry != NULL)
{
if (newEntry->Settings != NULL)
{
Current = newEntry->Settings;
while (Current != NULL)
{
PSETTINGS_ENTRY Next = Current->Flink;
HeapFree(GetProcessHeap(), 0, Current);
Current = Next;
}
}
if (newEntry->Resolutions != NULL)
HeapFree(GetProcessHeap(), 0, newEntry->Resolutions);
HeapFree(GetProcessHeap(), 0, newEntry);
}
if (description != NULL)
HeapFree(GetProcessHeap(), 0, description);
if (name != NULL)
HeapFree(GetProcessHeap(), 0, name);
}
static VOID
OnDisplayDeviceChanged(IN HWND hwndDlg, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry)
{
PSETTINGS_ENTRY Current;
DWORD index;
CurrentDisplayDevice = pDeviceEntry; /* Update global variable */
/* Fill color depths combo box */
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_RESETCONTENT, 0, 0);
for (Current = pDeviceEntry->Settings; Current != NULL; Current = Current->Flink)
{
TCHAR Buffer[64];
_stprintf(Buffer, TEXT("%d bits"), Current->dmBitsPerPel);
index = SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)Buffer);
if (index == CB_ERR)
{
index = SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_ADDSTRING, 0, (LPARAM)Buffer);
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SETITEMDATA, index, Current->dmBitsPerPel);
}
}
/* Fill resolutions slider */
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_CLEARTICS, TRUE, 0);
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETRANGE, TRUE, MAKELONG(0, pDeviceEntry->ResolutionsCount - 1));
UpdateDisplay(hwndDlg);
}
static VOID
OnInitDialog(IN HWND hwndDlg)
{
DWORD Result = 0;
DWORD iDevNum = 0;
DISPLAY_DEVICE displayDevice;
/* Get video cards list */
displayDevice.cb = (DWORD)sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0))
{
if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0)
{
AddDisplayDevice(displayDevice.DeviceString, displayDevice.DeviceName);
Result++;
}
iDevNum++;
}
if (Result == 0)
{
/* No adapter found */
EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_BPP), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT), FALSE);
EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_ADVANCED), FALSE);
}
else if (Result == 1)
{
/* Single video adapter */
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_DEVICE, WM_SETTEXT, 0, (LPARAM)DisplayDeviceList->DeviceDescription);
OnDisplayDeviceChanged(hwndDlg, DisplayDeviceList);
}
else
{
/* FIXME: multi video adapter */
/* FIXME: choose selected adapter being the primary one */
}
}
static VOID
OnBPPChanged(IN HWND hwndDlg)
{
/* if new BPP is not compatible with resolution:
* 1) try to find the nearest smaller matching resolution
* 2) otherwise, get the nearest bigger resolution
*/
PSETTINGS_ENTRY Current;
DWORD dmNewBitsPerPel;
DWORD index;
TCHAR Buffer[64];
SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, WM_GETTEXT, (WPARAM)(sizeof(Buffer) / sizeof(TCHAR)), (LPARAM)Buffer);
index = SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)Buffer);
dmNewBitsPerPel = SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETITEMDATA, index, 0);
/* find if new parameters are valid */
Current = CurrentDisplayDevice->CurrentSettings;
if (dmNewBitsPerPel == Current->dmBitsPerPel)
{
/* no change */
return;
}
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
if (dmNewBitsPerPel < Current->dmBitsPerPel)
{
Current = Current->Blink;
while (Current != NULL)
{
if (Current->dmBitsPerPel == dmNewBitsPerPel
&& Current->dmPelsHeight == CurrentDisplayDevice->CurrentSettings->dmPelsHeight
&& Current->dmPelsWidth == CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Blink;
}
}
else
{
Current = Current->Flink;
while (Current != NULL)
{
if (Current->dmBitsPerPel == dmNewBitsPerPel
&& Current->dmPelsHeight == CurrentDisplayDevice->CurrentSettings->dmPelsHeight
&& Current->dmPelsWidth == CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Flink;
}
}
/* search smaller resolution compatible with current color depth */
Current = CurrentDisplayDevice->CurrentSettings->Blink;
while (Current != NULL)
{
if (Current->dmBitsPerPel == dmNewBitsPerPel)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Blink;
}
/* search bigger resolution compatible with current color depth */
Current = CurrentDisplayDevice->CurrentSettings->Flink;
while (Current != NULL)
{
if (Current->dmBitsPerPel == dmNewBitsPerPel)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Flink;
}
/* we shouldn't go there */
}
static VOID
OnResolutionChanged(IN HWND hwndDlg, IN DWORD NewPosition)
{
/* if new resolution is not compatible with color depth:
* 1) try to find the nearest bigger matching color depth
* 2) otherwise, get the nearest smaller color depth
*/
PSETTINGS_ENTRY Current;
DWORD dmNewPelsHeight = CurrentDisplayDevice->Resolutions[NewPosition].dmPelsHeight;
DWORD dmNewPelsWidth = CurrentDisplayDevice->Resolutions[NewPosition].dmPelsWidth;
/* find if new parameters are valid */
Current = CurrentDisplayDevice->CurrentSettings;
if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
{
/* no change */
return;
}
PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
if (dmNewPelsHeight < Current->dmPelsHeight)
{
Current = Current->Blink;
while (Current != NULL)
{
if (Current->dmPelsHeight == dmNewPelsHeight
&& Current->dmPelsWidth == dmNewPelsWidth
&& Current->dmBitsPerPel == CurrentDisplayDevice->CurrentSettings->dmBitsPerPel)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Blink;
}
}
else
{
Current = Current->Flink;
while (Current != NULL)
{
if (Current->dmPelsHeight == dmNewPelsHeight
&& Current->dmPelsWidth == dmNewPelsWidth
&& Current->dmBitsPerPel == CurrentDisplayDevice->CurrentSettings->dmBitsPerPel)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Flink;
}
}
/* search bigger color depth compatible with current resolution */
Current = CurrentDisplayDevice->CurrentSettings->Flink;
while (Current != NULL)
{
if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Flink;
}
/* search smaller color depth compatible with current resolution */
Current = CurrentDisplayDevice->CurrentSettings->Blink;
while (Current != NULL)
{
if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
{
CurrentDisplayDevice->CurrentSettings = Current;
UpdateDisplay(hwndDlg);
return;
}
Current = Current->Blink;
}
/* we shouldn't go there */
}
static VOID
OnAdvancedButton()
{
MessageBox(NULL, TEXT("That button doesn't do anything yet"), TEXT("Whoops"), MB_OK);
}
/* Property page dialog callback */
INT_PTR CALLBACK
SettingsPageProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
OnInitDialog(hwndDlg);
break;
case WM_COMMAND:
{
DWORD controlId = LOWORD(wParam);
DWORD command = HIWORD(wParam);
if (controlId == IDC_SETTINGS_ADVANCED && command == BN_CLICKED)
OnAdvancedButton();
else if (controlId == IDC_SETTINGS_BPP && command == CBN_SELCHANGE)
OnBPPChanged(hwndDlg);
break;
}
case WM_HSCROLL:
{
switch (LOWORD(wParam))
{
case TB_LINEUP:
case TB_LINEDOWN:
case TB_PAGEUP:
case TB_PAGEDOWN:
case TB_TOP:
case TB_BOTTOM:
case TB_ENDTRACK:
{
DWORD newPosition = SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_GETPOS, 0, 0);
OnResolutionChanged(hwndDlg, newPosition);
}
}
break;
}
case WM_NOTIFY:
{
LPNMHDR lpnm = (LPNMHDR)lParam;
if (lpnm->code == PSN_APPLY)
{
if (CurrentDisplayDevice->CurrentSettings->dmPelsWidth != CurrentDisplayDevice->InitialSettings.dmPelsWidth
|| CurrentDisplayDevice->CurrentSettings->dmPelsHeight != CurrentDisplayDevice->InitialSettings.dmPelsHeight
|| CurrentDisplayDevice->CurrentSettings->dmBitsPerPel != CurrentDisplayDevice->InitialSettings.dmBitsPerPel)
{
#if 1
MessageBox(NULL, TEXT("Sorry... Applying changes is not implemented in ReactOS..."), TEXT("Display settings"), MB_OK | MB_ICONSTOP);
#else
/* FIXME: Need to test changes */
/* Apply new settings */
LONG rc;
DEVMODE devmode;
RtlZeroMemory(&devmode, sizeof(DEVMODE));
devmode.dmSize = (WORD)sizeof(DEVMODE);
devmode.dmPelsWidth = CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
devmode.dmPelsHeight = CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
devmode.dmBitsPerPel = CurrentDisplayDevice->CurrentSettings->dmBitsPerPel;
devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
rc = ChangeDisplaySettingsEx(
CurrentDisplayDevice->DeviceName,
&devmode,
NULL,
CDS_UPDATEREGISTRY,
NULL);
switch (rc)
{
case DISP_CHANGE_SUCCESSFUL:
CurrentDisplayDevice->InitialSettings.dmPelsWidth = CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
CurrentDisplayDevice->InitialSettings.dmPelsHeight = CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
CurrentDisplayDevice->InitialSettings.dmBitsPerPel = CurrentDisplayDevice->CurrentSettings->dmBitsPerPel;
break;
case DISP_CHANGE_FAILED:
MessageBox(NULL, TEXT("Failed to apply new settings..."), TEXT("Display settings"), MB_OK | MB_ICONSTOP);
break;
case DISP_CHANGE_RESTART:
MessageBox(NULL, TEXT("You need to restart your computer to apply changes."), TEXT("Display settings"), MB_OK | MB_ICONINFORMATION);
break;
default:
MessageBox(NULL, TEXT("Unknown error when applying new settings..."), TEXT("Display settings"), MB_OK | MB_ICONSTOP);
break;
}
#endif
}
}
break;
}
case WM_DESTROY:
{
PDISPLAY_DEVICE_ENTRY Current = DisplayDeviceList;
while (Current != NULL)
{
PDISPLAY_DEVICE_ENTRY Next = Current->Flink;
PSETTINGS_ENTRY CurrentSettings = Current->Settings;
while (CurrentSettings != NULL)
{
PSETTINGS_ENTRY NextSettings = CurrentSettings->Flink;
HeapFree(GetProcessHeap(), 0, CurrentSettings);
CurrentSettings = NextSettings;
}
HeapFree(GetProcessHeap(), 0, Current);
Current = Next;
}
}
}
return FALSE;
}