1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Video initialization and display settings 5 * FILE: win32ss/user/ntuser/display.c 6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org) 7 */ 8 9 #include <win32k.h> 10 DBG_DEFAULT_CHANNEL(UserDisplay); 11 12 BOOL gbBaseVideo = FALSE; 13 static PPROCESSINFO gpFullscreen = NULL; 14 15 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO"; 16 17 VOID 18 RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm) 19 { 20 RegWriteDWORD(hkey, L"DefaultSettings.BitsPerPel", pdm->dmBitsPerPel); 21 RegWriteDWORD(hkey, L"DefaultSettings.XResolution", pdm->dmPelsWidth); 22 RegWriteDWORD(hkey, L"DefaultSettings.YResolution", pdm->dmPelsHeight); 23 RegWriteDWORD(hkey, L"DefaultSettings.Flags", pdm->dmDisplayFlags); 24 RegWriteDWORD(hkey, L"DefaultSettings.VRefresh", pdm->dmDisplayFrequency); 25 RegWriteDWORD(hkey, L"DefaultSettings.XPanning", pdm->dmPanningWidth); 26 RegWriteDWORD(hkey, L"DefaultSettings.YPanning", pdm->dmPanningHeight); 27 RegWriteDWORD(hkey, L"DefaultSettings.Orientation", pdm->dmDisplayOrientation); 28 RegWriteDWORD(hkey, L"DefaultSettings.FixedOutput", pdm->dmDisplayFixedOutput); 29 RegWriteDWORD(hkey, L"Attach.RelativeX", pdm->dmPosition.x); 30 RegWriteDWORD(hkey, L"Attach.RelativeY", pdm->dmPosition.y); 31 // RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->); 32 } 33 34 VOID 35 RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm) 36 { 37 DWORD dwValue; 38 39 /* Zero out the structure */ 40 RtlZeroMemory(pdm, sizeof(DEVMODEW)); 41 42 /* Helper macro */ 43 #define READ(field, str, flag) \ 44 if (RegReadDWORD(hkey, L##str, &dwValue)) \ 45 { \ 46 pdm->field = dwValue; \ 47 pdm->dmFields |= flag; \ 48 } 49 50 /* Read all present settings */ 51 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL); 52 READ(dmPelsWidth, "DefaultSettings.XResolution", DM_PELSWIDTH); 53 READ(dmPelsHeight, "DefaultSettings.YResolution", DM_PELSHEIGHT); 54 READ(dmDisplayFlags, "DefaultSettings.Flags", DM_DISPLAYFLAGS); 55 READ(dmDisplayFrequency, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY); 56 READ(dmPanningWidth, "DefaultSettings.XPanning", DM_PANNINGWIDTH); 57 READ(dmPanningHeight, "DefaultSettings.YPanning", DM_PANNINGHEIGHT); 58 READ(dmDisplayOrientation, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION); 59 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT); 60 READ(dmPosition.x, "Attach.RelativeX", DM_POSITION); 61 READ(dmPosition.y, "Attach.RelativeY", DM_POSITION); 62 } 63 64 PGRAPHICS_DEVICE 65 NTAPI 66 InitDisplayDriver( 67 IN PWSTR pwszDeviceName, 68 IN PWSTR pwszRegKey) 69 { 70 PGRAPHICS_DEVICE pGraphicsDevice; 71 UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription; 72 NTSTATUS Status; 73 WCHAR awcBuffer[128]; 74 ULONG cbSize; 75 HKEY hkey; 76 DWORD dwVga; 77 78 TRACE("InitDisplayDriver(%S, %S);\n", 79 pwszDeviceName, pwszRegKey); 80 81 /* Open the driver's registry key */ 82 Status = RegOpenKey(pwszRegKey, &hkey); 83 if (!NT_SUCCESS(Status)) 84 { 85 ERR("Failed to open registry key: %ls\n", pwszRegKey); 86 return NULL; 87 } 88 89 /* Query the diplay drivers */ 90 cbSize = sizeof(awcBuffer) - 10; 91 Status = RegQueryValue(hkey, 92 L"InstalledDisplayDrivers", 93 REG_MULTI_SZ, 94 awcBuffer, 95 &cbSize); 96 if (!NT_SUCCESS(Status)) 97 { 98 ERR("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status); 99 ZwClose(hkey); 100 return NULL; 101 } 102 103 /* Initialize the UNICODE_STRING */ 104 ustrDisplayDrivers.Buffer = awcBuffer; 105 ustrDisplayDrivers.MaximumLength = (USHORT)cbSize; 106 ustrDisplayDrivers.Length = (USHORT)cbSize; 107 108 /* Set Buffer for description and size of remaining buffer */ 109 ustrDescription.Buffer = awcBuffer + (cbSize / sizeof(WCHAR)); 110 cbSize = sizeof(awcBuffer) - cbSize; 111 112 /* Query the device string */ 113 Status = RegQueryValue(hkey, 114 L"Device Description", 115 REG_SZ, 116 ustrDescription.Buffer, 117 &cbSize); 118 if (NT_SUCCESS(Status)) 119 { 120 ustrDescription.MaximumLength = (USHORT)cbSize; 121 ustrDescription.Length = (USHORT)cbSize; 122 } 123 else 124 { 125 RtlInitUnicodeString(&ustrDescription, L"<unknown>"); 126 } 127 128 /* Query if this is a VGA compatible driver */ 129 cbSize = sizeof(DWORD); 130 Status = RegQueryValue(hkey, L"VgaCompatible", REG_DWORD, &dwVga, &cbSize); 131 if (!NT_SUCCESS(Status)) dwVga = 0; 132 133 /* Close the registry key */ 134 ZwClose(hkey); 135 136 /* Register the device with GDI */ 137 RtlInitUnicodeString(&ustrDeviceName, pwszDeviceName); 138 pGraphicsDevice = EngpRegisterGraphicsDevice(&ustrDeviceName, 139 &ustrDisplayDrivers, 140 &ustrDescription); 141 if (pGraphicsDevice && dwVga) 142 { 143 pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_VGA_COMPATIBLE; 144 } 145 146 return pGraphicsDevice; 147 } 148 149 NTSTATUS 150 NTAPI 151 InitVideo(VOID) 152 { 153 NTSTATUS Status; 154 HKEY hkey; 155 156 TRACE("----------------------------- InitVideo() -------------------------------\n"); 157 158 /* Check if VGA mode is requested, by finding the special volatile key created by VIDEOPRT */ 159 Status = RegOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo", &hkey); 160 if (NT_SUCCESS(Status)) 161 ZwClose(hkey); 162 gbBaseVideo = NT_SUCCESS(Status); 163 if (gbBaseVideo) 164 ERR("VGA mode requested.\n"); 165 166 /* Initialize all display devices */ 167 Status = EngpUpdateGraphicsDeviceList(); 168 if (!NT_SUCCESS(Status)) 169 return Status; 170 171 /* Check if we had any success */ 172 if (!gpPrimaryGraphicsDevice) 173 { 174 /* Check if there is a VGA device we skipped */ 175 if (gpVgaGraphicsDevice) 176 { 177 /* There is, use the VGA device */ 178 gpPrimaryGraphicsDevice = gpVgaGraphicsDevice; 179 } 180 else 181 { 182 ERR("No usable display driver was found.\n"); 183 return STATUS_UNSUCCESSFUL; 184 } 185 } 186 187 InitSysParams(); 188 189 return STATUS_SUCCESS; 190 } 191 192 VOID 193 UserRefreshDisplay(IN PPDEVOBJ ppdev) 194 { 195 ULONG_PTR ulResult; 196 // PVOID pvOldCursor; 197 198 // TODO: Re-enable the cursor reset code once this function becomes called 199 // from within a Win32 thread... Indeed UserSetCursor() requires this, but 200 // at the moment this function is directly called from a separate thread 201 // from within videoprt, instead of by a separate win32k system thread. 202 203 if (!ppdev) 204 return; 205 206 PDEVOBJ_vReference(ppdev); 207 208 /* Remove mouse pointer */ 209 // pvOldCursor = UserSetCursor(NULL, TRUE); 210 211 /* Do the mode switch -- Use the actual same current mode */ 212 ulResult = PDEVOBJ_bSwitchMode(ppdev, ppdev->pdmwDev); 213 ASSERT(ulResult); 214 215 /* Restore mouse pointer, no hooks called */ 216 // pvOldCursor = UserSetCursor(pvOldCursor, TRUE); 217 // ASSERT(pvOldCursor == NULL); 218 219 /* Update the system metrics */ 220 InitMetrics(); 221 222 /* Set new size of the monitor */ 223 // UserUpdateMonitorSize((HDEV)ppdev); 224 225 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes); 226 UserRedrawDesktop(); 227 228 PDEVOBJ_vRelease(ppdev); 229 } 230 231 NTSTATUS 232 NTAPI 233 UserEnumDisplayDevices( 234 PUNICODE_STRING pustrDevice, 235 DWORD iDevNum, 236 PDISPLAY_DEVICEW pdispdev, 237 DWORD dwFlags) 238 { 239 PGRAPHICS_DEVICE pGraphicsDevice; 240 ULONG cbSize; 241 HKEY hkey; 242 NTSTATUS Status; 243 244 if (!pustrDevice) 245 { 246 /* Check if some devices have been added since last time */ 247 EngpUpdateGraphicsDeviceList(); 248 } 249 250 /* Ask gdi for the GRAPHICS_DEVICE */ 251 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, iDevNum); 252 if (!pGraphicsDevice) 253 { 254 /* No device found */ 255 ERR("No GRAPHICS_DEVICE found for '%wZ', iDevNum %lu\n", pustrDevice, iDevNum); 256 return STATUS_UNSUCCESSFUL; 257 } 258 259 /* Open the device map registry key */ 260 Status = RegOpenKey(KEY_VIDEO, &hkey); 261 if (!NT_SUCCESS(Status)) 262 { 263 /* No device found */ 264 ERR("Could not open reg key\n"); 265 return STATUS_UNSUCCESSFUL; 266 } 267 268 /* Query the registry path */ 269 cbSize = sizeof(pdispdev->DeviceKey); 270 RegQueryValue(hkey, 271 pGraphicsDevice->szNtDeviceName, 272 REG_SZ, 273 pdispdev->DeviceKey, 274 &cbSize); 275 276 /* Close registry key */ 277 ZwClose(hkey); 278 279 /* Copy device name, device string and StateFlags */ 280 RtlStringCbCopyW(pdispdev->DeviceName, sizeof(pdispdev->DeviceName), pGraphicsDevice->szWinDeviceName); 281 RtlStringCbCopyW(pdispdev->DeviceString, sizeof(pdispdev->DeviceString), pGraphicsDevice->pwszDescription); 282 pdispdev->StateFlags = pGraphicsDevice->StateFlags; 283 // FIXME: fill in DEVICE ID 284 pdispdev->DeviceID[0] = UNICODE_NULL; 285 286 return STATUS_SUCCESS; 287 } 288 289 //NTSTATUS 290 BOOL 291 NTAPI 292 NtUserEnumDisplayDevices( 293 PUNICODE_STRING pustrDevice, 294 DWORD iDevNum, 295 PDISPLAY_DEVICEW pDisplayDevice, 296 DWORD dwFlags) 297 { 298 UNICODE_STRING ustrDevice; 299 WCHAR awcDevice[CCHDEVICENAME]; 300 DISPLAY_DEVICEW dispdev; 301 NTSTATUS Status; 302 303 TRACE("Enter NtUserEnumDisplayDevices(%wZ, %lu)\n", 304 pustrDevice, iDevNum); 305 306 dispdev.cb = sizeof(dispdev); 307 308 if (pustrDevice) 309 { 310 /* Initialize destination string */ 311 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 312 313 _SEH2_TRY 314 { 315 /* Probe the UNICODE_STRING and the buffer */ 316 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1); 317 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1); 318 319 /* Copy the string */ 320 RtlCopyUnicodeString(&ustrDevice, pustrDevice); 321 } 322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 323 { 324 // _SEH2_YIELD(return _SEH2_GetExceptionCode()); 325 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode())); 326 } 327 _SEH2_END 328 329 if (ustrDevice.Length > 0) 330 pustrDevice = &ustrDevice; 331 else 332 pustrDevice = NULL; 333 } 334 335 /* If name is given only iDevNum==0 gives results */ 336 if (pustrDevice && iDevNum != 0) 337 return FALSE; 338 339 /* Acquire global USER lock */ 340 UserEnterShared(); 341 342 /* Call the internal function */ 343 Status = UserEnumDisplayDevices(pustrDevice, iDevNum, &dispdev, dwFlags); 344 345 /* Release lock */ 346 UserLeave(); 347 348 /* On success copy data to caller */ 349 if (NT_SUCCESS(Status)) 350 { 351 /* Enter SEH */ 352 _SEH2_TRY 353 { 354 /* First probe the cb field */ 355 ProbeForWrite(&pDisplayDevice->cb, sizeof(DWORD), 1); 356 357 /* Check the buffer size */ 358 if (pDisplayDevice->cb) 359 { 360 /* Probe the output buffer */ 361 pDisplayDevice->cb = min(pDisplayDevice->cb, sizeof(dispdev)); 362 ProbeForWrite(pDisplayDevice, pDisplayDevice->cb, 1); 363 364 /* Copy as much as the given buffer allows */ 365 RtlCopyMemory(pDisplayDevice, &dispdev, pDisplayDevice->cb); 366 } 367 } 368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 369 { 370 Status = _SEH2_GetExceptionCode(); 371 } 372 _SEH2_END 373 } 374 375 TRACE("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status); 376 /* Return the result */ 377 // return Status; 378 return NT_SUCCESS(Status); // FIXME 379 } 380 381 NTSTATUS 382 NTAPI 383 UserEnumCurrentDisplaySettings( 384 PUNICODE_STRING pustrDevice, 385 PDEVMODEW *ppdm) 386 { 387 PPDEVOBJ ppdev; 388 389 /* Get the PDEV for the device */ 390 ppdev = EngpGetPDEV(pustrDevice); 391 if (!ppdev) 392 { 393 /* No device found */ 394 ERR("No PDEV found!\n"); 395 return STATUS_INVALID_PARAMETER_1; 396 } 397 398 *ppdm = ppdev->pdmwDev; 399 PDEVOBJ_vRelease(ppdev); 400 401 return STATUS_SUCCESS; 402 } 403 404 NTSTATUS 405 NTAPI 406 UserEnumDisplaySettings( 407 PUNICODE_STRING pustrDevice, 408 DWORD iModeNum, 409 LPDEVMODEW *ppdm, 410 DWORD dwFlags) 411 { 412 PGRAPHICS_DEVICE pGraphicsDevice; 413 PDEVMODEENTRY pdmentry; 414 ULONG i, iFoundMode; 415 PPDEVOBJ ppdev; 416 417 TRACE("Enter UserEnumDisplaySettings('%wZ', %lu)\n", 418 pustrDevice, iModeNum); 419 420 /* Ask GDI for the GRAPHICS_DEVICE */ 421 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0); 422 ppdev = EngpGetPDEV(pustrDevice); 423 424 if (!pGraphicsDevice || !ppdev) 425 { 426 /* No device found */ 427 ERR("No device found!\n"); 428 return STATUS_INVALID_PARAMETER_1; 429 } 430 431 /* let's politely ask the driver for an updated mode list, 432 just in case there's something new in there (vbox) */ 433 434 PDEVOBJ_vRefreshModeList(ppdev); 435 PDEVOBJ_vRelease(ppdev); 436 437 iFoundMode = 0; 438 for (i = 0; i < pGraphicsDevice->cDevModes; i++) 439 { 440 pdmentry = &pGraphicsDevice->pDevModeList[i]; 441 442 /* FIXME: Consider EDS_RAWMODE */ 443 #if 0 444 if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) ||! 445 (dwFlags & EDS_RAWMODE)) 446 #endif 447 { 448 /* Is this the one we want? */ 449 if (iFoundMode == iModeNum) 450 { 451 *ppdm = pdmentry->pdm; 452 return STATUS_SUCCESS; 453 } 454 455 /* Increment number of found modes */ 456 iFoundMode++; 457 } 458 } 459 460 /* Nothing was found */ 461 return STATUS_INVALID_PARAMETER_2; 462 } 463 464 NTSTATUS 465 NTAPI 466 UserOpenDisplaySettingsKey( 467 OUT PHKEY phkey, 468 IN PUNICODE_STRING pustrDevice, 469 IN BOOL bGlobal) 470 { 471 HKEY hkey; 472 DISPLAY_DEVICEW dispdev; 473 NTSTATUS Status; 474 475 /* Get device info */ 476 Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0); 477 if (!NT_SUCCESS(Status)) 478 return Status; 479 480 if (bGlobal) 481 { 482 // FIXME: Need to fix the registry key somehow 483 } 484 485 /* Open the registry key */ 486 Status = RegOpenKey(dispdev.DeviceKey, &hkey); 487 if (!NT_SUCCESS(Status)) 488 return Status; 489 490 *phkey = hkey; 491 492 return Status; 493 } 494 495 NTSTATUS 496 NTAPI 497 UserEnumRegistryDisplaySettings( 498 IN PUNICODE_STRING pustrDevice, 499 OUT LPDEVMODEW pdm) 500 { 501 HKEY hkey; 502 NTSTATUS Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, 0); 503 if(NT_SUCCESS(Status)) 504 { 505 RegReadDisplaySettings(hkey, pdm); 506 ZwClose(hkey); 507 return STATUS_SUCCESS; 508 } 509 return Status; 510 } 511 512 NTSTATUS 513 APIENTRY 514 NtUserEnumDisplaySettings( 515 IN PUNICODE_STRING pustrDevice, 516 IN DWORD iModeNum, 517 OUT LPDEVMODEW lpDevMode, 518 IN DWORD dwFlags) 519 { 520 UNICODE_STRING ustrDeviceUser; 521 UNICODE_STRING ustrDevice; 522 WCHAR awcDevice[CCHDEVICENAME]; 523 NTSTATUS Status; 524 ULONG cbSize, cbExtra; 525 DEVMODEW dmReg, *pdm; 526 527 TRACE("Enter NtUserEnumDisplaySettings(%wZ, %lu, %p, 0x%lx)\n", 528 pustrDevice, iModeNum, lpDevMode, dwFlags); 529 530 _SEH2_TRY 531 { 532 ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(UCHAR)); 533 534 cbSize = lpDevMode->dmSize; 535 cbExtra = lpDevMode->dmDriverExtra; 536 537 ProbeForWrite(lpDevMode, cbSize + cbExtra, sizeof(UCHAR)); 538 } 539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 540 { 541 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 542 } 543 _SEH2_END; 544 545 if (cbSize != sizeof(DEVMODEW)) 546 { 547 return STATUS_BUFFER_TOO_SMALL; 548 } 549 550 if (pustrDevice) 551 { 552 /* Initialize destination string */ 553 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 554 555 _SEH2_TRY 556 { 557 /* Probe the UNICODE_STRING and the buffer */ 558 ustrDeviceUser = ProbeForReadUnicodeString(pustrDevice); 559 560 if (!ustrDeviceUser.Length || !ustrDeviceUser.Buffer) 561 ExRaiseStatus(STATUS_NO_MEMORY); 562 563 ProbeForRead(ustrDeviceUser.Buffer, 564 ustrDeviceUser.Length, 565 sizeof(UCHAR)); 566 567 /* Copy the string */ 568 RtlCopyUnicodeString(&ustrDevice, &ustrDeviceUser); 569 } 570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 571 { 572 _SEH2_YIELD(return STATUS_INVALID_PARAMETER_1); 573 } 574 _SEH2_END; 575 576 pustrDevice = &ustrDevice; 577 } 578 579 /* Acquire global USER lock */ 580 UserEnterShared(); 581 582 if (iModeNum == ENUM_REGISTRY_SETTINGS) 583 { 584 /* Get the registry settings */ 585 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg); 586 pdm = &dmReg; 587 pdm->dmSize = sizeof(DEVMODEW); 588 } 589 else if (iModeNum == ENUM_CURRENT_SETTINGS) 590 { 591 /* Get the current settings */ 592 Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm); 593 } 594 else 595 { 596 /* Get specified settings */ 597 Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags); 598 } 599 600 /* Release lock */ 601 UserLeave(); 602 603 /* Did we succeed? */ 604 if (NT_SUCCESS(Status)) 605 { 606 /* Copy some information back */ 607 _SEH2_TRY 608 { 609 /* Output what we got */ 610 RtlCopyMemory(lpDevMode, pdm, min(cbSize, pdm->dmSize)); 611 612 /* Output private/extra driver data */ 613 if (cbExtra > 0 && pdm->dmDriverExtra > 0) 614 { 615 RtlCopyMemory((PCHAR)lpDevMode + cbSize, 616 (PCHAR)pdm + pdm->dmSize, 617 min(cbExtra, pdm->dmDriverExtra)); 618 } 619 } 620 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 621 { 622 Status = _SEH2_GetExceptionCode(); 623 } 624 _SEH2_END; 625 } 626 627 return Status; 628 } 629 630 VOID 631 UserUpdateFullscreen( 632 DWORD flags) 633 { 634 if (flags & CDS_FULLSCREEN) 635 gpFullscreen = gptiCurrent->ppi; 636 else 637 gpFullscreen = NULL; 638 } 639 640 LONG 641 APIENTRY 642 UserChangeDisplaySettings( 643 PUNICODE_STRING pustrDevice, 644 LPDEVMODEW pdm, 645 DWORD flags, 646 LPVOID lParam) 647 { 648 DEVMODEW dm; 649 LONG lResult = DISP_CHANGE_SUCCESSFUL; 650 HKEY hkey; 651 NTSTATUS Status; 652 PPDEVOBJ ppdev; 653 WORD OrigBC; 654 //PDESKTOP pdesk; 655 PDEVMODEW newDevMode = NULL; 656 657 /* If no DEVMODE is given, use registry settings */ 658 if (!pdm) 659 { 660 /* Get the registry settings */ 661 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dm); 662 if (!NT_SUCCESS(Status)) 663 { 664 ERR("Could not load registry settings\n"); 665 return DISP_CHANGE_BADPARAM; 666 } 667 } 668 else if (pdm->dmSize < FIELD_OFFSET(DEVMODEW, dmFields)) 669 { 670 return DISP_CHANGE_BADMODE; /* This is what WinXP SP3 returns */ 671 } 672 else 673 { 674 dm = *pdm; 675 } 676 677 /* Save original bit count */ 678 OrigBC = gpsi->BitCount; 679 680 /* Check params */ 681 if ((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT)) 682 { 683 ERR("Devmode doesn't specify the resolution.\n"); 684 return DISP_CHANGE_BADMODE; 685 } 686 687 /* Get the PDEV */ 688 ppdev = EngpGetPDEV(pustrDevice); 689 if (!ppdev) 690 { 691 ERR("Failed to get PDEV\n"); 692 return DISP_CHANGE_BADPARAM; 693 } 694 695 /* Fixup values */ 696 if (dm.dmBitsPerPel == 0 || !(dm.dmFields & DM_BITSPERPEL)) 697 { 698 dm.dmBitsPerPel = ppdev->pdmwDev->dmBitsPerPel; 699 dm.dmFields |= DM_BITSPERPEL; 700 } 701 702 if ((dm.dmFields & DM_DISPLAYFREQUENCY) && (dm.dmDisplayFrequency == 0)) 703 dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency; 704 705 /* Look for the requested DEVMODE */ 706 if (!LDEVOBJ_bProbeAndCaptureDevmode(ppdev->pGraphicsDevice, &dm, &newDevMode, FALSE)) 707 { 708 ERR("Could not find a matching DEVMODE\n"); 709 lResult = DISP_CHANGE_BADMODE; 710 goto leave; 711 } 712 else if (flags & CDS_TEST) 713 { 714 /* It's possible, go ahead! */ 715 lResult = DISP_CHANGE_SUCCESSFUL; 716 goto leave; 717 } 718 719 /* Shall we update the registry? */ 720 if (flags & CDS_UPDATEREGISTRY) 721 { 722 /* Open the local or global settings key */ 723 Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL); 724 if (NT_SUCCESS(Status)) 725 { 726 /* Store the settings */ 727 RegWriteDisplaySettings(hkey, newDevMode); 728 729 /* Close the registry key */ 730 ZwClose(hkey); 731 } 732 else 733 { 734 ERR("Could not open registry key\n"); 735 lResult = DISP_CHANGE_NOTUPDATED; 736 } 737 } 738 739 /* Check if DEVMODE matches the current mode */ 740 if (newDevMode->dmSize == ppdev->pdmwDev->dmSize && 741 RtlCompareMemory(newDevMode, ppdev->pdmwDev, newDevMode->dmSize) == newDevMode->dmSize && 742 !(flags & CDS_RESET)) 743 { 744 ERR("DEVMODE matches, nothing to do\n"); 745 goto leave; 746 } 747 748 /* Shall we apply the settings? */ 749 if (!(flags & CDS_NORESET)) 750 { 751 ULONG_PTR ulResult; 752 PVOID pvOldCursor; 753 TEXTMETRICW tmw; 754 755 /* Remove mouse pointer */ 756 pvOldCursor = UserSetCursor(NULL, TRUE); 757 758 /* Do the mode switch */ 759 ulResult = PDEVOBJ_bSwitchMode(ppdev, newDevMode); 760 761 /* Restore mouse pointer, no hooks called */ 762 pvOldCursor = UserSetCursor(pvOldCursor, TRUE); 763 ASSERT(pvOldCursor == NULL); 764 765 /* Check for success or failure */ 766 if (!ulResult) 767 { 768 /* Setting mode failed */ 769 ERR("Failed to set mode\n"); 770 771 /* Set the correct return value */ 772 if ((flags & CDS_UPDATEREGISTRY) && (lResult != DISP_CHANGE_NOTUPDATED)) 773 lResult = DISP_CHANGE_RESTART; 774 else 775 lResult = DISP_CHANGE_FAILED; 776 } 777 else 778 { 779 /* Setting mode succeeded */ 780 lResult = DISP_CHANGE_SUCCESSFUL; 781 ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE); 782 ppdev->pdmwDev = newDevMode; 783 784 UserUpdateFullscreen(flags); 785 786 /* Update the system metrics */ 787 InitMetrics(); 788 789 /* Set new size of the monitor */ 790 UserUpdateMonitorSize((HDEV)ppdev); 791 792 /* Update the SERVERINFO */ 793 gpsi->dmLogPixels = ppdev->gdiinfo.ulLogPixelsY; 794 gpsi->Planes = ppdev->gdiinfo.cPlanes; 795 gpsi->BitsPixel = ppdev->gdiinfo.cBitsPixel; 796 gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel; 797 gpsi->aiSysMet[SM_CXSCREEN] = ppdev->gdiinfo.ulHorzRes; 798 gpsi->aiSysMet[SM_CYSCREEN] = ppdev->gdiinfo.ulVertRes; 799 if (ppdev->gdiinfo.flRaster & RC_PALETTE) 800 { 801 gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY; 802 } 803 else 804 { 805 gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY; 806 } 807 // Font is realized and this dc was previously set to internal DC_ATTR. 808 gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar); 809 gpsi->tmSysFont = tmw; 810 } 811 812 /* 813 * Refresh the display on success and even on failure, 814 * since the display may have been messed up. 815 */ 816 817 /* Remove all cursor clipping */ 818 UserClipCursor(NULL); 819 820 //pdesk = IntGetActiveDesktop(); 821 //IntHideDesktop(pdesk); 822 823 /* Send WM_DISPLAYCHANGE to all toplevel windows */ 824 co_IntSendMessageTimeout( HWND_BROADCAST, 825 WM_DISPLAYCHANGE, 826 gpsi->BitCount, 827 MAKELONG(gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN]), 828 SMTO_NORMAL, 829 100, 830 &ulResult ); 831 832 ERR("BitCount New %d Orig %d ChkNew %d\n",gpsi->BitCount,OrigBC,ppdev->gdiinfo.cBitsPixel); 833 834 /* Not full screen and different bit count, send messages */ 835 if (!(flags & CDS_FULLSCREEN) && 836 gpsi->BitCount != OrigBC) 837 { 838 ERR("Detect settings changed.\n"); 839 UserSendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0); 840 UserSendNotifyMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0); 841 } 842 843 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes); 844 845 UserRedrawDesktop(); 846 } 847 848 leave: 849 if (newDevMode && newDevMode != ppdev->pdmwDev) 850 ExFreePoolWithTag(newDevMode, GDITAG_DEVMODE); 851 852 /* Release the PDEV */ 853 PDEVOBJ_vRelease(ppdev); 854 855 return lResult; 856 } 857 858 VOID 859 UserDisplayNotifyShutdown( 860 PPROCESSINFO ppiCurrent) 861 { 862 if (ppiCurrent == gpFullscreen) 863 { 864 UserChangeDisplaySettings(NULL, NULL, 0, NULL); 865 if (gpFullscreen) 866 ERR("Failed to restore display mode!\n"); 867 } 868 } 869 870 LONG 871 APIENTRY 872 NtUserChangeDisplaySettings( 873 PUNICODE_STRING pustrDevice, 874 LPDEVMODEW lpDevMode, 875 DWORD dwflags, 876 LPVOID lParam) 877 { 878 WCHAR awcDevice[CCHDEVICENAME]; 879 UNICODE_STRING ustrDevice; 880 DEVMODEW dmLocal; 881 LONG lRet; 882 883 /* Check arguments */ 884 if ((dwflags != CDS_VIDEOPARAMETERS) && (lParam != NULL)) 885 { 886 EngSetLastError(ERROR_INVALID_PARAMETER); 887 return DISP_CHANGE_BADPARAM; 888 } 889 890 /* Check flags */ 891 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY)) 892 { 893 return DISP_CHANGE_BADFLAGS; 894 } 895 896 if ((dwflags & CDS_RESET) && (dwflags & CDS_NORESET)) 897 { 898 return DISP_CHANGE_BADFLAGS; 899 } 900 901 /* Copy the device name */ 902 if (pustrDevice) 903 { 904 /* Initialize destination string */ 905 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice)); 906 907 _SEH2_TRY 908 { 909 /* Probe the UNICODE_STRING and the buffer */ 910 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1); 911 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1); 912 913 /* Copy the string */ 914 RtlCopyUnicodeString(&ustrDevice, pustrDevice); 915 } 916 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 917 { 918 /* Set and return error */ 919 SetLastNtError(_SEH2_GetExceptionCode()); 920 _SEH2_YIELD(return DISP_CHANGE_BADPARAM); 921 } 922 _SEH2_END 923 924 pustrDevice = &ustrDevice; 925 } 926 927 /* Copy devmode */ 928 if (lpDevMode) 929 { 930 _SEH2_TRY 931 { 932 /* Probe the size field of the structure */ 933 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1); 934 935 /* Calculate usable size */ 936 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize); 937 938 /* Probe and copy the full DEVMODE */ 939 ProbeForRead(lpDevMode, dmLocal.dmSize, 1); 940 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize); 941 } 942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 943 { 944 /* Set and return error */ 945 SetLastNtError(_SEH2_GetExceptionCode()); 946 _SEH2_YIELD(return DISP_CHANGE_BADPARAM); 947 } 948 _SEH2_END 949 950 /* Check for extra parameters */ 951 if (dmLocal.dmDriverExtra > 0) 952 { 953 /* FIXME: TODO */ 954 ERR("lpDevMode->dmDriverExtra is IGNORED!\n"); 955 dmLocal.dmDriverExtra = 0; 956 } 957 958 /* Use the local structure */ 959 lpDevMode = &dmLocal; 960 } 961 962 // FIXME: Copy videoparameters 963 964 /* Acquire global USER lock */ 965 UserEnterExclusive(); 966 967 /* Call internal function */ 968 lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, dwflags, NULL); 969 970 /* Release lock */ 971 UserLeave(); 972 973 return lRet; 974 } 975