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