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 device description */ 304 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_DEVICE, WM_SETTEXT, 0, (LPARAM)pDeviceEntry->DeviceDescription); 305 306 /* Fill resolutions slider */ 307 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_CLEARTICS, TRUE, 0); 308 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETRANGE, TRUE, MAKELONG(0, pDeviceEntry->ResolutionsCount - 1)); 309 310 UpdateDisplay(hwndDlg, pData, TRUE); 311 } 312 313 static VOID 314 SettingsOnInitDialog(IN HWND hwndDlg) 315 { 316 BITMAP bitmap; 317 DWORD Result = 0; 318 DWORD iDevNum = 0; 319 DWORD i; 320 DISPLAY_DEVICE displayDevice; 321 PSETTINGS_DATA pData; 322 323 pData = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_DATA)); 324 if (pData == NULL) 325 return; 326 327 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData); 328 329 /* Get video cards list */ 330 pData->DisplayDeviceList = NULL; 331 displayDevice.cb = sizeof(displayDevice); 332 while (EnumDisplayDevices(NULL, iDevNum, &displayDevice, 0x1)) 333 { 334 if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0) 335 { 336 if (AddDisplayDevice(pData, &displayDevice)) 337 Result++; 338 } 339 iDevNum++; 340 } 341 342 if (Result == 0) 343 { 344 /* No adapter found */ 345 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_BPP), FALSE); 346 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION), FALSE); 347 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT), FALSE); 348 EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_ADVANCED), FALSE); 349 ShowWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM), SW_HIDE); 350 351 /* Do not initialize the color spectrum bitmaps */ 352 memset(pData->hSpectrumBitmaps, 0, sizeof(pData->hSpectrumBitmaps)); 353 return; 354 } 355 else if (Result == 1) 356 { 357 MONSL_MONINFO monitors; 358 359 /* Single video adapter */ 360 OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList); 361 362 monitors.Position.x = monitors.Position.y = 0; 363 monitors.Size.cx = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth; 364 monitors.Size.cy = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight; 365 monitors.Flags = 0; 366 SendDlgItemMessage(hwndDlg, 367 IDC_SETTINGS_MONSEL, 368 MSLM_SETMONITORSINFO, 369 1, 370 (LPARAM)&monitors); 371 } 372 else /* FIXME: Incomplete! */ 373 { 374 PMONSL_MONINFO pMonitors; 375 DWORD i; 376 377 OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList); 378 379 pMonitors = (PMONSL_MONINFO)HeapAlloc(GetProcessHeap(), 0, sizeof(MONSL_MONINFO) * Result); 380 if (pMonitors) 381 { 382 DWORD hack = 1280; 383 for (i = 0; i < Result; i++) 384 { 385 pMonitors[i].Position.x = hack * i; 386 pMonitors[i].Position.y = 0; 387 pMonitors[i].Size.cx = pData->DisplayDeviceList->CurrentSettings->dmPelsWidth; 388 pMonitors[i].Size.cy = pData->DisplayDeviceList->CurrentSettings->dmPelsHeight; 389 pMonitors[i].Flags = 0; 390 } 391 392 SendDlgItemMessage(hwndDlg, 393 IDC_SETTINGS_MONSEL, 394 MSLM_SETMONITORSINFO, 395 Result, 396 (LPARAM)pMonitors); 397 398 HeapFree(GetProcessHeap(), 0, pMonitors); 399 } 400 } 401 402 /* Initialize the color spectrum bitmaps */ 403 for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++) 404 { 405 pData->hSpectrumBitmaps[i] = LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_SPECTRUM_4 + i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); 406 407 if (pData->hSpectrumBitmaps[i] != NULL) 408 { 409 if (GetObjectW(pData->hSpectrumBitmaps[i], sizeof(BITMAP), &bitmap) != 0) 410 { 411 pData->cxSource[i] = bitmap.bmWidth; 412 pData->cySource[i] = bitmap.bmHeight; 413 } 414 else 415 { 416 pData->cxSource[i] = 0; 417 pData->cySource[i] = 0; 418 } 419 } 420 } 421 } 422 423 /* Get the ID for SETTINGS_DATA::hSpectrumBitmaps */ 424 static VOID 425 ShowColorSpectrum(IN HDC hDC, IN LPRECT client, IN DWORD BitsPerPel, IN PSETTINGS_DATA pData) 426 { 427 HDC hdcMem; 428 INT iBitmap; 429 430 hdcMem = CreateCompatibleDC(hDC); 431 432 if (!hdcMem) 433 return; 434 435 switch(BitsPerPel) 436 { 437 case 4: iBitmap = 0; break; 438 case 8: iBitmap = 1; break; 439 default: iBitmap = 2; 440 } 441 442 if (SelectObject(hdcMem, pData->hSpectrumBitmaps[iBitmap])) 443 { 444 StretchBlt(hDC, 445 client->left, client->top, 446 client->right - client->left, 447 client->bottom - client->top, 448 hdcMem, 0, 0, 449 pData->cxSource[iBitmap], 450 pData->cySource[iBitmap], SRCCOPY); 451 } 452 453 DeleteDC(hdcMem); 454 } 455 456 static VOID 457 OnBPPChanged(IN HWND hwndDlg, IN PSETTINGS_DATA pData) 458 { 459 /* If new BPP is not compatible with resolution: 460 * 1) try to find the nearest smaller matching resolution 461 * 2) otherwise, get the nearest bigger resolution 462 */ 463 PSETTINGS_ENTRY Current; 464 DWORD dmNewBitsPerPel; 465 DWORD index; 466 HDC hSpectrumDC; 467 HWND hSpectrumControl; 468 RECT client; 469 470 index = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETCURSEL, 0, 0); 471 dmNewBitsPerPel = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETITEMDATA, index, 0); 472 473 /* Show a new spectrum bitmap */ 474 hSpectrumControl = GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM); 475 hSpectrumDC = GetDC(hSpectrumControl); 476 if (hSpectrumDC == NULL) 477 return; 478 479 GetClientRect(hSpectrumControl, &client); 480 ShowColorSpectrum(hSpectrumDC, &client, dmNewBitsPerPel, pData); 481 ReleaseDC(hSpectrumControl, hSpectrumDC); 482 483 /* Find if new parameters are valid */ 484 Current = pData->CurrentDisplayDevice->CurrentSettings; 485 if (dmNewBitsPerPel == Current->dmBitsPerPel) 486 { 487 /* No change */ 488 return; 489 } 490 491 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 492 493 if (dmNewBitsPerPel < Current->dmBitsPerPel) 494 { 495 Current = Current->Blink; 496 while (Current != NULL) 497 { 498 if (Current->dmBitsPerPel == dmNewBitsPerPel 499 && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight 500 && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth) 501 { 502 pData->CurrentDisplayDevice->CurrentSettings = Current; 503 UpdateDisplay(hwndDlg, pData, TRUE); 504 return; 505 } 506 Current = Current->Blink; 507 } 508 } 509 else 510 { 511 Current = Current->Flink; 512 while (Current != NULL) 513 { 514 if (Current->dmBitsPerPel == dmNewBitsPerPel 515 && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight 516 && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth) 517 { 518 pData->CurrentDisplayDevice->CurrentSettings = Current; 519 UpdateDisplay(hwndDlg, pData, TRUE); 520 return; 521 } 522 Current = Current->Flink; 523 } 524 } 525 526 /* Search smaller resolution compatible with current color depth */ 527 Current = pData->CurrentDisplayDevice->CurrentSettings->Blink; 528 while (Current != NULL) 529 { 530 if (Current->dmBitsPerPel == dmNewBitsPerPel) 531 { 532 pData->CurrentDisplayDevice->CurrentSettings = Current; 533 UpdateDisplay(hwndDlg, pData, TRUE); 534 return; 535 } 536 Current = Current->Blink; 537 } 538 539 /* Search bigger resolution compatible with current color depth */ 540 Current = pData->CurrentDisplayDevice->CurrentSettings->Flink; 541 while (Current != NULL) 542 { 543 if (Current->dmBitsPerPel == dmNewBitsPerPel) 544 { 545 pData->CurrentDisplayDevice->CurrentSettings = Current; 546 UpdateDisplay(hwndDlg, pData, TRUE); 547 return; 548 } 549 Current = Current->Flink; 550 } 551 552 /* We shouldn't go there */ 553 } 554 555 static VOID 556 OnResolutionChanged(IN HWND hwndDlg, IN PSETTINGS_DATA pData, IN DWORD NewPosition, 557 IN BOOL bUpdateThumb) 558 { 559 /* If new resolution is not compatible with color depth: 560 * 1) try to find the nearest bigger matching color depth 561 * 2) otherwise, get the nearest smaller color depth 562 */ 563 PSETTINGS_ENTRY Current; 564 DWORD dmNewPelsHeight = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsHeight; 565 DWORD dmNewPelsWidth = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsWidth; 566 DWORD dmBitsPerPel; 567 DWORD dmDisplayFrequency; 568 569 /* Find if new parameters are valid */ 570 Current = pData->CurrentDisplayDevice->CurrentSettings; 571 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth) 572 { 573 /* No change */ 574 return; 575 } 576 577 PropSheet_Changed(GetParent(hwndDlg), hwndDlg); 578 579 dmBitsPerPel = Current->dmBitsPerPel; 580 dmDisplayFrequency = Current->dmDisplayFrequency; 581 582 if (CompareSettings(Current, dmNewPelsWidth, 583 dmNewPelsHeight, dmBitsPerPel, 584 dmDisplayFrequency) < 0) 585 { 586 Current = Current->Blink; 587 while (Current != NULL) 588 { 589 if (Current->dmPelsHeight == dmNewPelsHeight 590 && Current->dmPelsWidth == dmNewPelsWidth 591 && Current->dmBitsPerPel == dmBitsPerPel) 592 { 593 pData->CurrentDisplayDevice->CurrentSettings = Current; 594 UpdateDisplay(hwndDlg, pData, bUpdateThumb); 595 return; 596 } 597 Current = Current->Blink; 598 } 599 } 600 else 601 { 602 Current = Current->Flink; 603 while (Current != NULL) 604 { 605 if (Current->dmPelsHeight == dmNewPelsHeight 606 && Current->dmPelsWidth == dmNewPelsWidth 607 && Current->dmBitsPerPel == dmBitsPerPel) 608 { 609 pData->CurrentDisplayDevice->CurrentSettings = Current; 610 UpdateDisplay(hwndDlg, pData, bUpdateThumb); 611 return; 612 } 613 Current = Current->Flink; 614 } 615 } 616 617 /* Search bigger color depth compatible with current resolution */ 618 Current = pData->CurrentDisplayDevice->CurrentSettings->Flink; 619 while (Current != NULL) 620 { 621 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth) 622 { 623 pData->CurrentDisplayDevice->CurrentSettings = Current; 624 UpdateDisplay(hwndDlg, pData, bUpdateThumb); 625 return; 626 } 627 Current = Current->Flink; 628 } 629 630 /* Search smaller color depth compatible with current resolution */ 631 Current = pData->CurrentDisplayDevice->CurrentSettings->Blink; 632 while (Current != NULL) 633 { 634 if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth) 635 { 636 pData->CurrentDisplayDevice->CurrentSettings = Current; 637 UpdateDisplay(hwndDlg, pData, bUpdateThumb); 638 return; 639 } 640 Current = Current->Blink; 641 } 642 643 /* We shouldn't go there */ 644 } 645 646 /* Property sheet page callback */ 647 UINT CALLBACK 648 SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp) 649 { 650 UINT Ret = 0; 651 652 switch (uMsg) 653 { 654 case PSPCB_CREATE: 655 Ret = RegisterMonitorSelectionControl(hApplet); 656 break; 657 658 case PSPCB_RELEASE: 659 UnregisterMonitorSelectionControl(hApplet); 660 break; 661 } 662 663 return Ret; 664 } 665 666 static INT_PTR CALLBACK 667 ConfirmDlgProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) 668 { 669 PTIMEOUTDATA pData; 670 671 pData = (PTIMEOUTDATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 672 673 switch(uMsg) 674 { 675 case WM_INITDIALOG: 676 /* Allocate the local dialog data */ 677 pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEOUTDATA)); 678 if (pData == NULL) 679 return FALSE; 680 681 /* Link the dialog data to the dialog */ 682 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData); 683 684 /* Timeout in seconds */ 685 pData->nTimeout = 15; 686 687 /* Load the raw timeout string */ 688 LoadString(hApplet, IDS_TIMEOUTTEXT, pData->szRawBuffer, ARRAYSIZE(pData->szRawBuffer)); 689 690 /* Cook the timeout string and show it */ 691 _stprintf(pData->szCookedBuffer, pData->szRawBuffer, pData->nTimeout); 692 SetDlgItemText(hwndDlg, IDC_TIMEOUTTEXT, pData->szCookedBuffer); 693 694 /* Start the timer (ticks every second)*/ 695 SetTimer(hwndDlg, 1, 1000, NULL); 696 break; 697 698 case WM_TIMER: 699 /* Update the timepout value */ 700 pData->nTimeout--; 701 702 /* Update the timeout text */ 703 _stprintf(pData->szCookedBuffer, pData->szRawBuffer, pData->nTimeout); 704 SetDlgItemText(hwndDlg, IDC_TIMEOUTTEXT, pData->szCookedBuffer); 705 706 /* Kill the timer and return a 'No', if we ran out of time */ 707 if (pData->nTimeout == 0) 708 { 709 KillTimer(hwndDlg, 1); 710 EndDialog(hwndDlg, IDNO); 711 } 712 break; 713 714 case WM_COMMAND: 715 /* Kill the timer and return the clicked button id */ 716 KillTimer(hwndDlg, 1); 717 EndDialog(hwndDlg, LOWORD(wParam)); 718 break; 719 720 case WM_DESTROY: 721 /* Free the local dialog data */ 722 HeapFree(GetProcessHeap(), 0, pData); 723 break; 724 } 725 726 return FALSE; 727 } 728 729 static VOID 730 ApplyDisplaySettings(HWND hwndDlg, PSETTINGS_DATA pData) 731 { 732 TCHAR Message[1024], Title[256]; 733 DEVMODE devmode; 734 LONG rc; 735 736 RtlZeroMemory(&devmode, sizeof(devmode)); 737 devmode.dmSize = (WORD)sizeof(devmode); 738 devmode.dmPelsWidth = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth; 739 devmode.dmPelsHeight = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight; 740 devmode.dmBitsPerPel = pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel; 741 devmode.dmDisplayFrequency = pData->CurrentDisplayDevice->CurrentSettings->dmDisplayFrequency; 742 devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; 743 744 rc = ChangeDisplaySettingsEx(pData->CurrentDisplayDevice->DeviceName, 745 &devmode, 746 NULL, 747 CDS_UPDATEREGISTRY, 748 NULL); 749 switch (rc) 750 { 751 case DISP_CHANGE_SUCCESSFUL: 752 break; 753 754 case DISP_CHANGE_RESTART: 755 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR)); 756 LoadString(hApplet, IDS_APPLY_NEEDS_RESTART, Message, sizeof(Message) / sizeof (TCHAR)); 757 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONINFORMATION); 758 return; 759 760 case DISP_CHANGE_FAILED: 761 default: 762 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR)); 763 LoadString(hApplet, IDS_APPLY_FAILED, Message, sizeof(Message) / sizeof (TCHAR)); 764 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONSTOP); 765 return; 766 } 767 768 if (DialogBox(hApplet, MAKEINTRESOURCE(IDD_CONFIRMSETTINGS), hwndDlg, ConfirmDlgProc) == IDYES) 769 { 770 pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth; 771 pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight; 772 pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel = pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel; 773 } 774 else 775 { 776 devmode.dmPelsWidth = pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth; 777 devmode.dmPelsHeight = pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight; 778 devmode.dmBitsPerPel = pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel; 779 devmode.dmDisplayFrequency = pData->CurrentDisplayDevice->InitialSettings.dmDisplayFrequency; 780 781 rc = ChangeDisplaySettingsEx(pData->CurrentDisplayDevice->DeviceName, 782 &devmode, 783 NULL, 784 CDS_UPDATEREGISTRY, 785 NULL); 786 switch (rc) 787 { 788 case DISP_CHANGE_SUCCESSFUL: 789 pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth = pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth; 790 pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight = pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight; 791 pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel = pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel; 792 UpdateDisplay(hwndDlg, pData, TRUE); 793 break; 794 795 case DISP_CHANGE_RESTART: 796 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR)); 797 LoadString(hApplet, IDS_APPLY_NEEDS_RESTART, Message, sizeof(Message) / sizeof (TCHAR)); 798 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONINFORMATION); 799 return; 800 801 case DISP_CHANGE_FAILED: 802 default: 803 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, sizeof(Title) / sizeof(TCHAR)); 804 LoadString(hApplet, IDS_APPLY_FAILED, Message, sizeof(Message) / sizeof (TCHAR)); 805 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONSTOP); 806 return; 807 } 808 } 809 } 810 811 /* Property page dialog callback */ 812 INT_PTR CALLBACK 813 SettingsPageProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) 814 { 815 PSETTINGS_DATA pData; 816 817 pData = (PSETTINGS_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); 818 819 switch(uMsg) 820 { 821 case WM_INITDIALOG: 822 { 823 SettingsOnInitDialog(hwndDlg); 824 break; 825 } 826 case WM_DRAWITEM: 827 { 828 LPDRAWITEMSTRUCT lpDrawItem; 829 lpDrawItem = (LPDRAWITEMSTRUCT) lParam; 830 831 if (lpDrawItem->CtlID == IDC_SETTINGS_SPECTRUM) 832 ShowColorSpectrum(lpDrawItem->hDC, &lpDrawItem->rcItem, pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel, pData); 833 break; 834 } 835 case WM_COMMAND: 836 { 837 DWORD controlId = LOWORD(wParam); 838 DWORD command = HIWORD(wParam); 839 840 if (controlId == IDC_SETTINGS_ADVANCED && command == BN_CLICKED) 841 DisplayAdvancedSettings(hwndDlg, pData->CurrentDisplayDevice); 842 else if (controlId == IDC_SETTINGS_BPP && command == CBN_SELCHANGE) 843 OnBPPChanged(hwndDlg, pData); 844 break; 845 } 846 case WM_HSCROLL: 847 { 848 switch (LOWORD(wParam)) 849 { 850 case TB_LINEUP: 851 case TB_LINEDOWN: 852 case TB_PAGEUP: 853 case TB_PAGEDOWN: 854 case TB_TOP: 855 case TB_BOTTOM: 856 case TB_ENDTRACK: 857 { 858 DWORD newPosition = (DWORD) SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_GETPOS, 0, 0); 859 OnResolutionChanged(hwndDlg, pData, newPosition, TRUE); 860 break; 861 } 862 863 case TB_THUMBTRACK: 864 OnResolutionChanged(hwndDlg, pData, HIWORD(wParam), FALSE); 865 break; 866 } 867 break; 868 } 869 case WM_NOTIFY: 870 { 871 LPNMHDR lpnm = (LPNMHDR)lParam; 872 if (lpnm->code == (UINT)PSN_APPLY) 873 { 874 if (pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth != pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth 875 || pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight != pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight 876 || pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel != pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel) 877 { 878 /* Apply new settings */ 879 ApplyDisplaySettings(hwndDlg, pData); 880 } 881 } 882 else if (lpnm->code == MSLN_MONITORCHANGED) 883 { 884 PMONSL_MONNMMONITORCHANGING lpnmi = (PMONSL_MONNMMONITORCHANGING)lParam; 885 PDISPLAY_DEVICE_ENTRY Current = pData->DisplayDeviceList; 886 ULONG i; 887 for (i = 0; i < lpnmi->hdr.Index; i++) 888 Current = Current->Flink; 889 OnDisplayDeviceChanged(hwndDlg, pData, Current); 890 } 891 break; 892 } 893 894 case WM_CONTEXTMENU: 895 { 896 HWND hwndMonSel; 897 HMENU hPopup; 898 UINT uiCmd; 899 POINT pt, ptClient; 900 INT Index; 901 902 pt.x = (SHORT)LOWORD(lParam); 903 pt.y = (SHORT)HIWORD(lParam); 904 905 hwndMonSel = GetDlgItem(hwndDlg, 906 IDC_SETTINGS_MONSEL); 907 if ((HWND)wParam == hwndMonSel) 908 { 909 if (pt.x == -1 && pt.y == -1) 910 { 911 RECT rcMon; 912 913 Index = (INT)SendMessage(hwndMonSel, 914 MSLM_GETCURSEL, 915 0, 916 0); 917 918 if (Index >= 0 && 919 (INT)SendMessage(hwndMonSel, 920 MSLM_GETMONITORRECT, 921 Index, 922 (LPARAM)&rcMon) > 0) 923 { 924 pt.x = rcMon.left + ((rcMon.right - rcMon.left) / 2); 925 pt.y = rcMon.top + ((rcMon.bottom - rcMon.top) / 2); 926 } 927 else 928 pt.x = pt.y = 0; 929 930 MapWindowPoints(hwndMonSel, 931 NULL, 932 &pt, 933 1); 934 } 935 else 936 { 937 ptClient = pt; 938 MapWindowPoints(NULL, 939 hwndMonSel, 940 &ptClient, 941 1); 942 943 Index = (INT)SendMessage(hwndMonSel, 944 MSLM_HITTEST, 945 (WPARAM)&ptClient, 946 0); 947 } 948 949 if (Index >= 0) 950 { 951 hPopup = LoadPopupMenu(hApplet, 952 MAKEINTRESOURCE(IDM_MONITOR_MENU)); 953 if (hPopup != NULL) 954 { 955 /* FIXME: Enable/Disable menu items */ 956 EnableMenuItem(hPopup, 957 ID_MENU_ATTACHED, 958 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 959 EnableMenuItem(hPopup, 960 ID_MENU_PRIMARY, 961 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 962 EnableMenuItem(hPopup, 963 ID_MENU_IDENTIFY, 964 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 965 EnableMenuItem(hPopup, 966 ID_MENU_PROPERTIES, 967 MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); 968 969 uiCmd = (UINT)TrackPopupMenu(hPopup, 970 TPM_RETURNCMD | TPM_RIGHTBUTTON, 971 pt.x, 972 pt.y, 973 0, 974 hwndDlg, 975 NULL); 976 977 switch (uiCmd) 978 { 979 case ID_MENU_ATTACHED: 980 case ID_MENU_PRIMARY: 981 case ID_MENU_IDENTIFY: 982 case ID_MENU_PROPERTIES: 983 /* FIXME: Implement */ 984 break; 985 } 986 987 DestroyMenu(hPopup); 988 } 989 } 990 } 991 break; 992 } 993 994 case WM_DESTROY: 995 { 996 DWORD i; 997 PDISPLAY_DEVICE_ENTRY Current = pData->DisplayDeviceList; 998 999 while (Current != NULL) 1000 { 1001 PDISPLAY_DEVICE_ENTRY Next = Current->Flink; 1002 PSETTINGS_ENTRY CurrentSettings = Current->Settings; 1003 while (CurrentSettings != NULL) 1004 { 1005 PSETTINGS_ENTRY NextSettings = CurrentSettings->Flink; 1006 HeapFree(GetProcessHeap(), 0, CurrentSettings); 1007 CurrentSettings = NextSettings; 1008 } 1009 HeapFree(GetProcessHeap(), 0, Current); 1010 Current = Next; 1011 } 1012 1013 for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++) 1014 { 1015 if (pData->hSpectrumBitmaps[i]) 1016 DeleteObject(pData->hSpectrumBitmaps[i]); 1017 } 1018 1019 HeapFree(GetProcessHeap(), 0, pData); 1020 } 1021 } 1022 return FALSE; 1023 } 1024