c6fd08fa9f4312fc3739a25fdff54e3b9347f787
[reactos.git] / reactos / dll / cpl / desk / settings.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Display Control Panel
4 * FILE: dll/cpl/desk/settings.c
5 * PURPOSE: Settings property page
6 *
7 * PROGRAMMERS: Trevor McCort (lycan359@gmail.com)
8 * Hervé Poussineau (hpoussin@reactos.org)
9 */
10
11 #include "desk.h"
12
13 typedef struct _DATA
14 {
15 PDISPLAY_DEVICE_ENTRY DisplayDeviceList;
16 PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice;
17 HBITMAP hSpectrumBitmaps[NUM_SPECTRUM_BITMAPS];
18 int cxSource[NUM_SPECTRUM_BITMAPS];
19 int cySource[NUM_SPECTRUM_BITMAPS];
20 } DATA, *PDATA;
21
22
23 static VOID
24 UpdateDisplay(IN HWND hwndDlg, PDATA pData, IN BOOL bUpdateThumb)
25 {
26 TCHAR Buffer[64];
27 TCHAR Pixel[64];
28 DWORD index;
29 HWND hwndMonSel;
30 MONSL_MONINFO info;
31
32 LoadString(hApplet, IDS_PIXEL, Pixel, sizeof(Pixel) / sizeof(TCHAR));
33 _stprintf(Buffer, Pixel, pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth, pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight, Pixel);
34 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT, WM_SETTEXT, 0, (LPARAM)Buffer);
35
36 for (index = 0; index < pData->CurrentDisplayDevice->ResolutionsCount; index++)
37 {
38 if (pData->CurrentDisplayDevice->Resolutions[index].dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth &&
39 pData->CurrentDisplayDevice->Resolutions[index].dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight)
40 {
41 if (bUpdateThumb)
42 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETPOS, TRUE, index);
43 break;
44 }
45 }
46 if (LoadString(hApplet, (2900 + pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel), Buffer, sizeof(Buffer) / sizeof(TCHAR)))
47 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)Buffer);
48
49 hwndMonSel = GetDlgItem(hwndDlg, IDC_SETTINGS_MONSEL);
50 index = (INT)SendMessage(hwndMonSel, MSLM_GETCURSEL, 0, 0);
51 if (index != (DWORD)-1 && SendMessage(hwndMonSel, MSLM_GETMONITORINFO, index, (LPARAM)&info))
52 {
53 info.Size.cx = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
54 info.Size.cy = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
55 SendMessage(hwndMonSel, MSLM_SETMONITORINFO, index, (LPARAM)&info);
56 }
57 }
58
59 static int
60 CompareSettings(PSETTINGS_ENTRY Entry, DWORD dmPelsWidth, DWORD dmPelsHeight,
61 DWORD dmBitsPerPel, DWORD dmDisplayFrequency)
62 {
63 if (Entry->dmPelsWidth == dmPelsWidth &&
64 Entry->dmPelsHeight == dmPelsHeight &&
65 Entry->dmBitsPerPel == dmBitsPerPel &&
66 Entry->dmDisplayFrequency == dmDisplayFrequency)
67 {
68 return 0;
69 }
70 else
71 if ((Entry->dmPelsWidth < dmPelsWidth) ||
72 (Entry->dmPelsWidth == dmPelsWidth && Entry->dmPelsHeight < dmPelsHeight) ||
73 (Entry->dmPelsWidth == dmPelsWidth && Entry->dmPelsHeight == dmPelsHeight &&
74 Entry->dmBitsPerPel < dmBitsPerPel))
75 {
76 return 1;
77 }
78 return -1;
79 }
80
81 static PSETTINGS_ENTRY
82 GetPossibleSettings(IN LPCTSTR DeviceName, OUT DWORD* pSettingsCount, OUT PSETTINGS_ENTRY* CurrentSettings)
83 {
84 DEVMODE devmode;
85 DWORD NbSettings = 0;
86 DWORD iMode = 0;
87 DWORD dwFlags = 0;
88 PSETTINGS_ENTRY Settings = NULL;
89 HDC hDC;
90 PSETTINGS_ENTRY Current;
91 DWORD bpp, xres, yres;
92 DWORD curDispFreq;
93
94 /* Get current settings */
95 *CurrentSettings = NULL;
96 hDC = CreateIC(NULL, DeviceName, NULL, NULL);
97 bpp = GetDeviceCaps(hDC, PLANES);
98 bpp *= GetDeviceCaps(hDC, BITSPIXEL);
99 xres = GetDeviceCaps(hDC, HORZRES);
100 yres = GetDeviceCaps(hDC, VERTRES);
101 DeleteDC(hDC);
102
103 /* List all settings */
104 devmode.dmSize = (WORD)sizeof(devmode);
105 devmode.dmDriverExtra = 0;
106
107 if (!EnumDisplaySettingsEx(DeviceName, ENUM_CURRENT_SETTINGS, &devmode, dwFlags))
108 return NULL;
109
110 curDispFreq = devmode.dmDisplayFrequency;
111
112 while (EnumDisplaySettingsEx(DeviceName, iMode, &devmode, dwFlags))
113 {
114 iMode++;
115
116 if (devmode.dmPelsWidth < 640 ||
117 devmode.dmPelsHeight < 480 ||
118 devmode.dmDisplayFrequency != curDispFreq ||
119 (devmode.dmBitsPerPel != 4 &&
120 devmode.dmBitsPerPel != 8 &&
121 devmode.dmBitsPerPel != 16 &&
122 devmode.dmBitsPerPel != 24 &&
123 devmode.dmBitsPerPel != 32))
124 {
125 continue;
126 }
127
128 Current = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY));
129 if (Current != NULL)
130 {
131 /* Sort resolutions by increasing height, and BPP */
132 PSETTINGS_ENTRY Previous = NULL;
133 PSETTINGS_ENTRY Next = Settings;
134 Current->dmPelsWidth = devmode.dmPelsWidth;
135 Current->dmPelsHeight = devmode.dmPelsHeight;
136 Current->dmBitsPerPel = devmode.dmBitsPerPel;
137 Current->dmDisplayFrequency = devmode.dmDisplayFrequency;
138 while (Next != NULL &&
139 CompareSettings(Next, devmode.dmPelsWidth,
140 devmode.dmPelsHeight, devmode.dmBitsPerPel,
141 devmode.dmDisplayFrequency) > 0)
142 {
143 Previous = Next;
144 Next = Next->Flink;
145 }
146 Current->Blink = Previous;
147 Current->Flink = Next;
148 if (Previous == NULL)
149 Settings = Current;
150 else
151 Previous->Flink = Current;
152 if (Next != NULL)
153 Next->Blink = Current;
154 if (devmode.dmPelsWidth == xres && devmode.dmPelsHeight == yres && devmode.dmBitsPerPel == bpp)
155 {
156 *CurrentSettings = Current;
157 }
158 NbSettings++;
159 }
160 }
161
162 *pSettingsCount = NbSettings;
163 return Settings;
164 }
165
166 static BOOL
167 AddDisplayDevice(IN PDATA pData, IN const DISPLAY_DEVICE *DisplayDevice)
168 {
169 PDISPLAY_DEVICE_ENTRY newEntry = NULL;
170 LPTSTR description = NULL;
171 LPTSTR name = NULL;
172 LPTSTR key = NULL;
173 LPTSTR devid = NULL;
174 SIZE_T descriptionSize, nameSize, keySize, devidSize;
175 PSETTINGS_ENTRY Current;
176 DWORD ResolutionsCount = 1;
177 DWORD i;
178
179 newEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DISPLAY_DEVICE_ENTRY));
180 if (!newEntry) goto ByeBye;
181
182 newEntry->Settings = GetPossibleSettings(DisplayDevice->DeviceName, &newEntry->SettingsCount, &newEntry->CurrentSettings);
183 if (!newEntry->Settings) goto ByeBye;
184
185 newEntry->InitialSettings.dmPelsWidth = newEntry->CurrentSettings->dmPelsWidth;
186 newEntry->InitialSettings.dmPelsHeight = newEntry->CurrentSettings->dmPelsHeight;
187 newEntry->InitialSettings.dmBitsPerPel = newEntry->CurrentSettings->dmBitsPerPel;
188
189 /* Count different resolutions */
190 for (Current = newEntry->Settings; Current != NULL; Current = Current->Flink)
191 {
192 if (Current->Flink != NULL &&
193 ((Current->dmPelsWidth != Current->Flink->dmPelsWidth) ||
194 (Current->dmPelsHeight != Current->Flink->dmPelsHeight)))
195 {
196 ResolutionsCount++;
197 }
198 }
199
200 newEntry->Resolutions = HeapAlloc(GetProcessHeap(), 0, ResolutionsCount * sizeof(RESOLUTION_INFO));
201 if (!newEntry->Resolutions) goto ByeBye;
202
203 newEntry->ResolutionsCount = ResolutionsCount;
204
205 /* Fill resolutions infos */
206 for (Current = newEntry->Settings, i = 0; Current != NULL; Current = Current->Flink)
207 {
208 if (Current->Flink == NULL ||
209 (Current->Flink != NULL &&
210 ((Current->dmPelsWidth != Current->Flink->dmPelsWidth) ||
211 (Current->dmPelsHeight != Current->Flink->dmPelsHeight))))
212 {
213 newEntry->Resolutions[i].dmPelsWidth = Current->dmPelsWidth;
214 newEntry->Resolutions[i].dmPelsHeight = Current->dmPelsHeight;
215 i++;
216 }
217 }
218 descriptionSize = (_tcslen(DisplayDevice->DeviceString) + 1) * sizeof(TCHAR);
219 description = HeapAlloc(GetProcessHeap(), 0, descriptionSize);
220 if (!description) goto ByeBye;
221
222 nameSize = (_tcslen(DisplayDevice->DeviceName) + 1) * sizeof(TCHAR);
223 name = HeapAlloc(GetProcessHeap(), 0, nameSize);
224 if (!name) goto ByeBye;
225
226 keySize = (_tcslen(DisplayDevice->DeviceKey) + 1) * sizeof(TCHAR);
227 key = HeapAlloc(GetProcessHeap(), 0, keySize);
228 if (!key) goto ByeBye;
229
230 devidSize = (_tcslen(DisplayDevice->DeviceID) + 1) * sizeof(TCHAR);
231 devid = HeapAlloc(GetProcessHeap(), 0, devidSize);
232 if (!devid) goto ByeBye;
233
234 memcpy(description, DisplayDevice->DeviceString, descriptionSize);
235 memcpy(name, DisplayDevice->DeviceName, nameSize);
236 memcpy(key, DisplayDevice->DeviceKey, keySize);
237 memcpy(devid, DisplayDevice->DeviceID, devidSize);
238 newEntry->DeviceDescription = description;
239 newEntry->DeviceName = name;
240 newEntry->DeviceKey = key;
241 newEntry->DeviceID = devid;
242 newEntry->DeviceStateFlags = DisplayDevice->StateFlags;
243 newEntry->Flink = pData->DisplayDeviceList;
244 pData->DisplayDeviceList = newEntry;
245 return TRUE;
246
247 ByeBye:
248 if (newEntry != NULL)
249 {
250 if (newEntry->Settings != NULL)
251 {
252 Current = newEntry->Settings;
253 while (Current != NULL)
254 {
255 PSETTINGS_ENTRY Next = Current->Flink;
256 HeapFree(GetProcessHeap(), 0, Current);
257 Current = Next;
258 }
259 }
260 if (newEntry->Resolutions != NULL)
261 HeapFree(GetProcessHeap(), 0, newEntry->Resolutions);
262 HeapFree(GetProcessHeap(), 0, newEntry);
263 }
264 if (description != NULL)
265 HeapFree(GetProcessHeap(), 0, description);
266 if (name != NULL)
267 HeapFree(GetProcessHeap(), 0, name);
268 if (key != NULL)
269 HeapFree(GetProcessHeap(), 0, key);
270 return FALSE;
271 }
272
273 static VOID
274 OnDisplayDeviceChanged(IN HWND hwndDlg, IN PDATA pData, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry)
275 {
276 PSETTINGS_ENTRY Current;
277 DWORD index;
278
279 pData->CurrentDisplayDevice = pDeviceEntry; /* Update variable */
280
281 /* Fill color depths combo box */
282 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_RESETCONTENT, 0, 0);
283 for (Current = pDeviceEntry->Settings; Current != NULL; Current = Current->Flink)
284 {
285 TCHAR Buffer[64];
286 if (LoadString(hApplet, (2900 + Current->dmBitsPerPel), Buffer, sizeof(Buffer) / sizeof(TCHAR)))
287 {
288 index = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)Buffer);
289 if (index == (DWORD)CB_ERR)
290 {
291 index = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_ADDSTRING, 0, (LPARAM)Buffer);
292 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SETITEMDATA, index, Current->dmBitsPerPel);
293 }
294 }
295 }
296
297 /* Fill resolutions slider */
298 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_CLEARTICS, TRUE, 0);
299 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETRANGE, TRUE, MAKELONG(0, pDeviceEntry->ResolutionsCount - 1));
300
301 UpdateDisplay(hwndDlg, pData, TRUE);
302 }
303
304 static VOID
305 OnInitDialog(IN HWND hwndDlg)
306 {
307 BITMAP bitmap;
308 DWORD Result = 0;
309 DWORD iDevNum = 0;
310 DWORD i;
311 DISPLAY_DEVICE displayDevice;
312 PDATA pData;
313
314 pData = HeapAlloc(GetProcessHeap(), 0, sizeof(DATA));
315 if (pData == NULL)
316 return;
317
318 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
319
320 /* Get video cards list */
321 pData->DisplayDeviceList = NULL;
322 displayDevice.cb = sizeof(displayDevice);
323 while (EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0x1))
324 {
325 if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0)
326 {
327 if (AddDisplayDevice(pData, &displayDevice))
328 Result++;
329 }
330 iDevNum++;
331 }
332
333 if (Result == 0)
334 {
335 /* No adapter found */
336 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_BPP), FALSE);
337 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION), FALSE);
338 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT), FALSE);
339 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_ADVANCED), FALSE);
340 ShowWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM), SW_HIDE);
341
342 /* Do not initialize the color spectrum bitmaps */
343 memset(pData->hSpectrumBitmaps, 0, sizeof(pData->hSpectrumBitmaps));
344 return;
345 }
346 else if (Result == 1)
347 {
348 MONSL_MONINFO monitors;
349
350 /* Single video adapter */
351 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_DEVICE, WM_SETTEXT, 0, (LPARAM)pData->DisplayDeviceList->DeviceDescription);
352 OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList);
353
354 monitors.Position.x = monitors.Position.y = 0;
355 monitors.Size.cx = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
356 monitors.Size.cy = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
357 monitors.Flags = 0;
358 SendDlgItemMessage(hwndDlg,
359 IDC_SETTINGS_MONSEL,
360 MSLM_SETMONITORSINFO,
361 1,
362 (LPARAM)&monitors);
363 }
364 else /* FIXME: Incomplete! */
365 {
366 PMONSL_MONINFO pMonitors;
367 DWORD i;
368
369 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_DEVICE, WM_SETTEXT, 0, (LPARAM)pData->DisplayDeviceList->DeviceDescription);
370 OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList);
371
372 pMonitors = (PMONSL_MONINFO)HeapAlloc(GetProcessHeap(), 0, sizeof(MONSL_MONINFO) * Result);
373 if (pMonitors)
374 {
375 DWORD hack = 1280;
376 for (i = 0; i < Result; i++)
377 {
378 pMonitors[i].Position.x = hack * i;
379 pMonitors[i].Position.y = 0;
380 pMonitors[i].Size.cx = pData->DisplayDeviceList->CurrentSettings->dmPelsWidth;
381 pMonitors[i].Size.cy = pData->DisplayDeviceList->CurrentSettings->dmPelsHeight;
382 pMonitors[i].Flags = 0;
383 }
384
385 SendDlgItemMessage(hwndDlg,
386 IDC_SETTINGS_MONSEL,
387 MSLM_SETMONITORSINFO,
388 Result,
389 (LPARAM)pMonitors);
390
391 HeapFree(GetProcessHeap(), 0, pMonitors);
392 }
393 }
394
395 /* Initialize the color spectrum bitmaps */
396 for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++)
397 {
398 pData->hSpectrumBitmaps[i] = LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_SPECTRUM_4 + i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
399
400 if (pData->hSpectrumBitmaps[i] != NULL)
401 {
402 if (GetObjectW(pData->hSpectrumBitmaps[i], sizeof(BITMAP), &bitmap) != 0)
403 {
404 pData->cxSource[i] = bitmap.bmWidth;
405 pData->cySource[i] = bitmap.bmHeight;
406 }
407 else
408 {
409 pData->cxSource[i] = 0;
410 pData->cySource[i] = 0;
411 }
412 }
413 }
414 }
415
416 /* Get the ID for DATA::hSpectrumBitmaps */
417 static VOID
418 ShowColorSpectrum(IN HDC hDC, IN LPRECT client, IN DWORD BitsPerPel, IN PDATA pData)
419 {
420 HDC hdcMem;
421 INT iBitmap;
422
423 hdcMem = CreateCompatibleDC(hDC);
424
425 if (!hdcMem)
426 return;
427
428 switch(BitsPerPel)
429 {
430 case 4: iBitmap = 0; break;
431 case 8: iBitmap = 1; break;
432 default: iBitmap = 2;
433 }
434
435 if (SelectObject(hdcMem, pData->hSpectrumBitmaps[iBitmap]))
436 {
437 StretchBlt(hDC,
438 client->left, client->top,
439 client->right - client->left,
440 client->bottom - client->top,
441 hdcMem, 0, 0,
442 pData->cxSource[iBitmap],
443 pData->cySource[iBitmap], SRCCOPY);
444 }
445
446 DeleteDC(hdcMem);
447 }
448
449 static VOID
450 OnBPPChanged(IN HWND hwndDlg, IN PDATA pData)
451 {
452 /* If new BPP is not compatible with resolution:
453 * 1) try to find the nearest smaller matching resolution
454 * 2) otherwise, get the nearest bigger resolution
455 */
456 PSETTINGS_ENTRY Current;
457 DWORD dmNewBitsPerPel;
458 DWORD index;
459 HDC hSpectrumDC;
460 HWND hSpectrumControl;
461 RECT client;
462
463 index = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETCURSEL, 0, 0);
464 dmNewBitsPerPel = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETITEMDATA, index, 0);
465
466 /* Show a new spectrum bitmap */
467 hSpectrumControl = GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM);
468 hSpectrumDC = GetDC(hSpectrumControl);
469 GetClientRect(hSpectrumControl, &client);
470 ShowColorSpectrum(hSpectrumDC, &client, dmNewBitsPerPel, pData);
471
472 /* Find if new parameters are valid */
473 Current = pData->CurrentDisplayDevice->CurrentSettings;
474 if (dmNewBitsPerPel == Current->dmBitsPerPel)
475 {
476 /* No change */
477 return;
478 }
479
480 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
481
482 if (dmNewBitsPerPel < Current->dmBitsPerPel)
483 {
484 Current = Current->Blink;
485 while (Current != NULL)
486 {
487 if (Current->dmBitsPerPel == dmNewBitsPerPel
488 && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight
489 && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
490 {
491 pData->CurrentDisplayDevice->CurrentSettings = Current;
492 UpdateDisplay(hwndDlg, pData, TRUE);
493 return;
494 }
495 Current = Current->Blink;
496 }
497 }
498 else
499 {
500 Current = Current->Flink;
501 while (Current != NULL)
502 {
503 if (Current->dmBitsPerPel == dmNewBitsPerPel
504 && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight
505 && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
506 {
507 pData->CurrentDisplayDevice->CurrentSettings = Current;
508 UpdateDisplay(hwndDlg, pData, TRUE);
509 return;
510 }
511 Current = Current->Flink;
512 }
513 }
514
515 /* Search smaller resolution compatible with current color depth */
516 Current = pData->CurrentDisplayDevice->CurrentSettings->Blink;
517 while (Current != NULL)
518 {
519 if (Current->dmBitsPerPel == dmNewBitsPerPel)
520 {
521 pData->CurrentDisplayDevice->CurrentSettings = Current;
522 UpdateDisplay(hwndDlg, pData, TRUE);
523 return;
524 }
525 Current = Current->Blink;
526 }
527
528 /* Search bigger resolution compatible with current color depth */
529 Current = pData->CurrentDisplayDevice->CurrentSettings->Flink;
530 while (Current != NULL)
531 {
532 if (Current->dmBitsPerPel == dmNewBitsPerPel)
533 {
534 pData->CurrentDisplayDevice->CurrentSettings = Current;
535 UpdateDisplay(hwndDlg, pData, TRUE);
536 return;
537 }
538 Current = Current->Flink;
539 }
540
541 /* We shouldn't go there */
542 }
543
544 static VOID
545 OnResolutionChanged(IN HWND hwndDlg, IN PDATA pData, IN DWORD NewPosition,
546 IN BOOL bUpdateThumb)
547 {
548 /* If new resolution is not compatible with color depth:
549 * 1) try to find the nearest bigger matching color depth
550 * 2) otherwise, get the nearest smaller color depth
551 */
552 PSETTINGS_ENTRY Current;
553 DWORD dmNewPelsHeight = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsHeight;
554 DWORD dmNewPelsWidth = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsWidth;
555 DWORD dmBitsPerPel;
556 DWORD dmDisplayFrequency;
557
558 /* Find if new parameters are valid */
559 Current = pData->CurrentDisplayDevice->CurrentSettings;
560 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
561 {
562 /* No change */
563 return;
564 }
565
566 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
567
568 dmBitsPerPel = Current->dmBitsPerPel;
569 dmDisplayFrequency = Current->dmDisplayFrequency;
570
571 if (CompareSettings(Current, dmNewPelsWidth,
572 dmNewPelsHeight, dmBitsPerPel,
573 dmDisplayFrequency) < 0)
574 {
575 Current = Current->Blink;
576 while (Current != NULL)
577 {
578 if (Current->dmPelsHeight == dmNewPelsHeight
579 && Current->dmPelsWidth == dmNewPelsWidth
580 && Current->dmBitsPerPel == dmBitsPerPel)
581 {
582 pData->CurrentDisplayDevice->CurrentSettings = Current;
583 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
584 return;
585 }
586 Current = Current->Blink;
587 }
588 }
589 else
590 {
591 Current = Current->Flink;
592 while (Current != NULL)
593 {
594 if (Current->dmPelsHeight == dmNewPelsHeight
595 && Current->dmPelsWidth == dmNewPelsWidth
596 && Current->dmBitsPerPel == dmBitsPerPel)
597 {
598 pData->CurrentDisplayDevice->CurrentSettings = Current;
599 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
600 return;
601 }
602 Current = Current->Flink;
603 }
604 }
605
606 /* Search bigger color depth compatible with current resolution */
607 Current = pData->CurrentDisplayDevice->CurrentSettings->Flink;
608 while (Current != NULL)
609 {
610 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
611 {
612 pData->CurrentDisplayDevice->CurrentSettings = Current;
613 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
614 return;
615 }
616 Current = Current->Flink;
617 }
618
619 /* Search smaller color depth compatible with current resolution */
620 Current = pData->CurrentDisplayDevice->CurrentSettings->Blink;
621 while (Current != NULL)
622 {
623 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
624 {
625 pData->CurrentDisplayDevice->CurrentSettings = Current;
626 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
627 return;
628 }
629 Current = Current->Blink;
630 }
631
632 /* We shouldn't go there */
633 }
634
635 /* Property sheet page callback */
636 UINT CALLBACK
637 SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
638 {
639 UINT Ret = 0;
640
641 switch (uMsg)
642 {
643 case PSPCB_CREATE:
644 Ret = RegisterMonitorSelectionControl(hApplet);
645 break;
646
647 case PSPCB_RELEASE:
648 UnregisterMonitorSelectionControl(hApplet);
649 break;
650 }
651
652 return Ret;
653 }
654
655 /* Property page dialog callback */
656 INT_PTR CALLBACK
657 SettingsPageProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
658 {
659 PDATA pData;
660 TCHAR Message[1024], Title[256];
661
662 pData = (PDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
663
664 switch(uMsg)
665 {
666 case WM_INITDIALOG:
667 {
668 OnInitDialog(hwndDlg);
669 break;
670 }
671 case WM_DRAWITEM:
672 {
673 LPDRAWITEMSTRUCT lpDrawItem;
674 lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
675
676 if (lpDrawItem->CtlID == IDC_SETTINGS_SPECTRUM)
677 ShowColorSpectrum(lpDrawItem->hDC, &lpDrawItem->rcItem, pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel, pData);
678 break;
679 }
680 case WM_COMMAND:
681 {
682 DWORD controlId = LOWORD(wParam);
683 DWORD command = HIWORD(wParam);
684
685 if (controlId == IDC_SETTINGS_ADVANCED && command == BN_CLICKED)
686 DisplayAdvancedSettings(hwndDlg, pData->CurrentDisplayDevice);
687 else if (controlId == IDC_SETTINGS_BPP && command == CBN_SELCHANGE)
688 OnBPPChanged(hwndDlg, pData);
689 break;
690 }
691 case WM_HSCROLL:
692 {
693 switch (LOWORD(wParam))
694 {
695 case TB_LINEUP:
696 case TB_LINEDOWN:
697 case TB_PAGEUP:
698 case TB_PAGEDOWN:
699 case TB_TOP:
700 case TB_BOTTOM:
701 case TB_ENDTRACK:
702 {
703 DWORD newPosition = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_GETPOS, 0, 0);
704 OnResolutionChanged(hwndDlg, pData, newPosition, TRUE);
705 break;
706 }
707
708 case TB_THUMBTRACK:
709 OnResolutionChanged(hwndDlg, pData, HIWORD(wParam), FALSE);
710 break;
711 }
712 break;
713 }
714 case WM_NOTIFY:
715 {
716 LPNMHDR lpnm = (LPNMHDR)lParam;
717 if (lpnm->code == (UINT)PSN_APPLY)
718 {
719 if (pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth != pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth
720 || pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight != pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight
721 || pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel != pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel)
722 {
723 /* FIXME: Need to test changes */
724 /* Apply new settings */
725 LONG rc;
726 DEVMODE devmode;
727 RtlZeroMemory(&devmode, sizeof(devmode));
728 devmode.dmSize = (WORD)sizeof(devmode);
729 devmode.dmPelsWidth = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
730 devmode.dmPelsHeight = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
731 devmode.dmBitsPerPel = pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel;
732 devmode.dmDisplayFrequency = pData->CurrentDisplayDevice->CurrentSettings->dmDisplayFrequency;
733 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
734 rc = ChangeDisplaySettingsEx(
735 pData->CurrentDisplayDevice->DeviceName,
736 &devmode,
737 NULL,
738 CDS_UPDATEREGISTRY,
739 NULL);
740 switch (rc)
741 {
742 case DISP_CHANGE_SUCCESSFUL:
743 pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
744 pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
745 pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel = pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel;
746 break;
747 case DISP_CHANGE_RESTART:
748 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR));
749 LoadString(hApplet, IDS_APPLY_NEEDS_RESTART, Message, sizeof(Message) / sizeof (TCHAR));
750 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONINFORMATION);
751 break;
752 case DISP_CHANGE_FAILED:
753 default:
754 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR));
755 LoadString(hApplet, IDS_APPLY_FAILED, Message, sizeof(Message) / sizeof (TCHAR));
756 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONSTOP);
757 break;
758 }
759 }
760 }
761 break;
762 }
763
764 case WM_CONTEXTMENU:
765 {
766 HWND hwndMonSel;
767 HMENU hPopup;
768 UINT uiCmd;
769 POINT pt, ptClient;
770 INT Index;
771
772 pt.x = (SHORT)LOWORD(lParam);
773 pt.y = (SHORT)HIWORD(lParam);
774
775 hwndMonSel = GetDlgItem(hwndDlg,
776 IDC_SETTINGS_MONSEL);
777 if ((HWND)wParam == hwndMonSel)
778 {
779 if (pt.x == -1 && pt.y == -1)
780 {
781 RECT rcMon;
782
783 Index = (INT)SendMessage(hwndMonSel,
784 MSLM_GETCURSEL,
785 0,
786 0);
787
788 if (Index >= 0 &&
789 (INT)SendMessage(hwndMonSel,
790 MSLM_GETMONITORRECT,
791 Index,
792 (LPARAM)&rcMon) > 0)
793 {
794 pt.x = rcMon.left + ((rcMon.right - rcMon.left) / 2);
795 pt.y = rcMon.top + ((rcMon.bottom - rcMon.top) / 2);
796 }
797 else
798 pt.x = pt.y = 0;
799
800 MapWindowPoints(hwndMonSel,
801 NULL,
802 &pt,
803 1);
804 }
805 else
806 {
807 ptClient = pt;
808 MapWindowPoints(NULL,
809 hwndMonSel,
810 &ptClient,
811 1);
812
813 Index = (INT)SendMessage(hwndMonSel,
814 MSLM_HITTEST,
815 (WPARAM)&ptClient,
816 0);
817 }
818
819 if (Index >= 0)
820 {
821 hPopup = LoadPopupMenu(hApplet,
822 MAKEINTRESOURCE(IDM_MONITOR_MENU));
823 if (hPopup != NULL)
824 {
825 /* FIXME: Enable/Disable menu items */
826 EnableMenuItem(hPopup,
827 ID_MENU_ATTACHED,
828 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
829 EnableMenuItem(hPopup,
830 ID_MENU_PRIMARY,
831 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
832 EnableMenuItem(hPopup,
833 ID_MENU_IDENTIFY,
834 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
835 EnableMenuItem(hPopup,
836 ID_MENU_PROPERTIES,
837 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
838
839 uiCmd = (UINT)TrackPopupMenu(hPopup,
840 TPM_RETURNCMD | TPM_RIGHTBUTTON,
841 pt.x,
842 pt.y,
843 0,
844 hwndDlg,
845 NULL);
846
847 switch (uiCmd)
848 {
849 case ID_MENU_ATTACHED:
850 case ID_MENU_PRIMARY:
851 case ID_MENU_IDENTIFY:
852 case ID_MENU_PROPERTIES:
853 /* FIXME: Implement */
854 break;
855 }
856
857 DestroyMenu(hPopup);
858 }
859 }
860 }
861 break;
862 }
863
864 case WM_DESTROY:
865 {
866 DWORD i;
867 PDISPLAY_DEVICE_ENTRY Current = pData->DisplayDeviceList;
868
869 while (Current != NULL)
870 {
871 PDISPLAY_DEVICE_ENTRY Next = Current->Flink;
872 PSETTINGS_ENTRY CurrentSettings = Current->Settings;
873 while (CurrentSettings != NULL)
874 {
875 PSETTINGS_ENTRY NextSettings = CurrentSettings->Flink;
876 HeapFree(GetProcessHeap(), 0, CurrentSettings);
877 CurrentSettings = NextSettings;
878 }
879 HeapFree(GetProcessHeap(), 0, Current);
880 Current = Next;
881 }
882
883 for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++)
884 {
885 if (pData->hSpectrumBitmaps[i])
886 DeleteObject(pData->hSpectrumBitmaps[i]);
887 }
888
889 HeapFree(GetProcessHeap(), 0, pData);
890 }
891 }
892 return FALSE;
893 }