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)
14 /* As slider control can't contain user data, we have to keep an
15 * array of RESOLUTION_INFO to have our own associated data.
17 typedef struct _RESOLUTION_INFO
21 } RESOLUTION_INFO
, *PRESOLUTION_INFO
;
23 typedef struct _SETTINGS_ENTRY
25 struct _SETTINGS_ENTRY
*Blink
;
26 struct _SETTINGS_ENTRY
*Flink
;
30 } SETTINGS_ENTRY
, *PSETTINGS_ENTRY
;
32 typedef struct _DISPLAY_DEVICE_ENTRY
34 struct _DISPLAY_DEVICE_ENTRY
*Flink
;
35 LPTSTR DeviceDescription
;
37 PSETTINGS_ENTRY Settings
; /* sorted by increasing dmPelsHeight, BPP */
39 PRESOLUTION_INFO Resolutions
;
40 DWORD ResolutionsCount
;
41 PSETTINGS_ENTRY CurrentSettings
; /* Points into Settings list */
42 SETTINGS_ENTRY InitialSettings
;
43 } DISPLAY_DEVICE_ENTRY
, *PDISPLAY_DEVICE_ENTRY
;
45 static PDISPLAY_DEVICE_ENTRY DisplayDeviceList
= NULL
;
46 static PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice
= NULL
;
49 UpdateDisplay(IN HWND hwndDlg
)
55 LoadString(hApplet
, IDS_PIXEL
, Pixel
, sizeof(Pixel
) / sizeof(TCHAR
));
56 _stprintf(Buffer
, Pixel
, CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
, CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
, Pixel
);
57 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
, WM_SETTEXT
, 0, (LPARAM
)Buffer
);
60 for (index
= 0; index
< CurrentDisplayDevice
->ResolutionsCount
; index
++)
63 if (CurrentDisplayDevice
->Resolutions
[index
].dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
&&
64 CurrentDisplayDevice
->Resolutions
[index
].dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
)
66 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETPOS
, TRUE
, index
);
70 if (LoadString(hApplet
, (2900 + CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
71 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SELECTSTRING
, -1, (LPARAM
)Buffer
);
74 static PSETTINGS_ENTRY
75 GetPossibleSettings(IN LPTSTR DeviceName
, OUT DWORD
* pSettingsCount
, OUT PSETTINGS_ENTRY
* CurrentSettings
)
81 PSETTINGS_ENTRY Settings
= NULL
;
83 PSETTINGS_ENTRY Current
;
84 DWORD bpp
, xres
, yres
, checkbpp
;
86 /* Get current settings */
87 *CurrentSettings
= NULL
;
88 hDC
= CreateIC(NULL
, DeviceName
, NULL
, NULL
);
89 bpp
= GetDeviceCaps(hDC
, PLANES
);
90 bpp
*= GetDeviceCaps(hDC
, BITSPIXEL
);
91 xres
= GetDeviceCaps(hDC
, HORZRES
);
92 yres
= GetDeviceCaps(hDC
, VERTRES
);
95 /* List all settings */
96 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
97 devmode
.dmDriverExtra
= 0;
98 while (EnumDisplaySettingsEx(DeviceName
, iMode
, &devmode
, dwFlags
))
101 if (devmode
.dmBitsPerPel
==8 || devmode
.dmBitsPerPel
==16 || devmode
.dmBitsPerPel
==24 || devmode
.dmBitsPerPel
==32) checkbpp
=1;
104 if (devmode
.dmPelsWidth
< 640 ||
105 devmode
.dmPelsHeight
< 480 || checkbpp
== 0)
111 Current
= HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY
));
114 /* Sort resolutions by increasing height, and BPP */
115 PSETTINGS_ENTRY Previous
= NULL
;
116 PSETTINGS_ENTRY Next
= Settings
;
117 Current
->dmPelsWidth
= devmode
.dmPelsWidth
;
118 Current
->dmPelsHeight
= devmode
.dmPelsHeight
;
119 Current
->dmBitsPerPel
= devmode
.dmBitsPerPel
;
120 while (Next
!= NULL
&& (
121 Next
->dmPelsHeight
< Current
->dmPelsHeight
||
122 (Next
->dmPelsHeight
== Current
->dmPelsHeight
&& Next
->dmBitsPerPel
< Current
->dmBitsPerPel
)))
127 Current
->Blink
= Previous
;
128 Current
->Flink
= Next
;
129 if (Previous
== NULL
)
132 Previous
->Flink
= Current
;
134 Next
->Blink
= Current
;
135 if (devmode
.dmPelsWidth
== xres
&& devmode
.dmPelsHeight
== yres
&& devmode
.dmBitsPerPel
== bpp
)
137 *CurrentSettings
= Current
;
144 *pSettingsCount
= NbSettings
;
149 AddDisplayDevice(IN LPTSTR Description
, IN LPTSTR DeviceName
)
151 PDISPLAY_DEVICE_ENTRY newEntry
= NULL
;
152 LPTSTR description
= NULL
;
154 DWORD descriptionSize
;
156 PSETTINGS_ENTRY Current
;
157 DWORD ResolutionsCount
= 1;
160 newEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(DISPLAY_DEVICE_ENTRY
));
161 if (!newEntry
) goto ByeBye
;
163 newEntry
->Settings
= GetPossibleSettings(DeviceName
, &newEntry
->SettingsCount
, &newEntry
->CurrentSettings
);
164 if (!newEntry
->Settings
) goto ByeBye
;
166 newEntry
->InitialSettings
.dmPelsWidth
= newEntry
->CurrentSettings
->dmPelsWidth
;
167 newEntry
->InitialSettings
.dmPelsHeight
= newEntry
->CurrentSettings
->dmPelsHeight
;
168 newEntry
->InitialSettings
.dmBitsPerPel
= newEntry
->CurrentSettings
->dmBitsPerPel
;
170 /* Count different resolutions */
171 for (Current
= newEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
172 if (Current
->Flink
!= NULL
&&
173 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
)))
175 newEntry
->Resolutions
= HeapAlloc(GetProcessHeap(), 0, ResolutionsCount
* sizeof(RESOLUTION_INFO
));
176 if (!newEntry
->Resolutions
) goto ByeBye
;
177 newEntry
->ResolutionsCount
= ResolutionsCount
;
178 /* Fill resolutions infos */
179 for (Current
= newEntry
->Settings
, i
= 0; Current
!= NULL
; Current
= Current
->Flink
)
180 if (Current
->Flink
== NULL
|| (Current
->Flink
!= NULL
&&
181 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
))))
183 newEntry
->Resolutions
[i
].dmPelsWidth
= Current
->dmPelsWidth
;
184 newEntry
->Resolutions
[i
].dmPelsHeight
= Current
->dmPelsHeight
;
188 descriptionSize
= (_tcslen(Description
) + 1) * sizeof(TCHAR
);
189 description
= HeapAlloc(GetProcessHeap(), 0, descriptionSize
);
190 if (!description
) goto ByeBye
;
192 nameSize
= (_tcslen(DeviceName
) + 1) * sizeof(TCHAR
);
193 name
= HeapAlloc(GetProcessHeap(), 0, nameSize
);
194 if (!name
) goto ByeBye
;
196 memcpy(description
, Description
, descriptionSize
);
197 memcpy(name
, DeviceName
, nameSize
);
198 newEntry
->DeviceDescription
= description
;
199 newEntry
->DeviceName
= name
;
200 newEntry
->Flink
= DisplayDeviceList
;
201 DisplayDeviceList
= newEntry
;
205 if (newEntry
!= NULL
)
207 if (newEntry
->Settings
!= NULL
)
209 Current
= newEntry
->Settings
;
210 while (Current
!= NULL
)
212 PSETTINGS_ENTRY Next
= Current
->Flink
;
213 HeapFree(GetProcessHeap(), 0, Current
);
217 if (newEntry
->Resolutions
!= NULL
)
218 HeapFree(GetProcessHeap(), 0, newEntry
->Resolutions
);
219 HeapFree(GetProcessHeap(), 0, newEntry
);
221 if (description
!= NULL
)
222 HeapFree(GetProcessHeap(), 0, description
);
224 HeapFree(GetProcessHeap(), 0, name
);
228 OnDisplayDeviceChanged(IN HWND hwndDlg
, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry
)
230 PSETTINGS_ENTRY Current
;
233 CurrentDisplayDevice
= pDeviceEntry
; /* Update global variable */
235 /* Fill color depths combo box */
236 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_RESETCONTENT
, 0, 0);
237 for (Current
= pDeviceEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
240 if (LoadString(hApplet
, (2900 + Current
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
242 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
243 if (index
== (DWORD
)CB_ERR
)
245 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_ADDSTRING
, 0, (LPARAM
)Buffer
);
246 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SETITEMDATA
, index
, Current
->dmBitsPerPel
);
251 /* Fill resolutions slider */
252 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_CLEARTICS
, TRUE
, 0);
253 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETRANGE
, TRUE
, MAKELONG(0, pDeviceEntry
->ResolutionsCount
- 1));
255 UpdateDisplay(hwndDlg
);
259 OnInitDialog(IN HWND hwndDlg
)
263 DISPLAY_DEVICE displayDevice
;
265 /* Get video cards list */
266 displayDevice
.cb
= (DWORD
)sizeof(DISPLAY_DEVICE
);
267 while (EnumDisplayDevices(NULL
, iDevNum
, &displayDevice
, 0))
269 if ((displayDevice
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
) != 0)
271 AddDisplayDevice(displayDevice
.DeviceString
, displayDevice
.DeviceName
);
278 /* No adapter found */
279 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_BPP
), FALSE
);
280 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION
), FALSE
);
281 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
), FALSE
);
282 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_ADVANCED
), FALSE
);
284 else if (Result
== 1)
286 /* Single video adapter */
287 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_DEVICE
, WM_SETTEXT
, 0, (LPARAM
)DisplayDeviceList
->DeviceDescription
);
288 OnDisplayDeviceChanged(hwndDlg
, DisplayDeviceList
);
292 /* FIXME: multi video adapter */
293 /* FIXME: choose selected adapter being the primary one */
298 OnBPPChanged(IN HWND hwndDlg
)
300 /* if new BPP is not compatible with resolution:
301 * 1) try to find the nearest smaller matching resolution
302 * 2) otherwise, get the nearest bigger resolution
304 PSETTINGS_ENTRY Current
;
305 DWORD dmNewBitsPerPel
;
309 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, WM_GETTEXT
, (WPARAM
)(sizeof(Buffer
) / sizeof(TCHAR
)), (LPARAM
)Buffer
);
310 index
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
311 dmNewBitsPerPel
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_GETITEMDATA
, index
, 0);
313 /* find if new parameters are valid */
314 Current
= CurrentDisplayDevice
->CurrentSettings
;
315 if (dmNewBitsPerPel
== Current
->dmBitsPerPel
)
321 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
323 if (dmNewBitsPerPel
< Current
->dmBitsPerPel
)
325 Current
= Current
->Blink
;
326 while (Current
!= NULL
)
328 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
329 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
330 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
332 CurrentDisplayDevice
->CurrentSettings
= Current
;
333 UpdateDisplay(hwndDlg
);
336 Current
= Current
->Blink
;
341 Current
= Current
->Flink
;
342 while (Current
!= NULL
)
344 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
345 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
346 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
348 CurrentDisplayDevice
->CurrentSettings
= Current
;
349 UpdateDisplay(hwndDlg
);
352 Current
= Current
->Flink
;
356 /* search smaller resolution compatible with current color depth */
357 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
358 while (Current
!= NULL
)
360 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
362 CurrentDisplayDevice
->CurrentSettings
= Current
;
363 UpdateDisplay(hwndDlg
);
366 Current
= Current
->Blink
;
369 /* search bigger resolution compatible with current color depth */
370 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
371 while (Current
!= NULL
)
373 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
375 CurrentDisplayDevice
->CurrentSettings
= Current
;
376 UpdateDisplay(hwndDlg
);
379 Current
= Current
->Flink
;
382 /* we shouldn't go there */
386 OnResolutionChanged(IN HWND hwndDlg
, IN DWORD NewPosition
)
388 /* if new resolution is not compatible with color depth:
389 * 1) try to find the nearest bigger matching color depth
390 * 2) otherwise, get the nearest smaller color depth
392 PSETTINGS_ENTRY Current
;
393 DWORD dmNewPelsHeight
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsHeight
;
394 DWORD dmNewPelsWidth
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsWidth
;
396 /* find if new parameters are valid */
397 Current
= CurrentDisplayDevice
->CurrentSettings
;
398 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
404 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
406 if (dmNewPelsHeight
< Current
->dmPelsHeight
)
408 Current
= Current
->Blink
;
409 while (Current
!= NULL
)
411 if (Current
->dmPelsHeight
== dmNewPelsHeight
412 && Current
->dmPelsWidth
== dmNewPelsWidth
413 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
415 CurrentDisplayDevice
->CurrentSettings
= Current
;
416 UpdateDisplay(hwndDlg
);
419 Current
= Current
->Blink
;
424 Current
= Current
->Flink
;
425 while (Current
!= NULL
)
427 if (Current
->dmPelsHeight
== dmNewPelsHeight
428 && Current
->dmPelsWidth
== dmNewPelsWidth
429 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
431 CurrentDisplayDevice
->CurrentSettings
= Current
;
432 UpdateDisplay(hwndDlg
);
435 Current
= Current
->Flink
;
439 /* search bigger color depth compatible with current resolution */
440 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
441 while (Current
!= NULL
)
443 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
445 CurrentDisplayDevice
->CurrentSettings
= Current
;
446 UpdateDisplay(hwndDlg
);
449 Current
= Current
->Flink
;
452 /* search smaller color depth compatible with current resolution */
453 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
454 while (Current
!= NULL
)
456 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
458 CurrentDisplayDevice
->CurrentSettings
= Current
;
459 UpdateDisplay(hwndDlg
);
462 Current
= Current
->Blink
;
465 /* we shouldn't go there */
471 MessageBox(NULL
, TEXT("That button doesn't do anything yet"), TEXT("Whoops"), MB_OK
);
474 /* Property page dialog callback */
476 SettingsPageProc(IN HWND hwndDlg
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
)
481 OnInitDialog(hwndDlg
);
485 DWORD controlId
= LOWORD(wParam
);
486 DWORD command
= HIWORD(wParam
);
488 if (controlId
== IDC_SETTINGS_ADVANCED
&& command
== BN_CLICKED
)
490 else if (controlId
== IDC_SETTINGS_BPP
&& command
== CBN_SELCHANGE
)
491 OnBPPChanged(hwndDlg
);
496 switch (LOWORD(wParam
))
506 DWORD newPosition
= SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_GETPOS
, 0, 0);
507 OnResolutionChanged(hwndDlg
, newPosition
);
514 LPNMHDR lpnm
= (LPNMHDR
)lParam
;
515 if (lpnm
->code
== (UINT
)PSN_APPLY
)
517 if (CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
!= CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
518 || CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
!= CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
519 || CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
!= CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
)
521 /* FIXME: Need to test changes */
522 /* Apply new settings */
525 RtlZeroMemory(&devmode
, sizeof(DEVMODE
));
526 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
527 devmode
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
528 devmode
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
529 devmode
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
530 devmode
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
;
531 rc
= ChangeDisplaySettingsEx(
532 CurrentDisplayDevice
->DeviceName
,
539 case DISP_CHANGE_SUCCESSFUL
:
540 CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
541 CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
542 CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
544 case DISP_CHANGE_FAILED
:
545 MessageBox(NULL
, TEXT("Failed to apply new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
547 case DISP_CHANGE_RESTART
:
548 MessageBox(NULL
, TEXT("You need to restart your computer to apply changes."), TEXT("Display settings"), MB_OK
| MB_ICONINFORMATION
);
551 MessageBox(NULL
, TEXT("Unknown error when applying new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
560 PDISPLAY_DEVICE_ENTRY Current
= DisplayDeviceList
;
561 while (Current
!= NULL
)
563 PDISPLAY_DEVICE_ENTRY Next
= Current
->Flink
;
564 PSETTINGS_ENTRY CurrentSettings
= Current
->Settings
;
565 while (CurrentSettings
!= NULL
)
567 PSETTINGS_ENTRY NextSettings
= CurrentSettings
->Flink
;
568 HeapFree(GetProcessHeap(), 0, CurrentSettings
);
569 CurrentSettings
= NextSettings
;
571 HeapFree(GetProcessHeap(), 0, Current
);