2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Display Control Panel
4 * FILE: lib/cpl/desk/settings.c
5 * PURPOSE: Settings property page
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 * Hervé Poussineau (hpoussin@reactos.org)
13 /* As slider control can't contain user data, we have to keep an
14 * array of RESOLUTION_INFO to have our own associated data.
16 typedef struct _RESOLUTION_INFO
20 } RESOLUTION_INFO
, *PRESOLUTION_INFO
;
22 typedef struct _SETTINGS_ENTRY
24 struct _SETTINGS_ENTRY
*Blink
;
25 struct _SETTINGS_ENTRY
*Flink
;
29 } SETTINGS_ENTRY
, *PSETTINGS_ENTRY
;
31 typedef struct _DISPLAY_DEVICE_ENTRY
33 struct _DISPLAY_DEVICE_ENTRY
*Flink
;
34 LPTSTR DeviceDescription
;
36 PSETTINGS_ENTRY Settings
; /* sorted by increasing dmPelsHeight, BPP */
38 PRESOLUTION_INFO Resolutions
;
39 DWORD ResolutionsCount
;
40 PSETTINGS_ENTRY CurrentSettings
; /* Points into Settings list */
41 SETTINGS_ENTRY InitialSettings
;
42 } DISPLAY_DEVICE_ENTRY
, *PDISPLAY_DEVICE_ENTRY
;
44 static PDISPLAY_DEVICE_ENTRY DisplayDeviceList
= NULL
;
45 static PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice
= NULL
;
47 HBITMAP hBitmap
= NULL
;
48 int cxSource
, cySource
;
51 UpdateDisplay(IN HWND hwndDlg
)
57 LoadString(hApplet
, IDS_PIXEL
, Pixel
, sizeof(Pixel
) / sizeof(TCHAR
));
58 _stprintf(Buffer
, Pixel
, CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
, CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
, Pixel
);
59 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
, WM_SETTEXT
, 0, (LPARAM
)Buffer
);
61 for (index
= 0; index
< CurrentDisplayDevice
->ResolutionsCount
; index
++)
64 if (CurrentDisplayDevice
->Resolutions
[index
].dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
&&
65 CurrentDisplayDevice
->Resolutions
[index
].dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
)
67 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETPOS
, TRUE
, index
);
71 if (LoadString(hApplet
, (2900 + CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
72 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SELECTSTRING
, (WPARAM
)-1, (LPARAM
)Buffer
);
75 static PSETTINGS_ENTRY
76 GetPossibleSettings(IN LPTSTR DeviceName
, OUT DWORD
* pSettingsCount
, OUT PSETTINGS_ENTRY
* CurrentSettings
)
82 PSETTINGS_ENTRY Settings
= NULL
;
84 PSETTINGS_ENTRY Current
;
85 DWORD bpp
, xres
, yres
, checkbpp
;
87 /* Get current settings */
88 *CurrentSettings
= NULL
;
89 hDC
= CreateIC(NULL
, DeviceName
, NULL
, NULL
);
90 bpp
= GetDeviceCaps(hDC
, PLANES
);
91 bpp
*= GetDeviceCaps(hDC
, BITSPIXEL
);
92 xres
= GetDeviceCaps(hDC
, HORZRES
);
93 yres
= GetDeviceCaps(hDC
, VERTRES
);
96 /* List all settings */
97 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
98 devmode
.dmDriverExtra
= 0;
99 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
) ||
123 (Next
->dmPelsHeight
== Current
->dmPelsHeight
&&
124 Next
->dmBitsPerPel
== Current
->dmBitsPerPel
&&
125 Next
->dmPelsWidth
< Current
->dmPelsWidth
)))
130 Current
->Blink
= Previous
;
131 Current
->Flink
= Next
;
132 if (Previous
== NULL
)
135 Previous
->Flink
= Current
;
137 Next
->Blink
= Current
;
138 if (devmode
.dmPelsWidth
== xres
&& devmode
.dmPelsHeight
== yres
&& devmode
.dmBitsPerPel
== bpp
)
140 *CurrentSettings
= Current
;
147 *pSettingsCount
= NbSettings
;
152 AddDisplayDevice(IN LPTSTR Description
, IN LPTSTR DeviceName
)
154 PDISPLAY_DEVICE_ENTRY newEntry
= NULL
;
155 LPTSTR description
= NULL
;
157 DWORD descriptionSize
;
159 PSETTINGS_ENTRY Current
;
160 DWORD ResolutionsCount
= 1;
163 newEntry
= HeapAlloc(GetProcessHeap(), 0, sizeof(DISPLAY_DEVICE_ENTRY
));
164 memset(newEntry
, 0, sizeof(DISPLAY_DEVICE_ENTRY
));
165 if (!newEntry
) goto ByeBye
;
167 newEntry
->Settings
= GetPossibleSettings(DeviceName
, &newEntry
->SettingsCount
, &newEntry
->CurrentSettings
);
168 if (!newEntry
->Settings
) goto ByeBye
;
170 newEntry
->InitialSettings
.dmPelsWidth
= newEntry
->CurrentSettings
->dmPelsWidth
;
171 newEntry
->InitialSettings
.dmPelsHeight
= newEntry
->CurrentSettings
->dmPelsHeight
;
172 newEntry
->InitialSettings
.dmBitsPerPel
= newEntry
->CurrentSettings
->dmBitsPerPel
;
174 /* Count different resolutions */
175 for (Current
= newEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
176 if (Current
->Flink
!= NULL
&&
177 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
)))
179 newEntry
->Resolutions
= HeapAlloc(GetProcessHeap(), 0, ResolutionsCount
* sizeof(RESOLUTION_INFO
));
180 if (!newEntry
->Resolutions
) goto ByeBye
;
181 newEntry
->ResolutionsCount
= ResolutionsCount
;
182 /* Fill resolutions infos */
183 for (Current
= newEntry
->Settings
, i
= 0; Current
!= NULL
; Current
= Current
->Flink
)
184 if (Current
->Flink
== NULL
|| (Current
->Flink
!= NULL
&&
185 ((Current
->dmPelsWidth
!= Current
->Flink
->dmPelsWidth
) || (Current
->dmPelsHeight
!= Current
->Flink
->dmPelsHeight
))))
187 newEntry
->Resolutions
[i
].dmPelsWidth
= Current
->dmPelsWidth
;
188 newEntry
->Resolutions
[i
].dmPelsHeight
= Current
->dmPelsHeight
;
192 descriptionSize
= (_tcslen(Description
) + 1) * sizeof(TCHAR
);
193 description
= HeapAlloc(GetProcessHeap(), 0, descriptionSize
);
194 if (!description
) goto ByeBye
;
196 nameSize
= (_tcslen(DeviceName
) + 1) * sizeof(TCHAR
);
197 name
= HeapAlloc(GetProcessHeap(), 0, nameSize
);
198 if (!name
) goto ByeBye
;
200 memcpy(description
, Description
, descriptionSize
);
201 memcpy(name
, DeviceName
, nameSize
);
202 newEntry
->DeviceDescription
= description
;
203 newEntry
->DeviceName
= name
;
204 newEntry
->Flink
= DisplayDeviceList
;
205 DisplayDeviceList
= newEntry
;
209 if (newEntry
!= NULL
)
211 if (newEntry
->Settings
!= NULL
)
213 Current
= newEntry
->Settings
;
214 while (Current
!= NULL
)
216 PSETTINGS_ENTRY Next
= Current
->Flink
;
217 HeapFree(GetProcessHeap(), 0, Current
);
221 if (newEntry
->Resolutions
!= NULL
)
222 HeapFree(GetProcessHeap(), 0, newEntry
->Resolutions
);
223 HeapFree(GetProcessHeap(), 0, newEntry
);
225 if (description
!= NULL
)
226 HeapFree(GetProcessHeap(), 0, description
);
228 HeapFree(GetProcessHeap(), 0, name
);
233 OnDisplayDeviceChanged(IN HWND hwndDlg
, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry
)
235 PSETTINGS_ENTRY Current
;
238 CurrentDisplayDevice
= pDeviceEntry
; /* Update global variable */
240 /* Fill color depths combo box */
241 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_RESETCONTENT
, 0, 0);
242 for (Current
= pDeviceEntry
->Settings
; Current
!= NULL
; Current
= Current
->Flink
)
245 if (LoadString(hApplet
, (2900 + Current
->dmBitsPerPel
), Buffer
, sizeof(Buffer
) / sizeof(TCHAR
)))
247 index
= (DWORD
) SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
248 if (index
== (DWORD
)CB_ERR
)
250 index
= (DWORD
) SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_ADDSTRING
, 0, (LPARAM
)Buffer
);
251 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_SETITEMDATA
, index
, Current
->dmBitsPerPel
);
256 /* Fill resolutions slider */
257 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_CLEARTICS
, TRUE
, 0);
258 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_SETRANGE
, TRUE
, MAKELONG(0, pDeviceEntry
->ResolutionsCount
- 1));
260 UpdateDisplay(hwndDlg
);
264 OnInitDialog(IN HWND hwndDlg
)
268 DISPLAY_DEVICE displayDevice
;
271 /* Get video cards list */
272 displayDevice
.cb
= (DWORD
)sizeof(DISPLAY_DEVICE
);
273 while (EnumDisplayDevices(NULL
, iDevNum
, &displayDevice
, 0))
275 if ((displayDevice
.StateFlags
& DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
) != 0)
277 if (AddDisplayDevice(displayDevice
.DeviceString
, displayDevice
.DeviceName
))
284 /* No adapter found */
285 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_BPP
), FALSE
);
286 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION
), FALSE
);
287 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_RESOLUTION_TEXT
), FALSE
);
288 EnableWindow(GetDlgItem(hwndDlg
, IDC_SETTINGS_ADVANCED
), FALSE
);
290 else if (Result
== 1)
292 /* Single video adapter */
293 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_DEVICE
, WM_SETTEXT
, 0, (LPARAM
)DisplayDeviceList
->DeviceDescription
);
294 OnDisplayDeviceChanged(hwndDlg
, DisplayDeviceList
);
298 /* FIXME: multi video adapter */
299 /* FIXME: choose selected adapter being the primary one */
302 hBitmap
= LoadImage(hApplet
, MAKEINTRESOURCE(IDC_MONITOR
), IMAGE_BITMAP
, 0, 0, LR_LOADTRANSPARENT
);
305 GetObject(hBitmap
, sizeof(BITMAP
), &bitmap
);
307 cxSource
= bitmap
.bmWidth
;
308 cySource
= bitmap
.bmHeight
;
313 OnBPPChanged(IN HWND hwndDlg
)
315 /* if new BPP is not compatible with resolution:
316 * 1) try to find the nearest smaller matching resolution
317 * 2) otherwise, get the nearest bigger resolution
319 PSETTINGS_ENTRY Current
;
320 DWORD dmNewBitsPerPel
;
324 SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, WM_GETTEXT
, (WPARAM
)(sizeof(Buffer
) / sizeof(TCHAR
)), (LPARAM
)Buffer
);
325 index
= (DWORD
) SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_FINDSTRINGEXACT
, (WPARAM
)-1, (LPARAM
)Buffer
);
326 dmNewBitsPerPel
= (DWORD
) SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_BPP
, CB_GETITEMDATA
, index
, 0);
328 /* find if new parameters are valid */
329 Current
= CurrentDisplayDevice
->CurrentSettings
;
330 if (dmNewBitsPerPel
== Current
->dmBitsPerPel
)
336 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
338 if (dmNewBitsPerPel
< Current
->dmBitsPerPel
)
340 Current
= Current
->Blink
;
341 while (Current
!= NULL
)
343 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
344 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
345 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
347 CurrentDisplayDevice
->CurrentSettings
= Current
;
348 UpdateDisplay(hwndDlg
);
351 Current
= Current
->Blink
;
356 Current
= Current
->Flink
;
357 while (Current
!= NULL
)
359 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
360 && Current
->dmPelsHeight
== CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
361 && Current
->dmPelsWidth
== CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
)
363 CurrentDisplayDevice
->CurrentSettings
= Current
;
364 UpdateDisplay(hwndDlg
);
367 Current
= Current
->Flink
;
371 /* search smaller resolution compatible with current color depth */
372 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
373 while (Current
!= NULL
)
375 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
377 CurrentDisplayDevice
->CurrentSettings
= Current
;
378 UpdateDisplay(hwndDlg
);
381 Current
= Current
->Blink
;
384 /* search bigger resolution compatible with current color depth */
385 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
386 while (Current
!= NULL
)
388 if (Current
->dmBitsPerPel
== dmNewBitsPerPel
)
390 CurrentDisplayDevice
->CurrentSettings
= Current
;
391 UpdateDisplay(hwndDlg
);
394 Current
= Current
->Flink
;
397 /* we shouldn't go there */
401 OnResolutionChanged(IN HWND hwndDlg
, IN DWORD NewPosition
)
403 /* if new resolution is not compatible with color depth:
404 * 1) try to find the nearest bigger matching color depth
405 * 2) otherwise, get the nearest smaller color depth
407 PSETTINGS_ENTRY Current
;
408 DWORD dmNewPelsHeight
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsHeight
;
409 DWORD dmNewPelsWidth
= CurrentDisplayDevice
->Resolutions
[NewPosition
].dmPelsWidth
;
411 /* find if new parameters are valid */
412 Current
= CurrentDisplayDevice
->CurrentSettings
;
413 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
419 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
421 if (dmNewPelsHeight
< Current
->dmPelsHeight
)
423 Current
= Current
->Blink
;
424 while (Current
!= NULL
)
426 if (Current
->dmPelsHeight
== dmNewPelsHeight
427 && Current
->dmPelsWidth
== dmNewPelsWidth
428 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
430 CurrentDisplayDevice
->CurrentSettings
= Current
;
431 UpdateDisplay(hwndDlg
);
434 Current
= Current
->Blink
;
439 Current
= Current
->Flink
;
440 while (Current
!= NULL
)
442 if (Current
->dmPelsHeight
== dmNewPelsHeight
443 && Current
->dmPelsWidth
== dmNewPelsWidth
444 && Current
->dmBitsPerPel
== CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
)
446 CurrentDisplayDevice
->CurrentSettings
= Current
;
447 UpdateDisplay(hwndDlg
);
450 Current
= Current
->Flink
;
454 /* search bigger color depth compatible with current resolution */
455 Current
= CurrentDisplayDevice
->CurrentSettings
->Flink
;
456 while (Current
!= NULL
)
458 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
460 CurrentDisplayDevice
->CurrentSettings
= Current
;
461 UpdateDisplay(hwndDlg
);
464 Current
= Current
->Flink
;
467 /* search smaller color depth compatible with current resolution */
468 Current
= CurrentDisplayDevice
->CurrentSettings
->Blink
;
469 while (Current
!= NULL
)
471 if (dmNewPelsHeight
== Current
->dmPelsHeight
&& dmNewPelsWidth
== Current
->dmPelsWidth
)
473 CurrentDisplayDevice
->CurrentSettings
= Current
;
474 UpdateDisplay(hwndDlg
);
477 Current
= Current
->Blink
;
480 /* we shouldn't go there */
486 MessageBox(NULL
, TEXT("That button doesn't do anything yet"), TEXT("Whoops"), MB_OK
);
489 /* Property page dialog callback */
491 SettingsPageProc(IN HWND hwndDlg
, IN UINT uMsg
, IN WPARAM wParam
, IN LPARAM lParam
)
496 OnInitDialog(hwndDlg
);
500 DWORD controlId
= LOWORD(wParam
);
501 DWORD command
= HIWORD(wParam
);
503 if (controlId
== IDC_SETTINGS_ADVANCED
&& command
== BN_CLICKED
)
505 else if (controlId
== IDC_SETTINGS_BPP
&& command
== CBN_SELCHANGE
)
506 OnBPPChanged(hwndDlg
);
511 switch (LOWORD(wParam
))
521 DWORD newPosition
= (DWORD
) SendDlgItemMessage(hwndDlg
, IDC_SETTINGS_RESOLUTION
, TBM_GETPOS
, 0, 0);
522 OnResolutionChanged(hwndDlg
, newPosition
);
529 LPNMHDR lpnm
= (LPNMHDR
)lParam
;
530 if (lpnm
->code
== (UINT
)PSN_APPLY
)
532 if (CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
!= CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
533 || CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
!= CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
534 || CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
!= CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
)
536 /* FIXME: Need to test changes */
537 /* Apply new settings */
540 RtlZeroMemory(&devmode
, sizeof(DEVMODE
));
541 devmode
.dmSize
= (WORD
)sizeof(DEVMODE
);
542 devmode
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
543 devmode
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
544 devmode
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
545 devmode
.dmFields
= DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_BITSPERPEL
;
546 rc
= ChangeDisplaySettingsEx(
547 CurrentDisplayDevice
->DeviceName
,
554 case DISP_CHANGE_SUCCESSFUL
:
555 CurrentDisplayDevice
->InitialSettings
.dmPelsWidth
= CurrentDisplayDevice
->CurrentSettings
->dmPelsWidth
;
556 CurrentDisplayDevice
->InitialSettings
.dmPelsHeight
= CurrentDisplayDevice
->CurrentSettings
->dmPelsHeight
;
557 CurrentDisplayDevice
->InitialSettings
.dmBitsPerPel
= CurrentDisplayDevice
->CurrentSettings
->dmBitsPerPel
;
559 case DISP_CHANGE_FAILED
:
560 MessageBox(NULL
, TEXT("Failed to apply new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
562 case DISP_CHANGE_RESTART
:
563 MessageBox(NULL
, TEXT("You need to restart your computer to apply changes."), TEXT("Display settings"), MB_OK
| MB_ICONINFORMATION
);
566 MessageBox(NULL
, TEXT("Unknown error when applying new settings..."), TEXT("Display settings"), MB_OK
| MB_ICONSTOP
);
579 hdc
= BeginPaint(hwndDlg
, &ps
);
581 hdcMem
= CreateCompatibleDC(hdc
);
582 SelectObject(hdcMem
, hBitmap
);
584 TransparentBlt(hdc
, 98, 0, cxSource
, cySource
, hdcMem
, 0, 0, cxSource
, cySource
, 0xFF80FF);
587 EndPaint(hwndDlg
, &ps
);
594 PDISPLAY_DEVICE_ENTRY Current
= DisplayDeviceList
;
595 while (Current
!= NULL
)
597 PDISPLAY_DEVICE_ENTRY Next
= Current
->Flink
;
598 PSETTINGS_ENTRY CurrentSettings
= Current
->Settings
;
599 while (CurrentSettings
!= NULL
)
601 PSETTINGS_ENTRY NextSettings
= CurrentSettings
->Flink
;
602 HeapFree(GetProcessHeap(), 0, CurrentSettings
);
603 CurrentSettings
= NextSettings
;
605 HeapFree(GetProcessHeap(), 0, Current
);
609 DeleteObject(hBitmap
);