[WIN32K]
[reactos.git] / subsystems / win32 / win32k / ntuser / display.c
index e56cedb..7616abe 100644 (file)
@@ -6,7 +6,7 @@
  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #include <intrin.h>
 
@@ -78,70 +78,32 @@ 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,
@@ -607,8 +569,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 ;
 }
 
 
@@ -686,11 +655,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)
@@ -710,6 +676,9 @@ NtUserEnumDisplaySettings(
     return Status;
 }
 
+BOOL APIENTRY UserClipCursor(RECTL *prcl);
+VOID APIENTRY UserRedrawDesktop();
+HCURSOR FASTCALL UserSetCursor(PCURICON_OBJECT NewCursor, BOOL ForceChange);
 
 LONG
 APIENTRY
@@ -720,23 +689,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_FAILED;
+    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 */
@@ -747,14 +727,26 @@ UserChangeDisplaySettings(
         return DISP_CHANGE_BADPARAM;
     }
 
+    /* Fixup values */
+    if((dm.dmFields & DM_BITSPERPEL) && (dm.dmBitsPerPel == 0))
+        dm.dmBitsPerPel = ppdev->pdmwDev->dmBitsPerPel;
+    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)
@@ -786,18 +778,54 @@ 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) ?
                 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:
+    /* Release the PDEV */
     PDEVOBJ_vRelease(ppdev);
 
     return lResult;
@@ -815,7 +843,7 @@ NtUserChangeDisplaySettings(
     WCHAR awcDevice[CCHDEVICENAME];
     UNICODE_STRING ustrDevice;
     DEVMODEW dmLocal;
-    LONG Ret;
+    LONG lRet;
 
     /* Check arguments */
     if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
@@ -848,6 +876,7 @@ NtUserChangeDisplaySettings(
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
+            /* Set and return error */
             SetLastNtError(_SEH2_GetExceptionCode());
             _SEH2_YIELD(return DISP_CHANGE_BADPARAM);
         }
@@ -861,32 +890,48 @@ 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;
 }