[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / display.c
index 89b926a..f5770a7 100644 (file)
@@ -6,55 +6,19 @@
  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #include <intrin.h>
 
 #define NDEBUG
 #include <debug.h>
 
-PDEVOBJ *gpdevPrimary;
-
-const PWCHAR KEY_ROOT = L"";
-const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
-
-NTSTATUS
-NTAPI
-UserEnumDisplayDevices(
-    PUNICODE_STRING pustrDevice,
-    DWORD iDevNum,
-    PDISPLAY_DEVICEW pdispdev,
-    DWORD dwFlags);
-
-VOID
-RegWriteSZ(HKEY hkey, PWSTR pwszValue, PWSTR pwszData)
-{
-    UNICODE_STRING ustrValue;
-    UNICODE_STRING ustrData;
-
-    RtlInitUnicodeString(&ustrValue, pwszValue);
-    RtlInitUnicodeString(&ustrData, pwszData);
-    ZwSetValueKey(hkey, &ustrValue, 0, REG_SZ, &ustrData, ustrData.Length + sizeof(WCHAR));
-}
-
-VOID
-RegWriteDWORD(HKEY hkey, PWSTR pwszValue, DWORD dwData)
-{
-    UNICODE_STRING ustrValue;
-
-    RtlInitUnicodeString(&ustrValue, pwszValue);
-    ZwSetValueKey(hkey, &ustrValue, 0, REG_DWORD, &dwData, sizeof(DWORD));
-}
+BOOL InitSysParams();
 
+BOOL gbBaseVideo = 0;
 
-BOOL
-RegReadDWORD(HKEY hkey, PWSTR pwszValue, PDWORD pdwData)
-{
-    NTSTATUS Status;
-    ULONG cbSize = sizeof(DWORD);
-    Status = RegQueryValue(hkey, pwszValue, REG_DWORD, pdwData, &cbSize);
-    return NT_SUCCESS(Status);
-}
+static const PWCHAR KEY_ROOT = L"";
+static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
 
 VOID
 RegWriteDisplaySettings(HKEY hkey, PDEVMODEW pdm)
@@ -91,8 +55,8 @@ RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
 
     /* Read all present settings */
     READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL);
-    READ(dmPelsWidth, "DefaultSettings.XResolution", DM_YRESOLUTION); // DM_XRESOLUTION?
-    READ(dmPelsHeight, "DefaultSettings.YResolution", DM_YRESOLUTION);
+    READ(dmPelsWidth, "DefaultSettings.XResolution", DM_PELSWIDTH);
+    READ(dmPelsHeight, "DefaultSettings.YResolution", DM_PELSHEIGHT);
     READ(dmDisplayFlags, "DefaultSettings.Flags", DM_DISPLAYFLAGS);
     READ(dmDisplayFrequency, "DefaultSettings.VRefresh", DM_DISPLAYFREQUENCY);
     READ(dmPanningWidth, "DefaultSettings.XPanning", DM_PANNINGWIDTH);
@@ -103,96 +67,12 @@ RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
     READ(dmPosition.y, "Attach.RelativeY", DM_POSITION);
 }
 
-
-enum
-{
-    VF_USEVGA = 0x1,
-};
-
-BOOL
-InitDisplayDriver(
-    PUNICODE_STRING pustrRegPath,
-    FLONG flags)
-{
-//    PWSTR pwszDriverName;
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-    NTSTATUS Status;
-
-    /* Setup QueryTable for direct registry query */
-    RtlZeroMemory(QueryTable, sizeof(QueryTable));
-    QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED|RTL_QUERY_REGISTRY_DIRECT;
-
-
-    /* Check if vga mode is requested */
-    if (flags & VF_USEVGA)
-    {
-        DWORD dwVgaCompatible;
-
-        /*  */
-        QueryTable[0].Name = L"VgaCompatible";
-        QueryTable[0].EntryContext = &dwVgaCompatible;
-
-        /* Check if the driver is vga */
-        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                        pustrRegPath->Buffer,
-                                        QueryTable,
-                                        NULL,
-                                        NULL);
-
-        if (!dwVgaCompatible)
-        {
-            /* This driver is not a vga driver */
-            return FALSE;
-        }
-    }
-
-#if 0
-
-    /* Query the adapter's registry path */
-    swprintf(awcBuffer, L"\\Device\\Video%lu", iDevNum);
-    QueryTable[0].Name = pGraphicsDevice->szNtDeviceName;
-
-    /* Set string for the registry key */
-    ustrRegistryPath.Buffer = pdispdev->DeviceKey;
-    ustrRegistryPath.Length = 128;
-    ustrRegistryPath.MaximumLength = 128;
-    QueryTable[0].EntryContext = &ustrRegistryPath;
-
-    /* Query the registry */
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
-                                    L"VIDEO",
-                                    QueryTable,
-                                    NULL,
-                                    NULL);
-
-    RegQueryValue(KEY_VIDEO, awcBuffer, REG_SZ, pdispdev->DeviceKey, 256);
-
-    {
-        HANDLE hmod;
-
-        hmod = EngLoadImage(pwszDriverName);
-
-        /* Jump to next name */
-        pwszDriverName += wcslen(pwszDriverName) + 1;
-    }
-    while (pwszDriverName < 0);
-#endif
-
-    return 0;
-}
-
-
-NTSTATUS
+PGRAPHICS_DEVICE
 NTAPI
-DisplayDriverQueryRoutine(
-    IN PWSTR ValueName,
-    IN ULONG ValueType,
-    IN PVOID ValueData,
-    IN ULONG ValueLength,
-    IN PVOID Context,
-    IN PVOID EntryContext)
+InitDisplayDriver(
+    IN PWSTR pwszDeviceName,
+    IN PWSTR pwszRegKey)
 {
-    PWSTR pwszRegKey = ValueData;
     PGRAPHICS_DEVICE pGraphicsDevice;
     UNICODE_STRING ustrDeviceName, ustrDisplayDrivers, ustrDescription;
     NTSTATUS Status;
@@ -201,32 +81,17 @@ DisplayDriverQueryRoutine(
     HKEY hkey;
     DEVMODEW dmDefault;
 
-    UNREFERENCED_PARAMETER(ValueLength);
-    UNREFERENCED_PARAMETER(Context);
-    UNREFERENCED_PARAMETER(EntryContext);
-
-    DPRINT1("DisplayDriverQueryRoutine(%S, %S);\n",
-            ValueName, pwszRegKey);
-
-    /* Check if we have a correct entry */
-    if (ValueType != REG_SZ || ValueName[0] != '\\')
-    {
-        /* Something else, just skip it */
-        return STATUS_SUCCESS;
-    }
+    DPRINT1("InitDisplayDriver(%S, %S);\n",
+            pwszDeviceName, pwszRegKey);
 
     /* Open the driver's registry key */
     Status = RegOpenKey(pwszRegKey, &hkey);
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("Failed to open registry key\n");
-        return STATUS_SUCCESS;
+        DPRINT1("Failed to open registry key: %ls\n", pwszRegKey);
+        return NULL;
     }
 
-// HACK: only use 1st adapter
-//if (ValueName[13] != '0')
-//    return STATUS_SUCCESS;
-
     /* Query the diplay drivers */
     cbSize = sizeof(awcBuffer) - 10;
     Status = RegQueryValue(hkey,
@@ -238,7 +103,7 @@ DisplayDriverQueryRoutine(
     {
         DPRINT1("Didn't find 'InstalledDisplayDrivers', status = 0x%lx\n", Status);
         ZwClose(hkey);
-        return STATUS_SUCCESS;
+        return NULL;
     }
 
     /* Initialize the UNICODE_STRING */
@@ -273,44 +138,134 @@ DisplayDriverQueryRoutine(
     ZwClose(hkey);
 
     /* Register the device with GDI */
-    RtlInitUnicodeString(&ustrDeviceName, ValueName);
+    RtlInitUnicodeString(&ustrDeviceName, pwszDeviceName);
     pGraphicsDevice = EngpRegisterGraphicsDevice(&ustrDeviceName,
                                                  &ustrDisplayDrivers,
                                                  &ustrDescription,
                                                  &dmDefault);
 
-    // FIXME: what to do with pGraphicsDevice?
-
-    return STATUS_SUCCESS;
+    return pGraphicsDevice;
 }
 
-BOOL InitSysParams();
-
-BOOL
-InitVideo(FLONG flags)
+NTSTATUS
+NTAPI
+InitVideo()
 {
-    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+    ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
+    WCHAR awcDeviceName[20];
+    WCHAR awcBuffer[256];
     NTSTATUS Status;
+    PGRAPHICS_DEVICE pGraphicsDevice;
+    ULONG cbValue;
+    HKEY hkey;
 
-    DPRINT1("----------------------------- InitVideo() -------------------------------\n");
+    DPRINT("----------------------------- InitVideo() -------------------------------\n");
 
-    /* Setup QueryTable for registry query */
-    RtlZeroMemory(QueryTable, sizeof(QueryTable));
-    QueryTable[0].QueryRoutine = DisplayDriverQueryRoutine;
+    /* Open the key for the boot command line */
+    Status = RegOpenKey(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control", &hkey);
+    if (NT_SUCCESS(Status))
+    {
+        cbValue = 256;
+        Status = RegQueryValue(hkey, L"SystemStartOptions", REG_SZ, awcBuffer, &cbValue);
+        if (NT_SUCCESS(Status))
+        {
+            /* Check if VGA mode is requested. */
+            if (wcsstr(awcBuffer, L"/BASEVIDEO") != 0)
+            {
+                DPRINT1("VGA mode requested.\n");
+                gbBaseVideo = TRUE;
+            }
+        }
+
+        ZwClose(hkey);
+    }
+
+    /* Open the key for the adapters */
+    Status = RegOpenKey(KEY_VIDEO, &hkey);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Could not open device registry key!\n");
+        return Status;
+    }
+
+    /* Read the name of the VGA adapter */
+    cbValue = 20;
+    Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
+    if (NT_SUCCESS(Status))
+    {
+        iVGACompatible = _wtoi(&awcDeviceName[13]);
+        DPRINT1("VGA adapter = %ld\n", iVGACompatible);
+    }
+
+    /* Get the maximum mumber of adapters */
+    if (!RegReadDWORD(hkey, L"MaxObjectNumber", &ulMaxObjectNumber))
+    {
+        DPRINT1("Could not read MaxObjectNumber, defaulting to 0.\n");
+    }
+
+    DPRINT("Found %ld devices\n", ulMaxObjectNumber);
 
-    /* Query the registry */
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
-                                    L"VIDEO",
-                                    QueryTable,
-                                    NULL,
-                                    NULL);
+    /* Loop through all adapters */
+    for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
+    {
+        /* Create the adapter's key name */
+        swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
+
+        /* Read the reg key name */
+        cbValue = sizeof(awcBuffer);
+        Status = RegQueryValue(hkey, awcDeviceName, REG_SZ, awcBuffer, &cbValue);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("failed to query the registry path:0x%lx\n", Status);
+            continue;
+        }
+
+        /* Initialize the driver for this device */
+        pGraphicsDevice = InitDisplayDriver(awcDeviceName, awcBuffer);
+        if (!pGraphicsDevice) continue;
+
+        /* Check if this is the VGA adapter */
+        if (iDevNum == iVGACompatible)
+        {
+            /* Set the VGA device as primary */
+            gpVgaGraphicsDevice = pGraphicsDevice;
+            DPRINT1("gpVgaGraphicsDevice = %p\n", gpVgaGraphicsDevice);
+        }
+
+        /* Set the first one as primary device */
+        if (!gpPrimaryGraphicsDevice)
+            gpPrimaryGraphicsDevice = pGraphicsDevice;
+    }
+
+    /* Close the device map registry key */
+    ZwClose(hkey);
+
+    /* Check if we had any success */
+    if (!gpPrimaryGraphicsDevice)
+    {
+        DPRINT1("No usable display driver was found.\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    if (gbBaseVideo)
+    {
+        if (gpVgaGraphicsDevice)
+        {
+            /* Set the VgaAdapter as primary */
+            gpPrimaryGraphicsDevice = gpVgaGraphicsDevice;
+            // FIXME: DEVMODE
+        }
+        else
+        {
+            DPRINT1("Could not find VGA compatible driver. Trying normal.\n");
+        }
+    }
 
     InitSysParams();
 
-    return 0;
+    return 1;
 }
 
-
 NTSTATUS
 NTAPI
 UserEnumDisplayDevices(
@@ -377,8 +332,8 @@ NtUserEnumDisplayDevices(
     DISPLAY_DEVICEW dispdev;
     NTSTATUS Status;
 
-    DPRINT1("Enter NtUserEnumDisplayDevices(%p, %ls, %ld)\n",
-            pustrDevice, pustrDevice ? pustrDevice->Buffer : 0, iDevNum);
+    DPRINT("Enter NtUserEnumDisplayDevices(%wZ, %ld)\n",
+           pustrDevice, iDevNum);
 
     // FIXME: HACK, desk.cpl passes broken crap
     if (pustrDevice && iDevNum != 0)
@@ -490,31 +445,32 @@ UserEnumDisplaySettings(
     PDEVMODEENTRY pdmentry;
     ULONG i, iFoundMode;
 
-    DPRINT1("Enter UserEnumDisplaySettings('%ls', %ld)\n",
+    DPRINT("Enter UserEnumDisplaySettings('%ls', %ld)\n",
             pustrDevice ? pustrDevice->Buffer : NULL, iModeNum);
 
     /* Ask gdi for the GRAPHICS_DEVICE */
     pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
+
     if (!pGraphicsDevice)
     {
         /* No device found */
         DPRINT1("No device found!\n");
-        return FALSE;
+        return STATUS_UNSUCCESSFUL;
     }
 
-    if (iModeNum == 0)
-    {
-        DPRINT1("Should initialize modes somehow\n");
-        // Update DISPLAY_DEVICEs?
-    }
+    if (iModeNum >= pGraphicsDevice->cDevModes)
+        return STATUS_NO_MORE_ENTRIES;
 
     iFoundMode = 0;
     for (i = 0; i < pGraphicsDevice->cDevModes; i++)
     {
         pdmentry = &pGraphicsDevice->pDevModeList[i];
 
-//        if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) || // FIXME!
-//            (dwFlags & EDS_RAWMODE))
+        /* FIXME: consider EDS_RAWMODE */
+#if 0
+        if ((!(dwFlags & EDS_RAWMODE) && (pdmentry->dwFlags & 1)) ||!
+            (dwFlags & EDS_RAWMODE))
+#endif
         {
             /* Is this the one we want? */
             if (iFoundMode == iModeNum)
@@ -569,8 +525,15 @@ UserEnumRegistryDisplaySettings(
     IN PUNICODE_STRING pustrDevice,
     OUT LPDEVMODEW pdm)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    HKEY hkey;
+    NTSTATUS Status = UserOpenDisplaySettingsKey(&hkey, pustrDevice, 0);
+    if(NT_SUCCESS(Status))
+    {
+        RegReadDisplaySettings(hkey, pdm);
+        ZwClose(hkey);
+        return STATUS_SUCCESS;
+    }
+    return Status ;
 }
 
 
@@ -589,7 +552,7 @@ NtUserEnumDisplaySettings(
     DEVMODEW dmReg, *pdm;
 
     DPRINT1("Enter NtUserEnumDisplaySettings(%ls, %ld)\n",
-            pustrDevice ? pustrDevice->Buffer:0, iModeNum);
+            pustrDevice ? pustrDevice->Buffer : 0, iModeNum);
 
     if (pustrDevice)
     {
@@ -648,11 +611,8 @@ NtUserEnumDisplaySettings(
             cbExtra = lpDevMode->dmDriverExtra;
 
             ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
-            lpDevMode->dmPelsWidth = pdm->dmPelsWidth;
-            lpDevMode->dmPelsHeight = pdm->dmPelsHeight;
-            lpDevMode->dmBitsPerPel = pdm->dmBitsPerPel;
-            lpDevMode->dmDisplayFrequency = pdm->dmDisplayFrequency;
-            lpDevMode->dmDisplayFlags = pdm->dmDisplayFlags;
+            /* Output what we got */
+            RtlCopyMemory(lpDevMode, pdm, min(cbSize, pdm->dmSize));
 
             /* output private/extra driver data */
             if (cbExtra > 0 && pdm->dmDriverExtra > 0)
@@ -674,6 +634,7 @@ NtUserEnumDisplaySettings(
 
 BOOL APIENTRY UserClipCursor(RECTL *prcl);
 VOID APIENTRY UserRedrawDesktop();
+HCURSOR FASTCALL UserSetCursor(PCURICON_OBJECT NewCursor, BOOL ForceChange);
 
 LONG
 APIENTRY
@@ -684,7 +645,7 @@ UserChangeDisplaySettings(
    DWORD flags,
    LPVOID lParam)
 {
-    DEVMODEW dmReg;
+    DEVMODEW dm;
     LONG lResult = DISP_CHANGE_SUCCESSFUL;
     HKEY hkey;
     NTSTATUS Status;
@@ -695,13 +656,23 @@ UserChangeDisplaySettings(
     if (!pdm)
     {
         /* Get the registry settings */
-        Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
+        Status = UserEnumRegistryDisplaySettings(pustrDevice, &dm);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Could not load registry settings\n");
             return DISP_CHANGE_BADPARAM;
         }
-        pdm = &dmReg;
+    }
+    else if (pdm->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
+        return DISP_CHANGE_BADMODE; /* This is what winXP SP3 returns */
+    else
+        dm = *pdm;
+
+    /* Check params */
+    if ((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
+    {
+        DPRINT1("devmode doesn't specify the resolution.\n");
+        return DISP_CHANGE_BADMODE;
     }
 
     /* Get the PDEV */
@@ -712,14 +683,30 @@ UserChangeDisplaySettings(
         return DISP_CHANGE_BADPARAM;
     }
 
+    /* Fixup values */
+    if(dm.dmBitsPerPel == 0 || !(dm.dmFields & DM_BITSPERPEL))
+    {
+        dm.dmBitsPerPel = ppdev->pdmwDev->dmBitsPerPel;
+        dm.dmFields |= DM_BITSPERPEL;
+    }
+
+    if((dm.dmFields & DM_DISPLAYFREQUENCY) && (dm.dmDisplayFrequency == 0))
+        dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency;
+
     /* Look for the requested DEVMODE */
-    pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
+    pdm = PDEVOBJ_pdmMatchDevMode(ppdev, &dm);
     if (!pdm)
     {
         DPRINT1("Could not find a matching DEVMODE\n");
         lResult = DISP_CHANGE_BADMODE;
         goto leave;
     }
+    else if (flags & CDS_TEST)
+    {
+        /* It's possible, go ahead! */
+        lResult = DISP_CHANGE_SUCCESSFUL;
+        goto leave;
+    }
 
     /* Shall we update the registry? */
     if (flags & CDS_UPDATEREGISTRY)
@@ -753,7 +740,17 @@ UserChangeDisplaySettings(
     {
         ULONG ulResult;
 
-        if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
+        /* Remove mouse pointer */
+        UserSetCursor(NULL, TRUE);
+
+        /* Do the mode switch */
+        ulResult = PDEVOBJ_bSwitchMode(ppdev, pdm);
+
+        /* Restore mouse pointer, no hooks called */
+        UserSetCursorPos(gpsi->ptCursor.x, gpsi->ptCursor.y, FALSE);
+
+        /* Check for failure */
+        if (!ulResult)
         {
             DPRINT1("failed to set mode\n");
             lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
@@ -765,24 +762,24 @@ UserChangeDisplaySettings(
         /* Update the system metrics */
         InitMetrics();
 
+        //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
+
         /* Remove all cursor clipping */
         UserClipCursor(NULL);
 
-        //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
-
         pdesk = IntGetActiveDesktop();
-        IntHideDesktop(pdesk);
+        //IntHideDesktop(pdesk);
 
         /* Send WM_DISPLAYCHANGE to all toplevel windows */
         co_IntSendMessageTimeout(HWND_BROADCAST,
                                  WM_DISPLAYCHANGE,
                                  (WPARAM)ppdev->gdiinfo.cBitsPixel,
-                                 (LPARAM)(ppdev->gdiinfo.ulHorzRes + (ppdev->gdiinfo.ulHorzRes << 16)),
+                                 (LPARAM)(ppdev->gdiinfo.ulHorzRes + (ppdev->gdiinfo.ulVertRes << 16)),
                                  SMTO_NORMAL,
                                  100,
                                  &ulResult);
 
-        co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
+        //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
 
         UserRedrawDesktop();
     }
@@ -862,7 +859,6 @@ NtUserChangeDisplaySettings(
             /* Probe and copy the full DEVMODE */
             ProbeForRead(lpDevMode, dmLocal.dmSize, 1);
             RtlCopyMemory(&dmLocal, lpDevMode, dmLocal.dmSize);
-            dmLocal.dmSize = sizeof(dmLocal);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {