Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1867 lines
59 KiB

/****************************** Module Header ******************************\
* Module Name: fullscr.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* This module contains all the fullscreen code for Win32k.
*
* History:
* 12-Dec-1991 mikeke Created
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/***************************************************************************\
* We can only have one fullscreen window at a time so this information can
* be stored globally.
*
* We partially use busy waiting to set the state of the hardware. The
* problem is that while we are in the middle of a fullscreen switch, we
* leave the critical section, so someone else could come in and change the
* state of the fullscreen stuff. In order to keep the system from getting
* confused about the state of the device, we actually "post" the request.
*
* What we do with external requests for switching, is that we will do busy
* waiting on these state variables. So an app won't be able to request a
* fullscreen switch while one is under way. This is a way to make the
* system completely reentrant for state switches.
*
* The state variables themselves can only be touched while owning the
* critical section. We are guaranteed that we will not busy wait forever
* since the switch operations (although long) will eventually finish.
*
* 20-Mar-1996 andreva Created
\***************************************************************************/
#if DBG
LONG TraceFullscreenSwitch;
#endif
HANDLE ghSwitcher;
BOOL gfRedoFullScreenSwitch, gfGdiEnabled = TRUE;
POINT gptCursorFullScreen;
VOID SetVDMCursorBounds(LPRECT lprc);
VOID UserSetDelayedChangeBroadcastForAllDesktops(
PDESKTOP pCurrentDesktop)
{
PWINDOWSTATION pwinsta;
PDESKTOP pdesk;
/*
* Get a pointer to the windowstation so we can change display setting
* for all of its destops.
*/
if ((pwinsta = grpWinStaList) == NULL) {
RIPMSGF0(RIP_ERROR, "No interactive WindowStation");
return;
}
/*
* Walk all the desktops of the winstation and, for each of them, just
* set its delayed Broadcast indicator to TRUE so that next switch to
* that destop will force Display Settings change messages to be
* broadcasted to windows of that desktop.
*/
pdesk = pwinsta->rpdeskList;
while (pdesk != NULL) {
if (pdesk != pCurrentDesktop) {
pdesk->dwDTFlags |= DF_NEWDISPLAYSETTINGS;
}
pdesk = pdesk->rpdeskNext;
}
}
/***************************************************************************\
* FullScreenCleanup
*
* This is called during thread cleanup, we test to see if we died during a
* full screen switch and switch back to the GDI desktop if we did.
*
* NOTE:
* All the variables touched here are guaranteed to be touched under
* the CritSect.
*
* 12-Dec-1991 mikeke Created
\***************************************************************************/
VOID FullScreenCleanup(
VOID)
{
if (PsGetCurrentThreadId() == ghSwitcher) {
/*
* Correct the full screen state.
*/
if (gfGdiEnabled) {
TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Enabled\n"));
/*
* Gdi is enabled; since we are switching away from gdi the only
* thing we could have done so far is locking the screen so
* unlock it.
*/
CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
LockWindowUpdate2(NULL, TRUE);
} else {
/*
* GDI is not enabled. This means we were switching from a full
* screen to another fullscreen or back to GDI. Or we could have
* disabled gdi and sent a message to the new full screen which
* never got completed.
*
* In any case this probably means the fullscreen guy is gone so
* we will switch back to gdi.
*
* Delete any left over saved screen state stuff set the fullscreen
* to nothing and then send a message that will cause us to switch
* back to the gdi desktop.
*/
TL tlpwndT;
TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Disabled\n"));
Unlock(&gspwndFullScreen);
gbFullScreen = FULLSCREEN;
ThreadLock(grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN,
GDIFULLSCREEN,
(LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd));
ThreadUnlock(&tlpwndT);
}
ghSwitcher = NULL;
gfRedoFullScreenSwitch = FALSE;
}
}
/***************************************************************************\
* xxxMakeWindowForegroundWithState
*
* Syncs the screen graphics mode with the mode of the specified (foreground)
* window.
*
* We make sure only one thread is going through this code by checking
* ghSwitcher. If ghSwitcher is non-NULL someone is already in this code.
*
* 12-Dec-1991 mikeke Created
\***************************************************************************/
BOOL xxxMakeWindowForegroundWithState(
PWND pwnd,
BYTE NewState)
{
PWND pwndNewFG;
TL tlpwndNewFG;
TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState: Enter\n"));
TRACE_SWITCH(("\t \t pwnd = %08lx\n", pwnd));
TRACE_SWITCH(("\t \t NewState = %d\n", NewState));
CheckLock(pwnd);
UserAssert(IsWinEventNotifyDeferredOK());
/*
* If we should switch to a specific window save that window.
*/
if (pwnd != NULL) {
if (NewState == GDIFULLSCREEN) {
Lock(&gspwndShouldBeForeground, pwnd);
}
/*
* Change to the new state.
*/
SetFullScreen(pwnd, NewState);
if (NewState == FULLSCREEN &&
(gpqForeground == NULL || gpqForeground->spwndActive != pwnd)) {
SetFullScreen(pwnd, FULLSCREENMIN);
}
}
/*
* Since we leave the critical section during the switch, some other
* thread could come into this routine and request a switch. The global
* will be reset, and we will use the loop to perform the next switch.
*/
if (ghSwitcher != NULL) {
gfRedoFullScreenSwitch = TRUE;
TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState was posted: Exit\n"));
return TRUE;
}
UserAssert(!gfRedoFullScreenSwitch);
ghSwitcher = PsGetCurrentThreadId();
/*
* We loop, switching full screens until all states have stabilized
*/
while (TRUE) {
/*
* Figure out who should be foreground.
*/
gfRedoFullScreenSwitch = FALSE;
if (gspwndShouldBeForeground != NULL) {
pwndNewFG = gspwndShouldBeForeground;
Unlock(&gspwndShouldBeForeground);
} else {
if (gpqForeground != NULL && gpqForeground->spwndActive != NULL) {
pwndNewFG = gpqForeground->spwndActive;
if (GetFullScreen(pwndNewFG) == WINDOWED ||
GetFullScreen(pwndNewFG) == FULLSCREENMIN) {
pwndNewFG = PWNDDESKTOP(pwndNewFG);
}
} else {
/*
* No active window, switch to current desktop.
*/
pwndNewFG = grpdeskRitInput->pDeskInfo->spwnd;
}
}
/*
* We don't need to switch if the right window is already foreground.
*/
if (pwndNewFG == gspwndFullScreen) {
break;
}
ThreadLock(pwndNewFG, &tlpwndNewFG);
{
BYTE bStateNew = GetFullScreen(pwndNewFG);
TL tlpwndOldFG;
PWND pwndOldFG = gspwndFullScreen;
BYTE bStateOld = gbFullScreen;
ThreadLock(pwndOldFG, &tlpwndOldFG);
Lock(&gspwndFullScreen, pwndNewFG);
gbFullScreen = bStateNew;
UserAssert(!HMIsMarkDestroy(gspwndFullScreen));
/*
* If the old screen was GDIFULLSCREEN and we are switching to
* GDIFULLSCREEN then just repaint.
*
* BUG 231647: For remote sessions it can happen that pwndOldFG is
* NULL but the display is enabled therefore a call to
* DrvEnableMDEV would confuse the Drv* code. The way this happens
* is when gspwndFullScreen was the desktop window of a desktop
* that got destroyed after we switched away from it.
*/
if ((pwndOldFG != NULL || gbRemoteSession) &&
bStateOld == GDIFULLSCREEN &&
bStateNew == GDIFULLSCREEN) {
xxxRedrawWindow(pwndNewFG,
NULL,
NULL,
RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
RDW_ERASENOW);
ThreadUnlock(&tlpwndOldFG);
} else {
/*
* Tell old 'foreground' window it is losing control of the
* screen.
*/
if (pwndOldFG != NULL) {
switch (bStateOld) {
case FULLSCREEN:
if (GetFullScreen(pwndOldFG) == FULLSCREEN) {
SetFullScreen(pwndOldFG, FULLSCREENMIN);
}
xxxSendMessage(pwndOldFG, WM_FULLSCREEN, FALSE, 0);
xxxCapture(GETPTI(pwndOldFG), NULL, FULLSCREEN_CAPTURE);
SetVDMCursorBounds(NULL);
break;
case GDIFULLSCREEN:
/*
* Lock out other windows from drawing while we are
* fullscreen.
*/
LockWindowUpdate2(pwndOldFG, TRUE);
SET_PUDF(PUDF_LOCKFULLSCREEN);
UserAssert(gfGdiEnabled == TRUE);
/*
* We are about to switch to FULLSCREEN mode.
*
* IsRemoteConnection() == TRUE indicates that we
* are on a remote session. Switching to FULLSCREEN
* mode is not supported on remote sessions.
*
* gfSwitchInProgress flag means that we are
* currently in process of disconnecting the
* session, so even if it is not remote right now it
* is about to go remote. In these cases we must not
* switch to FULLSCREEN mode.
*/
if (IsRemoteConnection() || gfSwitchInProgress ||
!SafeDisableMDEV()) {
/*
* Restore the previous state before bailing.
*/
CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
LockWindowUpdate2(NULL, TRUE);
Lock(&gspwndFullScreen, pwndOldFG);
gbFullScreen = bStateOld;
ThreadUnlock(&tlpwndOldFG);
ThreadUnlock(&tlpwndNewFG);
ghSwitcher = NULL;
return FALSE;
}
gptCursorFullScreen = gpsi->ptCursor;
gfGdiEnabled = FALSE;
break;
default:
RIPMSG0(RIP_ERROR, "xxxMakeWindowForegroundWithState: bad screen state");
break;
}
}
ThreadUnlock(&tlpwndOldFG);
switch (bStateNew) {
case FULLSCREEN:
xxxCapture(GETPTI(pwndNewFG), pwndNewFG, FULLSCREEN_CAPTURE);
xxxSendMessage(pwndNewFG, WM_FULLSCREEN, TRUE, 0);
break;
case GDIFULLSCREEN:
if (ISTS() && pwndOldFG != NULL) {
UserAssert(gfGdiEnabled == FALSE);
}
SafeEnableMDEV();
gfGdiEnabled = TRUE;
/*
* Return the cursor to it's old state. Reset the screen
* saver mouse position or it'll go away by accident.
*/
gpqCursor = NULL;
gpcurPhysCurrent = NULL;
gpcurLogCurrent = NULL;
SetPointer(FALSE);
gptSSCursor = gptCursorFullScreen;
/*
* No need to DeferWinEventNotify() - we use only globals,
* then make an xxx call below.
*/
zzzInternalSetCursorPos(gptCursorFullScreen.x,
gptCursorFullScreen.y);
CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
LockWindowUpdate2(NULL, TRUE);
xxxRedrawWindow(pwndNewFG,
NULL,
NULL,
RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE |
RDW_ERASENOW);
break;
default:
RIPMSG0(RIP_ERROR, "xxxMakeWindowForegroundWithState: bad screen state");
break;
}
}
}
ThreadUnlock(&tlpwndNewFG);
if (!gfRedoFullScreenSwitch) {
break;
}
}
TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState: Exit\n"));
ghSwitcher = NULL;
return TRUE;
}
/***************************************************************************\
* MonitorFromHdev
\***************************************************************************/
PMONITOR MonitorFromHdev(
HANDLE hdev)
{
PMONITOR pMonitor;
for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor != NULL;
pMonitor = pMonitor->pMonitorNext) {
if (pMonitor->hDev == hdev) {
return pMonitor;
}
}
return NULL;
}
/***************************************************************************\
* HdevFromMonitor
\***************************************************************************/
ULONG HdevFromMonitor(
PMONITOR pMonitor)
{
PMDEV pmdev = gpDispInfo->pmdev;
ULONG i;
for (i = 0; i < pmdev->chdev; i++) {
if (pmdev->Dev[i].hdev == pMonitor->hDev) {
return i;
}
}
return -1;
}
/***************************************************************************\
* CreateMonitor
\***************************************************************************/
PMONITOR CreateMonitor(
VOID)
{
PMONITOR pMonitor;
pMonitor = (PMONITOR)HMAllocObject(NULL, NULL, TYPE_MONITOR, sizeof(MONITOR));
if (pMonitor != NULL) {
pMonitor->rcMonitor.left = 0;
pMonitor->rcMonitor.top = 0;
pMonitor->rcMonitor.right = 0;
pMonitor->rcMonitor.bottom = 0;
pMonitor->rcWork.left = 0;
pMonitor->rcWork.top = 0;
pMonitor->rcWork.right = 0;
pMonitor->rcWork.bottom = 0;
} else {
RIPERR0(ERROR_NOT_ENOUGH_MEMORY, RIP_WARNING, "CreateMonitor failed");
}
return pMonitor;
}
/***************************************************************************\
* CreateCachedMonitor
\***************************************************************************/
PMONITOR CreateCachedMonitor(
VOID)
{
if (gpMonitorCached == NULL) {
gpMonitorCached = CreateMonitor();
}
return gpMonitorCached;
}
/***************************************************************************\
* SetMonitorData
\***************************************************************************/
PMONITOR SetMonitorData(
PMONITOR pMonitor,
ULONG iDev)
{
PMDEV pmdev = gpDispInfo->pmdev;
HDEV hdev = pmdev->Dev[iDev].hdev;
BOOL fVisible = TRUE;
BOOL fPrimary = FALSE;
HDC hdcTmp;
UserAssert(iDev < pmdev->chdev);
if (hdcTmp = GreCreateDisplayDC(hdev, DCTYPE_DIRECT, FALSE)) {
if (GreGetDeviceCaps(hdcTmp, CAPS1) & C1_MIRROR_DEVICE) {
fVisible = FALSE;
}
GreDeleteDC(hdcTmp);
}
if (fVisible && (pmdev->Dev[iDev].rect.top == 0) &&
(pmdev->Dev[iDev].rect.left == 0)) {
fPrimary = TRUE;
}
if (pMonitor == NULL) {
if (fPrimary) {
UserAssert(gpMonitorCached != NULL);
pMonitor = gpMonitorCached;
gpMonitorCached = NULL;
} else {
pMonitor = CreateMonitor();
}
}
if (pMonitor == NULL) {
return NULL;
}
SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_VISIBLE, fVisible);
/*
* When the monitor rect is changing, size the work area so the same
* amount as before is clipped off each edge.
*/
if (!EqualRect(&pMonitor->rcMonitor, &pmdev->Dev[iDev].rect)) {
pMonitor->rcWork.left = pmdev->Dev[iDev].rect.left -
(pMonitor->rcMonitor.left - pMonitor->rcWork.left);
pMonitor->rcWork.top = pmdev->Dev[iDev].rect.top -
(pMonitor->rcMonitor.top - pMonitor->rcWork.top);
pMonitor->rcWork.right = pmdev->Dev[iDev].rect.right -
(pMonitor->rcMonitor.right - pMonitor->rcWork.right);
pMonitor->rcWork.bottom = pmdev->Dev[iDev].rect.bottom -
(pMonitor->rcMonitor.bottom - pMonitor->rcWork.bottom);
}
pMonitor->rcMonitor = pmdev->Dev[iDev].rect;
pMonitor->hDev = hdev;
/*
* Make sure that the work area is inside the monitor's bounds.
*/
if (pMonitor->rcWork.right < pMonitor->rcWork.left) {
pMonitor->rcWork.right = pMonitor->rcWork.left;
}
if (pMonitor->rcWork.bottom < pMonitor->rcWork.top) {
pMonitor->rcWork.bottom = pMonitor->rcWork.top;
}
if (!IntersectRect(&pMonitor->rcWork, &pMonitor->rcWork, &pMonitor->rcMonitor)) {
pMonitor->rcWork = pMonitor->rcMonitor;
}
if (fPrimary) {
gpDispInfo->pMonitorPrimary = pMonitor;
}
return pMonitor;
}
/***************************************************************************\
*
* Is this still TRUE ?
*
* When a window becomes FULLSCREEN, it is minimized and
* treated like any other minimized window. Whenever the
* minimized window is restored, by double clicking, menu
* or keyboard, it remains minimized and the application
* is given control of the screen device.
*
* 12-Dec-1991 mikeke Created
\***************************************************************************/
DWORD gdwMonitorBusy;
/***************************************************************************\
* xxxUpdateUserScreen
*
* Updates USER information associated with the screen
*
* History:
* 28-Sep-1996 adams Created.
\***************************************************************************/
BOOL xxxUpdateUserScreen(
BOOL fInitializeTime)
{
PMDEV pmdev = gpDispInfo->pmdev;
ULONG i;
PMONITOR pMonitor;
TEXTMETRIC tm;
PWINDOWSTATION pwinsta;
PDESKTOP pdesk;
HRGN hrgn;
BOOL fPaletteDisplay;
RECT rc;
PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
PMONITOR *ppMonitorLast = &gpDispInfo->pMonitorFirst;
TRACE_INIT(("xxxUpdateUserScreen\n"));
UserAssert(gpDispInfo->hdcScreen);
UserAssert(gpMonitorCached != NULL);
CheckCritIn();
if (!fInitializeTime) {
/*
* Wait until the unprotected code goes through the monitor reference.
* We skip this if it's initializing the session to avoid leaving the
* critical section.
*/
while (InterlockedCompareExchange(&gdwMonitorBusy, TRUE, FALSE) != FALSE) {
UserAssert(gdwMonitorBusy == TRUE);
RIPMSGF0(RIP_VERBOSE, "Monitor is busy referenced by the mouse input.");
LeaveCrit();
UserSleep(1);
EnterCrit();
}
}
/*
* Keep HMONITOR for the hdev that is the same. Delete the monitors that
* weren't found in the new hdev list.
*/
while (pMonitorNext != NULL) {
pMonitor = pMonitorNext;
pMonitorNext = pMonitor->pMonitorNext;
if ((i = HdevFromMonitor(pMonitor)) == -1) {
DestroyMonitor(pMonitor);
} else {
SetMonitorData(pMonitor, i);
ppMonitorLast = &pMonitor->pMonitorNext;
}
}
/*
* Create monitors for the hdevs that aren't yet on the monitor list.
*/
for (i = 0; i < pmdev->chdev; i++) {
if ((pMonitor = MonitorFromHdev(pmdev->Dev[i].hdev)) == NULL) {
/*
* Try to create a new monitor.
*/
pMonitor = SetMonitorData(NULL, i);
if (pMonitor != NULL) {
*ppMonitorLast = pMonitor;
ppMonitorLast = &pMonitor->pMonitorNext;
}
}
}
UserAssert(gpDispInfo->pMonitorFirst != NULL);
UserAssert(gpDispInfo->pMonitorPrimary != NULL);
/*
* For now, all monitors have the same display format.
*/
SYSMET(SAMEDISPLAYFORMAT) = (pmdev->ulFlags & MDEV_MISMATCH_COLORDEPTH) ? FALSE : TRUE;
fPaletteDisplay = GreGetDeviceCaps(gpDispInfo->hdcScreen, RASTERCAPS) & RC_PALETTE;
gpDispInfo->fAnyPalette = !!fPaletteDisplay;
/*
* Determine the coordinates of the virtual desktop. Compute cMonitors as
* the number of visible monitors.
*/
SetRectEmpty(&rc);
gpDispInfo->cMonitors = 0;
for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor; pMonitor = pMonitor->pMonitorNext) {
/*
* Only visible monitors contribute to the desktop area.
*/
if (pMonitor->dwMONFlags & MONF_VISIBLE) {
rc.left = min(rc.left, pMonitor->rcMonitor.left);
rc.top = min(rc.top, pMonitor->rcMonitor.top);
rc.right = max(rc.right, pMonitor->rcMonitor.right);
rc.bottom = max(rc.bottom, pMonitor->rcMonitor.bottom);
gpDispInfo->cMonitors++;
}
if (SYSMET(SAMEDISPLAYFORMAT)) {
SET_OR_CLEAR_FLAG(pMonitor->dwMONFlags, MONF_PALETTEDISPLAY, fPaletteDisplay);
} else {
if (GreIsPaletteDisplay(pMonitor->hDev)) {
pMonitor->dwMONFlags |= MONF_PALETTEDISPLAY;
gpDispInfo->fAnyPalette = TRUE;
}
}
#ifdef SUBPIXEL_MOUSE
/*
* The new mouse's acceleration curves depend on the screen resolution,
* so we rebuild the curves here.
*/
BuildMouseAccelerationCurve(pMonitor);
#endif // SUBPIXEL_MOUSE
}
UserAssert(gpDispInfo->pMonitorPrimary != NULL);
gpDispInfo->rcScreen = rc;
if (!fInitializeTime) {
/*
* Release the monitor busy lock, so that the
* mouse cursor update can resume.
*/
UserAssert(gdwMonitorBusy == TRUE);
InterlockedExchange(&gdwMonitorBusy, FALSE);
}
/*
* Notify the TS service if one coordinate of the virtual screen changed
* and we're doing console shadow.
*/
if (gfRemotingConsole &&
gpConsoleShadowDisplayChangeEvent &&
!((SYSMET(XVIRTUALSCREEN) == gpDispInfo->rcScreen.left) &&
(SYSMET(YVIRTUALSCREEN) == gpDispInfo->rcScreen.top) &&
(SYSMET(CXVIRTUALSCREEN) == gpDispInfo->rcScreen.right - gpDispInfo->rcScreen.left) &&
(SYSMET(CYVIRTUALSCREEN) == gpDispInfo->rcScreen.bottom - gpDispInfo->rcScreen.top))) {
KeSetEvent(gpConsoleShadowDisplayChangeEvent, EVENT_INCREMENT, FALSE);
}
/*
* Update system metrics
*/
SYSMET(CXSCREEN) = gpDispInfo->pMonitorPrimary->rcMonitor.right;
SYSMET(CYSCREEN) = gpDispInfo->pMonitorPrimary->rcMonitor.bottom;
SYSMET(XVIRTUALSCREEN) = gpDispInfo->rcScreen.left;
SYSMET(YVIRTUALSCREEN) = gpDispInfo->rcScreen.top;
SYSMET(CXVIRTUALSCREEN) = gpDispInfo->rcScreen.right - gpDispInfo->rcScreen.left;
SYSMET(CYVIRTUALSCREEN) = gpDispInfo->rcScreen.bottom - gpDispInfo->rcScreen.top;
SYSMET(CXMAXTRACK) = SYSMET(CXVIRTUALSCREEN) + (2 * (SYSMET(CXSIZEFRAME) + SYSMET(CXEDGE)));
SYSMET(CYMAXTRACK) = SYSMET(CYVIRTUALSCREEN) + (2 * (SYSMET(CYSIZEFRAME) + SYSMET(CYEDGE)));
SYSMET(CMONITORS) = gpDispInfo->cMonitors;
/*
* Bug 281219: Flush out the mouse move points if a mode change occured.
*/
RtlZeroMemory(gaptMouse, MAX_MOUSEPOINTS * sizeof(MOUSEMOVEPOINT));
SetDesktopMetrics();
gpDispInfo->dmLogPixels = (WORD)GreGetDeviceCaps(gpDispInfo->hdcScreen, LOGPIXELSY);
UserAssert(gpDispInfo->dmLogPixels != 0);
/*
* Get per-monitor or sum of monitor information, including:
* The desktop region.
* The region of each monitor.
* Min bit counts - Not for NT SP2.
* Same color format - Not for NT SP2.
*/
SetOrCreateRectRgnIndirectPublic(&gpDispInfo->hrgnScreen, PZERO(RECT));
if (gpDispInfo->hrgnScreen) {
int iRgn = RGN_ERROR;
for (pMonitor = gpDispInfo->pMonitorFirst;
pMonitor;
pMonitor = pMonitor->pMonitorNext) {
/*
* We want to set up hrgnMonitor for all monitors, visible or
* not.
*/
if (SetOrCreateRectRgnIndirectPublic(&pMonitor->hrgnMonitor,
&pMonitor->rcMonitor)) {
/*
* But we want only visible monitors to contribute to
* hrgnScreen.
*/
if (pMonitor->dwMONFlags & MONF_VISIBLE) {
iRgn = UnionRgn(gpDispInfo->hrgnScreen,
gpDispInfo->hrgnScreen,
pMonitor->hrgnMonitor);
}
}
}
gpDispInfo->fDesktopIsRect = (iRgn == SIMPLEREGION);
}
/*
* Reset the window region of desktop windows.
*/
hrgn = (gpDispInfo->fDesktopIsRect) ? NULL : gpDispInfo->hrgnScreen;
for (pwinsta = grpWinStaList; pwinsta; pwinsta = pwinsta->rpwinstaNext) {
for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
if (pdesk->pDispInfo == gpDispInfo) {
pdesk->pDeskInfo->spwnd->hrgnClip = hrgn;
}
}
}
/*
* Updated information stored in gpsi.
*/
gpsi->Planes = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, PLANES);
gpsi->BitsPixel = (BYTE)GreGetDeviceCaps(gpDispInfo->hdcScreen, BITSPIXEL);
gpsi->BitCount = gpsi->Planes * gpsi->BitsPixel;
gpDispInfo->BitCountMax = gpsi->BitCount;
SET_OR_CLEAR_PUSIF(PUSIF_PALETTEDISPLAY, fPaletteDisplay);
gpsi->dmLogPixels = gpDispInfo->dmLogPixels;
gpsi->rcScreen = gpDispInfo->rcScreen;
gpsi->cxSysFontChar = GetCharDimensions(HDCBITS(), &tm, &gpsi->cySysFontChar);
gpsi->tmSysFont = tm;
EnforceColorDependentSettings();
VerifyVisibleMonitorCount();
return TRUE;
}
/**************************************************************************\
* InitUserScreen
*
* Initializes user variables at startup.
*
* The caller of this function needs to handle failures. If this is called as
* part of the interactive console and it fails, USER will currently bugcheck.
* If this is called as part of RemoteConnect() for Terminal Server, the
* resources will be cleaned up in CleanupGDI() as part of normal thread
* cleanup.
*
* 12-Jan-1994 andreva Created
* 23-Jan-1995 ChrisWil ChangeDisplaySettings work.
\**************************************************************************/
BOOL InitUserScreen(
VOID)
{
int i;
TL tlName;
PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
BOOL fSuccess = TRUE;
TRACE_INIT(("UserInit: Initialize Screen\n"));
/*
* Create screen and memory dcs.
*/
gpDispInfo->hdcScreen = GreCreateDisplayDC(gpDispInfo->hDev, DCTYPE_DIRECT, FALSE);
if (gpDispInfo->hdcScreen == NULL) {
RIPMSG0(RIP_WARNING, "Fail to create gpDispInfo->hdcScreen");
fSuccess = FALSE;
goto Exit;
}
GreSelectFont(gpDispInfo->hdcScreen, GreGetStockObject(SYSTEM_FONT));
GreSetDCOwner(gpDispInfo->hdcScreen, OBJECT_OWNER_PUBLIC);
HDCBITS() = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
if (HDCBITS() == NULL) {
RIPMSG0(RIP_WARNING, "Fail to create HDCBITS()");
fSuccess = FALSE;
goto Exit;
}
GreSelectFont(HDCBITS(), GreGetStockObject(SYSTEM_FONT));
GreSetDCOwner(HDCBITS(), OBJECT_OWNER_PUBLIC);
ghdcMem = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
fSuccess &= !!ghdcMem;
ghdcMem2 = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
fSuccess &= !!ghdcMem2;
if (!fSuccess) {
RIPMSG0(RIP_WARNING, "Fail to create ghdcMem or ghdcMem2");
goto Exit;
}
GreSetDCOwner(ghdcMem, OBJECT_OWNER_PUBLIC);
GreSetDCOwner(ghdcMem2, OBJECT_OWNER_PUBLIC);
if (CreateCachedMonitor() == NULL) {
fSuccess = FALSE;
goto Exit;
}
/*
* N.b. although it's xxx, this function does not
* leave the critical section if fInitializeTime is TRUE.
*/
BEGINATOMICCHECK();
if (!xxxUpdateUserScreen(TRUE)) {
RIPMSG0(RIP_WARNING, "xxxUpdateUserScreen failed");
fSuccess = FALSE;
goto Exit;
}
ENDATOMICCHECK();
/*
* Do some initialization so we create the system colors.
*/
/*
* Set the window sizing border width to something reasonable.
*/
gpsi->gclBorder = 1;
/*
* Init InternalInvalidate globals
*/
ghrgnInv0 = CreateEmptyRgnPublic(); // For InternalInvalidate()
fSuccess &= !!ghrgnInv0;
ghrgnInv1 = CreateEmptyRgnPublic(); // For InternalInvalidate()
fSuccess &= !!ghrgnInv1;
ghrgnInv2 = CreateEmptyRgnPublic(); // For InternalInvalidate()
fSuccess &= !!ghrgnInv2;
/*
* Initialize SPB globals
*/
ghrgnSPB1 = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnSPB1;
ghrgnSPB2 = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnSPB2;
ghrgnSCR = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnSCR;
/*
* Initialize ScrollWindow/ScrollDC globals
*/
ghrgnSW = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnSW;
ghrgnScrl1 = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrl1;
ghrgnScrl2 = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrl2;
ghrgnScrlVis = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrlVis;
ghrgnScrlSrc = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrlSrc;
ghrgnScrlDst = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrlDst;
ghrgnScrlValid = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnScrlValid;
/*
* Initialize SetWindowPos()
*/
ghrgnInvalidSum = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnInvalidSum;
ghrgnVisNew = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnVisNew;
ghrgnSWP1 = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnSWP1;
ghrgnValid = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnValid;
ghrgnValidSum = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnValidSum;
ghrgnInvalid = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnInvalid;
/*
* Initialize DC cache
*/
ghrgnGDC = CreateEmptyRgnPublic();
fSuccess &= !!ghrgnGDC;
for (i = 0; i < DCE_SIZE_CACHEINIT; i++) {
fSuccess &= !!CreateCacheDC(NULL, DCX_INVALID | DCX_CACHE, NULL);
}
if (!fSuccess) {
RIPMSG0(RIP_WARNING, "CreateCacheDC failed");
goto Exit;
}
/*
* Let engine know that the display must be secure.
*/
GreMarkDCUnreadable(gpDispInfo->hdcScreen);
/*
* LATER mikeke - if ghfontsys is changed anywhere but here
* we need to fix SetNCFont()
*/
ghFontSys = (HFONT)GreGetStockObject(SYSTEM_FONT);
#if DBG
SYSMET(DEBUG) = TRUE;
#else
SYSMET(DEBUG) = FALSE;
#endif
SYSMET(CLEANBOOT) = **((PULONG *)&InitSafeBootMode);
SYSMET(SLOWMACHINE) = 0;
/*
* Initialize system colors from registry.
*/
xxxODI_ColorInit(pProfileUserName);
/*
* Paint the screen background.
*/
FillRect(gpDispInfo->hdcScreen, &gpDispInfo->rcScreen, SYSHBR(DESKTOP));
UserAssert(fSuccess);
Exit:
FreeProfileUserName(pProfileUserName, &tlName);
return fSuccess;
}
/***************************************************************************\
* xxxResetSharedDesktops
*
* Resets the attributes for other desktops which share the DISPINFO that
* was just changed. We need to resize all visrgns of the other desktops
* so that clipping is allright.
*
* NOTE: For now, we have to change all the desktop even though we keep
* track of the devmode on a per desktop basis, because we can switch
* back to a desktop that has a different resolution and paint it before
* we can change the resolution again.
*
* There is also an issue with CDS_FULLSCREEN where we currently lose track
* of whether or not the desktop settings need to be reset or not. [andreva]
*
* 19-Feb-1996 ChrisWil Created.
\***************************************************************************/
VOID ResetSharedDesktops(
PDISPLAYINFO pDIChanged,
PDESKTOP pdeskChanged)
{
PWINDOWSTATION pwinsta = _GetProcessWindowStation(NULL);
PDESKTOP pdesk;
HRGN hrgn;
POINT pt;
PRECT prc;
UserAssert(IsWinEventNotifyDeferredOK());
/*
* If this is CSRSS doing the dynamic resolution change then use
* WinSta0 since the process windowstation is NULL for CSRSS.
*/
if ((IsRemoteConnection()) && pwinsta == NULL && PsGetCurrentProcess() == gpepCSRSS) {
pwinsta = grpWinStaList;
}
if (pwinsta == NULL) {
if (PtiCurrent()->TIF_flags & (TIF_CSRSSTHREAD|TIF_SYSTEMTHREAD)) {
pwinsta = grpdeskRitInput->rpwinstaParent;
} else {
TRACE_SWITCH(("ResetSharedDesktops - NULL window station !\n"));
return;
}
}
for (pdesk = pwinsta->rpdeskList; pdesk; pdesk = pdesk->rpdeskNext) {
/*
* Make sure this is a shared DISPINFO.
*/
if (pdesk->pDispInfo == pDIChanged) {
#if 0
/*
* This is the preferable method to set the desktop-window.
* However, this causes synchronization problems where we
* leave the critical-section allowing other apps to call
* ChangeDisplaySettings() and thus mucking up the works.
*
* By calculating the vis-rgn ourselves, we can assure that
* the clipping is current for the desktop even when we leave
* the section.
*/
{
TL tlpwnd;
ThreadLockAlways(pdesk->pDeskInfo->spwnd, &tlpwnd);
xxxSetWindowPos(pdesk->pDeskInfo->spwnd,
PWND_TOP,
pDIChanged->rcScreen.left,
pDIChanged->rcScreen.top,
pDIChanged->rcScreen.right - pDIChanged->rcScreen.left,
pDIChanged->rcScreen.bottom - pDIChanged->rcScreen.top,
SWP_NOZORDER | SWP_NOACTIVATE);
ThreadUnlock(&tlpwnd);
}
#else
CopyRect(&pdesk->pDeskInfo->spwnd->rcWindow, &pDIChanged->rcScreen);
CopyRect(&pdesk->pDeskInfo->spwnd->rcClient, &pDIChanged->rcScreen);
#endif
}
}
/*
* Recalc the desktop visrgn.
*/
hrgn = CreateEmptyRgn();
CalcVisRgn(&hrgn,
pdeskChanged->pDeskInfo->spwnd,
pdeskChanged->pDeskInfo->spwnd,
DCX_WINDOW);
GreSelectVisRgn(pDIChanged->hdcScreen, hrgn, SVR_DELETEOLD);
/*
* Invalidate all DCE's visrgns.
*/
zzzInvalidateDCCache(pdeskChanged->pDeskInfo->spwnd, 0);
/*
* Position mouse so that it is within the new visrgn, once we
* recalc it.
*/
if (grpdeskRitInput->pDispInfo == pDIChanged) {
prc = &pDIChanged->pMonitorPrimary->rcMonitor;
pt.x = (prc->right - prc->left) / 2;
pt.y = (prc->bottom - prc->top) / 2;
/*
* Remember new mouse pos. Makes sure we don't wake the screensaver.
*/
gptSSCursor = pt;
zzzInternalSetCursorPos(pt.x, pt.y);
}
}
/***************************************************************************\
* DestroyMonitorDCs
*
* 03/03/1998 vadimg created
\***************************************************************************/
VOID DestroyMonitorDCs(
VOID)
{
PDCE pdce;
PDCE *ppdce;
/*
* Scan the DC cache to find any monitor DC's that need to be destroyed.
*/
for (ppdce = &gpDispInfo->pdceFirst; *ppdce != NULL;) {
pdce = *ppdce;
if (pdce->pMonitor != NULL) {
DestroyCacheDC(ppdce, pdce->hdc);
}
/*
* Step to the next DC. If the DC was deleted, there is no need to
* calculate address of the next entry.
*/
if (pdce == *ppdce) {
ppdce = &pdce->pdceNext;
}
}
}
/***************************************************************************\
* ResetSystemColors
*
* Reset all system colors to make sure magic colors are reset and
* solid system colors are indeed solid after a mode change.
\***************************************************************************/
VOID ResetSystemColors(
VOID)
{
INT i, colorIndex[COLOR_MAX];
COLORREF colorValue[COLOR_MAX];
for (i = 0; i < COLOR_MAX; i++) {
colorIndex[i] = i;
colorValue[i] = gpsi->argbSystemUnmatched[i];
}
BEGINATOMICCHECK();
xxxSetSysColors(NULL,
i,
colorIndex,
colorValue,
SSCF_FORCESOLIDCOLOR | SSCF_SETMAGICCOLORS);
ENDATOMICCHECK();
}
/***************************************************************************\
* xxxResetDisplayDevice
*
* Resets the user-globals with the new hdev settings.
*
* 19-Feb-1996 ChrisWil Created.
\***************************************************************************/
VOID xxxResetDisplayDevice(
PDESKTOP pdesk,
PDISPLAYINFO pDI,
DWORD CDS_Flags)
{
WORD wOldBpp;
PMONITORRECTS pmr = NULL;
TL tlPool;
PTHREADINFO ptiCurrent = PtiCurrent();
wOldBpp = gpsi->BitCount;
if (!(CDS_Flags & CDS_FULLSCREEN)) {
pmr = SnapshotMonitorRects();
if (pmr) {
ThreadLockPool(ptiCurrent, pmr, &tlPool);
}
}
/*
* Cleanup any monitor specific DCs we gave out.
*/
DestroyMonitorDCs();
xxxUpdateUserScreen(FALSE);
ResetSharedDesktops(pDI, pdesk);
ResetSystemColors();
if (ghbmCaption) {
GreDeleteObject(ghbmCaption);
ghbmCaption = CreateCaptionStrip();
}
zzzClipCursor(&pDI->rcScreen);
/*
* Adjust window positions to fit new resolutions and positions of
* monitors.
*
* Don't adjust the windows if we are in a temporary mode change.
*/
if (pmr) {
xxxDesktopRecalc(pmr);
ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
}
/*
* Relead the desktop wallpaper on a video mode change.
*/
if (ghbmWallpaper) {
UserAssert(gpszWall);
if (ptiCurrent->TIF_flags & TIF_INCLEANUP) {
/*
* The thread is being terminated. We cannot transition back to
* the client side. So we ask the desktop to do it for us.
*/
_PostThreadMessage(gTermIO.ptiDesktop,
WM_DESKTOPNOTIFY,
DESKTOP_RELOADWALLPAPER,
0);
} else {
TL tlName;
PUNICODE_STRING pProfileUserName = CreateProfileUserName(&tlName);
xxxSetDeskWallpaper(pProfileUserName, SETWALLPAPER_METRICS);
FreeProfileUserName(pProfileUserName, &tlName);
}
}
/*
* Recreate cached bitmaps.
*/
CreateBitmapStrip();
/*
* Broadcast that the display has changed resolution. Also broadcast a
* color-change if we were not in fullscreen, and a color-change took
* effect.
*/
if (!(CDS_Flags & CDS_FULLSCREEN) && gpsi->BitCount != wOldBpp) {
xxxBroadcastDisplaySettingsChange(pdesk, TRUE);
} else {
xxxBroadcastDisplaySettingsChange(pdesk, FALSE);
}
/*
* If the user performed a CTL-ESC, it is possible that the tray-window
* is then in the menu-loop. We want to clear this out so that we don't
* leave improper menu positioning.
*/
if (gpqForeground && gpqForeground->spwndCapture) {
QueueNotifyMessage(gpqForeground->spwndCapture, WM_CANCELMODE, 0, 0);
}
}
/***************************************************************************\
* TrackFullscreenMode
*
* Remember the process going into the fullscreen mode, so that the mode can
* be restored if the process doesn't clean up upon exit. If some other mode
* change, clear the global since that means we're definitely out of the
* fullscreen mode.
*
* 1/12/1999 vadimg created
\***************************************************************************/
VOID TrackFullscreenMode(
DWORD dwFlags)
{
if (dwFlags & CDS_FULLSCREEN) {
gppiFullscreen = PtiCurrent()->ppi;
} else {
gppiFullscreen = NULL;
}
}
/***************************************************************************\
* NtUserChangeDisplaySettings
*
* ChangeDisplaySettings API
*
* 01-Sep-1995 andreva Created
* 19-Feb-1996 ChrisWil Implemented Dynamic-Resolution changes.
\***************************************************************************/
LONG xxxUserChangeDisplaySettings(
IN PUNICODE_STRING pstrDeviceName,
IN LPDEVMODEW pDevMode,
IN PDESKTOP pdesk,
IN DWORD dwFlags,
IN PVOID lParam,
IN MODE PreviousMode)
{
BOOL bSwitchMode;
PDESKTOP pdesktop;
LONG status;
PMDEV pmdev;
/*
* NOTE: The lParam has NOT been properly captured. It is not used in
* this function, but is passed onto other called functions. Once the
* correct type is determined and it is to be used, it must be properly
* captured.
*/
TRACE_INIT(("ChangeDisplaySettings - Entering\n"));
TRACE_SWITCH(("ChangeDisplaySettings - Entering\n"));
TRACE_INIT((" Flags -"));
if (dwFlags & CDS_UPDATEREGISTRY) TRACE_INIT((" CDS_UPDATEREGISTRY - "));
if (dwFlags & CDS_TEST) TRACE_INIT((" CDS_TEST - "));
if (dwFlags & CDS_FULLSCREEN) TRACE_INIT((" CDS_FULLSCREEN - "));
if (dwFlags & CDS_GLOBAL) TRACE_INIT((" CDS_GLOBAL - "));
if (dwFlags & CDS_SET_PRIMARY) TRACE_INIT((" CDS_SET_PRIMARY - "));
if (dwFlags & CDS_RESET) TRACE_INIT((" CDS_RESET - "));
if (dwFlags & CDS_NORESET) TRACE_INIT((" CDS_NORESET - "));
if (dwFlags & CDS_VIDEOPARAMETERS) TRACE_INIT((" CDS_VIDEOPARAMETERS - "));
TRACE_INIT(("\n"));
/*
* Perform Error Checking to verify flag combinations are valid.
*/
if (dwFlags & ~CDS_VALID) {
return GRE_DISP_CHANGE_BADFLAGS;
}
if (DrvQueryMDEVPowerState(gpDispInfo->pmdev) == FALSE) {
RIPMSG0(RIP_WARNING, "ChangeDisplaySettings failed because the device is powered off");
return GRE_DISP_CHANGE_BADPARAM;
}
if (gbMDEVDisabled) {
RIPMSG0(RIP_WARNING, "ChangeDisplaySettings failed because the MDEV is already disabled");
return GRE_DISP_CHANGE_FAILED;
}
/*
* CDS_GLOBAL and CDS_NORESET can only be specified if UPDATEREGISTRY
* is specified.
*/
if ((dwFlags & (CDS_GLOBAL | CDS_NORESET)) && (!(dwFlags & CDS_UPDATEREGISTRY))) {
return GRE_DISP_CHANGE_BADFLAGS;
}
if ((dwFlags & CDS_NORESET) && (dwFlags & CDS_RESET)) {
return GRE_DISP_CHANGE_BADFLAGS;
}
if ((dwFlags & CDS_EXCLUSIVE) && (dwFlags & CDS_FULLSCREEN) && (dwFlags & CDS_RESET)) {
return GRE_DISP_CHANGE_BADFLAGS;
}
/*
* Allow mode change if this is a CSRSS of a remote session. This means we
* are changing display settings when reconnecting a session with a
* diferent resolution.
*/
if (TEST_PUDF(PUDF_LOCKFULLSCREEN)) {
if (!(ISCSRSS() && (IsRemoteConnection()))) {
return GRE_DISP_CHANGE_FAILED;
}
}
/*
* If the modeset is being done on a non-active desktop, we don't want
* it to happen.
*
* PtiCurrent()->rpdesk can be NULL in the case of thread shutdown.
*/
if (pdesk) {
pdesktop = pdesk;
} else {
pdesktop = PtiCurrent()->rpdesk;
}
if (pdesktop != grpdeskRitInput) {
RIPMSG0(RIP_WARNING, "ChangeDisplaySettings on wrong desktop pdesk\n");
return GRE_DISP_CHANGE_FAILED;
}
bSwitchMode = !(dwFlags & (CDS_NORESET | CDS_TEST));
/*
* Turn off cursor and free the spb's prior to calling the mode-change.
* This will make sure off-screen memory is cleaned up for gdi while
* mucking with the resolution changes.
*/
if (bSwitchMode) {
if (CreateCachedMonitor() == NULL) {
return GRE_DISP_CHANGE_FAILED;
}
SetPointer(FALSE);
FreeAllSpbs();
}
/*
* Before calling gdi to change the mode, we should kill the fade sprite.
* This is so that we won't keep pointers to gdi sprites during the mode
* change because the sprites could be reallocated.
*/
if (gfade.hbm != NULL) {
StopFade();
}
/*
* Similarly, we should kill the sprites associated with the drag rect
* (if any exist) before the mode change.
*/
bSetDevDragRect(gpDispInfo->hDev, NULL, NULL);
/*
* Let's capture our parameters. They are both required.
*
* If the input string is not NULL, then we are trying to affect another
* device. The device name is the same as for EnumDisplaySettings.
*/
status = DrvChangeDisplaySettings(pstrDeviceName,
gpDispInfo->pMonitorPrimary->hDev,
pDevMode,
LongToPtr(pdesktop->dwDesktopId),
PreviousMode,
(dwFlags & CDS_UPDATEREGISTRY),
bSwitchMode,
gpDispInfo->pmdev,
&pmdev,
(dwFlags & CDS_RAWMODE) ? GRE_RAWMODE : GRE_DEFAULT,
(dwFlags & CDS_TRYCLOSEST));
if (bSwitchMode) {
/*
* If the caller wanted a reset, but the mode is identical, just reset
* the current mode.
*/
if (status == GRE_DISP_CHANGE_NO_CHANGE) {
TrackFullscreenMode(dwFlags);
if (pmdev != NULL) {
GreFreePool(pmdev);
}
if (dwFlags & CDS_RESET) {
if (SafeDisableMDEV()) {
SafeEnableMDEV();
}
xxxUserResetDisplayDevice();
}
status = GRE_DISP_CHANGE_SUCCESSFUL;
} else if (status == GRE_DISP_CHANGE_SUCCESSFUL) {
ResetRedirectedWindows();
TrackFullscreenMode(dwFlags);
/*
* ChangeDisplaySettings automatically destroys the old MDEV, we
* only have to delete it here.
*/
GreFreePool(gpDispInfo->pmdev);
gpDispInfo->pmdev = pmdev;
xxxResetDisplayDevice(pdesktop, gpDispInfo, dwFlags);
/*
* Set delayed change indicator for currently background desktops.
*/
UserSetDelayedChangeBroadcastForAllDesktops(pdesktop);
} else if (status < GRE_DISP_CHANGE_SUCCESSFUL) {
UserAssert(pmdev == NULL);
xxxUserResetDisplayDevice();
}
xxxInternalInvalidate(pdesktop->pDeskInfo->spwnd,
HRGN_FULL,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME |
RDW_ALLCHILDREN);
/*
* Bring back the cursor-shape.
*/
SetPointer(TRUE);
zzzUpdateCursorImage();
}
/*
* TV-Out Support.
*/
if (NT_SUCCESS(status) && (dwFlags & CDS_VIDEOPARAMETERS)) {
if (lParam == NULL) {
status = GRE_DISP_CHANGE_BADPARAM;
} else {
status = DrvSetVideoParameters(pstrDeviceName,
gpDispInfo->pMonitorPrimary->hDev,
PreviousMode,
lParam);
}
}
TRACE_INIT(("ChangeDisplaySettings - Leaving, Status = %d\n", status));
return status;
}
/***************************************************************************\
* xxxbFullscreenSwitch
*
* Switch in and out of fullscreen console mode
*
* 15-Apr-1997 andreva Created
\***************************************************************************/
BOOL xxxbFullscreenSwitch(
BOOL bFullscreenSwitch,
HWND hwnd)
{
PWND pwnd;
TL tlpwnd;
BOOL bStat = TRUE;
pwnd = ValidateHwnd(hwnd);
if (!pwnd) {
return GRE_DISP_CHANGE_BADPARAM;
}
/*
* We don't want our mode switch to be posted on the looping thread.
* So let's loop until the system has settled down and no mode switch
* is currently occuring.
*/
ThreadLock(pwnd, &tlpwnd);
UserAssert(ghSwitcher != PsGetCurrentThreadId());
while (ghSwitcher != NULL) {
/*
* Make sure we aren't blocking anyone who's sending us a message.
* They can have ghSwitcher and never release it because they are
* waiting on us to process the sent message. And we're waiting on
* ghSwitcher, hence a deadlock.
*/
xxxSleepThread(0, 1, FALSE);
}
/*
* Syncronize with session switching.
*/
if (gfSwitchInProgress || IsRemoteConnection() || gfSessionSwitchBlock) {
ThreadUnlock(&tlpwnd);
return FALSE;
} else {
gfSessionSwitchBlock = TRUE;
}
/*
* If there is a window, we want to check the state of the window. For
* most calls, we want to ensure we are in windowed mode. However, for
* Console, we want to make sure we are in fullscreen mode. So
* differentiate between the two. We will check if the TEXTMODE flag
* is passed in the DEVMODE.
*/
if (bFullscreenSwitch) {
if (GetFullScreen(pwnd) != FULLSCREEN) {
xxxShowWindow(pwnd, SW_SHOWMINIMIZED | TEST_PUDF(PUDF_ANIMATE));
xxxUpdateWindow(pwnd);
}
if (!xxxMakeWindowForegroundWithState(pwnd, FULLSCREEN)) {
goto FullscreenSwitchFailed;
}
if (ghSwitcher != NULL || gbFullScreen != FULLSCREEN) {
goto FullscreenSwitchFailed;
}
} else {
/*
* For the console windows, we want to call with WINDOWED.
*/
if (!xxxMakeWindowForegroundWithState(pwnd, WINDOWED)) {
goto FullscreenSwitchFailed;
}
if (ghSwitcher != NULL || gbFullScreen != GDIFULLSCREEN) {
FullscreenSwitchFailed:
TRACE_INIT(("ChangeDisplaySettings: Can not switch out of fullscreen\n"));
bStat = FALSE;
}
}
ThreadUnlock(&tlpwnd);
gfSessionSwitchBlock = FALSE;
return bStat;
}
NTSTATUS RemoteRedrawRectangle(
WORD Left,
WORD Top,
WORD Right,
WORD Bottom)
{
CheckCritIn();
TRACE_HYDAPI(("RemoteRedrawRectangle\n"));
UserAssert(ISCSRSS());
/*
* If xxxRemoteStopScreenUpdates has not been called, then just repaint
* the current foreground window.
*/
if (gspdeskShouldBeForeground == NULL) {
if (gspwndFullScreen) {
TL tlpwnd;
RECT rcl;
ThreadLock(gspwndFullScreen, &tlpwnd);
rcl.left = Left;
rcl.top = Top;
rcl.right = Right;
rcl.bottom = Bottom;
vDrvInvalidateRect(gpDispInfo->hDev, &rcl);
xxxRedrawWindow(gspwndFullScreen, &rcl, NULL,
RDW_INVALIDATE | RDW_ALLCHILDREN |
RDW_ERASE | RDW_ERASENOW);
ThreadUnlock(&tlpwnd);
}
}
return STATUS_SUCCESS;
}
NTSTATUS RemoteRedrawScreen(
VOID)
{
TL tlpdesk;
PWINDOWSTATION pwinsta;
PTHREADINFO ptiCurrent;
TRACE_HYDAPI(("RemoteRedrawScreen\n"));
CheckCritIn();
if (!gbFreezeScreenUpdates) {
return STATUS_SUCCESS;
}
ptiCurrent = PtiCurrentShared();
gbFreezeScreenUpdates = FALSE;
/*
* Switch back to the previous desktop
*/
if (gspdeskShouldBeForeground == NULL) {
RIPMSG0(RIP_WARNING,
"RemoteRedrawScreen called with no gspdeskShouldBeForeground");
return STATUS_SUCCESS;
}
gbDesktopLocked = FALSE;
pwinsta = gspdeskShouldBeForeground->rpwinstaParent;
/*
* Switch back to the previous desktop.
*/
if (!(gspdeskShouldBeForeground->dwDTFlags & DF_DESTROYED)) {
ThreadLockDesktop(ptiCurrent, gspdeskShouldBeForeground, &tlpdesk, LDLT_FN_CTXREDRAWSCREEN);
xxxSwitchDesktop(pwinsta, gspdeskShouldBeForeground, SDF_SLOVERRIDE);
ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXREDRAWSCREEN);
}
LockDesktop(&gspdeskShouldBeForeground, NULL, LDL_DESKSHOULDBEFOREGROUND2, 0);
return STATUS_SUCCESS;
}
NTSTATUS RemoteDisableScreen(
VOID)
{
TL tlpdesk;
PTHREADINFO ptiCurrent;
PWINDOWSTATION pwinsta;
NTSTATUS Status = STATUS_SUCCESS;
CheckCritIn();
TRACE_HYDAPI(("RemoteDisableScreen\n"));
ptiCurrent = PtiCurrentShared();
if (grpdeskRitInput != gspdeskDisconnect &&
gspdeskDisconnect != NULL) {
pwinsta = gspdeskDisconnect->rpwinstaParent;
/*
* Save current desktop
*/
UserAssert(grpdeskRitInput == pwinsta->pdeskCurrent);
LockDesktop(&gspdeskShouldBeForeground,
grpdeskRitInput,
LDL_DESKSHOULDBEFOREGROUND3,
0);
gbDesktopLocked = TRUE;
/*
* Switch to disconnected desktop.
*/
ThreadLockDesktop(ptiCurrent, gspdeskDisconnect, &tlpdesk, LDLT_FN_CTXDISABLESCREEN);
xxxSwitchDesktop(pwinsta, gspdeskDisconnect, SDF_SLOVERRIDE);
ThreadUnlockDesktop(ptiCurrent, &tlpdesk, LDUT_FN_CTXDISABLESCREEN);
} else if (gspdeskDisconnect != NULL) {
/*
* For some reason the disconnected desktop was the current desktop.
* Now prevent switching from it.
*/
gbDesktopLocked = TRUE;
}
return Status;
}
VOID xxxBroadcastDisplaySettingsChange(
PDESKTOP pdesk,
BOOL bBroadcastColorChange)
{
/*
* Broadcast that the display has changed resolution. We are going
* to specify the desktop for the changing-desktop. That way we
* don't get confused as to what desktop to broadcast to.
*/
xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
WM_DISPLAYCHANGE,
gpsi->BitCount,
MAKELONG(SYSMET(CXSCREEN), SYSMET(CYSCREEN)),
BMSG_SENDNOTIFYMSG,
NULL);
/*
* Broadcast a color-change if requested to do so.
*/
if (bBroadcastColorChange) {
xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
WM_SETTINGCHANGE,
0,
0,
BMSG_SENDNOTIFYMSG,
NULL);
xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
WM_SYSCOLORCHANGE,
0,
0,
BMSG_SENDNOTIFYMSG,
NULL);
}
}
NTSTATUS xxxRequestOutOfFullScreenMode(
VOID)
{
TL tlpwndT;
NTSTATUS Status = STATUS_SUCCESS;
if (gspwndFullScreen) {
/*
* Give the console window a chance to orderly exit full screen mode.
*/
ThreadLock(gspwndFullScreen, &tlpwndT);
xxxSendMessage(gspwndFullScreen, CM_MODE_TRANSITION, (WPARAM)WINDOWED, (LPARAM)0);
ThreadUnlock(&tlpwndT);
/*
* Let's loop until the system has settled down and no mode switch
* is currently occuring.
*/
while (ghSwitcher != NULL) {
/*
* Make sure we aren't blocking anyone who's sending us a
* message. They can have ghSwitcher and never release it
* because they are waiting on us to process the sent message.
* And we're waiting on ghSwitcher, hence a deadlock.
*/
xxxSleepThread(0, 1, FALSE);
}
/*
* See if the fullscreen window didn't exit fullscreen mode
* gracefully.
*/
if (gspwndFullScreen && (gbFullScreen == FULLSCREEN)) {
Status = STATUS_UNSUCCESSFUL;
}
}
return Status;
}