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.
4619 lines
150 KiB
4619 lines
150 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: rare.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* History:
|
|
* 06-28-91 MikeHar Created.
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
* MetricsRecalc flags
|
|
*/
|
|
#define CALC_RESIZE 0x0001
|
|
#define CALC_FRAME 0x0002
|
|
#define CALC_MINIMIZE 0x0004
|
|
|
|
/*
|
|
* NormalizeRect flags
|
|
*/
|
|
#define NORMALIZERECT_NORMAL 0
|
|
#define NORMALIZERECT_MAXIMIZED 1
|
|
#define NORMALIZERECT_FULLSCREEN 2
|
|
|
|
/***************************************************************************\
|
|
* SnapshotMonitorRects
|
|
*
|
|
* This is called from ResetDisplay to memorize the monitor positions so
|
|
* DesktopRecalcEx will know where to move stuff.
|
|
*
|
|
* Returns the MONITORRECTS if succeeded, NULL otherwise.
|
|
*
|
|
* History:
|
|
* 09-Dec-1996 adams Created.
|
|
\***************************************************************************/
|
|
PMONITORRECTS SnapshotMonitorRects(
|
|
VOID)
|
|
{
|
|
PMONITOR pMonitor;
|
|
PMONITORRECTS pmr;
|
|
PMONITORPOS pmp;
|
|
#if DBG
|
|
ULONG cVisMon = 0;
|
|
#endif
|
|
|
|
pmr = UserAllocPool(sizeof(MONITORRECTS) + sizeof(MONITORPOS) * (gpDispInfo->cMonitors - 1),
|
|
TAG_MONITORRECTS);
|
|
|
|
if (!pmr) {
|
|
RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "Out of memory in SnapshotMonitorRects");
|
|
return NULL;
|
|
}
|
|
|
|
pmp = pmr->amp;
|
|
for (pMonitor = gpDispInfo->pMonitorFirst;
|
|
pMonitor;
|
|
pMonitor = pMonitor->pMonitorNext) {
|
|
|
|
if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) {
|
|
continue;
|
|
}
|
|
#if DBG
|
|
cVisMon++;
|
|
#endif
|
|
|
|
CopyRect(&pmp->rcMonitor, &pMonitor->rcMonitor);
|
|
CopyRect(&pmp->rcWork, &pMonitor->rcWork);
|
|
|
|
/*
|
|
* If the device for this monitor object is not active, don't store
|
|
* the pointer to it in the list. This way the windows on the inactive
|
|
* monitor will be later moved to the default one.
|
|
*/
|
|
if (HdevFromMonitor(pMonitor) == -1) {
|
|
pmp->pMonitor = NULL;
|
|
} else {
|
|
pmp->pMonitor = pMonitor;
|
|
}
|
|
|
|
pmp++;
|
|
}
|
|
UserAssert(cVisMon == gpDispInfo->cMonitors);
|
|
|
|
pmr->cMonitor = (int)(pmp - pmr->amp);
|
|
|
|
return pmr;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* UpdateMonitorRectsSnapShot
|
|
*
|
|
* Updates a Monitor rects snapshot. Every pMonitor in MONITORPOS is checked
|
|
* to still be a valid monitor. If the pMonitor is no loger valid (deleted
|
|
* by a ChangeDisplaySettings. it is zeroed so that its windows will be
|
|
* repositioned on the primary monitor. This code is only used on by the
|
|
* reconnect in TS scenario and is there for cases that are not happening
|
|
* today: today reconnect always happens from disconnected state where we go
|
|
* from 1 monitor (the disconnected display driver) to n monitors and this
|
|
* monitor (starting in (0,0) never gets deleted because it alway matches one
|
|
* of the new n monitors (the one starting in (0,0). So this code is just in
|
|
* case of future changes.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
VOID UpdateMonitorRectsSnapShot(
|
|
PMONITORRECTS pmr)
|
|
{
|
|
int i;
|
|
PMONITORPOS pmp = pmr->amp;
|
|
|
|
for (i = 0; i < pmr->cMonitor; i++) {
|
|
if (pmp->pMonitor != NULL) {
|
|
if (!IsValidMonitor(pmp->pMonitor)) {
|
|
pmp->pMonitor = NULL;
|
|
}
|
|
}
|
|
|
|
pmp++;
|
|
}
|
|
}
|
|
|
|
BOOL IsValidMonitor(
|
|
PMONITOR pMonitor)
|
|
{
|
|
PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
|
|
|
|
while (pMonitorNext != NULL) {
|
|
if (pMonitorNext == pMonitor) {
|
|
return TRUE;
|
|
}
|
|
|
|
pMonitorNext = pMonitorNext->pMonitorNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* NormalizeRect
|
|
*
|
|
* Adjusts a window rectangle when the working area changes. This can be
|
|
* because of a tray move, with the resolution staying the same, or
|
|
* because of a dynamic resolution change, with the tray staying the same
|
|
* relatively.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
PMONITOR NormalizeRect(
|
|
LPRECT lprcDest,
|
|
LPRECT lprcSrc,
|
|
PMONITORRECTS pmrOld,
|
|
int iOldMonitor,
|
|
int codeFullScreen,
|
|
DWORD style)
|
|
{
|
|
LPCRECT lprcOldMonitor;
|
|
LPCRECT lprcOldWork;
|
|
LPRECT lprcNewWork;
|
|
PMONITOR pMonitor;
|
|
int cxOldMonitor;
|
|
int cyOldMonitor;
|
|
int cxNewMonitor;
|
|
int cyNewMonitor;
|
|
int dxOrg, dyOrg;
|
|
|
|
/*
|
|
* Track the window so it stays in the same place on the same monitor.
|
|
* If the old monitor is no longer active then pick a default.
|
|
*/
|
|
if ((pMonitor = pmrOld->amp[iOldMonitor].pMonitor) == NULL) {
|
|
pMonitor = GetPrimaryMonitor();
|
|
}
|
|
|
|
lprcOldMonitor = &pmrOld->amp[iOldMonitor].rcMonitor;
|
|
lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
|
|
|
|
/*
|
|
* If is a fullscreen app just make it fullscreen at the new location.
|
|
*/
|
|
if (codeFullScreen != NORMALIZERECT_NORMAL) {
|
|
LPCRECT lprcOldSnap, lprcNewSnap;
|
|
|
|
/*
|
|
* If it is a maximized window snap it to the work area. Otherwise
|
|
* it is a rude app so snap it to the screen.
|
|
*/
|
|
if (codeFullScreen == NORMALIZERECT_MAXIMIZED) {
|
|
lprcOldSnap = lprcOldWork;
|
|
lprcNewSnap = &pMonitor->rcWork;
|
|
} else {
|
|
lprcOldSnap = lprcOldMonitor;
|
|
lprcNewSnap = &pMonitor->rcMonitor;
|
|
}
|
|
|
|
lprcDest->left = lprcSrc->left +
|
|
lprcNewSnap->left - lprcOldSnap->left;
|
|
|
|
lprcDest->top = lprcSrc->top +
|
|
lprcNewSnap->top - lprcOldSnap->top;
|
|
|
|
lprcDest->right = lprcSrc->right +
|
|
lprcNewSnap->right - lprcOldSnap->right;
|
|
|
|
lprcDest->bottom = lprcSrc->bottom +
|
|
lprcNewSnap->bottom - lprcOldSnap->bottom;
|
|
|
|
goto AllDone;
|
|
}
|
|
|
|
/*
|
|
* Offset the window by the change in desktop origin.
|
|
*/
|
|
dxOrg = pMonitor->rcMonitor.left - lprcOldMonitor->left;
|
|
dyOrg = pMonitor->rcMonitor.top - lprcOldMonitor->top;
|
|
|
|
/*
|
|
* Calculate the change in screen size (we need it in more than one place).
|
|
*/
|
|
cxOldMonitor = lprcOldMonitor->right - lprcOldMonitor->left;
|
|
cyOldMonitor = lprcOldMonitor->bottom - lprcOldMonitor->top;
|
|
cxNewMonitor = pMonitor->rcMonitor.right - pMonitor->rcMonitor.left;
|
|
cyNewMonitor = pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top;
|
|
|
|
/*
|
|
* If the monitor resolution has changed (or we moved to a new monitor)
|
|
* then factor in the size change.
|
|
*/
|
|
if (cxNewMonitor != cxOldMonitor || cyNewMonitor != cyOldMonitor) {
|
|
int xWnd = lprcSrc->left - lprcOldMonitor->left;
|
|
int yWnd = lprcSrc->top - lprcOldMonitor->top;
|
|
|
|
dxOrg += MultDiv(xWnd, cxNewMonitor - cxOldMonitor, cxOldMonitor);
|
|
dyOrg += MultDiv(yWnd, cyNewMonitor - cyOldMonitor, cyOldMonitor);
|
|
}
|
|
|
|
/*
|
|
* Compute the initial new position.
|
|
*/
|
|
CopyOffsetRect(lprcDest, lprcSrc, dxOrg, dyOrg);
|
|
lprcNewWork = &pMonitor->rcWork;
|
|
|
|
/*
|
|
* Fit horizontally. Try to fit so that the window isn't out of the
|
|
* working area horizontally. Keep left edge visible always.
|
|
*/
|
|
if (lprcDest->right > lprcNewWork->right) {
|
|
OffsetRect(lprcDest, lprcNewWork->right - lprcDest->right, 0);
|
|
}
|
|
|
|
if (lprcDest->left < lprcNewWork->left) {
|
|
OffsetRect(lprcDest, lprcNewWork->left - lprcDest->left, 0);
|
|
}
|
|
|
|
/*
|
|
* Fit vertically. Try to fit so that the window isn't out of the
|
|
* working area vertically. Keep top edge visible always.
|
|
*/
|
|
if (lprcDest->bottom > lprcNewWork->bottom) {
|
|
OffsetRect(lprcDest, 0, lprcNewWork->bottom - lprcDest->bottom);
|
|
}
|
|
|
|
if (lprcDest->top < lprcNewWork->top) {
|
|
OffsetRect(lprcDest, 0, lprcNewWork->top - lprcDest->top);
|
|
}
|
|
|
|
/*
|
|
* If the window is sizeable then shrink it if necessary.
|
|
*/
|
|
if (style & WS_THICKFRAME) {
|
|
int cSnap = 0;
|
|
|
|
if (lprcDest->right > lprcNewWork->right) {
|
|
lprcDest->right = lprcNewWork->right;
|
|
cSnap++;
|
|
}
|
|
|
|
if (lprcDest->bottom > lprcNewWork->bottom) {
|
|
lprcDest->bottom = lprcNewWork->bottom;
|
|
cSnap++;
|
|
}
|
|
|
|
|
|
/*
|
|
* Now make sure we didn't turn this normal window into a
|
|
* fullscreen window. This is a complete hack but it is much
|
|
* better than changing from 800x600 to 640x480 and ending up with
|
|
* a bunch of fullscreen apps...
|
|
*/
|
|
if (cSnap == 2) {
|
|
InflateRect(lprcDest, -1, -1);
|
|
}
|
|
}
|
|
|
|
AllDone:
|
|
return pMonitor;
|
|
}
|
|
|
|
|
|
#if DBG
|
|
/***************************************************************************\
|
|
* SetRipFlags
|
|
*
|
|
* Sets the debug rip flags.
|
|
*
|
|
* History:
|
|
* 16-Aug-1996 adams Created.
|
|
\***************************************************************************/
|
|
VOID SetRipFlags(
|
|
DWORD dwRipFlags)
|
|
{
|
|
if (gpsi) {
|
|
if (!(dwRipFlags & ~RIPF_VALIDUSERFLAGS)) {
|
|
gpsi->dwRIPFlags = ((gpsi->dwRIPFlags & ~RIPF_VALIDUSERFLAGS) | dwRipFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetDbgTag
|
|
*
|
|
* Sets debugging level for a tag.
|
|
*
|
|
* History:
|
|
* 16-Aug-1996 adams Created.
|
|
\***************************************************************************/
|
|
VOID SetDbgTag(
|
|
int tag,
|
|
DWORD dwDBGTAGFlags)
|
|
{
|
|
if (tag > DBGTAG_Max || tag < 0) {
|
|
return;
|
|
}
|
|
|
|
if (gpsi && tag < DBGTAG_Max && !(dwDBGTAGFlags & ~DBGTAG_VALIDUSERFLAGS)) {
|
|
COPY_FLAG(gpsi->adwDBGTAGFlags[tag], dwDBGTAGFlags, DBGTAG_VALIDUSERFLAGS);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SetDbgTagCount
|
|
*
|
|
* Sets the number of tags. This is necessary because one can use a
|
|
* userkdx.dll that was built in an enlistment with N tags, but use it against
|
|
* a system that has M tags (where N != M), which causes obvious problems.
|
|
*
|
|
* History:
|
|
* 05-Oct-2001 JasonSch Created.
|
|
\***************************************************************************/
|
|
VOID SetDbgTagCount(
|
|
DWORD dwCount)
|
|
{
|
|
gpsi->dwTagCount = dwCount;
|
|
}
|
|
#endif
|
|
|
|
/***************************************************************************\
|
|
* UpdateWinIniInt
|
|
*
|
|
* History:
|
|
* 18-Apr-1994 mikeke Created
|
|
\***************************************************************************/
|
|
BOOL UpdateWinIniInt(
|
|
PUNICODE_STRING pProfileUserName,
|
|
UINT idSection,
|
|
UINT wKeyNameId,
|
|
int value)
|
|
{
|
|
WCHAR szTemp[40];
|
|
WCHAR szKeyName[40];
|
|
|
|
swprintf(szTemp, L"%d", value);
|
|
|
|
ServerLoadString(hModuleWin,
|
|
wKeyNameId,
|
|
szKeyName,
|
|
ARRAY_SIZE(szKeyName));
|
|
|
|
return FastWriteProfileStringW(pProfileUserName,
|
|
idSection,
|
|
szKeyName,
|
|
szTemp);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetDesktopMetrics
|
|
*
|
|
* History:
|
|
* 31-Jan-1994 mikeke Ported
|
|
\***************************************************************************/
|
|
VOID SetDesktopMetrics(
|
|
VOID)
|
|
{
|
|
LPRECT lprcWork;
|
|
|
|
lprcWork = &GetPrimaryMonitor()->rcWork;
|
|
|
|
SYSMET(CXFULLSCREEN) = lprcWork->right - lprcWork->left;
|
|
SYSMET(CXMAXIMIZED) = lprcWork->right - lprcWork->left + 2 * SYSMET(CXSIZEFRAME);
|
|
|
|
SYSMET(CYFULLSCREEN) = lprcWork->bottom - lprcWork->top - SYSMET(CYCAPTION);
|
|
SYSMET(CYMAXIMIZED) = lprcWork->bottom - lprcWork->top + 2 * SYSMET(CYSIZEFRAME);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxMetricsRecalc (Win95: MetricsRecalc)
|
|
*
|
|
* Does work to size/position all minimized or nonminimized
|
|
* windows. Called when frame metrics or min metrics are changed.
|
|
*
|
|
* Note that you can NOT do DeferWindowPos() with this function. SWP doesn't
|
|
* work when you do parents and children at the same time--it's only for
|
|
* peer windows. Thus we must do SetWindowPos() for each window.
|
|
*
|
|
* History:
|
|
* 06-28-91 MikeHar Ported.
|
|
\***************************************************************************/
|
|
VOID xxxMetricsRecalc(
|
|
UINT wFlags,
|
|
int dx,
|
|
int dy,
|
|
int dyCaption,
|
|
int dyMenu)
|
|
{
|
|
PHWND phwnd;
|
|
PWND pwnd;
|
|
RECT rc;
|
|
PCHECKPOINT pcp;
|
|
TL tlpwnd;
|
|
BOOL fResized;
|
|
PBWL pbwl;
|
|
PTHREADINFO ptiCurrent;
|
|
int c;
|
|
|
|
ptiCurrent = PtiCurrent();
|
|
pbwl = BuildHwndList(GETDESKINFO(ptiCurrent)->spwnd->spwndChild,
|
|
BWL_ENUMLIST | BWL_ENUMCHILDREN,
|
|
NULL);
|
|
|
|
if (!pbwl) {
|
|
return;
|
|
}
|
|
|
|
UserAssert(*pbwl->phwndNext == (HWND) 1);
|
|
c = (int)(pbwl->phwndNext - pbwl->rghwnd);
|
|
for (phwnd = pbwl->rghwnd; c > 0; c--, phwnd++) {
|
|
pwnd = RevalidateHwnd(*phwnd);
|
|
if (!pwnd) {
|
|
continue;
|
|
}
|
|
|
|
ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
|
|
|
|
fResized = FALSE;
|
|
|
|
if ((wFlags & CALC_MINIMIZE) && TestWF(pwnd, WFMINIMIZED)) {
|
|
/*
|
|
* We're changing the minimized window dimensions. We need to
|
|
* resize. Note that we do NOT move.
|
|
*/
|
|
CopyRect(&rc, (&pwnd->rcWindow));
|
|
rc.right += dx;
|
|
rc.bottom += dy;
|
|
|
|
goto PositionWnd;
|
|
}
|
|
|
|
/*
|
|
* We're changing the size of the window because the sizing border
|
|
* changed.
|
|
*/
|
|
if ((wFlags & CALC_RESIZE) && TestWF(pwnd, WFSIZEBOX)) {
|
|
pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
|
|
|
|
/*
|
|
* Update maximized position to account for sizing border
|
|
* We do this for DOS box also. This way client of max'ed windows
|
|
* stays in same relative position.
|
|
*/
|
|
if (pcp && (pcp->fMaxInitialized)) {
|
|
pcp->ptMax.x -= dx;
|
|
pcp->ptMax.y -= dy;
|
|
}
|
|
|
|
if (TestWF(pwnd, WFMINIMIZED)) {
|
|
if (pcp) {
|
|
InflateRect(&pcp->rcNormal, dx, dy);
|
|
}
|
|
} else {
|
|
CopyInflateRect(&rc, (&pwnd->rcWindow), dx, dy);
|
|
if (TestWF(pwnd, WFCPRESENT)) {
|
|
rc.bottom += dyCaption;
|
|
}
|
|
if (TestWF(pwnd, WFMPRESENT)) {
|
|
rc.bottom += dyMenu;
|
|
}
|
|
|
|
PositionWnd:
|
|
fResized = TRUE;
|
|
|
|
/*
|
|
* Remember SWP expects values in PARENT CLIENT coordinates.
|
|
*/
|
|
if (pwnd->spwndParent != PWNDDESKTOP(pwnd)) {
|
|
OffsetRect(&rc,
|
|
-pwnd->spwndParent->rcClient.left,
|
|
-pwnd->spwndParent->rcClient.top);
|
|
}
|
|
|
|
xxxSetWindowPos(pwnd,
|
|
PWND_TOP,
|
|
rc.left,
|
|
rc.top,
|
|
rc.right-rc.left,
|
|
rc.bottom-rc.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS |
|
|
SWP_FRAMECHANGED | SWP_NOREDRAW);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We're changing the nonclient widgets, so recalculate the client.
|
|
*/
|
|
if (wFlags & CALC_FRAME) {
|
|
/*
|
|
* Delete any cached small icons.
|
|
*/
|
|
if (dyCaption) {
|
|
xxxSendMessage(pwnd, WM_SETICON, ICON_RECREATE, 0);
|
|
}
|
|
|
|
if (!TestWF(pwnd, WFMINIMIZED) && !fResized) {
|
|
CopyRect(&rc, &(pwnd->rcWindow));
|
|
if (TestWF(pwnd, WFMPRESENT)) {
|
|
rc.bottom += dyMenu;
|
|
}
|
|
|
|
if (TestWF(pwnd, WFCPRESENT)) {
|
|
rc.bottom += dyCaption;
|
|
|
|
/*
|
|
* Maximized MDI child windows position their caption
|
|
* outside their parent's client area (negative y). If
|
|
* the caption has changed, they need to be repositioned.
|
|
*/
|
|
if (TestWF(pwnd, WFMAXIMIZED)
|
|
&& TestWF(pwnd, WFCHILD)
|
|
&& (GETFNID(pwnd->spwndParent) == FNID_MDICLIENT)) {
|
|
|
|
xxxSetWindowPos(pwnd,
|
|
PWND_TOP,
|
|
rc.left - pwnd->spwndParent->rcWindow.left,
|
|
rc.top - pwnd->spwndParent->rcWindow.top - dyCaption,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE |
|
|
SWP_FRAMECHANGED | SWP_NOREDRAW);
|
|
goto LoopCleanup;
|
|
}
|
|
}
|
|
|
|
xxxSetWindowPos(pwnd,
|
|
PWND_TOP,
|
|
0,
|
|
0,
|
|
rc.right-rc.left,
|
|
rc.bottom-rc.top,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE |
|
|
SWP_FRAMECHANGED | SWP_NOCOPYBITS |
|
|
SWP_NOREDRAW);
|
|
}
|
|
}
|
|
|
|
LoopCleanup:
|
|
ThreadUnlock(&tlpwnd);
|
|
}
|
|
|
|
FreeHwndList(pbwl);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FindOldMonitor
|
|
*
|
|
* Returns the index of the monitor in "pmr" which has the greatest
|
|
* overlap with a rectangle. This function is used to determine which
|
|
* monitor a window was on after one or more monitor rectangles have
|
|
* changed.
|
|
*
|
|
* History:
|
|
* 11-Sep-1996 adams Created.
|
|
\***************************************************************************/
|
|
int FindOldMonitor(
|
|
LPCRECT lprc,
|
|
PMONITORRECTS pmr)
|
|
{
|
|
DWORD dwClosest;
|
|
int iClosest, i;
|
|
int cxRect, cyRect;
|
|
PMONITORPOS pmp;
|
|
|
|
iClosest = -1;
|
|
dwClosest = 0;
|
|
|
|
cxRect = (lprc->right - lprc->left);
|
|
cyRect = (lprc->bottom - lprc->top);
|
|
|
|
for (i = 0, pmp = pmr->amp; i < pmr->cMonitor; pmp++, i++) {
|
|
RECT rcT;
|
|
|
|
if (IntersectRect(&rcT, lprc, &pmp->rcMonitor)) {
|
|
DWORD dwT;
|
|
|
|
/*
|
|
* Convert to width/height.
|
|
*/
|
|
rcT.right -= rcT.left;
|
|
rcT.bottom -= rcT.top;
|
|
|
|
/*
|
|
* If fully enclosed, we're done.
|
|
*/
|
|
if (rcT.right == cxRect && rcT.bottom == cyRect) {
|
|
return i;
|
|
}
|
|
|
|
/*
|
|
* Use largest area.
|
|
*/
|
|
dwT = (DWORD)rcT.right * (DWORD)rcT.bottom;
|
|
if (dwT > dwClosest) {
|
|
dwClosest = dwT;
|
|
iClosest = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return iClosest;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxDesktopRecalc
|
|
*
|
|
* Moves all top-level nonpopup windows into free desktop area,
|
|
* attempting to keep them in the same position relative to the monitor
|
|
* they were on. Also resets minimized info (so that when a window is
|
|
* subsequently minimized it will go to the correct location).
|
|
*
|
|
* History:
|
|
* 11-Sep-1996 adams Created.
|
|
\***************************************************************************/
|
|
VOID xxxDesktopRecalc(
|
|
PMONITORRECTS pmrOld)
|
|
{
|
|
PWND pwndDesktop;
|
|
PSMWP psmwp;
|
|
PHWND phwnd;
|
|
PBWL pbwl;
|
|
PWND pwnd;
|
|
CHECKPOINT * pcp;
|
|
int iOldMonitor;
|
|
int codeFullScreen;
|
|
UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
|
|
|
|
|
|
/*
|
|
* We never want CSRSS to position windows synchronously because it
|
|
* might get blocked by a hung app. CSRSS needs to reposition windows
|
|
* in the TS reconnect and disconnect path as part of changing display
|
|
* setting to switch display drivers or to match new client resolution.
|
|
*/
|
|
if (ISCSRSS()) {
|
|
flags |= SWP_ASYNCWINDOWPOS;
|
|
}
|
|
|
|
UserVerify(pwndDesktop = _GetDesktopWindow());
|
|
if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
|
|
return;
|
|
}
|
|
|
|
if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
|
|
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1 && psmwp; phwnd++) {
|
|
/*
|
|
* Make sure this hwnd is still around.
|
|
*/
|
|
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL ||
|
|
TestWF(pwnd, WEFTOOLWINDOW)) {
|
|
continue;
|
|
}
|
|
|
|
codeFullScreen = TestWF(pwnd, WFFULLSCREEN) ?
|
|
NORMALIZERECT_FULLSCREEN : NORMALIZERECT_NORMAL;
|
|
|
|
pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
|
|
if (pcp) {
|
|
/*
|
|
* We don't need to blow away saved maximized positions
|
|
* anymore, since the max position is always (for top level
|
|
* windows) relative to the origin of the monitor's working
|
|
* area. And for child windows, we shouldn't do it period
|
|
* anyway.
|
|
*/
|
|
pcp->fMinInitialized = FALSE;
|
|
|
|
/*
|
|
* Figure out which monitor the position was on before things
|
|
* got shuffled around and try to keep it on that monitor. If
|
|
* it was never visible on a monitor then leave it alone.
|
|
*/
|
|
iOldMonitor = FindOldMonitor(&pcp->rcNormal, pmrOld);
|
|
if (iOldMonitor != (UINT)-1) {
|
|
NormalizeRect(&pcp->rcNormal,
|
|
&pcp->rcNormal,
|
|
pmrOld,
|
|
iOldMonitor,
|
|
codeFullScreen,
|
|
pwnd->style);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Figure out which monitor the position was on before things got
|
|
* shuffled around and try to keep it on that monitor. If it
|
|
* was never visible on a monitor then leave it alone.
|
|
*/
|
|
iOldMonitor = FindOldMonitor(&pwnd->rcWindow, pmrOld);
|
|
if (iOldMonitor != -1) {
|
|
PMONITOR pMonitorDst;
|
|
RECT rc;
|
|
|
|
/*
|
|
* Check for maximized apps that are truly maximized (as
|
|
* opposed to apps that manage their owm maximized rect).
|
|
*/
|
|
if (TestWF(pwnd, WFMAXIMIZED)) {
|
|
LPRECT lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
|
|
|
|
if ( (pwnd->rcWindow.right - pwnd->rcWindow.left >=
|
|
lprcOldWork->right - lprcOldWork->left)
|
|
&&
|
|
(pwnd->rcWindow.bottom - pwnd->rcWindow.top >=
|
|
lprcOldWork->bottom - lprcOldWork->top)) {
|
|
|
|
codeFullScreen = NORMALIZERECT_MAXIMIZED;
|
|
}
|
|
}
|
|
|
|
pMonitorDst = NormalizeRect(&rc,
|
|
&pwnd->rcWindow,
|
|
pmrOld,
|
|
iOldMonitor,
|
|
codeFullScreen,
|
|
pwnd->style);
|
|
|
|
if (TestWF(pwnd, WFMAXFAKEREGIONAL)) {
|
|
UserAssert(pMonitorDst->hrgnMonitor);
|
|
pwnd->hrgnClip = pMonitorDst->hrgnMonitor;
|
|
}
|
|
|
|
|
|
psmwp = _DeferWindowPos(psmwp,
|
|
pwnd,
|
|
(PWND)HWND_TOP,
|
|
rc.left,
|
|
rc.top,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
flags);
|
|
}
|
|
}
|
|
|
|
if (psmwp) {
|
|
xxxEndDeferWindowPosEx(psmwp, TRUE);
|
|
}
|
|
}
|
|
|
|
FreeHwndList(pbwl);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SetWindowMetricInt
|
|
*
|
|
* History:
|
|
* 25-Feb-96 BradG Added Pixel -> TWIPS conversion
|
|
\***************************************************************************/
|
|
BOOL SetWindowMetricInt(
|
|
PUNICODE_STRING pProfileUserName,
|
|
WORD wKeyNameId,
|
|
int iIniValue)
|
|
{
|
|
/*
|
|
* If you change the below list of STR_* make sure you make a
|
|
* corresponding change in FastGetProfileIntFromID.
|
|
*/
|
|
switch (wKeyNameId) {
|
|
case STR_BORDERWIDTH:
|
|
case STR_SCROLLWIDTH:
|
|
case STR_SCROLLHEIGHT:
|
|
case STR_CAPTIONWIDTH:
|
|
case STR_CAPTIONHEIGHT:
|
|
case STR_SMCAPTIONWIDTH:
|
|
case STR_SMCAPTIONHEIGHT:
|
|
case STR_MENUWIDTH:
|
|
case STR_MENUHEIGHT:
|
|
case STR_ICONHORZSPACING:
|
|
case STR_ICONVERTSPACING:
|
|
case STR_MINWIDTH:
|
|
case STR_MINHORZGAP:
|
|
case STR_MINVERTGAP:
|
|
/*
|
|
* Always store window metrics in TWIPS
|
|
*/
|
|
iIniValue = -MultDiv(iIniValue, 72*20, gpsi->dmLogPixels);
|
|
break;
|
|
}
|
|
|
|
return UpdateWinIniInt(pProfileUserName,
|
|
PMAP_METRICS,
|
|
wKeyNameId,
|
|
iIniValue);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetWindowMetricFont
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
BOOL SetWindowMetricFont(
|
|
PUNICODE_STRING pProfileUserName,
|
|
UINT idKey,
|
|
LPLOGFONT lplf)
|
|
{
|
|
return FastWriteProfileValue(pProfileUserName,
|
|
PMAP_METRICS,
|
|
(LPWSTR)UIntToPtr(idKey),
|
|
REG_BINARY,
|
|
(LPBYTE)lplf,
|
|
sizeof(LOGFONTW));
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SetAndDrawNCMetrics
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
BOOL xxxSetAndDrawNCMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
int clNewBorder,
|
|
LPNONCLIENTMETRICS lpnc)
|
|
{
|
|
int dl;
|
|
int dxMinOld;
|
|
int dyMinOld;
|
|
int cxBorder;
|
|
int cyBorder;
|
|
int dyCaption;
|
|
int dyMenu;
|
|
|
|
dl = clNewBorder - gpsi->gclBorder;
|
|
dxMinOld = SYSMET(CXMINIMIZED);
|
|
dyMinOld = SYSMET(CYMINIMIZED);
|
|
cxBorder = SYSMET(CXBORDER);
|
|
cyBorder = SYSMET(CYBORDER);
|
|
|
|
|
|
/*
|
|
* Do we need to recalculate?
|
|
*/
|
|
if (lpnc == NULL && !dl) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (lpnc) {
|
|
dyCaption = (int)lpnc->iCaptionHeight - SYSMET(CYSIZE);
|
|
dyMenu = (int)lpnc->iMenuHeight - SYSMET(CYMENUSIZE);
|
|
} else {
|
|
dyCaption = dyMenu = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Recalculate the system metrics.
|
|
*/
|
|
xxxSetWindowNCMetrics(pProfileUserName, lpnc, TRUE, clNewBorder);
|
|
|
|
/*
|
|
* Reset our saved menu size/position info.
|
|
*/
|
|
MenuRecalc();
|
|
|
|
/*
|
|
* Reset window sized, positions, frames
|
|
*/
|
|
xxxMetricsRecalc(CALC_FRAME | (dl ? CALC_RESIZE : 0),
|
|
dl * cxBorder,
|
|
dl * cyBorder,
|
|
dyCaption,
|
|
dyMenu);
|
|
|
|
dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
|
|
dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
|
|
if (dxMinOld || dyMinOld) {
|
|
xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
|
|
}
|
|
|
|
xxxRedrawScreen();
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSetAndDrawMinMetrics
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL xxxSetAndDrawMinMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPMINIMIZEDMETRICS lpmin)
|
|
{
|
|
/*
|
|
* Save minimized window dimensions.
|
|
*/
|
|
int dxMinOld = SYSMET(CXMINIMIZED);
|
|
int dyMinOld = SYSMET(CYMINIMIZED);
|
|
|
|
SetMinMetrics(pProfileUserName,lpmin);
|
|
|
|
/*
|
|
* Do we need to adjust minimized size?
|
|
*/
|
|
dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
|
|
dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
|
|
|
|
if (dxMinOld || dyMinOld) {
|
|
xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
|
|
}
|
|
|
|
xxxRedrawScreen();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxSPISetNCMetrics
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL xxxSPISetNCMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPNONCLIENTMETRICS lpnc,
|
|
BOOL fAlterWinIni)
|
|
{
|
|
BOOL fWriteAllowed = !fAlterWinIni;
|
|
BOOL fChanged = FALSE;
|
|
|
|
lpnc->iBorderWidth = max(lpnc->iBorderWidth, 1);
|
|
lpnc->iBorderWidth = min(lpnc->iBorderWidth, 50);
|
|
|
|
if (fAlterWinIni) {
|
|
fChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, lpnc->iBorderWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLWIDTH, lpnc->iScrollWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLHEIGHT, lpnc->iScrollHeight);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONWIDTH, lpnc->iCaptionWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONHEIGHT, lpnc->iCaptionHeight);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONWIDTH, lpnc->iSmCaptionWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONHEIGHT, lpnc->iSmCaptionHeight);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUWIDTH, lpnc->iMenuWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUHEIGHT, lpnc->iMenuHeight);
|
|
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_CAPTIONFONT, &lpnc->lfCaptionFont);
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_SMCAPTIONFONT, &lpnc->lfSmCaptionFont);
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_MENUFONT, &lpnc->lfMenuFont);
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_STATUSFONT, &lpnc->lfStatusFont);
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_MESSAGEFONT, &lpnc->lfMessageFont);
|
|
|
|
fWriteAllowed = fChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
xxxSetAndDrawNCMetrics(pProfileUserName, lpnc->iBorderWidth, lpnc);
|
|
}
|
|
|
|
return fChanged;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSPISetMinMetrics
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL xxxSPISetMinMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPMINIMIZEDMETRICS lpmin,
|
|
BOOL fAlterWinIni)
|
|
{
|
|
BOOL fWriteAllowed = !fAlterWinIni;
|
|
BOOL fChanged = FALSE;
|
|
|
|
if (fAlterWinIni) {
|
|
fChanged = SetWindowMetricInt(pProfileUserName, STR_MINWIDTH, lpmin->iWidth);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINHORZGAP, lpmin->iHorzGap);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINVERTGAP, lpmin->iVertGap);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINARRANGE, lpmin->iArrange);
|
|
|
|
fWriteAllowed = fChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
xxxSetAndDrawMinMetrics(pProfileUserName, lpmin);
|
|
}
|
|
|
|
return fChanged;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SPISetIconMetrics
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL SPISetIconMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPICONMETRICS lpicon,
|
|
BOOL fAlterWinIni)
|
|
{
|
|
BOOL fWriteAllowed = !fAlterWinIni;
|
|
BOOL fChanged = FALSE;
|
|
|
|
if (fAlterWinIni) {
|
|
fChanged = SetWindowMetricInt(pProfileUserName, STR_ICONHORZSPACING, lpicon->iHorzSpacing);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONVERTSPACING, lpicon->iVertSpacing);
|
|
fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONTITLEWRAP, lpicon->iTitleWrap);
|
|
fChanged &= SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lpicon->lfFont);
|
|
|
|
fWriteAllowed = fChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SetIconMetrics(pProfileUserName,lpicon);
|
|
xxxRedrawScreen();
|
|
}
|
|
|
|
return fChanged;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* SPISetIconTitleFont
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL SPISetIconTitleFont(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPLOGFONT lplf,
|
|
BOOL fAlterWinIni)
|
|
{
|
|
HFONT hfnT;
|
|
BOOL fWriteAllowed = !fAlterWinIni;
|
|
BOOL fWinIniChanged = FALSE;
|
|
|
|
if (hfnT = CreateFontFromWinIni(pProfileUserName,lplf, STR_ICONFONT)) {
|
|
if (fAlterWinIni) {
|
|
if (lplf) {
|
|
LOGFONT lf;
|
|
|
|
GreExtGetObjectW(hfnT, sizeof(LOGFONTW), &lf);
|
|
fWinIniChanged = SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lf);
|
|
} else {
|
|
/*
|
|
* !lParam so go back to current win.ini settings.
|
|
*/
|
|
fWinIniChanged = TRUE;
|
|
}
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
if (ghIconFont) {
|
|
GreMarkDeletableFont(ghIconFont);
|
|
GreDeleteObject(ghIconFont);
|
|
}
|
|
|
|
ghIconFont = hfnT;
|
|
} else {
|
|
GreMarkDeletableFont(hfnT);
|
|
GreDeleteObject(hfnT);
|
|
}
|
|
}
|
|
|
|
return fWinIniChanged;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSetSPIMetrics
|
|
*
|
|
* History:
|
|
* 13-May-1994 mikeke mikeke Ported
|
|
\***************************************************************************/
|
|
BOOL xxxSetSPIMetrics(
|
|
PUNICODE_STRING pProfileUserName,
|
|
DWORD wFlag,
|
|
LPVOID lParam,
|
|
BOOL fAlterWinIni)
|
|
{
|
|
BOOL fWinIniChanged;
|
|
|
|
switch (wFlag) {
|
|
case SPI_SETANIMATION:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = SetWindowMetricInt(pProfileUserName,
|
|
STR_MINANIMATE,
|
|
(int)((LPANIMATIONINFO)lParam)->iMinAnimate);
|
|
|
|
if (!fWinIniChanged) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
fWinIniChanged = FALSE;
|
|
}
|
|
|
|
SET_OR_CLEAR_PUDF(PUDF_ANIMATE, ((LPANIMATIONINFO)lParam)->iMinAnimate);
|
|
return fWinIniChanged;
|
|
|
|
case SPI_SETNONCLIENTMETRICS:
|
|
return xxxSPISetNCMetrics(pProfileUserName, (LPNONCLIENTMETRICS)lParam, fAlterWinIni);
|
|
|
|
case SPI_SETICONMETRICS:
|
|
return SPISetIconMetrics(pProfileUserName, (LPICONMETRICS)lParam, fAlterWinIni);
|
|
|
|
case SPI_SETMINIMIZEDMETRICS:
|
|
return xxxSPISetMinMetrics(pProfileUserName, (LPMINIMIZEDMETRICS)lParam, fAlterWinIni);
|
|
|
|
case SPI_SETICONTITLELOGFONT:
|
|
return SPISetIconTitleFont(pProfileUserName, (LPLOGFONT)lParam, fAlterWinIni);
|
|
|
|
default:
|
|
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "SetSPIMetrics. Invalid wFlag: 0x%x", wFlag);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetFilterKeys
|
|
*
|
|
* History:
|
|
* 10-12-94 JimA Created.
|
|
\***************************************************************************/
|
|
BOOL SetFilterKeys(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPFILTERKEYS pFilterKeys)
|
|
{
|
|
LPWSTR pwszd = L"%d";
|
|
BOOL fWinIniChanged;
|
|
WCHAR szTemp[40];
|
|
|
|
swprintf(szTemp, pwszd, pFilterKeys->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_KEYBOARDRESPONSE,
|
|
L"Flags",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pFilterKeys->iWaitMSec);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_KEYBOARDRESPONSE,
|
|
L"DelayBeforeAcceptance",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pFilterKeys->iDelayMSec);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_KEYBOARDRESPONSE,
|
|
L"AutoRepeatDelay",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pFilterKeys->iRepeatMSec);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_KEYBOARDRESPONSE,
|
|
L"AutoRepeatRate",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pFilterKeys->iBounceMSec);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_KEYBOARDRESPONSE,
|
|
L"BounceTime",
|
|
szTemp);
|
|
|
|
return fWinIniChanged;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetMouseKeys
|
|
*
|
|
* History:
|
|
* 10-12-94 JimA Created.
|
|
\***************************************************************************/
|
|
BOOL SetMouseKeys(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPMOUSEKEYS pMK)
|
|
{
|
|
LPWSTR pwszd = L"%d";
|
|
BOOL fWinIniChanged;
|
|
WCHAR szTemp[40];
|
|
|
|
swprintf(szTemp, pwszd, pMK->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_MOUSEKEYS,
|
|
L"Flags",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pMK->iMaxSpeed);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_MOUSEKEYS,
|
|
L"MaximumSpeed",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pMK->iTimeToMaxSpeed);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_MOUSEKEYS,
|
|
L"TimeToMaximumSpeed",
|
|
szTemp);
|
|
|
|
return fWinIniChanged;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetSoundSentry
|
|
*
|
|
* History:
|
|
* 10-12-94 JimA Created.
|
|
\***************************************************************************/
|
|
BOOL SetSoundSentry(
|
|
PUNICODE_STRING pProfileUserName,
|
|
LPSOUNDSENTRY pSS)
|
|
{
|
|
LPWSTR pwszd = L"%d";
|
|
BOOL fWinIniChanged;
|
|
WCHAR szTemp[40];
|
|
|
|
swprintf(szTemp, pwszd, pSS->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_SOUNDSENTRY,
|
|
L"Flags",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pSS->iFSTextEffect);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_SOUNDSENTRY,
|
|
L"TextEffect",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pSS->iWindowsEffect);
|
|
fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_SOUNDSENTRY,
|
|
L"WindowsEffect",
|
|
szTemp);
|
|
|
|
return fWinIniChanged;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* CalculateMouseSensitivity
|
|
*
|
|
* The resultant table looks like this...
|
|
*
|
|
* Sens | Sensitivity Adjustment
|
|
* 0 | 0 * SENS_SCALAR ALGORITHM 0<=NUM<=2
|
|
* 1 | 1/32 * SENS_SCALAR (NUM/32)*SENS_SCALAR
|
|
* 2 | 1/16 * SENS_SCALAR
|
|
* 3 | 1/8 * SENS_SCALAR ALGORITHM 3<=NUM<=10
|
|
* 4 | 1/4 (2/8) * SENS_SCALAR ((NUM-2)/8)*SENS_SCALAR
|
|
* 5 | 3/8 * SENS_SCALAR
|
|
* 6 | 1/2 (4/8) * SENS_SCALAR
|
|
* 7 | 5/8 * SENS_SCALAR
|
|
* 8 | 3/4 (6/8) * SENS_SCALAR
|
|
* 9 | 7/8 * SENS_SCALAR
|
|
* 10 | 1 * SENS_SCALAR
|
|
* 11 | 5/4 * SENS_SCALAR ALGORITHM NUM>=11
|
|
* 12 | 3/2 (6/4) * SENS_SCALAR ((NUM-6)/4)*SENS_SCALAR
|
|
* 13 | 7/4 * SENS_SCALAR
|
|
* 14 | 2 (8/4) * SENS_SCALAR
|
|
* 15 | 9/4 * SENS_SCALAR
|
|
* 16 | 5/2 (10/4) * SENS_SCALAR
|
|
* 17 | 11/4 * SENS_SCALAR
|
|
* 18 | 3 (12/4) * SENS_SCALAR
|
|
* 19 | 13/4 * SENS_SCALAR
|
|
* 20 | 7/2 (14/4) * SENS_SCALAR
|
|
*
|
|
* COMMENTS: Sensitivities are constrained to be between 1 and 20.
|
|
*
|
|
* History:
|
|
* 09-27-96 jparsons Created.
|
|
\***************************************************************************/
|
|
LONG CalculateMouseSensitivity(
|
|
LONG lSens)
|
|
{
|
|
LONG lSenFactor;
|
|
|
|
if (lSens <= 2) {
|
|
lSenFactor = lSens * 256 / 32;
|
|
} else if (lSens >= 3 && lSens <= 10 ) {
|
|
lSenFactor = (lSens - 2) * 256 /8;
|
|
} else {
|
|
lSenFactor= (lSens - 6) * 256 / 4;
|
|
}
|
|
|
|
return lSenFactor;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* xxxSystemParametersInfo
|
|
*
|
|
* SPI_GETBEEP: wParam is not used. lParam is long pointer to a boolean which
|
|
* gets true if beep on, false if beep off.
|
|
*
|
|
* SPI_SETBEEP: wParam is a bool which sets beep on (true) or off (false).
|
|
* lParam is not used.
|
|
*
|
|
* SPI_GETMOUSE: wParam is not used. lParam is long pointer to an integer
|
|
* array where rgw[0] gets xMouseThreshold, rgw[1] gets
|
|
* yMouseThreshold, and rgw[2] gets gMouseSpeed.
|
|
*
|
|
* SPI_SETMOUSE: wParam is not used. lParam is long pointer to an integer
|
|
* array as described above. User's values are set to values
|
|
* in array.
|
|
*
|
|
* SPI_GETBORDER: wParam is not used. lParam is long pointer to an integer
|
|
* which gets the value of clBorder (border multiplier factor).
|
|
*
|
|
* SPI_SETBORDER: wParam is an integer which sets gpsi->gclBorder.
|
|
* lParam is not used.
|
|
*
|
|
* SPI_GETKEYBOARDDELAY: wParam is not used. lParam is a long pointer to an int
|
|
* which gets the current keyboard repeat delay setting.
|
|
*
|
|
* SPI_SETKEYBOARDDELAY: wParam is the new keyboard delay setting.
|
|
* lParam is not used.
|
|
*
|
|
* SPI_GETKEYBOARDSPEED: wParam is not used. lParam is a long pointer
|
|
* to an int which gets the current keyboard repeat
|
|
* speed setting.
|
|
*
|
|
* SPI_SETKEYBOARDSPEED: wParam is the new keyboard speed setting.
|
|
* lParam is not used.
|
|
*
|
|
* SPI_KANJIMENU: wParam contains:
|
|
* 1 - Mouse accelerator
|
|
* 2 - ASCII accelerator
|
|
* 3 - Kana accelerator
|
|
* lParam is not used. The wParam value is stored in the global
|
|
* KanjiMenu for use in accelerator displaying & searching.
|
|
*
|
|
* SPI_LANGDRIVER: wParam is not used.
|
|
* lParam contains a LPSTR to the new language driver filename.
|
|
*
|
|
* SPI_ICONHORIZONTALSPACING: wParam is the width in pixels of an icon cell.
|
|
*
|
|
* SPI_ICONVERTICALSPACING: wParam is the height in pixels of an icon cell.
|
|
*
|
|
* SPI_GETSCREENSAVETIMEOUT: wParam is not used
|
|
* lParam is a pointer to an int which gets the screen saver
|
|
* timeout value.
|
|
*
|
|
* SPI_SETSCREENSAVETIMEOUT: wParam is the time in seconds for the system
|
|
* to be idle before screensaving.
|
|
*
|
|
* SPI_GETSCREENSAVEACTIVE: lParam is a pointer to a BOOL which gets TRUE
|
|
* if the screensaver is active else gets false.
|
|
*
|
|
* SPI_SETSCREENSAVEACTIVE: if wParam is TRUE, screensaving is activated
|
|
* else it is deactivated.
|
|
*
|
|
*
|
|
* SPI_SETBLOCKSENDINPUTRESETS:
|
|
* SPI_GETBLOCKSENDINPUTRESETS:
|
|
* wParam is BOOL signifying if this is active or not.
|
|
*
|
|
* SPI_GETLOWPOWERTIMEOUT:
|
|
* SPI_GETPOWEROFFTIMEOUT: wParam is not used
|
|
* lParam is a pointer to an int which gets the appropriate
|
|
* power saving screen blanker timeout value.
|
|
*
|
|
* SPI_SETLOWPOWERTIMEOUT:
|
|
* SPI_SETPOWEROFFTIMEOUT: wParam is the time in seconds for the system
|
|
* to be idle before power saving screen blanking.
|
|
*
|
|
* SPI_GETLOWPOWERACTIVE:
|
|
* SPI_GETPOWEROFFACTIVE: lParam is a pointer to a BOOL which gets TRUE
|
|
* if the power saving screen blanker is active else gets false.
|
|
*
|
|
* SPI_SETLOWPOWERACTIVE:
|
|
* SPI_SETPOWEROFFACTIVE: if wParam is TRUE, power saving screen blanking is
|
|
* activated else it is deactivated.
|
|
*
|
|
* SPI_GETGRIDGRANULARITY: Obsolete. Returns 1 always.
|
|
*
|
|
* SPI_SETGRIDGRANULARITY: Obsolete. Does nothing.
|
|
*
|
|
* SPI_SETDESKWALLPAPER: wParam is not used; lParam is a long ptr to a string
|
|
* that holds the name of the bitmap file to be used as the
|
|
* desktop wall paper.
|
|
*
|
|
* SPI_SETDESKPATTERN: Both wParam and lParam are not used; USER will read the
|
|
* "pattern=" from WIN.INI and make it as the current desktop
|
|
* pattern;
|
|
*
|
|
* SPI_GETICONTITLEWRAP: lParam is LPINT which gets 0 if wrapping if off
|
|
* else gets 1.
|
|
*
|
|
* SPI_SETICONTITLEWRAP: wParam specifies TRUE to turn wrapping on else false
|
|
*
|
|
* SPI_GETMENUDROPALIGNMENT: lParam is LPINT which gets 0 specifies if menus
|
|
* drop left aligned else 1 if drop right aligned.
|
|
*
|
|
* SPI_SETMENUDROPALIGNMENT: wParam 0 specifies if menus drop left aligned else
|
|
* the drop right aligned.
|
|
*
|
|
* SPI_SETDOUBLECLKWIDTH: wParam specifies the width of the rectangle
|
|
* within which the second click of a double click must fall
|
|
* for it to be registered as a double click.
|
|
*
|
|
* SPI_SETDOUBLECLKHEIGHT: wParam specifies the height of the rectangle
|
|
* within which the second click of a double click must fall
|
|
* for it to be registered as a double click.
|
|
*
|
|
* SPI_GETICONTITLELOGFONT: lParam is a pointer to a LOGFONT struct which
|
|
* gets the logfont for the current icon title font. wParam
|
|
* specifies the size of the logfont struct.
|
|
*
|
|
* SPI_SETDOUBLECLICKTIME: wParm specifies the double click time
|
|
*
|
|
* SPI_SETMOUSEBUTTONSWAP: if wParam is 1, swap mouse buttons else if wParam
|
|
* is 0, don't swap buttons
|
|
* SPI_SETDRAGFULLWINDOWS: wParam = fSet.
|
|
* SPI_GETDRAGFULLWINDOWS: returns fSet.
|
|
*
|
|
* SPI_GETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
|
|
* specifies the size of the filterkeys struct.
|
|
*
|
|
* SPI_SETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
|
|
* is not used.
|
|
*
|
|
* SPI_GETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
|
|
* specifies the size of the stickykeys struct.
|
|
*
|
|
* SPI_SETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
|
|
* is not used.
|
|
*
|
|
* SPI_GETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
|
|
* specifies the size of the mousekeys struct.
|
|
*
|
|
* SPI_SETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
|
|
* is not used.
|
|
*
|
|
* SPI_GETACCESSTIMEOUT: lParam is a pointer to an ACCESSTIMEOUT struct.
|
|
* wParam specifies the size of the accesstimeout struct.
|
|
*
|
|
* SPI_SETACCESSTIMEOUT: lParam is a pointer to a ACCESSTIMEOUT struct.
|
|
* wParam is not used.
|
|
*
|
|
* SPI_GETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
|
|
* specifies the size of the togglekeys struct.
|
|
*
|
|
* SPI_SETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
|
|
* is not used.
|
|
*
|
|
* SPI_GETKEYBOARDPREF: lParam is a pointer to a BOOL.
|
|
* wParam is not used.
|
|
*
|
|
* SPI_SETKEYBOARDPREF: wParam is a BOOL.
|
|
* lParam is not used.
|
|
*
|
|
* SPI_GETSCREENREADER: lParam is a pointer to a BOOL.
|
|
* wParam is not used.
|
|
*
|
|
* SPI_SETSCREENREADER: wParam is a BOOL.
|
|
* lParam is not used.
|
|
*
|
|
* SPI_GETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
|
|
* specifies the size of the showsounds struct.
|
|
*
|
|
* SPI_SETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
|
|
* is not used.
|
|
*
|
|
* SPI_GETNONCLIENTMETRICS: lParam is a pointer to a NONCLIENTMETRICSW struct.
|
|
* wPAram is not used.
|
|
*
|
|
* SPI_GETSNAPTODEFBUTTON: lParam is a pointer to a BOOL which gets TRUE
|
|
* if the snap to default push button is active else gets false.
|
|
*
|
|
* SPI_SETSNAPTODEFBUTTON: if wParam is TRUE, dialog boxes will snap the mouse
|
|
* pointer to the default push button when created.
|
|
*
|
|
* SPI_GETFONTSMOOTHING:
|
|
* wParam is unused
|
|
* lParam is LPINT for boolean fFontSmoothing
|
|
*
|
|
* SPI_SETFONTSMOOTHING:
|
|
* wParam is INT for boolean fFontSmoothing
|
|
*
|
|
* SPI_GETWHEELSCROLLLINES: lParam is a pointer to a ULONG to receive the
|
|
* suggested number of lines to scroll when the wheel is
|
|
* rotated. wParam is unused.
|
|
*
|
|
* SPI_SETWHEELSCROLLLINES: wParam is a ULONG containing the suggested number
|
|
* of lines to scroll when the wheel is rotated. lParam is
|
|
* unused.
|
|
*
|
|
* SPI_SETSCREENSAVERRUNNING / SPI_SCREENSAVERRUNNING: not supported on NT.
|
|
* SPI_GETSCREENSAVERRUNNING: wParam - Not used. lParam a pointer to a BOOL which
|
|
* will receive TRUE is a screen saver is running or FALSE otherwise.
|
|
*
|
|
* SPI_SETSHOWIMEUI wParam is TRUE or FALSE
|
|
* SPI_GETSHOWIMEUI neither wParam or lParam used
|
|
*
|
|
* History:
|
|
* 06-28-91 MikeHar Ported.
|
|
* 12-8-93 SanfordS Added SPI_SET/GETDRAGFULLWINDOWS
|
|
* 20-May-1996 adams Added SPI_SET/GETWHEELSCROLLLINES
|
|
* 02-Feb-2002 MMcCr Added SPI_SET/GETBLOCKSENDINPUTRESETS
|
|
\***************************************************************************/
|
|
BOOL xxxSystemParametersInfo(
|
|
UINT wFlag,
|
|
DWORD wParam,
|
|
PVOID lParam,
|
|
UINT flags)
|
|
{
|
|
PPROCESSINFO ppi = PpiCurrent();
|
|
LPWSTR pwszd = L"%d";
|
|
WCHAR szSection[40];
|
|
WCHAR szTemp[40];
|
|
WCHAR szPat[MAX_PATH];
|
|
BOOL fWinIniChanged = FALSE;
|
|
BOOL fAlterWinIni = ((flags & SPIF_UPDATEINIFILE) != 0);
|
|
BOOL fSendWinIniChange = ((flags & SPIF_SENDCHANGE) != 0);
|
|
BOOL fWriteAllowed = !fAlterWinIni;
|
|
ACCESS_MASK amRequest;
|
|
LARGE_UNICODE_STRING strSection;
|
|
int *piTimeOut;
|
|
int iResID;
|
|
TL tlName;
|
|
PUNICODE_STRING pProfileUserName = NULL;
|
|
|
|
UserAssert(IsWinEventNotifyDeferredOK());
|
|
|
|
/*
|
|
* CONSIDER(adams): Many of the SPI_GET* could be implemented
|
|
* on the client side (SnapTo, WheelScrollLines, etc.).
|
|
*/
|
|
|
|
/*
|
|
* Features not implemented.
|
|
*/
|
|
switch (wFlag) {
|
|
case SPI_TIMEOUTS:
|
|
case SPI_KANJIMENU:
|
|
case SPI_LANGDRIVER:
|
|
case SPI_UNUSED39:
|
|
case SPI_UNUSED40:
|
|
case SPI_SETPENWINDOWS:
|
|
|
|
case SPI_GETWINDOWSEXTENSION:
|
|
case SPI_SETSCREENSAVERRUNNING: // same as SPI_SCREENSAVERRUNNING
|
|
|
|
case SPI_GETSERIALKEYS:
|
|
case SPI_SETSERIALKEYS:
|
|
RIPERR1(ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"SPI_ 0x%lx parameter not supported", wFlag);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Perform access check. Always grant access to CSR.
|
|
*/
|
|
if (ppi->Process != gpepCSRSS) {
|
|
switch (wFlag) {
|
|
case SPI_SETBEEP:
|
|
case SPI_SETMOUSE:
|
|
case SPI_SETBORDER:
|
|
case SPI_SETKEYBOARDSPEED:
|
|
case SPI_SETDEFAULTINPUTLANG:
|
|
case SPI_SETSCREENSAVETIMEOUT:
|
|
case SPI_SETSCREENSAVEACTIVE:
|
|
case SPI_SETBLOCKSENDINPUTRESETS:
|
|
case SPI_SETLOWPOWERTIMEOUT:
|
|
case SPI_SETPOWEROFFTIMEOUT:
|
|
case SPI_SETLOWPOWERACTIVE:
|
|
case SPI_SETPOWEROFFACTIVE:
|
|
case SPI_SETGRIDGRANULARITY:
|
|
case SPI_SETDESKWALLPAPER:
|
|
case SPI_SETDESKPATTERN:
|
|
case SPI_SETKEYBOARDDELAY:
|
|
case SPI_SETICONTITLEWRAP:
|
|
case SPI_SETMENUDROPALIGNMENT:
|
|
case SPI_SETDOUBLECLKWIDTH:
|
|
case SPI_SETDOUBLECLKHEIGHT:
|
|
case SPI_SETDOUBLECLICKTIME:
|
|
case SPI_SETMOUSEBUTTONSWAP:
|
|
case SPI_SETICONTITLELOGFONT:
|
|
case SPI_SETFASTTASKSWITCH:
|
|
case SPI_SETFILTERKEYS:
|
|
case SPI_SETTOGGLEKEYS:
|
|
case SPI_SETMOUSEKEYS:
|
|
case SPI_SETSHOWSOUNDS:
|
|
case SPI_SETSTICKYKEYS:
|
|
case SPI_SETACCESSTIMEOUT:
|
|
case SPI_SETSOUNDSENTRY:
|
|
case SPI_SETKEYBOARDPREF:
|
|
case SPI_SETSCREENREADER:
|
|
case SPI_SETSNAPTODEFBUTTON:
|
|
case SPI_SETANIMATION:
|
|
case SPI_SETNONCLIENTMETRICS:
|
|
case SPI_SETICONMETRICS:
|
|
case SPI_SETMINIMIZEDMETRICS:
|
|
case SPI_SETWORKAREA:
|
|
|
|
case SPI_SETFONTSMOOTHING:
|
|
case SPI_SETMOUSEHOVERWIDTH:
|
|
case SPI_SETMOUSEHOVERHEIGHT:
|
|
case SPI_SETMOUSEHOVERTIME:
|
|
case SPI_SETWHEELSCROLLLINES:
|
|
case SPI_SETMENUSHOWDELAY:
|
|
case SPI_SETHIGHCONTRAST:
|
|
case SPI_SETDRAGFULLWINDOWS:
|
|
case SPI_SETDRAGWIDTH:
|
|
case SPI_SETDRAGHEIGHT:
|
|
case SPI_SETCURSORS:
|
|
case SPI_SETICONS:
|
|
case SPI_SETLANGTOGGLE:
|
|
amRequest = WINSTA_WRITEATTRIBUTES;
|
|
break;
|
|
|
|
case SPI_ICONHORIZONTALSPACING:
|
|
case SPI_ICONVERTICALSPACING:
|
|
if (IS_PTR(lParam)) {
|
|
amRequest = WINSTA_READATTRIBUTES;
|
|
} else if (wParam) {
|
|
amRequest = WINSTA_WRITEATTRIBUTES;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((wFlag & SPIF_RANGETYPEMASK) && (wFlag & SPIF_SET)) {
|
|
amRequest = WINSTA_WRITEATTRIBUTES;
|
|
} else {
|
|
amRequest = WINSTA_READATTRIBUTES;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (amRequest == WINSTA_READATTRIBUTES) {
|
|
RETURN_IF_ACCESS_DENIED(ppi->amwinsta, amRequest, FALSE);
|
|
} else {
|
|
UserAssert(amRequest == WINSTA_WRITEATTRIBUTES);
|
|
if (!CheckWinstaWriteAttributesAccess()) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we're reading, then set the write flag to ensure that the
|
|
* return value will be TRUE.
|
|
*/
|
|
if (amRequest == WINSTA_READATTRIBUTES) {
|
|
fWriteAllowed = TRUE;
|
|
}
|
|
} else {
|
|
fWriteAllowed = TRUE;
|
|
}
|
|
|
|
/*
|
|
* Make sure the section buffer is terminated.
|
|
*/
|
|
szSection[0] = 0;
|
|
|
|
switch (wFlag) {
|
|
case SPI_GETBEEP:
|
|
(*(BOOL *)lParam) = TEST_BOOL_PUDF(PUDF_BEEP);
|
|
break;
|
|
|
|
case SPI_SETBEEP:
|
|
if (fAlterWinIni) {
|
|
ServerLoadString(hModuleWin,
|
|
(wParam ? STR_BEEPYES : STR_BEEPNO),
|
|
(LPWSTR)szTemp,
|
|
10);
|
|
|
|
fWinIniChanged = FastUpdateWinIni(NULL,
|
|
PMAP_BEEP,
|
|
STR_BEEP,
|
|
szTemp);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_PUDF(PUDF_BEEP, wParam);
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case SPI_SETMOUSESPEED:
|
|
if (((LONG_PTR) lParam < MOUSE_SENSITIVITY_MIN) || ((LONG_PTR) lParam > MOUSE_SENSITIVITY_MAX)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
swprintf(szTemp, pwszd, lParam);
|
|
fWinIniChanged = FastUpdateWinIni(NULL,
|
|
PMAP_MOUSE,
|
|
STR_MOUSESENSITIVITY,
|
|
szTemp);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
gMouseSensitivity = PtrToLong(lParam);
|
|
gMouseSensitivityFactor = CalculateMouseSensitivity(PtrToLong(lParam));
|
|
|
|
#ifdef SUBPIXEL_MOUSE
|
|
ResetMouseAccelerationCurves();
|
|
#endif // SUBPIXEL_MOUSE
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMOUSESPEED:
|
|
*((LPINT)lParam) = gMouseSensitivity;
|
|
break;
|
|
|
|
case SPI_SETMOUSETRAILS:
|
|
if (fAlterWinIni) {
|
|
swprintf(szTemp, pwszd, wParam);
|
|
fWinIniChanged = FastUpdateWinIni(NULL,
|
|
PMAP_MOUSE,
|
|
STR_MOUSETRAILS,
|
|
szTemp);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SetMouseTrails(wParam);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMOUSETRAILS:
|
|
*((LPINT)lParam) = gMouseTrails ? gMouseTrails + 1 : gMouseTrails;
|
|
break;
|
|
|
|
case SPI_GETMOUSE:
|
|
((LPINT)lParam)[0] = gMouseThresh1;
|
|
((LPINT)lParam)[1] = gMouseThresh2;
|
|
((LPINT)lParam)[2] = gMouseSpeed;
|
|
break;
|
|
|
|
case SPI_SETMOUSE:
|
|
if (fAlterWinIni) {
|
|
BOOL bWritten1, bWritten2, bWritten3;
|
|
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
bWritten1 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, ((LPINT)lParam)[0]);
|
|
bWritten2 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, ((LPINT)lParam)[1]);
|
|
bWritten3 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, ((LPINT)lParam)[2]);
|
|
if (bWritten1 && bWritten2 && bWritten3) {
|
|
fWinIniChanged = TRUE;
|
|
} else {
|
|
/*
|
|
* Attempt to backout any changes.
|
|
*/
|
|
if (bWritten1) {
|
|
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, gMouseThresh1);
|
|
}
|
|
if (bWritten2) {
|
|
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, gMouseThresh2);
|
|
}
|
|
if (bWritten3) {
|
|
UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, gMouseSpeed);
|
|
}
|
|
}
|
|
fWriteAllowed = fWinIniChanged;
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
gMouseThresh1 = ((LPINT)lParam)[0];
|
|
gMouseThresh2 = ((LPINT)lParam)[1];
|
|
gMouseSpeed = ((LPINT)lParam)[2];
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSNAPTODEFBUTTON:
|
|
(*(LPBOOL)lParam) = TEST_BOOL_PUSIF(PUSIF_SNAPTO);
|
|
break;
|
|
|
|
case SPI_SETSNAPTODEFBUTTON:
|
|
wParam = (wParam != 0);
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SNAPTO, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_PUSIF(PUSIF_SNAPTO, wParam);
|
|
}
|
|
|
|
break;
|
|
|
|
case SPI_GETBORDER:
|
|
(*(LPINT)lParam) = gpsi->gclBorder;
|
|
break;
|
|
|
|
case SPI_SETBORDER:
|
|
wParam = max((int)wParam, 1);
|
|
wParam = min(wParam, 50);
|
|
|
|
if (wParam == gpsi->gclBorder) {
|
|
/*
|
|
* If border size doesn't change, don't waste time.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
xxxSetAndDrawNCMetrics(pProfileUserName, wParam, NULL);
|
|
|
|
/*
|
|
* Nice magic number of 3. So if the border is set to 1, there
|
|
* are actualy 4 pixels in the border.
|
|
*/
|
|
bSetDevDragWidth(gpDispInfo->hDev, gpsi->gclBorder + BORDER_EXTRA);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
break;
|
|
|
|
case SPI_GETFONTSMOOTHING:
|
|
(*(LPINT)lParam) = !!(GreGetFontEnumeration() & FE_AA_ON);
|
|
break;
|
|
|
|
case SPI_SETFONTSMOOTHING:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_FONTSMOOTHING)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
|
|
wParam = (wParam ? FE_AA_ON : 0);
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_FONTSMOOTHING, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
GreSetFontEnumeration(wParam | FE_SET_AA);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETKEYBOARDSPEED:
|
|
(*(int *)lParam) = (gnKeyboardSpeed & KSPEED_MASK);
|
|
break;
|
|
|
|
case SPI_SETKEYBOARDSPEED:
|
|
/*
|
|
* Limit the range to max value; SetKeyboardRate takes both speed
|
|
* and delay.
|
|
*/
|
|
if (wParam > KSPEED_MASK) { // KSPEED_MASK == KSPEED_MAX
|
|
wParam = KSPEED_MASK;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYSPEED, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
gnKeyboardSpeed = (gnKeyboardSpeed & ~KSPEED_MASK) | wParam;
|
|
SetKeyboardRate(gnKeyboardSpeed);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETKEYBOARDDELAY:
|
|
(*(int *)lParam) = (gnKeyboardSpeed & KDELAY_MASK) >> KDELAY_SHIFT;
|
|
break;
|
|
|
|
case SPI_SETKEYBOARDDELAY:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYDELAY, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
gnKeyboardSpeed = (gnKeyboardSpeed & ~KDELAY_MASK) | (wParam << KDELAY_SHIFT);
|
|
SetKeyboardRate(gnKeyboardSpeed);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETLANGTOGGLE:
|
|
|
|
/*
|
|
* wParam unused, lParam unused. Simply reread the registry setting.
|
|
*/
|
|
return GetKbdLangSwitch(NULL);
|
|
|
|
break;
|
|
|
|
case SPI_GETDEFAULTINPUTLANG:
|
|
/*
|
|
* wParam unused. lParam is a pointer to buffer to store hkl.
|
|
*/
|
|
UserAssert(gspklBaseLayout != NULL);
|
|
(*(HKL *)lParam) = gspklBaseLayout->hkl;
|
|
break;
|
|
|
|
case SPI_SETDEFAULTINPUTLANG: {
|
|
PKL pkl;
|
|
/*
|
|
* wParam unused. lParam is new language of hkl (depending on
|
|
* whether the hiword is set).
|
|
*/
|
|
pkl = HKLtoPKL(PtiCurrent(), *(HKL *)lParam);
|
|
if (pkl == NULL) {
|
|
return FALSE;
|
|
}
|
|
if (fWriteAllowed) {
|
|
Lock(&gspklBaseLayout, pkl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SPI_ICONHORIZONTALSPACING:
|
|
if (IS_PTR(lParam)) {
|
|
*(LPINT)lParam = SYSMET(CXICONSPACING);
|
|
} else if (wParam) {
|
|
|
|
/*
|
|
* Make sure icon spacing is reasonable.
|
|
*/
|
|
wParam = max(wParam, (DWORD)SYSMET(CXICON));
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONHORZSPACING, wParam );
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SYSMET(CXICONSPACING) = (UINT)wParam;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_ICONVERTICALSPACING:
|
|
if (IS_PTR(lParam)) {
|
|
*(LPINT)lParam = SYSMET(CYICONSPACING);
|
|
} else if (wParam) {
|
|
wParam = max(wParam, (DWORD)SYSMET(CYICON));
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONVERTSPACING, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SYSMET(CYICONSPACING) = (UINT)wParam;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSCREENSAVETIMEOUT:
|
|
piTimeOut = &giScreenSaveTimeOutMs;
|
|
goto HandleGetTimeouts;
|
|
|
|
case SPI_GETLOWPOWERTIMEOUT:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giLowPowerTimeOutMs;
|
|
goto HandleGetTimeouts;
|
|
|
|
case SPI_GETPOWEROFFTIMEOUT:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giPowerOffTimeOutMs;
|
|
|
|
HandleGetTimeouts:
|
|
/*
|
|
* If the screen saver is disabled, store this fact as a negative
|
|
* time out value (we give the Control Panel the absolute value
|
|
* of the screen saver time out). We store this in milliseconds.
|
|
*/
|
|
if (*piTimeOut < 0) {
|
|
(*(int *)lParam) = -*piTimeOut / 1000;
|
|
} else {
|
|
(*(int *)lParam) = *piTimeOut / 1000;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETSCREENSAVETIMEOUT:
|
|
piTimeOut = &giScreenSaveTimeOutMs;
|
|
iResID = STR_SCREENSAVETIMEOUT;
|
|
goto HandleSetTimeouts;
|
|
|
|
case SPI_SETLOWPOWERTIMEOUT:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giLowPowerTimeOutMs;
|
|
iResID = STR_LOWPOWERTIMEOUT;
|
|
goto HandleSetTimeouts;
|
|
|
|
case SPI_SETPOWEROFFTIMEOUT:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giPowerOffTimeOutMs;
|
|
iResID = STR_POWEROFFTIMEOUT;
|
|
|
|
HandleSetTimeouts:
|
|
if (gfSwitchInProgress) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Maintain the screen save active/inactive state when setting the
|
|
* time out value. Timeout value is given in seconds but stored
|
|
* in milliseconds
|
|
*/
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
|
|
// Call video driver here to exit power down mode.
|
|
// KdPrint(("Exit video power down mode\n"));
|
|
DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
|
|
}
|
|
glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
|
|
if (!gbBlockSendInputResets) {
|
|
glinp.timeLastInputMessage = NtGetTickCount();
|
|
}
|
|
|
|
if (*piTimeOut < 0) {
|
|
*piTimeOut = -((int)wParam);
|
|
} else {
|
|
*piTimeOut = wParam;
|
|
}
|
|
*piTimeOut *= 1000;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETBLOCKSENDINPUTRESETS:
|
|
(*(BOOL *)lParam) = (gbBlockSendInputResets != 0);
|
|
break;
|
|
|
|
case SPI_GETSCREENSAVEACTIVE:
|
|
(*(BOOL *)lParam) = (giScreenSaveTimeOutMs > 0);
|
|
break;
|
|
|
|
case SPI_GETLOWPOWERACTIVE:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
|
|
return FALSE;
|
|
}
|
|
(*(BOOL *)lParam) = (giLowPowerTimeOutMs > 0);
|
|
break;
|
|
|
|
case SPI_GETPOWEROFFACTIVE:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
|
|
return FALSE;
|
|
}
|
|
(*(BOOL *)lParam) = (giPowerOffTimeOutMs > 0);
|
|
break;
|
|
|
|
case SPI_SETSCREENSAVEACTIVE:
|
|
piTimeOut = &giScreenSaveTimeOutMs;
|
|
iResID = STR_SCREENSAVEACTIVE;
|
|
goto HandleSetActive;
|
|
|
|
case SPI_SETLOWPOWERACTIVE:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giLowPowerTimeOutMs;
|
|
iResID = STR_LOWPOWERACTIVE;
|
|
goto HandleSetActive;
|
|
|
|
case SPI_SETPOWEROFFACTIVE:
|
|
if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
|
|
return FALSE;
|
|
}
|
|
piTimeOut = &giPowerOffTimeOutMs;
|
|
iResID = STR_POWEROFFACTIVE;
|
|
|
|
HandleSetActive:
|
|
if (gfSwitchInProgress) {
|
|
return FALSE;
|
|
}
|
|
|
|
wParam = (wParam != 0);
|
|
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
|
|
// Call video driver here to exit power down mode.
|
|
// KdPrint(("Exit video power down mode\n"));
|
|
DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
|
|
}
|
|
glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
|
|
|
|
if (!gbBlockSendInputResets) {
|
|
glinp.timeLastInputMessage = NtGetTickCount();
|
|
}
|
|
|
|
if ((*piTimeOut < 0 && wParam) ||
|
|
(*piTimeOut >= 0 && !wParam)) {
|
|
*piTimeOut = -*piTimeOut;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_SETBLOCKSENDINPUTRESETS:
|
|
wParam = (wParam != 0);
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(STR_BLOCKSENDINPUTRESETS))) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_BLOCKSENDINPUTRESETS, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
gbBlockSendInputResets = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDESKWALLPAPER:
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DTBITMAP)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
if (wParam != (WPARAM)-1) {
|
|
/*
|
|
* Save current wallpaper in case of failure.
|
|
*
|
|
* Unlike the rest of the per-user settings that got updated
|
|
* in xxxUpdatePerUserSystemParameters, the wallpaper is
|
|
* being updated via a direct call to SystemParametersInfo
|
|
* from UpdatePerUserSystemParameters. Force remote settings
|
|
* check in this case.
|
|
*/
|
|
FastGetProfileStringFromIDW(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DTBITMAP,
|
|
TEXT(""),
|
|
szPat,
|
|
ARRAY_SIZE(szPat),
|
|
POLICY_REMOTE);
|
|
|
|
fWinIniChanged = FastUpdateWinIni(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DTBITMAP,
|
|
(LPWSTR)lParam);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
} else {
|
|
fWriteAllowed = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
if (xxxSetDeskWallpaper(pProfileUserName,(LPWSTR)lParam)) {
|
|
if (grpdeskRitInput) {
|
|
xxxInternalInvalidate(grpdeskRitInput->pDeskInfo->spwnd,
|
|
HRGN_FULL,
|
|
RDW_INVALIDATE |
|
|
RDW_ERASE |
|
|
RDW_FRAME |
|
|
RDW_ALLCHILDREN);
|
|
}
|
|
} else if (fAlterWinIni && (wParam != 0xFFFFFFFF)) {
|
|
/*
|
|
* Backout any change to win.ini.
|
|
*/
|
|
FastUpdateWinIni(pProfileUserName,PMAP_DESKTOP, STR_DTBITMAP, szPat);
|
|
fWinIniChanged = FALSE;
|
|
fWriteAllowed = fWinIniChanged;
|
|
} else if (!fAlterWinIni) {
|
|
/*
|
|
* Bug 304109 - joejo
|
|
* Make sure we return a 0 retval if we didn't do anything!
|
|
*/
|
|
fWinIniChanged = FALSE;
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
}
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
break;
|
|
|
|
case SPI_GETDESKWALLPAPER:
|
|
/*
|
|
* Get the string from the gobal var, not the registry, as it's
|
|
* more current.
|
|
*/
|
|
if (gpszWall != NULL) {
|
|
/*
|
|
* Copy the global wallpaper name ONLY if noni-null.
|
|
*/
|
|
wcscpy(lParam, gpszWall);
|
|
} else {
|
|
/*
|
|
* Null out the string so no garbage can corrupt the user's
|
|
* buffer.
|
|
*/
|
|
(*(LPWSTR)lParam) = (WCHAR)0;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDESKPATTERN: {
|
|
BOOL fRet;
|
|
|
|
if (wParam == -1 && lParam != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DESKPATTERN)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni && wParam != -1) {
|
|
/*
|
|
* Save the current pattern in case of failure.
|
|
*/
|
|
FastGetProfileStringFromIDW(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DESKPATTERN,
|
|
TEXT(""),
|
|
szPat,
|
|
ARRAY_SIZE(szPat),
|
|
0);
|
|
|
|
fWinIniChanged = FastUpdateWinIni(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DESKPATTERN,
|
|
(LPWSTR)lParam);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
fRet = xxxSetDeskPattern(pProfileUserName,
|
|
wParam == -1 ? (LPWSTR)-1 : (LPWSTR)lParam,
|
|
FALSE);
|
|
|
|
if (!fRet) {
|
|
/*
|
|
* Back out any change to win.ini.
|
|
*/
|
|
if (fAlterWinIni && wParam != -1) {
|
|
FastUpdateWinIni(pProfileUserName,
|
|
PMAP_DESKTOP,
|
|
STR_DESKPATTERN,
|
|
szPat);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
break;
|
|
|
|
case SPI_GETICONTITLEWRAP:
|
|
*((int *)lParam) = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
|
|
break;
|
|
|
|
case SPI_SETICONTITLEWRAP:
|
|
wParam = (wParam != 0);
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONTITLEWRAP, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_PUDF(PUDF_ICONTITLEWRAP, wParam);
|
|
xxxMetricsRecalc(CALC_FRAME, 0, 0, 0, 0);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDRAGWIDTH:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGWIDTH)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGWIDTH, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SYSMET(CXDRAG) = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDRAGHEIGHT:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGHEIGHT)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGHEIGHT, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SYSMET(CYDRAG) = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMENUDROPALIGNMENT:
|
|
(*(int *)lParam) = (SYSMET(MENUDROPALIGNMENT));
|
|
break;
|
|
|
|
case SPI_SETMENUDROPALIGNMENT:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_WINDOWSU, STR_MENUDROPALIGNMENT, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SYSMET(MENUDROPALIGNMENT) = (BOOL)(wParam != 0);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDOUBLECLKWIDTH:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKWIDTH, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SYSMET(CXDOUBLECLK) = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETDOUBLECLKHEIGHT:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKHEIGHT, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SYSMET(CYDOUBLECLK) = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETICONTITLELOGFONT:
|
|
GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), lParam);
|
|
break;
|
|
|
|
case SPI_SETICONTITLELOGFONT:
|
|
{
|
|
if (lParam != NULL) {
|
|
if (wParam != sizeof(LOGFONTW)) {
|
|
return FALSE;
|
|
}
|
|
} else if (wParam) {
|
|
return FALSE;
|
|
}
|
|
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
fWinIniChanged = xxxSetSPIMetrics(pProfileUserName, wFlag, lParam, fAlterWinIni);
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
if (fAlterWinIni) {
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SPI_SETDOUBLECLICKTIME:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL,PMAP_MOUSE, STR_DBLCLKSPEED, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
_SetDoubleClickTime((UINT)wParam);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETANIMATION: {
|
|
LPANIMATIONINFO lpai = (LPANIMATIONINFO) lParam;
|
|
|
|
if (lpai == NULL || wParam != sizeof(ANIMATIONINFO)) {
|
|
return FALSE;
|
|
}
|
|
|
|
lpai->cbSize = sizeof(ANIMATIONINFO);
|
|
lpai->iMinAnimate = TEST_BOOL_PUDF(PUDF_ANIMATE);
|
|
|
|
break;
|
|
}
|
|
|
|
case SPI_GETNONCLIENTMETRICS: {
|
|
LPNONCLIENTMETRICS lpnc = (LPNONCLIENTMETRICS) lParam;
|
|
if (lpnc == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
GetWindowNCMetrics(lpnc);
|
|
break;
|
|
}
|
|
|
|
case SPI_GETMINIMIZEDMETRICS: {
|
|
LPMINIMIZEDMETRICS lpmin = (LPMINIMIZEDMETRICS)lParam;
|
|
|
|
lpmin->cbSize = sizeof(MINIMIZEDMETRICS);
|
|
|
|
lpmin->iWidth = SYSMET(CXMINIMIZED) - 2 * SYSMET(CXFIXEDFRAME);
|
|
lpmin->iHorzGap = SYSMET(CXMINSPACING) - SYSMET(CXMINIMIZED);
|
|
lpmin->iVertGap = SYSMET(CYMINSPACING) - SYSMET(CYMINIMIZED);
|
|
lpmin->iArrange = SYSMET(ARRANGE);
|
|
|
|
break;
|
|
}
|
|
|
|
case SPI_GETICONMETRICS: {
|
|
LPICONMETRICS lpicon = (LPICONMETRICS)lParam;
|
|
|
|
lpicon->cbSize = sizeof(ICONMETRICS);
|
|
|
|
lpicon->iHorzSpacing = SYSMET(CXICONSPACING);
|
|
lpicon->iVertSpacing = SYSMET(CYICONSPACING);
|
|
lpicon->iTitleWrap = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
|
|
GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), &(lpicon->lfFont));
|
|
|
|
break;
|
|
}
|
|
|
|
case SPI_SETANIMATION:
|
|
case SPI_SETNONCLIENTMETRICS:
|
|
case SPI_SETICONMETRICS:
|
|
case SPI_SETMINIMIZEDMETRICS:
|
|
{
|
|
fWinIniChanged = xxxSetSPIMetrics(NULL, wFlag, lParam, fAlterWinIni);
|
|
if (fAlterWinIni) {
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
ServerLoadString(hModuleWin, STR_METRICS, szSection, ARRAY_SIZE(szSection));
|
|
break;
|
|
}
|
|
case SPI_SETMOUSEBUTTONSWAP:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SWAPBUTTONS, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
_SwapMouseButton((wParam != 0));
|
|
}
|
|
break;
|
|
|
|
case SPI_GETFASTTASKSWITCH:
|
|
*((PINT)lParam) = TRUE; // Do the work so we don't anger anybody.
|
|
|
|
case SPI_SETFASTTASKSWITCH:
|
|
RIPMSG0(RIP_WARNING,"SPI_SETFASTTASKSWITCH and SPI_GETFASTTASKSWITCH are obsolete actions.");
|
|
break;
|
|
|
|
case SPI_GETWORKAREA:
|
|
CopyRect((LPRECT)lParam, &GetPrimaryMonitor()->rcWork);
|
|
break;
|
|
|
|
case SPI_SETWORKAREA:
|
|
{
|
|
RECT rcNewWork;
|
|
LPRECT lprcNewWork;
|
|
PMONITOR pMonitorWork;
|
|
|
|
lprcNewWork = (LPRECT)lParam;
|
|
|
|
/*
|
|
* Validate Rectangle.
|
|
*/
|
|
if (lprcNewWork != NULL &&
|
|
(lprcNewWork->right < lprcNewWork->left ||
|
|
lprcNewWork->bottom < lprcNewWork->top)) {
|
|
|
|
RIPMSG0(RIP_WARNING, "Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...)\n");
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Figure out which monitor has the working area.
|
|
*/
|
|
if (!lprcNewWork) {
|
|
pMonitorWork = GetPrimaryMonitor();
|
|
lprcNewWork = &pMonitorWork->rcMonitor;
|
|
} else {
|
|
pMonitorWork = _MonitorFromRect(lprcNewWork, MONITOR_DEFAULTTOPRIMARY);
|
|
}
|
|
|
|
|
|
/*
|
|
* Get new working area, clipped to monitor of course.
|
|
*/
|
|
if (!IntersectRect(&rcNewWork, lprcNewWork, &pMonitorWork->rcMonitor) ||
|
|
!EqualRect(&rcNewWork, lprcNewWork))
|
|
{
|
|
/*
|
|
* Complain.
|
|
*/
|
|
RIPERR4(
|
|
ERROR_INVALID_PARAMETER,
|
|
RIP_WARNING,
|
|
"Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...) %d, %d, %d, %d",
|
|
lprcNewWork->left, lprcNewWork->top, lprcNewWork->right, lprcNewWork->bottom);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!EqualRect(&pMonitorWork->rcWork, &rcNewWork)) {
|
|
PMONITORRECTS pmr;
|
|
|
|
/*
|
|
* If we are going to reposition windows, remember the old
|
|
* monitor positions for xxxDesktopRecalc.
|
|
*/
|
|
if (wParam) {
|
|
pmr = SnapshotMonitorRects();
|
|
if (!pmr) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
pMonitorWork->rcWork = rcNewWork;
|
|
if (pMonitorWork == GetPrimaryMonitor()) {
|
|
SetDesktopMetrics();
|
|
}
|
|
|
|
/*
|
|
* Reposition windows.
|
|
*/
|
|
if (wParam) {
|
|
TL tlPool;
|
|
|
|
ThreadLockPool(PtiCurrent(), pmr, &tlPool);
|
|
xxxDesktopRecalc(pmr);
|
|
ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
|
|
}
|
|
|
|
fWinIniChanged = TRUE;
|
|
}
|
|
|
|
fWriteAllowed = TRUE;
|
|
break;
|
|
}
|
|
|
|
case SPI_SETDRAGFULLWINDOWS:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGFULLWINDOWS)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
wParam = (wParam == 1);
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGFULLWINDOWS, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_PUDF(PUDF_DRAGFULLWINDOWS, wParam);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETDRAGFULLWINDOWS:
|
|
*((PINT)lParam) = TEST_BOOL_PUDF(PUDF_DRAGFULLWINDOWS);
|
|
break;
|
|
|
|
case SPI_GETFILTERKEYS:
|
|
{
|
|
LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
|
|
int cbSkip = sizeof(gFilterKeys.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pFK + cbSkip),
|
|
(LPVOID)((LPBYTE)&gFilterKeys + cbSkip),
|
|
pFK->cbSize - cbSkip);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETFILTERKEYS:
|
|
{
|
|
LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
|
|
|
|
if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* SlowKeys and BounceKeys cannot both be active simultaneously
|
|
*/
|
|
if (pFK->iWaitMSec && pFK->iBounceMSec) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*/
|
|
if ((pFK->dwFlags & FKF_VALID) != pFK->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* FKF_AVAILABLE can't be set via API. Use registry value.
|
|
*/
|
|
if (TEST_ACCESSFLAG(FilterKeys, FKF_AVAILABLE)) {
|
|
pFK->dwFlags |= FKF_AVAILABLE;
|
|
} else {
|
|
pFK->dwFlags &= ~FKF_AVAILABLE;
|
|
}
|
|
|
|
if (pFK->iWaitMSec > 20000 ||
|
|
pFK->iDelayMSec > 20000 ||
|
|
pFK->iRepeatMSec > 20000 ||
|
|
pFK->iBounceMSec > 20000) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
fWinIniChanged = SetFilterKeys(pProfileUserName, pFK);
|
|
fWriteAllowed = fWinIniChanged;
|
|
if (!fWinIniChanged) {
|
|
/*
|
|
* Back out any changes to win.ini.
|
|
*/
|
|
SetFilterKeys(pProfileUserName, &gFilterKeys);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gFilterKeys, pFK, pFK->cbSize);
|
|
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gFilterKeys.cbSize = sizeof(FILTERKEYS);
|
|
|
|
if (!TEST_ACCESSFLAG(FilterKeys, FKF_FILTERKEYSON)) {
|
|
StopFilterKeysTimers();
|
|
}
|
|
SetAccessEnabledFlag();
|
|
if (FCallHookTray()) {
|
|
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
|
|
ACCESS_FILTERKEYS,
|
|
0,
|
|
WH_SHELL);
|
|
}
|
|
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_FILTERKEYS);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSTICKYKEYS:
|
|
{
|
|
LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
|
|
int cbSkip = sizeof(gStickyKeys.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pSK + cbSkip),
|
|
(LPVOID)((LPBYTE)&gStickyKeys + cbSkip),
|
|
pSK->cbSize - cbSkip);
|
|
|
|
pSK->dwFlags &= ~SKF_STATEINFO;
|
|
pSK->dwFlags |= (gLatchBits&0xff) <<24;
|
|
|
|
#if SKF_LALTLATCHED != 0x10000000
|
|
#error SKF_LALTLATCHED value is incorrect
|
|
#endif
|
|
#if SKF_LCTLLATCHED != 0x04000000
|
|
#error SKF_LCTLLATCHED value is incorrect
|
|
#endif
|
|
#if SKF_LSHIFTLATCHED != 0x01000000
|
|
#error SKF_LSHIFTLATCHED value is incorrect
|
|
#endif
|
|
#if SKF_RALTLATCHED != 0x20000000
|
|
#error SKF_RALTLATCHED value is incorrect
|
|
#endif
|
|
#if SKF_RCTLLATCHED != 0x08000000
|
|
#error SKF_RCTLLATCHED value is incorrect
|
|
#endif
|
|
#if SKF_RSHIFTLATCHED != 0x02000000
|
|
#error SKF_RSHIFTLATCHED value is incorrect
|
|
#endif
|
|
pSK->dwFlags |= (gLockBits&0xff) <<16;
|
|
#if SKF_LALTLOCKED != 0x00100000
|
|
#error SKF_LALTLOCKED value is incorrect
|
|
#endif
|
|
#if SKF_LCTLLOCKED != 0x00040000
|
|
#error SKF_LCTLLOCKED value is incorrect
|
|
#endif
|
|
#if SKF_LSHIFTLOCKED != 0x00010000
|
|
#error SKF_LSHIFTLOCKED value is incorrect
|
|
#endif
|
|
#if SKF_RALTLOCKED != 0x00200000
|
|
#error SKF_RALTLOCKED value is incorrect
|
|
#endif
|
|
#if SKF_RCTLLOCKED != 0x00080000
|
|
#error SKF_RCTLLOCKED value is incorrect
|
|
#endif
|
|
#if SKF_RSHIFTLOCKED != 0x00020000
|
|
#error SKF_RSHIFTLOCKED value is incorrect
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SPI_SETSTICKYKEYS:
|
|
{
|
|
LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
|
|
BOOL fWasOn;
|
|
|
|
fWasOn = TEST_BOOL_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON);
|
|
if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*
|
|
* Don't penalize them for using data from SPI_GETSTICKYKEYS,
|
|
* though.
|
|
*/
|
|
pSK->dwFlags &= ~SKF_STATEINFO;
|
|
if ((pSK->dwFlags & SKF_VALID) != pSK->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* SKF_AVAILABLE can't be set via API. Use registry value.
|
|
*/
|
|
if (TEST_ACCESSFLAG(StickyKeys, SKF_AVAILABLE)) {
|
|
pSK->dwFlags |= SKF_AVAILABLE;
|
|
} else {
|
|
pSK->dwFlags &= ~SKF_AVAILABLE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
swprintf(szTemp, pwszd, pSK->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(NULL,
|
|
PMAP_STICKYKEYS,
|
|
L"Flags",
|
|
szTemp);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gStickyKeys, pSK, pSK->cbSize);
|
|
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gStickyKeys.cbSize = sizeof(STICKYKEYS);
|
|
if (!TEST_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON) && fWasOn) {
|
|
xxxTurnOffStickyKeys();
|
|
}
|
|
|
|
SetAccessEnabledFlag();
|
|
if (FCallHookTray()) {
|
|
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
|
|
ACCESS_STICKYKEYS,
|
|
0,
|
|
WH_SHELL);
|
|
}
|
|
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_STICKYKEYS);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETTOGGLEKEYS:
|
|
{
|
|
LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
|
|
int cbSkip = sizeof(gToggleKeys.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pTK + cbSkip),
|
|
(LPVOID)((LPBYTE)&gToggleKeys + cbSkip),
|
|
pTK->cbSize - cbSkip);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETTOGGLEKEYS:
|
|
{
|
|
LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
|
|
|
|
if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*/
|
|
if ((pTK->dwFlags & TKF_VALID) != pTK->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* TKF_AVAILABLE can't be set via API. Use registry value.
|
|
*/
|
|
if (TEST_ACCESSFLAG(ToggleKeys, TKF_AVAILABLE)) {
|
|
pTK->dwFlags |= TKF_AVAILABLE;
|
|
} else {
|
|
pTK->dwFlags &= ~TKF_AVAILABLE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
swprintf(szTemp, pwszd, pTK->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(NULL,
|
|
PMAP_TOGGLEKEYS,
|
|
L"Flags",
|
|
szTemp);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gToggleKeys, pTK, pTK->cbSize);
|
|
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gToggleKeys.cbSize = sizeof(TOGGLEKEYS);
|
|
|
|
SetAccessEnabledFlag();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMOUSEKEYS:
|
|
{
|
|
LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
|
|
int cbSkip = sizeof(gMouseKeys.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pMK + cbSkip),
|
|
(LPVOID)((LPBYTE)&gMouseKeys + cbSkip),
|
|
pMK->cbSize - cbSkip);
|
|
|
|
|
|
pMK->dwFlags &= ~MKF_STATEINFO;
|
|
if (gbMKMouseMode) {
|
|
pMK->dwFlags |= MKF_MOUSEMODE;
|
|
}
|
|
|
|
pMK->dwFlags |= (gwMKButtonState & 3) << 24;
|
|
#if MOUSE_BUTTON_LEFT != 0x01
|
|
#error MOUSE_BUTTON_LEFT value is incorrect
|
|
#endif
|
|
#if MOUSE_BUTTON_RIGHT != 0x02
|
|
#error MOUSE_BUTTON_RIGHT value is incorrect
|
|
#endif
|
|
#if MKF_LEFTBUTTONDOWN != 0x01000000
|
|
#error MKF_LEFTBUTTONDOWN value is incorrect
|
|
#endif
|
|
#if MKF_RIGHTBUTTONDOWN != 0x02000000
|
|
#error MKF_RIGHTBUTTONDOWN value is incorrect
|
|
#endif
|
|
|
|
pMK->dwFlags |= (gwMKCurrentButton & 3)<< 28;
|
|
#if MKF_LEFTBUTTONSEL != 0x10000000
|
|
#error MKF_LEFTBUTTONSEL value is incorrect
|
|
#endif
|
|
#if MKF_RIGHTBUTTONSEL != 0x20000000
|
|
#error MKF_RIGHTBUTTONSEL value is incorrect
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case SPI_SETMOUSEKEYS:
|
|
{
|
|
LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
|
|
|
|
if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*
|
|
* Don't penalize them for using data from SPI_GETMOUSEKEYS.
|
|
*/
|
|
pMK->dwFlags &= ~MKF_STATEINFO;
|
|
if ((pMK->dwFlags & MKF_VALID) != pMK->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* MKF_AVAILABLE can't be set via API. Use registry value.
|
|
*/
|
|
if (TEST_ACCESSFLAG(MouseKeys, MKF_AVAILABLE)) {
|
|
pMK->dwFlags |= MKF_AVAILABLE;
|
|
} else {
|
|
pMK->dwFlags &= ~MKF_AVAILABLE;
|
|
}
|
|
|
|
if (pMK->iMaxSpeed < MAXSPEED_MIN || pMK->iMaxSpeed > MAXSPEED_MAX) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pMK->iTimeToMaxSpeed < TIMETOMAXSPEED_MIN || pMK->iTimeToMaxSpeed > TIMETOMAXSPEED_MAX) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
fWinIniChanged = SetMouseKeys(pProfileUserName, pMK);
|
|
fWriteAllowed = fWinIniChanged;
|
|
if (!fWinIniChanged) {
|
|
/*
|
|
* Back out any changes to win.ini.
|
|
*/
|
|
SetMouseKeys(pProfileUserName, &gMouseKeys);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gMouseKeys, pMK, pMK->cbSize);
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gMouseKeys.cbSize = sizeof(MOUSEKEYS);
|
|
|
|
CalculateMouseTable();
|
|
|
|
if (TEST_ACCESSFLAG(MouseKeys, MKF_MOUSEKEYSON)) {
|
|
if ((TestAsyncKeyStateToggle(gNumLockVk) != 0) ^
|
|
(TEST_ACCESSFLAG(MouseKeys, MKF_REPLACENUMBERS) != 0)) {
|
|
gbMKMouseMode = TRUE;
|
|
} else {
|
|
gbMKMouseMode = FALSE;
|
|
}
|
|
MKShowMouseCursor();
|
|
} else {
|
|
MKHideMouseCursor();
|
|
}
|
|
|
|
SetAccessEnabledFlag();
|
|
|
|
if (FCallHookTray()) {
|
|
xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
|
|
ACCESS_MOUSEKEYS,
|
|
0,
|
|
WH_SHELL);
|
|
}
|
|
PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_MOUSEKEYS);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETHIGHCONTRAST:
|
|
{
|
|
LPHIGHCONTRAST pHC = (LPHIGHCONTRAST)lParam;
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
|
|
pHC->dwFlags = gHighContrast.dwFlags;
|
|
|
|
/*
|
|
* A hostile app could deallocate the memory using a second thread,
|
|
* so shelter the copy with a try.
|
|
*/
|
|
try {
|
|
RtlCopyMemory(pHC->lpszDefaultScheme, gHighContrastDefaultScheme, MAX_SCHEME_NAME_SIZE * sizeof(WCHAR));
|
|
} except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case SPI_SETHIGHCONTRAST:
|
|
{
|
|
LPINTERNALSETHIGHCONTRAST pHC = (LPINTERNALSETHIGHCONTRAST)lParam;
|
|
WCHAR wcDefaultScheme[MAX_SCHEME_NAME_SIZE];
|
|
|
|
if (pHC->usDefaultScheme.Length >= MAX_SCHEME_NAME_SIZE*sizeof(WCHAR)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pHC->usDefaultScheme.Buffer) {
|
|
/*
|
|
* Only set the scheme if the user specifies a scheme. An
|
|
* empty buffer is ignored. We do the copy here so that we
|
|
* don't need to put a try/except around the
|
|
* WriteProfileString code.
|
|
*/
|
|
|
|
try {
|
|
RtlCopyMemory(wcDefaultScheme, pHC->usDefaultScheme.Buffer, pHC->usDefaultScheme.Length);
|
|
} except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
wcDefaultScheme[pHC->usDefaultScheme.Length / sizeof(WCHAR)] = 0;
|
|
|
|
if (fAlterWinIni) {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
swprintf(szTemp, pwszd, pHC->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_HIGHCONTRAST,
|
|
L"Flags",
|
|
szTemp
|
|
);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
|
|
/*
|
|
* Note -- we do not write anything if there is no default
|
|
* scheme from the app. This is consistent with Win95/Win98
|
|
* behavior.
|
|
*/
|
|
if (pHC->usDefaultScheme.Buffer) {
|
|
fWinIniChanged |= FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_HIGHCONTRAST,
|
|
TEXT("High Contrast Scheme"),
|
|
wcDefaultScheme);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
DWORD dwFlagsOld = gHighContrast.dwFlags;
|
|
LPARAM lp = fAlterWinIni ? 0 : ACCESS_HIGHCONTRASTNOREG;
|
|
|
|
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTOFF) != ACCESS_HIGHCONTRASTOFFNOREG
|
|
#error ACCESS_HIGHCONTRASTOFF value is incorrect
|
|
#endif
|
|
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTON) != ACCESS_HIGHCONTRASTONNOREG
|
|
#error ACCESS_HIGHCONTRASTON value is incorrect
|
|
#endif
|
|
#if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTCHANGE) != ACCESS_HIGHCONTRASTCHANGENOREG
|
|
#error ACCESS_HIGHCONTRASTCHANGE value is incorrect
|
|
#endif
|
|
|
|
/*
|
|
* If a NULL is specified in the lpszDefaultScheme, then it
|
|
* is not changed. This is consistent with Win95/Win98
|
|
* behavior.
|
|
*/
|
|
if (pHC->usDefaultScheme.Buffer) {
|
|
wcscpy(gHighContrastDefaultScheme, wcDefaultScheme);
|
|
}
|
|
|
|
gHighContrast.dwFlags = pHC->dwFlags;
|
|
|
|
SetAccessEnabledFlag();
|
|
|
|
/*
|
|
* Now, post message to turn high contrast on or off.
|
|
*/
|
|
if (pHC->dwFlags & HCF_HIGHCONTRASTON) {
|
|
_PostMessage(gspwndLogonNotify,
|
|
WM_LOGONNOTIFY,
|
|
LOGON_ACCESSNOTIFY,
|
|
(dwFlagsOld & HCF_HIGHCONTRASTON) ?
|
|
(ACCESS_HIGHCONTRASTCHANGE | lp) :
|
|
(ACCESS_HIGHCONTRASTON | lp));
|
|
} else {
|
|
_PostMessage(gspwndLogonNotify,
|
|
WM_LOGONNOTIFY,
|
|
LOGON_ACCESSNOTIFY,
|
|
ACCESS_HIGHCONTRASTOFF | lp);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SPI_GETACCESSTIMEOUT:
|
|
{
|
|
LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
|
|
int cbSkip = sizeof(gAccessTimeOut.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pTO + cbSkip),
|
|
(LPVOID)((LPBYTE)&gAccessTimeOut + cbSkip),
|
|
pTO->cbSize - cbSkip);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETACCESSTIMEOUT:
|
|
{
|
|
LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
|
|
|
|
if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*/
|
|
if ((pTO->dwFlags & ATF_VALID) != pTO->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pTO->iTimeOutMSec > 3600000) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
swprintf(szTemp, pwszd, pTO->dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_TIMEOUT,
|
|
L"Flags",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, pTO->iTimeOutMSec);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_TIMEOUT,
|
|
L"TimeToWait",
|
|
szTemp);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
if (!fWinIniChanged) {
|
|
/*
|
|
* Back out any changes to win.ini.
|
|
*/
|
|
swprintf(szTemp, pwszd, gAccessTimeOut.dwFlags);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_TIMEOUT,
|
|
L"Flags",
|
|
szTemp);
|
|
|
|
swprintf(szTemp, pwszd, gAccessTimeOut.iTimeOutMSec);
|
|
fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
|
|
PMAP_TIMEOUT,
|
|
L"TimeToWait",
|
|
szTemp);
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gAccessTimeOut, pTO, pTO->cbSize);
|
|
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gAccessTimeOut.cbSize = sizeof(ACCESSTIMEOUT);
|
|
|
|
SetAccessEnabledFlag();
|
|
|
|
AccessTimeOutReset();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_SETSHOWSOUNDS:
|
|
if (fAlterWinIni) {
|
|
swprintf(szTemp, pwszd, (wParam == 1));
|
|
fWinIniChanged = FastWriteProfileStringW(NULL,
|
|
PMAP_SHOWSOUNDS,
|
|
L"On",
|
|
szTemp);
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_ACCF(ACCF_SHOWSOUNDSON, wParam == 1);
|
|
SetAccessEnabledFlag();
|
|
|
|
/*
|
|
* Update the System Metrics Info.
|
|
*/
|
|
SYSMET(SHOWSOUNDS) = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSHOWSOUNDS: {
|
|
PINT pint = (int *)lParam;
|
|
|
|
*pint = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
|
|
}
|
|
break;
|
|
|
|
case SPI_GETKEYBOARDPREF:
|
|
{
|
|
PBOOL pfKeyboardPref = (PBOOL)lParam;
|
|
|
|
*pfKeyboardPref = TEST_BOOL_ACCF(ACCF_KEYBOARDPREF);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETKEYBOARDPREF:
|
|
{
|
|
BOOL fKeyboardPref = (BOOL)wParam;
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = FastWriteProfileStringW(NULL,
|
|
PMAP_KEYBOARDPREF,
|
|
L"On",
|
|
fKeyboardPref ? L"1" : L"0");
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_ACCF(ACCF_KEYBOARDPREF, wParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSCREENREADER:
|
|
{
|
|
PBOOL pfScreenReader = (PBOOL)lParam;
|
|
|
|
*pfScreenReader = TEST_BOOL_ACCF(ACCF_SCREENREADER);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETSCREENREADER:
|
|
{
|
|
BOOL fScreenReader = (BOOL)wParam;
|
|
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = FastWriteProfileStringW(NULL,
|
|
PMAP_SCREENREADER,
|
|
L"On",
|
|
fScreenReader ? L"1" : L"0");
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
SET_OR_CLEAR_ACCF(ACCF_SCREENREADER, wParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_GETSOUNDSENTRY:
|
|
{
|
|
LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
|
|
int cbSkip = sizeof(gSoundSentry.cbSize);
|
|
|
|
if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* In the future we may support multiple sizes of this data
|
|
* structure. Don't change the cbSize field of the data
|
|
* structure passed in.
|
|
*/
|
|
RtlCopyMemory((LPVOID)((LPBYTE)pSS + cbSkip),
|
|
(LPVOID)((LPBYTE)&gSoundSentry + cbSkip),
|
|
pSS->cbSize - cbSkip);
|
|
}
|
|
break;
|
|
|
|
case SPI_SETSOUNDSENTRY:
|
|
{
|
|
LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
|
|
|
|
if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Do some parameter validation. We will fail on unsupported and
|
|
* undefined bits being set.
|
|
*/
|
|
if ((pSS->dwFlags & SSF_VALID) != pSS->dwFlags) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* We don't support SSWF_CUSTOM.
|
|
*/
|
|
if (pSS->iWindowsEffect > SSWF_DISPLAY) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* No support for non-windows apps.
|
|
*/
|
|
if (pSS->iFSTextEffect != SSTF_NONE) {
|
|
return FALSE;
|
|
}
|
|
if (pSS->iFSGrafEffect != SSGF_NONE) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* SSF_AVAILABLE can't be set via API. Use registry value.
|
|
*/
|
|
if (TEST_ACCESSFLAG(SoundSentry, SSF_AVAILABLE)) {
|
|
pSS->dwFlags |= SSF_AVAILABLE;
|
|
} else {
|
|
pSS->dwFlags &= ~SSF_AVAILABLE;
|
|
}
|
|
|
|
if (fAlterWinIni) {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
fWinIniChanged = SetSoundSentry(pProfileUserName, pSS);
|
|
fWriteAllowed = fWinIniChanged;
|
|
if (!fWinIniChanged) {
|
|
|
|
/*
|
|
* Back out any changes to win.ini
|
|
*/
|
|
SetSoundSentry(pProfileUserName, &gSoundSentry);
|
|
}
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
if (fWriteAllowed) {
|
|
RtlCopyMemory(&gSoundSentry, pSS, pSS->cbSize);
|
|
|
|
/*
|
|
* Don't allow user to change cbSize field.
|
|
*/
|
|
gSoundSentry.cbSize = sizeof(SOUNDSENTRY);
|
|
|
|
SetAccessEnabledFlag();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SPI_SETCURSORS:
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
xxxUpdateSystemCursorsFromRegistry(pProfileUserName);
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
|
|
break;
|
|
|
|
case SPI_SETICONS:
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
xxxUpdateSystemIconsFromRegistry(pProfileUserName);
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
|
|
break;
|
|
|
|
case SPI_GETMOUSEHOVERWIDTH:
|
|
*((UINT *)lParam) = gcxMouseHover;
|
|
break;
|
|
|
|
case SPI_SETMOUSEHOVERWIDTH:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERWIDTH, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
gcxMouseHover = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMOUSEHOVERHEIGHT:
|
|
*((UINT *)lParam) = gcyMouseHover;
|
|
break;
|
|
|
|
case SPI_SETMOUSEHOVERHEIGHT:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERHEIGHT, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
gcyMouseHover = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETMOUSEHOVERTIME:
|
|
*((UINT *)lParam) = gdtMouseHover;
|
|
break;
|
|
|
|
case SPI_SETMOUSEHOVERTIME:
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERTIME, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed) {
|
|
gdtMouseHover = wParam;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETWHEELSCROLLLINES:
|
|
(*(LPDWORD)lParam) = gpsi->ucWheelScrollLines;
|
|
break;
|
|
|
|
case SPI_SETWHEELSCROLLLINES:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_WHEELSCROLLLINES)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_WHEELSCROLLLINES, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed)
|
|
gpsi->ucWheelScrollLines = (UINT)wParam;
|
|
break;
|
|
|
|
case SPI_GETMENUSHOWDELAY:
|
|
(*(LPDWORD)lParam) = gdtMNDropDown;
|
|
break;
|
|
|
|
case SPI_SETMENUSHOWDELAY:
|
|
if (CheckDesktopPolicy(NULL, (PCWSTR)STR_MENUSHOWDELAY)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_MENUSHOWDELAY, wParam);
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
if (fWriteAllowed)
|
|
gdtMNDropDown = wParam;
|
|
break;
|
|
|
|
case SPI_GETSCREENSAVERRUNNING:
|
|
(*(LPBOOL)lParam) = gppiScreenSaver != NULL;
|
|
break;
|
|
|
|
case SPI_SETSHOWIMEUI:
|
|
return xxxSetIMEShowStatus(!!wParam);
|
|
|
|
case SPI_GETSHOWIMEUI:
|
|
(*(LPBOOL)lParam) = _GetIMEShowStatus();
|
|
break;
|
|
|
|
default:
|
|
|
|
#define ppvi (UPDWORDPointer(wFlag))
|
|
#define uDataRead ((UINT)fWinIniChanged)
|
|
|
|
if (wFlag < SPI_MAX) {
|
|
RIPERR1(ERROR_INVALID_SPI_VALUE,
|
|
RIP_WARNING,
|
|
"xxxSystemParamtersInfo: Invalid SPI_: 0x%x",
|
|
wFlag);
|
|
return FALSE;
|
|
}
|
|
|
|
UserAssert(wFlag & SPIF_RANGETYPEMASK);
|
|
|
|
if (!(wFlag & SPIF_SET)) {
|
|
|
|
if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
|
|
BOOL fDisable, fDisableValue;
|
|
|
|
UserAssert(UPIsBOOLRange(wFlag));
|
|
/*
|
|
* Handle settings that can be disabled by additional conditions.
|
|
*/
|
|
fDisable = fDisableValue = FALSE;
|
|
if (wFlag < SPI_GETUIEFFECTS) {
|
|
if (!TestUP(UIEFFECTS)) {
|
|
switch (wFlag) {
|
|
case SPI_GETACTIVEWNDTRKZORDER:
|
|
case SPI_GETACTIVEWINDOWTRACKING:
|
|
#ifdef MOUSE_IP
|
|
case SPI_GETMOUSESONAR:
|
|
#endif
|
|
case SPI_GETMOUSECLICKLOCK:
|
|
break;
|
|
|
|
case SPI_GETKEYBOARDCUES:
|
|
fDisableValue = TRUE;
|
|
/* Fall Through */
|
|
|
|
default:
|
|
fDisable = TRUE;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (wFlag) {
|
|
case SPI_GETKEYBOARDCUES:
|
|
if (TEST_BOOL_ACCF(ACCF_KEYBOARDPREF)) {
|
|
fDisableValue = TRUE;
|
|
fDisable = TRUE;
|
|
}
|
|
break;
|
|
|
|
case SPI_GETGRADIENTCAPTIONS:
|
|
case SPI_GETSELECTIONFADE:
|
|
case SPI_GETMENUFADE:
|
|
case SPI_GETTOOLTIPFADE:
|
|
case SPI_GETCURSORSHADOW:
|
|
if (gbDisableAlpha) {
|
|
fDisable = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Give them the disabled value or read the actual one.
|
|
*/
|
|
if (fDisable) {
|
|
*((BOOL *)lParam) = fDisableValue;
|
|
} else if (wFlag == SPI_GETUIEFFECTS && IsRemoteConnection()) {
|
|
/*
|
|
* Fix for 689707.
|
|
* In remote connections, lie about the SPI_GETUIEFFECTS.
|
|
* We look at a certain subset of the uieffects array.
|
|
* If all the subset bits are off,
|
|
* we return FALSE, otherwise TRUE.
|
|
*/
|
|
*((BOOL *)lParam) = !!(TestUP(CURSORSHADOW) |
|
|
TestUP(MENUANIMATION) |
|
|
TestUP(MENUFADE) |
|
|
TestUP(TOOLTIPANIMATION) |
|
|
TestUP(TOOLTIPFADE) |
|
|
TestUP(COMBOBOXANIMATION) |
|
|
TestUP(LISTBOXSMOOTHSCROLLING));
|
|
} else {
|
|
*((BOOL *)lParam) = !!TestUPBOOL(gpdwCPUserPreferencesMask, wFlag);
|
|
}
|
|
} else {
|
|
UserAssert(UPIsDWORDRange(wFlag));
|
|
*((DWORD *)lParam) = UPDWORDValue(wFlag);
|
|
switch(wFlag) {
|
|
case SPI_GETFONTSMOOTHINGCONTRAST:
|
|
/*
|
|
* If the contrast value was never set by the user,
|
|
* we will return the default value from the display
|
|
* driver
|
|
*/
|
|
if (*((DWORD *)lParam) == 0) {
|
|
*((DWORD *)lParam) = GreGetFontContrast();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
pProfileUserName = CreateProfileUserName(&tlName);
|
|
|
|
if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
|
|
DWORD pdwValue [SPI_BOOLMASKDWORDSIZE];
|
|
|
|
UserAssert(UPIsBOOLRange(wFlag));
|
|
UserAssert(sizeof(pdwValue) == sizeof(gpdwCPUserPreferencesMask));
|
|
|
|
if (gpviCPUserPreferences->uSection == PMAP_DESKTOP) {
|
|
if (CheckDesktopPolicy(pProfileUserName, gpviCPUserPreferences->pwszKeyName)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
}
|
|
if (fAlterWinIni) {
|
|
/*
|
|
* We only need to set/clear the bit passed in, however,
|
|
* we write the whole bit mask to the registry. Since
|
|
* the info in gpdwCPUserPreferencesMask might not match
|
|
* what it is in the registry, we need to read the
|
|
* registry before we write to it.
|
|
*/
|
|
uDataRead = FastGetProfileValue(pProfileUserName,
|
|
gpviCPUserPreferences->uSection,
|
|
gpviCPUserPreferences->pwszKeyName,
|
|
NULL,
|
|
(LPBYTE)pdwValue,
|
|
sizeof(pdwValue),
|
|
0);
|
|
|
|
/*
|
|
* If some bits are not in the registry, get them from
|
|
* gpdwCPUserPreferencesMask.
|
|
*/
|
|
UserAssert(uDataRead <= sizeof(gpdwCPUserPreferencesMask));
|
|
RtlCopyMemory(pdwValue + uDataRead,
|
|
gpdwCPUserPreferencesMask + uDataRead,
|
|
sizeof(gpdwCPUserPreferencesMask) - uDataRead);
|
|
|
|
/*
|
|
* Set/Clear the new state and write it.
|
|
*/
|
|
if (lParam) {
|
|
SetUPBOOL(pdwValue, wFlag);
|
|
} else {
|
|
ClearUPBOOL(pdwValue, wFlag);
|
|
}
|
|
|
|
fWinIniChanged = FastWriteProfileValue(pProfileUserName,
|
|
gpviCPUserPreferences->uSection,
|
|
gpviCPUserPreferences->pwszKeyName,
|
|
REG_BINARY,
|
|
(LPBYTE)pdwValue,
|
|
sizeof(pdwValue));
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
if (lParam) {
|
|
SetUPBOOL(gpdwCPUserPreferencesMask, wFlag);
|
|
} else {
|
|
ClearUPBOOL(gpdwCPUserPreferencesMask, wFlag);
|
|
}
|
|
|
|
/*
|
|
* Propagate gpsi flags.
|
|
*/
|
|
switch (wFlag) {
|
|
case SPI_SETUIEFFECTS:
|
|
PropagetUPBOOLTogpsi(UIEFFECTS);
|
|
SetPointer(TRUE);
|
|
|
|
/*
|
|
* Fall through.
|
|
*/
|
|
|
|
case SPI_SETGRADIENTCAPTIONS:
|
|
CreateBitmapStrip();
|
|
xxxRedrawScreen();
|
|
break;
|
|
|
|
case SPI_SETCOMBOBOXANIMATION:
|
|
PropagetUPBOOLTogpsi(COMBOBOXANIMATION);
|
|
break;
|
|
|
|
case SPI_SETLISTBOXSMOOTHSCROLLING:
|
|
PropagetUPBOOLTogpsi(LISTBOXSMOOTHSCROLLING);
|
|
break;
|
|
|
|
case SPI_SETKEYBOARDCUES:
|
|
PropagetUPBOOLTogpsi(KEYBOARDCUES);
|
|
break;
|
|
|
|
case SPI_SETCURSORSHADOW:
|
|
SetPointer(TRUE);
|
|
break;
|
|
|
|
case SPI_SETFLATMENU:
|
|
xxxRedrawScreen();
|
|
break;
|
|
|
|
}
|
|
}
|
|
} else {
|
|
|
|
UserAssert(UPIsDWORDRange(wFlag));
|
|
|
|
if (ppvi->uSection == PMAP_DESKTOP) {
|
|
if (CheckDesktopPolicy(pProfileUserName, ppvi->pwszKeyName)) {
|
|
fAlterWinIni = FALSE;
|
|
fWriteAllowed = FALSE;
|
|
}
|
|
}
|
|
if (fAlterWinIni) {
|
|
fWinIniChanged = FastWriteProfileValue(pProfileUserName,
|
|
ppvi->uSection,
|
|
ppvi->pwszKeyName,
|
|
REG_DWORD,
|
|
(LPBYTE)&lParam,
|
|
sizeof(DWORD));
|
|
|
|
fWriteAllowed = fWinIniChanged;
|
|
}
|
|
|
|
if (fWriteAllowed) {
|
|
ppvi->dwValue = PtrToUlong(lParam);
|
|
|
|
switch(wFlag) {
|
|
case SPI_SETCARETWIDTH:
|
|
gpsi->uCaretWidth = ppvi->dwValue;
|
|
break;
|
|
|
|
case SPI_SETFOCUSBORDERWIDTH:
|
|
if (ppvi->dwValue) {
|
|
SYSMET(CXFOCUSBORDER) = ppvi->dwValue;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETFOCUSBORDERHEIGHT:
|
|
if (ppvi->dwValue) {
|
|
SYSMET(CYFOCUSBORDER) = ppvi->dwValue;
|
|
}
|
|
break;
|
|
|
|
case SPI_SETFONTSMOOTHINGTYPE:
|
|
GreSetFontEnumeration((ppvi->dwValue & FE_FONTSMOOTHINGCLEARTYPE) ? FE_CT_ON | FE_SET_CT : FE_SET_CT);
|
|
break;
|
|
case SPI_SETFONTSMOOTHINGCONTRAST:
|
|
GreSetFontContrast(ppvi->dwValue);
|
|
break;
|
|
case SPI_SETFONTSMOOTHINGORIENTATION:
|
|
GreSetLCDOrientation(ppvi->dwValue);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeProfileUserName(pProfileUserName, &tlName);
|
|
}
|
|
|
|
break;
|
|
#undef ppvi
|
|
#undef uDataRead
|
|
}
|
|
|
|
|
|
if (fWinIniChanged && fSendWinIniChange) {
|
|
ULONG_PTR dwResult;
|
|
|
|
RtlInitLargeUnicodeString(&strSection, szSection, (UINT)-1);
|
|
xxxSendMessageTimeout(PWND_BROADCAST,
|
|
WM_SETTINGCHANGE,
|
|
wFlag,
|
|
(LPARAM)&strSection,
|
|
SMTO_NORMAL,
|
|
100,
|
|
&dwResult);
|
|
}
|
|
|
|
return fWriteAllowed;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* _RegisterShellHookWindow
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
BOOL _RegisterShellHookWindow(
|
|
PWND pwnd)
|
|
{
|
|
PDESKTOPINFO pdeskinfo;
|
|
|
|
if (pwnd->head.rpdesk == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
|
|
|
|
/*
|
|
* Add pwnd to the desktop's Volatile Window Pointer List (VWPL) of
|
|
* ShellHook windows. If this call initializes the VWPL, set the
|
|
* (re)allocation threshhold to 2 PWNDs (we know we never have more than
|
|
* 2 windows in this list anyway)
|
|
*/
|
|
if (VWPLAdd(&(pdeskinfo->pvwplShellHook), pwnd, 2)) {
|
|
SetWF(pwnd, WFSHELLHOOKWND);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* _DeregisterShellHookWindow
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
BOOL _DeregisterShellHookWindow(
|
|
PWND pwnd)
|
|
{
|
|
PDESKTOPINFO pdeskinfo;
|
|
|
|
if (pwnd->head.rpdesk == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
|
|
|
|
if (VWPLRemove(&(pdeskinfo->pvwplShellHook), pwnd)) {
|
|
ClrWF(pwnd, WFSHELLHOOKWND);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSendMinRectMessages
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
BOOL xxxSendMinRectMessages(
|
|
PWND pwnd,
|
|
RECT *lpRect)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
HWND hwnd = HW(pwnd);
|
|
PTHREADINFO pti = PtiCurrent();
|
|
PDESKTOPINFO pdeskinfo;
|
|
DWORD nPwndShellHook;
|
|
PWND pwndShellHook;
|
|
|
|
if (IsHooked(pti, WHF_SHELL)) {
|
|
xxxCallHook(HSHELL_GETMINRECT, (WPARAM)hwnd, (LPARAM)lpRect, WH_SHELL);
|
|
fRet = TRUE;
|
|
}
|
|
|
|
pdeskinfo = GETDESKINFO(pti);
|
|
if (pdeskinfo->pvwplShellHook == NULL) {
|
|
return fRet;
|
|
}
|
|
|
|
nPwndShellHook = 0;
|
|
pwndShellHook = NULL;
|
|
while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
|
|
TL tlpwnd;
|
|
ULONG_PTR dwRes;
|
|
|
|
ThreadLock(pwndShellHook, &tlpwnd);
|
|
if (xxxSendMessageTimeout(pwndShellHook, WM_KLUDGEMINRECT, (WPARAM)(hwnd), (LPARAM)lpRect,
|
|
SMTO_NORMAL, 100, &dwRes))
|
|
fRet = TRUE;
|
|
|
|
/*
|
|
* pdeskinfo->pvwplShellHook may have been realloced to a different
|
|
* location and size during the WM_KLUDGEMINRECT callback.
|
|
*/
|
|
ThreadUnlock(&tlpwnd);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* PostShellHookMessages
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
VOID PostShellHookMessages(
|
|
UINT message,
|
|
LPARAM lParam)
|
|
{
|
|
PDESKTOPINFO pdeskinfo = GETDESKINFO(PtiCurrent());
|
|
DWORD nPwndShellHook;
|
|
PWND pwndShellHook;
|
|
|
|
nPwndShellHook = 0;
|
|
pwndShellHook = NULL;
|
|
|
|
/*
|
|
* We want to allow anyone who's listening for these WM_APPCOMMAND
|
|
* messages to be able to take the foreground. I.E., pressing mail will
|
|
* launch outlook AND bring it to the foreground. We set the token to
|
|
* null so anyone can steal the foreground - else it isn't clear who
|
|
* should have the right to steal it - only one person gets the right.
|
|
* We let them fight it out to decide who gets foreground if more than
|
|
* one listener will try make a foreground change.
|
|
*/
|
|
if (HSHELL_APPCOMMAND == message) {
|
|
TAGMSG0(DBGTAG_FOREGROUND,
|
|
"PostShellHookMessages cleared last input token - open foreground.");
|
|
|
|
glinp.ptiLastWoken = NULL;
|
|
}
|
|
|
|
/*
|
|
* Loop through all the windows registered to listen for shell hooks and
|
|
* post the message to them.
|
|
*/
|
|
while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
|
|
if (pwndShellHook == pdeskinfo->spwndProgman) {
|
|
switch (message) {
|
|
case HSHELL_WINDOWCREATED:
|
|
_PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowCreated, lParam);
|
|
break;
|
|
case HSHELL_WINDOWDESTROYED:
|
|
_PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowDestroyed, lParam);
|
|
break;
|
|
}
|
|
} else {
|
|
_PostMessage(pwndShellHook, gpsi->uiShellMsg, message, lParam);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* _ResetDblClk
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
VOID _ResetDblClk(
|
|
VOID)
|
|
{
|
|
PtiCurrent()->pq->timeDblClk = 0L;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetMsgBox
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
VOID SetMsgBox(
|
|
PWND pwnd)
|
|
{
|
|
pwnd->head.rpdesk->pDeskInfo->cntMBox++;
|
|
SetWF(pwnd, WFMSGBOX);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* xxxSimulateShiftF10
|
|
*
|
|
* This routine is called to convert a WM_CONTEXTHELP message back to a
|
|
* SHIFT-F10 sequence for old applications. It is called from the default
|
|
* window procedure.
|
|
*
|
|
* History:
|
|
* 22-Aug-95 BradG Ported from Win95 (rare.asm)
|
|
\***************************************************************************/
|
|
VOID xxxSimulateShiftF10(
|
|
VOID)
|
|
{
|
|
/*
|
|
* VK_SHIFT down
|
|
*/
|
|
xxxKeyEvent(VK_LSHIFT, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
|
|
#ifdef GENERIC_INPUT
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
FALSE);
|
|
|
|
/*
|
|
* VK_F10 down
|
|
*/
|
|
xxxKeyEvent(VK_F10, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
|
|
#ifdef GENERIC_INPUT
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
FALSE);
|
|
|
|
/*
|
|
* VK_F10 up
|
|
*/
|
|
xxxKeyEvent(VK_F10 | KBDBREAK, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
|
|
#ifdef GENERIC_INPUT
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
FALSE);
|
|
|
|
/*
|
|
* VK_SHIFT up
|
|
*/
|
|
xxxKeyEvent(VK_LSHIFT | KBDBREAK, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
|
|
#ifdef GENERIC_INPUT
|
|
NULL,
|
|
NULL,
|
|
#endif
|
|
FALSE);
|
|
}
|
|
|
|
/*
|
|
* VWPL (Volatile Window Pointer List) Implementation details.
|
|
* ===========================================================
|
|
* Volatile Window Pointer Lists are used to keep a list of windows that we want
|
|
* to send messages to, where the list may get altered during each of those send
|
|
* message callbacks.
|
|
*
|
|
* The list is volatile in that it can change its size, contents and location
|
|
* while we continue to traverse the list.
|
|
*
|
|
* Examples of use:
|
|
* - hungapp redraw code in hungapp.c
|
|
* - xxxSendMinRectMessages stuff in rare.c
|
|
*
|
|
* Members of the VWPL struct:
|
|
* cPwnd
|
|
* The number of pwnds in the list, not including NULLs
|
|
* cElem
|
|
* The size of the list, including NULLs.
|
|
* cThreshhold
|
|
* When growing, the number of extra spaces to add to the list.
|
|
* When (cElem - cPwnd) > cThreshhold, that's when we reallocate to shrink.
|
|
* apwnd[]
|
|
* An array of pwnds.
|
|
* The array may have some empty slots, but they will all be at the end.
|
|
*
|
|
* VWPL Internal Invariants:
|
|
* - no pwnd appears more than once.
|
|
* - cPwnd <= cElem
|
|
* - number of unused slots (cElem - cPwnd) < cThreshhold
|
|
* - all unused slots are at the end of the aPwnd[] array
|
|
*
|
|
* Restrictions on use of VWPLs:
|
|
* - NULL pwnd is not allowed (except in unused slots)
|
|
* - all pwnds in the list must be valid: pwnds must be explicitly removed from
|
|
* the list in their xxxFreeWindow.
|
|
*/
|
|
|
|
#if DBG_VWPL
|
|
BOOL DbgCheckVWPL(
|
|
PVWPL pvwpl)
|
|
{
|
|
DWORD ixPwnd;
|
|
|
|
if (!pvwpl) {
|
|
return TRUE;
|
|
}
|
|
|
|
UserAssert(pvwpl->cElem >= pvwpl->cPwnd);
|
|
|
|
/*
|
|
* Check that cElem is not too big.
|
|
*/
|
|
UserAssert(pvwpl->cElem < 1000);
|
|
|
|
/*
|
|
* Check that the pwnds are all in the first cPwnd slots.
|
|
*/
|
|
for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
|
|
UserAssert(pvwpl->aPwnd[ixPwnd] != NULL);
|
|
}
|
|
|
|
#if ZERO_INIT_VWPL
|
|
/*
|
|
* Check that the NULLs are all in the last few slots.
|
|
*/
|
|
for (ixPwnd = pvwpl->cPwnd; ixPwnd < pvwpl->cElem; ixPwnd++) {
|
|
UserAssert(pvwpl->aPwnd[ixPwnd] == NULL);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Check that no pwnds appears twice.
|
|
*/
|
|
for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
|
|
DWORD ix2;
|
|
for (ix2 = ixPwnd + 1; ix2 < pvwpl->cPwnd; ix2++) {
|
|
UserAssert(pvwpl->aPwnd[ixPwnd] != pvwpl->aPwnd[ix2]);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
#define DbgCheckVWPL(foo)
|
|
#endif
|
|
|
|
/*****************************************************************************\
|
|
* VWPLAdd
|
|
*
|
|
* Adds a pwnd to a VWPL (Volatile Window Pointer List). Allocates or
|
|
* reallocates memory as required.
|
|
*
|
|
* History:
|
|
* 98-01-30 IanJa Created.
|
|
\*****************************************************************************/
|
|
BOOL VWPLAdd(
|
|
PVWPL *ppvwpl,
|
|
PWND pwnd,
|
|
DWORD dwThreshhold)
|
|
{
|
|
PVWPL pvwpl;
|
|
DWORD ixPwnd;
|
|
|
|
TAGMSG2(DBGTAG_VWPL, "VWPL %#p + %#p", *ppvwpl, pwnd);
|
|
UserAssert(pwnd);
|
|
|
|
if (*ppvwpl == NULL) {
|
|
/*
|
|
* Initialize the VWPL.
|
|
*/
|
|
UserAssert(dwThreshhold >= 2); // could be 1, but that would be silly
|
|
pvwpl = (PVWPL)UserAllocPool(sizeof(VWPL) + (sizeof(PWND) * dwThreshhold),
|
|
TAG_VWPL);
|
|
if (pvwpl == NULL) {
|
|
RIPMSG1(RIP_WARNING,
|
|
"VWPLAdd fail to allocate initial %lx",
|
|
sizeof(VWPL) + (sizeof(PWND) * dwThreshhold));
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return FALSE;
|
|
}
|
|
pvwpl->cElem = dwThreshhold;
|
|
pvwpl->cThreshhold = dwThreshhold;
|
|
#if ZERO_INIT_VWPL
|
|
RtlZeroMemory(&(pvwpl->aPwnd[0]), (sizeof(PWND) * dwThreshhold));
|
|
#endif
|
|
pvwpl->cPwnd = 0;
|
|
*ppvwpl = pvwpl;
|
|
ixPwnd = 0;
|
|
goto AddPwnd;
|
|
} else {
|
|
pvwpl = *ppvwpl;
|
|
for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
|
|
if (pwnd == pvwpl->aPwnd[ixPwnd]) {
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return FALSE; // callers require FALSE this case
|
|
}
|
|
}
|
|
|
|
if (pvwpl->cPwnd >= pvwpl->cElem ) {
|
|
/*
|
|
* Didn't find it already there, and no space so grow the VWPL.
|
|
*/
|
|
DWORD dwSize;
|
|
DWORD dwSizeNew;
|
|
|
|
dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
|
|
dwSizeNew = dwSize + (sizeof(PWND) * pvwpl->cThreshhold);
|
|
pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
|
|
if (pvwpl == NULL) {
|
|
RIPMSG2(RIP_WARNING,
|
|
"VWPLAdd fail to reallocate %lx to %lx", dwSize, dwSizeNew);
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return FALSE;
|
|
}
|
|
#if ZERO_INIT_VWPL
|
|
RtlZeroMemory(&(pvwpl->aPwnd[pvwpl->cPwnd]), (sizeof(PWND) * dwThreshhold));
|
|
#endif
|
|
pvwpl->cElem += pvwpl->cThreshhold;
|
|
*ppvwpl = pvwpl;
|
|
}
|
|
}
|
|
|
|
AddPwnd:
|
|
ixPwnd = pvwpl->cPwnd;
|
|
pvwpl->aPwnd[ixPwnd] = pwnd;
|
|
pvwpl->cPwnd++;
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* VWPLRemove
|
|
*
|
|
* Removes a pwnd from a VWPL list of pwnds. Reallocates memory as required.
|
|
*
|
|
* Returns FALSE if the pwnd was not found.
|
|
*
|
|
* History:
|
|
* 98-01-30 IanJa Created.
|
|
\*****************************************************************************/
|
|
BOOL VWPLRemove(
|
|
PVWPL *ppvwpl,
|
|
PWND pwnd)
|
|
{
|
|
PVWPL pvwpl = *ppvwpl;
|
|
DWORD ixPwnd;
|
|
|
|
TAGMSG2(DBGTAG_VWPL, "VWPL %#p - %#p", *ppvwpl, pwnd);
|
|
UserAssert(pwnd);
|
|
|
|
if (!pvwpl) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
|
|
if (pwnd == pvwpl->aPwnd[ixPwnd]) {
|
|
goto PwndIsFound;
|
|
}
|
|
}
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return FALSE;
|
|
|
|
PwndIsFound:
|
|
pvwpl->aPwnd[ixPwnd] = NULL;
|
|
pvwpl->cPwnd--;
|
|
|
|
if (pvwpl->cPwnd == 0) {
|
|
UserFreePool(pvwpl);
|
|
*ppvwpl = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Compact the VWPL to keep all the empty slots at the end. If these
|
|
* free slots exceeds the threshhold, realloc to shrink. It doesn't
|
|
* matter that we change the order.
|
|
*/
|
|
pvwpl->aPwnd[ixPwnd] = pvwpl->aPwnd[pvwpl->cPwnd];
|
|
#if ZERO_INIT_VWPL
|
|
pvwpl->aPwnd[pvwpl->cPwnd] = NULL;
|
|
#endif
|
|
|
|
|
|
if ((pvwpl->cElem - pvwpl->cPwnd) >= pvwpl->cThreshhold) {
|
|
DWORD dwSize;
|
|
DWORD dwSizeNew;
|
|
|
|
dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
|
|
dwSizeNew = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cPwnd);
|
|
pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
|
|
if (pvwpl == NULL) {
|
|
RIPMSG2(RIP_WARNING,
|
|
"VWPLRemove fail to reallocate %lx to %lx",
|
|
dwSize, dwSizeNew);
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return TRUE;
|
|
}
|
|
pvwpl->cElem = pvwpl->cPwnd;
|
|
*ppvwpl = pvwpl;
|
|
}
|
|
|
|
DbgCheckVWPL(*ppvwpl);
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* VWPLNext
|
|
*
|
|
* Returns the next pwnd from a VWPL (Volatile Window Pointer List).
|
|
*
|
|
* Setting *pnPrev to 0 will return the first pwnd in the VWPL, and gets a new
|
|
* value in *pnPrev which is to be used in a subsequent call to VWPLNext to
|
|
* obtain the next pwnd.
|
|
* Returns NULL when the last pwnd has been obtained, and sets *pnPrev back to 0
|
|
*
|
|
* History:
|
|
* 98-01-30 IanJa Created.
|
|
\*****************************************************************************/
|
|
PWND VWPLNext(
|
|
PVWPL pvwpl,
|
|
PWND pwndPrev,
|
|
DWORD *pnPrev)
|
|
{
|
|
DbgCheckVWPL(pvwpl);
|
|
|
|
if (!pvwpl) {
|
|
TAGMSG1(DBGTAG_VWPL, "VWPL %#p => NULL (empty)", pvwpl);
|
|
return NULL;
|
|
}
|
|
|
|
if (*pnPrev >= pvwpl->cPwnd) {
|
|
goto NoMorePwnds;
|
|
}
|
|
|
|
/*
|
|
* If our previous pwnd is still there, advance to the next slot
|
|
* (else it has gone, so return the one now occupying its slot).
|
|
*/
|
|
if (pvwpl->aPwnd[*pnPrev] == pwndPrev) {
|
|
(*pnPrev)++;
|
|
}
|
|
|
|
if (*pnPrev < pvwpl->cPwnd) {
|
|
UserAssert(pvwpl->aPwnd[*pnPrev] != pwndPrev);
|
|
TAGMSG2(DBGTAG_VWPL, "VWPL %#p => %#p", pvwpl, pvwpl->aPwnd[*pnPrev]);
|
|
return pvwpl->aPwnd[*pnPrev];
|
|
}
|
|
|
|
/*
|
|
* We came to the end.
|
|
*/
|
|
NoMorePwnds:
|
|
TAGMSG1(DBGTAG_VWPL, "VWPL 0x%p => NULL (end)", pvwpl);
|
|
*pnPrev = 0;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* RestoreMonitorsAndWindowsRects
|
|
*
|
|
* Restore a windows sizes and positions previously captured in a WMSNAPSHOT
|
|
* structure. Capture happens when disconnecting from local console and
|
|
* restore happens when connecting back to local console.
|
|
\*****************************************************************************/
|
|
NTSTATUS RestoreMonitorsAndWindowsRects(
|
|
VOID)
|
|
{
|
|
PMONITORRECTS pmr;
|
|
int i;
|
|
int j;
|
|
BOOL bFound;
|
|
PSMWP psmwp;
|
|
PWND pwnd;
|
|
NTSTATUS Status;
|
|
PWPSNAPSHOT pwps = NULL;
|
|
|
|
/*
|
|
* Don't do anything if not multimon.
|
|
*/
|
|
if (!IsMultimon()) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Nothing to do if we don't currently have captured monitors or
|
|
* windows snapshots.
|
|
*/
|
|
if (gwms.pmr == NULL || gwms.pwps == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* Get Current monitors layout.
|
|
*/
|
|
pmr = SnapshotMonitorRects();
|
|
if (pmr == NULL) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
/*
|
|
* make sure monitors we captured are still there.
|
|
*/
|
|
|
|
Status = STATUS_SUCCESS;
|
|
for (i = 0; i < gwms.pmr->cMonitor; i++) {
|
|
bFound = FALSE;
|
|
for (j = 0; j < pmr->cMonitor; j++) {
|
|
if (EqualRect(&gwms.pmr->amp[i].rcMonitor, &pmr->amp[j].rcMonitor)) {
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFound) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
}
|
|
UserFreePool(pmr);
|
|
|
|
/*
|
|
* Position Windows now.
|
|
*/
|
|
if (NT_SUCCESS(Status)) {
|
|
if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
|
|
for (i = 0, pwps = gwms.pwps; (i < gwms.cWindows) && (psmwp != NULL) ; i++, pwps++) {
|
|
/*
|
|
* Make sure this hwnd is still here.
|
|
*/
|
|
if ((pwnd = RevalidateHwnd(pwps->hwnd)) == NULL ||
|
|
TestWF(pwnd, WEFTOOLWINDOW)) {
|
|
continue;
|
|
}
|
|
|
|
psmwp = _DeferWindowPos(psmwp,
|
|
pwnd,
|
|
(PWND)HWND_TOP,
|
|
pwps->rcWindow.left,
|
|
pwps->rcWindow.top,
|
|
pwps->rcWindow.right - pwps->rcWindow.left,
|
|
pwps->rcWindow.bottom - pwps->rcWindow.top,
|
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
|
}
|
|
|
|
if (psmwp != NULL) {
|
|
xxxEndDeferWindowPosEx(psmwp, TRUE);
|
|
} else{
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
Exit:
|
|
CleanupMonitorsAndWindowsSnapShot();
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*****************************************************************************\
|
|
* SnapShotMonitorsAndWindowsRects
|
|
*
|
|
* Captures windows sizes and positions in a WMSNAPSHOT structure. Capture
|
|
* happens when disconnecting from local console.
|
|
\*****************************************************************************/
|
|
NTSTATUS SnapShotMonitorsAndWindowsRects(
|
|
VOID)
|
|
|
|
{
|
|
/*
|
|
* First, cleanup anything left over from previous captures.
|
|
*/
|
|
if (gwms.pmr != NULL || gwms.pwps != NULL) {
|
|
CleanupMonitorsAndWindowsSnapShot();
|
|
}
|
|
|
|
/*
|
|
* Get a snaphot of current monitors configuration.
|
|
*/
|
|
if ((gwms.pmr = SnapshotMonitorRects()) == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/*
|
|
* Get a snaphsot of windows positions.
|
|
*/
|
|
if ((gwms.pwps = SnapshotWindowRects(&gwms.cWindows)) == NULL) {
|
|
CleanupMonitorsAndWindowsSnapShot();
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* CleanupMonitorsAndWindowsSnapShot
|
|
*
|
|
* Frees memory allocated to capture windows sizes and positions a WMSNAPSHOT
|
|
* structure.
|
|
\*****************************************************************************/
|
|
VOID CleanupMonitorsAndWindowsSnapShot(
|
|
VOID)
|
|
{
|
|
PWPSNAPSHOT pwps = gwms.pwps;
|
|
|
|
if (gwms.pmr != NULL) {
|
|
UserFreePool(gwms.pmr);
|
|
gwms.pmr = NULL;
|
|
}
|
|
|
|
if (pwps != NULL) {
|
|
UserFreePool(gwms.pwps);
|
|
gwms.pwps = NULL;
|
|
}
|
|
|
|
gwms.cWindows = 0;
|
|
}
|
|
|
|
|
|
/*****************************************************************************\
|
|
* SnapshotWindowRects
|
|
*
|
|
* Allocates memory to capture window sizes and positions in a WMSNAPSHOT
|
|
* structure.
|
|
\*****************************************************************************/
|
|
PWPSNAPSHOT SnapshotWindowRects(
|
|
int *pnWindows)
|
|
{
|
|
PWND pwndDesktop;
|
|
PHWND phwnd;
|
|
PBWL pbwl;
|
|
PWND pwnd;
|
|
int nWindows = 0;
|
|
PWPSNAPSHOT pwps = NULL;
|
|
PWPSNAPSHOT pReturnedpwps = NULL;
|
|
|
|
/*
|
|
* Initialize captured windows count.
|
|
*/
|
|
|
|
*pnWindows = 0;
|
|
|
|
/*
|
|
* Build a list of top windows.
|
|
*/
|
|
|
|
UserVerify(pwndDesktop = _GetDesktopWindow());
|
|
if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Count maximum captured windows to allocate WPSNAPSHOT array.
|
|
*/
|
|
phwnd = pbwl->rghwnd;
|
|
while (*phwnd != (HWND)1) {
|
|
nWindows++;
|
|
phwnd++;
|
|
}
|
|
|
|
if (nWindows != 0) {
|
|
pwps = UserAllocPoolWithQuotaZInit(sizeof(WPSNAPSHOT) * nWindows, TAG_SWP);
|
|
}
|
|
|
|
if (pwps == NULL) {
|
|
FreeHwndList(pbwl);
|
|
return NULL;
|
|
}
|
|
pReturnedpwps = pwps;
|
|
|
|
|
|
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
|
|
/*
|
|
* Make sure this hwnd is still around.
|
|
*/
|
|
if ((pwnd = RevalidateHwnd(*phwnd)) == NULL || TestWF(pwnd, WEFTOOLWINDOW) ) {
|
|
continue;
|
|
}
|
|
|
|
pwps->hwnd = *phwnd;
|
|
CopyRect(&pwps->rcWindow, &pwnd->rcWindow);
|
|
(*pnWindows)++;
|
|
pwps++;
|
|
|
|
}
|
|
|
|
if (*pnWindows != 0) {
|
|
return pReturnedpwps;
|
|
} else {
|
|
UserFreePool(pReturnedpwps);
|
|
return NULL;
|
|
}
|
|
}
|
|
|