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)
10 DBG_DEFAULT_CHANNEL(UserDisplay
);
12 BOOL gbBaseVideo
= FALSE
;
13 static PPROCESSINFO gpFullscreen
= NULL
;
15 static const PWCHAR KEY_VIDEO
= L
"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
18 RegWriteDisplaySettings(HKEY hkey
, PDEVMODEW pdm
)
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->);
35 RegReadDisplaySettings(HKEY hkey
, PDEVMODEW pdm
)
39 /* Zero out the structure */
40 RtlZeroMemory(pdm
, sizeof(DEVMODEW
));
43 #define READ(field, str, flag) \
44 if (RegReadDWORD(hkey, L##str, &dwValue)) \
46 pdm->field = dwValue; \
47 pdm->dmFields |= flag; \
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
);
67 IN PWSTR pwszDeviceName
,
70 PGRAPHICS_DEVICE pGraphicsDevice
;
71 UNICODE_STRING ustrDeviceName
, ustrDisplayDrivers
, ustrDescription
;
79 TRACE("InitDisplayDriver(%S, %S);\n",
80 pwszDeviceName
, pwszRegKey
);
82 /* Open the driver's registry key */
83 Status
= RegOpenKey(pwszRegKey
, &hkey
);
84 if (!NT_SUCCESS(Status
))
86 ERR("Failed to open registry key: %ls\n", pwszRegKey
);
90 /* Query the diplay drivers */
91 cbSize
= sizeof(awcBuffer
) - 10;
92 Status
= RegQueryValue(hkey
,
93 L
"InstalledDisplayDrivers",
97 if (!NT_SUCCESS(Status
))
99 ERR("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status
);
104 /* Initialize the UNICODE_STRING */
105 ustrDisplayDrivers
.Buffer
= awcBuffer
;
106 ustrDisplayDrivers
.MaximumLength
= (USHORT
)cbSize
;
107 ustrDisplayDrivers
.Length
= (USHORT
)cbSize
;
109 /* Set Buffer for description and size of remaining buffer */
110 ustrDescription
.Buffer
= awcBuffer
+ (cbSize
/ sizeof(WCHAR
));
111 cbSize
= sizeof(awcBuffer
) - cbSize
;
113 /* Query the device string */
114 Status
= RegQueryValue(hkey
,
115 L
"Device Description",
117 ustrDescription
.Buffer
,
119 if (NT_SUCCESS(Status
))
121 ustrDescription
.MaximumLength
= (USHORT
)cbSize
;
122 ustrDescription
.Length
= (USHORT
)cbSize
;
126 RtlInitUnicodeString(&ustrDescription
, L
"<unknown>");
129 /* Query the default settings */
130 RegReadDisplaySettings(hkey
, &dmDefault
);
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;
137 /* Close the registry key */
140 /* Register the device with GDI */
141 RtlInitUnicodeString(&ustrDeviceName
, pwszDeviceName
);
142 pGraphicsDevice
= EngpRegisterGraphicsDevice(&ustrDeviceName
,
146 if (pGraphicsDevice
&& dwVga
)
148 pGraphicsDevice
->StateFlags
|= DISPLAY_DEVICE_VGA_COMPATIBLE
;
151 return pGraphicsDevice
;
158 ULONG iDevNum
, iVGACompatible
= -1, ulMaxObjectNumber
= 0;
159 WCHAR awcDeviceName
[20];
160 WCHAR awcBuffer
[256];
162 PGRAPHICS_DEVICE pGraphicsDevice
;
166 TRACE("----------------------------- InitVideo() -------------------------------\n");
168 /* Check if VGA mode is requested, by finding the special volatile key created by VIDEOPRT */
169 Status
= RegOpenKey(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\GraphicsDrivers\\BaseVideo", &hkey
);
170 if (NT_SUCCESS(Status
))
172 gbBaseVideo
= NT_SUCCESS(Status
);
174 ERR("VGA mode requested.\n");
176 /* Open the key for the adapters */
177 Status
= RegOpenKey(KEY_VIDEO
, &hkey
);
178 if (!NT_SUCCESS(Status
))
180 ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status
);
184 /* Read the name of the VGA adapter */
185 cbValue
= sizeof(awcDeviceName
);
186 Status
= RegQueryValue(hkey
, L
"VgaCompatible", REG_SZ
, awcDeviceName
, &cbValue
);
187 if (NT_SUCCESS(Status
))
189 iVGACompatible
= _wtoi(&awcDeviceName
[sizeof("\\Device\\Video")-1]);
190 ERR("VGA adapter = %lu\n", iVGACompatible
);
193 /* Get the maximum mumber of adapters */
194 if (!RegReadDWORD(hkey
, L
"MaxObjectNumber", &ulMaxObjectNumber
))
196 ERR("Could not read MaxObjectNumber, defaulting to 0.\n");
199 TRACE("Found %lu devices\n", ulMaxObjectNumber
+ 1);
201 /* Loop through all adapters */
202 for (iDevNum
= 0; iDevNum
<= ulMaxObjectNumber
; iDevNum
++)
204 /* Create the adapter's key name */
205 swprintf(awcDeviceName
, L
"\\Device\\Video%lu", iDevNum
);
207 /* Read the reg key name */
208 cbValue
= sizeof(awcBuffer
);
209 Status
= RegQueryValue(hkey
, awcDeviceName
, REG_SZ
, awcBuffer
, &cbValue
);
210 if (!NT_SUCCESS(Status
))
212 ERR("failed to query the registry path:0x%lx\n", Status
);
216 /* Initialize the driver for this device */
217 pGraphicsDevice
= InitDisplayDriver(awcDeviceName
, awcBuffer
);
218 if (!pGraphicsDevice
) continue;
220 /* Check if this is a VGA compatible adapter */
221 if (pGraphicsDevice
->StateFlags
& DISPLAY_DEVICE_VGA_COMPATIBLE
)
223 /* Save this as the VGA adapter */
224 if (!gpVgaGraphicsDevice
)
225 gpVgaGraphicsDevice
= pGraphicsDevice
;
226 TRACE("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice
);
230 /* Set the first one as primary device */
231 if (!gpPrimaryGraphicsDevice
)
232 gpPrimaryGraphicsDevice
= pGraphicsDevice
;
233 TRACE("gpPrimaryGraphicsDevice = %p\n", gpPrimaryGraphicsDevice
);
237 /* Close the device map registry key */
240 /* Was VGA mode requested? */
243 /* Check if we found a VGA compatible device */
244 if (gpVgaGraphicsDevice
)
246 /* Set the VgaAdapter as primary */
247 gpPrimaryGraphicsDevice
= gpVgaGraphicsDevice
;
252 ERR("Could not find VGA compatible driver. Trying normal.\n");
256 /* Check if we had any success */
257 if (!gpPrimaryGraphicsDevice
)
259 /* Check if there is a VGA device we skipped */
260 if (gpVgaGraphicsDevice
)
262 /* There is, use the VGA device */
263 gpPrimaryGraphicsDevice
= gpVgaGraphicsDevice
;
267 ERR("No usable display driver was found.\n");
268 return STATUS_UNSUCCESSFUL
;
274 return STATUS_SUCCESS
;
278 UserRefreshDisplay(IN PPDEVOBJ ppdev
)
281 // PVOID pvOldCursor;
283 // TODO: Re-enable the cursor reset code once this function becomes called
284 // from within a Win32 thread... Indeed UserSetCursor() requires this, but
285 // at the moment this function is directly called from a separate thread
286 // from within videoprt, instead of by a separate win32k system thread.
291 PDEVOBJ_vReference(ppdev
);
293 /* Remove mouse pointer */
294 // pvOldCursor = UserSetCursor(NULL, TRUE);
296 /* Do the mode switch -- Use the actual same current mode */
297 ulResult
= PDEVOBJ_bSwitchMode(ppdev
, ppdev
->pdmwDev
);
300 /* Restore mouse pointer, no hooks called */
301 // pvOldCursor = UserSetCursor(pvOldCursor, TRUE);
302 // ASSERT(pvOldCursor == NULL);
304 /* Update the system metrics */
307 /* Set new size of the monitor */
308 // UserUpdateMonitorSize((HDEV)ppdev);
310 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
313 PDEVOBJ_vRelease(ppdev
);
318 UserEnumDisplayDevices(
319 PUNICODE_STRING pustrDevice
,
321 PDISPLAY_DEVICEW pdispdev
,
324 PGRAPHICS_DEVICE pGraphicsDevice
;
329 /* Ask gdi for the GRAPHICS_DEVICE */
330 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDevice
, iDevNum
, 0);
331 if (!pGraphicsDevice
)
333 /* No device found */
334 ERR("No GRAPHICS_DEVICE found\n");
335 return STATUS_UNSUCCESSFUL
;
338 /* Open the device map registry key */
339 Status
= RegOpenKey(KEY_VIDEO
, &hkey
);
340 if (!NT_SUCCESS(Status
))
342 /* No device found */
343 ERR("Could not open reg key\n");
344 return STATUS_UNSUCCESSFUL
;
347 /* Query the registry path */
348 cbSize
= sizeof(pdispdev
->DeviceKey
);
350 pGraphicsDevice
->szNtDeviceName
,
355 /* Close registry key */
358 /* Copy device name, device string and StateFlags */
359 RtlStringCbCopyW(pdispdev
->DeviceName
, sizeof(pdispdev
->DeviceName
), pGraphicsDevice
->szWinDeviceName
);
360 RtlStringCbCopyW(pdispdev
->DeviceString
, sizeof(pdispdev
->DeviceString
), pGraphicsDevice
->pwszDescription
);
361 pdispdev
->StateFlags
= pGraphicsDevice
->StateFlags
;
362 // FIXME: fill in DEVICE ID
363 pdispdev
->DeviceID
[0] = UNICODE_NULL
;
365 return STATUS_SUCCESS
;
371 NtUserEnumDisplayDevices(
372 PUNICODE_STRING pustrDevice
,
374 PDISPLAY_DEVICEW pDisplayDevice
,
377 UNICODE_STRING ustrDevice
;
378 WCHAR awcDevice
[CCHDEVICENAME
];
379 DISPLAY_DEVICEW dispdev
;
382 TRACE("Enter NtUserEnumDisplayDevices(%wZ, %lu)\n",
383 pustrDevice
, iDevNum
);
385 dispdev
.cb
= sizeof(dispdev
);
389 /* Initialize destination string */
390 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
394 /* Probe the UNICODE_STRING and the buffer */
395 ProbeForRead(pustrDevice
, sizeof(UNICODE_STRING
), 1);
396 ProbeForRead(pustrDevice
->Buffer
, pustrDevice
->Length
, 1);
398 /* Copy the string */
399 RtlCopyUnicodeString(&ustrDevice
, pustrDevice
);
401 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
403 // _SEH2_YIELD(return _SEH2_GetExceptionCode());
404 _SEH2_YIELD(return NT_SUCCESS(_SEH2_GetExceptionCode()));
408 if (ustrDevice
.Length
> 0)
409 pustrDevice
= &ustrDevice
;
414 /* If name is given only iDevNum==0 gives results */
415 if (pustrDevice
&& iDevNum
!= 0)
418 /* Acquire global USER lock */
421 /* Call the internal function */
422 Status
= UserEnumDisplayDevices(pustrDevice
, iDevNum
, &dispdev
, dwFlags
);
427 /* On success copy data to caller */
428 if (NT_SUCCESS(Status
))
433 /* First probe the cb field */
434 ProbeForWrite(&pDisplayDevice
->cb
, sizeof(DWORD
), 1);
436 /* Check the buffer size */
437 if (pDisplayDevice
->cb
)
439 /* Probe the output buffer */
440 pDisplayDevice
->cb
= min(pDisplayDevice
->cb
, sizeof(dispdev
));
441 ProbeForWrite(pDisplayDevice
, pDisplayDevice
->cb
, 1);
443 /* Copy as much as the given buffer allows */
444 RtlCopyMemory(pDisplayDevice
, &dispdev
, pDisplayDevice
->cb
);
447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
449 Status
= _SEH2_GetExceptionCode();
454 TRACE("Leave NtUserEnumDisplayDevices, Status = 0x%lx\n", Status
);
455 /* Return the result */
457 return NT_SUCCESS(Status
); // FIXME
462 UserEnumCurrentDisplaySettings(
463 PUNICODE_STRING pustrDevice
,
468 /* Get the PDEV for the device */
469 ppdev
= EngpGetPDEV(pustrDevice
);
472 /* No device found */
473 ERR("No PDEV found!\n");
474 return STATUS_INVALID_PARAMETER_1
;
477 *ppdm
= ppdev
->pdmwDev
;
478 PDEVOBJ_vRelease(ppdev
);
480 return STATUS_SUCCESS
;
485 UserEnumDisplaySettings(
486 PUNICODE_STRING pustrDevice
,
491 PGRAPHICS_DEVICE pGraphicsDevice
;
492 PDEVMODEENTRY pdmentry
;
496 TRACE("Enter UserEnumDisplaySettings('%wZ', %lu)\n",
497 pustrDevice
, iModeNum
);
499 /* Ask GDI for the GRAPHICS_DEVICE */
500 pGraphicsDevice
= EngpFindGraphicsDevice(pustrDevice
, 0, 0);
501 ppdev
= EngpGetPDEV(pustrDevice
);
503 if (!pGraphicsDevice
|| !ppdev
)
505 /* No device found */
506 ERR("No device found!\n");
507 return STATUS_INVALID_PARAMETER_1
;
510 /* let's politely ask the driver for an updated mode list,
511 just in case there's something new in there (vbox) */
513 PDEVOBJ_vRefreshModeList(ppdev
);
514 PDEVOBJ_vRelease(ppdev
);
517 for (i
= 0; i
< pGraphicsDevice
->cDevModes
; i
++)
519 pdmentry
= &pGraphicsDevice
->pDevModeList
[i
];
521 /* FIXME: Consider EDS_RAWMODE */
523 if ((!(dwFlags
& EDS_RAWMODE
) && (pdmentry
->dwFlags
& 1)) ||!
524 (dwFlags
& EDS_RAWMODE
))
527 /* Is this the one we want? */
528 if (iFoundMode
== iModeNum
)
530 *ppdm
= pdmentry
->pdm
;
531 return STATUS_SUCCESS
;
534 /* Increment number of found modes */
539 /* Nothing was found */
540 return STATUS_INVALID_PARAMETER_2
;
545 UserOpenDisplaySettingsKey(
547 IN PUNICODE_STRING pustrDevice
,
551 DISPLAY_DEVICEW dispdev
;
554 /* Get device info */
555 Status
= UserEnumDisplayDevices(pustrDevice
, 0, &dispdev
, 0);
556 if (!NT_SUCCESS(Status
))
561 // FIXME: Need to fix the registry key somehow
564 /* Open the registry key */
565 Status
= RegOpenKey(dispdev
.DeviceKey
, &hkey
);
566 if (!NT_SUCCESS(Status
))
576 UserEnumRegistryDisplaySettings(
577 IN PUNICODE_STRING pustrDevice
,
581 NTSTATUS Status
= UserOpenDisplaySettingsKey(&hkey
, pustrDevice
, 0);
582 if(NT_SUCCESS(Status
))
584 RegReadDisplaySettings(hkey
, pdm
);
586 return STATUS_SUCCESS
;
593 NtUserEnumDisplaySettings(
594 IN PUNICODE_STRING pustrDevice
,
596 OUT LPDEVMODEW lpDevMode
,
599 UNICODE_STRING ustrDeviceUser
;
600 UNICODE_STRING ustrDevice
;
601 WCHAR awcDevice
[CCHDEVICENAME
];
603 ULONG cbSize
, cbExtra
;
604 DEVMODEW dmReg
, *pdm
;
606 TRACE("Enter NtUserEnumDisplaySettings(%wZ, %lu, %p, 0x%lx)\n",
607 pustrDevice
, iModeNum
, lpDevMode
, dwFlags
);
611 ProbeForRead(lpDevMode
, sizeof(DEVMODEW
), sizeof(UCHAR
));
613 cbSize
= lpDevMode
->dmSize
;
614 cbExtra
= lpDevMode
->dmDriverExtra
;
616 ProbeForWrite(lpDevMode
, cbSize
+ cbExtra
, sizeof(UCHAR
));
618 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
620 _SEH2_YIELD(return _SEH2_GetExceptionCode());
624 if (lpDevMode
->dmSize
!= sizeof(DEVMODEW
))
626 return STATUS_BUFFER_TOO_SMALL
;
631 /* Initialize destination string */
632 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
636 /* Probe the UNICODE_STRING and the buffer */
637 ustrDeviceUser
= ProbeForReadUnicodeString(pustrDevice
);
639 if (!ustrDeviceUser
.Length
|| !ustrDeviceUser
.Buffer
)
640 ExRaiseStatus(STATUS_NO_MEMORY
);
642 ProbeForRead(ustrDeviceUser
.Buffer
,
643 ustrDeviceUser
.Length
,
646 /* Copy the string */
647 RtlCopyUnicodeString(&ustrDevice
, &ustrDeviceUser
);
649 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
651 _SEH2_YIELD(return STATUS_INVALID_PARAMETER_1
);
655 pustrDevice
= &ustrDevice
;
658 /* Acquire global USER lock */
661 if (iModeNum
== ENUM_REGISTRY_SETTINGS
)
663 /* Get the registry settings */
664 Status
= UserEnumRegistryDisplaySettings(pustrDevice
, &dmReg
);
666 pdm
->dmSize
= sizeof(DEVMODEW
);
668 else if (iModeNum
== ENUM_CURRENT_SETTINGS
)
670 /* Get the current settings */
671 Status
= UserEnumCurrentDisplaySettings(pustrDevice
, &pdm
);
675 /* Get specified settings */
676 Status
= UserEnumDisplaySettings(pustrDevice
, iModeNum
, &pdm
, dwFlags
);
682 /* Did we succeed? */
683 if (NT_SUCCESS(Status
))
685 /* Copy some information back */
688 /* Output what we got */
689 RtlCopyMemory(lpDevMode
, pdm
, min(cbSize
, pdm
->dmSize
));
691 /* Output private/extra driver data */
692 if (cbExtra
> 0 && pdm
->dmDriverExtra
> 0)
694 RtlCopyMemory((PCHAR
)lpDevMode
+ cbSize
,
695 (PCHAR
)pdm
+ pdm
->dmSize
,
696 min(cbExtra
, pdm
->dmDriverExtra
));
699 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
701 Status
= _SEH2_GetExceptionCode();
710 UserUpdateFullscreen(
713 if (flags
& CDS_FULLSCREEN
)
714 gpFullscreen
= gptiCurrent
->ppi
;
721 UserChangeDisplaySettings(
722 PUNICODE_STRING pustrDevice
,
728 LONG lResult
= DISP_CHANGE_SUCCESSFUL
;
735 /* If no DEVMODE is given, use registry settings */
738 /* Get the registry settings */
739 Status
= UserEnumRegistryDisplaySettings(pustrDevice
, &dm
);
740 if (!NT_SUCCESS(Status
))
742 ERR("Could not load registry settings\n");
743 return DISP_CHANGE_BADPARAM
;
746 else if (pdm
->dmSize
< FIELD_OFFSET(DEVMODEW
, dmFields
))
748 return DISP_CHANGE_BADMODE
; /* This is what WinXP SP3 returns */
755 /* Save original bit count */
756 OrigBC
= gpsi
->BitCount
;
759 if ((dm
.dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
761 ERR("Devmode doesn't specify the resolution.\n");
762 return DISP_CHANGE_BADMODE
;
766 ppdev
= EngpGetPDEV(pustrDevice
);
769 ERR("Failed to get PDEV\n");
770 return DISP_CHANGE_BADPARAM
;
774 if (dm
.dmBitsPerPel
== 0 || !(dm
.dmFields
& DM_BITSPERPEL
))
776 dm
.dmBitsPerPel
= ppdev
->pdmwDev
->dmBitsPerPel
;
777 dm
.dmFields
|= DM_BITSPERPEL
;
780 if ((dm
.dmFields
& DM_DISPLAYFREQUENCY
) && (dm
.dmDisplayFrequency
== 0))
781 dm
.dmDisplayFrequency
= ppdev
->pdmwDev
->dmDisplayFrequency
;
783 /* Look for the requested DEVMODE */
784 pdm
= PDEVOBJ_pdmMatchDevMode(ppdev
, &dm
);
787 ERR("Could not find a matching DEVMODE\n");
788 lResult
= DISP_CHANGE_BADMODE
;
791 else if (flags
& CDS_TEST
)
793 /* It's possible, go ahead! */
794 lResult
= DISP_CHANGE_SUCCESSFUL
;
798 /* Shall we update the registry? */
799 if (flags
& CDS_UPDATEREGISTRY
)
801 /* Open the local or global settings key */
802 Status
= UserOpenDisplaySettingsKey(&hkey
, pustrDevice
, flags
& CDS_GLOBAL
);
803 if (NT_SUCCESS(Status
))
805 /* Store the settings */
806 RegWriteDisplaySettings(hkey
, pdm
);
808 /* Close the registry key */
813 ERR("Could not open registry key\n");
814 lResult
= DISP_CHANGE_NOTUPDATED
;
818 /* Check if DEVMODE matches the current mode */
819 if (pdm
== ppdev
->pdmwDev
&& !(flags
& CDS_RESET
))
821 ERR("DEVMODE matches, nothing to do\n");
825 /* Shall we apply the settings? */
826 if (!(flags
& CDS_NORESET
))
832 /* Remove mouse pointer */
833 pvOldCursor
= UserSetCursor(NULL
, TRUE
);
835 /* Do the mode switch */
836 ulResult
= PDEVOBJ_bSwitchMode(ppdev
, pdm
);
838 /* Restore mouse pointer, no hooks called */
839 pvOldCursor
= UserSetCursor(pvOldCursor
, TRUE
);
840 ASSERT(pvOldCursor
== NULL
);
842 /* Check for success or failure */
845 /* Setting mode failed */
846 ERR("Failed to set mode\n");
848 /* Set the correct return value */
849 if ((flags
& CDS_UPDATEREGISTRY
) && (lResult
!= DISP_CHANGE_NOTUPDATED
))
850 lResult
= DISP_CHANGE_RESTART
;
852 lResult
= DISP_CHANGE_FAILED
;
856 /* Setting mode succeeded */
857 lResult
= DISP_CHANGE_SUCCESSFUL
;
859 UserUpdateFullscreen(flags
);
861 /* Update the system metrics */
864 /* Set new size of the monitor */
865 UserUpdateMonitorSize((HDEV
)ppdev
);
867 /* Update the SERVERINFO */
868 gpsi
->dmLogPixels
= ppdev
->gdiinfo
.ulLogPixelsY
;
869 gpsi
->Planes
= ppdev
->gdiinfo
.cPlanes
;
870 gpsi
->BitsPixel
= ppdev
->gdiinfo
.cBitsPixel
;
871 gpsi
->BitCount
= gpsi
->Planes
* gpsi
->BitsPixel
;
872 gpsi
->aiSysMet
[SM_CXSCREEN
] = ppdev
->gdiinfo
.ulHorzRes
;
873 gpsi
->aiSysMet
[SM_CYSCREEN
] = ppdev
->gdiinfo
.ulVertRes
;
874 if (ppdev
->gdiinfo
.flRaster
& RC_PALETTE
)
876 gpsi
->PUSIFlags
|= PUSIF_PALETTEDISPLAY
;
880 gpsi
->PUSIFlags
&= ~PUSIF_PALETTEDISPLAY
;
882 // Font is realized and this dc was previously set to internal DC_ATTR.
883 gpsi
->cxSysFontChar
= IntGetCharDimensions(hSystemBM
, &tmw
, (DWORD
*)&gpsi
->cySysFontChar
);
884 gpsi
->tmSysFont
= tmw
;
888 * Refresh the display on success and even on failure,
889 * since the display may have been messed up.
892 /* Remove all cursor clipping */
893 UserClipCursor(NULL
);
895 //pdesk = IntGetActiveDesktop();
896 //IntHideDesktop(pdesk);
898 /* Send WM_DISPLAYCHANGE to all toplevel windows */
899 co_IntSendMessageTimeout( HWND_BROADCAST
,
902 MAKELONG(gpsi
->aiSysMet
[SM_CXSCREEN
], gpsi
->aiSysMet
[SM_CYSCREEN
]),
907 ERR("BitCount New %d Orig %d ChkNew %d\n",gpsi
->BitCount
,OrigBC
,ppdev
->gdiinfo
.cBitsPixel
);
909 /* Not full screen and different bit count, send messages */
910 if (!(flags
& CDS_FULLSCREEN
) &&
911 gpsi
->BitCount
!= OrigBC
)
913 ERR("Detect settings changed.\n");
914 UserSendNotifyMessage(HWND_BROADCAST
, WM_SETTINGCHANGE
, 0, 0);
915 UserSendNotifyMessage(HWND_BROADCAST
, WM_SYSCOLORCHANGE
, 0, 0);
918 //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
924 /* Release the PDEV */
925 PDEVOBJ_vRelease(ppdev
);
931 UserDisplayNotifyShutdown(
932 PPROCESSINFO ppiCurrent
)
934 if (ppiCurrent
== gpFullscreen
)
936 UserChangeDisplaySettings(NULL
, NULL
, 0, NULL
);
938 ERR("Failed to restore display mode!\n");
944 NtUserChangeDisplaySettings(
945 PUNICODE_STRING pustrDevice
,
946 LPDEVMODEW lpDevMode
,
950 WCHAR awcDevice
[CCHDEVICENAME
];
951 UNICODE_STRING ustrDevice
;
955 /* Check arguments */
956 if ((dwflags
!= CDS_VIDEOPARAMETERS
) && (lParam
!= NULL
))
958 EngSetLastError(ERROR_INVALID_PARAMETER
);
959 return DISP_CHANGE_BADPARAM
;
963 if ((dwflags
& (CDS_GLOBAL
|CDS_NORESET
)) && !(dwflags
& CDS_UPDATEREGISTRY
))
965 return DISP_CHANGE_BADFLAGS
;
968 if ((dwflags
& CDS_RESET
) && (dwflags
& CDS_NORESET
))
970 return DISP_CHANGE_BADFLAGS
;
973 /* Copy the device name */
976 /* Initialize destination string */
977 RtlInitEmptyUnicodeString(&ustrDevice
, awcDevice
, sizeof(awcDevice
));
981 /* Probe the UNICODE_STRING and the buffer */
982 ProbeForRead(pustrDevice
, sizeof(UNICODE_STRING
), 1);
983 ProbeForRead(pustrDevice
->Buffer
, pustrDevice
->Length
, 1);
985 /* Copy the string */
986 RtlCopyUnicodeString(&ustrDevice
, pustrDevice
);
988 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
990 /* Set and return error */
991 SetLastNtError(_SEH2_GetExceptionCode());
992 _SEH2_YIELD(return DISP_CHANGE_BADPARAM
);
996 pustrDevice
= &ustrDevice
;
1004 /* Probe the size field of the structure */
1005 ProbeForRead(lpDevMode
, sizeof(dmLocal
.dmSize
), 1);
1007 /* Calculate usable size */
1008 dmLocal
.dmSize
= min(sizeof(dmLocal
), lpDevMode
->dmSize
);
1010 /* Probe and copy the full DEVMODE */
1011 ProbeForRead(lpDevMode
, dmLocal
.dmSize
, 1);
1012 RtlCopyMemory(&dmLocal
, lpDevMode
, dmLocal
.dmSize
);
1014 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1016 /* Set and return error */
1017 SetLastNtError(_SEH2_GetExceptionCode());
1018 _SEH2_YIELD(return DISP_CHANGE_BADPARAM
);
1022 /* Check for extra parameters */
1023 if (dmLocal
.dmDriverExtra
> 0)
1026 ERR("lpDevMode->dmDriverExtra is IGNORED!\n");
1027 dmLocal
.dmDriverExtra
= 0;
1030 /* Use the local structure */
1031 lpDevMode
= &dmLocal
;
1034 // FIXME: Copy videoparameters
1036 /* Acquire global USER lock */
1037 UserEnterExclusive();
1039 /* Call internal function */
1040 lRet
= UserChangeDisplaySettings(pustrDevice
, lpDevMode
, dwflags
, NULL
);