https://git.reactos.org/?p=reactos.git;a=commitdiff;h=2d2824f1b98b772eb36e4e2b75185b48cbeed618

commit 2d2824f1b98b772eb36e4e2b75185b48cbeed618
Author:     Hervé Poussineau <[email protected]>
AuthorDate: Sun Mar 20 17:38:16 2022 +0100
Commit:     hpoussin <[email protected]>
CommitDate: Fri Apr 15 23:09:16 2022 +0200

    [WIN32SS] Implement PDEVOBJ_lChangeDisplaySettings to create initial MDEV
    
    This function can create a MDEV for the whole display (maybe containing 
multiple
    PDEVs), or update settings of a specific PDEV.
    
    - call PDEVOBJ_lChangeDisplaySettings when switching to graphics mode.
    - modify EngpGetPDEV to search requested PDEV only in current MDEV
---
 win32ss/gdi/eng/pdevobj.c    | 181 ++++++++++++++++++++++++++++++++++++++-----
 win32ss/gdi/eng/pdevobj.h    |  16 ++++
 win32ss/user/ntuser/winsta.c |   5 +-
 3 files changed, 180 insertions(+), 22 deletions(-)

diff --git a/win32ss/gdi/eng/pdevobj.c b/win32ss/gdi/eng/pdevobj.c
index a24a8c05dee..1642b94763e 100644
--- a/win32ss/gdi/eng/pdevobj.c
+++ b/win32ss/gdi/eng/pdevobj.c
@@ -643,8 +643,9 @@ EngpGetPDEV(
     _In_opt_ PUNICODE_STRING pustrDeviceName)
 {
     UNICODE_STRING ustrCurrent;
-    PPDEVOBJ ppdev;
+    PPDEVOBJ ppdev = NULL;
     PGRAPHICS_DEVICE pGraphicsDevice;
+    ULONG i;
 
     /* Acquire PDEV lock */
     EngAcquireSemaphore(ghsemPDEV);
@@ -653,16 +654,17 @@ EngpGetPDEV(
     if (pustrDeviceName)
     {
         /* Loop all present PDEVs */
-        for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
+        for (i = 0; i < gpmdev->cDev; i++)
         {
             /* Get a pointer to the GRAPHICS_DEVICE */
-            pGraphicsDevice = ppdev->pGraphicsDevice;
+            pGraphicsDevice = gpmdev->dev[i].ppdev->pGraphicsDevice;
 
             /* Compare the name */
             RtlInitUnicodeString(&ustrCurrent, 
pGraphicsDevice->szWinDeviceName);
             if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
             {
                 /* Found! */
+                ppdev = gpmdev->dev[i].ppdev;
                 break;
             }
         }
@@ -679,32 +681,173 @@ EngpGetPDEV(
         /* Yes, reference the PDEV */
         PDEVOBJ_vReference(ppdev);
     }
-    else
+
+    /* Release PDEV lock */
+    EngReleaseSemaphore(ghsemPDEV);
+
+    return ppdev;
+}
+
+LONG
+PDEVOBJ_lChangeDisplaySettings(
+    _In_opt_ PUNICODE_STRING pustrDeviceName,
+    _In_opt_ PDEVMODEW RequestedMode,
+    _In_opt_ PMDEVOBJ pmdevOld,
+    _Out_ PMDEVOBJ *ppmdevNew,
+    _In_ BOOL bSearchClosestMode)
+{
+    PGRAPHICS_DEVICE pGraphicsDevice;
+    PMDEVOBJ pmdev = NULL;
+    PDEVMODEW pdm = NULL;
+    ULONG lRet = DISP_CHANGE_SUCCESSFUL;
+    ULONG i, j;
+
+    TRACE("PDEVOBJ_lChangeDisplaySettings('%wZ' '%dx%dx%d (%d Hz)' %p %p)\n",
+        pustrDeviceName,
+        RequestedMode ? RequestedMode->dmPelsWidth : 0,
+        RequestedMode ? RequestedMode->dmPelsHeight : 0,
+        RequestedMode ? RequestedMode->dmBitsPerPel : 0,
+        RequestedMode ? RequestedMode->dmDisplayFrequency : 0,
+        pmdevOld, ppmdevNew);
+
+    if (pustrDeviceName)
     {
-        if (pustrDeviceName)
-            pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0);
+        pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0);
         if (!pGraphicsDevice)
-            pGraphicsDevice = gpPrimaryGraphicsDevice;
+        {
+            ERR("Wrong device name provided: '%wZ'\n", pustrDeviceName);
+            lRet = DISP_CHANGE_BADPARAM;
+            goto cleanup;
+        }
+    }
+    else if (RequestedMode)
+    {
+        pGraphicsDevice = gpPrimaryGraphicsDevice;
+        if (!pGraphicsDevice)
+        {
+            ERR("Wrong device'\n");
+            lRet = DISP_CHANGE_BADPARAM;
+            goto cleanup;
+        }
+    }
+
+    if (pGraphicsDevice)
+    {
+        if (!LDEVOBJ_bProbeAndCaptureDevmode(pGraphicsDevice, RequestedMode, 
&pdm, bSearchClosestMode))
+        {
+            ERR("DrvProbeAndCaptureDevmode() failed\n");
+            lRet = DISP_CHANGE_BADMODE;
+            goto cleanup;
+        }
+    }
+
+    /* Here, we know that input parameters were correct */
+
+    {
+        /* Create new MDEV. Note that if we provide a device name,
+         * MDEV will only contain one device.
+         * */
+
+        if (pmdevOld)
+        {
+            /* Disable old MDEV */
+            if (MDEVOBJ_bDisable(pmdevOld))
+            {
+                /* Create new MDEV. On failure, reenable old MDEV */
+                pmdev = MDEVOBJ_Create(pustrDeviceName, pdm);
+                if (!pmdev)
+                    MDEVOBJ_vEnable(pmdevOld);
+            }
+        }
+        else
+        {
+            pmdev = MDEVOBJ_Create(pustrDeviceName, pdm);
+        }
 
-        /* No, create a new PDEV for the given device */
-        ppdev = PDEVOBJ_Create(pGraphicsDevice,
-                               
pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm,
-                               LDEV_DEVICE_DISPLAY);
-        if (ppdev)
+        if (!pmdev)
         {
-            /* Set as primary PDEV, if we don't have one yet */
-            if (!gpmdev->ppdevGlobal)
+            ERR("Failed to create new MDEV\n");
+            lRet = DISP_CHANGE_FAILED;
+            goto cleanup;
+        }
+
+        lRet = DISP_CHANGE_SUCCESSFUL;
+        *ppmdevNew = pmdev;
+
+        /* We now have to do the mode switch */
+
+        if (pustrDeviceName && pmdevOld)
+        {
+            /* We changed settings of one device. Add other devices which were 
already present */
+            for (i = 0; i < pmdevOld->cDev; i++)
             {
-                gpmdev->ppdevGlobal = ppdev;
-                ppdev->pGraphicsDevice->StateFlags |= 
DISPLAY_DEVICE_PRIMARY_DEVICE;
+                for (j = 0; j < pmdev->cDev; j++)
+                {
+                    if (pmdev->dev[j].ppdev->pGraphicsDevice == 
pmdevOld->dev[i].ppdev->pGraphicsDevice)
+                    {
+                        if (PDEVOBJ_bDynamicModeChange(pmdevOld->dev[i].ppdev, 
pmdev->dev[j].ppdev))
+                        {
+                            PPDEVOBJ tmp = pmdevOld->dev[i].ppdev;
+                            pmdevOld->dev[i].ppdev = pmdev->dev[j].ppdev;
+                            pmdev->dev[j].ppdev = tmp;
+                        }
+                        else
+                        {
+                            ERR("Failed to apply new settings\n");
+                            UNIMPLEMENTED;
+                            ASSERT(FALSE);
+                        }
+                        break;
+                    }
+                }
+                if (j == pmdev->cDev)
+                {
+                    PDEVOBJ_vReference(pmdevOld->dev[i].ppdev);
+                    pmdev->dev[pmdev->cDev].ppdev = pmdevOld->dev[i].ppdev;
+                    pmdev->cDev++;
+                }
+            }
+        }
+
+        if (pmdev->cDev == 1)
+        {
+            pmdev->ppdevGlobal = pmdev->dev[0].ppdev;
+        }
+        else
+        {
+            /* FIXME: currently, only use the first display */
+            UNIMPLEMENTED;
+            PDEVOBJ_vReference(pmdev->dev[0].ppdev);
+            pmdev->ppdevGlobal = pmdev->dev[0].ppdev;
+        }
+
+        if (pmdevOld)
+        {
+            /* Search PDEVs which were in pmdevOld, but are not anymore in 
pmdev, and disable them */
+            for (i = 0; i < pmdevOld->cDev; i++)
+            {
+                for (j = 0; j < pmdev->cDev; j++)
+                {
+                    if (pmdev->dev[j].ppdev->pGraphicsDevice == 
pmdevOld->dev[i].ppdev->pGraphicsDevice)
+                        break;
+                }
+                if (j == pmdev->cDev)
+                    PDEVOBJ_bDisableDisplay(pmdevOld->dev[i].ppdev);
             }
         }
     }
 
-    /* Release PDEV lock */
-    EngReleaseSemaphore(ghsemPDEV);
+cleanup:
+    if (lRet != DISP_CHANGE_SUCCESSFUL)
+    {
+        *ppmdevNew = NULL;
+        if (pmdev)
+            MDEVOBJ_vDestroy(pmdev);
+        if (pdm && pdm != RequestedMode)
+            ExFreePoolWithTag(pdm, GDITAG_DEVMODE);
+    }
 
-    return ppdev;
+    return lRet;
 }
 
 INT
diff --git a/win32ss/gdi/eng/pdevobj.h b/win32ss/gdi/eng/pdevobj.h
index 5590ac9548f..c5b63b56e7d 100644
--- a/win32ss/gdi/eng/pdevobj.h
+++ b/win32ss/gdi/eng/pdevobj.h
@@ -228,4 +228,20 @@ PDEVOBJ_Create(
     _In_opt_ PDEVMODEW pdm,
     _In_ ULONG ldevtype);
 
+/* Change display settings:
+ * - pustrDeviceName: name of the device to change settings. Can be NULL to 
specify whole display surface
+ * - RequestedMode: new parameters for device. Ignored if pstrDeviceName is 
NULL
+ * - pmdevOld: old MDEVOBJ. Can be NULL if we are creating the first one
+ * - ppdevNew: MDEVOBJ created by this function, with the new settings
+ * - bSearchClosestMode: do we need to search exact requested mode, or a 
mostly similar one
+ * Return value: a DISP_CHANGE_* value
+ */
+LONG
+PDEVOBJ_lChangeDisplaySettings(
+    _In_opt_ PUNICODE_STRING pustrDeviceName,
+    _In_opt_ PDEVMODEW RequestedMode,
+    _In_opt_ PMDEVOBJ pmdevOld,
+    _Out_ PMDEVOBJ *ppmdevNew,
+    _In_ BOOL bSearchClosestMode);
+
 #endif /* !__WIN32K_PDEVOBJ_H */
diff --git a/win32ss/user/ntuser/winsta.c b/win32ss/user/ntuser/winsta.c
index ba1db88a6bd..88266ad5bb0 100644
--- a/win32ss/user/ntuser/winsta.c
+++ b/win32ss/user/ntuser/winsta.c
@@ -263,10 +263,9 @@ co_IntInitializeDesktopGraphics(VOID)
     UNICODE_STRING DriverName = RTL_CONSTANT_STRING(L"DISPLAY");
     PDESKTOP pdesk;
 
-    gpmdev = ExAllocatePoolZero(PagedPool, sizeof(MDEVOBJ), GDITAG_MDEV);
-    if (!gpmdev)
+    if (PDEVOBJ_lChangeDisplaySettings(NULL, NULL, NULL, &gpmdev, TRUE) != 
DISP_CHANGE_SUCCESSFUL)
     {
-        ERR("Failed to allocate MDEV.\n");
+        ERR("PDEVOBJ_lChangeDisplaySettings() failed.\n");
         return FALSE;
     }
 

Reply via email to