https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3cb1dd8ab20c8b29ed497…
commit 3cb1dd8ab20c8b29ed497518b5abb8656ac8354e
Author: Hervé Poussineau <hpoussin(a)reactos.org>
AuthorDate: Sun Jan 9 10:44:53 2022 +0100
Commit: hpoussin <32227662+hpoussin(a)users.noreply.github.com>
CommitDate: Fri Apr 15 23:09:16 2022 +0200
[WIN32SS] Rewrite PDEVOBJ_pdmMatchDevMode to LDEVOBJ_bProbeAndCaptureDevmode
- make it return a new allocated PDEVMODEW instead of a pointer into
existing PGRAPHICS_DEVICE (usefull when available display modes can
dynamically change: VirtualBox, RDP, ...)
- update all callers
---
win32ss/gdi/eng/device.c | 27 +++++-----------
win32ss/gdi/eng/ldevobj.c | 71 +++++++++++++++++++++++++++++++++++++++++++
win32ss/gdi/eng/ldevobj.h | 8 +++++
win32ss/gdi/eng/pdevobj.c | 68 ++++++++++-------------------------------
win32ss/gdi/eng/pdevobj.h | 6 ----
win32ss/user/ntuser/display.c | 17 ++++++++---
6 files changed, 114 insertions(+), 83 deletions(-)
diff --git a/win32ss/gdi/eng/device.c b/win32ss/gdi/eng/device.c
index 8ad49ed5fd1..4f2284fa1e6 100644
--- a/win32ss/gdi/eng/device.c
+++ b/win32ss/gdi/eng/device.c
@@ -130,25 +130,18 @@ EngpPopulateDeviceModeList(
_In_ PDEVMODEW pdmDefault)
{
PDEVMODEINFO pdminfo;
- PDEVMODEW pdm;
+ PDEVMODEW pdm, pdmSelected;
ULONG i;
- BOOLEAN bModeMatch = FALSE;
ASSERT(pGraphicsDevice->pdevmodeInfo == NULL);
ASSERT(pGraphicsDevice->pDevModeList == NULL);
- if (!LDEVOBJ_bBuildDevmodeList(pGraphicsDevice))
+ if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, pdmDefault, &pdmSelected,
TRUE))
{
- ERR("LDEVOBJ_bBuildDevmodeList() failed\n");
+ ERR("LDEVOBJ_bProbeAndCaptureDevmode() failed\n");
return FALSE;
}
- TRACE("Looking for mode %lux%lux%lu(%lu Hz)\n",
- pdmDefault->dmPelsWidth,
- pdmDefault->dmPelsHeight,
- pdmDefault->dmBitsPerPel,
- pdmDefault->dmDisplayFrequency);
-
/* Loop through all DEVMODEINFOs */
for (pdminfo = pGraphicsDevice->pdevmodeInfo, i = 0;
pdminfo;
@@ -159,20 +152,14 @@ EngpPopulateDeviceModeList(
{
pdm = pGraphicsDevice->pDevModeList[i].pdm;
- /* Compare with the default entry */
- if (!bModeMatch &&
- pdm->dmBitsPerPel == pdmDefault->dmBitsPerPel &&
- pdm->dmPelsWidth == pdmDefault->dmPelsWidth &&
- pdm->dmPelsHeight == pdmDefault->dmPelsHeight)
+ /* Compare with the selected entry */
+ if (pdm->dmSize == pdmSelected->dmSize &&
+ RtlCompareMemory(pdm, pdmSelected, pdm->dmSize) == pdm->dmSize)
{
pGraphicsDevice->iDefaultMode = i;
pGraphicsDevice->iCurrentMode = i;
TRACE("Found default entry: %lu '%ls'\n", i,
pdm->dmDeviceName);
- if (pdm->dmDisplayFrequency == pdmDefault->dmDisplayFrequency)
- {
- /* Uh oh, even the display frequency matches. */
- bModeMatch = TRUE;
- }
+ break;
}
}
}
diff --git a/win32ss/gdi/eng/ldevobj.c b/win32ss/gdi/eng/ldevobj.c
index e2079da8178..db46a0dfbb6 100644
--- a/win32ss/gdi/eng/ldevobj.c
+++ b/win32ss/gdi/eng/ldevobj.c
@@ -558,6 +558,77 @@ LDEVOBJ_bBuildDevmodeList(
return TRUE;
}
+BOOL
+LDEVOBJ_bProbeAndCaptureDevmode(
+ _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
+ _In_ PDEVMODEW RequestedMode,
+ _Out_ PDEVMODEW *pSelectedMode,
+ _In_ BOOL bSearchClosestMode)
+{
+ PDEVMODEW pdmCurrent, pdm, pdmSelected = NULL;
+ ULONG i;
+ DWORD dwFields;
+
+ if (!LDEVOBJ_bBuildDevmodeList(pGraphicsDevice))
+ return FALSE;
+
+ /* Search if requested mode exists */
+ for (i = 0; i < pGraphicsDevice->cDevModes; i++)
+ {
+ pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
+
+ /* Compare asked DEVMODE fields
+ * Only compare those that are valid in both DEVMODE structs */
+ dwFields = pdmCurrent->dmFields & RequestedMode->dmFields;
+
+ /* For now, we only need those */
+ if ((dwFields & DM_BITSPERPEL) &&
+ (pdmCurrent->dmBitsPerPel != RequestedMode->dmBitsPerPel)) continue;
+ if ((dwFields & DM_PELSWIDTH) &&
+ (pdmCurrent->dmPelsWidth != RequestedMode->dmPelsWidth)) continue;
+ if ((dwFields & DM_PELSHEIGHT) &&
+ (pdmCurrent->dmPelsHeight != RequestedMode->dmPelsHeight)) continue;
+ if ((dwFields & DM_DISPLAYFREQUENCY) &&
+ (pdmCurrent->dmDisplayFrequency != RequestedMode->dmDisplayFrequency))
continue;
+
+ pdmSelected = pdmCurrent;
+ break;
+ }
+
+ if (!pdmSelected)
+ {
+ WARN("Requested mode not found (%dx%dx%d %d Hz)\n",
+ RequestedMode->dmFields & DM_PELSWIDTH ? RequestedMode->dmPelsWidth
: 0,
+ RequestedMode->dmFields & DM_PELSHEIGHT ?
RequestedMode->dmPelsHeight : 0,
+ RequestedMode->dmFields & DM_BITSPERPEL ?
RequestedMode->dmBitsPerPel : 0,
+ RequestedMode->dmFields & DM_DISPLAYFREQUENCY ?
RequestedMode->dmDisplayFrequency : 0);
+ if (!bSearchClosestMode || pGraphicsDevice->cDevModes == 0)
+ return FALSE;
+
+ /* FIXME: need to search the closest mode instead of taking the first one */
+ pdmSelected = pGraphicsDevice->pDevModeList[0].pdm;
+ WARN("Replacing it by %dx%dx%d %d Hz\n",
+ pdmSelected->dmFields & DM_PELSWIDTH ? pdmSelected->dmPelsWidth :
0,
+ pdmSelected->dmFields & DM_PELSHEIGHT ? pdmSelected->dmPelsHeight :
0,
+ pdmSelected->dmFields & DM_BITSPERPEL ? pdmSelected->dmBitsPerPel :
0,
+ pdmSelected->dmFields & DM_DISPLAYFREQUENCY ?
pdmSelected->dmDisplayFrequency : 0);
+ }
+
+ /* Allocate memory for output */
+ pdm = ExAllocatePoolZero(PagedPool, pdmSelected->dmSize +
pdmSelected->dmDriverExtra, GDITAG_DEVMODE);
+ if (!pdm)
+ return FALSE;
+
+ /* Copy selected mode */
+ RtlCopyMemory(pdm, pdmSelected, pdmSelected->dmSize);
+ RtlCopyMemory((PVOID)((ULONG_PTR)pdm + pdm->dmSize),
+ (PVOID)((ULONG_PTR)pdmSelected + pdmSelected->dmSize),
+ pdmSelected->dmDriverExtra);
+
+ *pSelectedMode = pdm;
+ return TRUE;
+}
+
/** Exported functions ********************************************************/
HANDLE
diff --git a/win32ss/gdi/eng/ldevobj.h b/win32ss/gdi/eng/ldevobj.h
index cac2ec8f5e0..7b2fc2065ee 100644
--- a/win32ss/gdi/eng/ldevobj.h
+++ b/win32ss/gdi/eng/ldevobj.h
@@ -56,6 +56,14 @@ BOOL
LDEVOBJ_bBuildDevmodeList(
_Inout_ PGRAPHICS_DEVICE pGraphicsDevice);
+/* This function selects the best available mode corresponding to requested mode */
+BOOL
+LDEVOBJ_bProbeAndCaptureDevmode(
+ _Inout_ PGRAPHICS_DEVICE pGraphicsDevice,
+ _In_ PDEVMODEW RequestedMode,
+ _Out_ PDEVMODEW *pSelectedMode,
+ _In_ BOOL bSearchClosestMode);
+
PLDEVOBJ
NTAPI
EngGetLDEV(
diff --git a/win32ss/gdi/eng/pdevobj.c b/win32ss/gdi/eng/pdevobj.c
index e764dea384c..77b9a9fafc3 100644
--- a/win32ss/gdi/eng/pdevobj.c
+++ b/win32ss/gdi/eng/pdevobj.c
@@ -83,6 +83,8 @@ PDEVOBJ_vDeletePDEV(
PPDEVOBJ ppdev)
{
EngDeleteSemaphore(ppdev->hsemDevLock);
+ if (ppdev->pdmwDev)
+ ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE);
if (ppdev->pEDDgpl)
ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV);
ExFreePoolWithTag(ppdev, GDITAG_PDEV);
@@ -266,18 +268,13 @@ PDEVOBJ_vRefreshModeList(
{
PGRAPHICS_DEVICE pGraphicsDevice;
PDEVMODEINFO pdminfo, pdmiNext;
- DEVMODEW dmDefault;
- DEVMODEW dmCurrent;
+ PDEVMODEW newDevMode;
/* Lock the PDEV */
EngAcquireSemaphore(ppdev->hsemDevLock);
pGraphicsDevice = ppdev->pGraphicsDevice;
- /* Remember our default mode */
- dmDefault = *pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm;
- dmCurrent = *ppdev->pdmwDev;
-
/* Clear out the modes */
for (pdminfo = pGraphicsDevice->pdevmodeInfo;
pdminfo;
@@ -290,57 +287,17 @@ PDEVOBJ_vRefreshModeList(
ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE);
pGraphicsDevice->pDevModeList = NULL;
- /* Now re-populate the list */
- if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault))
+ /* Search an available display mode */
+ if (LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, ppdev->pdmwDev,
&newDevMode, TRUE))
{
- DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a
perfectly good mode list\n");
+ ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE);
+ ppdev->pdmwDev = newDevMode;
}
- ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, &dmCurrent);
-
/* Unlock PDEV */
EngReleaseSemaphore(ppdev->hsemDevLock);
}
-PDEVMODEW
-NTAPI
-PDEVOBJ_pdmMatchDevMode(
- PPDEVOBJ ppdev,
- PDEVMODEW pdm)
-{
- PGRAPHICS_DEVICE pGraphicsDevice;
- PDEVMODEW pdmCurrent;
- ULONG i;
- DWORD dwFields;
-
- pGraphicsDevice = ppdev->pGraphicsDevice;
-
- for (i = 0; i < pGraphicsDevice->cDevModes; i++)
- {
- pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
-
- /* Compare asked DEVMODE fields
- * Only compare those that are valid in both DEVMODE structs */
- dwFields = pdmCurrent->dmFields & pdm->dmFields;
-
- /* For now, we only need those */
- if ((dwFields & DM_BITSPERPEL) &&
- (pdmCurrent->dmBitsPerPel != pdm->dmBitsPerPel)) continue;
- if ((dwFields & DM_PELSWIDTH) &&
- (pdmCurrent->dmPelsWidth != pdm->dmPelsWidth)) continue;
- if ((dwFields & DM_PELSHEIGHT) &&
- (pdmCurrent->dmPelsHeight != pdm->dmPelsHeight)) continue;
- if ((dwFields & DM_DISPLAYFREQUENCY) &&
- (pdmCurrent->dmDisplayFrequency != pdm->dmDisplayFrequency)) continue;
-
- /* Match! Return the DEVMODE */
- return pdmCurrent;
- }
-
- /* Nothing found */
- return NULL;
-}
-
static
PPDEVOBJ
EngpCreatePDEV(
@@ -349,6 +306,7 @@ EngpCreatePDEV(
{
PGRAPHICS_DEVICE pGraphicsDevice;
PPDEVOBJ ppdev;
+ PDEVMODEW newDevMode;
DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm);
@@ -410,7 +368,13 @@ EngpCreatePDEV(
ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject;
// Should we change the ative mode of pGraphicsDevice ?
- ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
+ if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, pdm, &newDevMode, TRUE))
+ {
+ DPRINT1("LDEVOBJ_bProbeAndCaptureDevmode() failed\n");
+ PDEVOBJ_vRelease(ppdev);
+ return NULL;
+ }
+ ppdev->pdmwDev = newDevMode;
/* FIXME! */
ppdev->flFlags = PDEV_DISPLAY;
@@ -525,7 +489,7 @@ PDEVOBJ_bSwitchMode(
DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev,
ppdev->pSurface);
// Lookup the GraphicsDevice + select DEVMODE
- // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
+ // pdm = LDEVOBJ_bProbeAndCaptureDevmode(ppdev, pdm);
/* 1. Temporarily disable the current PDEV and reset video to its default mode */
if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE))
diff --git a/win32ss/gdi/eng/pdevobj.h b/win32ss/gdi/eng/pdevobj.h
index 4d22c270aa7..af4973b60f6 100644
--- a/win32ss/gdi/eng/pdevobj.h
+++ b/win32ss/gdi/eng/pdevobj.h
@@ -213,10 +213,4 @@ PDEVOBJ_bSwitchMode(
PPDEVOBJ ppdev,
PDEVMODEW pdm);
-PDEVMODEW
-NTAPI
-PDEVOBJ_pdmMatchDevMode(
- PPDEVOBJ ppdev,
- PDEVMODEW pdm);
-
#endif /* !__WIN32K_PDEVOBJ_H */
diff --git a/win32ss/user/ntuser/display.c b/win32ss/user/ntuser/display.c
index df00c0e3974..81ed1bdb402 100644
--- a/win32ss/user/ntuser/display.c
+++ b/win32ss/user/ntuser/display.c
@@ -657,6 +657,7 @@ UserChangeDisplaySettings(
PPDEVOBJ ppdev;
WORD OrigBC;
//PDESKTOP pdesk;
+ PDEVMODEW newDevMode = NULL;
/* If no DEVMODE is given, use registry settings */
if (!pdm)
@@ -707,8 +708,7 @@ UserChangeDisplaySettings(
dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency;
/* Look for the requested DEVMODE */
- pdm = PDEVOBJ_pdmMatchDevMode(ppdev, &dm);
- if (!pdm)
+ if (!LDEVOBJ_bProbeAndCaptureDevmode(ppdev->pGraphicsDevice, &dm,
&newDevMode, FALSE))
{
ERR("Could not find a matching DEVMODE\n");
lResult = DISP_CHANGE_BADMODE;
@@ -729,7 +729,7 @@ UserChangeDisplaySettings(
if (NT_SUCCESS(Status))
{
/* Store the settings */
- RegWriteDisplaySettings(hkey, pdm);
+ RegWriteDisplaySettings(hkey, newDevMode);
/* Close the registry key */
ZwClose(hkey);
@@ -742,7 +742,9 @@ UserChangeDisplaySettings(
}
/* Check if DEVMODE matches the current mode */
- if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
+ if (newDevMode->dmSize == ppdev->pdmwDev->dmSize &&
+ RtlCompareMemory(newDevMode, ppdev->pdmwDev, newDevMode->dmSize) ==
newDevMode->dmSize &&
+ !(flags & CDS_RESET))
{
ERR("DEVMODE matches, nothing to do\n");
goto leave;
@@ -759,7 +761,7 @@ UserChangeDisplaySettings(
pvOldCursor = UserSetCursor(NULL, TRUE);
/* Do the mode switch */
- ulResult = PDEVOBJ_bSwitchMode(ppdev, pdm);
+ ulResult = PDEVOBJ_bSwitchMode(ppdev, newDevMode);
/* Restore mouse pointer, no hooks called */
pvOldCursor = UserSetCursor(pvOldCursor, TRUE);
@@ -781,6 +783,8 @@ UserChangeDisplaySettings(
{
/* Setting mode succeeded */
lResult = DISP_CHANGE_SUCCESSFUL;
+ ExFreePoolWithTag(ppdev->pdmwDev, GDITAG_DEVMODE);
+ ppdev->pdmwDev = newDevMode;
UserUpdateFullscreen(flags);
@@ -847,6 +851,9 @@ UserChangeDisplaySettings(
}
leave:
+ if (newDevMode && newDevMode != ppdev->pdmwDev)
+ ExFreePoolWithTag(newDevMode, GDITAG_DEVMODE);
+
/* Release the PDEV */
PDEVOBJ_vRelease(ppdev);