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

4619 lines
150 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: rare.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * History:
  7. * 06-28-91 MikeHar Created.
  8. \***************************************************************************/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. /*
  12. * MetricsRecalc flags
  13. */
  14. #define CALC_RESIZE 0x0001
  15. #define CALC_FRAME 0x0002
  16. #define CALC_MINIMIZE 0x0004
  17. /*
  18. * NormalizeRect flags
  19. */
  20. #define NORMALIZERECT_NORMAL 0
  21. #define NORMALIZERECT_MAXIMIZED 1
  22. #define NORMALIZERECT_FULLSCREEN 2
  23. /***************************************************************************\
  24. * SnapshotMonitorRects
  25. *
  26. * This is called from ResetDisplay to memorize the monitor positions so
  27. * DesktopRecalcEx will know where to move stuff.
  28. *
  29. * Returns the MONITORRECTS if succeeded, NULL otherwise.
  30. *
  31. * History:
  32. * 09-Dec-1996 adams Created.
  33. \***************************************************************************/
  34. PMONITORRECTS SnapshotMonitorRects(
  35. VOID)
  36. {
  37. PMONITOR pMonitor;
  38. PMONITORRECTS pmr;
  39. PMONITORPOS pmp;
  40. #if DBG
  41. ULONG cVisMon = 0;
  42. #endif
  43. pmr = UserAllocPool(sizeof(MONITORRECTS) + sizeof(MONITORPOS) * (gpDispInfo->cMonitors - 1),
  44. TAG_MONITORRECTS);
  45. if (!pmr) {
  46. RIPERR0(ERROR_OUTOFMEMORY, RIP_WARNING, "Out of memory in SnapshotMonitorRects");
  47. return NULL;
  48. }
  49. pmp = pmr->amp;
  50. for (pMonitor = gpDispInfo->pMonitorFirst;
  51. pMonitor;
  52. pMonitor = pMonitor->pMonitorNext) {
  53. if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) {
  54. continue;
  55. }
  56. #if DBG
  57. cVisMon++;
  58. #endif
  59. CopyRect(&pmp->rcMonitor, &pMonitor->rcMonitor);
  60. CopyRect(&pmp->rcWork, &pMonitor->rcWork);
  61. /*
  62. * If the device for this monitor object is not active, don't store
  63. * the pointer to it in the list. This way the windows on the inactive
  64. * monitor will be later moved to the default one.
  65. */
  66. if (HdevFromMonitor(pMonitor) == -1) {
  67. pmp->pMonitor = NULL;
  68. } else {
  69. pmp->pMonitor = pMonitor;
  70. }
  71. pmp++;
  72. }
  73. UserAssert(cVisMon == gpDispInfo->cMonitors);
  74. pmr->cMonitor = (int)(pmp - pmr->amp);
  75. return pmr;
  76. }
  77. /***************************************************************************\
  78. * UpdateMonitorRectsSnapShot
  79. *
  80. * Updates a Monitor rects snapshot. Every pMonitor in MONITORPOS is checked
  81. * to still be a valid monitor. If the pMonitor is no loger valid (deleted
  82. * by a ChangeDisplaySettings. it is zeroed so that its windows will be
  83. * repositioned on the primary monitor. This code is only used on by the
  84. * reconnect in TS scenario and is there for cases that are not happening
  85. * today: today reconnect always happens from disconnected state where we go
  86. * from 1 monitor (the disconnected display driver) to n monitors and this
  87. * monitor (starting in (0,0) never gets deleted because it alway matches one
  88. * of the new n monitors (the one starting in (0,0). So this code is just in
  89. * case of future changes.
  90. *
  91. * History:
  92. \***************************************************************************/
  93. VOID UpdateMonitorRectsSnapShot(
  94. PMONITORRECTS pmr)
  95. {
  96. int i;
  97. PMONITORPOS pmp = pmr->amp;
  98. for (i = 0; i < pmr->cMonitor; i++) {
  99. if (pmp->pMonitor != NULL) {
  100. if (!IsValidMonitor(pmp->pMonitor)) {
  101. pmp->pMonitor = NULL;
  102. }
  103. }
  104. pmp++;
  105. }
  106. }
  107. BOOL IsValidMonitor(
  108. PMONITOR pMonitor)
  109. {
  110. PMONITOR pMonitorNext = gpDispInfo->pMonitorFirst;
  111. while (pMonitorNext != NULL) {
  112. if (pMonitorNext == pMonitor) {
  113. return TRUE;
  114. }
  115. pMonitorNext = pMonitorNext->pMonitorNext;
  116. }
  117. return FALSE;
  118. }
  119. /***************************************************************************\
  120. * NormalizeRect
  121. *
  122. * Adjusts a window rectangle when the working area changes. This can be
  123. * because of a tray move, with the resolution staying the same, or
  124. * because of a dynamic resolution change, with the tray staying the same
  125. * relatively.
  126. *
  127. * History:
  128. \***************************************************************************/
  129. PMONITOR NormalizeRect(
  130. LPRECT lprcDest,
  131. LPRECT lprcSrc,
  132. PMONITORRECTS pmrOld,
  133. int iOldMonitor,
  134. int codeFullScreen,
  135. DWORD style)
  136. {
  137. LPCRECT lprcOldMonitor;
  138. LPCRECT lprcOldWork;
  139. LPRECT lprcNewWork;
  140. PMONITOR pMonitor;
  141. int cxOldMonitor;
  142. int cyOldMonitor;
  143. int cxNewMonitor;
  144. int cyNewMonitor;
  145. int dxOrg, dyOrg;
  146. /*
  147. * Track the window so it stays in the same place on the same monitor.
  148. * If the old monitor is no longer active then pick a default.
  149. */
  150. if ((pMonitor = pmrOld->amp[iOldMonitor].pMonitor) == NULL) {
  151. pMonitor = GetPrimaryMonitor();
  152. }
  153. lprcOldMonitor = &pmrOld->amp[iOldMonitor].rcMonitor;
  154. lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
  155. /*
  156. * If is a fullscreen app just make it fullscreen at the new location.
  157. */
  158. if (codeFullScreen != NORMALIZERECT_NORMAL) {
  159. LPCRECT lprcOldSnap, lprcNewSnap;
  160. /*
  161. * If it is a maximized window snap it to the work area. Otherwise
  162. * it is a rude app so snap it to the screen.
  163. */
  164. if (codeFullScreen == NORMALIZERECT_MAXIMIZED) {
  165. lprcOldSnap = lprcOldWork;
  166. lprcNewSnap = &pMonitor->rcWork;
  167. } else {
  168. lprcOldSnap = lprcOldMonitor;
  169. lprcNewSnap = &pMonitor->rcMonitor;
  170. }
  171. lprcDest->left = lprcSrc->left +
  172. lprcNewSnap->left - lprcOldSnap->left;
  173. lprcDest->top = lprcSrc->top +
  174. lprcNewSnap->top - lprcOldSnap->top;
  175. lprcDest->right = lprcSrc->right +
  176. lprcNewSnap->right - lprcOldSnap->right;
  177. lprcDest->bottom = lprcSrc->bottom +
  178. lprcNewSnap->bottom - lprcOldSnap->bottom;
  179. goto AllDone;
  180. }
  181. /*
  182. * Offset the window by the change in desktop origin.
  183. */
  184. dxOrg = pMonitor->rcMonitor.left - lprcOldMonitor->left;
  185. dyOrg = pMonitor->rcMonitor.top - lprcOldMonitor->top;
  186. /*
  187. * Calculate the change in screen size (we need it in more than one place).
  188. */
  189. cxOldMonitor = lprcOldMonitor->right - lprcOldMonitor->left;
  190. cyOldMonitor = lprcOldMonitor->bottom - lprcOldMonitor->top;
  191. cxNewMonitor = pMonitor->rcMonitor.right - pMonitor->rcMonitor.left;
  192. cyNewMonitor = pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top;
  193. /*
  194. * If the monitor resolution has changed (or we moved to a new monitor)
  195. * then factor in the size change.
  196. */
  197. if (cxNewMonitor != cxOldMonitor || cyNewMonitor != cyOldMonitor) {
  198. int xWnd = lprcSrc->left - lprcOldMonitor->left;
  199. int yWnd = lprcSrc->top - lprcOldMonitor->top;
  200. dxOrg += MultDiv(xWnd, cxNewMonitor - cxOldMonitor, cxOldMonitor);
  201. dyOrg += MultDiv(yWnd, cyNewMonitor - cyOldMonitor, cyOldMonitor);
  202. }
  203. /*
  204. * Compute the initial new position.
  205. */
  206. CopyOffsetRect(lprcDest, lprcSrc, dxOrg, dyOrg);
  207. lprcNewWork = &pMonitor->rcWork;
  208. /*
  209. * Fit horizontally. Try to fit so that the window isn't out of the
  210. * working area horizontally. Keep left edge visible always.
  211. */
  212. if (lprcDest->right > lprcNewWork->right) {
  213. OffsetRect(lprcDest, lprcNewWork->right - lprcDest->right, 0);
  214. }
  215. if (lprcDest->left < lprcNewWork->left) {
  216. OffsetRect(lprcDest, lprcNewWork->left - lprcDest->left, 0);
  217. }
  218. /*
  219. * Fit vertically. Try to fit so that the window isn't out of the
  220. * working area vertically. Keep top edge visible always.
  221. */
  222. if (lprcDest->bottom > lprcNewWork->bottom) {
  223. OffsetRect(lprcDest, 0, lprcNewWork->bottom - lprcDest->bottom);
  224. }
  225. if (lprcDest->top < lprcNewWork->top) {
  226. OffsetRect(lprcDest, 0, lprcNewWork->top - lprcDest->top);
  227. }
  228. /*
  229. * If the window is sizeable then shrink it if necessary.
  230. */
  231. if (style & WS_THICKFRAME) {
  232. int cSnap = 0;
  233. if (lprcDest->right > lprcNewWork->right) {
  234. lprcDest->right = lprcNewWork->right;
  235. cSnap++;
  236. }
  237. if (lprcDest->bottom > lprcNewWork->bottom) {
  238. lprcDest->bottom = lprcNewWork->bottom;
  239. cSnap++;
  240. }
  241. /*
  242. * Now make sure we didn't turn this normal window into a
  243. * fullscreen window. This is a complete hack but it is much
  244. * better than changing from 800x600 to 640x480 and ending up with
  245. * a bunch of fullscreen apps...
  246. */
  247. if (cSnap == 2) {
  248. InflateRect(lprcDest, -1, -1);
  249. }
  250. }
  251. AllDone:
  252. return pMonitor;
  253. }
  254. #if DBG
  255. /***************************************************************************\
  256. * SetRipFlags
  257. *
  258. * Sets the debug rip flags.
  259. *
  260. * History:
  261. * 16-Aug-1996 adams Created.
  262. \***************************************************************************/
  263. VOID SetRipFlags(
  264. DWORD dwRipFlags)
  265. {
  266. if (gpsi) {
  267. if (!(dwRipFlags & ~RIPF_VALIDUSERFLAGS)) {
  268. gpsi->dwRIPFlags = ((gpsi->dwRIPFlags & ~RIPF_VALIDUSERFLAGS) | dwRipFlags);
  269. }
  270. }
  271. }
  272. /***************************************************************************\
  273. * SetDbgTag
  274. *
  275. * Sets debugging level for a tag.
  276. *
  277. * History:
  278. * 16-Aug-1996 adams Created.
  279. \***************************************************************************/
  280. VOID SetDbgTag(
  281. int tag,
  282. DWORD dwDBGTAGFlags)
  283. {
  284. if (tag > DBGTAG_Max || tag < 0) {
  285. return;
  286. }
  287. if (gpsi && tag < DBGTAG_Max && !(dwDBGTAGFlags & ~DBGTAG_VALIDUSERFLAGS)) {
  288. COPY_FLAG(gpsi->adwDBGTAGFlags[tag], dwDBGTAGFlags, DBGTAG_VALIDUSERFLAGS);
  289. }
  290. }
  291. /***************************************************************************\
  292. * SetDbgTagCount
  293. *
  294. * Sets the number of tags. This is necessary because one can use a
  295. * userkdx.dll that was built in an enlistment with N tags, but use it against
  296. * a system that has M tags (where N != M), which causes obvious problems.
  297. *
  298. * History:
  299. * 05-Oct-2001 JasonSch Created.
  300. \***************************************************************************/
  301. VOID SetDbgTagCount(
  302. DWORD dwCount)
  303. {
  304. gpsi->dwTagCount = dwCount;
  305. }
  306. #endif
  307. /***************************************************************************\
  308. * UpdateWinIniInt
  309. *
  310. * History:
  311. * 18-Apr-1994 mikeke Created
  312. \***************************************************************************/
  313. BOOL UpdateWinIniInt(
  314. PUNICODE_STRING pProfileUserName,
  315. UINT idSection,
  316. UINT wKeyNameId,
  317. int value)
  318. {
  319. WCHAR szTemp[40];
  320. WCHAR szKeyName[40];
  321. swprintf(szTemp, L"%d", value);
  322. ServerLoadString(hModuleWin,
  323. wKeyNameId,
  324. szKeyName,
  325. ARRAY_SIZE(szKeyName));
  326. return FastWriteProfileStringW(pProfileUserName,
  327. idSection,
  328. szKeyName,
  329. szTemp);
  330. }
  331. /***************************************************************************\
  332. * SetDesktopMetrics
  333. *
  334. * History:
  335. * 31-Jan-1994 mikeke Ported
  336. \***************************************************************************/
  337. VOID SetDesktopMetrics(
  338. VOID)
  339. {
  340. LPRECT lprcWork;
  341. lprcWork = &GetPrimaryMonitor()->rcWork;
  342. SYSMET(CXFULLSCREEN) = lprcWork->right - lprcWork->left;
  343. SYSMET(CXMAXIMIZED) = lprcWork->right - lprcWork->left + 2 * SYSMET(CXSIZEFRAME);
  344. SYSMET(CYFULLSCREEN) = lprcWork->bottom - lprcWork->top - SYSMET(CYCAPTION);
  345. SYSMET(CYMAXIMIZED) = lprcWork->bottom - lprcWork->top + 2 * SYSMET(CYSIZEFRAME);
  346. }
  347. /***************************************************************************\
  348. * xxxMetricsRecalc (Win95: MetricsRecalc)
  349. *
  350. * Does work to size/position all minimized or nonminimized
  351. * windows. Called when frame metrics or min metrics are changed.
  352. *
  353. * Note that you can NOT do DeferWindowPos() with this function. SWP doesn't
  354. * work when you do parents and children at the same time--it's only for
  355. * peer windows. Thus we must do SetWindowPos() for each window.
  356. *
  357. * History:
  358. * 06-28-91 MikeHar Ported.
  359. \***************************************************************************/
  360. VOID xxxMetricsRecalc(
  361. UINT wFlags,
  362. int dx,
  363. int dy,
  364. int dyCaption,
  365. int dyMenu)
  366. {
  367. PHWND phwnd;
  368. PWND pwnd;
  369. RECT rc;
  370. PCHECKPOINT pcp;
  371. TL tlpwnd;
  372. BOOL fResized;
  373. PBWL pbwl;
  374. PTHREADINFO ptiCurrent;
  375. int c;
  376. ptiCurrent = PtiCurrent();
  377. pbwl = BuildHwndList(GETDESKINFO(ptiCurrent)->spwnd->spwndChild,
  378. BWL_ENUMLIST | BWL_ENUMCHILDREN,
  379. NULL);
  380. if (!pbwl) {
  381. return;
  382. }
  383. UserAssert(*pbwl->phwndNext == (HWND) 1);
  384. c = (int)(pbwl->phwndNext - pbwl->rghwnd);
  385. for (phwnd = pbwl->rghwnd; c > 0; c--, phwnd++) {
  386. pwnd = RevalidateHwnd(*phwnd);
  387. if (!pwnd) {
  388. continue;
  389. }
  390. ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd);
  391. fResized = FALSE;
  392. if ((wFlags & CALC_MINIMIZE) && TestWF(pwnd, WFMINIMIZED)) {
  393. /*
  394. * We're changing the minimized window dimensions. We need to
  395. * resize. Note that we do NOT move.
  396. */
  397. CopyRect(&rc, (&pwnd->rcWindow));
  398. rc.right += dx;
  399. rc.bottom += dy;
  400. goto PositionWnd;
  401. }
  402. /*
  403. * We're changing the size of the window because the sizing border
  404. * changed.
  405. */
  406. if ((wFlags & CALC_RESIZE) && TestWF(pwnd, WFSIZEBOX)) {
  407. pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
  408. /*
  409. * Update maximized position to account for sizing border
  410. * We do this for DOS box also. This way client of max'ed windows
  411. * stays in same relative position.
  412. */
  413. if (pcp && (pcp->fMaxInitialized)) {
  414. pcp->ptMax.x -= dx;
  415. pcp->ptMax.y -= dy;
  416. }
  417. if (TestWF(pwnd, WFMINIMIZED)) {
  418. if (pcp) {
  419. InflateRect(&pcp->rcNormal, dx, dy);
  420. }
  421. } else {
  422. CopyInflateRect(&rc, (&pwnd->rcWindow), dx, dy);
  423. if (TestWF(pwnd, WFCPRESENT)) {
  424. rc.bottom += dyCaption;
  425. }
  426. if (TestWF(pwnd, WFMPRESENT)) {
  427. rc.bottom += dyMenu;
  428. }
  429. PositionWnd:
  430. fResized = TRUE;
  431. /*
  432. * Remember SWP expects values in PARENT CLIENT coordinates.
  433. */
  434. if (pwnd->spwndParent != PWNDDESKTOP(pwnd)) {
  435. OffsetRect(&rc,
  436. -pwnd->spwndParent->rcClient.left,
  437. -pwnd->spwndParent->rcClient.top);
  438. }
  439. xxxSetWindowPos(pwnd,
  440. PWND_TOP,
  441. rc.left,
  442. rc.top,
  443. rc.right-rc.left,
  444. rc.bottom-rc.top,
  445. SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS |
  446. SWP_FRAMECHANGED | SWP_NOREDRAW);
  447. }
  448. }
  449. /*
  450. * We're changing the nonclient widgets, so recalculate the client.
  451. */
  452. if (wFlags & CALC_FRAME) {
  453. /*
  454. * Delete any cached small icons.
  455. */
  456. if (dyCaption) {
  457. xxxSendMessage(pwnd, WM_SETICON, ICON_RECREATE, 0);
  458. }
  459. if (!TestWF(pwnd, WFMINIMIZED) && !fResized) {
  460. CopyRect(&rc, &(pwnd->rcWindow));
  461. if (TestWF(pwnd, WFMPRESENT)) {
  462. rc.bottom += dyMenu;
  463. }
  464. if (TestWF(pwnd, WFCPRESENT)) {
  465. rc.bottom += dyCaption;
  466. /*
  467. * Maximized MDI child windows position their caption
  468. * outside their parent's client area (negative y). If
  469. * the caption has changed, they need to be repositioned.
  470. */
  471. if (TestWF(pwnd, WFMAXIMIZED)
  472. && TestWF(pwnd, WFCHILD)
  473. && (GETFNID(pwnd->spwndParent) == FNID_MDICLIENT)) {
  474. xxxSetWindowPos(pwnd,
  475. PWND_TOP,
  476. rc.left - pwnd->spwndParent->rcWindow.left,
  477. rc.top - pwnd->spwndParent->rcWindow.top - dyCaption,
  478. rc.right - rc.left,
  479. rc.bottom - rc.top,
  480. SWP_NOZORDER | SWP_NOACTIVATE |
  481. SWP_FRAMECHANGED | SWP_NOREDRAW);
  482. goto LoopCleanup;
  483. }
  484. }
  485. xxxSetWindowPos(pwnd,
  486. PWND_TOP,
  487. 0,
  488. 0,
  489. rc.right-rc.left,
  490. rc.bottom-rc.top,
  491. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE |
  492. SWP_FRAMECHANGED | SWP_NOCOPYBITS |
  493. SWP_NOREDRAW);
  494. }
  495. }
  496. LoopCleanup:
  497. ThreadUnlock(&tlpwnd);
  498. }
  499. FreeHwndList(pbwl);
  500. }
  501. /***************************************************************************\
  502. * FindOldMonitor
  503. *
  504. * Returns the index of the monitor in "pmr" which has the greatest
  505. * overlap with a rectangle. This function is used to determine which
  506. * monitor a window was on after one or more monitor rectangles have
  507. * changed.
  508. *
  509. * History:
  510. * 11-Sep-1996 adams Created.
  511. \***************************************************************************/
  512. int FindOldMonitor(
  513. LPCRECT lprc,
  514. PMONITORRECTS pmr)
  515. {
  516. DWORD dwClosest;
  517. int iClosest, i;
  518. int cxRect, cyRect;
  519. PMONITORPOS pmp;
  520. iClosest = -1;
  521. dwClosest = 0;
  522. cxRect = (lprc->right - lprc->left);
  523. cyRect = (lprc->bottom - lprc->top);
  524. for (i = 0, pmp = pmr->amp; i < pmr->cMonitor; pmp++, i++) {
  525. RECT rcT;
  526. if (IntersectRect(&rcT, lprc, &pmp->rcMonitor)) {
  527. DWORD dwT;
  528. /*
  529. * Convert to width/height.
  530. */
  531. rcT.right -= rcT.left;
  532. rcT.bottom -= rcT.top;
  533. /*
  534. * If fully enclosed, we're done.
  535. */
  536. if (rcT.right == cxRect && rcT.bottom == cyRect) {
  537. return i;
  538. }
  539. /*
  540. * Use largest area.
  541. */
  542. dwT = (DWORD)rcT.right * (DWORD)rcT.bottom;
  543. if (dwT > dwClosest) {
  544. dwClosest = dwT;
  545. iClosest = i;
  546. }
  547. }
  548. }
  549. return iClosest;
  550. }
  551. /***************************************************************************\
  552. * xxxDesktopRecalc
  553. *
  554. * Moves all top-level nonpopup windows into free desktop area,
  555. * attempting to keep them in the same position relative to the monitor
  556. * they were on. Also resets minimized info (so that when a window is
  557. * subsequently minimized it will go to the correct location).
  558. *
  559. * History:
  560. * 11-Sep-1996 adams Created.
  561. \***************************************************************************/
  562. VOID xxxDesktopRecalc(
  563. PMONITORRECTS pmrOld)
  564. {
  565. PWND pwndDesktop;
  566. PSMWP psmwp;
  567. PHWND phwnd;
  568. PBWL pbwl;
  569. PWND pwnd;
  570. CHECKPOINT * pcp;
  571. int iOldMonitor;
  572. int codeFullScreen;
  573. UINT flags = SWP_NOACTIVATE | SWP_NOZORDER;
  574. /*
  575. * We never want CSRSS to position windows synchronously because it
  576. * might get blocked by a hung app. CSRSS needs to reposition windows
  577. * in the TS reconnect and disconnect path as part of changing display
  578. * setting to switch display drivers or to match new client resolution.
  579. */
  580. if (ISCSRSS()) {
  581. flags |= SWP_ASYNCWINDOWPOS;
  582. }
  583. UserVerify(pwndDesktop = _GetDesktopWindow());
  584. if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
  585. return;
  586. }
  587. if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
  588. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1 && psmwp; phwnd++) {
  589. /*
  590. * Make sure this hwnd is still around.
  591. */
  592. if ((pwnd = RevalidateHwnd(*phwnd)) == NULL ||
  593. TestWF(pwnd, WEFTOOLWINDOW)) {
  594. continue;
  595. }
  596. codeFullScreen = TestWF(pwnd, WFFULLSCREEN) ?
  597. NORMALIZERECT_FULLSCREEN : NORMALIZERECT_NORMAL;
  598. pcp = (PCHECKPOINT)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
  599. if (pcp) {
  600. /*
  601. * We don't need to blow away saved maximized positions
  602. * anymore, since the max position is always (for top level
  603. * windows) relative to the origin of the monitor's working
  604. * area. And for child windows, we shouldn't do it period
  605. * anyway.
  606. */
  607. pcp->fMinInitialized = FALSE;
  608. /*
  609. * Figure out which monitor the position was on before things
  610. * got shuffled around and try to keep it on that monitor. If
  611. * it was never visible on a monitor then leave it alone.
  612. */
  613. iOldMonitor = FindOldMonitor(&pcp->rcNormal, pmrOld);
  614. if (iOldMonitor != (UINT)-1) {
  615. NormalizeRect(&pcp->rcNormal,
  616. &pcp->rcNormal,
  617. pmrOld,
  618. iOldMonitor,
  619. codeFullScreen,
  620. pwnd->style);
  621. }
  622. }
  623. /*
  624. * Figure out which monitor the position was on before things got
  625. * shuffled around and try to keep it on that monitor. If it
  626. * was never visible on a monitor then leave it alone.
  627. */
  628. iOldMonitor = FindOldMonitor(&pwnd->rcWindow, pmrOld);
  629. if (iOldMonitor != -1) {
  630. PMONITOR pMonitorDst;
  631. RECT rc;
  632. /*
  633. * Check for maximized apps that are truly maximized (as
  634. * opposed to apps that manage their owm maximized rect).
  635. */
  636. if (TestWF(pwnd, WFMAXIMIZED)) {
  637. LPRECT lprcOldWork = &pmrOld->amp[iOldMonitor].rcWork;
  638. if ( (pwnd->rcWindow.right - pwnd->rcWindow.left >=
  639. lprcOldWork->right - lprcOldWork->left)
  640. &&
  641. (pwnd->rcWindow.bottom - pwnd->rcWindow.top >=
  642. lprcOldWork->bottom - lprcOldWork->top)) {
  643. codeFullScreen = NORMALIZERECT_MAXIMIZED;
  644. }
  645. }
  646. pMonitorDst = NormalizeRect(&rc,
  647. &pwnd->rcWindow,
  648. pmrOld,
  649. iOldMonitor,
  650. codeFullScreen,
  651. pwnd->style);
  652. if (TestWF(pwnd, WFMAXFAKEREGIONAL)) {
  653. UserAssert(pMonitorDst->hrgnMonitor);
  654. pwnd->hrgnClip = pMonitorDst->hrgnMonitor;
  655. }
  656. psmwp = _DeferWindowPos(psmwp,
  657. pwnd,
  658. (PWND)HWND_TOP,
  659. rc.left,
  660. rc.top,
  661. rc.right - rc.left,
  662. rc.bottom - rc.top,
  663. flags);
  664. }
  665. }
  666. if (psmwp) {
  667. xxxEndDeferWindowPosEx(psmwp, TRUE);
  668. }
  669. }
  670. FreeHwndList(pbwl);
  671. }
  672. /***************************************************************************\
  673. * SetWindowMetricInt
  674. *
  675. * History:
  676. * 25-Feb-96 BradG Added Pixel -> TWIPS conversion
  677. \***************************************************************************/
  678. BOOL SetWindowMetricInt(
  679. PUNICODE_STRING pProfileUserName,
  680. WORD wKeyNameId,
  681. int iIniValue)
  682. {
  683. /*
  684. * If you change the below list of STR_* make sure you make a
  685. * corresponding change in FastGetProfileIntFromID.
  686. */
  687. switch (wKeyNameId) {
  688. case STR_BORDERWIDTH:
  689. case STR_SCROLLWIDTH:
  690. case STR_SCROLLHEIGHT:
  691. case STR_CAPTIONWIDTH:
  692. case STR_CAPTIONHEIGHT:
  693. case STR_SMCAPTIONWIDTH:
  694. case STR_SMCAPTIONHEIGHT:
  695. case STR_MENUWIDTH:
  696. case STR_MENUHEIGHT:
  697. case STR_ICONHORZSPACING:
  698. case STR_ICONVERTSPACING:
  699. case STR_MINWIDTH:
  700. case STR_MINHORZGAP:
  701. case STR_MINVERTGAP:
  702. /*
  703. * Always store window metrics in TWIPS
  704. */
  705. iIniValue = -MultDiv(iIniValue, 72*20, gpsi->dmLogPixels);
  706. break;
  707. }
  708. return UpdateWinIniInt(pProfileUserName,
  709. PMAP_METRICS,
  710. wKeyNameId,
  711. iIniValue);
  712. }
  713. /***************************************************************************\
  714. * SetWindowMetricFont
  715. *
  716. * History:
  717. \***************************************************************************/
  718. BOOL SetWindowMetricFont(
  719. PUNICODE_STRING pProfileUserName,
  720. UINT idKey,
  721. LPLOGFONT lplf)
  722. {
  723. return FastWriteProfileValue(pProfileUserName,
  724. PMAP_METRICS,
  725. (LPWSTR)UIntToPtr(idKey),
  726. REG_BINARY,
  727. (LPBYTE)lplf,
  728. sizeof(LOGFONTW));
  729. }
  730. /***************************************************************************\
  731. * SetAndDrawNCMetrics
  732. *
  733. * History:
  734. \***************************************************************************/
  735. BOOL xxxSetAndDrawNCMetrics(
  736. PUNICODE_STRING pProfileUserName,
  737. int clNewBorder,
  738. LPNONCLIENTMETRICS lpnc)
  739. {
  740. int dl;
  741. int dxMinOld;
  742. int dyMinOld;
  743. int cxBorder;
  744. int cyBorder;
  745. int dyCaption;
  746. int dyMenu;
  747. dl = clNewBorder - gpsi->gclBorder;
  748. dxMinOld = SYSMET(CXMINIMIZED);
  749. dyMinOld = SYSMET(CYMINIMIZED);
  750. cxBorder = SYSMET(CXBORDER);
  751. cyBorder = SYSMET(CYBORDER);
  752. /*
  753. * Do we need to recalculate?
  754. */
  755. if (lpnc == NULL && !dl) {
  756. return FALSE;
  757. }
  758. if (lpnc) {
  759. dyCaption = (int)lpnc->iCaptionHeight - SYSMET(CYSIZE);
  760. dyMenu = (int)lpnc->iMenuHeight - SYSMET(CYMENUSIZE);
  761. } else {
  762. dyCaption = dyMenu = 0;
  763. }
  764. /*
  765. * Recalculate the system metrics.
  766. */
  767. xxxSetWindowNCMetrics(pProfileUserName, lpnc, TRUE, clNewBorder);
  768. /*
  769. * Reset our saved menu size/position info.
  770. */
  771. MenuRecalc();
  772. /*
  773. * Reset window sized, positions, frames
  774. */
  775. xxxMetricsRecalc(CALC_FRAME | (dl ? CALC_RESIZE : 0),
  776. dl * cxBorder,
  777. dl * cyBorder,
  778. dyCaption,
  779. dyMenu);
  780. dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
  781. dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
  782. if (dxMinOld || dyMinOld) {
  783. xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
  784. }
  785. xxxRedrawScreen();
  786. return TRUE;
  787. }
  788. /***************************************************************************\
  789. * xxxSetAndDrawMinMetrics
  790. *
  791. * History:
  792. * 13-May-1994 mikeke mikeke Ported
  793. \***************************************************************************/
  794. BOOL xxxSetAndDrawMinMetrics(
  795. PUNICODE_STRING pProfileUserName,
  796. LPMINIMIZEDMETRICS lpmin)
  797. {
  798. /*
  799. * Save minimized window dimensions.
  800. */
  801. int dxMinOld = SYSMET(CXMINIMIZED);
  802. int dyMinOld = SYSMET(CYMINIMIZED);
  803. SetMinMetrics(pProfileUserName,lpmin);
  804. /*
  805. * Do we need to adjust minimized size?
  806. */
  807. dxMinOld = SYSMET(CXMINIMIZED) - dxMinOld;
  808. dyMinOld = SYSMET(CYMINIMIZED) - dyMinOld;
  809. if (dxMinOld || dyMinOld) {
  810. xxxMetricsRecalc(CALC_MINIMIZE, dxMinOld, dyMinOld, 0, 0);
  811. }
  812. xxxRedrawScreen();
  813. return TRUE;
  814. }
  815. /***************************************************************************\
  816. * xxxSPISetNCMetrics
  817. *
  818. * History:
  819. * 13-May-1994 mikeke mikeke Ported
  820. \***************************************************************************/
  821. BOOL xxxSPISetNCMetrics(
  822. PUNICODE_STRING pProfileUserName,
  823. LPNONCLIENTMETRICS lpnc,
  824. BOOL fAlterWinIni)
  825. {
  826. BOOL fWriteAllowed = !fAlterWinIni;
  827. BOOL fChanged = FALSE;
  828. lpnc->iBorderWidth = max(lpnc->iBorderWidth, 1);
  829. lpnc->iBorderWidth = min(lpnc->iBorderWidth, 50);
  830. if (fAlterWinIni) {
  831. fChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, lpnc->iBorderWidth);
  832. fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLWIDTH, lpnc->iScrollWidth);
  833. fChanged &= SetWindowMetricInt(pProfileUserName, STR_SCROLLHEIGHT, lpnc->iScrollHeight);
  834. fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONWIDTH, lpnc->iCaptionWidth);
  835. fChanged &= SetWindowMetricInt(pProfileUserName, STR_CAPTIONHEIGHT, lpnc->iCaptionHeight);
  836. fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONWIDTH, lpnc->iSmCaptionWidth);
  837. fChanged &= SetWindowMetricInt(pProfileUserName, STR_SMCAPTIONHEIGHT, lpnc->iSmCaptionHeight);
  838. fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUWIDTH, lpnc->iMenuWidth);
  839. fChanged &= SetWindowMetricInt(pProfileUserName, STR_MENUHEIGHT, lpnc->iMenuHeight);
  840. fChanged &= SetWindowMetricFont(pProfileUserName, STR_CAPTIONFONT, &lpnc->lfCaptionFont);
  841. fChanged &= SetWindowMetricFont(pProfileUserName, STR_SMCAPTIONFONT, &lpnc->lfSmCaptionFont);
  842. fChanged &= SetWindowMetricFont(pProfileUserName, STR_MENUFONT, &lpnc->lfMenuFont);
  843. fChanged &= SetWindowMetricFont(pProfileUserName, STR_STATUSFONT, &lpnc->lfStatusFont);
  844. fChanged &= SetWindowMetricFont(pProfileUserName, STR_MESSAGEFONT, &lpnc->lfMessageFont);
  845. fWriteAllowed = fChanged;
  846. }
  847. if (fWriteAllowed) {
  848. xxxSetAndDrawNCMetrics(pProfileUserName, lpnc->iBorderWidth, lpnc);
  849. }
  850. return fChanged;
  851. }
  852. /***************************************************************************\
  853. * xxxSPISetMinMetrics
  854. *
  855. * History:
  856. * 13-May-1994 mikeke mikeke Ported
  857. \***************************************************************************/
  858. BOOL xxxSPISetMinMetrics(
  859. PUNICODE_STRING pProfileUserName,
  860. LPMINIMIZEDMETRICS lpmin,
  861. BOOL fAlterWinIni)
  862. {
  863. BOOL fWriteAllowed = !fAlterWinIni;
  864. BOOL fChanged = FALSE;
  865. if (fAlterWinIni) {
  866. fChanged = SetWindowMetricInt(pProfileUserName, STR_MINWIDTH, lpmin->iWidth);
  867. fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINHORZGAP, lpmin->iHorzGap);
  868. fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINVERTGAP, lpmin->iVertGap);
  869. fChanged &= SetWindowMetricInt(pProfileUserName, STR_MINARRANGE, lpmin->iArrange);
  870. fWriteAllowed = fChanged;
  871. }
  872. if (fWriteAllowed) {
  873. xxxSetAndDrawMinMetrics(pProfileUserName, lpmin);
  874. }
  875. return fChanged;
  876. }
  877. /***************************************************************************\
  878. * SPISetIconMetrics
  879. *
  880. * History:
  881. * 13-May-1994 mikeke mikeke Ported
  882. \***************************************************************************/
  883. BOOL SPISetIconMetrics(
  884. PUNICODE_STRING pProfileUserName,
  885. LPICONMETRICS lpicon,
  886. BOOL fAlterWinIni)
  887. {
  888. BOOL fWriteAllowed = !fAlterWinIni;
  889. BOOL fChanged = FALSE;
  890. if (fAlterWinIni) {
  891. fChanged = SetWindowMetricInt(pProfileUserName, STR_ICONHORZSPACING, lpicon->iHorzSpacing);
  892. fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONVERTSPACING, lpicon->iVertSpacing);
  893. fChanged &= SetWindowMetricInt(pProfileUserName, STR_ICONTITLEWRAP, lpicon->iTitleWrap);
  894. fChanged &= SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lpicon->lfFont);
  895. fWriteAllowed = fChanged;
  896. }
  897. if (fWriteAllowed) {
  898. SetIconMetrics(pProfileUserName,lpicon);
  899. xxxRedrawScreen();
  900. }
  901. return fChanged;
  902. }
  903. /***************************************************************************\
  904. * SPISetIconTitleFont
  905. *
  906. * History:
  907. * 13-May-1994 mikeke mikeke Ported
  908. \***************************************************************************/
  909. BOOL SPISetIconTitleFont(
  910. PUNICODE_STRING pProfileUserName,
  911. LPLOGFONT lplf,
  912. BOOL fAlterWinIni)
  913. {
  914. HFONT hfnT;
  915. BOOL fWriteAllowed = !fAlterWinIni;
  916. BOOL fWinIniChanged = FALSE;
  917. if (hfnT = CreateFontFromWinIni(pProfileUserName,lplf, STR_ICONFONT)) {
  918. if (fAlterWinIni) {
  919. if (lplf) {
  920. LOGFONT lf;
  921. GreExtGetObjectW(hfnT, sizeof(LOGFONTW), &lf);
  922. fWinIniChanged = SetWindowMetricFont(pProfileUserName, STR_ICONFONT, &lf);
  923. } else {
  924. /*
  925. * !lParam so go back to current win.ini settings.
  926. */
  927. fWinIniChanged = TRUE;
  928. }
  929. fWriteAllowed = fWinIniChanged;
  930. }
  931. if (fWriteAllowed) {
  932. if (ghIconFont) {
  933. GreMarkDeletableFont(ghIconFont);
  934. GreDeleteObject(ghIconFont);
  935. }
  936. ghIconFont = hfnT;
  937. } else {
  938. GreMarkDeletableFont(hfnT);
  939. GreDeleteObject(hfnT);
  940. }
  941. }
  942. return fWinIniChanged;
  943. }
  944. /***************************************************************************\
  945. * xxxSetSPIMetrics
  946. *
  947. * History:
  948. * 13-May-1994 mikeke mikeke Ported
  949. \***************************************************************************/
  950. BOOL xxxSetSPIMetrics(
  951. PUNICODE_STRING pProfileUserName,
  952. DWORD wFlag,
  953. LPVOID lParam,
  954. BOOL fAlterWinIni)
  955. {
  956. BOOL fWinIniChanged;
  957. switch (wFlag) {
  958. case SPI_SETANIMATION:
  959. if (fAlterWinIni) {
  960. fWinIniChanged = SetWindowMetricInt(pProfileUserName,
  961. STR_MINANIMATE,
  962. (int)((LPANIMATIONINFO)lParam)->iMinAnimate);
  963. if (!fWinIniChanged) {
  964. return FALSE;
  965. }
  966. } else {
  967. fWinIniChanged = FALSE;
  968. }
  969. SET_OR_CLEAR_PUDF(PUDF_ANIMATE, ((LPANIMATIONINFO)lParam)->iMinAnimate);
  970. return fWinIniChanged;
  971. case SPI_SETNONCLIENTMETRICS:
  972. return xxxSPISetNCMetrics(pProfileUserName, (LPNONCLIENTMETRICS)lParam, fAlterWinIni);
  973. case SPI_SETICONMETRICS:
  974. return SPISetIconMetrics(pProfileUserName, (LPICONMETRICS)lParam, fAlterWinIni);
  975. case SPI_SETMINIMIZEDMETRICS:
  976. return xxxSPISetMinMetrics(pProfileUserName, (LPMINIMIZEDMETRICS)lParam, fAlterWinIni);
  977. case SPI_SETICONTITLELOGFONT:
  978. return SPISetIconTitleFont(pProfileUserName, (LPLOGFONT)lParam, fAlterWinIni);
  979. default:
  980. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "SetSPIMetrics. Invalid wFlag: 0x%x", wFlag);
  981. return FALSE;
  982. }
  983. }
  984. /***************************************************************************\
  985. * SetFilterKeys
  986. *
  987. * History:
  988. * 10-12-94 JimA Created.
  989. \***************************************************************************/
  990. BOOL SetFilterKeys(
  991. PUNICODE_STRING pProfileUserName,
  992. LPFILTERKEYS pFilterKeys)
  993. {
  994. LPWSTR pwszd = L"%d";
  995. BOOL fWinIniChanged;
  996. WCHAR szTemp[40];
  997. swprintf(szTemp, pwszd, pFilterKeys->dwFlags);
  998. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  999. PMAP_KEYBOARDRESPONSE,
  1000. L"Flags",
  1001. szTemp);
  1002. swprintf(szTemp, pwszd, pFilterKeys->iWaitMSec);
  1003. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1004. PMAP_KEYBOARDRESPONSE,
  1005. L"DelayBeforeAcceptance",
  1006. szTemp);
  1007. swprintf(szTemp, pwszd, pFilterKeys->iDelayMSec);
  1008. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1009. PMAP_KEYBOARDRESPONSE,
  1010. L"AutoRepeatDelay",
  1011. szTemp);
  1012. swprintf(szTemp, pwszd, pFilterKeys->iRepeatMSec);
  1013. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1014. PMAP_KEYBOARDRESPONSE,
  1015. L"AutoRepeatRate",
  1016. szTemp);
  1017. swprintf(szTemp, pwszd, pFilterKeys->iBounceMSec);
  1018. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1019. PMAP_KEYBOARDRESPONSE,
  1020. L"BounceTime",
  1021. szTemp);
  1022. return fWinIniChanged;
  1023. }
  1024. /***************************************************************************\
  1025. * SetMouseKeys
  1026. *
  1027. * History:
  1028. * 10-12-94 JimA Created.
  1029. \***************************************************************************/
  1030. BOOL SetMouseKeys(
  1031. PUNICODE_STRING pProfileUserName,
  1032. LPMOUSEKEYS pMK)
  1033. {
  1034. LPWSTR pwszd = L"%d";
  1035. BOOL fWinIniChanged;
  1036. WCHAR szTemp[40];
  1037. swprintf(szTemp, pwszd, pMK->dwFlags);
  1038. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  1039. PMAP_MOUSEKEYS,
  1040. L"Flags",
  1041. szTemp);
  1042. swprintf(szTemp, pwszd, pMK->iMaxSpeed);
  1043. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1044. PMAP_MOUSEKEYS,
  1045. L"MaximumSpeed",
  1046. szTemp);
  1047. swprintf(szTemp, pwszd, pMK->iTimeToMaxSpeed);
  1048. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1049. PMAP_MOUSEKEYS,
  1050. L"TimeToMaximumSpeed",
  1051. szTemp);
  1052. return fWinIniChanged;
  1053. }
  1054. /***************************************************************************\
  1055. * SetSoundSentry
  1056. *
  1057. * History:
  1058. * 10-12-94 JimA Created.
  1059. \***************************************************************************/
  1060. BOOL SetSoundSentry(
  1061. PUNICODE_STRING pProfileUserName,
  1062. LPSOUNDSENTRY pSS)
  1063. {
  1064. LPWSTR pwszd = L"%d";
  1065. BOOL fWinIniChanged;
  1066. WCHAR szTemp[40];
  1067. swprintf(szTemp, pwszd, pSS->dwFlags);
  1068. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  1069. PMAP_SOUNDSENTRY,
  1070. L"Flags",
  1071. szTemp);
  1072. swprintf(szTemp, pwszd, pSS->iFSTextEffect);
  1073. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1074. PMAP_SOUNDSENTRY,
  1075. L"TextEffect",
  1076. szTemp);
  1077. swprintf(szTemp, pwszd, pSS->iWindowsEffect);
  1078. fWinIniChanged &= FastWriteProfileStringW(pProfileUserName,
  1079. PMAP_SOUNDSENTRY,
  1080. L"WindowsEffect",
  1081. szTemp);
  1082. return fWinIniChanged;
  1083. }
  1084. /***************************************************************************\
  1085. * CalculateMouseSensitivity
  1086. *
  1087. * The resultant table looks like this...
  1088. *
  1089. * Sens | Sensitivity Adjustment
  1090. * 0 | 0 * SENS_SCALAR ALGORITHM 0<=NUM<=2
  1091. * 1 | 1/32 * SENS_SCALAR (NUM/32)*SENS_SCALAR
  1092. * 2 | 1/16 * SENS_SCALAR
  1093. * 3 | 1/8 * SENS_SCALAR ALGORITHM 3<=NUM<=10
  1094. * 4 | 1/4 (2/8) * SENS_SCALAR ((NUM-2)/8)*SENS_SCALAR
  1095. * 5 | 3/8 * SENS_SCALAR
  1096. * 6 | 1/2 (4/8) * SENS_SCALAR
  1097. * 7 | 5/8 * SENS_SCALAR
  1098. * 8 | 3/4 (6/8) * SENS_SCALAR
  1099. * 9 | 7/8 * SENS_SCALAR
  1100. * 10 | 1 * SENS_SCALAR
  1101. * 11 | 5/4 * SENS_SCALAR ALGORITHM NUM>=11
  1102. * 12 | 3/2 (6/4) * SENS_SCALAR ((NUM-6)/4)*SENS_SCALAR
  1103. * 13 | 7/4 * SENS_SCALAR
  1104. * 14 | 2 (8/4) * SENS_SCALAR
  1105. * 15 | 9/4 * SENS_SCALAR
  1106. * 16 | 5/2 (10/4) * SENS_SCALAR
  1107. * 17 | 11/4 * SENS_SCALAR
  1108. * 18 | 3 (12/4) * SENS_SCALAR
  1109. * 19 | 13/4 * SENS_SCALAR
  1110. * 20 | 7/2 (14/4) * SENS_SCALAR
  1111. *
  1112. * COMMENTS: Sensitivities are constrained to be between 1 and 20.
  1113. *
  1114. * History:
  1115. * 09-27-96 jparsons Created.
  1116. \***************************************************************************/
  1117. LONG CalculateMouseSensitivity(
  1118. LONG lSens)
  1119. {
  1120. LONG lSenFactor;
  1121. if (lSens <= 2) {
  1122. lSenFactor = lSens * 256 / 32;
  1123. } else if (lSens >= 3 && lSens <= 10 ) {
  1124. lSenFactor = (lSens - 2) * 256 /8;
  1125. } else {
  1126. lSenFactor= (lSens - 6) * 256 / 4;
  1127. }
  1128. return lSenFactor;
  1129. }
  1130. /***************************************************************************\
  1131. * xxxSystemParametersInfo
  1132. *
  1133. * SPI_GETBEEP: wParam is not used. lParam is long pointer to a boolean which
  1134. * gets true if beep on, false if beep off.
  1135. *
  1136. * SPI_SETBEEP: wParam is a bool which sets beep on (true) or off (false).
  1137. * lParam is not used.
  1138. *
  1139. * SPI_GETMOUSE: wParam is not used. lParam is long pointer to an integer
  1140. * array where rgw[0] gets xMouseThreshold, rgw[1] gets
  1141. * yMouseThreshold, and rgw[2] gets gMouseSpeed.
  1142. *
  1143. * SPI_SETMOUSE: wParam is not used. lParam is long pointer to an integer
  1144. * array as described above. User's values are set to values
  1145. * in array.
  1146. *
  1147. * SPI_GETBORDER: wParam is not used. lParam is long pointer to an integer
  1148. * which gets the value of clBorder (border multiplier factor).
  1149. *
  1150. * SPI_SETBORDER: wParam is an integer which sets gpsi->gclBorder.
  1151. * lParam is not used.
  1152. *
  1153. * SPI_GETKEYBOARDDELAY: wParam is not used. lParam is a long pointer to an int
  1154. * which gets the current keyboard repeat delay setting.
  1155. *
  1156. * SPI_SETKEYBOARDDELAY: wParam is the new keyboard delay setting.
  1157. * lParam is not used.
  1158. *
  1159. * SPI_GETKEYBOARDSPEED: wParam is not used. lParam is a long pointer
  1160. * to an int which gets the current keyboard repeat
  1161. * speed setting.
  1162. *
  1163. * SPI_SETKEYBOARDSPEED: wParam is the new keyboard speed setting.
  1164. * lParam is not used.
  1165. *
  1166. * SPI_KANJIMENU: wParam contains:
  1167. * 1 - Mouse accelerator
  1168. * 2 - ASCII accelerator
  1169. * 3 - Kana accelerator
  1170. * lParam is not used. The wParam value is stored in the global
  1171. * KanjiMenu for use in accelerator displaying & searching.
  1172. *
  1173. * SPI_LANGDRIVER: wParam is not used.
  1174. * lParam contains a LPSTR to the new language driver filename.
  1175. *
  1176. * SPI_ICONHORIZONTALSPACING: wParam is the width in pixels of an icon cell.
  1177. *
  1178. * SPI_ICONVERTICALSPACING: wParam is the height in pixels of an icon cell.
  1179. *
  1180. * SPI_GETSCREENSAVETIMEOUT: wParam is not used
  1181. * lParam is a pointer to an int which gets the screen saver
  1182. * timeout value.
  1183. *
  1184. * SPI_SETSCREENSAVETIMEOUT: wParam is the time in seconds for the system
  1185. * to be idle before screensaving.
  1186. *
  1187. * SPI_GETSCREENSAVEACTIVE: lParam is a pointer to a BOOL which gets TRUE
  1188. * if the screensaver is active else gets false.
  1189. *
  1190. * SPI_SETSCREENSAVEACTIVE: if wParam is TRUE, screensaving is activated
  1191. * else it is deactivated.
  1192. *
  1193. *
  1194. * SPI_SETBLOCKSENDINPUTRESETS:
  1195. * SPI_GETBLOCKSENDINPUTRESETS:
  1196. * wParam is BOOL signifying if this is active or not.
  1197. *
  1198. * SPI_GETLOWPOWERTIMEOUT:
  1199. * SPI_GETPOWEROFFTIMEOUT: wParam is not used
  1200. * lParam is a pointer to an int which gets the appropriate
  1201. * power saving screen blanker timeout value.
  1202. *
  1203. * SPI_SETLOWPOWERTIMEOUT:
  1204. * SPI_SETPOWEROFFTIMEOUT: wParam is the time in seconds for the system
  1205. * to be idle before power saving screen blanking.
  1206. *
  1207. * SPI_GETLOWPOWERACTIVE:
  1208. * SPI_GETPOWEROFFACTIVE: lParam is a pointer to a BOOL which gets TRUE
  1209. * if the power saving screen blanker is active else gets false.
  1210. *
  1211. * SPI_SETLOWPOWERACTIVE:
  1212. * SPI_SETPOWEROFFACTIVE: if wParam is TRUE, power saving screen blanking is
  1213. * activated else it is deactivated.
  1214. *
  1215. * SPI_GETGRIDGRANULARITY: Obsolete. Returns 1 always.
  1216. *
  1217. * SPI_SETGRIDGRANULARITY: Obsolete. Does nothing.
  1218. *
  1219. * SPI_SETDESKWALLPAPER: wParam is not used; lParam is a long ptr to a string
  1220. * that holds the name of the bitmap file to be used as the
  1221. * desktop wall paper.
  1222. *
  1223. * SPI_SETDESKPATTERN: Both wParam and lParam are not used; USER will read the
  1224. * "pattern=" from WIN.INI and make it as the current desktop
  1225. * pattern;
  1226. *
  1227. * SPI_GETICONTITLEWRAP: lParam is LPINT which gets 0 if wrapping if off
  1228. * else gets 1.
  1229. *
  1230. * SPI_SETICONTITLEWRAP: wParam specifies TRUE to turn wrapping on else false
  1231. *
  1232. * SPI_GETMENUDROPALIGNMENT: lParam is LPINT which gets 0 specifies if menus
  1233. * drop left aligned else 1 if drop right aligned.
  1234. *
  1235. * SPI_SETMENUDROPALIGNMENT: wParam 0 specifies if menus drop left aligned else
  1236. * the drop right aligned.
  1237. *
  1238. * SPI_SETDOUBLECLKWIDTH: wParam specifies the width of the rectangle
  1239. * within which the second click of a double click must fall
  1240. * for it to be registered as a double click.
  1241. *
  1242. * SPI_SETDOUBLECLKHEIGHT: wParam specifies the height of the rectangle
  1243. * within which the second click of a double click must fall
  1244. * for it to be registered as a double click.
  1245. *
  1246. * SPI_GETICONTITLELOGFONT: lParam is a pointer to a LOGFONT struct which
  1247. * gets the logfont for the current icon title font. wParam
  1248. * specifies the size of the logfont struct.
  1249. *
  1250. * SPI_SETDOUBLECLICKTIME: wParm specifies the double click time
  1251. *
  1252. * SPI_SETMOUSEBUTTONSWAP: if wParam is 1, swap mouse buttons else if wParam
  1253. * is 0, don't swap buttons
  1254. * SPI_SETDRAGFULLWINDOWS: wParam = fSet.
  1255. * SPI_GETDRAGFULLWINDOWS: returns fSet.
  1256. *
  1257. * SPI_GETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
  1258. * specifies the size of the filterkeys struct.
  1259. *
  1260. * SPI_SETFILTERKEYS: lParam is a pointer to a FILTERKEYS struct. wParam
  1261. * is not used.
  1262. *
  1263. * SPI_GETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
  1264. * specifies the size of the stickykeys struct.
  1265. *
  1266. * SPI_SETSTICKYKEYS: lParam is a pointer to a STICKYKEYS struct. wParam
  1267. * is not used.
  1268. *
  1269. * SPI_GETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
  1270. * specifies the size of the mousekeys struct.
  1271. *
  1272. * SPI_SETMOUSEKEYS: lParam is a pointer to a MOUSEKEYS struct. wParam
  1273. * is not used.
  1274. *
  1275. * SPI_GETACCESSTIMEOUT: lParam is a pointer to an ACCESSTIMEOUT struct.
  1276. * wParam specifies the size of the accesstimeout struct.
  1277. *
  1278. * SPI_SETACCESSTIMEOUT: lParam is a pointer to a ACCESSTIMEOUT struct.
  1279. * wParam is not used.
  1280. *
  1281. * SPI_GETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
  1282. * specifies the size of the togglekeys struct.
  1283. *
  1284. * SPI_SETTOGGLEKEYS: lParam is a pointer to a TOGGLEKEYS struct. wParam
  1285. * is not used.
  1286. *
  1287. * SPI_GETKEYBOARDPREF: lParam is a pointer to a BOOL.
  1288. * wParam is not used.
  1289. *
  1290. * SPI_SETKEYBOARDPREF: wParam is a BOOL.
  1291. * lParam is not used.
  1292. *
  1293. * SPI_GETSCREENREADER: lParam is a pointer to a BOOL.
  1294. * wParam is not used.
  1295. *
  1296. * SPI_SETSCREENREADER: wParam is a BOOL.
  1297. * lParam is not used.
  1298. *
  1299. * SPI_GETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
  1300. * specifies the size of the showsounds struct.
  1301. *
  1302. * SPI_SETSHOWSOUNDS: lParam is a pointer to a SHOWSOUNDS struct. wParam
  1303. * is not used.
  1304. *
  1305. * SPI_GETNONCLIENTMETRICS: lParam is a pointer to a NONCLIENTMETRICSW struct.
  1306. * wPAram is not used.
  1307. *
  1308. * SPI_GETSNAPTODEFBUTTON: lParam is a pointer to a BOOL which gets TRUE
  1309. * if the snap to default push button is active else gets false.
  1310. *
  1311. * SPI_SETSNAPTODEFBUTTON: if wParam is TRUE, dialog boxes will snap the mouse
  1312. * pointer to the default push button when created.
  1313. *
  1314. * SPI_GETFONTSMOOTHING:
  1315. * wParam is unused
  1316. * lParam is LPINT for boolean fFontSmoothing
  1317. *
  1318. * SPI_SETFONTSMOOTHING:
  1319. * wParam is INT for boolean fFontSmoothing
  1320. *
  1321. * SPI_GETWHEELSCROLLLINES: lParam is a pointer to a ULONG to receive the
  1322. * suggested number of lines to scroll when the wheel is
  1323. * rotated. wParam is unused.
  1324. *
  1325. * SPI_SETWHEELSCROLLLINES: wParam is a ULONG containing the suggested number
  1326. * of lines to scroll when the wheel is rotated. lParam is
  1327. * unused.
  1328. *
  1329. * SPI_SETSCREENSAVERRUNNING / SPI_SCREENSAVERRUNNING: not supported on NT.
  1330. * SPI_GETSCREENSAVERRUNNING: wParam - Not used. lParam a pointer to a BOOL which
  1331. * will receive TRUE is a screen saver is running or FALSE otherwise.
  1332. *
  1333. * SPI_SETSHOWIMEUI wParam is TRUE or FALSE
  1334. * SPI_GETSHOWIMEUI neither wParam or lParam used
  1335. *
  1336. * History:
  1337. * 06-28-91 MikeHar Ported.
  1338. * 12-8-93 SanfordS Added SPI_SET/GETDRAGFULLWINDOWS
  1339. * 20-May-1996 adams Added SPI_SET/GETWHEELSCROLLLINES
  1340. * 02-Feb-2002 MMcCr Added SPI_SET/GETBLOCKSENDINPUTRESETS
  1341. \***************************************************************************/
  1342. BOOL xxxSystemParametersInfo(
  1343. UINT wFlag,
  1344. DWORD wParam,
  1345. PVOID lParam,
  1346. UINT flags)
  1347. {
  1348. PPROCESSINFO ppi = PpiCurrent();
  1349. LPWSTR pwszd = L"%d";
  1350. WCHAR szSection[40];
  1351. WCHAR szTemp[40];
  1352. WCHAR szPat[MAX_PATH];
  1353. BOOL fWinIniChanged = FALSE;
  1354. BOOL fAlterWinIni = ((flags & SPIF_UPDATEINIFILE) != 0);
  1355. BOOL fSendWinIniChange = ((flags & SPIF_SENDCHANGE) != 0);
  1356. BOOL fWriteAllowed = !fAlterWinIni;
  1357. ACCESS_MASK amRequest;
  1358. LARGE_UNICODE_STRING strSection;
  1359. int *piTimeOut;
  1360. int iResID;
  1361. TL tlName;
  1362. PUNICODE_STRING pProfileUserName = NULL;
  1363. UserAssert(IsWinEventNotifyDeferredOK());
  1364. /*
  1365. * CONSIDER(adams): Many of the SPI_GET* could be implemented
  1366. * on the client side (SnapTo, WheelScrollLines, etc.).
  1367. */
  1368. /*
  1369. * Features not implemented.
  1370. */
  1371. switch (wFlag) {
  1372. case SPI_TIMEOUTS:
  1373. case SPI_KANJIMENU:
  1374. case SPI_LANGDRIVER:
  1375. case SPI_UNUSED39:
  1376. case SPI_UNUSED40:
  1377. case SPI_SETPENWINDOWS:
  1378. case SPI_GETWINDOWSEXTENSION:
  1379. case SPI_SETSCREENSAVERRUNNING: // same as SPI_SCREENSAVERRUNNING
  1380. case SPI_GETSERIALKEYS:
  1381. case SPI_SETSERIALKEYS:
  1382. RIPERR1(ERROR_INVALID_PARAMETER,
  1383. RIP_WARNING,
  1384. "SPI_ 0x%lx parameter not supported", wFlag);
  1385. return FALSE;
  1386. }
  1387. /*
  1388. * Perform access check. Always grant access to CSR.
  1389. */
  1390. if (ppi->Process != gpepCSRSS) {
  1391. switch (wFlag) {
  1392. case SPI_SETBEEP:
  1393. case SPI_SETMOUSE:
  1394. case SPI_SETBORDER:
  1395. case SPI_SETKEYBOARDSPEED:
  1396. case SPI_SETDEFAULTINPUTLANG:
  1397. case SPI_SETSCREENSAVETIMEOUT:
  1398. case SPI_SETSCREENSAVEACTIVE:
  1399. case SPI_SETBLOCKSENDINPUTRESETS:
  1400. case SPI_SETLOWPOWERTIMEOUT:
  1401. case SPI_SETPOWEROFFTIMEOUT:
  1402. case SPI_SETLOWPOWERACTIVE:
  1403. case SPI_SETPOWEROFFACTIVE:
  1404. case SPI_SETGRIDGRANULARITY:
  1405. case SPI_SETDESKWALLPAPER:
  1406. case SPI_SETDESKPATTERN:
  1407. case SPI_SETKEYBOARDDELAY:
  1408. case SPI_SETICONTITLEWRAP:
  1409. case SPI_SETMENUDROPALIGNMENT:
  1410. case SPI_SETDOUBLECLKWIDTH:
  1411. case SPI_SETDOUBLECLKHEIGHT:
  1412. case SPI_SETDOUBLECLICKTIME:
  1413. case SPI_SETMOUSEBUTTONSWAP:
  1414. case SPI_SETICONTITLELOGFONT:
  1415. case SPI_SETFASTTASKSWITCH:
  1416. case SPI_SETFILTERKEYS:
  1417. case SPI_SETTOGGLEKEYS:
  1418. case SPI_SETMOUSEKEYS:
  1419. case SPI_SETSHOWSOUNDS:
  1420. case SPI_SETSTICKYKEYS:
  1421. case SPI_SETACCESSTIMEOUT:
  1422. case SPI_SETSOUNDSENTRY:
  1423. case SPI_SETKEYBOARDPREF:
  1424. case SPI_SETSCREENREADER:
  1425. case SPI_SETSNAPTODEFBUTTON:
  1426. case SPI_SETANIMATION:
  1427. case SPI_SETNONCLIENTMETRICS:
  1428. case SPI_SETICONMETRICS:
  1429. case SPI_SETMINIMIZEDMETRICS:
  1430. case SPI_SETWORKAREA:
  1431. case SPI_SETFONTSMOOTHING:
  1432. case SPI_SETMOUSEHOVERWIDTH:
  1433. case SPI_SETMOUSEHOVERHEIGHT:
  1434. case SPI_SETMOUSEHOVERTIME:
  1435. case SPI_SETWHEELSCROLLLINES:
  1436. case SPI_SETMENUSHOWDELAY:
  1437. case SPI_SETHIGHCONTRAST:
  1438. case SPI_SETDRAGFULLWINDOWS:
  1439. case SPI_SETDRAGWIDTH:
  1440. case SPI_SETDRAGHEIGHT:
  1441. case SPI_SETCURSORS:
  1442. case SPI_SETICONS:
  1443. case SPI_SETLANGTOGGLE:
  1444. amRequest = WINSTA_WRITEATTRIBUTES;
  1445. break;
  1446. case SPI_ICONHORIZONTALSPACING:
  1447. case SPI_ICONVERTICALSPACING:
  1448. if (IS_PTR(lParam)) {
  1449. amRequest = WINSTA_READATTRIBUTES;
  1450. } else if (wParam) {
  1451. amRequest = WINSTA_WRITEATTRIBUTES;
  1452. } else {
  1453. return TRUE;
  1454. }
  1455. break;
  1456. default:
  1457. if ((wFlag & SPIF_RANGETYPEMASK) && (wFlag & SPIF_SET)) {
  1458. amRequest = WINSTA_WRITEATTRIBUTES;
  1459. } else {
  1460. amRequest = WINSTA_READATTRIBUTES;
  1461. }
  1462. break;
  1463. }
  1464. if (amRequest == WINSTA_READATTRIBUTES) {
  1465. RETURN_IF_ACCESS_DENIED(ppi->amwinsta, amRequest, FALSE);
  1466. } else {
  1467. UserAssert(amRequest == WINSTA_WRITEATTRIBUTES);
  1468. if (!CheckWinstaWriteAttributesAccess()) {
  1469. return FALSE;
  1470. }
  1471. }
  1472. /*
  1473. * If we're reading, then set the write flag to ensure that the
  1474. * return value will be TRUE.
  1475. */
  1476. if (amRequest == WINSTA_READATTRIBUTES) {
  1477. fWriteAllowed = TRUE;
  1478. }
  1479. } else {
  1480. fWriteAllowed = TRUE;
  1481. }
  1482. /*
  1483. * Make sure the section buffer is terminated.
  1484. */
  1485. szSection[0] = 0;
  1486. switch (wFlag) {
  1487. case SPI_GETBEEP:
  1488. (*(BOOL *)lParam) = TEST_BOOL_PUDF(PUDF_BEEP);
  1489. break;
  1490. case SPI_SETBEEP:
  1491. if (fAlterWinIni) {
  1492. ServerLoadString(hModuleWin,
  1493. (wParam ? STR_BEEPYES : STR_BEEPNO),
  1494. (LPWSTR)szTemp,
  1495. 10);
  1496. fWinIniChanged = FastUpdateWinIni(NULL,
  1497. PMAP_BEEP,
  1498. STR_BEEP,
  1499. szTemp);
  1500. fWriteAllowed = fWinIniChanged;
  1501. }
  1502. if (fWriteAllowed) {
  1503. SET_OR_CLEAR_PUDF(PUDF_BEEP, wParam);
  1504. }
  1505. break;
  1506. case SPI_SETMOUSESPEED:
  1507. if (((LONG_PTR) lParam < MOUSE_SENSITIVITY_MIN) || ((LONG_PTR) lParam > MOUSE_SENSITIVITY_MAX)) {
  1508. return FALSE;
  1509. }
  1510. if (fAlterWinIni) {
  1511. swprintf(szTemp, pwszd, lParam);
  1512. fWinIniChanged = FastUpdateWinIni(NULL,
  1513. PMAP_MOUSE,
  1514. STR_MOUSESENSITIVITY,
  1515. szTemp);
  1516. fWriteAllowed = fWinIniChanged;
  1517. }
  1518. if (fWriteAllowed) {
  1519. gMouseSensitivity = PtrToLong(lParam);
  1520. gMouseSensitivityFactor = CalculateMouseSensitivity(PtrToLong(lParam));
  1521. #ifdef SUBPIXEL_MOUSE
  1522. ResetMouseAccelerationCurves();
  1523. #endif // SUBPIXEL_MOUSE
  1524. }
  1525. break;
  1526. case SPI_GETMOUSESPEED:
  1527. *((LPINT)lParam) = gMouseSensitivity;
  1528. break;
  1529. case SPI_SETMOUSETRAILS:
  1530. if (fAlterWinIni) {
  1531. swprintf(szTemp, pwszd, wParam);
  1532. fWinIniChanged = FastUpdateWinIni(NULL,
  1533. PMAP_MOUSE,
  1534. STR_MOUSETRAILS,
  1535. szTemp);
  1536. fWriteAllowed = fWinIniChanged;
  1537. }
  1538. if (fWriteAllowed) {
  1539. SetMouseTrails(wParam);
  1540. }
  1541. break;
  1542. case SPI_GETMOUSETRAILS:
  1543. *((LPINT)lParam) = gMouseTrails ? gMouseTrails + 1 : gMouseTrails;
  1544. break;
  1545. case SPI_GETMOUSE:
  1546. ((LPINT)lParam)[0] = gMouseThresh1;
  1547. ((LPINT)lParam)[1] = gMouseThresh2;
  1548. ((LPINT)lParam)[2] = gMouseSpeed;
  1549. break;
  1550. case SPI_SETMOUSE:
  1551. if (fAlterWinIni) {
  1552. BOOL bWritten1, bWritten2, bWritten3;
  1553. pProfileUserName = CreateProfileUserName(&tlName);
  1554. bWritten1 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, ((LPINT)lParam)[0]);
  1555. bWritten2 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, ((LPINT)lParam)[1]);
  1556. bWritten3 = UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, ((LPINT)lParam)[2]);
  1557. if (bWritten1 && bWritten2 && bWritten3) {
  1558. fWinIniChanged = TRUE;
  1559. } else {
  1560. /*
  1561. * Attempt to backout any changes.
  1562. */
  1563. if (bWritten1) {
  1564. UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH1, gMouseThresh1);
  1565. }
  1566. if (bWritten2) {
  1567. UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSETHRESH2, gMouseThresh2);
  1568. }
  1569. if (bWritten3) {
  1570. UpdateWinIniInt(pProfileUserName, PMAP_MOUSE, STR_MOUSESPEED, gMouseSpeed);
  1571. }
  1572. }
  1573. fWriteAllowed = fWinIniChanged;
  1574. FreeProfileUserName(pProfileUserName, &tlName);
  1575. }
  1576. if (fWriteAllowed) {
  1577. gMouseThresh1 = ((LPINT)lParam)[0];
  1578. gMouseThresh2 = ((LPINT)lParam)[1];
  1579. gMouseSpeed = ((LPINT)lParam)[2];
  1580. }
  1581. break;
  1582. case SPI_GETSNAPTODEFBUTTON:
  1583. (*(LPBOOL)lParam) = TEST_BOOL_PUSIF(PUSIF_SNAPTO);
  1584. break;
  1585. case SPI_SETSNAPTODEFBUTTON:
  1586. wParam = (wParam != 0);
  1587. if (fAlterWinIni) {
  1588. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SNAPTO, wParam);
  1589. fWriteAllowed = fWinIniChanged;
  1590. }
  1591. if (fWriteAllowed) {
  1592. SET_OR_CLEAR_PUSIF(PUSIF_SNAPTO, wParam);
  1593. }
  1594. break;
  1595. case SPI_GETBORDER:
  1596. (*(LPINT)lParam) = gpsi->gclBorder;
  1597. break;
  1598. case SPI_SETBORDER:
  1599. wParam = max((int)wParam, 1);
  1600. wParam = min(wParam, 50);
  1601. if (wParam == gpsi->gclBorder) {
  1602. /*
  1603. * If border size doesn't change, don't waste time.
  1604. */
  1605. break;
  1606. }
  1607. pProfileUserName = CreateProfileUserName(&tlName);
  1608. if (fAlterWinIni) {
  1609. fWinIniChanged = SetWindowMetricInt(pProfileUserName, STR_BORDERWIDTH, wParam);
  1610. fWriteAllowed = fWinIniChanged;
  1611. }
  1612. if (fWriteAllowed) {
  1613. xxxSetAndDrawNCMetrics(pProfileUserName, wParam, NULL);
  1614. /*
  1615. * Nice magic number of 3. So if the border is set to 1, there
  1616. * are actualy 4 pixels in the border.
  1617. */
  1618. bSetDevDragWidth(gpDispInfo->hDev, gpsi->gclBorder + BORDER_EXTRA);
  1619. }
  1620. FreeProfileUserName(pProfileUserName, &tlName);
  1621. break;
  1622. case SPI_GETFONTSMOOTHING:
  1623. (*(LPINT)lParam) = !!(GreGetFontEnumeration() & FE_AA_ON);
  1624. break;
  1625. case SPI_SETFONTSMOOTHING:
  1626. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_FONTSMOOTHING)) {
  1627. fAlterWinIni = FALSE;
  1628. fWriteAllowed = FALSE;
  1629. }
  1630. wParam = (wParam ? FE_AA_ON : 0);
  1631. if (fAlterWinIni) {
  1632. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_FONTSMOOTHING, wParam);
  1633. fWriteAllowed = fWinIniChanged;
  1634. }
  1635. if (fWriteAllowed) {
  1636. GreSetFontEnumeration(wParam | FE_SET_AA);
  1637. }
  1638. break;
  1639. case SPI_GETKEYBOARDSPEED:
  1640. (*(int *)lParam) = (gnKeyboardSpeed & KSPEED_MASK);
  1641. break;
  1642. case SPI_SETKEYBOARDSPEED:
  1643. /*
  1644. * Limit the range to max value; SetKeyboardRate takes both speed
  1645. * and delay.
  1646. */
  1647. if (wParam > KSPEED_MASK) { // KSPEED_MASK == KSPEED_MAX
  1648. wParam = KSPEED_MASK;
  1649. }
  1650. if (fAlterWinIni) {
  1651. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYSPEED, wParam);
  1652. fWriteAllowed = fWinIniChanged;
  1653. }
  1654. if (fWriteAllowed) {
  1655. gnKeyboardSpeed = (gnKeyboardSpeed & ~KSPEED_MASK) | wParam;
  1656. SetKeyboardRate(gnKeyboardSpeed);
  1657. }
  1658. break;
  1659. case SPI_GETKEYBOARDDELAY:
  1660. (*(int *)lParam) = (gnKeyboardSpeed & KDELAY_MASK) >> KDELAY_SHIFT;
  1661. break;
  1662. case SPI_SETKEYBOARDDELAY:
  1663. if (fAlterWinIni) {
  1664. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_KEYBOARD, STR_KEYDELAY, wParam);
  1665. fWriteAllowed = fWinIniChanged;
  1666. }
  1667. if (fWriteAllowed) {
  1668. gnKeyboardSpeed = (gnKeyboardSpeed & ~KDELAY_MASK) | (wParam << KDELAY_SHIFT);
  1669. SetKeyboardRate(gnKeyboardSpeed);
  1670. }
  1671. break;
  1672. case SPI_SETLANGTOGGLE:
  1673. /*
  1674. * wParam unused, lParam unused. Simply reread the registry setting.
  1675. */
  1676. return GetKbdLangSwitch(NULL);
  1677. break;
  1678. case SPI_GETDEFAULTINPUTLANG:
  1679. /*
  1680. * wParam unused. lParam is a pointer to buffer to store hkl.
  1681. */
  1682. UserAssert(gspklBaseLayout != NULL);
  1683. (*(HKL *)lParam) = gspklBaseLayout->hkl;
  1684. break;
  1685. case SPI_SETDEFAULTINPUTLANG: {
  1686. PKL pkl;
  1687. /*
  1688. * wParam unused. lParam is new language of hkl (depending on
  1689. * whether the hiword is set).
  1690. */
  1691. pkl = HKLtoPKL(PtiCurrent(), *(HKL *)lParam);
  1692. if (pkl == NULL) {
  1693. return FALSE;
  1694. }
  1695. if (fWriteAllowed) {
  1696. Lock(&gspklBaseLayout, pkl);
  1697. }
  1698. break;
  1699. }
  1700. case SPI_ICONHORIZONTALSPACING:
  1701. if (IS_PTR(lParam)) {
  1702. *(LPINT)lParam = SYSMET(CXICONSPACING);
  1703. } else if (wParam) {
  1704. /*
  1705. * Make sure icon spacing is reasonable.
  1706. */
  1707. wParam = max(wParam, (DWORD)SYSMET(CXICON));
  1708. if (fAlterWinIni) {
  1709. fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONHORZSPACING, wParam );
  1710. fWriteAllowed = fWinIniChanged;
  1711. }
  1712. if (fWriteAllowed) {
  1713. SYSMET(CXICONSPACING) = (UINT)wParam;
  1714. }
  1715. }
  1716. break;
  1717. case SPI_ICONVERTICALSPACING:
  1718. if (IS_PTR(lParam)) {
  1719. *(LPINT)lParam = SYSMET(CYICONSPACING);
  1720. } else if (wParam) {
  1721. wParam = max(wParam, (DWORD)SYSMET(CYICON));
  1722. if (fAlterWinIni) {
  1723. fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONVERTSPACING, wParam);
  1724. fWriteAllowed = fWinIniChanged;
  1725. }
  1726. if (fWriteAllowed) {
  1727. SYSMET(CYICONSPACING) = (UINT)wParam;
  1728. }
  1729. }
  1730. break;
  1731. case SPI_GETSCREENSAVETIMEOUT:
  1732. piTimeOut = &giScreenSaveTimeOutMs;
  1733. goto HandleGetTimeouts;
  1734. case SPI_GETLOWPOWERTIMEOUT:
  1735. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
  1736. return FALSE;
  1737. }
  1738. piTimeOut = &giLowPowerTimeOutMs;
  1739. goto HandleGetTimeouts;
  1740. case SPI_GETPOWEROFFTIMEOUT:
  1741. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
  1742. return FALSE;
  1743. }
  1744. piTimeOut = &giPowerOffTimeOutMs;
  1745. HandleGetTimeouts:
  1746. /*
  1747. * If the screen saver is disabled, store this fact as a negative
  1748. * time out value (we give the Control Panel the absolute value
  1749. * of the screen saver time out). We store this in milliseconds.
  1750. */
  1751. if (*piTimeOut < 0) {
  1752. (*(int *)lParam) = -*piTimeOut / 1000;
  1753. } else {
  1754. (*(int *)lParam) = *piTimeOut / 1000;
  1755. }
  1756. break;
  1757. case SPI_SETSCREENSAVETIMEOUT:
  1758. piTimeOut = &giScreenSaveTimeOutMs;
  1759. iResID = STR_SCREENSAVETIMEOUT;
  1760. goto HandleSetTimeouts;
  1761. case SPI_SETLOWPOWERTIMEOUT:
  1762. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
  1763. return FALSE;
  1764. }
  1765. piTimeOut = &giLowPowerTimeOutMs;
  1766. iResID = STR_LOWPOWERTIMEOUT;
  1767. goto HandleSetTimeouts;
  1768. case SPI_SETPOWEROFFTIMEOUT:
  1769. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
  1770. return FALSE;
  1771. }
  1772. piTimeOut = &giPowerOffTimeOutMs;
  1773. iResID = STR_POWEROFFTIMEOUT;
  1774. HandleSetTimeouts:
  1775. if (gfSwitchInProgress) {
  1776. return FALSE;
  1777. }
  1778. /*
  1779. * Maintain the screen save active/inactive state when setting the
  1780. * time out value. Timeout value is given in seconds but stored
  1781. * in milliseconds
  1782. */
  1783. if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
  1784. fAlterWinIni = FALSE;
  1785. fWriteAllowed = FALSE;
  1786. }
  1787. if (fAlterWinIni) {
  1788. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
  1789. fWriteAllowed = fWinIniChanged;
  1790. }
  1791. if (fWriteAllowed) {
  1792. if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
  1793. // Call video driver here to exit power down mode.
  1794. // KdPrint(("Exit video power down mode\n"));
  1795. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  1796. }
  1797. glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
  1798. if (!gbBlockSendInputResets) {
  1799. glinp.timeLastInputMessage = NtGetTickCount();
  1800. }
  1801. if (*piTimeOut < 0) {
  1802. *piTimeOut = -((int)wParam);
  1803. } else {
  1804. *piTimeOut = wParam;
  1805. }
  1806. *piTimeOut *= 1000;
  1807. }
  1808. break;
  1809. case SPI_GETBLOCKSENDINPUTRESETS:
  1810. (*(BOOL *)lParam) = (gbBlockSendInputResets != 0);
  1811. break;
  1812. case SPI_GETSCREENSAVEACTIVE:
  1813. (*(BOOL *)lParam) = (giScreenSaveTimeOutMs > 0);
  1814. break;
  1815. case SPI_GETLOWPOWERACTIVE:
  1816. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
  1817. return FALSE;
  1818. }
  1819. (*(BOOL *)lParam) = (giLowPowerTimeOutMs > 0);
  1820. break;
  1821. case SPI_GETPOWEROFFACTIVE:
  1822. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
  1823. return FALSE;
  1824. }
  1825. (*(BOOL *)lParam) = (giPowerOffTimeOutMs > 0);
  1826. break;
  1827. case SPI_SETSCREENSAVEACTIVE:
  1828. piTimeOut = &giScreenSaveTimeOutMs;
  1829. iResID = STR_SCREENSAVEACTIVE;
  1830. goto HandleSetActive;
  1831. case SPI_SETLOWPOWERACTIVE:
  1832. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD1))) {
  1833. return FALSE;
  1834. }
  1835. piTimeOut = &giLowPowerTimeOutMs;
  1836. iResID = STR_LOWPOWERACTIVE;
  1837. goto HandleSetActive;
  1838. case SPI_SETPOWEROFFACTIVE:
  1839. if (!NT_SUCCESS(DrvGetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD3))) {
  1840. return FALSE;
  1841. }
  1842. piTimeOut = &giPowerOffTimeOutMs;
  1843. iResID = STR_POWEROFFACTIVE;
  1844. HandleSetActive:
  1845. if (gfSwitchInProgress) {
  1846. return FALSE;
  1847. }
  1848. wParam = (wParam != 0);
  1849. if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(iResID))) {
  1850. fAlterWinIni = FALSE;
  1851. fWriteAllowed = FALSE;
  1852. }
  1853. if (fAlterWinIni) {
  1854. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, iResID, wParam);
  1855. fWriteAllowed = fWinIniChanged;
  1856. }
  1857. if (fWriteAllowed) {
  1858. if (glinp.dwFlags & LINP_POWERTIMEOUTS) {
  1859. // Call video driver here to exit power down mode.
  1860. // KdPrint(("Exit video power down mode\n"));
  1861. DrvSetMonitorPowerState(gpDispInfo->pmdev, PowerDeviceD0);
  1862. }
  1863. glinp.dwFlags &= ~LINP_INPUTTIMEOUTS;
  1864. if (!gbBlockSendInputResets) {
  1865. glinp.timeLastInputMessage = NtGetTickCount();
  1866. }
  1867. if ((*piTimeOut < 0 && wParam) ||
  1868. (*piTimeOut >= 0 && !wParam)) {
  1869. *piTimeOut = -*piTimeOut;
  1870. }
  1871. }
  1872. break;
  1873. case SPI_SETBLOCKSENDINPUTRESETS:
  1874. wParam = (wParam != 0);
  1875. if (CheckDesktopPolicy(NULL, (PCWSTR)IntToPtr(STR_BLOCKSENDINPUTRESETS))) {
  1876. fAlterWinIni = FALSE;
  1877. fWriteAllowed = FALSE;
  1878. }
  1879. if (fAlterWinIni) {
  1880. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_DESKTOP, STR_BLOCKSENDINPUTRESETS, wParam);
  1881. fWriteAllowed = fWinIniChanged;
  1882. }
  1883. if (fWriteAllowed) {
  1884. gbBlockSendInputResets = wParam;
  1885. }
  1886. break;
  1887. case SPI_SETDESKWALLPAPER:
  1888. pProfileUserName = CreateProfileUserName(&tlName);
  1889. if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DTBITMAP)) {
  1890. fAlterWinIni = FALSE;
  1891. fWriteAllowed = FALSE;
  1892. }
  1893. if (fAlterWinIni) {
  1894. if (wParam != (WPARAM)-1) {
  1895. /*
  1896. * Save current wallpaper in case of failure.
  1897. *
  1898. * Unlike the rest of the per-user settings that got updated
  1899. * in xxxUpdatePerUserSystemParameters, the wallpaper is
  1900. * being updated via a direct call to SystemParametersInfo
  1901. * from UpdatePerUserSystemParameters. Force remote settings
  1902. * check in this case.
  1903. */
  1904. FastGetProfileStringFromIDW(pProfileUserName,
  1905. PMAP_DESKTOP,
  1906. STR_DTBITMAP,
  1907. TEXT(""),
  1908. szPat,
  1909. ARRAY_SIZE(szPat),
  1910. POLICY_REMOTE);
  1911. fWinIniChanged = FastUpdateWinIni(pProfileUserName,
  1912. PMAP_DESKTOP,
  1913. STR_DTBITMAP,
  1914. (LPWSTR)lParam);
  1915. fWriteAllowed = fWinIniChanged;
  1916. } else {
  1917. fWriteAllowed = TRUE;
  1918. }
  1919. }
  1920. if (fWriteAllowed) {
  1921. if (xxxSetDeskWallpaper(pProfileUserName,(LPWSTR)lParam)) {
  1922. if (grpdeskRitInput) {
  1923. xxxInternalInvalidate(grpdeskRitInput->pDeskInfo->spwnd,
  1924. HRGN_FULL,
  1925. RDW_INVALIDATE |
  1926. RDW_ERASE |
  1927. RDW_FRAME |
  1928. RDW_ALLCHILDREN);
  1929. }
  1930. } else if (fAlterWinIni && (wParam != 0xFFFFFFFF)) {
  1931. /*
  1932. * Backout any change to win.ini.
  1933. */
  1934. FastUpdateWinIni(pProfileUserName,PMAP_DESKTOP, STR_DTBITMAP, szPat);
  1935. fWinIniChanged = FALSE;
  1936. fWriteAllowed = fWinIniChanged;
  1937. } else if (!fAlterWinIni) {
  1938. /*
  1939. * Bug 304109 - joejo
  1940. * Make sure we return a 0 retval if we didn't do anything!
  1941. */
  1942. fWinIniChanged = FALSE;
  1943. fWriteAllowed = fWinIniChanged;
  1944. }
  1945. }
  1946. FreeProfileUserName(pProfileUserName, &tlName);
  1947. break;
  1948. case SPI_GETDESKWALLPAPER:
  1949. /*
  1950. * Get the string from the gobal var, not the registry, as it's
  1951. * more current.
  1952. */
  1953. if (gpszWall != NULL) {
  1954. /*
  1955. * Copy the global wallpaper name ONLY if noni-null.
  1956. */
  1957. wcscpy(lParam, gpszWall);
  1958. } else {
  1959. /*
  1960. * Null out the string so no garbage can corrupt the user's
  1961. * buffer.
  1962. */
  1963. (*(LPWSTR)lParam) = (WCHAR)0;
  1964. }
  1965. break;
  1966. case SPI_SETDESKPATTERN: {
  1967. BOOL fRet;
  1968. if (wParam == -1 && lParam != 0) {
  1969. return FALSE;
  1970. }
  1971. pProfileUserName = CreateProfileUserName(&tlName);
  1972. if (CheckDesktopPolicy(pProfileUserName, (PCWSTR)STR_DESKPATTERN)) {
  1973. fAlterWinIni = FALSE;
  1974. fWriteAllowed = FALSE;
  1975. }
  1976. if (fAlterWinIni && wParam != -1) {
  1977. /*
  1978. * Save the current pattern in case of failure.
  1979. */
  1980. FastGetProfileStringFromIDW(pProfileUserName,
  1981. PMAP_DESKTOP,
  1982. STR_DESKPATTERN,
  1983. TEXT(""),
  1984. szPat,
  1985. ARRAY_SIZE(szPat),
  1986. 0);
  1987. fWinIniChanged = FastUpdateWinIni(pProfileUserName,
  1988. PMAP_DESKTOP,
  1989. STR_DESKPATTERN,
  1990. (LPWSTR)lParam);
  1991. fWriteAllowed = fWinIniChanged;
  1992. }
  1993. if (fWriteAllowed) {
  1994. fRet = xxxSetDeskPattern(pProfileUserName,
  1995. wParam == -1 ? (LPWSTR)-1 : (LPWSTR)lParam,
  1996. FALSE);
  1997. if (!fRet) {
  1998. /*
  1999. * Back out any change to win.ini.
  2000. */
  2001. if (fAlterWinIni && wParam != -1) {
  2002. FastUpdateWinIni(pProfileUserName,
  2003. PMAP_DESKTOP,
  2004. STR_DESKPATTERN,
  2005. szPat);
  2006. }
  2007. FreeProfileUserName(pProfileUserName, &tlName);
  2008. return FALSE;
  2009. }
  2010. }
  2011. }
  2012. FreeProfileUserName(pProfileUserName, &tlName);
  2013. break;
  2014. case SPI_GETICONTITLEWRAP:
  2015. *((int *)lParam) = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
  2016. break;
  2017. case SPI_SETICONTITLEWRAP:
  2018. wParam = (wParam != 0);
  2019. if (fAlterWinIni) {
  2020. fWinIniChanged = SetWindowMetricInt(NULL, STR_ICONTITLEWRAP, wParam);
  2021. fWriteAllowed = fWinIniChanged;
  2022. }
  2023. if (fWriteAllowed) {
  2024. SET_OR_CLEAR_PUDF(PUDF_ICONTITLEWRAP, wParam);
  2025. xxxMetricsRecalc(CALC_FRAME, 0, 0, 0, 0);
  2026. }
  2027. break;
  2028. case SPI_SETDRAGWIDTH:
  2029. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGWIDTH)) {
  2030. fAlterWinIni = FALSE;
  2031. fWriteAllowed = FALSE;
  2032. }
  2033. if (fAlterWinIni) {
  2034. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGWIDTH, wParam);
  2035. fWriteAllowed = fWinIniChanged;
  2036. }
  2037. if (fWriteAllowed) {
  2038. SYSMET(CXDRAG) = wParam;
  2039. }
  2040. break;
  2041. case SPI_SETDRAGHEIGHT:
  2042. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGHEIGHT)) {
  2043. fAlterWinIni = FALSE;
  2044. fWriteAllowed = FALSE;
  2045. }
  2046. if (fAlterWinIni) {
  2047. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGHEIGHT, wParam);
  2048. fWriteAllowed = fWinIniChanged;
  2049. }
  2050. if (fWriteAllowed) {
  2051. SYSMET(CYDRAG) = wParam;
  2052. }
  2053. break;
  2054. case SPI_GETMENUDROPALIGNMENT:
  2055. (*(int *)lParam) = (SYSMET(MENUDROPALIGNMENT));
  2056. break;
  2057. case SPI_SETMENUDROPALIGNMENT:
  2058. if (fAlterWinIni) {
  2059. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_WINDOWSU, STR_MENUDROPALIGNMENT, wParam);
  2060. fWriteAllowed = fWinIniChanged;
  2061. }
  2062. if (fWriteAllowed) {
  2063. SYSMET(MENUDROPALIGNMENT) = (BOOL)(wParam != 0);
  2064. }
  2065. break;
  2066. case SPI_SETDOUBLECLKWIDTH:
  2067. if (fAlterWinIni) {
  2068. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKWIDTH, wParam);
  2069. fWriteAllowed = fWinIniChanged;
  2070. }
  2071. if (fWriteAllowed) {
  2072. SYSMET(CXDOUBLECLK) = wParam;
  2073. }
  2074. break;
  2075. case SPI_SETDOUBLECLKHEIGHT:
  2076. if (fAlterWinIni) {
  2077. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_DOUBLECLICKHEIGHT, wParam);
  2078. fWriteAllowed = fWinIniChanged;
  2079. }
  2080. if (fWriteAllowed) {
  2081. SYSMET(CYDOUBLECLK) = wParam;
  2082. }
  2083. break;
  2084. case SPI_GETICONTITLELOGFONT:
  2085. GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), lParam);
  2086. break;
  2087. case SPI_SETICONTITLELOGFONT:
  2088. {
  2089. if (lParam != NULL) {
  2090. if (wParam != sizeof(LOGFONTW)) {
  2091. return FALSE;
  2092. }
  2093. } else if (wParam) {
  2094. return FALSE;
  2095. }
  2096. pProfileUserName = CreateProfileUserName(&tlName);
  2097. fWinIniChanged = xxxSetSPIMetrics(pProfileUserName, wFlag, lParam, fAlterWinIni);
  2098. FreeProfileUserName(pProfileUserName, &tlName);
  2099. if (fAlterWinIni) {
  2100. fWriteAllowed = fWinIniChanged;
  2101. }
  2102. break;
  2103. }
  2104. case SPI_SETDOUBLECLICKTIME:
  2105. if (fAlterWinIni) {
  2106. fWinIniChanged = UpdateWinIniInt(NULL,PMAP_MOUSE, STR_DBLCLKSPEED, wParam);
  2107. fWriteAllowed = fWinIniChanged;
  2108. }
  2109. if (fWriteAllowed) {
  2110. _SetDoubleClickTime((UINT)wParam);
  2111. }
  2112. break;
  2113. case SPI_GETANIMATION: {
  2114. LPANIMATIONINFO lpai = (LPANIMATIONINFO) lParam;
  2115. if (lpai == NULL || wParam != sizeof(ANIMATIONINFO)) {
  2116. return FALSE;
  2117. }
  2118. lpai->cbSize = sizeof(ANIMATIONINFO);
  2119. lpai->iMinAnimate = TEST_BOOL_PUDF(PUDF_ANIMATE);
  2120. break;
  2121. }
  2122. case SPI_GETNONCLIENTMETRICS: {
  2123. LPNONCLIENTMETRICS lpnc = (LPNONCLIENTMETRICS) lParam;
  2124. if (lpnc == NULL) {
  2125. return FALSE;
  2126. }
  2127. GetWindowNCMetrics(lpnc);
  2128. break;
  2129. }
  2130. case SPI_GETMINIMIZEDMETRICS: {
  2131. LPMINIMIZEDMETRICS lpmin = (LPMINIMIZEDMETRICS)lParam;
  2132. lpmin->cbSize = sizeof(MINIMIZEDMETRICS);
  2133. lpmin->iWidth = SYSMET(CXMINIMIZED) - 2 * SYSMET(CXFIXEDFRAME);
  2134. lpmin->iHorzGap = SYSMET(CXMINSPACING) - SYSMET(CXMINIMIZED);
  2135. lpmin->iVertGap = SYSMET(CYMINSPACING) - SYSMET(CYMINIMIZED);
  2136. lpmin->iArrange = SYSMET(ARRANGE);
  2137. break;
  2138. }
  2139. case SPI_GETICONMETRICS: {
  2140. LPICONMETRICS lpicon = (LPICONMETRICS)lParam;
  2141. lpicon->cbSize = sizeof(ICONMETRICS);
  2142. lpicon->iHorzSpacing = SYSMET(CXICONSPACING);
  2143. lpicon->iVertSpacing = SYSMET(CYICONSPACING);
  2144. lpicon->iTitleWrap = TEST_BOOL_PUDF(PUDF_ICONTITLEWRAP);
  2145. GreExtGetObjectW(ghIconFont, sizeof(LOGFONTW), &(lpicon->lfFont));
  2146. break;
  2147. }
  2148. case SPI_SETANIMATION:
  2149. case SPI_SETNONCLIENTMETRICS:
  2150. case SPI_SETICONMETRICS:
  2151. case SPI_SETMINIMIZEDMETRICS:
  2152. {
  2153. fWinIniChanged = xxxSetSPIMetrics(NULL, wFlag, lParam, fAlterWinIni);
  2154. if (fAlterWinIni) {
  2155. fWriteAllowed = fWinIniChanged;
  2156. }
  2157. ServerLoadString(hModuleWin, STR_METRICS, szSection, ARRAY_SIZE(szSection));
  2158. break;
  2159. }
  2160. case SPI_SETMOUSEBUTTONSWAP:
  2161. if (fAlterWinIni) {
  2162. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_SWAPBUTTONS, wParam);
  2163. fWriteAllowed = fWinIniChanged;
  2164. }
  2165. if (fWriteAllowed) {
  2166. _SwapMouseButton((wParam != 0));
  2167. }
  2168. break;
  2169. case SPI_GETFASTTASKSWITCH:
  2170. *((PINT)lParam) = TRUE; // Do the work so we don't anger anybody.
  2171. case SPI_SETFASTTASKSWITCH:
  2172. RIPMSG0(RIP_WARNING,"SPI_SETFASTTASKSWITCH and SPI_GETFASTTASKSWITCH are obsolete actions.");
  2173. break;
  2174. case SPI_GETWORKAREA:
  2175. CopyRect((LPRECT)lParam, &GetPrimaryMonitor()->rcWork);
  2176. break;
  2177. case SPI_SETWORKAREA:
  2178. {
  2179. RECT rcNewWork;
  2180. LPRECT lprcNewWork;
  2181. PMONITOR pMonitorWork;
  2182. lprcNewWork = (LPRECT)lParam;
  2183. /*
  2184. * Validate Rectangle.
  2185. */
  2186. if (lprcNewWork != NULL &&
  2187. (lprcNewWork->right < lprcNewWork->left ||
  2188. lprcNewWork->bottom < lprcNewWork->top)) {
  2189. RIPMSG0(RIP_WARNING, "Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...)\n");
  2190. return FALSE;
  2191. }
  2192. /*
  2193. * Figure out which monitor has the working area.
  2194. */
  2195. if (!lprcNewWork) {
  2196. pMonitorWork = GetPrimaryMonitor();
  2197. lprcNewWork = &pMonitorWork->rcMonitor;
  2198. } else {
  2199. pMonitorWork = _MonitorFromRect(lprcNewWork, MONITOR_DEFAULTTOPRIMARY);
  2200. }
  2201. /*
  2202. * Get new working area, clipped to monitor of course.
  2203. */
  2204. if (!IntersectRect(&rcNewWork, lprcNewWork, &pMonitorWork->rcMonitor) ||
  2205. !EqualRect(&rcNewWork, lprcNewWork))
  2206. {
  2207. /*
  2208. * Complain.
  2209. */
  2210. RIPERR4(
  2211. ERROR_INVALID_PARAMETER,
  2212. RIP_WARNING,
  2213. "Bad work rectangle passed to SystemParametersInfo(SPI_SETWORKAREA, ...) %d, %d, %d, %d",
  2214. lprcNewWork->left, lprcNewWork->top, lprcNewWork->right, lprcNewWork->bottom);
  2215. return FALSE;
  2216. }
  2217. if (!EqualRect(&pMonitorWork->rcWork, &rcNewWork)) {
  2218. PMONITORRECTS pmr;
  2219. /*
  2220. * If we are going to reposition windows, remember the old
  2221. * monitor positions for xxxDesktopRecalc.
  2222. */
  2223. if (wParam) {
  2224. pmr = SnapshotMonitorRects();
  2225. if (!pmr) {
  2226. return FALSE;
  2227. }
  2228. }
  2229. pMonitorWork->rcWork = rcNewWork;
  2230. if (pMonitorWork == GetPrimaryMonitor()) {
  2231. SetDesktopMetrics();
  2232. }
  2233. /*
  2234. * Reposition windows.
  2235. */
  2236. if (wParam) {
  2237. TL tlPool;
  2238. ThreadLockPool(PtiCurrent(), pmr, &tlPool);
  2239. xxxDesktopRecalc(pmr);
  2240. ThreadUnlockAndFreePool(PtiCurrent(), &tlPool);
  2241. }
  2242. fWinIniChanged = TRUE;
  2243. }
  2244. fWriteAllowed = TRUE;
  2245. break;
  2246. }
  2247. case SPI_SETDRAGFULLWINDOWS:
  2248. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_DRAGFULLWINDOWS)) {
  2249. fAlterWinIni = FALSE;
  2250. fWriteAllowed = FALSE;
  2251. }
  2252. wParam = (wParam == 1);
  2253. if (fAlterWinIni) {
  2254. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_DRAGFULLWINDOWS, wParam);
  2255. fWriteAllowed = fWinIniChanged;
  2256. }
  2257. if (fWriteAllowed) {
  2258. SET_OR_CLEAR_PUDF(PUDF_DRAGFULLWINDOWS, wParam);
  2259. }
  2260. break;
  2261. case SPI_GETDRAGFULLWINDOWS:
  2262. *((PINT)lParam) = TEST_BOOL_PUDF(PUDF_DRAGFULLWINDOWS);
  2263. break;
  2264. case SPI_GETFILTERKEYS:
  2265. {
  2266. LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
  2267. int cbSkip = sizeof(gFilterKeys.cbSize);
  2268. if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
  2269. return FALSE;
  2270. }
  2271. if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
  2272. return FALSE;
  2273. }
  2274. /*
  2275. * In the future we may support multiple sizes of this data
  2276. * structure. Don't change the cbSize field of the data
  2277. * structure passed in.
  2278. */
  2279. RtlCopyMemory((LPVOID)((LPBYTE)pFK + cbSkip),
  2280. (LPVOID)((LPBYTE)&gFilterKeys + cbSkip),
  2281. pFK->cbSize - cbSkip);
  2282. }
  2283. break;
  2284. case SPI_SETFILTERKEYS:
  2285. {
  2286. LPFILTERKEYS pFK = (LPFILTERKEYS)lParam;
  2287. if (wParam != 0 && wParam != sizeof(FILTERKEYS)) {
  2288. return FALSE;
  2289. }
  2290. if (!pFK || pFK->cbSize != sizeof(FILTERKEYS)) {
  2291. return FALSE;
  2292. }
  2293. /*
  2294. * SlowKeys and BounceKeys cannot both be active simultaneously
  2295. */
  2296. if (pFK->iWaitMSec && pFK->iBounceMSec) {
  2297. return FALSE;
  2298. }
  2299. /*
  2300. * Do some parameter validation. We will fail on unsupported and
  2301. * undefined bits being set.
  2302. */
  2303. if ((pFK->dwFlags & FKF_VALID) != pFK->dwFlags) {
  2304. return FALSE;
  2305. }
  2306. /*
  2307. * FKF_AVAILABLE can't be set via API. Use registry value.
  2308. */
  2309. if (TEST_ACCESSFLAG(FilterKeys, FKF_AVAILABLE)) {
  2310. pFK->dwFlags |= FKF_AVAILABLE;
  2311. } else {
  2312. pFK->dwFlags &= ~FKF_AVAILABLE;
  2313. }
  2314. if (pFK->iWaitMSec > 20000 ||
  2315. pFK->iDelayMSec > 20000 ||
  2316. pFK->iRepeatMSec > 20000 ||
  2317. pFK->iBounceMSec > 20000) {
  2318. return FALSE;
  2319. }
  2320. if (fAlterWinIni) {
  2321. pProfileUserName = CreateProfileUserName(&tlName);
  2322. fWinIniChanged = SetFilterKeys(pProfileUserName, pFK);
  2323. fWriteAllowed = fWinIniChanged;
  2324. if (!fWinIniChanged) {
  2325. /*
  2326. * Back out any changes to win.ini.
  2327. */
  2328. SetFilterKeys(pProfileUserName, &gFilterKeys);
  2329. }
  2330. FreeProfileUserName(pProfileUserName, &tlName);
  2331. }
  2332. if (fWriteAllowed) {
  2333. RtlCopyMemory(&gFilterKeys, pFK, pFK->cbSize);
  2334. /*
  2335. * Don't allow user to change cbSize field.
  2336. */
  2337. gFilterKeys.cbSize = sizeof(FILTERKEYS);
  2338. if (!TEST_ACCESSFLAG(FilterKeys, FKF_FILTERKEYSON)) {
  2339. StopFilterKeysTimers();
  2340. }
  2341. SetAccessEnabledFlag();
  2342. if (FCallHookTray()) {
  2343. xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
  2344. ACCESS_FILTERKEYS,
  2345. 0,
  2346. WH_SHELL);
  2347. }
  2348. PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_FILTERKEYS);
  2349. }
  2350. }
  2351. break;
  2352. case SPI_GETSTICKYKEYS:
  2353. {
  2354. LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
  2355. int cbSkip = sizeof(gStickyKeys.cbSize);
  2356. if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
  2357. return FALSE;
  2358. }
  2359. if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
  2360. return FALSE;
  2361. }
  2362. /*
  2363. * In the future we may support multiple sizes of this data
  2364. * structure. Don't change the cbSize field of the data
  2365. * structure passed in.
  2366. */
  2367. RtlCopyMemory((LPVOID)((LPBYTE)pSK + cbSkip),
  2368. (LPVOID)((LPBYTE)&gStickyKeys + cbSkip),
  2369. pSK->cbSize - cbSkip);
  2370. pSK->dwFlags &= ~SKF_STATEINFO;
  2371. pSK->dwFlags |= (gLatchBits&0xff) <<24;
  2372. #if SKF_LALTLATCHED != 0x10000000
  2373. #error SKF_LALTLATCHED value is incorrect
  2374. #endif
  2375. #if SKF_LCTLLATCHED != 0x04000000
  2376. #error SKF_LCTLLATCHED value is incorrect
  2377. #endif
  2378. #if SKF_LSHIFTLATCHED != 0x01000000
  2379. #error SKF_LSHIFTLATCHED value is incorrect
  2380. #endif
  2381. #if SKF_RALTLATCHED != 0x20000000
  2382. #error SKF_RALTLATCHED value is incorrect
  2383. #endif
  2384. #if SKF_RCTLLATCHED != 0x08000000
  2385. #error SKF_RCTLLATCHED value is incorrect
  2386. #endif
  2387. #if SKF_RSHIFTLATCHED != 0x02000000
  2388. #error SKF_RSHIFTLATCHED value is incorrect
  2389. #endif
  2390. pSK->dwFlags |= (gLockBits&0xff) <<16;
  2391. #if SKF_LALTLOCKED != 0x00100000
  2392. #error SKF_LALTLOCKED value is incorrect
  2393. #endif
  2394. #if SKF_LCTLLOCKED != 0x00040000
  2395. #error SKF_LCTLLOCKED value is incorrect
  2396. #endif
  2397. #if SKF_LSHIFTLOCKED != 0x00010000
  2398. #error SKF_LSHIFTLOCKED value is incorrect
  2399. #endif
  2400. #if SKF_RALTLOCKED != 0x00200000
  2401. #error SKF_RALTLOCKED value is incorrect
  2402. #endif
  2403. #if SKF_RCTLLOCKED != 0x00080000
  2404. #error SKF_RCTLLOCKED value is incorrect
  2405. #endif
  2406. #if SKF_RSHIFTLOCKED != 0x00020000
  2407. #error SKF_RSHIFTLOCKED value is incorrect
  2408. #endif
  2409. }
  2410. break;
  2411. case SPI_SETSTICKYKEYS:
  2412. {
  2413. LPSTICKYKEYS pSK = (LPSTICKYKEYS)lParam;
  2414. BOOL fWasOn;
  2415. fWasOn = TEST_BOOL_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON);
  2416. if (wParam != 0 && wParam != sizeof(STICKYKEYS)) {
  2417. return FALSE;
  2418. }
  2419. if (!pSK || pSK->cbSize != sizeof(STICKYKEYS)) {
  2420. return FALSE;
  2421. }
  2422. /*
  2423. * Do some parameter validation. We will fail on unsupported and
  2424. * undefined bits being set.
  2425. *
  2426. * Don't penalize them for using data from SPI_GETSTICKYKEYS,
  2427. * though.
  2428. */
  2429. pSK->dwFlags &= ~SKF_STATEINFO;
  2430. if ((pSK->dwFlags & SKF_VALID) != pSK->dwFlags) {
  2431. return FALSE;
  2432. }
  2433. /*
  2434. * SKF_AVAILABLE can't be set via API. Use registry value.
  2435. */
  2436. if (TEST_ACCESSFLAG(StickyKeys, SKF_AVAILABLE)) {
  2437. pSK->dwFlags |= SKF_AVAILABLE;
  2438. } else {
  2439. pSK->dwFlags &= ~SKF_AVAILABLE;
  2440. }
  2441. if (fAlterWinIni) {
  2442. swprintf(szTemp, pwszd, pSK->dwFlags);
  2443. fWinIniChanged = FastWriteProfileStringW(NULL,
  2444. PMAP_STICKYKEYS,
  2445. L"Flags",
  2446. szTemp);
  2447. fWriteAllowed = fWinIniChanged;
  2448. }
  2449. if (fWriteAllowed) {
  2450. RtlCopyMemory(&gStickyKeys, pSK, pSK->cbSize);
  2451. /*
  2452. * Don't allow user to change cbSize field.
  2453. */
  2454. gStickyKeys.cbSize = sizeof(STICKYKEYS);
  2455. if (!TEST_ACCESSFLAG(StickyKeys, SKF_STICKYKEYSON) && fWasOn) {
  2456. xxxTurnOffStickyKeys();
  2457. }
  2458. SetAccessEnabledFlag();
  2459. if (FCallHookTray()) {
  2460. xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
  2461. ACCESS_STICKYKEYS,
  2462. 0,
  2463. WH_SHELL);
  2464. }
  2465. PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_STICKYKEYS);
  2466. }
  2467. }
  2468. break;
  2469. case SPI_GETTOGGLEKEYS:
  2470. {
  2471. LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
  2472. int cbSkip = sizeof(gToggleKeys.cbSize);
  2473. if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
  2474. return FALSE;
  2475. }
  2476. if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
  2477. return FALSE;
  2478. }
  2479. /*
  2480. * In the future we may support multiple sizes of this data
  2481. * structure. Don't change the cbSize field of the data
  2482. * structure passed in.
  2483. */
  2484. RtlCopyMemory((LPVOID)((LPBYTE)pTK + cbSkip),
  2485. (LPVOID)((LPBYTE)&gToggleKeys + cbSkip),
  2486. pTK->cbSize - cbSkip);
  2487. }
  2488. break;
  2489. case SPI_SETTOGGLEKEYS:
  2490. {
  2491. LPTOGGLEKEYS pTK = (LPTOGGLEKEYS)lParam;
  2492. if (wParam != 0 && wParam != sizeof(TOGGLEKEYS)) {
  2493. return FALSE;
  2494. }
  2495. if (!pTK || pTK->cbSize != sizeof(TOGGLEKEYS)) {
  2496. return FALSE;
  2497. }
  2498. /*
  2499. * Do some parameter validation. We will fail on unsupported and
  2500. * undefined bits being set.
  2501. */
  2502. if ((pTK->dwFlags & TKF_VALID) != pTK->dwFlags) {
  2503. return FALSE;
  2504. }
  2505. /*
  2506. * TKF_AVAILABLE can't be set via API. Use registry value.
  2507. */
  2508. if (TEST_ACCESSFLAG(ToggleKeys, TKF_AVAILABLE)) {
  2509. pTK->dwFlags |= TKF_AVAILABLE;
  2510. } else {
  2511. pTK->dwFlags &= ~TKF_AVAILABLE;
  2512. }
  2513. if (fAlterWinIni) {
  2514. swprintf(szTemp, pwszd, pTK->dwFlags);
  2515. fWinIniChanged = FastWriteProfileStringW(NULL,
  2516. PMAP_TOGGLEKEYS,
  2517. L"Flags",
  2518. szTemp);
  2519. fWriteAllowed = fWinIniChanged;
  2520. }
  2521. if (fWriteAllowed) {
  2522. RtlCopyMemory(&gToggleKeys, pTK, pTK->cbSize);
  2523. /*
  2524. * Don't allow user to change cbSize field.
  2525. */
  2526. gToggleKeys.cbSize = sizeof(TOGGLEKEYS);
  2527. SetAccessEnabledFlag();
  2528. }
  2529. }
  2530. break;
  2531. case SPI_GETMOUSEKEYS:
  2532. {
  2533. LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
  2534. int cbSkip = sizeof(gMouseKeys.cbSize);
  2535. if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
  2536. return FALSE;
  2537. }
  2538. if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
  2539. return FALSE;
  2540. }
  2541. /*
  2542. * In the future we may support multiple sizes of this data
  2543. * structure. Don't change the cbSize field of the data
  2544. * structure passed in.
  2545. */
  2546. RtlCopyMemory((LPVOID)((LPBYTE)pMK + cbSkip),
  2547. (LPVOID)((LPBYTE)&gMouseKeys + cbSkip),
  2548. pMK->cbSize - cbSkip);
  2549. pMK->dwFlags &= ~MKF_STATEINFO;
  2550. if (gbMKMouseMode) {
  2551. pMK->dwFlags |= MKF_MOUSEMODE;
  2552. }
  2553. pMK->dwFlags |= (gwMKButtonState & 3) << 24;
  2554. #if MOUSE_BUTTON_LEFT != 0x01
  2555. #error MOUSE_BUTTON_LEFT value is incorrect
  2556. #endif
  2557. #if MOUSE_BUTTON_RIGHT != 0x02
  2558. #error MOUSE_BUTTON_RIGHT value is incorrect
  2559. #endif
  2560. #if MKF_LEFTBUTTONDOWN != 0x01000000
  2561. #error MKF_LEFTBUTTONDOWN value is incorrect
  2562. #endif
  2563. #if MKF_RIGHTBUTTONDOWN != 0x02000000
  2564. #error MKF_RIGHTBUTTONDOWN value is incorrect
  2565. #endif
  2566. pMK->dwFlags |= (gwMKCurrentButton & 3)<< 28;
  2567. #if MKF_LEFTBUTTONSEL != 0x10000000
  2568. #error MKF_LEFTBUTTONSEL value is incorrect
  2569. #endif
  2570. #if MKF_RIGHTBUTTONSEL != 0x20000000
  2571. #error MKF_RIGHTBUTTONSEL value is incorrect
  2572. #endif
  2573. }
  2574. break;
  2575. case SPI_SETMOUSEKEYS:
  2576. {
  2577. LPMOUSEKEYS pMK = (LPMOUSEKEYS)lParam;
  2578. if (wParam != 0 && wParam != sizeof(MOUSEKEYS)) {
  2579. return FALSE;
  2580. }
  2581. if (!pMK || pMK->cbSize != sizeof(MOUSEKEYS)) {
  2582. return FALSE;
  2583. }
  2584. /*
  2585. * Do some parameter validation. We will fail on unsupported and
  2586. * undefined bits being set.
  2587. *
  2588. * Don't penalize them for using data from SPI_GETMOUSEKEYS.
  2589. */
  2590. pMK->dwFlags &= ~MKF_STATEINFO;
  2591. if ((pMK->dwFlags & MKF_VALID) != pMK->dwFlags) {
  2592. return FALSE;
  2593. }
  2594. /*
  2595. * MKF_AVAILABLE can't be set via API. Use registry value.
  2596. */
  2597. if (TEST_ACCESSFLAG(MouseKeys, MKF_AVAILABLE)) {
  2598. pMK->dwFlags |= MKF_AVAILABLE;
  2599. } else {
  2600. pMK->dwFlags &= ~MKF_AVAILABLE;
  2601. }
  2602. if (pMK->iMaxSpeed < MAXSPEED_MIN || pMK->iMaxSpeed > MAXSPEED_MAX) {
  2603. return FALSE;
  2604. }
  2605. if (pMK->iTimeToMaxSpeed < TIMETOMAXSPEED_MIN || pMK->iTimeToMaxSpeed > TIMETOMAXSPEED_MAX) {
  2606. return FALSE;
  2607. }
  2608. if (fAlterWinIni) {
  2609. pProfileUserName = CreateProfileUserName(&tlName);
  2610. fWinIniChanged = SetMouseKeys(pProfileUserName, pMK);
  2611. fWriteAllowed = fWinIniChanged;
  2612. if (!fWinIniChanged) {
  2613. /*
  2614. * Back out any changes to win.ini.
  2615. */
  2616. SetMouseKeys(pProfileUserName, &gMouseKeys);
  2617. }
  2618. FreeProfileUserName(pProfileUserName, &tlName);
  2619. }
  2620. if (fWriteAllowed) {
  2621. RtlCopyMemory(&gMouseKeys, pMK, pMK->cbSize);
  2622. /*
  2623. * Don't allow user to change cbSize field.
  2624. */
  2625. gMouseKeys.cbSize = sizeof(MOUSEKEYS);
  2626. CalculateMouseTable();
  2627. if (TEST_ACCESSFLAG(MouseKeys, MKF_MOUSEKEYSON)) {
  2628. if ((TestAsyncKeyStateToggle(gNumLockVk) != 0) ^
  2629. (TEST_ACCESSFLAG(MouseKeys, MKF_REPLACENUMBERS) != 0)) {
  2630. gbMKMouseMode = TRUE;
  2631. } else {
  2632. gbMKMouseMode = FALSE;
  2633. }
  2634. MKShowMouseCursor();
  2635. } else {
  2636. MKHideMouseCursor();
  2637. }
  2638. SetAccessEnabledFlag();
  2639. if (FCallHookTray()) {
  2640. xxxCallHook(HSHELL_ACCESSIBILITYSTATE,
  2641. ACCESS_MOUSEKEYS,
  2642. 0,
  2643. WH_SHELL);
  2644. }
  2645. PostShellHookMessages(HSHELL_ACCESSIBILITYSTATE, ACCESS_MOUSEKEYS);
  2646. }
  2647. }
  2648. break;
  2649. case SPI_GETHIGHCONTRAST:
  2650. {
  2651. LPHIGHCONTRAST pHC = (LPHIGHCONTRAST)lParam;
  2652. /*
  2653. * In the future we may support multiple sizes of this data
  2654. * structure. Don't change the cbSize field of the data
  2655. * structure passed in.
  2656. */
  2657. pHC->dwFlags = gHighContrast.dwFlags;
  2658. /*
  2659. * A hostile app could deallocate the memory using a second thread,
  2660. * so shelter the copy with a try.
  2661. */
  2662. try {
  2663. RtlCopyMemory(pHC->lpszDefaultScheme, gHighContrastDefaultScheme, MAX_SCHEME_NAME_SIZE * sizeof(WCHAR));
  2664. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  2665. }
  2666. }
  2667. break;
  2668. case SPI_SETHIGHCONTRAST:
  2669. {
  2670. LPINTERNALSETHIGHCONTRAST pHC = (LPINTERNALSETHIGHCONTRAST)lParam;
  2671. WCHAR wcDefaultScheme[MAX_SCHEME_NAME_SIZE];
  2672. if (pHC->usDefaultScheme.Length >= MAX_SCHEME_NAME_SIZE*sizeof(WCHAR)) {
  2673. return FALSE;
  2674. }
  2675. if (pHC->usDefaultScheme.Buffer) {
  2676. /*
  2677. * Only set the scheme if the user specifies a scheme. An
  2678. * empty buffer is ignored. We do the copy here so that we
  2679. * don't need to put a try/except around the
  2680. * WriteProfileString code.
  2681. */
  2682. try {
  2683. RtlCopyMemory(wcDefaultScheme, pHC->usDefaultScheme.Buffer, pHC->usDefaultScheme.Length);
  2684. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  2685. return FALSE;
  2686. }
  2687. }
  2688. wcDefaultScheme[pHC->usDefaultScheme.Length / sizeof(WCHAR)] = 0;
  2689. if (fAlterWinIni) {
  2690. pProfileUserName = CreateProfileUserName(&tlName);
  2691. swprintf(szTemp, pwszd, pHC->dwFlags);
  2692. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  2693. PMAP_HIGHCONTRAST,
  2694. L"Flags",
  2695. szTemp
  2696. );
  2697. fWriteAllowed = fWinIniChanged;
  2698. /*
  2699. * Note -- we do not write anything if there is no default
  2700. * scheme from the app. This is consistent with Win95/Win98
  2701. * behavior.
  2702. */
  2703. if (pHC->usDefaultScheme.Buffer) {
  2704. fWinIniChanged |= FastWriteProfileStringW(pProfileUserName,
  2705. PMAP_HIGHCONTRAST,
  2706. TEXT("High Contrast Scheme"),
  2707. wcDefaultScheme);
  2708. }
  2709. FreeProfileUserName(pProfileUserName, &tlName);
  2710. }
  2711. if (fWriteAllowed) {
  2712. DWORD dwFlagsOld = gHighContrast.dwFlags;
  2713. LPARAM lp = fAlterWinIni ? 0 : ACCESS_HIGHCONTRASTNOREG;
  2714. #if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTOFF) != ACCESS_HIGHCONTRASTOFFNOREG
  2715. #error ACCESS_HIGHCONTRASTOFF value is incorrect
  2716. #endif
  2717. #if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTON) != ACCESS_HIGHCONTRASTONNOREG
  2718. #error ACCESS_HIGHCONTRASTON value is incorrect
  2719. #endif
  2720. #if (ACCESS_HIGHCONTRASTNOREG | ACCESS_HIGHCONTRASTCHANGE) != ACCESS_HIGHCONTRASTCHANGENOREG
  2721. #error ACCESS_HIGHCONTRASTCHANGE value is incorrect
  2722. #endif
  2723. /*
  2724. * If a NULL is specified in the lpszDefaultScheme, then it
  2725. * is not changed. This is consistent with Win95/Win98
  2726. * behavior.
  2727. */
  2728. if (pHC->usDefaultScheme.Buffer) {
  2729. wcscpy(gHighContrastDefaultScheme, wcDefaultScheme);
  2730. }
  2731. gHighContrast.dwFlags = pHC->dwFlags;
  2732. SetAccessEnabledFlag();
  2733. /*
  2734. * Now, post message to turn high contrast on or off.
  2735. */
  2736. if (pHC->dwFlags & HCF_HIGHCONTRASTON) {
  2737. _PostMessage(gspwndLogonNotify,
  2738. WM_LOGONNOTIFY,
  2739. LOGON_ACCESSNOTIFY,
  2740. (dwFlagsOld & HCF_HIGHCONTRASTON) ?
  2741. (ACCESS_HIGHCONTRASTCHANGE | lp) :
  2742. (ACCESS_HIGHCONTRASTON | lp));
  2743. } else {
  2744. _PostMessage(gspwndLogonNotify,
  2745. WM_LOGONNOTIFY,
  2746. LOGON_ACCESSNOTIFY,
  2747. ACCESS_HIGHCONTRASTOFF | lp);
  2748. }
  2749. }
  2750. break;
  2751. }
  2752. case SPI_GETACCESSTIMEOUT:
  2753. {
  2754. LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
  2755. int cbSkip = sizeof(gAccessTimeOut.cbSize);
  2756. if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
  2757. return FALSE;
  2758. }
  2759. if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
  2760. return FALSE;
  2761. }
  2762. /*
  2763. * In the future we may support multiple sizes of this data
  2764. * structure. Don't change the cbSize field of the data
  2765. * structure passed in.
  2766. */
  2767. RtlCopyMemory((LPVOID)((LPBYTE)pTO + cbSkip),
  2768. (LPVOID)((LPBYTE)&gAccessTimeOut + cbSkip),
  2769. pTO->cbSize - cbSkip);
  2770. }
  2771. break;
  2772. case SPI_SETACCESSTIMEOUT:
  2773. {
  2774. LPACCESSTIMEOUT pTO = (LPACCESSTIMEOUT)lParam;
  2775. if (wParam != 0 && wParam != sizeof(ACCESSTIMEOUT)) {
  2776. return FALSE;
  2777. }
  2778. if (!pTO || pTO->cbSize != sizeof(ACCESSTIMEOUT)) {
  2779. return FALSE;
  2780. }
  2781. /*
  2782. * Do some parameter validation. We will fail on unsupported and
  2783. * undefined bits being set.
  2784. */
  2785. if ((pTO->dwFlags & ATF_VALID) != pTO->dwFlags) {
  2786. return FALSE;
  2787. }
  2788. if (pTO->iTimeOutMSec > 3600000) {
  2789. return FALSE;
  2790. }
  2791. if (fAlterWinIni) {
  2792. pProfileUserName = CreateProfileUserName(&tlName);
  2793. swprintf(szTemp, pwszd, pTO->dwFlags);
  2794. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  2795. PMAP_TIMEOUT,
  2796. L"Flags",
  2797. szTemp);
  2798. swprintf(szTemp, pwszd, pTO->iTimeOutMSec);
  2799. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  2800. PMAP_TIMEOUT,
  2801. L"TimeToWait",
  2802. szTemp);
  2803. fWriteAllowed = fWinIniChanged;
  2804. if (!fWinIniChanged) {
  2805. /*
  2806. * Back out any changes to win.ini.
  2807. */
  2808. swprintf(szTemp, pwszd, gAccessTimeOut.dwFlags);
  2809. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  2810. PMAP_TIMEOUT,
  2811. L"Flags",
  2812. szTemp);
  2813. swprintf(szTemp, pwszd, gAccessTimeOut.iTimeOutMSec);
  2814. fWinIniChanged = FastWriteProfileStringW(pProfileUserName,
  2815. PMAP_TIMEOUT,
  2816. L"TimeToWait",
  2817. szTemp);
  2818. }
  2819. FreeProfileUserName(pProfileUserName, &tlName);
  2820. }
  2821. if (fWriteAllowed) {
  2822. RtlCopyMemory(&gAccessTimeOut, pTO, pTO->cbSize);
  2823. /*
  2824. * Don't allow user to change cbSize field.
  2825. */
  2826. gAccessTimeOut.cbSize = sizeof(ACCESSTIMEOUT);
  2827. SetAccessEnabledFlag();
  2828. AccessTimeOutReset();
  2829. }
  2830. }
  2831. break;
  2832. case SPI_SETSHOWSOUNDS:
  2833. if (fAlterWinIni) {
  2834. swprintf(szTemp, pwszd, (wParam == 1));
  2835. fWinIniChanged = FastWriteProfileStringW(NULL,
  2836. PMAP_SHOWSOUNDS,
  2837. L"On",
  2838. szTemp);
  2839. fWriteAllowed = fWinIniChanged;
  2840. }
  2841. if (fWriteAllowed) {
  2842. SET_OR_CLEAR_ACCF(ACCF_SHOWSOUNDSON, wParam == 1);
  2843. SetAccessEnabledFlag();
  2844. /*
  2845. * Update the System Metrics Info.
  2846. */
  2847. SYSMET(SHOWSOUNDS) = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
  2848. }
  2849. break;
  2850. case SPI_GETSHOWSOUNDS: {
  2851. PINT pint = (int *)lParam;
  2852. *pint = TEST_BOOL_ACCF(ACCF_SHOWSOUNDSON);
  2853. }
  2854. break;
  2855. case SPI_GETKEYBOARDPREF:
  2856. {
  2857. PBOOL pfKeyboardPref = (PBOOL)lParam;
  2858. *pfKeyboardPref = TEST_BOOL_ACCF(ACCF_KEYBOARDPREF);
  2859. }
  2860. break;
  2861. case SPI_SETKEYBOARDPREF:
  2862. {
  2863. BOOL fKeyboardPref = (BOOL)wParam;
  2864. if (fAlterWinIni) {
  2865. fWinIniChanged = FastWriteProfileStringW(NULL,
  2866. PMAP_KEYBOARDPREF,
  2867. L"On",
  2868. fKeyboardPref ? L"1" : L"0");
  2869. fWriteAllowed = fWinIniChanged;
  2870. }
  2871. if (fWriteAllowed) {
  2872. SET_OR_CLEAR_ACCF(ACCF_KEYBOARDPREF, wParam);
  2873. }
  2874. }
  2875. break;
  2876. case SPI_GETSCREENREADER:
  2877. {
  2878. PBOOL pfScreenReader = (PBOOL)lParam;
  2879. *pfScreenReader = TEST_BOOL_ACCF(ACCF_SCREENREADER);
  2880. }
  2881. break;
  2882. case SPI_SETSCREENREADER:
  2883. {
  2884. BOOL fScreenReader = (BOOL)wParam;
  2885. if (fAlterWinIni) {
  2886. fWinIniChanged = FastWriteProfileStringW(NULL,
  2887. PMAP_SCREENREADER,
  2888. L"On",
  2889. fScreenReader ? L"1" : L"0");
  2890. fWriteAllowed = fWinIniChanged;
  2891. }
  2892. if (fWriteAllowed) {
  2893. SET_OR_CLEAR_ACCF(ACCF_SCREENREADER, wParam);
  2894. }
  2895. }
  2896. break;
  2897. case SPI_GETSOUNDSENTRY:
  2898. {
  2899. LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
  2900. int cbSkip = sizeof(gSoundSentry.cbSize);
  2901. if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
  2902. return FALSE;
  2903. }
  2904. if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
  2905. return FALSE;
  2906. }
  2907. /*
  2908. * In the future we may support multiple sizes of this data
  2909. * structure. Don't change the cbSize field of the data
  2910. * structure passed in.
  2911. */
  2912. RtlCopyMemory((LPVOID)((LPBYTE)pSS + cbSkip),
  2913. (LPVOID)((LPBYTE)&gSoundSentry + cbSkip),
  2914. pSS->cbSize - cbSkip);
  2915. }
  2916. break;
  2917. case SPI_SETSOUNDSENTRY:
  2918. {
  2919. LPSOUNDSENTRY pSS = (LPSOUNDSENTRY)lParam;
  2920. if (wParam != 0 && wParam != sizeof(SOUNDSENTRY)) {
  2921. return FALSE;
  2922. }
  2923. if (!pSS || pSS->cbSize != sizeof(SOUNDSENTRY)) {
  2924. return FALSE;
  2925. }
  2926. /*
  2927. * Do some parameter validation. We will fail on unsupported and
  2928. * undefined bits being set.
  2929. */
  2930. if ((pSS->dwFlags & SSF_VALID) != pSS->dwFlags) {
  2931. return FALSE;
  2932. }
  2933. /*
  2934. * We don't support SSWF_CUSTOM.
  2935. */
  2936. if (pSS->iWindowsEffect > SSWF_DISPLAY) {
  2937. return FALSE;
  2938. }
  2939. /*
  2940. * No support for non-windows apps.
  2941. */
  2942. if (pSS->iFSTextEffect != SSTF_NONE) {
  2943. return FALSE;
  2944. }
  2945. if (pSS->iFSGrafEffect != SSGF_NONE) {
  2946. return FALSE;
  2947. }
  2948. /*
  2949. * SSF_AVAILABLE can't be set via API. Use registry value.
  2950. */
  2951. if (TEST_ACCESSFLAG(SoundSentry, SSF_AVAILABLE)) {
  2952. pSS->dwFlags |= SSF_AVAILABLE;
  2953. } else {
  2954. pSS->dwFlags &= ~SSF_AVAILABLE;
  2955. }
  2956. if (fAlterWinIni) {
  2957. pProfileUserName = CreateProfileUserName(&tlName);
  2958. fWinIniChanged = SetSoundSentry(pProfileUserName, pSS);
  2959. fWriteAllowed = fWinIniChanged;
  2960. if (!fWinIniChanged) {
  2961. /*
  2962. * Back out any changes to win.ini
  2963. */
  2964. SetSoundSentry(pProfileUserName, &gSoundSentry);
  2965. }
  2966. FreeProfileUserName(pProfileUserName, &tlName);
  2967. }
  2968. if (fWriteAllowed) {
  2969. RtlCopyMemory(&gSoundSentry, pSS, pSS->cbSize);
  2970. /*
  2971. * Don't allow user to change cbSize field.
  2972. */
  2973. gSoundSentry.cbSize = sizeof(SOUNDSENTRY);
  2974. SetAccessEnabledFlag();
  2975. }
  2976. }
  2977. break;
  2978. case SPI_SETCURSORS:
  2979. pProfileUserName = CreateProfileUserName(&tlName);
  2980. xxxUpdateSystemCursorsFromRegistry(pProfileUserName);
  2981. FreeProfileUserName(pProfileUserName, &tlName);
  2982. break;
  2983. case SPI_SETICONS:
  2984. pProfileUserName = CreateProfileUserName(&tlName);
  2985. xxxUpdateSystemIconsFromRegistry(pProfileUserName);
  2986. FreeProfileUserName(pProfileUserName, &tlName);
  2987. break;
  2988. case SPI_GETMOUSEHOVERWIDTH:
  2989. *((UINT *)lParam) = gcxMouseHover;
  2990. break;
  2991. case SPI_SETMOUSEHOVERWIDTH:
  2992. if (fAlterWinIni) {
  2993. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERWIDTH, wParam);
  2994. fWriteAllowed = fWinIniChanged;
  2995. }
  2996. if (fWriteAllowed) {
  2997. gcxMouseHover = wParam;
  2998. }
  2999. break;
  3000. case SPI_GETMOUSEHOVERHEIGHT:
  3001. *((UINT *)lParam) = gcyMouseHover;
  3002. break;
  3003. case SPI_SETMOUSEHOVERHEIGHT:
  3004. if (fAlterWinIni) {
  3005. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERHEIGHT, wParam);
  3006. fWriteAllowed = fWinIniChanged;
  3007. }
  3008. if (fWriteAllowed) {
  3009. gcyMouseHover = wParam;
  3010. }
  3011. break;
  3012. case SPI_GETMOUSEHOVERTIME:
  3013. *((UINT *)lParam) = gdtMouseHover;
  3014. break;
  3015. case SPI_SETMOUSEHOVERTIME:
  3016. if (fAlterWinIni) {
  3017. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_MOUSE, STR_MOUSEHOVERTIME, wParam);
  3018. fWriteAllowed = fWinIniChanged;
  3019. }
  3020. if (fWriteAllowed) {
  3021. gdtMouseHover = wParam;
  3022. }
  3023. break;
  3024. case SPI_GETWHEELSCROLLLINES:
  3025. (*(LPDWORD)lParam) = gpsi->ucWheelScrollLines;
  3026. break;
  3027. case SPI_SETWHEELSCROLLLINES:
  3028. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_WHEELSCROLLLINES)) {
  3029. fAlterWinIni = FALSE;
  3030. fWriteAllowed = FALSE;
  3031. }
  3032. if (fAlterWinIni) {
  3033. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_WHEELSCROLLLINES, wParam);
  3034. fWriteAllowed = fWinIniChanged;
  3035. }
  3036. if (fWriteAllowed)
  3037. gpsi->ucWheelScrollLines = (UINT)wParam;
  3038. break;
  3039. case SPI_GETMENUSHOWDELAY:
  3040. (*(LPDWORD)lParam) = gdtMNDropDown;
  3041. break;
  3042. case SPI_SETMENUSHOWDELAY:
  3043. if (CheckDesktopPolicy(NULL, (PCWSTR)STR_MENUSHOWDELAY)) {
  3044. fAlterWinIni = FALSE;
  3045. fWriteAllowed = FALSE;
  3046. }
  3047. if (fAlterWinIni) {
  3048. fWinIniChanged = UpdateWinIniInt(NULL, PMAP_DESKTOP, STR_MENUSHOWDELAY, wParam);
  3049. fWriteAllowed = fWinIniChanged;
  3050. }
  3051. if (fWriteAllowed)
  3052. gdtMNDropDown = wParam;
  3053. break;
  3054. case SPI_GETSCREENSAVERRUNNING:
  3055. (*(LPBOOL)lParam) = gppiScreenSaver != NULL;
  3056. break;
  3057. case SPI_SETSHOWIMEUI:
  3058. return xxxSetIMEShowStatus(!!wParam);
  3059. case SPI_GETSHOWIMEUI:
  3060. (*(LPBOOL)lParam) = _GetIMEShowStatus();
  3061. break;
  3062. default:
  3063. #define ppvi (UPDWORDPointer(wFlag))
  3064. #define uDataRead ((UINT)fWinIniChanged)
  3065. if (wFlag < SPI_MAX) {
  3066. RIPERR1(ERROR_INVALID_SPI_VALUE,
  3067. RIP_WARNING,
  3068. "xxxSystemParamtersInfo: Invalid SPI_: 0x%x",
  3069. wFlag);
  3070. return FALSE;
  3071. }
  3072. UserAssert(wFlag & SPIF_RANGETYPEMASK);
  3073. if (!(wFlag & SPIF_SET)) {
  3074. if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
  3075. BOOL fDisable, fDisableValue;
  3076. UserAssert(UPIsBOOLRange(wFlag));
  3077. /*
  3078. * Handle settings that can be disabled by additional conditions.
  3079. */
  3080. fDisable = fDisableValue = FALSE;
  3081. if (wFlag < SPI_GETUIEFFECTS) {
  3082. if (!TestUP(UIEFFECTS)) {
  3083. switch (wFlag) {
  3084. case SPI_GETACTIVEWNDTRKZORDER:
  3085. case SPI_GETACTIVEWINDOWTRACKING:
  3086. #ifdef MOUSE_IP
  3087. case SPI_GETMOUSESONAR:
  3088. #endif
  3089. case SPI_GETMOUSECLICKLOCK:
  3090. break;
  3091. case SPI_GETKEYBOARDCUES:
  3092. fDisableValue = TRUE;
  3093. /* Fall Through */
  3094. default:
  3095. fDisable = TRUE;
  3096. break;
  3097. }
  3098. } else {
  3099. switch (wFlag) {
  3100. case SPI_GETKEYBOARDCUES:
  3101. if (TEST_BOOL_ACCF(ACCF_KEYBOARDPREF)) {
  3102. fDisableValue = TRUE;
  3103. fDisable = TRUE;
  3104. }
  3105. break;
  3106. case SPI_GETGRADIENTCAPTIONS:
  3107. case SPI_GETSELECTIONFADE:
  3108. case SPI_GETMENUFADE:
  3109. case SPI_GETTOOLTIPFADE:
  3110. case SPI_GETCURSORSHADOW:
  3111. if (gbDisableAlpha) {
  3112. fDisable = TRUE;
  3113. }
  3114. break;
  3115. }
  3116. }
  3117. }
  3118. /*
  3119. * Give them the disabled value or read the actual one.
  3120. */
  3121. if (fDisable) {
  3122. *((BOOL *)lParam) = fDisableValue;
  3123. } else if (wFlag == SPI_GETUIEFFECTS && IsRemoteConnection()) {
  3124. /*
  3125. * Fix for 689707.
  3126. * In remote connections, lie about the SPI_GETUIEFFECTS.
  3127. * We look at a certain subset of the uieffects array.
  3128. * If all the subset bits are off,
  3129. * we return FALSE, otherwise TRUE.
  3130. */
  3131. *((BOOL *)lParam) = !!(TestUP(CURSORSHADOW) |
  3132. TestUP(MENUANIMATION) |
  3133. TestUP(MENUFADE) |
  3134. TestUP(TOOLTIPANIMATION) |
  3135. TestUP(TOOLTIPFADE) |
  3136. TestUP(COMBOBOXANIMATION) |
  3137. TestUP(LISTBOXSMOOTHSCROLLING));
  3138. } else {
  3139. *((BOOL *)lParam) = !!TestUPBOOL(gpdwCPUserPreferencesMask, wFlag);
  3140. }
  3141. } else {
  3142. UserAssert(UPIsDWORDRange(wFlag));
  3143. *((DWORD *)lParam) = UPDWORDValue(wFlag);
  3144. switch(wFlag) {
  3145. case SPI_GETFONTSMOOTHINGCONTRAST:
  3146. /*
  3147. * If the contrast value was never set by the user,
  3148. * we will return the default value from the display
  3149. * driver
  3150. */
  3151. if (*((DWORD *)lParam) == 0) {
  3152. *((DWORD *)lParam) = GreGetFontContrast();
  3153. }
  3154. break;
  3155. default:
  3156. break;
  3157. }
  3158. }
  3159. } else {
  3160. pProfileUserName = CreateProfileUserName(&tlName);
  3161. if ((wFlag & SPIF_RANGETYPEMASK) == SPIF_BOOL) {
  3162. DWORD pdwValue [SPI_BOOLMASKDWORDSIZE];
  3163. UserAssert(UPIsBOOLRange(wFlag));
  3164. UserAssert(sizeof(pdwValue) == sizeof(gpdwCPUserPreferencesMask));
  3165. if (gpviCPUserPreferences->uSection == PMAP_DESKTOP) {
  3166. if (CheckDesktopPolicy(pProfileUserName, gpviCPUserPreferences->pwszKeyName)) {
  3167. fAlterWinIni = FALSE;
  3168. fWriteAllowed = FALSE;
  3169. }
  3170. }
  3171. if (fAlterWinIni) {
  3172. /*
  3173. * We only need to set/clear the bit passed in, however,
  3174. * we write the whole bit mask to the registry. Since
  3175. * the info in gpdwCPUserPreferencesMask might not match
  3176. * what it is in the registry, we need to read the
  3177. * registry before we write to it.
  3178. */
  3179. uDataRead = FastGetProfileValue(pProfileUserName,
  3180. gpviCPUserPreferences->uSection,
  3181. gpviCPUserPreferences->pwszKeyName,
  3182. NULL,
  3183. (LPBYTE)pdwValue,
  3184. sizeof(pdwValue),
  3185. 0);
  3186. /*
  3187. * If some bits are not in the registry, get them from
  3188. * gpdwCPUserPreferencesMask.
  3189. */
  3190. UserAssert(uDataRead <= sizeof(gpdwCPUserPreferencesMask));
  3191. RtlCopyMemory(pdwValue + uDataRead,
  3192. gpdwCPUserPreferencesMask + uDataRead,
  3193. sizeof(gpdwCPUserPreferencesMask) - uDataRead);
  3194. /*
  3195. * Set/Clear the new state and write it.
  3196. */
  3197. if (lParam) {
  3198. SetUPBOOL(pdwValue, wFlag);
  3199. } else {
  3200. ClearUPBOOL(pdwValue, wFlag);
  3201. }
  3202. fWinIniChanged = FastWriteProfileValue(pProfileUserName,
  3203. gpviCPUserPreferences->uSection,
  3204. gpviCPUserPreferences->pwszKeyName,
  3205. REG_BINARY,
  3206. (LPBYTE)pdwValue,
  3207. sizeof(pdwValue));
  3208. fWriteAllowed = fWinIniChanged;
  3209. }
  3210. if (fWriteAllowed) {
  3211. if (lParam) {
  3212. SetUPBOOL(gpdwCPUserPreferencesMask, wFlag);
  3213. } else {
  3214. ClearUPBOOL(gpdwCPUserPreferencesMask, wFlag);
  3215. }
  3216. /*
  3217. * Propagate gpsi flags.
  3218. */
  3219. switch (wFlag) {
  3220. case SPI_SETUIEFFECTS:
  3221. PropagetUPBOOLTogpsi(UIEFFECTS);
  3222. SetPointer(TRUE);
  3223. /*
  3224. * Fall through.
  3225. */
  3226. case SPI_SETGRADIENTCAPTIONS:
  3227. CreateBitmapStrip();
  3228. xxxRedrawScreen();
  3229. break;
  3230. case SPI_SETCOMBOBOXANIMATION:
  3231. PropagetUPBOOLTogpsi(COMBOBOXANIMATION);
  3232. break;
  3233. case SPI_SETLISTBOXSMOOTHSCROLLING:
  3234. PropagetUPBOOLTogpsi(LISTBOXSMOOTHSCROLLING);
  3235. break;
  3236. case SPI_SETKEYBOARDCUES:
  3237. PropagetUPBOOLTogpsi(KEYBOARDCUES);
  3238. break;
  3239. case SPI_SETCURSORSHADOW:
  3240. SetPointer(TRUE);
  3241. break;
  3242. case SPI_SETFLATMENU:
  3243. xxxRedrawScreen();
  3244. break;
  3245. }
  3246. }
  3247. } else {
  3248. UserAssert(UPIsDWORDRange(wFlag));
  3249. if (ppvi->uSection == PMAP_DESKTOP) {
  3250. if (CheckDesktopPolicy(pProfileUserName, ppvi->pwszKeyName)) {
  3251. fAlterWinIni = FALSE;
  3252. fWriteAllowed = FALSE;
  3253. }
  3254. }
  3255. if (fAlterWinIni) {
  3256. fWinIniChanged = FastWriteProfileValue(pProfileUserName,
  3257. ppvi->uSection,
  3258. ppvi->pwszKeyName,
  3259. REG_DWORD,
  3260. (LPBYTE)&lParam,
  3261. sizeof(DWORD));
  3262. fWriteAllowed = fWinIniChanged;
  3263. }
  3264. if (fWriteAllowed) {
  3265. ppvi->dwValue = PtrToUlong(lParam);
  3266. switch(wFlag) {
  3267. case SPI_SETCARETWIDTH:
  3268. gpsi->uCaretWidth = ppvi->dwValue;
  3269. break;
  3270. case SPI_SETFOCUSBORDERWIDTH:
  3271. if (ppvi->dwValue) {
  3272. SYSMET(CXFOCUSBORDER) = ppvi->dwValue;
  3273. }
  3274. break;
  3275. case SPI_SETFOCUSBORDERHEIGHT:
  3276. if (ppvi->dwValue) {
  3277. SYSMET(CYFOCUSBORDER) = ppvi->dwValue;
  3278. }
  3279. break;
  3280. case SPI_SETFONTSMOOTHINGTYPE:
  3281. GreSetFontEnumeration((ppvi->dwValue & FE_FONTSMOOTHINGCLEARTYPE) ? FE_CT_ON | FE_SET_CT : FE_SET_CT);
  3282. break;
  3283. case SPI_SETFONTSMOOTHINGCONTRAST:
  3284. GreSetFontContrast(ppvi->dwValue);
  3285. break;
  3286. case SPI_SETFONTSMOOTHINGORIENTATION:
  3287. GreSetLCDOrientation(ppvi->dwValue);
  3288. break;
  3289. default:
  3290. break;
  3291. }
  3292. }
  3293. }
  3294. FreeProfileUserName(pProfileUserName, &tlName);
  3295. }
  3296. break;
  3297. #undef ppvi
  3298. #undef uDataRead
  3299. }
  3300. if (fWinIniChanged && fSendWinIniChange) {
  3301. ULONG_PTR dwResult;
  3302. RtlInitLargeUnicodeString(&strSection, szSection, (UINT)-1);
  3303. xxxSendMessageTimeout(PWND_BROADCAST,
  3304. WM_SETTINGCHANGE,
  3305. wFlag,
  3306. (LPARAM)&strSection,
  3307. SMTO_NORMAL,
  3308. 100,
  3309. &dwResult);
  3310. }
  3311. return fWriteAllowed;
  3312. }
  3313. /***************************************************************************\
  3314. * _RegisterShellHookWindow
  3315. *
  3316. * History:
  3317. \***************************************************************************/
  3318. BOOL _RegisterShellHookWindow(
  3319. PWND pwnd)
  3320. {
  3321. PDESKTOPINFO pdeskinfo;
  3322. if (pwnd->head.rpdesk == NULL) {
  3323. return FALSE;
  3324. }
  3325. pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
  3326. /*
  3327. * Add pwnd to the desktop's Volatile Window Pointer List (VWPL) of
  3328. * ShellHook windows. If this call initializes the VWPL, set the
  3329. * (re)allocation threshhold to 2 PWNDs (we know we never have more than
  3330. * 2 windows in this list anyway)
  3331. */
  3332. if (VWPLAdd(&(pdeskinfo->pvwplShellHook), pwnd, 2)) {
  3333. SetWF(pwnd, WFSHELLHOOKWND);
  3334. return TRUE;
  3335. }
  3336. return FALSE;
  3337. }
  3338. /***************************************************************************\
  3339. * _DeregisterShellHookWindow
  3340. *
  3341. * History:
  3342. \***************************************************************************/
  3343. BOOL _DeregisterShellHookWindow(
  3344. PWND pwnd)
  3345. {
  3346. PDESKTOPINFO pdeskinfo;
  3347. if (pwnd->head.rpdesk == NULL) {
  3348. return FALSE;
  3349. }
  3350. pdeskinfo = pwnd->head.rpdesk->pDeskInfo;
  3351. if (VWPLRemove(&(pdeskinfo->pvwplShellHook), pwnd)) {
  3352. ClrWF(pwnd, WFSHELLHOOKWND);
  3353. }
  3354. return TRUE;
  3355. }
  3356. /***************************************************************************\
  3357. * xxxSendMinRectMessages
  3358. *
  3359. * History:
  3360. \***************************************************************************/
  3361. BOOL xxxSendMinRectMessages(
  3362. PWND pwnd,
  3363. RECT *lpRect)
  3364. {
  3365. BOOL fRet = FALSE;
  3366. HWND hwnd = HW(pwnd);
  3367. PTHREADINFO pti = PtiCurrent();
  3368. PDESKTOPINFO pdeskinfo;
  3369. DWORD nPwndShellHook;
  3370. PWND pwndShellHook;
  3371. if (IsHooked(pti, WHF_SHELL)) {
  3372. xxxCallHook(HSHELL_GETMINRECT, (WPARAM)hwnd, (LPARAM)lpRect, WH_SHELL);
  3373. fRet = TRUE;
  3374. }
  3375. pdeskinfo = GETDESKINFO(pti);
  3376. if (pdeskinfo->pvwplShellHook == NULL) {
  3377. return fRet;
  3378. }
  3379. nPwndShellHook = 0;
  3380. pwndShellHook = NULL;
  3381. while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
  3382. TL tlpwnd;
  3383. ULONG_PTR dwRes;
  3384. ThreadLock(pwndShellHook, &tlpwnd);
  3385. if (xxxSendMessageTimeout(pwndShellHook, WM_KLUDGEMINRECT, (WPARAM)(hwnd), (LPARAM)lpRect,
  3386. SMTO_NORMAL, 100, &dwRes))
  3387. fRet = TRUE;
  3388. /*
  3389. * pdeskinfo->pvwplShellHook may have been realloced to a different
  3390. * location and size during the WM_KLUDGEMINRECT callback.
  3391. */
  3392. ThreadUnlock(&tlpwnd);
  3393. }
  3394. return fRet;
  3395. }
  3396. /***************************************************************************\
  3397. * PostShellHookMessages
  3398. *
  3399. * History:
  3400. \***************************************************************************/
  3401. VOID PostShellHookMessages(
  3402. UINT message,
  3403. LPARAM lParam)
  3404. {
  3405. PDESKTOPINFO pdeskinfo = GETDESKINFO(PtiCurrent());
  3406. DWORD nPwndShellHook;
  3407. PWND pwndShellHook;
  3408. nPwndShellHook = 0;
  3409. pwndShellHook = NULL;
  3410. /*
  3411. * We want to allow anyone who's listening for these WM_APPCOMMAND
  3412. * messages to be able to take the foreground. I.E., pressing mail will
  3413. * launch outlook AND bring it to the foreground. We set the token to
  3414. * null so anyone can steal the foreground - else it isn't clear who
  3415. * should have the right to steal it - only one person gets the right.
  3416. * We let them fight it out to decide who gets foreground if more than
  3417. * one listener will try make a foreground change.
  3418. */
  3419. if (HSHELL_APPCOMMAND == message) {
  3420. TAGMSG0(DBGTAG_FOREGROUND,
  3421. "PostShellHookMessages cleared last input token - open foreground.");
  3422. glinp.ptiLastWoken = NULL;
  3423. }
  3424. /*
  3425. * Loop through all the windows registered to listen for shell hooks and
  3426. * post the message to them.
  3427. */
  3428. while (pwndShellHook = VWPLNext(pdeskinfo->pvwplShellHook, pwndShellHook, &nPwndShellHook)) {
  3429. if (pwndShellHook == pdeskinfo->spwndProgman) {
  3430. switch (message) {
  3431. case HSHELL_WINDOWCREATED:
  3432. _PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowCreated, lParam);
  3433. break;
  3434. case HSHELL_WINDOWDESTROYED:
  3435. _PostMessage(pwndShellHook, gpsi->uiShellMsg, guiOtherWindowDestroyed, lParam);
  3436. break;
  3437. }
  3438. } else {
  3439. _PostMessage(pwndShellHook, gpsi->uiShellMsg, message, lParam);
  3440. }
  3441. }
  3442. }
  3443. /***************************************************************************\
  3444. * _ResetDblClk
  3445. *
  3446. * History:
  3447. \***************************************************************************/
  3448. VOID _ResetDblClk(
  3449. VOID)
  3450. {
  3451. PtiCurrent()->pq->timeDblClk = 0L;
  3452. }
  3453. /***************************************************************************\
  3454. * SetMsgBox
  3455. *
  3456. * History:
  3457. \***************************************************************************/
  3458. VOID SetMsgBox(
  3459. PWND pwnd)
  3460. {
  3461. pwnd->head.rpdesk->pDeskInfo->cntMBox++;
  3462. SetWF(pwnd, WFMSGBOX);
  3463. }
  3464. /***************************************************************************\
  3465. * xxxSimulateShiftF10
  3466. *
  3467. * This routine is called to convert a WM_CONTEXTHELP message back to a
  3468. * SHIFT-F10 sequence for old applications. It is called from the default
  3469. * window procedure.
  3470. *
  3471. * History:
  3472. * 22-Aug-95 BradG Ported from Win95 (rare.asm)
  3473. \***************************************************************************/
  3474. VOID xxxSimulateShiftF10(
  3475. VOID)
  3476. {
  3477. /*
  3478. * VK_SHIFT down
  3479. */
  3480. xxxKeyEvent(VK_LSHIFT, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
  3481. #ifdef GENERIC_INPUT
  3482. NULL,
  3483. NULL,
  3484. #endif
  3485. FALSE);
  3486. /*
  3487. * VK_F10 down
  3488. */
  3489. xxxKeyEvent(VK_F10, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
  3490. #ifdef GENERIC_INPUT
  3491. NULL,
  3492. NULL,
  3493. #endif
  3494. FALSE);
  3495. /*
  3496. * VK_F10 up
  3497. */
  3498. xxxKeyEvent(VK_F10 | KBDBREAK, 0x44 | SCANCODE_SIMULATED, NtGetTickCount(), 0,
  3499. #ifdef GENERIC_INPUT
  3500. NULL,
  3501. NULL,
  3502. #endif
  3503. FALSE);
  3504. /*
  3505. * VK_SHIFT up
  3506. */
  3507. xxxKeyEvent(VK_LSHIFT | KBDBREAK, 0x2A | SCANCODE_SIMULATED, NtGetTickCount(), 0,
  3508. #ifdef GENERIC_INPUT
  3509. NULL,
  3510. NULL,
  3511. #endif
  3512. FALSE);
  3513. }
  3514. /*
  3515. * VWPL (Volatile Window Pointer List) Implementation details.
  3516. * ===========================================================
  3517. * Volatile Window Pointer Lists are used to keep a list of windows that we want
  3518. * to send messages to, where the list may get altered during each of those send
  3519. * message callbacks.
  3520. *
  3521. * The list is volatile in that it can change its size, contents and location
  3522. * while we continue to traverse the list.
  3523. *
  3524. * Examples of use:
  3525. * - hungapp redraw code in hungapp.c
  3526. * - xxxSendMinRectMessages stuff in rare.c
  3527. *
  3528. * Members of the VWPL struct:
  3529. * cPwnd
  3530. * The number of pwnds in the list, not including NULLs
  3531. * cElem
  3532. * The size of the list, including NULLs.
  3533. * cThreshhold
  3534. * When growing, the number of extra spaces to add to the list.
  3535. * When (cElem - cPwnd) > cThreshhold, that's when we reallocate to shrink.
  3536. * apwnd[]
  3537. * An array of pwnds.
  3538. * The array may have some empty slots, but they will all be at the end.
  3539. *
  3540. * VWPL Internal Invariants:
  3541. * - no pwnd appears more than once.
  3542. * - cPwnd <= cElem
  3543. * - number of unused slots (cElem - cPwnd) < cThreshhold
  3544. * - all unused slots are at the end of the aPwnd[] array
  3545. *
  3546. * Restrictions on use of VWPLs:
  3547. * - NULL pwnd is not allowed (except in unused slots)
  3548. * - all pwnds in the list must be valid: pwnds must be explicitly removed from
  3549. * the list in their xxxFreeWindow.
  3550. */
  3551. #if DBG_VWPL
  3552. BOOL DbgCheckVWPL(
  3553. PVWPL pvwpl)
  3554. {
  3555. DWORD ixPwnd;
  3556. if (!pvwpl) {
  3557. return TRUE;
  3558. }
  3559. UserAssert(pvwpl->cElem >= pvwpl->cPwnd);
  3560. /*
  3561. * Check that cElem is not too big.
  3562. */
  3563. UserAssert(pvwpl->cElem < 1000);
  3564. /*
  3565. * Check that the pwnds are all in the first cPwnd slots.
  3566. */
  3567. for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
  3568. UserAssert(pvwpl->aPwnd[ixPwnd] != NULL);
  3569. }
  3570. #if ZERO_INIT_VWPL
  3571. /*
  3572. * Check that the NULLs are all in the last few slots.
  3573. */
  3574. for (ixPwnd = pvwpl->cPwnd; ixPwnd < pvwpl->cElem; ixPwnd++) {
  3575. UserAssert(pvwpl->aPwnd[ixPwnd] == NULL);
  3576. }
  3577. #endif
  3578. /*
  3579. * Check that no pwnds appears twice.
  3580. */
  3581. for (ixPwnd = 0; ixPwnd < pvwpl->cPwnd; ixPwnd++) {
  3582. DWORD ix2;
  3583. for (ix2 = ixPwnd + 1; ix2 < pvwpl->cPwnd; ix2++) {
  3584. UserAssert(pvwpl->aPwnd[ixPwnd] != pvwpl->aPwnd[ix2]);
  3585. }
  3586. }
  3587. }
  3588. #else
  3589. #define DbgCheckVWPL(foo)
  3590. #endif
  3591. /*****************************************************************************\
  3592. * VWPLAdd
  3593. *
  3594. * Adds a pwnd to a VWPL (Volatile Window Pointer List). Allocates or
  3595. * reallocates memory as required.
  3596. *
  3597. * History:
  3598. * 98-01-30 IanJa Created.
  3599. \*****************************************************************************/
  3600. BOOL VWPLAdd(
  3601. PVWPL *ppvwpl,
  3602. PWND pwnd,
  3603. DWORD dwThreshhold)
  3604. {
  3605. PVWPL pvwpl;
  3606. DWORD ixPwnd;
  3607. TAGMSG2(DBGTAG_VWPL, "VWPL %#p + %#p", *ppvwpl, pwnd);
  3608. UserAssert(pwnd);
  3609. if (*ppvwpl == NULL) {
  3610. /*
  3611. * Initialize the VWPL.
  3612. */
  3613. UserAssert(dwThreshhold >= 2); // could be 1, but that would be silly
  3614. pvwpl = (PVWPL)UserAllocPool(sizeof(VWPL) + (sizeof(PWND) * dwThreshhold),
  3615. TAG_VWPL);
  3616. if (pvwpl == NULL) {
  3617. RIPMSG1(RIP_WARNING,
  3618. "VWPLAdd fail to allocate initial %lx",
  3619. sizeof(VWPL) + (sizeof(PWND) * dwThreshhold));
  3620. DbgCheckVWPL(*ppvwpl);
  3621. return FALSE;
  3622. }
  3623. pvwpl->cElem = dwThreshhold;
  3624. pvwpl->cThreshhold = dwThreshhold;
  3625. #if ZERO_INIT_VWPL
  3626. RtlZeroMemory(&(pvwpl->aPwnd[0]), (sizeof(PWND) * dwThreshhold));
  3627. #endif
  3628. pvwpl->cPwnd = 0;
  3629. *ppvwpl = pvwpl;
  3630. ixPwnd = 0;
  3631. goto AddPwnd;
  3632. } else {
  3633. pvwpl = *ppvwpl;
  3634. for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
  3635. if (pwnd == pvwpl->aPwnd[ixPwnd]) {
  3636. DbgCheckVWPL(*ppvwpl);
  3637. return FALSE; // callers require FALSE this case
  3638. }
  3639. }
  3640. if (pvwpl->cPwnd >= pvwpl->cElem ) {
  3641. /*
  3642. * Didn't find it already there, and no space so grow the VWPL.
  3643. */
  3644. DWORD dwSize;
  3645. DWORD dwSizeNew;
  3646. dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
  3647. dwSizeNew = dwSize + (sizeof(PWND) * pvwpl->cThreshhold);
  3648. pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
  3649. if (pvwpl == NULL) {
  3650. RIPMSG2(RIP_WARNING,
  3651. "VWPLAdd fail to reallocate %lx to %lx", dwSize, dwSizeNew);
  3652. DbgCheckVWPL(*ppvwpl);
  3653. return FALSE;
  3654. }
  3655. #if ZERO_INIT_VWPL
  3656. RtlZeroMemory(&(pvwpl->aPwnd[pvwpl->cPwnd]), (sizeof(PWND) * dwThreshhold));
  3657. #endif
  3658. pvwpl->cElem += pvwpl->cThreshhold;
  3659. *ppvwpl = pvwpl;
  3660. }
  3661. }
  3662. AddPwnd:
  3663. ixPwnd = pvwpl->cPwnd;
  3664. pvwpl->aPwnd[ixPwnd] = pwnd;
  3665. pvwpl->cPwnd++;
  3666. DbgCheckVWPL(*ppvwpl);
  3667. return TRUE;
  3668. }
  3669. /*****************************************************************************\
  3670. * VWPLRemove
  3671. *
  3672. * Removes a pwnd from a VWPL list of pwnds. Reallocates memory as required.
  3673. *
  3674. * Returns FALSE if the pwnd was not found.
  3675. *
  3676. * History:
  3677. * 98-01-30 IanJa Created.
  3678. \*****************************************************************************/
  3679. BOOL VWPLRemove(
  3680. PVWPL *ppvwpl,
  3681. PWND pwnd)
  3682. {
  3683. PVWPL pvwpl = *ppvwpl;
  3684. DWORD ixPwnd;
  3685. TAGMSG2(DBGTAG_VWPL, "VWPL %#p - %#p", *ppvwpl, pwnd);
  3686. UserAssert(pwnd);
  3687. if (!pvwpl) {
  3688. return FALSE;
  3689. }
  3690. for (ixPwnd = 0; ixPwnd < pvwpl->cElem; ixPwnd++) {
  3691. if (pwnd == pvwpl->aPwnd[ixPwnd]) {
  3692. goto PwndIsFound;
  3693. }
  3694. }
  3695. DbgCheckVWPL(*ppvwpl);
  3696. return FALSE;
  3697. PwndIsFound:
  3698. pvwpl->aPwnd[ixPwnd] = NULL;
  3699. pvwpl->cPwnd--;
  3700. if (pvwpl->cPwnd == 0) {
  3701. UserFreePool(pvwpl);
  3702. *ppvwpl = NULL;
  3703. return TRUE;
  3704. }
  3705. /*
  3706. * Compact the VWPL to keep all the empty slots at the end. If these
  3707. * free slots exceeds the threshhold, realloc to shrink. It doesn't
  3708. * matter that we change the order.
  3709. */
  3710. pvwpl->aPwnd[ixPwnd] = pvwpl->aPwnd[pvwpl->cPwnd];
  3711. #if ZERO_INIT_VWPL
  3712. pvwpl->aPwnd[pvwpl->cPwnd] = NULL;
  3713. #endif
  3714. if ((pvwpl->cElem - pvwpl->cPwnd) >= pvwpl->cThreshhold) {
  3715. DWORD dwSize;
  3716. DWORD dwSizeNew;
  3717. dwSize = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cElem);
  3718. dwSizeNew = sizeof(VWPL) + (sizeof(PWND) * pvwpl->cPwnd);
  3719. pvwpl = (PVWPL)UserReAllocPool(pvwpl, dwSize, dwSizeNew, TAG_VWPL);
  3720. if (pvwpl == NULL) {
  3721. RIPMSG2(RIP_WARNING,
  3722. "VWPLRemove fail to reallocate %lx to %lx",
  3723. dwSize, dwSizeNew);
  3724. DbgCheckVWPL(*ppvwpl);
  3725. return TRUE;
  3726. }
  3727. pvwpl->cElem = pvwpl->cPwnd;
  3728. *ppvwpl = pvwpl;
  3729. }
  3730. DbgCheckVWPL(*ppvwpl);
  3731. return TRUE;
  3732. }
  3733. /*****************************************************************************\
  3734. * VWPLNext
  3735. *
  3736. * Returns the next pwnd from a VWPL (Volatile Window Pointer List).
  3737. *
  3738. * Setting *pnPrev to 0 will return the first pwnd in the VWPL, and gets a new
  3739. * value in *pnPrev which is to be used in a subsequent call to VWPLNext to
  3740. * obtain the next pwnd.
  3741. * Returns NULL when the last pwnd has been obtained, and sets *pnPrev back to 0
  3742. *
  3743. * History:
  3744. * 98-01-30 IanJa Created.
  3745. \*****************************************************************************/
  3746. PWND VWPLNext(
  3747. PVWPL pvwpl,
  3748. PWND pwndPrev,
  3749. DWORD *pnPrev)
  3750. {
  3751. DbgCheckVWPL(pvwpl);
  3752. if (!pvwpl) {
  3753. TAGMSG1(DBGTAG_VWPL, "VWPL %#p => NULL (empty)", pvwpl);
  3754. return NULL;
  3755. }
  3756. if (*pnPrev >= pvwpl->cPwnd) {
  3757. goto NoMorePwnds;
  3758. }
  3759. /*
  3760. * If our previous pwnd is still there, advance to the next slot
  3761. * (else it has gone, so return the one now occupying its slot).
  3762. */
  3763. if (pvwpl->aPwnd[*pnPrev] == pwndPrev) {
  3764. (*pnPrev)++;
  3765. }
  3766. if (*pnPrev < pvwpl->cPwnd) {
  3767. UserAssert(pvwpl->aPwnd[*pnPrev] != pwndPrev);
  3768. TAGMSG2(DBGTAG_VWPL, "VWPL %#p => %#p", pvwpl, pvwpl->aPwnd[*pnPrev]);
  3769. return pvwpl->aPwnd[*pnPrev];
  3770. }
  3771. /*
  3772. * We came to the end.
  3773. */
  3774. NoMorePwnds:
  3775. TAGMSG1(DBGTAG_VWPL, "VWPL 0x%p => NULL (end)", pvwpl);
  3776. *pnPrev = 0;
  3777. return NULL;
  3778. }
  3779. /*****************************************************************************\
  3780. * RestoreMonitorsAndWindowsRects
  3781. *
  3782. * Restore a windows sizes and positions previously captured in a WMSNAPSHOT
  3783. * structure. Capture happens when disconnecting from local console and
  3784. * restore happens when connecting back to local console.
  3785. \*****************************************************************************/
  3786. NTSTATUS RestoreMonitorsAndWindowsRects(
  3787. VOID)
  3788. {
  3789. PMONITORRECTS pmr;
  3790. int i;
  3791. int j;
  3792. BOOL bFound;
  3793. PSMWP psmwp;
  3794. PWND pwnd;
  3795. NTSTATUS Status;
  3796. PWPSNAPSHOT pwps = NULL;
  3797. /*
  3798. * Don't do anything if not multimon.
  3799. */
  3800. if (!IsMultimon()) {
  3801. return STATUS_SUCCESS;
  3802. }
  3803. /*
  3804. * Nothing to do if we don't currently have captured monitors or
  3805. * windows snapshots.
  3806. */
  3807. if (gwms.pmr == NULL || gwms.pwps == NULL) {
  3808. Status = STATUS_UNSUCCESSFUL;
  3809. goto Exit;
  3810. }
  3811. /*
  3812. * Get Current monitors layout.
  3813. */
  3814. pmr = SnapshotMonitorRects();
  3815. if (pmr == NULL) {
  3816. Status = STATUS_NO_MEMORY;
  3817. goto Exit;
  3818. }
  3819. /*
  3820. * make sure monitors we captured are still there.
  3821. */
  3822. Status = STATUS_SUCCESS;
  3823. for (i = 0; i < gwms.pmr->cMonitor; i++) {
  3824. bFound = FALSE;
  3825. for (j = 0; j < pmr->cMonitor; j++) {
  3826. if (EqualRect(&gwms.pmr->amp[i].rcMonitor, &pmr->amp[j].rcMonitor)) {
  3827. bFound = TRUE;
  3828. break;
  3829. }
  3830. }
  3831. if (!bFound) {
  3832. Status = STATUS_UNSUCCESSFUL;
  3833. break;
  3834. }
  3835. }
  3836. UserFreePool(pmr);
  3837. /*
  3838. * Position Windows now.
  3839. */
  3840. if (NT_SUCCESS(Status)) {
  3841. if ((psmwp = InternalBeginDeferWindowPos(4)) != NULL) {
  3842. for (i = 0, pwps = gwms.pwps; (i < gwms.cWindows) && (psmwp != NULL) ; i++, pwps++) {
  3843. /*
  3844. * Make sure this hwnd is still here.
  3845. */
  3846. if ((pwnd = RevalidateHwnd(pwps->hwnd)) == NULL ||
  3847. TestWF(pwnd, WEFTOOLWINDOW)) {
  3848. continue;
  3849. }
  3850. psmwp = _DeferWindowPos(psmwp,
  3851. pwnd,
  3852. (PWND)HWND_TOP,
  3853. pwps->rcWindow.left,
  3854. pwps->rcWindow.top,
  3855. pwps->rcWindow.right - pwps->rcWindow.left,
  3856. pwps->rcWindow.bottom - pwps->rcWindow.top,
  3857. SWP_NOACTIVATE | SWP_NOZORDER);
  3858. }
  3859. if (psmwp != NULL) {
  3860. xxxEndDeferWindowPosEx(psmwp, TRUE);
  3861. } else{
  3862. Status = STATUS_NO_MEMORY;
  3863. }
  3864. }
  3865. }
  3866. Exit:
  3867. CleanupMonitorsAndWindowsSnapShot();
  3868. return Status;
  3869. }
  3870. /*****************************************************************************\
  3871. * SnapShotMonitorsAndWindowsRects
  3872. *
  3873. * Captures windows sizes and positions in a WMSNAPSHOT structure. Capture
  3874. * happens when disconnecting from local console.
  3875. \*****************************************************************************/
  3876. NTSTATUS SnapShotMonitorsAndWindowsRects(
  3877. VOID)
  3878. {
  3879. /*
  3880. * First, cleanup anything left over from previous captures.
  3881. */
  3882. if (gwms.pmr != NULL || gwms.pwps != NULL) {
  3883. CleanupMonitorsAndWindowsSnapShot();
  3884. }
  3885. /*
  3886. * Get a snaphot of current monitors configuration.
  3887. */
  3888. if ((gwms.pmr = SnapshotMonitorRects()) == NULL) {
  3889. return STATUS_NO_MEMORY;
  3890. }
  3891. /*
  3892. * Get a snaphsot of windows positions.
  3893. */
  3894. if ((gwms.pwps = SnapshotWindowRects(&gwms.cWindows)) == NULL) {
  3895. CleanupMonitorsAndWindowsSnapShot();
  3896. return STATUS_NO_MEMORY;
  3897. }
  3898. return STATUS_SUCCESS;
  3899. }
  3900. /*****************************************************************************\
  3901. * CleanupMonitorsAndWindowsSnapShot
  3902. *
  3903. * Frees memory allocated to capture windows sizes and positions a WMSNAPSHOT
  3904. * structure.
  3905. \*****************************************************************************/
  3906. VOID CleanupMonitorsAndWindowsSnapShot(
  3907. VOID)
  3908. {
  3909. PWPSNAPSHOT pwps = gwms.pwps;
  3910. if (gwms.pmr != NULL) {
  3911. UserFreePool(gwms.pmr);
  3912. gwms.pmr = NULL;
  3913. }
  3914. if (pwps != NULL) {
  3915. UserFreePool(gwms.pwps);
  3916. gwms.pwps = NULL;
  3917. }
  3918. gwms.cWindows = 0;
  3919. }
  3920. /*****************************************************************************\
  3921. * SnapshotWindowRects
  3922. *
  3923. * Allocates memory to capture window sizes and positions in a WMSNAPSHOT
  3924. * structure.
  3925. \*****************************************************************************/
  3926. PWPSNAPSHOT SnapshotWindowRects(
  3927. int *pnWindows)
  3928. {
  3929. PWND pwndDesktop;
  3930. PHWND phwnd;
  3931. PBWL pbwl;
  3932. PWND pwnd;
  3933. int nWindows = 0;
  3934. PWPSNAPSHOT pwps = NULL;
  3935. PWPSNAPSHOT pReturnedpwps = NULL;
  3936. /*
  3937. * Initialize captured windows count.
  3938. */
  3939. *pnWindows = 0;
  3940. /*
  3941. * Build a list of top windows.
  3942. */
  3943. UserVerify(pwndDesktop = _GetDesktopWindow());
  3944. if ((pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, NULL)) == NULL) {
  3945. return NULL;
  3946. }
  3947. /*
  3948. * Count maximum captured windows to allocate WPSNAPSHOT array.
  3949. */
  3950. phwnd = pbwl->rghwnd;
  3951. while (*phwnd != (HWND)1) {
  3952. nWindows++;
  3953. phwnd++;
  3954. }
  3955. if (nWindows != 0) {
  3956. pwps = UserAllocPoolWithQuotaZInit(sizeof(WPSNAPSHOT) * nWindows, TAG_SWP);
  3957. }
  3958. if (pwps == NULL) {
  3959. FreeHwndList(pbwl);
  3960. return NULL;
  3961. }
  3962. pReturnedpwps = pwps;
  3963. for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  3964. /*
  3965. * Make sure this hwnd is still around.
  3966. */
  3967. if ((pwnd = RevalidateHwnd(*phwnd)) == NULL || TestWF(pwnd, WEFTOOLWINDOW) ) {
  3968. continue;
  3969. }
  3970. pwps->hwnd = *phwnd;
  3971. CopyRect(&pwps->rcWindow, &pwnd->rcWindow);
  3972. (*pnWindows)++;
  3973. pwps++;
  3974. }
  3975. if (*pnWindows != 0) {
  3976. return pReturnedpwps;
  3977. } else {
  3978. UserFreePool(pReturnedpwps);
  3979. return NULL;
  3980. }
  3981. }