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