[WIN32K:ENG] In PDEVOBJ_vRefreshModeList, find a proper match for the current display...
[reactos.git] / win32ss / gdi / eng / pdevobj.c
index b890f47..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);
@@ -94,8 +117,12 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
             PALETTE_ShareUnlockPalette(ppdev->ppalSurf);
         }
 
-        /* Disable PDEV */
-        ppdev->pfn.DisablePDEV(ppdev->dhpdev);
+        /* Check if the PDEV was enabled */
+        if (ppdev->dhpdev != NULL)
+        {
+            /* Disable the PDEV */
+            ppdev->pfn.DisablePDEV(ppdev->dhpdev);
+        }
 
         /* Remove it from list */
         if( ppdev == gppdevList )
@@ -120,7 +147,7 @@ PDEVOBJ_vRelease(PPDEVOBJ ppdev)
             gppdevPrimary = NULL;
 
         /* Free it */
-        ExFreePoolWithTag(ppdev, GDITAG_PDEV );
+        PDEVOBJ_vDeletePDEV(ppdev);
     }
 
     /* Unlock loader */
@@ -155,6 +182,11 @@ PDEVOBJ_bEnablePDEV(
                                   (HDEV)ppdev,
                                   ppdev->pGraphicsDevice->pwszDescription,
                                   ppdev->pGraphicsDevice->DeviceObject);
+    if (ppdev->dhpdev == NULL)
+    {
+        DPRINT1("Failed to enable PDEV\n");
+        return FALSE;
+    }
 
     /* Fix up some values */
     if (ppdev->gdiinfo.ulLogPixelsX == 0)
@@ -163,6 +195,15 @@ PDEVOBJ_bEnablePDEV(
     if (ppdev->gdiinfo.ulLogPixelsY == 0)
         ppdev->gdiinfo.ulLogPixelsY = 96;
 
+    /* Set raster caps */
+    ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT;
+    if ((ppdev->gdiinfo.ulTechnology != DT_PLOTTER) && (ppdev->gdiinfo.ulTechnology != DT_CHARSTREAM))
+        ppdev->gdiinfo.flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_DI_BITMAP | RC_BITMAP64 | RC_BITBLT;
+    if (ppdev->gdiinfo.ulTechnology == DT_RASDISPLAY)
+        ppdev->gdiinfo.flRaster |= RC_FLOODFILL;
+    if (ppdev->devinfo.flGraphicsCaps & GCAPS_PALMANAGED)
+        ppdev->gdiinfo.flRaster |= RC_PALETTE;
+
     /* Setup Palette */
     ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
 
@@ -194,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(
@@ -301,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;
     }
 
@@ -314,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) ;
 
@@ -328,7 +419,8 @@ EngpCreatePDEV(
     if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL))
     {
         DPRINT1("Failed to enable PDEV!\n");
-        ASSERT(FALSE);
+        PDEVOBJ_vRelease(ppdev);
+        return NULL;
     }
 
     /* FIXME: this must be done in a better way */
@@ -341,52 +433,68 @@ EngpCreatePDEV(
     return ppdev;
 }
 
+FORCEINLINE
+VOID
+SwitchPointer(
+    _Inout_ PVOID pvPointer1,
+    _Inout_ PVOID pvPointer2)
+{
+    PVOID *ppvPointer1 = pvPointer1;
+    PVOID *ppvPointer2 = pvPointer2;
+    PVOID pvTemp;
+
+    pvTemp = *ppvPointer1;
+    *ppvPointer1 = *ppvPointer2;
+    *ppvPointer2 = pvTemp;
+}
+
 VOID
 NTAPI
 PDEVOBJ_vSwitchPdev(
     PPDEVOBJ ppdev,
     PPDEVOBJ ppdev2)
 {
-    PDEVOBJ pdevTmp;
-    DWORD tmpStateFlags;
-
-    /* Exchange data */
-    pdevTmp = *ppdev;
+    union
+    {
+        DRIVER_FUNCTIONS pfn;
+        GDIINFO gdiinfo;
+        DEVINFO devinfo;
+        DWORD StateFlags;
+    } temp;
 
     /* Exchange driver functions */
+    temp.pfn = ppdev->pfn;
     ppdev->pfn = ppdev2->pfn;
-    ppdev2->pfn = pdevTmp.pfn;
+    ppdev2->pfn = temp.pfn;
 
     /* Exchange LDEVs */
-    ppdev->pldev = ppdev2->pldev;
-    ppdev2->pldev = pdevTmp.pldev;
+    SwitchPointer(&ppdev->pldev, &ppdev2->pldev);
 
     /* Exchange DHPDEV */
-    ppdev->dhpdev = ppdev2->dhpdev;
-    ppdev2->dhpdev = pdevTmp.dhpdev;
+    SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev);
 
     /* Exchange surfaces and associate them with their new PDEV */
-    ppdev->pSurface = ppdev2->pSurface;
-    ppdev2->pSurface = pdevTmp.pSurface;
+    SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface);
     ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev;
     ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2;
 
     /* Exchange devinfo */
+    temp.devinfo = ppdev->devinfo;
     ppdev->devinfo = ppdev2->devinfo;
-    ppdev2->devinfo = pdevTmp.devinfo;
+    ppdev2->devinfo = temp.devinfo;
 
     /* Exchange gdiinfo */
+    temp.gdiinfo = ppdev->gdiinfo;
     ppdev->gdiinfo = ppdev2->gdiinfo;
-    ppdev2->gdiinfo = pdevTmp.gdiinfo;
+    ppdev2->gdiinfo = temp.gdiinfo;
 
     /* Exchange DEVMODE */
-    ppdev->pdmwDev = ppdev2->pdmwDev;
-    ppdev2->pdmwDev = pdevTmp.pdmwDev;
+    SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev);
 
     /* Exchange state flags */
-    tmpStateFlags = ppdev->pGraphicsDevice->StateFlags;
+    temp.StateFlags = ppdev->pGraphicsDevice->StateFlags;
     ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags;
-    ppdev2->pGraphicsDevice->StateFlags = tmpStateFlags;
+    ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags;
 
     /* Notify each driver instance of its new HDEV association */
     ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev);
@@ -407,6 +515,7 @@ PDEVOBJ_bSwitchMode(
 
     /* Lock the PDEV */
     EngAcquireSemaphore(ppdev->hsemDevLock);
+
     /* And everything else */
     EngAcquireSemaphore(ghsemPDEV);
 
@@ -415,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;
     }
 
@@ -428,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 */
@@ -458,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);
 
@@ -472,7 +591,7 @@ leave:
 PPDEVOBJ
 NTAPI
 EngpGetPDEV(
-    PUNICODE_STRING pustrDeviceName)
+    _In_opt_ PUNICODE_STRING pustrDeviceName)
 {
     UNICODE_STRING ustrCurrent;
     PPDEVOBJ ppdev;
@@ -481,37 +600,39 @@ EngpGetPDEV(
     /* Acquire PDEV lock */
     EngAcquireSemaphore(ghsemPDEV);
 
-    /* If no device name is given, ... */
-    if (!pustrDeviceName && gppdevPrimary)
+    /* Did the caller pass a device name? */
+    if (pustrDeviceName)
     {
-        /* ... use the primary PDEV */
-        ppdev = gppdevPrimary;
+        /* Loop all present PDEVs */
+        for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
+        {
+            /* Get a pointer to the GRAPHICS_DEVICE */
+            pGraphicsDevice = ppdev->pGraphicsDevice;
 
-        /* Reference the pdev */
-        InterlockedIncrement(&ppdev->cPdevRefs);
-        goto leave;
+            /* Compare the name */
+            RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
+            if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
+            {
+                /* Found! */
+                break;
+            }
+        }
     }
-
-    /* Loop all present PDEVs */
-    for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
+    else
     {
-        /* Get a pointer to the GRAPHICS_DEVICE */
-        pGraphicsDevice = ppdev->pGraphicsDevice;
-
-        /* Compare the name */
-        RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
-        if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
-        {
-            /* Found! Reference the PDEV */
-            InterlockedIncrement(&ppdev->cPdevRefs);
-            break;
-        }
+        /* Otherwise use the primary PDEV */
+        ppdev = gppdevPrimary;
     }
 
     /* Did we find one? */
-    if (!ppdev)
+    if (ppdev)
     {
-        /* No, create a new PDEV */
+        /* Yes, reference the PDEV */
+        InterlockedIncrement(&ppdev->cPdevRefs);
+    }
+    else
+    {
+        /* No, create a new PDEV for the given device */
         ppdev = EngpCreatePDEV(pustrDeviceName, NULL);
         if (ppdev)
         {
@@ -528,7 +649,6 @@ EngpGetPDEV(
         }
     }
 
-leave:
     /* Release PDEV lock */
     EngReleaseSemaphore(ghsemPDEV);
 
@@ -612,9 +732,10 @@ PDEVOBJ_vGetDeviceCaps(
 
 /** Exported functions ********************************************************/
 
+_Must_inspect_result_ _Ret_z_
 LPWSTR
 APIENTRY
-EngGetDriverName(IN HDEV hdev)
+EngGetDriverName(_In_ HDEV hdev)
 {
     PPDEVOBJ ppdev = (PPDEVOBJ)hdev;
 
@@ -775,7 +896,7 @@ NtGdiGetDeviceCaps(
     return 0;
 }
 
-
+_Success_(return!=FALSE)
 BOOL
 APIENTRY
 NtGdiGetDeviceCapsAll(