[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / display.c
index e5748fc..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)
@@ -78,159 +42,37 @@ RegReadDisplaySettings(HKEY hkey, PDEVMODEW pdm)
 {
     DWORD dwValue;
 
+    /* Zero out the structure */
     RtlZeroMemory(pdm, sizeof(DEVMODEW));
 
-    if (RegReadDWORD(hkey, L"DefaultSettings.BitsPerPel", &dwValue))
-    {
-        pdm->dmBitsPerPel = dwValue;
-        pdm->dmFields |= DM_BITSPERPEL;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.XResolution", &dwValue))
-    {
-        pdm->dmPelsWidth = dwValue;
-//        pdm->dmFields |= DM_XRESOLUTION;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.YResolution", &dwValue))
-    {
-        pdm->dmPelsHeight = dwValue;
-        pdm->dmFields |= DM_YRESOLUTION;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.Flags", &dwValue))
-    {
-        pdm->dmDisplayFlags = dwValue;
-        pdm->dmFields |= DM_BITSPERPEL;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.VRefresh", &dwValue))
-    {
-        pdm->dmDisplayFrequency = dwValue;
-        pdm->dmFields |= DM_DISPLAYFREQUENCY;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.XPanning", &dwValue))
-    {
-        pdm->dmPanningWidth = dwValue;
-        pdm->dmFields |= DM_PANNINGWIDTH;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.YPanning", &dwValue))
-    {
-        pdm->dmPanningHeight = dwValue;
-        pdm->dmFields |= DM_PANNINGHEIGHT;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.Orientation", &dwValue))
-    {
-        pdm->dmDisplayOrientation = dwValue;
-        pdm->dmFields |= DM_DISPLAYORIENTATION;
-    }
-    if (RegReadDWORD(hkey, L"DefaultSettings.FixedOutput", &dwValue))
-    {
-        pdm->dmDisplayFixedOutput = dwValue;
-        pdm->dmFields |= DM_BITSPERPEL;
-    }
-    if (RegReadDWORD(hkey, L"Attach.RelativeX", &dwValue))
-    {
-        pdm->dmPosition.x = dwValue;
-        pdm->dmFields |= DM_POSITION;
-    }
-    if (RegReadDWORD(hkey, L"Attach.RelativeY", &dwValue))
-    {
-        pdm->dmPosition.y = dwValue;
-        pdm->dmFields |= DM_POSITION;
-    }
-//    RegReadDWORD(hkey, L"Attach.ToDesktop, pdm->dmBitsPerPel", &pdm->);
-
+/* Helper macro */
+#define READ(field, str, flag) \
+    if (RegReadDWORD(hkey, L##str, &dwValue)) \
+    { \
+        pdm->field = dwValue; \
+        pdm->dmFields |= flag; \
+    }
+
+    /* Read all present settings */
+    READ(dmBitsPerPel, "DefaultSettings.BitsPerPel", DM_BITSPERPEL);
+    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);
+    READ(dmPanningHeight, "DefaultSettings.YPanning", DM_PANNINGHEIGHT);
+    READ(dmDisplayOrientation, "DefaultSettings.Orientation", DM_DISPLAYORIENTATION);
+    READ(dmDisplayFixedOutput, "DefaultSettings.FixedOutput", DM_DISPLAYFIXEDOUTPUT);
+    READ(dmPosition.x, "Attach.RelativeX", DM_POSITION);
+    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;
@@ -239,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,
@@ -276,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 */
@@ -311,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);
+
+    /* Loop through all adapters */
+    for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
+    {
+        /* Create the adapter's key name */
+        swprintf(awcDeviceName, L"\\Device\\Video%lu", iDevNum);
 
-    /* Query the registry */
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
-                                    L"VIDEO",
-                                    QueryTable,
-                                    NULL,
-                                    NULL);
+        /* 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(
@@ -408,15 +325,15 @@ NtUserEnumDisplayDevices(
     PUNICODE_STRING pustrDevice,
     DWORD iDevNum,
     PDISPLAY_DEVICEW pDisplayDevice,
-    DWORD dwFlags)             
+    DWORD dwFlags)
 {
     UNICODE_STRING ustrDevice;
     WCHAR awcDevice[CCHDEVICENAME];
     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)
@@ -511,7 +428,8 @@ UserEnumCurrentDisplaySettings(
     }
 
     *ppdm = ppdev->pdmwDev;
-    
+    PDEVOBJ_vRelease(ppdev);
+
     return STATUS_SUCCESS;
 }
 
@@ -527,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)
@@ -606,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 ;
 }
 
 
@@ -626,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)
     {
@@ -685,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)
@@ -709,6 +632,9 @@ NtUserEnumDisplaySettings(
     return Status;
 }
 
+BOOL APIENTRY UserClipCursor(RECTL *prcl);
+VOID APIENTRY UserRedrawDesktop();
+HCURSOR FASTCALL UserSetCursor(PCURICON_OBJECT NewCursor, BOOL ForceChange);
 
 LONG
 APIENTRY
@@ -719,23 +645,34 @@ UserChangeDisplaySettings(
    DWORD flags,
    LPVOID lParam)
 {
-    DEVMODEW dmReg;
+    DEVMODEW dm;
     LONG lResult = DISP_CHANGE_SUCCESSFUL;
     HKEY hkey;
     NTSTATUS Status;
     PPDEVOBJ ppdev;
+    PDESKTOP pdesk;
 
     /* If no DEVMODE is given, use registry settings */
     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 */
@@ -746,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)
@@ -772,7 +725,7 @@ UserChangeDisplaySettings(
         {
             DPRINT1("Could not open registry key\n");
             lResult = DISP_CHANGE_NOTUPDATED;
-        }       
+        }
     }
 
     /* Check if DEVMODE matches the current mode */
@@ -785,19 +738,55 @@ UserChangeDisplaySettings(
     /* Shall we apply the settings? */
     if (!(flags & CDS_NORESET))
     {
-        if (!PDEVOBJ_bSwitchMode(ppdev, pdm))
+        ULONG ulResult;
+
+        /* 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) ? 
+            lResult = (lResult == DISP_CHANGE_NOTUPDATED) ?
                 DISP_CHANGE_FAILED : DISP_CHANGE_RESTART;
+
+            goto leave;
         }
-        
-        /* Send message */
-        
+
+        /* Update the system metrics */
+        InitMetrics();
+
+        //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
+
+        /* Remove all cursor clipping */
+        UserClipCursor(NULL);
+
+        pdesk = IntGetActiveDesktop();
+        //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.ulVertRes << 16)),
+                                 SMTO_NORMAL,
+                                 100,
+                                 &ulResult);
+
+        //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
+
+        UserRedrawDesktop();
     }
 
 leave:
-//    PDEVOBJ_vReleasePdev(ppdev);
+    /* Release the PDEV */
+    PDEVOBJ_vRelease(ppdev);
 
     return lResult;
 }
@@ -814,7 +803,7 @@ NtUserChangeDisplaySettings(
     WCHAR awcDevice[CCHDEVICENAME];
     UNICODE_STRING ustrDevice;
     DEVMODEW dmLocal;
-    LONG Ret;
+    LONG lRet;
 
     /* Check arguments */
     if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
@@ -847,6 +836,7 @@ NtUserChangeDisplaySettings(
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
+            /* Set and return error */
             SetLastNtError(_SEH2_GetExceptionCode());
             _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
         }
@@ -860,32 +850,47 @@ NtUserChangeDisplaySettings(
     {
         _SEH2_TRY
         {
+            /* Probe the size field of the structure */
             ProbeForRead(lpDevMode, sizeof(dmLocal.dmSize), 1);
+
+            /* Calculate usable size */
             dmLocal.dmSize = min(sizeof(dmLocal), lpDevMode->dmSize);
+
+            /* 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)
         {
+            /* Set and return error */
             SetLastNtError(_SEH2_GetExceptionCode());
             _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
         }
         _SEH2_END
 
+        /* Check for extra parameters */
         if (dmLocal.dmDriverExtra > 0)
         {
+            /* FIXME: TODO */
             DPRINT1("lpDevMode->dmDriverExtra is IGNORED!\n");
             dmLocal.dmDriverExtra = 0;
         }
+
+        /* Use the local structure */
         lpDevMode = &dmLocal;
     }
 
     // FIXME: Copy videoparameters
 
+    /* Acquire global USER lock */
+    UserEnterExclusive();
+
     /* Call internal function */
-    Ret = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
+    lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
+
+    /* Release lock */
+    UserLeave();
 
-    return Ret;
+    return lRet;
 }