[WIN32K:ENG] In PDEVOBJ_vRefreshModeList, find a proper match for the current display...
[reactos.git] / win32ss / gdi / eng / pdevobj.c
index 4d90b0a..19c2fee 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Support for physical devices
- * FILE:             subsystems/win32/win32k/eng/pdevobj.c
+ * FILE:             win32ss/gdi/eng/pdevobj.c
  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
@@ -18,7 +18,7 @@ static HSEMAPHORE ghsemPDEV;
 INIT_FUNCTION
 NTSTATUS
 NTAPI
-InitPDEVImpl()
+InitPDEVImpl(VOID)
 {
     ghsemPDEV = EngCreateSemaphore();
     if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES;
@@ -50,7 +50,7 @@ DbgLookupDHPDEV(DHPDEV dhpdev)
 #endif
 
 PPDEVOBJ
-PDEVOBJ_AllocPDEV()
+PDEVOBJ_AllocPDEV(VOID)
 {
     PPDEVOBJ ppdev;
 
@@ -60,11 +60,34 @@ PDEVOBJ_AllocPDEV()
 
     RtlZeroMemory(ppdev, sizeof(PDEVOBJ));
 
+    ppdev->hsemDevLock = EngCreateSemaphore();
+    if (ppdev->hsemDevLock == NULL)
+    {
+        ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+        return NULL;
+    }
+
+    /* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */
+    ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV);
+    if (ppdev->pEDDgpl)
+        RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL));
+
     ppdev->cPdevRefs = 1;
 
     return ppdev;
 }
 
+static
+VOID
+PDEVOBJ_vDeletePDEV(
+    PPDEVOBJ ppdev)
+{
+    EngDeleteSemaphore(ppdev->hsemDevLock);
+    if (ppdev->pEDDgpl)
+        ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV);
+    ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+}
+
 VOID
 NTAPI
 PDEVOBJ_vRelease(PPDEVOBJ ppdev)
@@ -81,7 +104,7 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
     if (ppdev->cPdevRefs == 0)
     {
         /* Do we have a surface? */
-        if(ppdev->pSurface)
+        if (ppdev->pSurface)
         {
             /* Release the surface and let the driver free it */
             SURFACE_ShareUnlockSurface(ppdev->pSurface);
@@ -124,7 +147,7 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
             gppdevPrimary = NULL;
 
         /* Free it */
-        ExFreePoolWithTag(ppdev, GDITAG_PDEV );
+        PDEVOBJ_vDeletePDEV(ppdev);
     }
 
     /* Unlock loader */
@@ -212,25 +235,72 @@ PDEVOBJ_pSurface(
 {
     HSURF hsurf;
 
-    /* Check if we already have a surface */
-    if (ppdev->pSurface)
-    {
-        /* Increment reference count */
-        GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject);
-    }
-    else
+    /* Check if there is no surface for this PDEV yet */
+    if (ppdev->pSurface == NULL)
     {
         /* Call the drivers DrvEnableSurface */
         hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev);
+        if (hsurf== NULL)
+        {
+            DPRINT1("Failed to create PDEV surface!\n");
+            return NULL;
+        }
 
-        /* Lock the surface */
+        /* Get a reference to the surface */
         ppdev->pSurface = SURFACE_ShareLockSurface(hsurf);
+        NT_ASSERT(ppdev->pSurface != NULL);
     }
 
+    /* Increment reference count */
+    GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject);
+
     DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev->pSurface);
     return ppdev->pSurface;
 }
 
+VOID
+NTAPI
+PDEVOBJ_vRefreshModeList(
+    PPDEVOBJ ppdev)
+{
+    PGRAPHICS_DEVICE pGraphicsDevice;
+    PDEVMODEINFO pdminfo, pdmiNext;
+    DEVMODEW dmDefault;
+    DEVMODEW dmCurrent;
+
+    /* 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;
+         pdminfo = pdmiNext)
+    {
+        pdmiNext = pdminfo->pdmiNext;
+        ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE);
+    }
+    pGraphicsDevice->pdevmodeInfo = NULL;
+    ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE);
+    pGraphicsDevice->pDevModeList = NULL;
+
+    /* Now re-populate the list */
+    if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault))
+    {
+        DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a perfectly good mode list\n");
+    }
+
+    ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, &dmCurrent);
+
+    /* Unlock PDEV */
+    EngReleaseSemaphore(ppdev->hsemDevLock);
+}
+
 PDEVMODEW
 NTAPI
 PDEVOBJ_pdmMatchDevMode(
@@ -319,7 +389,7 @@ EngpCreatePDEV(
         DPRINT1("Could not load display driver '%ls', '%ls'\n",
                 pGraphicsDevice->pDiplayDrivers,
                 pdm->dmDeviceName);
-        ExFreePoolWithTag(ppdev, GDITAG_PDEV);
+        PDEVOBJ_vRelease(ppdev);
         return NULL;
     }
 
@@ -332,7 +402,10 @@ EngpCreatePDEV(
         ppdev->pfnMovePointer = EngMovePointer;
 
     ppdev->pGraphicsDevice = pGraphicsDevice;
-    ppdev->hsemDevLock = EngCreateSemaphore();
+
+    // DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field
+    ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject;
+
     // Should we change the ative mode of pGraphicsDevice ?
     ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm) ;
 
@@ -451,10 +524,10 @@ PDEVOBJ_bSwitchMode(
     // Lookup the GraphicsDevice + select DEVMODE
     // pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
 
-    /* 1. Temporarily disable the current PDEV */
+    /* 1. Temporarily disable the current PDEV and reset video to its default mode */
     if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE))
     {
-        DPRINT1("DrvAssertMode failed\n");
+        DPRINT1("DrvAssertMode(FALSE) failed\n");
         goto leave;
     }
 
@@ -464,15 +537,16 @@ PDEVOBJ_bSwitchMode(
     if (!ppdevTmp)
     {
         DPRINT1("Failed to create a new PDEV\n");
-        goto leave;
+        goto leave2;
     }
 
     /* 3. Create a new surface */
     pSurface = PDEVOBJ_pSurface(ppdevTmp);
     if (!pSurface)
     {
-        DPRINT1("DrvEnableSurface failed\n");
-        goto leave;
+        DPRINT1("PDEVOBJ_pSurface failed\n");
+        PDEVOBJ_vRelease(ppdevTmp);
+        goto leave2;
     }
 
     /* 4. Get DirectDraw information */
@@ -494,10 +568,19 @@ PDEVOBJ_bSwitchMode(
 
     /* Success! */
     retval = TRUE;
+
+leave2:
+    /* Set the new video mode, or restore the original one in case of failure */
+    if (!ppdev->pfn.AssertMode(ppdev->dhpdev, TRUE))
+    {
+        DPRINT1("DrvAssertMode(TRUE) failed\n");
+    }
+
 leave:
-    /* Unlock PDEV */
-    EngReleaseSemaphore(ppdev->hsemDevLock);
+    /* Unlock everything else */
     EngReleaseSemaphore(ghsemPDEV);
+    /* Unlock the PDEV */
+    EngReleaseSemaphore(ppdev->hsemDevLock);
 
     DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);