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