3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Display Control Panel
5 * FILE: lib/cpl/desk/settings.c
6 * PURPOSE: Settings property page
8 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
9 * Hervé Poussineau (poussine@freesurf.fr)
21 /* As slider control can't contain user data, we have to keep an
22 * array of RESOLUTION_INFO to have our own associated data.
24 typedef struct _RESOLUTION_INFO
28 } RESOLUTION_INFO
, *PRESOLUTION_INFO
;
30 typedef struct _SETTINGS_ENTRY
32 struct _SETTINGS_ENTRY
*Blink
;
33 struct _SETTINGS_ENTRY
*Flink
;
37 } SETTINGS_ENTRY
, *PSETTINGS_ENTRY
;
39 typedef struct _DISPLAY_DEVICE_ENTRY
41 struct _DISPLAY_DEVICE_ENTRY
*Flink
;
42 LPTSTR DeviceDescription
;
44 PSETTINGS_ENTRY Settings
; /* sorted by increasing dmPelsHeight, BPP */
46 PRESOLUTION_INFO Resolutions
;
47 DWORD ResolutionsCount
;
48 PSETTINGS_ENTRY CurrentSettings
; /* Points into Settings list */
49 SETTINGS_ENTRY InitialSettings
;
50 } DISPLAY_DEVICE_ENTRY
, *PDISPLAY_DEVICE_ENTRY
;
52 static PDISPLAY_DEVICE_ENTRY DisplayDeviceList
= NULL
;
53 static PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice
= NULL
;
56 UpdateDisplay(IN HWND hwndDlg
)
62 LoadString(hApplet
, IDS_PIXEL
, Pixel
, sizeof(Pixel
) / sizeof(TCHAR
));
63 _stprintf(Buffer
, Pixel
, CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
, CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
, Pixel
);
64 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
, WM_SETTEXT
, 0, (LPARAM
)Buffer
);
67 for (index
= 0; index
< CurrentDisplayDevice
->ResolutionsCount
; index
++)
70 if (CurrentDisplayDevice
->Resolutions
[index
].dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
&&
71 CurrentDisplayDevice
->Resolutions
[index
].dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
)
73 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETPOS
, TRUE
, index
);
77 if (LoadString(hApplet
, (2900 + CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
78 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SELECTSTRING
, -1, (LPARAM
)Buffer
);
81 static PSETTINGS_ENTRY
82 GetPossibleSettings(IN LPTSTR DeviceName
, OUT DWORD
* pSettingsCount
, OUT PSETTINGS_ENTRY
* CurrentSettings
)
88 PSETTINGS_ENTRY Settings
= NULL
;
90 PSETTINGS_ENTRY Current
;
91 DWORD bpp
, xres
, yres
, checkbpp
;
93 /* Get current settings */
94 *CurrentSettings
= NULL
;
95 hDC
= CreateIC(NULL
, DeviceName
, NULL
, NULL
);
96 bpp
= GetDeviceCaps(hDC
, PLANES
);
97 bpp
*= GetDeviceCaps(hDC
, BITSPIXEL
);
98 xres
= GetDeviceCaps(hDC
, HORZRES
);
99 yres
= GetDeviceCaps(hDC
, VERTRES
);
102 /* List all settings */
103 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
104 devmode
.dmDriverExtra
= 0;
105 while (EnumDisplaySettingsEx(DeviceName
, iMode
, &devmode
, dwFlags
))
108 if (devmode
.dmBitsPerPel
==8 || devmode
.dmBitsPerPel
==16 || devmode
.dmBitsPerPel
==24 || devmode
.dmBitsPerPel
==32) checkbpp
=1;
111 if (devmode
.dmPelsWidth
< 640 ||
112 devmode
.dmPelsHeight
< 480 || checkbpp
== 0)
118 Current
= HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY
));
121 /* Sort resolutions by increasing height, and BPP */
122 PSETTINGS_ENTRY Previous
= NULL
;
123 PSETTINGS_ENTRY Next
= Settings
;
124 Current
->dmPelsWidth
= devmode
.dmPelsWidth
;
125 Current
->dmPelsHeight
= devmode
.dmPelsHeight
;
126 Current
->dmBitsPerPel
= devmode
.dmBitsPerPel
;
127 while (Next
!= NULL
&& (
128 Next
->dmPelsHeight
< Current
->dmPelsHeight
||
129 (Next
->dmPelsHeight
== Current
->dmPelsHeight
&& Next
->dmBitsPerPel
< Current
->dmBitsPerPel
)))
134 Current
->Blink
= Previous
;
135 Current
->Flink
= Next
;
136 if (Previous
== NULL
)
139 Previous
->Flink
= Current
;
141 Next
->Blink
= Current
;
142 if (devmode
.dmPelsWidth
== xres
&& devmode
.dmPelsHeight
== yres
&& devmode
.dmBitsPerPel
== bpp
)
144 *CurrentSettings
= Current
;
151 *pSettingsCount
= NbSettings
;
156 AddDisplayDevice(IN LPTSTR Description
, IN LPTSTR DeviceName
)
158 PDISPLAY_DEVICE_ENTRY newEntry
= NULL
;
159 LPTSTR description
= NULL
;
161 DWORD descriptionSize
;
163 PSETTINGS_ENTRY Current
;
164 DWORD ResolutionsCount
= 1;
167 newEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(DISPLAY_DEVICE_ENTRY
));
168 if (!newEntry
) goto ByeBye
;
170 newEntry
->Settings
= GetPossibleSettings(DeviceName
, &newEntry
->SettingsCount
, &newEntry
->CurrentSettings
);
171 if (!newEntry
->Settings
) goto ByeBye
;
173 newEntry
->InitialSettings
.dmPelsWidth
= newEntry
->CurrentSettings
->dmPelsWidth
;
174 newEntry
->InitialSettings
.dmPelsHeight
= newEntry
->CurrentSettings
->dmPelsHeight
;
175 newEntry
->InitialSettings
.dmBitsPerPel
= newEntry
->CurrentSettings
->dmBitsPerPel
;
177 /* Count different resolutions */
178 for (Current
= newEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
179 if (Current
->Flink
!= NULL
&&
180 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
)))
182 newEntry
->Resolutions
= HeapAlloc(GetProcessHeap(), 0, ResolutionsCount
* sizeof(RESOLUTION_INFO
));
183 if (!newEntry
->Resolutions
) goto ByeBye
;
184 newEntry
->ResolutionsCount
= ResolutionsCount
;
185 /* Fill resolutions infos */
186 for (Current
= newEntry
->Settings
, i
= 0; Current
!= NULL
; Current
= Current
->Flink
)
187 if (Current
->Flink
== NULL
|| (Current
->Flink
!= NULL
&&
188 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
))))
190 newEntry
->Resolutions
[i
].dmPelsWidth
= Current
->dmPelsWidth
;
191 newEntry
->Resolutions
[i
].dmPelsHeight
= Current
->dmPelsHeight
;
195 descriptionSize
= (_tcslen(Description
) + 1) * sizeof(TCHAR
);
196 description
= HeapAlloc(GetProcessHeap(), 0, descriptionSize
);
197 if (!description
) goto ByeBye
;
199 nameSize
= (_tcslen(DeviceName
) + 1) * sizeof(TCHAR
);
200 name
= HeapAlloc(GetProcessHeap(), 0, nameSize
);
201 if (!name
) goto ByeBye
;
203 memcpy(description
, Description
, descriptionSize
);
204 memcpy(name
, DeviceName
, nameSize
);
205 newEntry
->DeviceDescription
= description
;
206 newEntry
->DeviceName
= name
;
207 newEntry
->Flink
= DisplayDeviceList
;
208 DisplayDeviceList
= newEntry
;
212 if (newEntry
!= NULL
)
214 if (newEntry
->Settings
!= NULL
)
216 Current
= newEntry
->Settings
;
217 while (Current
!= NULL
)
219 PSETTINGS_ENTRY Next
= Current
->Flink
;
220 HeapFree(GetProcessHeap(), 0, Current
);
224 if (newEntry
->Resolutions
!= NULL
)
225 HeapFree(GetProcessHeap(), 0, newEntry
->Resolutions
);
226 HeapFree(GetProcessHeap(), 0, newEntry
);
228 if (description
!= NULL
)
229 HeapFree(GetProcessHeap(), 0, description
);
231 HeapFree(GetProcessHeap(), 0, name
);
235 OnDisplayDeviceChanged(IN HWND hwndDlg
, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry
)
237 PSETTINGS_ENTRY Current
;
240 CurrentDisplayDevice
= pDeviceEntry
; /* Update global variable */
242 /* Fill color depths combo box */
243 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_RESETCONTENT
, 0, 0);
244 for (Current
= pDeviceEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
247 if (LoadString(hApplet
, (2900 + Current
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
249 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
250 if (index
== (DWORD
)CB_ERR
)
252 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_ADDSTRING
, 0, (LPARAM
)Buffer
);
253 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SETITEMDATA
, index
, Current
->dmBitsPerPel
);
258 /* Fill resolutions slider */
259 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_CLEARTICS
, TRUE
, 0);
260 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETRANGE
, TRUE
, MAKELONG(0, pDeviceEntry
->ResolutionsCount
- 1));
262 UpdateDisplay(hwndDlg
);
266 OnInitDialog(IN HWND hwndDlg
)
270 DISPLAY_DEVICE displayDevice
;
272 /* Get video cards list */
273 displayDevice
.cb
= (DWORD
)sizeof(DISPLAY_DEVICE
);
274 while (EnumDisplayDevices(NULL
, iDevNum
, &displayDevice
, 0))
276 if ((displayDevice
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
) != 0)
278 AddDisplayDevice(displayDevice
.DeviceString
, displayDevice
.DeviceName
);
285 /* No adapter found */
286 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_BPP
), FALSE
);
287 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION
), FALSE
);
288 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
), FALSE
);
289 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_ADVANCED
), FALSE
);
291 else if (Result
== 1)
293 /* Single video adapter */
294 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_DEVICE
, WM_SETTEXT
, 0, (LPARAM
)DisplayDeviceList
->DeviceDescription
);
295 OnDisplayDeviceChanged(hwndDlg
, DisplayDeviceList
);
299 /* FIXME: multi video adapter */
300 /* FIXME: choose selected adapter being the primary one */
305 OnBPPChanged(IN HWND hwndDlg
)
307 /* if new BPP is not compatible with resolution:
308 * 1) try to find the nearest smaller matching resolution
309 * 2) otherwise, get the nearest bigger resolution
311 PSETTINGS_ENTRY Current
;
312 DWORD dmNewBitsPerPel
;
316 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, WM_GETTEXT
, (WPARAM
)(sizeof(Buffer
) / sizeof(TCHAR
)), (LPARAM
)Buffer
);
317 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
318 dmNewBitsPerPel
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_GETITEMDATA
, index
, 0);
320 /* find if new parameters are valid */
321 Current
= CurrentDisplayDevice
->CurrentSettings
;
322 if (dmNewBitsPerPel
== Current
->dmBitsPerPel
)
328 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
330 if (dmNewBitsPerPel
< Current
->dmBitsPerPel
)
332 Current
= Current
->Blink
;
333 while (Current
!= NULL
)
335 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
336 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
337 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
339 CurrentDisplayDevice
->CurrentSettings
= Current
;
340 UpdateDisplay(hwndDlg
);
343 Current
= Current
->Blink
;
348 Current
= Current
->Flink
;
349 while (Current
!= NULL
)
351 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
352 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
353 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
355 CurrentDisplayDevice
->CurrentSettings
= Current
;
356 UpdateDisplay(hwndDlg
);
359 Current
= Current
->Flink
;
363 /* search smaller resolution compatible with current color depth */
364 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
365 while (Current
!= NULL
)
367 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
369 CurrentDisplayDevice
->CurrentSettings
= Current
;
370 UpdateDisplay(hwndDlg
);
373 Current
= Current
->Blink
;
376 /* search bigger resolution compatible with current color depth */
377 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
378 while (Current
!= NULL
)
380 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
382 CurrentDisplayDevice
->CurrentSettings
= Current
;
383 UpdateDisplay(hwndDlg
);
386 Current
= Current
->Flink
;
389 /* we shouldn't go there */
393 OnResolutionChanged(IN HWND hwndDlg
, IN DWORD NewPosition
)
395 /* if new resolution is not compatible with color depth:
396 * 1) try to find the nearest bigger matching color depth
397 * 2) otherwise, get the nearest smaller color depth
399 PSETTINGS_ENTRY Current
;
400 DWORD dmNewPelsHeight
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsHeight
;
401 DWORD dmNewPelsWidth
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsWidth
;
403 /* find if new parameters are valid */
404 Current
= CurrentDisplayDevice
->CurrentSettings
;
405 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
411 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
413 if (dmNewPelsHeight
< Current
->dmPelsHeight
)
415 Current
= Current
->Blink
;
416 while (Current
!= NULL
)
418 if (Current
->dmPelsHeight
== dmNewPelsHeight
419 && Current
->dmPelsWidth
== dmNewPelsWidth
420 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
422 CurrentDisplayDevice
->CurrentSettings
= Current
;
423 UpdateDisplay(hwndDlg
);
426 Current
= Current
->Blink
;
431 Current
= Current
->Flink
;
432 while (Current
!= NULL
)
434 if (Current
->dmPelsHeight
== dmNewPelsHeight
435 && Current
->dmPelsWidth
== dmNewPelsWidth
436 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
438 CurrentDisplayDevice
->CurrentSettings
= Current
;
439 UpdateDisplay(hwndDlg
);
442 Current
= Current
->Flink
;
446 /* search bigger color depth compatible with current resolution */
447 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
448 while (Current
!= NULL
)
450 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
452 CurrentDisplayDevice
->CurrentSettings
= Current
;
453 UpdateDisplay(hwndDlg
);
456 Current
= Current
->Flink
;
459 /* search smaller color depth compatible with current resolution */
460 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
461 while (Current
!= NULL
)
463 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
465 CurrentDisplayDevice
->CurrentSettings
= Current
;
466 UpdateDisplay(hwndDlg
);
469 Current
= Current
->Blink
;
472 /* we shouldn't go there */
478 MessageBox(NULL
, TEXT("That button doesn't do anything yet"), TEXT("Whoops"), MB_OK
);
481 /* Property page dialog callback */
483 SettingsPageProc(IN HWND hwndDlg
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
)
488 OnInitDialog(hwndDlg
);
492 DWORD controlId
= LOWORD(wParam
);
493 DWORD command
= HIWORD(wParam
);
495 if (controlId
== IDC_SETTINGS_ADVANCED
&& command
== BN_CLICKED
)
497 else if (controlId
== IDC_SETTINGS_BPP
&& command
== CBN_SELCHANGE
)
498 OnBPPChanged(hwndDlg
);
503 switch (LOWORD(wParam
))
513 DWORD newPosition
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_GETPOS
, 0, 0);
514 OnResolutionChanged(hwndDlg
, newPosition
);
521 LPNMHDR lpnm
= (LPNMHDR
)lParam
;
522 if (lpnm
->code
== (UINT
)PSN_APPLY
)
524 if (CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
!= CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
525 || CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
!= CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
526 || CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
!= CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
)
528 /* FIXME: Need to test changes */
529 /* Apply new settings */
532 RtlZeroMemory(&devmode
, sizeof(DEVMODE
));
533 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
534 devmode
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
535 devmode
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
536 devmode
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
537 devmode
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
;
538 rc
= ChangeDisplaySettingsEx(
539 CurrentDisplayDevice
->DeviceName
,
546 case DISP_CHANGE_SUCCESSFUL
:
547 CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
548 CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
549 CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
551 case DISP_CHANGE_FAILED
:
552 MessageBox(NULL
, TEXT("Failed to apply new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
554 case DISP_CHANGE_RESTART
:
555 MessageBox(NULL
, TEXT("You need to restart your computer to apply changes."), TEXT("Display settings"), MB_OK
| MB_ICONINFORMATION
);
558 MessageBox(NULL
, TEXT("Unknown error when applying new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
567 PDISPLAY_DEVICE_ENTRY Current
= DisplayDeviceList
;
568 while (Current
!= NULL
)
570 PDISPLAY_DEVICE_ENTRY Next
= Current
->Flink
;
571 PSETTINGS_ENTRY CurrentSettings
= Current
->Settings
;
572 while (CurrentSettings
!= NULL
)
574 PSETTINGS_ENTRY NextSettings
= CurrentSettings
->Flink
;
575 HeapFree(GetProcessHeap(), 0, CurrentSettings
);
576 CurrentSettings
= NextSettings
;
578 HeapFree(GetProcessHeap(), 0, Current
);