7ab53638f1a85e5e5a2b5453265fc7ec65d096e8
[reactos.git] / subsystems / win32 / win32k / ntuser / display.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Video initialization and display settings
5 * FILE: subsystems/win32/win32k/ntuser/display.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 #include <win32k.h>
10
11 #include <intrin.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 BOOL InitSysParams();
17
18 BOOL gbBaseVideo = 0;
19
20 static const PWCHAR KEY_ROOT = L"";
21 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
22
23 VOID
24 RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm)
25 {
26 RegWriteDWORD(hkey, L"DefaultSettings.BitsPerPel", pdm->dmBitsPerPel);
27 RegWriteDWORD(hkey, L"DefaultSettings.XResolution", pdm->dmPelsWidth);
28 RegWriteDWORD(hkey, L"DefaultSettings.YResolution", pdm->dmPelsHeight);
29 RegWriteDWORD(hkey, L"DefaultSettings.Flags", pdm->dmDisplayFlags);
30 RegWriteDWORD(hkey, L"DefaultSettings.VRefresh", pdm->dmDisplayFrequency);
31 RegWriteDWORD(hkey, L"DefaultSettings.XPanning", pdm->dmPanningWidth);
32 RegWriteDWORD(hkey, L"DefaultSettings.YPanning", pdm->dmPanningHeight);
33 RegWriteDWORD(hkey, L"DefaultSettings.Orientation", pdm->dmDisplayOrientation);
34 RegWriteDWORD(hkey, L"DefaultSettings.FixedOutput", pdm->dmDisplayFixedOutput);
35 RegWriteDWORD(hkey, L"Attach.RelativeX", pdm->dmPosition.x);
36 RegWriteDWORD(hkey, L"Attach.RelativeY", pdm->dmPosition.y);
37 // RegWriteDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", pdm->);
38 }
39
40 VOID
41 RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
42 {
43 DWORD dwValue;
44
45 /* Zero out the structure */
46 RtlZeroMemory(pdm, sizeof(DEVMODEW));
47
48 /* Helper macro */
49 #define READ(field, str, flag) \
50 if (RegReadDWORD(hkey, L##str, &dwValue)) \
51 { \
52 pdm->field = dwValue; \
53 pdm->dmFields |= flag; \
54 }
55
56 /* Read all present settings */
57 READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL);
58 READ(dmPelsWidth, "DefaultSettings.XResolution", DM_PELSWIDTH);
59 READ(dmPelsHeight, "DefaultSettings.YResolution", DM_PELSHEIGHT);
60 READ(dmDisplayFlags, "DefaultSettings.Flags", DM_DISPLAYFLAGS);
61 READ(dmDisplayFrequency, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY);
62 READ(dmPanningWidth, "DefaultSettings.XPanning", DM_PANNINGWIDTH);
63 READ(dmPanningHeight, "DefaultSettings.YPanning", DM_PANNINGHEIGHT);
64 READ(dmDisplayOrientation, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION);
65 READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT);
66 READ(dmPosition.x, "Attach.RelativeX", DM_POSITION);
67 READ(dmPosition.y, "Attach.RelativeY", DM_POSITION);
68 }
69
70 PGRAPHICS_DEVICE
71 NTAPI
72 InitDisplayDriver(
73 IN PWSTR pwszDeviceName,
74 IN PWSTR pwszRegKey)
75 {
76 PGRAPHICS_DEVICE pGraphicsDevice;
77 UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription;
78 NTSTATUS Status;
79 WCHAR awcBuffer[128];
80 ULONG cbSize;
81 HKEY hkey;
82 DEVMODEW dmDefault;
83
84 DPRINT1("InitDisplayDriver(%S, %S);\n",
85 pwszDeviceName, pwszRegKey);
86
87 /* Open the driver's registry key */
88 Status = RegOpenKey(pwszRegKey, &hkey);
89 if (!NT_SUCCESS(Status))
90 {
91 DPRINT1("Failed to open registry key: %ls\n", pwszRegKey);
92 return NULL;
93 }
94
95 /* Query the diplay drivers */
96 cbSize = sizeof(awcBuffer) - 10;
97 Status = RegQueryValue(hkey,
98 L"InstalledDisplayDrivers",
99 REG_MULTI_SZ,
100 awcBuffer,
101 &cbSize);
102 if (!NT_SUCCESS(Status))
103 {
104 DPRINT1("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status);
105 ZwClose(hkey);
106 return NULL;
107 }
108
109 /* Initialize the UNICODE_STRING */
110 ustrDisplayDrivers.Buffer = awcBuffer;
111 ustrDisplayDrivers.MaximumLength = cbSize;
112 ustrDisplayDrivers.Length = cbSize;
113
114 /* Set Buffer for description and size of remaining buffer */
115 ustrDescription.Buffer = awcBuffer + (cbSize / sizeof(WCHAR));
116 cbSize = sizeof(awcBuffer) - cbSize;
117
118 /* Query the device string */
119 Status = RegQueryValue(hkey,
120 L"Device Description",
121 REG_SZ,
122 ustrDescription.Buffer,
123 &cbSize);
124 if (NT_SUCCESS(Status))
125 {
126 ustrDescription.MaximumLength = cbSize;
127 ustrDescription.Length = cbSize;
128 }
129 else
130 {
131 RtlInitUnicodeString(&ustrDescription, L"<unknown>");
132 }
133
134 /* Query the default settings */
135 RegReadDisplaySettings(hkey, &dmDefault);
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
147 return pGraphicsDevice;
148 }
149
150 BOOL
151 InitVideo(
152 PUNICODE_STRING pustrRegPath,
153 FLONG flags)
154 {
155 ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
156 WCHAR awcDeviceName[20];
157 WCHAR awcBuffer[256];
158 NTSTATUS Status;
159 PGRAPHICS_DEVICE pGraphicsDevice;
160 ULONG cbValue;
161 HKEY hkey;
162
163 DPRINT1("----------------------------- InitVideo() -------------------------------\n");
164
165 Status = RegOpenKey(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control", &hkey);
166 if (NT_SUCCESS(Status))
167 {
168 cbValue = 256;
169 Status = RegQueryValue(hkey, L"SystemStartOptions", REG_SZ, awcBuffer, &cbValue);
170 if (NT_SUCCESS(Status))
171 {
172 /* Check if VGA mode is requested. */
173 if (wcsstr(awcBuffer, L"/BASEVIDEO") != 0)
174 {
175 DPRINT1("VGA mode requested.\n");
176 gbBaseVideo = TRUE;
177 }
178 }
179
180 ZwClose(hkey);
181 }
182
183 /* Open the key for the adapters */
184 Status = RegOpenKey(KEY_VIDEO, &hkey);
185 if (!NT_SUCCESS(Status))
186 {
187 DPRINT1("Could not open device registry key!\n");
188 ASSERT(FALSE);
189 }
190
191 /* Read the name of the VGA adapter */
192 cbValue = 20;
193 Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
194 if (NT_SUCCESS(Status))
195 {
196 iVGACompatible = _wtoi(&awcDeviceName[13]);
197 DPRINT1("VGA adapter = %ld\n", iVGACompatible);
198 }
199
200 /* Get the maximum mumber of adapters */
201 if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber))
202 {
203 DPRINT1("Could not read MaxObjectNumber, defaulting to 0.\n");
204 }
205
206 DPRINT("Found %ld devices\n", ulMaxObjectNumber);
207
208 /* Loop through all adapters */
209 cbValue = 256;
210 for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
211 {
212 /* Create the adapter's key name */
213 swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
214
215 /* Read the reg key name */
216 Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue);
217
218 pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer);
219
220 /* Check if this is the VGA adapter */
221 if (iDevNum == iVGACompatible)
222 {
223 /* Set the VGA device as primary */
224 gpVgaGraphicsDevice = pGraphicsDevice;
225 DPRINT1("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice);
226 }
227
228 /* Set the first one as primary device */
229 if (!gpPrimaryGraphicsDevice)
230 gpPrimaryGraphicsDevice = pGraphicsDevice;
231 }
232
233 ZwClose(hkey);
234
235 if (gbBaseVideo)
236 {
237 if (gpVgaGraphicsDevice)
238 {
239 /* Set the VgaAdapter as primary */
240 gpPrimaryGraphicsDevice = gpVgaGraphicsDevice;
241 // FIXME: DEVMODE
242 }
243 else
244 {
245 DPRINT1("Could not find VGA compatible driver. Trying normal.\n");
246 }
247 }
248
249 InitSysParams();
250
251 return 1;
252 }
253
254 NTSTATUS
255 NTAPI
256 UserEnumDisplayDevices(
257 PUNICODE_STRING pustrDevice,
258 DWORD iDevNum,
259 PDISPLAY_DEVICEW pdispdev,
260 DWORD dwFlags)
261 {
262 PGRAPHICS_DEVICE pGraphicsDevice;
263 ULONG cbSize;
264 HKEY hkey;
265 NTSTATUS Status;
266
267 /* Ask gdi for the GRAPHICS_DEVICE */
268 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, iDevNum, 0);
269 if (!pGraphicsDevice)
270 {
271 /* No device found */
272 DPRINT1("No GRAPHICS_DEVICE found\n");
273 return STATUS_UNSUCCESSFUL;
274 }
275
276 /* Open thhe device map registry key */
277 Status = RegOpenKey(KEY_VIDEO, &hkey);
278 if (!NT_SUCCESS(Status))
279 {
280 /* No device found */
281 DPRINT1("Could not open reg key\n");
282 return STATUS_UNSUCCESSFUL;
283 }
284
285 /* Query the registry path */
286 cbSize = sizeof(pdispdev->DeviceKey);
287 RegQueryValue(hkey,
288 pGraphicsDevice->szNtDeviceName,
289 REG_SZ,
290 pdispdev->DeviceKey,
291 &cbSize);
292
293 /* Close registry key */
294 ZwClose(hkey);
295
296 /* Copy device name, device string and StateFlags */
297 wcsncpy(pdispdev->DeviceName, pGraphicsDevice->szWinDeviceName, 32);
298 wcsncpy(pdispdev->DeviceString, pGraphicsDevice->pwszDescription, 128);
299 pdispdev->StateFlags = pGraphicsDevice->StateFlags;
300
301 // FIXME: fill in DEVICE ID
302
303 return STATUS_SUCCESS;
304 }
305
306 //NTSTATUS
307 BOOL
308 NTAPI
309 NtUserEnumDisplayDevices(
310 PUNICODE_STRING pustrDevice,
311 DWORD iDevNum,
312 PDISPLAY_DEVICEW pDisplayDevice,
313 DWORD dwFlags)
314 {
315 UNICODE_STRING ustrDevice;
316 WCHAR awcDevice[CCHDEVICENAME];
317 DISPLAY_DEVICEW dispdev;
318 NTSTATUS Status;
319
320 DPRINT("Enter NtUserEnumDisplayDevices(%wZ, %ld)\n",
321 pustrDevice, iDevNum);
322
323 // FIXME: HACK, desk.cpl passes broken crap
324 if (pustrDevice && iDevNum != 0)
325 return FALSE;
326
327 dispdev.cb = sizeof(DISPLAY_DEVICEW);
328
329 if (pustrDevice)
330 {
331 /* Initialize destination string */
332 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
333
334 _SEH2_TRY
335 {
336 /* Probe the UNICODE_STRING and the buffer */
337 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
338 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
339
340 /* Copy the string */
341 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
342 }
343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
344 {
345 // _SEH2_YIELD(return _SEH2_GetExceptionCode());
346 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode()));
347 }
348 _SEH2_END
349
350 if (ustrDevice.Length > 0)
351 pustrDevice = &ustrDevice;
352 else
353 pustrDevice = NULL;
354 }
355
356 /* Acquire global USER lock */
357 UserEnterExclusive();
358
359 /* Call the internal function */
360 Status = UserEnumDisplayDevices(pustrDevice, iDevNum, &dispdev, dwFlags);
361
362 /* Release lock */
363 UserLeave();
364
365 /* On success copy data to caller */
366 if (NT_SUCCESS(Status))
367 {
368 /* Enter SEH */
369 _SEH2_TRY
370 {
371 /* First probe the cb field */
372 ProbeForWrite(&pDisplayDevice->cb, sizeof(DWORD), 1);
373
374 /* Check the buffer size */
375 if (pDisplayDevice->cb)
376 {
377 /* Probe the output buffer */
378 pDisplayDevice->cb = min(pDisplayDevice->cb, sizeof(dispdev));
379 ProbeForWrite(pDisplayDevice, pDisplayDevice->cb, 1);
380
381 /* Copy as much as the given buffer allows */
382 RtlCopyMemory(pDisplayDevice, &dispdev, pDisplayDevice->cb);
383 }
384 }
385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
386 {
387 Status = _SEH2_GetExceptionCode();
388 }
389 _SEH2_END
390 }
391
392 DPRINT1("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status);
393 /* Return the result */
394 // return Status;
395 return NT_SUCCESS(Status); // FIXME
396 }
397
398 NTSTATUS
399 NTAPI
400 UserEnumCurrentDisplaySettings(
401 PUNICODE_STRING pustrDevice,
402 PDEVMODEW *ppdm)
403 {
404 PPDEVOBJ ppdev;
405
406 /* Get the PDEV for the device */
407 ppdev = EngpGetPDEV(pustrDevice);
408 if (!ppdev)
409 {
410 /* No device found */
411 DPRINT1("No PDEV found!\n");
412 return STATUS_UNSUCCESSFUL;
413 }
414
415 *ppdm = ppdev->pdmwDev;
416 PDEVOBJ_vRelease(ppdev);
417
418 return STATUS_SUCCESS;
419 }
420
421 NTSTATUS
422 NTAPI
423 UserEnumDisplaySettings(
424 PUNICODE_STRING pustrDevice,
425 DWORD iModeNum,
426 LPDEVMODEW *ppdm,
427 DWORD dwFlags)
428 {
429 PGRAPHICS_DEVICE pGraphicsDevice;
430 PDEVMODEENTRY pdmentry;
431 ULONG i, iFoundMode;
432
433 DPRINT("Enter UserEnumDisplaySettings('%ls', %ld)\n",
434 pustrDevice ? pustrDevice->Buffer : NULL, iModeNum);
435
436 /* Ask gdi for the GRAPHICS_DEVICE */
437 pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
438
439 if (!pGraphicsDevice)
440 {
441 /* No device found */
442 DPRINT1("No device found!\n");
443 return STATUS_UNSUCCESSFUL;
444 }
445
446 if (iModeNum >= pGraphicsDevice->cDevModes)
447 return STATUS_NO_MORE_ENTRIES;
448
449 iFoundMode = 0;
450 for (i = 0; i < pGraphicsDevice->cDevModes; i++)
451 {
452 pdmentry = &pGraphicsDevice->pDevModeList[i];
453
454 /* FIXME: consider EDS_RAWMODE */
455 #if 0
456 if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) ||!
457 (dwFlags & EDS_RAWMODE))
458 #endif
459 {
460 /* Is this the one we want? */
461 if (iFoundMode == iModeNum)
462 {
463 *ppdm = pdmentry->pdm;
464 return STATUS_SUCCESS;
465 }
466
467 /* Increment number of found modes */
468 iFoundMode++;
469 }
470 }
471
472 /* Nothing was found */
473 return STATUS_INVALID_PARAMETER;
474 }
475
476 NTSTATUS
477 NTAPI
478 UserOpenDisplaySettingsKey(
479 OUT PHKEY phkey,
480 IN PUNICODE_STRING pustrDevice,
481 IN BOOL bGlobal)
482 {
483 HKEY hkey;
484 DISPLAY_DEVICEW dispdev;
485 NTSTATUS Status;
486
487 /* Get device info */
488 Status = UserEnumDisplayDevices(pustrDevice, 0, &dispdev, 0);
489 if (!NT_SUCCESS(Status))
490 return Status;
491
492 if (bGlobal)
493 {
494 // FIXME: need to fix the registry key somehow
495 }
496
497 /* Open the registry key */
498 Status = RegOpenKey(dispdev.DeviceKey, &hkey);
499 if (!NT_SUCCESS(Status))
500 return Status;
501
502 *phkey = hkey;
503
504 return Status;
505 }
506
507 NTSTATUS
508 NTAPI
509 UserEnumRegistryDisplaySettings(
510 IN PUNICODE_STRING pustrDevice,
511 OUT LPDEVMODEW pdm)
512 {
513 HKEY hkey;
514 NTSTATUS Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, 0);
515 if(NT_SUCCESS(Status))
516 {
517 RegReadDisplaySettings(hkey, pdm);
518 ZwClose(hkey);
519 return STATUS_SUCCESS;
520 }
521 return Status ;
522 }
523
524
525 NTSTATUS
526 APIENTRY
527 NtUserEnumDisplaySettings(
528 IN PUNICODE_STRING pustrDevice,
529 IN DWORD iModeNum,
530 OUT LPDEVMODEW lpDevMode,
531 IN DWORD dwFlags)
532 {
533 UNICODE_STRING ustrDevice;
534 WCHAR awcDevice[CCHDEVICENAME];
535 NTSTATUS Status;
536 ULONG cbSize, cbExtra;
537 DEVMODEW dmReg, *pdm;
538
539 DPRINT1("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
540 pustrDevice ? pustrDevice->Buffer : 0, iModeNum);
541
542 if (pustrDevice)
543 {
544 /* Initialize destination string */
545 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
546
547 _SEH2_TRY
548 {
549 /* Probe the UNICODE_STRING and the buffer */
550 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
551 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
552
553 /* Copy the string */
554 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
555 }
556 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
557 {
558 _SEH2_YIELD(return _SEH2_GetExceptionCode());
559 }
560 _SEH2_END
561
562 pustrDevice = &ustrDevice;
563 }
564
565 /* Acquire global USER lock */
566 UserEnterExclusive();
567
568 if (iModeNum == ENUM_REGISTRY_SETTINGS)
569 {
570 /* Get the registry settings */
571 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
572 pdm = &dmReg;
573 }
574 else if (iModeNum == ENUM_CURRENT_SETTINGS)
575 {
576 /* Get the current settings */
577 Status = UserEnumCurrentDisplaySettings(pustrDevice, &pdm);
578 }
579 else
580 {
581 /* Get specified settings */
582 Status = UserEnumDisplaySettings(pustrDevice, iModeNum, &pdm, dwFlags);
583 }
584
585 /* Release lock */
586 UserLeave();
587
588 /* Did we succeed? */
589 if (NT_SUCCESS(Status))
590 {
591 /* Copy some information back */
592 _SEH2_TRY
593 {
594 ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
595 cbSize = lpDevMode->dmSize;
596 cbExtra = lpDevMode->dmDriverExtra;
597
598 ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
599 /* Output what we got */
600 RtlCopyMemory(lpDevMode, pdm, min(cbSize, pdm->dmSize));
601
602 /* output private/extra driver data */
603 if (cbExtra > 0 && pdm->dmDriverExtra > 0)
604 {
605 RtlCopyMemory((PCHAR)lpDevMode + cbSize,
606 (PCHAR)pdm + pdm->dmSize,
607 min(cbExtra, pdm->dmDriverExtra));
608 }
609 }
610 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
611 {
612 Status = _SEH2_GetExceptionCode();
613 }
614 _SEH2_END;
615 }
616
617 return Status;
618 }
619
620 BOOL APIENTRY UserClipCursor(RECTL *prcl);
621 VOID APIENTRY UserRedrawDesktop();
622 HCURSOR FASTCALL UserSetCursor(PCURICON_OBJECT NewCursor, BOOL ForceChange);
623
624 LONG
625 APIENTRY
626 UserChangeDisplaySettings(
627 PUNICODE_STRING pustrDevice,
628 LPDEVMODEW pdm,
629 HWND hwnd,
630 DWORD flags,
631 LPVOID lParam)
632 {
633 DEVMODEW dm;
634 LONG lResult = DISP_CHANGE_SUCCESSFUL;
635 HKEY hkey;
636 NTSTATUS Status;
637 PPDEVOBJ ppdev;
638 PDESKTOP pdesk;
639
640 /* If no DEVMODE is given, use registry settings */
641 if (!pdm)
642 {
643 /* Get the registry settings */
644 Status = UserEnumRegistryDisplaySettings(pustrDevice, &dm);
645 if (!NT_SUCCESS(Status))
646 {
647 DPRINT1("Could not load registry settings\n");
648 return DISP_CHANGE_BADPARAM;
649 }
650 }
651 else if (pdm->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
652 return DISP_CHANGE_BADMODE; /* This is what winXP SP3 returns */
653 else
654 dm = *pdm;
655
656 /* Check params */
657 if ((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
658 {
659 DPRINT1("devmode doesn't specify the resolution.\n");
660 return DISP_CHANGE_BADMODE;
661 }
662
663 /* Get the PDEV */
664 ppdev = EngpGetPDEV(pustrDevice);
665 if (!ppdev)
666 {
667 DPRINT1("failed to get PDEV\n");
668 return DISP_CHANGE_BADPARAM;
669 }
670
671 /* Fixup values */
672 if(dm.dmBitsPerPel == 0 || !(dm.dmFields & DM_BITSPERPEL))
673 {
674 dm.dmBitsPerPel = ppdev->pdmwDev->dmBitsPerPel;
675 dm.dmFields |= DM_BITSPERPEL;
676 }
677
678 if((dm.dmFields & DM_DISPLAYFREQUENCY) && (dm.dmDisplayFrequency == 0))
679 dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency;
680
681 /* Look for the requested DEVMODE */
682 pdm = PDEVOBJ_pdmMatchDevMode(ppdev, &dm);
683 if (!pdm)
684 {
685 DPRINT1("Could not find a matching DEVMODE\n");
686 lResult = DISP_CHANGE_BADMODE;
687 goto leave;
688 }
689 else if (flags & CDS_TEST)
690 {
691 /* It's possible, go ahead! */
692 lResult = DISP_CHANGE_SUCCESSFUL;
693 goto leave;
694 }
695
696 /* Shall we update the registry? */
697 if (flags & CDS_UPDATEREGISTRY)
698 {
699 /* Open the local or global settings key */
700 Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, flags & CDS_GLOBAL);
701 if (NT_SUCCESS(Status))
702 {
703 /* Store the settings */
704 RegWriteDisplaySettings(hkey, pdm);
705
706 /* Close the registry key */
707 ZwClose(hkey);
708 }
709 else
710 {
711 DPRINT1("Could not open registry key\n");
712 lResult = DISP_CHANGE_NOTUPDATED;
713 }
714 }
715
716 /* Check if DEVMODE matches the current mode */
717 if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
718 {
719 DPRINT1("DEVMODE matches, nothing to do\n");
720 goto leave;
721 }
722
723 /* Shall we apply the settings? */
724 if (!(flags & CDS_NORESET))
725 {
726 ULONG ulResult;
727
728 /* Remove mouse pointer */
729 UserSetCursor(NULL, TRUE);
730
731 /* Do the mode switch */
732 ulResult = PDEVOBJ_bSwitchMode(ppdev, pdm);
733
734 /* Restore mouse pointer, no hooks called */
735 UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
736
737 /* Check for failure */
738 if (!ulResult)
739 {
740 DPRINT1("failed to set mode\n");
741 lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
742 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
743
744 goto leave;
745 }
746
747 /* Update the system metrics */
748 InitMetrics();
749
750 //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
751
752 /* Remove all cursor clipping */
753 UserClipCursor(NULL);
754
755 pdesk = IntGetActiveDesktop();
756 //IntHideDesktop(pdesk);
757
758 /* Send WM_DISPLAYCHANGE to all toplevel windows */
759 co_IntSendMessageTimeout(HWND_BROADCAST,
760 WM_DISPLAYCHANGE,
761 (WPARAM)ppdev->gdiinfo.cBitsPixel,
762 (LPARAM)(ppdev->gdiinfo.ulHorzRes + (ppdev->gdiinfo.ulVertRes << 16)),
763 SMTO_NORMAL,
764 100,
765 &ulResult);
766
767 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
768
769 UserRedrawDesktop();
770 }
771
772 leave:
773 /* Release the PDEV */
774 PDEVOBJ_vRelease(ppdev);
775
776 return lResult;
777 }
778
779 LONG
780 APIENTRY
781 NtUserChangeDisplaySettings(
782 PUNICODE_STRING pustrDevice,
783 LPDEVMODEW lpDevMode,
784 HWND hwnd,
785 DWORD dwflags,
786 LPVOID lParam)
787 {
788 WCHAR awcDevice[CCHDEVICENAME];
789 UNICODE_STRING ustrDevice;
790 DEVMODEW dmLocal;
791 LONG lRet;
792
793 /* Check arguments */
794 if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
795 (hwnd != NULL))
796 {
797 SetLastWin32Error(ERROR_INVALID_PARAMETER);
798 return DISP_CHANGE_BADPARAM;
799 }
800
801 /* Check flags */
802 if ((dwflags & (CDS_GLOBAL|CDS_NORESET)) && !(dwflags & CDS_UPDATEREGISTRY))
803 {
804 return DISP_CHANGE_BADFLAGS;
805 }
806
807 /* Copy the device name */
808 if (pustrDevice)
809 {
810 /* Initialize destination string */
811 RtlInitEmptyUnicodeString(&ustrDevice, awcDevice, sizeof(awcDevice));
812
813 _SEH2_TRY
814 {
815 /* Probe the UNICODE_STRING and the buffer */
816 ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
817 ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
818
819 /* Copy the string */
820 RtlCopyUnicodeString(&ustrDevice, pustrDevice);
821 }
822 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
823 {
824 /* Set and return error */
825 SetLastNtError(_SEH2_GetExceptionCode());
826 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
827 }
828 _SEH2_END
829
830 pustrDevice = &ustrDevice;
831 }
832
833 /* Copy devmode */
834 if (lpDevMode)
835 {
836 _SEH2_TRY
837 {
838 /* Probe the size field of the structure */
839 ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
840
841 /* Calculate usable size */
842 dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
843
844 /* Probe and copy the full DEVMODE */
845 ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
846 RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
847 }
848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
849 {
850 /* Set and return error */
851 SetLastNtError(_SEH2_GetExceptionCode());
852 _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
853 }
854 _SEH2_END
855
856 /* Check for extra parameters */
857 if (dmLocal.dmDriverExtra > 0)
858 {
859 /* FIXME: TODO */
860 DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
861 dmLocal.dmDriverExtra = 0;
862 }
863
864 /* Use the local structure */
865 lpDevMode = &dmLocal;
866 }
867
868 // FIXME: Copy videoparameters
869
870 /* Acquire global USER lock */
871 UserEnterExclusive();
872
873 /* Call internal function */
874 lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
875
876 /* Release lock */
877 UserLeave();
878
879 return lRet;
880 }
881