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