[WIN32SS:NTUSER] Remove some hardcoded buffer sizes + number of chars vs. bytes mixup.
[reactos.git] / win32ss / user / ntuser / display.c
index 350f497..8ef37c9 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Video initialization and display settings
- * FILE:             subsystems/win32/win32k/ntuser/display.c
+ * FILE:             win32ss/user/ntuser/display.c
  * PROGRAMER:        Timo Kreuzer (timo.kreuzer@reactos.org)
  */
 
@@ -10,6 +10,7 @@
 DBG_DEFAULT_CHANNEL(UserDisplay);
 
 BOOL gbBaseVideo = 0;
+static PPROCESSINFO gpFullscreen = NULL;
 
 static const PWCHAR KEY_VIDEO = L"\\Registry\\Machine\\HARDWARE\\DEVICEMAP\\VIDEO";
 
@@ -75,8 +76,8 @@ InitDisplayDriver(
     DEVMODEW dmDefault;
     DWORD dwVga;
 
-    ERR("InitDisplayDriver(%S, %S);\n",
-            pwszDeviceName, pwszRegKey);
+    TRACE("InitDisplayDriver(%S, %S);\n",
+          pwszDeviceName, pwszRegKey);
 
     /* Open the driver's registry key */
     Status = RegOpenKey(pwszRegKey, &hkey);
@@ -152,7 +153,7 @@ InitDisplayDriver(
 
 NTSTATUS
 NTAPI
-InitVideo()
+InitVideo(VOID)
 {
     ULONG iDevNum, iVGACompatible = -1, ulMaxObjectNumber = 0;
     WCHAR awcDeviceName[20];
@@ -168,7 +169,7 @@ InitVideo()
     Status = RegOpenKey(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control", &hkey);
     if (NT_SUCCESS(Status))
     {
-        cbValue = 256;
+        cbValue = sizeof(awcBuffer);
         Status = RegQueryValue(hkey, L"SystemStartOptions", REG_SZ, awcBuffer, &cbValue);
         if (NT_SUCCESS(Status))
         {
@@ -187,17 +188,17 @@ InitVideo()
     Status = RegOpenKey(KEY_VIDEO, &hkey);
     if (!NT_SUCCESS(Status))
     {
-        ERR("Could not open device registry key!\n");
+        ERR("Could not open HARDWARE\\DEVICEMAP\\VIDEO registry key:0x%lx\n", Status);
         return Status;
     }
 
     /* Read the name of the VGA adapter */
-    cbValue = 20;
+    cbValue = sizeof(awcDeviceName);
     Status = RegQueryValue(hkey, L"VgaCompatible", REG_SZ, awcDeviceName, &cbValue);
     if (NT_SUCCESS(Status))
     {
-        iVGACompatible = _wtoi(&awcDeviceName[13]);
-        ERR("VGA adapter = %ld\n", iVGACompatible);
+        iVGACompatible = _wtoi(&awcDeviceName[sizeof("\\Device\\Video")-1]);
+        ERR("VGA adapter = %lu\n", iVGACompatible);
     }
 
     /* Get the maximum mumber of adapters */
@@ -206,7 +207,7 @@ InitVideo()
         ERR("Could not read MaxObjectNumber, defaulting to 0.\n");
     }
 
-    TRACE("Found %ld devices\n", ulMaxObjectNumber + 1);
+    TRACE("Found %lu devices\n", ulMaxObjectNumber + 1);
 
     /* Loop through all adapters */
     for (iDevNum = 0; iDevNum <= ulMaxObjectNumber; iDevNum++)
@@ -350,8 +351,8 @@ NtUserEnumDisplayDevices(
     DISPLAY_DEVICEW dispdev;
     NTSTATUS Status;
 
-    TRACE("Enter NtUserEnumDisplayDevices(%wZ, %ld)\n",
-           pustrDevice, iDevNum);
+    TRACE("Enter NtUserEnumDisplayDevices(%wZ, %lu)\n",
+          pustrDevice, iDevNum);
 
     dispdev.cb = sizeof(dispdev);
 
@@ -442,7 +443,7 @@ UserEnumCurrentDisplaySettings(
     {
         /* No device found */
         ERR("No PDEV found!\n");
-        return STATUS_UNSUCCESSFUL;
+        return STATUS_INVALID_PARAMETER_1;
     }
 
     *ppdm = ppdev->pdmwDev;
@@ -462,22 +463,27 @@ UserEnumDisplaySettings(
     PGRAPHICS_DEVICE pGraphicsDevice;
     PDEVMODEENTRY pdmentry;
     ULONG i, iFoundMode;
+    PPDEVOBJ ppdev;
 
-    TRACE("Enter UserEnumDisplaySettings('%wZ', %ld)\n",
-            pustrDevice, iModeNum);
+    TRACE("Enter UserEnumDisplaySettings('%wZ', %lu)\n",
+          pustrDevice, iModeNum);
 
     /* Ask GDI for the GRAPHICS_DEVICE */
     pGraphicsDevice = EngpFindGraphicsDevice(pustrDevice, 0, 0);
+    ppdev = EngpGetPDEV(pustrDevice);
 
-    if (!pGraphicsDevice)
+    if (!pGraphicsDevice || !ppdev)
     {
         /* No device found */
         ERR("No device found!\n");
-        return STATUS_UNSUCCESSFUL;
+        return STATUS_INVALID_PARAMETER_1;
     }
 
-    if (iModeNum >= pGraphicsDevice->cDevModes)
-        return STATUS_NO_MORE_ENTRIES;
+    /* let's politely ask the driver for an updated mode list,
+       just in case there's something new in there (vbox) */
+
+    PDEVOBJ_vRefreshModeList(ppdev);
+    PDEVOBJ_vRelease(ppdev);
 
     iFoundMode = 0;
     for (i = 0; i < pGraphicsDevice->cDevModes; i++)
@@ -503,7 +509,7 @@ UserEnumDisplaySettings(
     }
 
     /* Nothing was found */
-    return STATUS_INVALID_PARAMETER;
+    return STATUS_INVALID_PARAMETER_2;
 }
 
 NTSTATUS
@@ -568,8 +574,28 @@ NtUserEnumDisplaySettings(
     ULONG cbSize, cbExtra;
     DEVMODEW dmReg, *pdm;
 
-    TRACE("Enter NtUserEnumDisplaySettings(%wZ, %ld, %p, 0x%lx)\n",
-            pustrDevice, iModeNum, lpDevMode, dwFlags);
+    TRACE("Enter NtUserEnumDisplaySettings(%wZ, %lu, %p, 0x%lx)\n",
+          pustrDevice, iModeNum, lpDevMode, dwFlags);
+
+    _SEH2_TRY
+    {
+        ProbeForRead(lpDevMode, sizeof(DEVMODEW), sizeof(UCHAR));
+
+        cbSize = lpDevMode->dmSize;
+        cbExtra = lpDevMode->dmDriverExtra;
+
+        ProbeForWrite(lpDevMode, cbSize + cbExtra, sizeof(UCHAR));
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    if (lpDevMode->dmSize != sizeof(DEVMODEW))
+    {
+        return STATUS_BUFFER_TOO_SMALL;
+    }
 
     if (pustrDevice)
     {
@@ -579,20 +605,24 @@ NtUserEnumDisplaySettings(
         _SEH2_TRY
         {
             /* Probe the UNICODE_STRING and the buffer */
-            ProbeForRead(pustrDevice, sizeof(UNICODE_STRING), 1);
-            ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, 1);
+            ProbeForReadUnicodeString(pustrDevice);
+
+            if (!pustrDevice->Length || !pustrDevice->Buffer)
+                ExRaiseStatus(STATUS_NO_MEMORY);
+
+            ProbeForRead(pustrDevice->Buffer, pustrDevice->Length, sizeof(UCHAR));
 
             /* Copy the string */
             RtlCopyUnicodeString(&ustrDevice, pustrDevice);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
-            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            _SEH2_YIELD(return STATUS_INVALID_PARAMETER_1);
         }
-        _SEH2_END
+        _SEH2_END;
 
         pustrDevice = &ustrDevice;
-   }
+    }
 
     /* Acquire global USER lock */
     UserEnterShared();
@@ -602,6 +632,7 @@ NtUserEnumDisplaySettings(
         /* Get the registry settings */
         Status = UserEnumRegistryDisplaySettings(pustrDevice, &dmReg);
         pdm = &dmReg;
+        pdm->dmSize = sizeof(DEVMODEW);
     }
     else if (iModeNum == ENUM_CURRENT_SETTINGS)
     {
@@ -623,11 +654,6 @@ NtUserEnumDisplaySettings(
         /* Copy some information back */
         _SEH2_TRY
         {
-            ProbeForRead(lpDevMode, sizeof(DEVMODEW), 1);
-            cbSize = lpDevMode->dmSize;
-            cbExtra = lpDevMode->dmDriverExtra;
-
-            ProbeForWrite(lpDevMode, cbSize + cbExtra, 1);
             /* Output what we got */
             RtlCopyMemory(lpDevMode, pdm, min(cbSize, pdm->dmSize));
 
@@ -648,13 +674,21 @@ NtUserEnumDisplaySettings(
 
     return Status;
 }
+VOID
+UserUpdateFullscreen(
+    DWORD flags)
+{
+    if (flags & CDS_FULLSCREEN)
+        gpFullscreen = gptiCurrent->ppi;
+    else
+        gpFullscreen = NULL;
+}
 
 LONG
 APIENTRY
 UserChangeDisplaySettings(
    PUNICODE_STRING pustrDevice,
    LPDEVMODEW pdm,
-   HWND hwnd,
    DWORD flags,
    LPVOID lParam)
 {
@@ -663,6 +697,7 @@ UserChangeDisplaySettings(
     HKEY hkey;
     NTSTATUS Status;
     PPDEVOBJ ppdev;
+    WORD OrigBC;
     //PDESKTOP pdesk;
 
     /* If no DEVMODE is given, use registry settings */
@@ -677,9 +712,16 @@ UserChangeDisplaySettings(
         }
     }
     else if (pdm->dmSize < FIELD_OFFSET(DEVMODEW, dmFields))
-        return DISP_CHANGE_BADMODE; /* This is what winXP SP3 returns */
+    {
+        return DISP_CHANGE_BADMODE; /* This is what WinXP SP3 returns */
+    }
     else
+    {
         dm = *pdm;
+    }
+
+    /* Save original bit count */
+    OrigBC = gpsi->BitCount;
 
     /* Check params */
     if ((dm.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT))
@@ -697,13 +739,13 @@ UserChangeDisplaySettings(
     }
 
     /* Fixup values */
-    if(dm.dmBitsPerPel == 0 || !(dm.dmFields & DM_BITSPERPEL))
+    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))
+    if ((dm.dmFields & DM_DISPLAYFREQUENCY) && (dm.dmDisplayFrequency == 0))
         dm.dmDisplayFrequency = ppdev->pdmwDev->dmDisplayFrequency;
 
     /* Look for the requested DEVMODE */
@@ -741,18 +783,12 @@ UserChangeDisplaySettings(
         }
     }
 
-    /* Check if DEVMODE matches the current mode */
-    if (pdm == ppdev->pdmwDev && !(flags & CDS_RESET))
-    {
-        ERR("DEVMODE matches, nothing to do\n");
-        goto leave;
-    }
-
     /* Shall we apply the settings? */
     if (!(flags & CDS_NORESET))
     {
         ULONG ulResult;
         PVOID pvOldCursor;
+        TEXTMETRICW tmw;
 
         /* Remove mouse pointer */
         pvOldCursor = UserSetCursor(NULL, TRUE);
@@ -761,7 +797,8 @@ UserChangeDisplaySettings(
         ulResult = PDEVOBJ_bSwitchMode(ppdev, pdm);
 
         /* Restore mouse pointer, no hooks called */
-        UserSetCursor(pvOldCursor, TRUE);
+        pvOldCursor = UserSetCursor(pvOldCursor, TRUE);
+        ASSERT(pvOldCursor == NULL);
 
         /* Check for failure */
         if (!ulResult)
@@ -773,14 +810,29 @@ UserChangeDisplaySettings(
             goto leave;
         }
 
+        UserUpdateFullscreen(flags);
+
         /* Update the system metrics */
         InitMetrics();
 
-        //IntvGetDeviceCaps(&PrimarySurface, &GdiHandleTable->DevCaps);
-
         /* Set new size of the monitor */
         UserUpdateMonitorSize((HDEV)ppdev);
 
+        /* Update the SERVERINFO */
+        gpsi->dmLogPixels = ppdev->gdiinfo.ulLogPixelsY;
+        gpsi->Planes      = ppdev->gdiinfo.cPlanes;
+        gpsi->BitsPixel   = ppdev->gdiinfo.cBitsPixel;
+        gpsi->BitCount    = gpsi->Planes * gpsi->BitsPixel;
+        if (ppdev->gdiinfo.flRaster & RC_PALETTE)
+        {
+            gpsi->PUSIFlags |= PUSIF_PALETTEDISPLAY;
+        }
+        else
+            gpsi->PUSIFlags &= ~PUSIF_PALETTEDISPLAY;
+        // Font is realized and this dc was previously set to internal DC_ATTR.
+        gpsi->cxSysFontChar = IntGetCharDimensions(hSystemBM, &tmw, (DWORD*)&gpsi->cySysFontChar);
+        gpsi->tmSysFont     = tmw;
+
         /* Remove all cursor clipping */
         UserClipCursor(NULL);
 
@@ -788,13 +840,21 @@ UserChangeDisplaySettings(
         //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);
+        UserSendNotifyMessage(HWND_BROADCAST,
+                              WM_DISPLAYCHANGE,
+                              gpsi->BitCount,
+                              MAKELONG(gpsi->aiSysMet[SM_CXSCREEN], gpsi->aiSysMet[SM_CYSCREEN]));
+
+        ERR("BitCount New %d Orig %d ChkNew %d\n",gpsi->BitCount,OrigBC,ppdev->gdiinfo.cBitsPixel);
+
+        /* Not full screen and different bit count, send messages */
+        if (!(flags & CDS_FULLSCREEN) &&
+            gpsi->BitCount != OrigBC)
+        {
+            ERR("Detect settings changed.\n");
+            UserSendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
+            UserSendNotifyMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
+        }
 
         //co_IntShowDesktop(pdesk, ppdev->gdiinfo.ulHorzRes, ppdev->gdiinfo.ulVertRes);
 
@@ -808,12 +868,23 @@ leave:
     return lResult;
 }
 
+VOID
+UserDisplayNotifyShutdown(
+    PPROCESSINFO ppiCurrent)
+{
+    if (ppiCurrent == gpFullscreen)
+    {
+        UserChangeDisplaySettings(NULL, NULL, 0, NULL);
+        if (gpFullscreen)
+            ERR("Failed to restore display mode!\n");
+    }
+}
+
 LONG
 APIENTRY
 NtUserChangeDisplaySettings(
     PUNICODE_STRING pustrDevice,
     LPDEVMODEW lpDevMode,
-    HWND hwnd,
     DWORD dwflags,
     LPVOID lParam)
 {
@@ -823,8 +894,7 @@ NtUserChangeDisplaySettings(
     LONG lRet;
 
     /* Check arguments */
-    if ((dwflags != CDS_VIDEOPARAMETERS && lParam != NULL) ||
-        (hwnd != NULL))
+    if ((dwflags != CDS_VIDEOPARAMETERS) && (lParam != NULL))
     {
         EngSetLastError(ERROR_INVALID_PARAMETER);
         return DISP_CHANGE_BADPARAM;
@@ -903,7 +973,7 @@ NtUserChangeDisplaySettings(
     UserEnterExclusive();
 
     /* Call internal function */
-    lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, hwnd, dwflags, NULL);
+    lRet = UserChangeDisplaySettings(pustrDevice, lpDevMode, dwflags, NULL);
 
     /* Release lock */
     UserLeave();