1930 lines
58 KiB
C
1930 lines
58 KiB
C
/****************************** 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 store 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
|
|
\***************************************************************************/
|
|
|
|
LONG TraceFullscreenSwitch;
|
|
|
|
#define NOSWITCHER ((HANDLE)-1)
|
|
|
|
HANDLE idSwitcher = NOSWITCHER;
|
|
BOOL fRedoFullScreenSwitch;
|
|
BOOL fGdiEnabled = TRUE;
|
|
POINT gptCursorFullScreen;
|
|
|
|
|
|
void SetVDMCursorBounds(LPRECT lprc);
|
|
|
|
|
|
VOID UserSetDelayedChangeBroadcastForAllDesktops(PDESKTOP pCurrentDesktop);
|
|
|
|
NTSTATUS xxxRequestOutOfFullScreenMode(VOID);
|
|
|
|
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) {
|
|
RIPMSG0(RIP_WARNING, "UserSaveCurrentModeForAllDesktops - No interactive WindowStation!!!\n");
|
|
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()
|
|
{
|
|
if (PsGetCurrentThreadId() == idSwitcher) {
|
|
|
|
/*
|
|
* correct the full screen state
|
|
*/
|
|
|
|
if (fGdiEnabled) {
|
|
|
|
TRACE_SWITCH(("Switching: FullScreenCleanup: Gdi Enabled\n"));
|
|
|
|
/*
|
|
* gdi is enabled, 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);
|
|
}
|
|
|
|
idSwitcher = NOSWITCHER;
|
|
fRedoFullScreenSwitch = 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
|
|
* idSwitcher. If idSwticher is non-null someone is allready 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 (idSwitcher != NOSWITCHER) {
|
|
fRedoFullScreenSwitch = TRUE;
|
|
TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState was posted: Exit\n"));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
UserAssert(!fRedoFullScreenSwitch);
|
|
idSwitcher = PsGetCurrentThreadId();
|
|
|
|
/*
|
|
* We loop, switching full screens until all states have stabilized
|
|
*/
|
|
|
|
while (TRUE) {
|
|
/*
|
|
* figure out who should be foreground
|
|
*/
|
|
fRedoFullScreenSwitch = 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(fGdiEnabled == TRUE);
|
|
|
|
if (!SafeDisableMDEV()) {
|
|
|
|
/*
|
|
* Restore the previous state before bailing.
|
|
*/
|
|
CLEAR_PUDF(PUDF_LOCKFULLSCREEN);
|
|
LockWindowUpdate2(NULL, TRUE);
|
|
|
|
Lock(&gspwndFullScreen, pwndOldFG);
|
|
gbFullScreen = bStateOld;
|
|
|
|
ThreadUnlock(&tlpwndOldFG);
|
|
ThreadUnlock(&tlpwndNewFG);
|
|
|
|
idSwitcher = NOSWITCHER;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gptCursorFullScreen = gpsi->ptCursor;
|
|
fGdiEnabled = 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(fGdiEnabled == FALSE);
|
|
}
|
|
|
|
SafeEnableMDEV();
|
|
fGdiEnabled = 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 (!fRedoFullScreenSwitch) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
TRACE_SWITCH(("Switching: xxxMakeWindowForegroundWithState: Exit\n"));
|
|
|
|
idSwitcher = NOSWITCHER;
|
|
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
|
|
\***************************************************************************/
|
|
|
|
|
|
/***************************************************************************\
|
|
* UpdateUserScreen
|
|
*
|
|
* Updates USER information associated with the screen
|
|
*
|
|
* History:
|
|
* 28-Sep-1996 adams Created.
|
|
\***************************************************************************/
|
|
|
|
BOOL UpdateUserScreen(void)
|
|
{
|
|
PMDEV pmdev = gpDispInfo->pmdev;
|
|
ULONG i;
|
|
PMONITOR pMonitor;
|
|
TEXTMETRIC tm;
|
|
int iRgn;
|
|
PWINDOWSTATION pwinsta;
|
|
PDESKTOP pdesk;
|
|
HRGN hrgn;
|
|
BOOL fPaletteDisplay;
|
|
RECT rc;
|
|
PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
|
|
PMONITOR *ppMonitorLast = &gpDispInfo->pMonitorFirst;
|
|
|
|
|
|
TRACE_INIT(("UpdateUserScreen\n"));
|
|
|
|
UserAssert(gpDispInfo->hdcScreen);
|
|
UserAssert(gpMonitorCached != NULL);
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* 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) {
|
|
|
|
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();
|
|
|
|
#if DBG
|
|
VerifyVisibleMonitorCount();
|
|
#endif
|
|
|
|
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.
|
|
*
|
|
* This function only initializes gpDispInfo. If any other DISPLAYINFO's
|
|
* are created, they must be initialized directly.
|
|
*
|
|
* 12-Jan-1994 andreva Created
|
|
* 23-Jan-1995 ChrisWil ChangeDisplaySettings work.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
InitUserScreen()
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (!UpdateUserScreen()) {
|
|
RIPMSG0(RIP_WARNING, "UpdateUserScreen failed");
|
|
fSuccess = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
INT 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();
|
|
|
|
UpdateUserScreen();
|
|
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) {
|
|
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, 0l);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* 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 HWND hwnd,
|
|
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"));
|
|
|
|
|
|
#if ((DISP_CHANGE_SUCCESSFUL != GRE_DISP_CHANGE_SUCCESSFUL) || \
|
|
(DISP_CHANGE_RESTART != GRE_DISP_CHANGE_RESTART) || \
|
|
(DISP_CHANGE_FAILED != GRE_DISP_CHANGE_FAILED) || \
|
|
(DISP_CHANGE_BADMODE != GRE_DISP_CHANGE_BADMODE) || \
|
|
(DISP_CHANGE_NOTUPDATED != GRE_DISP_CHANGE_NOTUPDATED) || \
|
|
(DISP_CHANGE_BADFLAGS != GRE_DISP_CHANGE_BADFLAGS) || \
|
|
(DISP_CHANGE_BADPARAM != GRE_DISP_CHANGE_BADPARAM))
|
|
#error "inconsistent header files"
|
|
#endif
|
|
|
|
/*
|
|
* Perform Error Checking to verify flag combinations are valid.
|
|
*/
|
|
if (dwFlags & (~CDS_VALID)) {
|
|
return DISP_CHANGE_BADFLAGS;
|
|
}
|
|
|
|
if (DrvQueryMDEVPowerState(gpDispInfo->pmdev) == FALSE) {
|
|
RIPMSG0(RIP_WARNING, "ChangeDisplaySettings failed because the device is powered off");
|
|
return 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 UPDAREREGISTRY
|
|
* is specified.
|
|
*/
|
|
|
|
if ((dwFlags & (CDS_GLOBAL | CDS_NORESET)) &&
|
|
(!(dwFlags & CDS_UPDATEREGISTRY))) {
|
|
|
|
return DISP_CHANGE_BADFLAGS;
|
|
}
|
|
|
|
if ((dwFlags & CDS_NORESET) &&
|
|
(dwFlags & CDS_RESET)) {
|
|
|
|
return DISP_CHANGE_BADFLAGS;
|
|
}
|
|
|
|
if ((dwFlags & CDS_EXCLUSIVE) && (dwFlags & CDS_FULLSCREEN) && (dwFlags & CDS_RESET)) {
|
|
|
|
return DISP_CHANGE_BADFLAGS;
|
|
}
|
|
|
|
if (hwnd) {
|
|
return DISP_CHANGE_BADPARAM;
|
|
}
|
|
|
|
/*
|
|
* 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 DISP_CHANGE_FAILED;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* If the modeset is being done on a non-active desktop, we don't want
|
|
* it too 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 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 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);
|
|
|
|
/*
|
|
* Lets 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 = DISP_CHANGE_SUCCESSFUL;
|
|
|
|
} else if (status == 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 < DISP_CHANGE_SUCCESSFUL) {
|
|
UserAssert(pmdev == NULL);
|
|
xxxUserResetDisplayDevice();
|
|
}
|
|
|
|
/*
|
|
* Inline so we can specify which desktop this should happen on.
|
|
* xxxRedrawScreen();
|
|
*/
|
|
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 = 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 DISP_CHANGE_BADPARAM;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Lock the PWND, if it is provided
|
|
*/
|
|
|
|
ThreadLock(pwnd, &tlpwnd);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
while (idSwitcher != NOSWITCHER) {
|
|
/*
|
|
* Make sure we aren't blocking anyone who's sending us a message.
|
|
* They can have idSwitcher and never release it because they are
|
|
* waiting on us to process the sent message. And we're waiting on
|
|
* idSwitcher, 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 ((idSwitcher != NOSWITCHER) ||
|
|
(gbFullScreen != FULLSCREEN)) {
|
|
goto FullscreenSwitchFailed;
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* For the console windows, we want to call with WINDOWED
|
|
*/
|
|
|
|
if (!xxxMakeWindowForegroundWithState(pwnd, WINDOWED)) {
|
|
goto FullscreenSwitchFailed;
|
|
}
|
|
|
|
if ((idSwitcher != NOSWITCHER) ||
|
|
(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)
|
|
{
|
|
TL tlpwnd;
|
|
RECT rcl;
|
|
|
|
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) {
|
|
|
|
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 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){
|
|
#if 1 // We might want to remove this call, since color-change seems
|
|
// to provide apps the notification. Need to review
|
|
// chriswil - 06/11/96
|
|
|
|
xxxBroadcastMessage(pdesk->pDeskInfo->spwnd,
|
|
WM_SETTINGCHANGE,
|
|
0,
|
|
0,
|
|
BMSG_SENDNOTIFYMSG,
|
|
NULL);
|
|
#endif
|
|
|
|
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 (idSwitcher != NOSWITCHER) {
|
|
/*
|
|
* Make sure we aren't blocking anyone who's sending us a message.
|
|
* They can have idSwitcher and never release it because they are
|
|
* waiting on us to process the sent message. And we're waiting on
|
|
* idSwitcher, hence a deadlock.
|
|
*/
|
|
xxxSleepThread(0, 1, FALSE);
|
|
}
|
|
/*
|
|
* See if the fullscreen window did exit fullscreen mode gracefuly.
|
|
*/
|
|
if (gspwndFullScreen && (gbFullScreen == FULLSCREEN)) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
return Status;
|
|
|
|
}
|
|
|