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.

2685 lines
88 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: tmswitch.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * History:
  7. * 29-May-1991 DavidPe Created.
  8. \***************************************************************************/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. /*
  12. * COOLSWITCHTRACE is used to trace problems
  13. * in the CoolSwitch window
  14. */
  15. #undef COOLSWITCHTRACE
  16. #define ALT_F6 2
  17. #define ALT_ESCAPE 1
  18. #define FDIR_FORWARD 0
  19. #define FDIR_BACKWARD 1
  20. /*
  21. * Win95 hard codes the size of the icon matrix, the size of
  22. * the icons, the highlight border and the icon spacing
  23. */
  24. #define CXICONSLOT 43
  25. #define CYICONSLOT 43
  26. #define CXICONSIZE 32
  27. #define CYICONSIZE 32
  28. /*
  29. * Pointer to the start of the SwitchInfo list.
  30. */
  31. PSWINFO gpswiFirst;
  32. VOID xxxPaintIconsInSwitchWindow(PWND, PSWINFO, HDC, INT, INT, INT, BOOL, BOOL, PICON);
  33. /***************************************************************************\
  34. * Getpswi
  35. *
  36. * 04-29-96 GerardoB Created
  37. \***************************************************************************/
  38. __inline PSWINFO Getpswi(
  39. PWND pwnd)
  40. {
  41. UserAssert(GETFNID(pwnd) == FNID_SWITCH);
  42. return TestWF(pwnd, WFDESTROYED) ? NULL : ((PSWITCHWND)pwnd)->pswi;
  43. }
  44. /***************************************************************************\
  45. * Setpswi
  46. *
  47. * 04-29-96 GerardoB Created
  48. \***************************************************************************/
  49. __inline VOID Setpswi(
  50. PWND pwnd,
  51. PSWINFO pswi)
  52. {
  53. UserAssert(GETFNID(pwnd) == FNID_SWITCH);
  54. ((PSWITCHWND)pwnd)->pswi = pswi;
  55. }
  56. /***************************************************************************\
  57. * DSW_GetTopLevelCreatorWindow
  58. \***************************************************************************/
  59. PWND DSW_GetTopLevelCreatorWindow(
  60. PWND pwnd)
  61. {
  62. UserAssert(pwnd != NULL);
  63. if (pwnd != NULL) {
  64. while (pwnd->spwndOwner) {
  65. pwnd = pwnd->spwndOwner;
  66. }
  67. }
  68. return pwnd;
  69. }
  70. /***************************************************************************\
  71. * GetNextQueueWindow
  72. *
  73. * This routine is used to implement the Alt+Esc feature. This feature lets
  74. * the user switch between windows for different applications (a.k.a. "Tasks")
  75. * currently running. We keep track of the most recently active window in
  76. * each task. This routine starts with the window passed and searches for the
  77. * next window, in the "top-level" window list, that is from a different task
  78. * than the one passed. We then return the most recenly active window from
  79. * that task (or the window we found if the most recently active has been
  80. * destroyed or is currently disabled or hidden). This routine returns NULL
  81. * if no other enabled, visible window for another task can be found.
  82. *
  83. * History:
  84. * 30-May-1991 DavidPe Ported from Win 3.1 sources.
  85. \***************************************************************************/
  86. PWND _GetNextQueueWindow(
  87. PWND pwnd,
  88. BOOL fPrev, /* 1 backward 0 forward */
  89. BOOL fAltEsc)
  90. {
  91. PWND pwndAltTab;
  92. PWND pwndNext;
  93. PWND pwndT;
  94. PWND pwndDesktop;
  95. BOOL bBeenHereAlready = FALSE;
  96. /*
  97. * If the window we receive is Null then use the last topmost window
  98. */
  99. if (!pwnd) {
  100. pwnd = GetLastTopMostWindow();
  101. if (!pwnd) {
  102. return NULL;
  103. }
  104. }
  105. pwndAltTab = gspwndAltTab;
  106. pwnd = pwndNext = GetTopLevelWindow(pwnd);
  107. if (!pwndNext) {
  108. return NULL;
  109. }
  110. /*
  111. * Get the window's desktop
  112. */
  113. if ((pwndDesktop = pwndNext->spwndParent) == NULL) {
  114. pwndDesktop = grpdeskRitInput->pDeskInfo->spwnd;
  115. pwnd = pwndNext = pwndDesktop->spwndChild;
  116. }
  117. while (TRUE) {
  118. if (pwndNext == NULL)
  119. return NULL;
  120. /*
  121. * Get the next window
  122. */
  123. pwndNext = _GetWindow(pwndNext, fPrev ? GW_HWNDPREV : GW_HWNDNEXT);
  124. if (!pwndNext) {
  125. pwndNext = fPrev ? _GetWindow(pwndDesktop->spwndChild, GW_HWNDLAST)
  126. : pwndDesktop->spwndChild;
  127. /*
  128. * To avoid searching the child chain forever, bale out if we get
  129. * to the end (beginning) of the chain twice.
  130. * This happens if pwnd is a partially destroyed window that has
  131. * been unlinked from its siblings but not yet unlinked from the
  132. * parent. (Happens while sending WM_NCDESTROY in xxxFreeWindow)
  133. */
  134. if (bBeenHereAlready) {
  135. RIPMSG1(RIP_WARNING, "pwnd %#p is no longer a sibling", pwnd);
  136. return NULL;
  137. }
  138. bBeenHereAlready = TRUE;
  139. }
  140. /*
  141. * If we have gone all the way around with no success, return NULL.
  142. */
  143. if (!pwndNext || (pwndNext == pwnd))
  144. return NULL;
  145. /*
  146. * Ignore the following windows:
  147. * Switch window
  148. * Tool Windows
  149. * NoActivate Windows
  150. * Hidden windows
  151. * Disabled windows
  152. * Topmost windows if via Alt+Esc
  153. * Bottommost windows if via Alt+Esc
  154. *
  155. * If we're doing Alt-Esc processing, we have to skip topmost windows.
  156. *
  157. * Because topmost windows don't really go to the back when we
  158. * send them there, alt-esc would never enumerate non-topmost windows.
  159. * So, although we're allowed to start enumeration at a topmost window,
  160. * we only allow enumeration of non-topmost windows, so the user can
  161. * enumerate his presumably more important applications.
  162. */
  163. if ((pwndNext != pwndAltTab) &&
  164. // BradG - Win95 is missing the check for Tool Windows
  165. (!TestWF(pwndNext, WEFTOOLWINDOW)) &&
  166. (!TestWF(pwndNext, WEFNOACTIVATE)) &&
  167. (TestWF(pwndNext, WFVISIBLE)) &&
  168. ((pwndNext->spwndLastActive == NULL) || (!TestWF(pwndNext->spwndLastActive, WFDISABLED)) &&
  169. (!fAltEsc || (!TestWF(pwndNext, WEFTOPMOST) && !TestWF(pwndNext, WFBOTTOMMOST))))) {
  170. /*
  171. * If this window is owned, don't return it unless it is the most
  172. * recently active window in its owner/ownee group.
  173. */
  174. /*
  175. * Hard loop to find top level owner
  176. */
  177. for (pwndT = pwndNext; pwndT->spwndOwner; pwndT = pwndT->spwndOwner)
  178. ;
  179. /*
  180. * Don't return it unless it is the most recently active
  181. * window in its owner/ownee group.
  182. */
  183. if (pwndNext == pwndT->spwndLastActive)
  184. return pwndNext;
  185. }
  186. }
  187. }
  188. /***************************************************************************\
  189. *
  190. * SwitchToThisWindow()
  191. *
  192. * This function was added specifically for Win386. It is called to tell
  193. * USER that a particular window has been switched to via Alt+Tab or
  194. * Alt+Esc in the Win386 environment. They call this function to maintain
  195. * Z-ordering and consistent operation of these two functions. This function
  196. * must be exported, but need not be documented.
  197. *
  198. * The parameter fTab is TRUE if this window is to be switched to via an
  199. * Alt/Ctl+Tab key sequence otherwise it must be FALSE.
  200. *
  201. * History:
  202. * 04-Feb-1991 DarrinM Created.
  203. \***************************************************************************/
  204. VOID xxxSwitchToThisWindow(
  205. PWND pwnd,
  206. BOOL fAltTab)
  207. {
  208. CheckLock(pwnd);
  209. /*
  210. * If we need to, push old window to the bottom.
  211. */
  212. if (gpqForeground && !fAltTab) {
  213. BOOL fPush;
  214. PWND pwndActive;
  215. TL tlpwndActive;
  216. /*
  217. * if ALT-ESC, and the window brought forward is the next one in the
  218. * list, we must be rotating the zorder forward, so push the current
  219. * window to the back
  220. */
  221. pwndActive = gpqForeground->spwndActive;
  222. fPush = pwndActive && _GetNextQueueWindow(pwndActive, FDIR_FORWARD, !fAltTab);
  223. if (fPush && !TestWF(pwndActive, WEFTOPMOST) && !TestWF(pwndActive, WFBOTTOMMOST)) {
  224. ThreadLock(pwndActive, &tlpwndActive);
  225. xxxSetWindowPos(pwndActive, PWND_BOTTOM, 0, 0, 0, 0,
  226. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
  227. ThreadUnlock(&tlpwndActive);
  228. }
  229. }
  230. /*
  231. * Switch this new window to the foreground
  232. * This window can go away during the SetForeground call if it isn't
  233. * on the thread calling SwitchToThisWindow()!
  234. */
  235. xxxSetForegroundWindow(pwnd, TRUE);
  236. /*
  237. * Restore minimized windows if the Alt+Tab case
  238. */
  239. if (fAltTab && TestWF(pwnd,WFMINIMIZED)) {
  240. /*
  241. * We need to package up a special 'posted' queue message here. This
  242. * ensures that this message gets processed after the asynchronous
  243. * activation event occurs (via SetForegroundWindow).
  244. */
  245. PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq,
  246. QEVENT_POSTMESSAGE, pwnd, WM_SYSCOMMAND,
  247. SC_RESTORE, 0 );
  248. }
  249. }
  250. /***************************************************************************\
  251. * NextPrevTaskIndex
  252. *
  253. * History:
  254. * 01-Jun-1995 BradG Ported from Win95
  255. \***************************************************************************/
  256. INT NextPrevTaskIndex(
  257. PSWINFO pswInfo,
  258. INT iIndex,
  259. INT iCount,
  260. BOOL fNext)
  261. {
  262. UserAssert(iCount <= pswInfo->iTotalTasks);
  263. if (fNext) {
  264. iIndex += iCount;
  265. if (iIndex >= pswInfo->iTotalTasks) {
  266. iIndex -= pswInfo->iTotalTasks;
  267. }
  268. } else {
  269. iIndex -= iCount;
  270. if (iIndex < 0) {
  271. iIndex += pswInfo->iTotalTasks;
  272. }
  273. }
  274. UserAssert((iIndex >= 0) && (iIndex < pswInfo->iTotalTasks));
  275. return iIndex;
  276. }
  277. /***************************************************************************\
  278. * NextPrevPhwnd
  279. *
  280. * Given a pointer to one entry in the window list, this can return
  281. * the pointer to the next/prev entry in a circular list fashion.
  282. *
  283. * History:
  284. * 01-Jun-1995 BradG Ported from Win95
  285. \***************************************************************************/
  286. PHWND NextPrevPhwnd(
  287. PSWINFO pswInfo,
  288. PHWND phwnd,
  289. BOOL fNext)
  290. {
  291. PBWL pbwl;
  292. PHWND phwndStart;
  293. PHWND phwndLast;
  294. pbwl = pswInfo->pbwl;
  295. phwndStart = &(pbwl->rghwnd[0]);
  296. phwndLast = pswInfo->phwndLast;
  297. UserAssert(*phwndLast == (HWND)1); // Last entry must have a 1.
  298. UserAssert(phwndStart < phwndLast); // There must be atleast one entry.
  299. UserAssert(phwnd != phwndLast); // Can't be passing in an invalid entry.
  300. if (fNext) {
  301. phwnd++;
  302. if (phwnd == phwndLast) {
  303. phwnd = phwndStart;
  304. }
  305. } else {
  306. if (phwnd == phwndStart) {
  307. phwnd = phwndLast - 1; // we have atleast one valid entry.
  308. } else {
  309. phwnd--;
  310. }
  311. }
  312. return phwnd;
  313. }
  314. /***************************************************************************\
  315. * _IsTaskWindow
  316. *
  317. * History:
  318. * 01-Jun-95 BradG Ported from Win95
  319. \***************************************************************************/
  320. BOOL _IsTaskWindow(
  321. PWND pwnd,
  322. PWND pwndActive)
  323. {
  324. /*
  325. * Following windows do not qualify to be shown in task list:
  326. * Switch Window, Hidden windows (unless they are the active
  327. * window), Disabled windows, Kanji Conv windows.
  328. *
  329. * Also, check for a combobox popup list which has the top-most
  330. * style (it's spwndLastActive will be NULL).
  331. */
  332. UserAssert(pwnd != NULL);
  333. return( (TestWF(pwnd, WEFAPPWINDOW)
  334. || (!TestWF(pwnd, WEFTOOLWINDOW) && !TestWF(pwnd, WEFNOACTIVATE))) &&
  335. (TestWF(pwnd, WFVISIBLE) || (pwnd == pwndActive)) &&
  336. (!(pwnd->spwndLastActive && TestWF(pwnd->spwndLastActive, WFDISABLED))));
  337. }
  338. /***************************************************************************\
  339. * RemoveNonTaskWindows()
  340. *
  341. * Given a list of Windows, this walks down the list and removes the
  342. * windows that do not qualify to be shown in the Task-Switch screen.
  343. * This also shrinks the list when it removes some entries.
  344. * Returns the total number of "tasks" (windows) qualified and remained
  345. * in the list. The last entry will have a 1 as usual.
  346. * It also returns a pointer to this last entry via params. It also
  347. * returns the index of the Currently active task via params.
  348. *
  349. * History:
  350. * 01-Jun-1995 BradG Ported from Win95
  351. \***************************************************************************/
  352. INT _RemoveNonTaskWindows(
  353. PBWL pbwl,
  354. PWND pwndActive,
  355. LPINT lpiActiveTask,
  356. PHWND *pphwndLast)
  357. {
  358. INT iTaskCount = 0;
  359. PHWND phwnd;
  360. PWND pwnd;
  361. PWND pwndUse;
  362. PWND pwndOwnee;
  363. PHWND phwndHole;
  364. *lpiActiveTask = -1;
  365. /*
  366. * Walk down the window list and do the following:
  367. * 1. Remove all entries that do not qualify to be shown in the task list.
  368. * 2. Count the total number of windows that qualify.
  369. * 3. Get the pointer to the entry that contains current active window.
  370. * 4. Get the pointer to the last dummy entry (that has 1 in it)
  371. */
  372. for (phwndHole = phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
  373. pwnd = RevalidateHwnd(*phwnd);
  374. if (!pwnd) {
  375. continue;
  376. }
  377. if (_IsTaskWindow(pwnd, pwndActive)) {
  378. pwndUse = pwnd;
  379. /*
  380. * First let's find the task-list owner of this window.
  381. */
  382. while (!TestWF(pwndUse, WEFAPPWINDOW) && pwndUse->spwndOwner) {
  383. pwndOwnee = pwndUse;
  384. pwndUse = pwndUse->spwndOwner;
  385. if (TestWF(pwndUse, WEFTOOLWINDOW)) {
  386. /*
  387. * If this is the owner of a top level property sheet,
  388. * show the property sheet.
  389. */
  390. if (TestWF(pwndOwnee, WEFCONTROLPARENT) && (pwndUse->spwndOwner == NULL)) {
  391. pwndUse = pwnd;
  392. } else {
  393. pwndUse = NULL;
  394. }
  395. break;
  396. }
  397. }
  398. if (!pwndUse || !pwndUse->spwndLastActive) {
  399. continue;
  400. }
  401. /*
  402. * walk up from the last active window 'til we find a valid task
  403. * list window or until we run out of windows in the ownership
  404. * chain
  405. */
  406. for (pwndUse = pwndUse->spwndLastActive; pwndUse; pwndUse = pwndUse->spwndOwner)
  407. if (_IsTaskWindow(pwndUse, pwndActive))
  408. break;
  409. /*
  410. * if we ran out of windows in the ownership chain then use the
  411. * owned window itself -- or if we didn't run out of the ownership
  412. * chain, then only include this window if it's the window in the
  413. * ownership chain that we just found (VB will love us for it !)
  414. * -- jeffbog -- 4/20/95 -- Win95C B#2821
  415. */
  416. if (!pwndUse || (pwndUse == pwnd)) {
  417. /*
  418. * Do we have any holes above this? If so, move this handle to
  419. * that hole.
  420. */
  421. if (phwndHole < phwnd) {
  422. /*
  423. * Yes! There is a hole. Let us move the valid
  424. * handle there.
  425. */
  426. *phwndHole = *phwnd;
  427. }
  428. if (pwndActive == pwnd)
  429. *lpiActiveTask = iTaskCount;
  430. iTaskCount++;
  431. phwndHole++; // Move to the next entry.
  432. }
  433. /*
  434. * Else, leave it as a hole for later filling.
  435. */
  436. }
  437. }
  438. *phwndHole = (HWND)1;
  439. *pphwndLast = phwndHole;
  440. return iTaskCount;
  441. }
  442. /***************************************************************************\
  443. * DrawSwitchWndHilite()
  444. *
  445. * This draws or erases the Hilite we draw around the icon to show which
  446. * task we are going to switch to.
  447. * This also updates the name on the Task title window.
  448. *
  449. * History:
  450. * 01-Jun-1995 BradG Ported from Win95
  451. \***************************************************************************/
  452. VOID DrawSwitchWndHilite(
  453. PSWINFO pswInfo,
  454. HDC hdcSwitch,
  455. int iCol,
  456. int iRow,
  457. BOOL fShow)
  458. {
  459. BOOL fGetAndReleaseIt;
  460. RECT rcTemp;
  461. /*
  462. * Draw or erase the hilite depending on "fShow".
  463. */
  464. if (fGetAndReleaseIt = (hdcSwitch == NULL))
  465. hdcSwitch = _GetDCEx(gspwndAltTab, NULL, DCX_USESTYLE);
  466. rcTemp.left = pswInfo->ptFirstRowStart.x + iCol * CXICONSLOT;
  467. rcTemp.top = pswInfo->ptFirstRowStart.y + iRow * CYICONSLOT;
  468. rcTemp.right = rcTemp.left + CXICONSLOT;
  469. rcTemp.bottom = rcTemp.top + CYICONSLOT;
  470. DrawFrame(hdcSwitch,
  471. &rcTemp,
  472. 2,
  473. DF_PATCOPY | ((fShow ? COLOR_HIGHLIGHT : COLOR_3DFACE) << 3));
  474. /*
  475. * Update the Task title window.
  476. */
  477. if (fShow) {
  478. WCHAR szText[CCHTITLEMAX];
  479. INT cch;
  480. COLORREF clrOldText, clrOldBk;
  481. PWND pwnd;
  482. RECT rcRect;
  483. HFONT hOldFont;
  484. INT iLeft;
  485. ULONG_PTR dwResult = 0;
  486. clrOldText = GreSetTextColor(hdcSwitch, SYSRGB(BTNTEXT));
  487. clrOldBk = GreSetBkColor(hdcSwitch, SYSRGB(3DFACE));
  488. hOldFont = GreSelectFont(hdcSwitch, gpsi->hCaptionFont);
  489. /*
  490. * Validate this window handle; This could be some app that terminated
  491. * in the background and the following line will GP fault in that case;
  492. * BOGUS: We should handle it some other better way.
  493. */
  494. pwnd = RevalidateHwnd( *(pswInfo->phwndCurrent) );
  495. if (pwnd) {
  496. /*
  497. * Get the window's title.
  498. */
  499. if (pwnd->strName.Length) {
  500. cch = TextCopy(&pwnd->strName, szText, CCHTITLEMAX);
  501. } else {
  502. *szText = TEXT('\0');
  503. cch = 0;
  504. }
  505. /*
  506. * Draw the text
  507. */
  508. CopyRect(&rcRect, &pswInfo->rcTaskName);
  509. iLeft = rcRect.left;
  510. FillRect(hdcSwitch, &rcRect, SYSHBR(3DFACE));
  511. /*
  512. * If an lpk is installed let it draw the text.
  513. */
  514. if (CALL_LPK(PtiCurrentShared())) {
  515. TL tlpwnd;
  516. LPKDRAWSWITCHWND LpkDrawSwitchWnd;
  517. RtlInitLargeUnicodeString(&LpkDrawSwitchWnd.strName, szText, (UINT)-1);
  518. LpkDrawSwitchWnd.rcRect = rcRect;
  519. ThreadLock(pwnd, &tlpwnd);
  520. xxxSendMessageTimeout(pwnd, WM_LPKDRAWSWITCHWND, (WPARAM)hdcSwitch,
  521. (LPARAM)&LpkDrawSwitchWnd, SMTO_ABORTIFHUNG, 100, &dwResult);
  522. ThreadUnlock(&tlpwnd);
  523. } else {
  524. DRAWTEXTPARAMS dtp;
  525. dtp.cbSize = sizeof(dtp);
  526. dtp.iLeftMargin = 0;
  527. dtp.iRightMargin = 0;
  528. DrawTextEx(hdcSwitch, szText, cch, &rcRect, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE, &dtp );
  529. }
  530. }
  531. GreSelectFont(hdcSwitch, hOldFont);
  532. GreSetBkColor(hdcSwitch, clrOldBk);
  533. GreSetTextColor(hdcSwitch, clrOldText);
  534. }
  535. if (fGetAndReleaseIt)
  536. _ReleaseDC(hdcSwitch);
  537. }
  538. /***************************************************************************\
  539. * DrawIconCallBack
  540. *
  541. * This function is called by a Windows app returning his icon.
  542. *
  543. * History:
  544. * 17-Jun-1993 mikesch Created.
  545. \***************************************************************************/
  546. VOID CALLBACK DrawIconCallBack(
  547. HWND hwnd,
  548. UINT uMsg,
  549. ULONG_PTR dwData,
  550. LRESULT lResult)
  551. {
  552. PWND pwndAltTab;
  553. /*
  554. * dwData is the pointer to the switch window handle.
  555. * If this Alt+Tab instance is still active, we need to derive this
  556. * window's index in the bwl array, otherwise, we are receiving an icon
  557. * for an old Alt+Tab window.
  558. */
  559. pwndAltTab = RevalidateHwnd((HWND)dwData);
  560. if (pwndAltTab && TestWF(pwndAltTab, WFVISIBLE)) {
  561. PSWINFO pswCurrent;
  562. PICON pIcon;
  563. PHWND phwnd;
  564. PWND pwnd;
  565. PWND pwndT;
  566. INT iStartTaskIndex;
  567. TL tlpwndAltTab;
  568. /*
  569. * Derive this window's index in the BWL array
  570. */
  571. if ((pwnd = RevalidateHwnd(hwnd)) == NULL)
  572. return;
  573. /*
  574. * Get the switch window info
  575. */
  576. pswCurrent = Getpswi(pwndAltTab);
  577. if (!pswCurrent)
  578. return;
  579. for (iStartTaskIndex = 0, phwnd=&(pswCurrent->pbwl->rghwnd[0]); *phwnd != (HWND)1; phwnd++, iStartTaskIndex++) {
  580. /*
  581. * Because we list the active window in the Switch Window, the
  582. * hwnd here might not be the same, so we also need to walk back
  583. * to the top-level window to see if this is the right entry
  584. * in the list.
  585. */
  586. for(pwndT = RevalidateHwnd(*phwnd); pwndT; pwndT = pwndT->spwndOwner) {
  587. if (pwnd == pwndT)
  588. goto DrawIcon;
  589. }
  590. }
  591. return;
  592. /*
  593. * Convert the App's HICON into a PICON, or if the App did not return
  594. * an icon, use the Windows default icon.
  595. */
  596. DrawIcon:
  597. pIcon = NULL;
  598. if (lResult)
  599. pIcon = HMValidateHandleNoRip((HCURSOR)lResult, TYPE_CURSOR);
  600. if (!pIcon)
  601. pIcon = SYSICO(WINLOGO);
  602. /*
  603. * Paint this icon in the Alt+Tab window.
  604. */
  605. ThreadLockAlways(pwndAltTab, &tlpwndAltTab);
  606. xxxPaintIconsInSwitchWindow(pwndAltTab,
  607. pswCurrent,
  608. NULL,
  609. iStartTaskIndex,
  610. 0,
  611. 1,
  612. FALSE,
  613. FALSE,
  614. pIcon);
  615. ThreadUnlock(&tlpwndAltTab);
  616. }
  617. UNREFERENCED_PARAMETER(uMsg);
  618. }
  619. /***************************************************************************\
  620. * TSW_CalcRowAndCol
  621. *
  622. * History:
  623. * 01-Jun-1995 BradG Ported from Win95
  624. \***************************************************************************/
  625. BOOL TSW_CalcRowAndCol(
  626. PSWINFO pswInfo,
  627. INT iTaskIndex,
  628. LPINT lpiRow,
  629. LPINT lpiCol)
  630. {
  631. INT iDiff;
  632. INT iRow;
  633. /*
  634. * Calculate how far is the given task from the first task shown
  635. * on the switch window.
  636. */
  637. if ((iDiff = (iTaskIndex - pswInfo->iFirstTaskIndex)) < 0)
  638. iDiff += pswInfo->iTotalTasks;
  639. /*
  640. * Calculate the Row and if this lies outside the switch window, return FALSE
  641. */
  642. if ((iRow = iDiff / pswInfo->iNoOfColumns) >= pswInfo->iNoOfRows)
  643. return FALSE;
  644. /*
  645. * Return the Row and column where this task lies.
  646. */
  647. *lpiRow = iRow;
  648. *lpiCol = iDiff - (iRow * pswInfo->iNoOfColumns);
  649. return TRUE; // This task lies within the switch window.
  650. }
  651. /***************************************************************************\
  652. * xxxPaintIconsInSwitchWindow()
  653. *
  654. * This can simply paint the icons in the switch window or Scroll the
  655. * whole window UP/DOWN and then paint the remaining area;
  656. * * If fScroll is TRUE, then the second, third and fourth params are ignored.
  657. * * If hIcon is passed in, then we're being called by DrawIconCallBack and
  658. * iStartRow parameter is ignored in this case.
  659. *
  660. * History:
  661. * 02-Jun-1995 BradG Ported from Win95
  662. \***************************************************************************/
  663. VOID xxxPaintIconsInSwitchWindow(
  664. PWND pwndAltTab,
  665. PSWINFO pswInfo,
  666. HDC hdc,
  667. INT iStartTaskIndex,
  668. INT iStartRow,
  669. INT iNoOfIcons,
  670. BOOL fScroll,
  671. BOOL fUp,
  672. PICON pIcon)
  673. {
  674. INT cx, cy, xStart;
  675. PHWND phwnd;
  676. BOOL fGetAndReleaseIt;
  677. INT iColumnIndex = 0;
  678. RECT rcScroll;
  679. PWND pwnd;
  680. TL tlpwnd;
  681. HICON hIcon;
  682. RECT rcIcon;
  683. CheckLock(pwndAltTab);
  684. /*
  685. * If we were not supplied a DC, get ghwndSwitch's and set a flag
  686. * so we remember to release it.
  687. */
  688. if (fGetAndReleaseIt = (hdc == NULL))
  689. hdc = _GetDCEx(pwndAltTab, NULL, DCX_USESTYLE);
  690. cx = pswInfo->ptFirstRowStart.x;
  691. cy = pswInfo->ptFirstRowStart.y;
  692. if (fScroll) {
  693. rcScroll.left = cx;
  694. rcScroll.top = cy;
  695. rcScroll.right = cx + CXICONSLOT * pswInfo->iNoOfColumns;
  696. rcScroll.bottom = cy + CYICONSLOT * pswInfo->iNoOfRows;
  697. _ScrollDC(hdc,
  698. 0,
  699. (fUp ? -CYICONSLOT : CYICONSLOT),
  700. &rcScroll,
  701. &rcScroll,
  702. NULL,
  703. NULL);
  704. iStartRow = (fUp ? pswInfo->iNoOfRows - 1 : 0);
  705. iNoOfIcons = pswInfo->iNoOfColumns;
  706. iStartTaskIndex = (fUp ? NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
  707. (pswInfo->iNoOfRows - 1) * pswInfo->iNoOfColumns, TRUE) :
  708. pswInfo->iFirstTaskIndex);
  709. }
  710. if (pIcon) {
  711. /*
  712. * If pIcon is given, this is to paint just one icon during callback.
  713. */
  714. // BradG - Win95 Assert
  715. UserAssert(iNoOfIcons == 1);
  716. /*
  717. * Due to earlier scrolling, the row number would have changed. So,
  718. * recalc the row and column from the iStartTaskIndex given.
  719. */
  720. if (!TSW_CalcRowAndCol(pswInfo, iStartTaskIndex, &iStartRow, &iColumnIndex))
  721. goto Cleanup;
  722. }
  723. xStart = cx += (CXICONSLOT - CXICONSIZE) / 2;
  724. cx += iColumnIndex * CXICONSLOT;
  725. cy += ((CYICONSLOT - CYICONSIZE) / 2) + iStartRow * CYICONSLOT;
  726. phwnd = &(pswInfo->pbwl->rghwnd[iStartTaskIndex]);
  727. /*
  728. * Draw all the icons one by one.
  729. */
  730. while (iNoOfIcons--) {
  731. /*
  732. * If the Alt+Key is no longer down, abort painting icons.
  733. */
  734. if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  735. (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
  736. goto Cleanup;
  737. /*
  738. * Check if this window is still alive. (Some task could have
  739. * terminated in the background)
  740. */
  741. if (pwnd = RevalidateHwnd(*phwnd)) {
  742. /*
  743. * Find the window's top-level owner
  744. */
  745. pwnd = DSW_GetTopLevelCreatorWindow(pwnd);
  746. /*
  747. * If we don't have an icon, find one
  748. */
  749. if (!pIcon) {
  750. /*
  751. * Try window icon
  752. */
  753. hIcon = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL);
  754. if (hIcon) {
  755. pIcon = (PICON)HMValidateHandleNoRip(hIcon, TYPE_CURSOR);
  756. }
  757. /*
  758. * If we don't have an icon yet, try the class icon
  759. */
  760. if (!pIcon) {
  761. pIcon = pwnd->pcls->spicn;
  762. }
  763. /*
  764. * If we don't have an icon yet, use WM_QUERYDRAGICON to ask
  765. * 3,x apps for their icon.
  766. */
  767. if (!pIcon && !TestWF(pwnd, WFWIN40COMPAT)) {
  768. /*
  769. * The callback routine will paint the icon for
  770. * us, so just leave pIcon set to NULL
  771. */
  772. ThreadLock(pwnd, &tlpwnd);
  773. xxxSendMessageCallback(pwnd, WM_QUERYDRAGICON, 0, 0,
  774. (SENDASYNCPROC)DrawIconCallBack,
  775. HandleToUlong(PtoH(pwndAltTab)), FALSE);
  776. ThreadUnlock(&tlpwnd);
  777. } else {
  778. /*
  779. * If we can't find an icon, so use the Windows icon
  780. */
  781. if (!pIcon) {
  782. pIcon = SYSICO(WINLOGO);
  783. }
  784. }
  785. }
  786. }
  787. if (pIcon) {
  788. _DrawIconEx(hdc, cx, cy, pIcon, SYSMET(CXICON), SYSMET(CYICON),
  789. 0, SYSHBR(3DFACE), DI_NORMAL);
  790. } else if (fScroll) {
  791. /*
  792. * NOT IN WIN95
  793. *
  794. * No icon was available, do while we are waiting for the
  795. * application to paint it's icon, we need to "erase" the
  796. * background in case we have scrolled the window.
  797. */
  798. rcIcon.left = cx;
  799. rcIcon.top = cy;
  800. rcIcon.right = cx + SYSMET(CXICON);
  801. rcIcon.bottom = cy + SYSMET(CYICON);
  802. FillRect(hdc, &rcIcon, SYSHBR(3DFACE));
  803. }
  804. /*
  805. * Check if we are done.
  806. */
  807. if (iNoOfIcons <= 0)
  808. break;
  809. /*
  810. * Reset hIcon for the next run through the loop
  811. */
  812. pIcon = NULL;
  813. /*
  814. * Move all pointers to the next task/icon.
  815. */
  816. phwnd = NextPrevPhwnd(pswInfo, phwnd, TRUE); // Get next.
  817. /*
  818. * Is it going to be in the same row; then adjust cx and cy.
  819. */
  820. if (++iColumnIndex >= pswInfo->iNoOfColumns) {
  821. iColumnIndex = 0;
  822. cx = xStart; // Move to first column
  823. cy += CYICONSLOT; // Move to next row.
  824. iStartRow++;
  825. } else {
  826. /*
  827. * else, adjust cx;
  828. */
  829. cx += CXICONSLOT;
  830. }
  831. iStartTaskIndex = NextPrevTaskIndex(pswInfo, iStartTaskIndex, 1, TRUE);
  832. }
  833. Cleanup:
  834. if (fGetAndReleaseIt)
  835. _ReleaseDC(hdc);
  836. }
  837. /***************************************************************************\
  838. * PaintSwitchWindow
  839. *
  840. * History:
  841. * 02-Jun-1995 BradG Ported from Win95
  842. \***************************************************************************/
  843. VOID xxxPaintSwitchWindow(
  844. PWND pwndSwitch)
  845. {
  846. LPRECT lprcRect;
  847. RECT rcRgn;
  848. HDC hdcSwitch;
  849. PSWINFO pswCurrent;
  850. CheckLock(pwndSwitch);
  851. /*
  852. * If our window isn't visible, return
  853. */
  854. if (!TestWF(pwndSwitch, WFVISIBLE))
  855. return;
  856. /*
  857. * Get the switch window information
  858. */
  859. pswCurrent = Getpswi(pwndSwitch);
  860. if (!pswCurrent)
  861. return;
  862. /*
  863. * Get the Switch windows DC so we can paint with it
  864. */
  865. hdcSwitch = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE );
  866. /*
  867. * Paint the background of the Switch Screen.
  868. */
  869. if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  870. (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
  871. goto PSWExit;
  872. lprcRect = &(pswCurrent->rcTaskName);
  873. _GetClientRect(pwndSwitch, lprcRect);
  874. FillRect(hdcSwitch, lprcRect, SYSHBR(3DFACE));
  875. /*
  876. * Store this "caption" area back into the current switch
  877. * window data structure.
  878. */
  879. InflateRect(lprcRect, -(gcxCaptionFontChar << 1), -(gcyCaptionFontChar));
  880. lprcRect->top = lprcRect->bottom - gcyCaptionFontChar;
  881. /*
  882. * Draw the sunken edge for showing the task names.
  883. */
  884. if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  885. (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
  886. goto PSWExit;
  887. CopyInflateRect(&rcRgn, lprcRect, gcxCaptionFontChar >> 1, gcyCaptionFontChar >> 1);
  888. DrawEdge(hdcSwitch, &rcRgn, EDGE_SUNKEN, BF_RECT);
  889. /*
  890. * Paint the icons
  891. */
  892. if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  893. (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
  894. goto PSWExit;
  895. xxxPaintIconsInSwitchWindow(pwndSwitch,
  896. pswCurrent,
  897. hdcSwitch,
  898. pswCurrent->iFirstTaskIndex,
  899. 0,
  900. pswCurrent->iTasksShown,
  901. FALSE,
  902. FALSE,
  903. NULL);
  904. /*
  905. * So, just draw the hilite.
  906. */
  907. if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  908. (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
  909. goto PSWExit;
  910. DrawSwitchWndHilite(pswCurrent,
  911. hdcSwitch,
  912. pswCurrent->iCurCol,
  913. pswCurrent->iCurRow,
  914. TRUE);
  915. /*
  916. * Release the switch windows DC
  917. */
  918. PSWExit:
  919. _ReleaseDC(hdcSwitch);
  920. }
  921. /***************************************************************************\
  922. * SwitchWndCleanup()
  923. *
  924. * Clean up all the mem allocated etc.,
  925. *
  926. * History:
  927. * 07-Jun-1995 BradG Ported from Win95
  928. \***************************************************************************/
  929. VOID SwitchWndCleanup(
  930. PSWINFO *ppswInfo)
  931. {
  932. UserAssert(ppswInfo != NULL);
  933. UserAssert(*ppswInfo != NULL);
  934. /*
  935. * First of all free the Window list.
  936. */
  937. if ((*ppswInfo)->pbwl)
  938. FreeHwndList((*ppswInfo)->pbwl);
  939. UserFreePool(*ppswInfo);
  940. *ppswInfo = NULL;
  941. }
  942. /***************************************************************************\
  943. * AddSwitchWindowInfo
  944. *
  945. * 09-12-01 MSadek Created
  946. \***************************************************************************/
  947. VOID AddSwitchWindowInfo(
  948. PSWINFO pswInfo)
  949. {
  950. CheckCritIn();
  951. pswInfo->pswiNext = gpswiFirst;
  952. gpswiFirst = pswInfo;
  953. }
  954. /***************************************************************************\
  955. * RemoveSwitchWindowInfo
  956. *
  957. * 09-12-01 MSadek Created
  958. \***************************************************************************/
  959. VOID RemoveSwitchWindowInfo(
  960. PSWINFO *ppswInfo)
  961. {
  962. PSWINFO* ppswi;
  963. PSWINFO pswiT;
  964. CheckCritIn();
  965. for (ppswi = &gpswiFirst; *ppswi != NULL; ppswi = &(*ppswi)->pswiNext) {
  966. pswiT = *ppswi;
  967. if (pswiT == *ppswInfo) {
  968. *ppswi = pswiT->pswiNext;
  969. SwitchWndCleanup(ppswInfo);
  970. }
  971. if (*ppswi == NULL) {
  972. break;
  973. }
  974. }
  975. }
  976. /***************************************************************************\
  977. * RemoveThreadSwitchWindowInfo
  978. *
  979. * 09-12-01 MSadek Created
  980. \***************************************************************************/
  981. VOID RemoveThreadSwitchWindowInfo(
  982. PTHREADINFO pti)
  983. {
  984. PSWINFO* ppswi;
  985. PSWINFO pswiT;
  986. CheckCritIn();
  987. for (ppswi = &gpswiFirst; *ppswi != NULL; ppswi = &(*ppswi)->pswiNext) {
  988. pswiT = *ppswi;
  989. if (pswiT->pti == pti) {
  990. *ppswi = pswiT->pswiNext;
  991. SwitchWndCleanup(&pswiT);
  992. }
  993. if (*ppswi == NULL) {
  994. break;
  995. }
  996. }
  997. }
  998. /***************************************************************************\
  999. * InitSwitchWndInfo
  1000. *
  1001. * This function allocs and Initializes all the data structures
  1002. * required the build and show the tasks in the system.
  1003. * If there is insufficient mem, then this find the next window to switch
  1004. * to and returns it. In this case, we will behave as if the end user hit
  1005. * ALT+ESC. The SWitchScreen will not comeup in this case.
  1006. * If there is only one task in the whole system, then this function
  1007. * fails and returns a NULL. (No ALT+TAB processing is required).
  1008. * Otherwise, it allocs one SwitchWndInfo struc, fills it up and returns
  1009. * the window we gonna switch to.
  1010. *
  1011. * History:
  1012. * 02-Jun-95 BradG Ported from Win95
  1013. \***************************************************************************/
  1014. PWND InitSwitchWndInfo(
  1015. PSWINFO * lppswInfo,
  1016. PWND pwndCurActive,
  1017. BOOL fPrev)
  1018. {
  1019. PBWL pbwl;
  1020. INT iTotalTasks;
  1021. INT iCols, iRows, iIconsInLastRow;
  1022. INT iDiff;
  1023. PHWND phwndLast;
  1024. PSWINFO pswInfo;
  1025. INT iIconIndex;
  1026. INT iCurRow, iCurCol;
  1027. INT cxSwitch, cySwitch;
  1028. INT iFirstRowIcons;
  1029. INT iActiveTask;
  1030. PWND pwnd = NULL;
  1031. PTHREADINFO ptiCurrent = PtiCurrent();
  1032. PDESKTOPINFO pdeskinfo = GETDESKINFO(ptiCurrent);
  1033. PMONITOR pMonitor = GetPrimaryMonitor();
  1034. /*
  1035. * Initialize the list
  1036. */
  1037. *lppswInfo = (PSWINFO)NULL;
  1038. /*
  1039. * Build the Window list of all the top level windows.
  1040. */
  1041. #if 0
  1042. if (!(pbwl = BuildHwndList(NULL, BWL_ENUMLIST | BWL_ALLDESKTOPS, NULL)))
  1043. goto ReturnNextWnd;
  1044. #else
  1045. // BradG - HACK, enumerate on current desktop!
  1046. // For the long run, we will need to enumerate all desktops
  1047. // This will be tricky because we need to check the security of
  1048. // each desktop, thus needing the user's security "token".
  1049. if (!(pbwl = BuildHwndList(pdeskinfo->spwnd->spwndChild, BWL_ENUMLIST, NULL))) {
  1050. #ifdef COOLSWITCHTRACE
  1051. DbgPrint("CoolSwitch: BuildHwndList failed (contact bradg).\n");
  1052. UserAssert(pbwl != NULL);
  1053. #endif
  1054. goto ReturnNextWnd;
  1055. }
  1056. #endif
  1057. /*
  1058. * Walk down the list and remove all non-task windows from the list.
  1059. * Replace those hwnds with 0.
  1060. */
  1061. if ((iTotalTasks = _RemoveNonTaskWindows(pbwl, pwndCurActive, &iActiveTask, &phwndLast)) < 2) {
  1062. if (iTotalTasks == 1) {
  1063. /*
  1064. * If we have only one window and it's in full screen mode, we will
  1065. * return the shell window so the can switch back to GDI mode.
  1066. */
  1067. pwnd = RevalidateHwnd(pbwl->rghwnd[0]);
  1068. if (pwnd && GetFullScreen(pwnd) == FULLSCREEN && pwndCurActive == pwnd)
  1069. pwnd = pdeskinfo->spwndShell;
  1070. } else {
  1071. pwnd = pdeskinfo->spwndShell;
  1072. }
  1073. #ifdef COOLSWITCHTRACE
  1074. DbgPrint("CoolSwitch: Not enough windows to switch.\n");
  1075. #endif
  1076. goto FreeAndReturnNextWnd; // If there isn't even two tasks, no switch wnd processing.
  1077. }
  1078. /*
  1079. * Allocate the Switch Info structure. If we don't have enough
  1080. * memory, act as if we are doing Alt+Esc.
  1081. */
  1082. if (!(pswInfo = (PSWINFO)UserAllocPoolWithQuota(sizeof(SWITCHWNDINFO), TAG_ALTTAB))) {
  1083. #ifdef COOLSWITCHTRACE
  1084. DbgPrint("CoolSwitch: UserAllocPool failed on 0x%X bytes (contact bradg).\n", sizeof(SWITCHWNDINFO));
  1085. UserAssert(pswInfo != NULL);
  1086. #endif
  1087. goto FreeAndReturnNextWnd; // Unable to alloc SwitchWndInfo struct.
  1088. }
  1089. pswInfo->pti = ptiCurrent;
  1090. pswInfo->pbwl = pbwl;
  1091. pswInfo->phwndLast = phwndLast;
  1092. pswInfo->iTasksShown = pswInfo->iTotalTasks = iTotalTasks;
  1093. /*
  1094. * Get the next/prev window that must become active.
  1095. */
  1096. iIconIndex = NextPrevTaskIndex(pswInfo, iActiveTask, 1, !fPrev);
  1097. pswInfo->phwndCurrent = &(pbwl->rghwnd[iIconIndex]);
  1098. iCols = min(gnFastAltTabColumns, iTotalTasks);
  1099. iRows = iTotalTasks / iCols; // Truncation might occur.
  1100. iIconsInLastRow = iTotalTasks - iRows * iCols;
  1101. iRows += (iIconsInLastRow ? 1 : 0); // Take care of earlier truncation.
  1102. /*
  1103. * Restrict the number of rows to just MAXROWSALLOWED (3)
  1104. */
  1105. if (iRows > gnFastAltTabRows) {
  1106. iRows = gnFastAltTabRows;
  1107. pswInfo->fScroll = TRUE; // We need to scroll.
  1108. iIconsInLastRow = iCols;
  1109. pswInfo->iTasksShown = iCols * iRows;
  1110. } else {
  1111. pswInfo->fScroll = FALSE;
  1112. }
  1113. pswInfo->iNoOfColumns = iCols;
  1114. pswInfo->iNoOfRows = iRows;
  1115. if (iIconsInLastRow == 0)
  1116. iIconsInLastRow = pswInfo->iNoOfColumns; // Last Row is full.
  1117. pswInfo->iIconsInLastRow = iIconsInLastRow;
  1118. /*
  1119. * Find out Row and Col where the next/prev icon will lie.
  1120. */
  1121. if (iIconIndex >= (iRows * iCols)) {
  1122. /*
  1123. * Next Icon lies outside. Bring it to the center.
  1124. */
  1125. iCurRow = (iRows >> 2) + 1;
  1126. iCurCol = (iCols >> 2) + 1;
  1127. iDiff = (iIconIndex - ((iCurRow * iCols) + iCurCol));
  1128. } else {
  1129. iDiff = 0;
  1130. iCurRow = iIconIndex / iCols;
  1131. iCurCol = iIconIndex - (iCurRow * iCols);
  1132. }
  1133. pswInfo->iFirstTaskIndex = iDiff;
  1134. pswInfo->iCurRow = iCurRow;
  1135. pswInfo->iCurCol = iCurCol;
  1136. /*
  1137. * Calculate the Switch Window Dimensions.
  1138. */
  1139. cxSwitch = min(
  1140. pMonitor->rcMonitor.right - pMonitor->rcMonitor.left,
  1141. gnFastAltTabColumns * CXICONSLOT +
  1142. CXICONSIZE / 2 +
  1143. 6 * gpsi->gclBorder * SYSMET(CXBORDER) +
  1144. gcxCaptionFontChar);
  1145. cySwitch = min(
  1146. pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top,
  1147. iRows * CYICONSLOT +
  1148. CYICONSIZE +
  1149. gcyCaptionFontChar * 2 +
  1150. gcyCaptionFontChar / 2);
  1151. /*
  1152. * Find the number of icons in first row
  1153. */
  1154. if (iRows == 1) {
  1155. iFirstRowIcons = iIconsInLastRow;
  1156. } else {
  1157. iFirstRowIcons = iCols;
  1158. }
  1159. /*
  1160. * Center the icons based on the number of icons in first row.
  1161. */
  1162. pswInfo->ptFirstRowStart.x = (cxSwitch - 4*gpsi->gclBorder*SYSMET(CXBORDER) - iFirstRowIcons * CXICONSLOT) >> 1;
  1163. pswInfo->ptFirstRowStart.y = (CYICONSIZE >> 1);
  1164. pswInfo->cxSwitch = cxSwitch;
  1165. pswInfo->cySwitch = cySwitch;
  1166. AddSwitchWindowInfo(pswInfo);
  1167. *lppswInfo = pswInfo;
  1168. return RevalidateHwnd(*(pswInfo->phwndCurrent)); // Success!
  1169. /*
  1170. * When there is insufficient mem to create the reqd structures, we simply
  1171. * return the next window. We make the phwndInfo as NULL. So, we won't
  1172. * attempt to draw the switch window.
  1173. */
  1174. FreeAndReturnNextWnd:
  1175. FreeHwndList(pbwl);
  1176. ReturnNextWnd:
  1177. if (pwnd)
  1178. return(pwnd);
  1179. return(_GetNextQueueWindow(pwndCurActive, _GetKeyState(VK_SHIFT) < 0, FALSE));
  1180. }
  1181. /***************************************************************************\
  1182. * xxxMoveSwitchWndHilite()
  1183. *
  1184. * This moves the Hilite to the next/prev icon.
  1185. * Checks if this move results in a scrolling. If it does, then
  1186. * make sure scroll occurs.
  1187. * Else, erase hilite from the current icon;
  1188. * Then draw hilite on the new Icon.
  1189. * fPrev indicates whether you want the prev task or next.
  1190. *
  1191. * History:
  1192. * 02-Jun-1995 BradG Ported from Win95
  1193. \***************************************************************************/
  1194. HWND xxxMoveSwitchWndHilite(
  1195. PWND pwndSwitch,
  1196. PSWINFO pswInfo,
  1197. BOOL fPrev)
  1198. {
  1199. INT iCurCol, iCurRow;
  1200. INT iMaxColumns;
  1201. BOOL fLastRow;
  1202. BOOL fNeedToScroll = FALSE;
  1203. HDC hdc;
  1204. HWND hwnd;
  1205. CheckLock(pwndSwitch);
  1206. UserAssert(IsWinEventNotifyDeferredOK());
  1207. iCurCol = pswInfo->iCurCol;
  1208. iCurRow = pswInfo->iCurRow;
  1209. /*
  1210. * Find out the new postion (row and column) of hilite.
  1211. */
  1212. if (fPrev) {
  1213. if (iCurCol > 0) {
  1214. /*
  1215. * Move cursor to prev column on the same row.
  1216. */
  1217. iCurCol--;
  1218. } else {
  1219. /*
  1220. * Try to move to the previous row.
  1221. */
  1222. if (iCurRow > 0) {
  1223. /*
  1224. * Move to the last column on the previous row.
  1225. */
  1226. iCurRow--;
  1227. iCurCol = pswInfo->iNoOfColumns - 1;
  1228. } else {
  1229. /*
  1230. * We are already at (0,0); See if we need to scroll.
  1231. */
  1232. if (pswInfo->fScroll) {
  1233. /*
  1234. * Time to scroll; Scroll by one Row;
  1235. * Repaint the whole window.
  1236. */
  1237. fNeedToScroll = TRUE;
  1238. pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
  1239. pswInfo->iNoOfColumns, FALSE);
  1240. iCurCol = pswInfo->iNoOfColumns - 1;
  1241. } else {
  1242. /*
  1243. * Move the hilite to the last icon shown.
  1244. */
  1245. iCurRow = pswInfo->iNoOfRows - 1;
  1246. iCurCol = pswInfo->iIconsInLastRow - 1;
  1247. }
  1248. }
  1249. }
  1250. } else {
  1251. /*
  1252. * !fPrev
  1253. * Get the number of columns in the current row.
  1254. */
  1255. if (fLastRow = (iCurRow == (pswInfo->iNoOfRows - 1))) // Are we at the last row?
  1256. iMaxColumns = pswInfo->iIconsInLastRow;
  1257. else
  1258. iMaxColumns = pswInfo->iNoOfColumns;
  1259. /*
  1260. * Are we at the last column yet?
  1261. */
  1262. if (iCurCol < (iMaxColumns - 1)) {
  1263. /*
  1264. * No! Move to the right.
  1265. */
  1266. iCurCol++;
  1267. } else {
  1268. /*
  1269. * We are at the last column.
  1270. * If we are not at last row, then move to next row.
  1271. */
  1272. if (!fLastRow) {
  1273. iCurCol = 0;
  1274. iCurRow++;
  1275. } else {
  1276. /*
  1277. * We are at the last row, last col;
  1278. * See if we need to scroll.
  1279. */
  1280. if (pswInfo->fScroll) {
  1281. fNeedToScroll = TRUE;
  1282. pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
  1283. pswInfo->iNoOfColumns, TRUE);
  1284. iCurCol = 0;
  1285. } else {
  1286. /*
  1287. * Move to the top left corner (0, 0).
  1288. */
  1289. iCurRow = iCurCol = 0;
  1290. }
  1291. }
  1292. }
  1293. }
  1294. /*
  1295. * Move the phwnd to the next/prev
  1296. */
  1297. pswInfo->phwndCurrent = NextPrevPhwnd(pswInfo, pswInfo->phwndCurrent, !fPrev);
  1298. /*
  1299. * Remove Hilite from the current location.
  1300. */
  1301. hdc = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE);
  1302. DrawSwitchWndHilite(pswInfo, hdc, pswInfo->iCurCol, pswInfo->iCurRow, FALSE);
  1303. pswInfo->iCurRow = iCurRow;
  1304. pswInfo->iCurCol = iCurCol;
  1305. hwnd = (*(pswInfo->phwndCurrent));
  1306. /*
  1307. * Repaint if needed.
  1308. */
  1309. if (fNeedToScroll)
  1310. xxxPaintIconsInSwitchWindow(pwndSwitch, pswInfo, hdc, pswInfo->iFirstTaskIndex, 0, 0, TRUE, !fPrev, NULL);
  1311. /*
  1312. * Draw Hilite at the new location.
  1313. */
  1314. DrawSwitchWndHilite(pswInfo, hdc, iCurCol, iCurRow, TRUE);
  1315. _ReleaseDC(hdc);
  1316. xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndSwitch, OBJID_CLIENT,
  1317. iCurRow * pswInfo->iNoOfColumns + iCurCol + 1, WEF_USEPWNDTHREAD);
  1318. return hwnd;
  1319. }
  1320. /***************************************************************************\
  1321. * xxxShowSwitchWindow()
  1322. *
  1323. * Show the switch Window.
  1324. * Returns: TRUE if succeeded. FALSE, if the window was not shown because
  1325. * of the pre-mature release of ALT key. The selection has been made already.
  1326. *
  1327. * History:
  1328. * 07-Jun-1995 BradG Ported from Win95
  1329. \***************************************************************************/
  1330. BOOL xxxShowSwitchWindow(
  1331. PWND pwndAltTab)
  1332. {
  1333. PSWINFO pswInfo;
  1334. PMONITOR pMonitorSwitch = GetPrimaryMonitor();
  1335. CheckLock(pwndAltTab);
  1336. UserAssert(IsWinEventNotifyDeferredOK());
  1337. /*
  1338. * Get the switch window information
  1339. */
  1340. pswInfo = Getpswi(pwndAltTab);
  1341. if (pswInfo == NULL) {
  1342. return FALSE;
  1343. }
  1344. /*
  1345. * If the key is not down, don't bother to display Switch Window.
  1346. */
  1347. if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
  1348. (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) {
  1349. #ifdef COOLSWITCHTRACE
  1350. DbgPrint("CoolSwitch: Not displaying window because VM_MENU is up (contact bradg).\n");
  1351. #endif
  1352. return FALSE;
  1353. }
  1354. /*
  1355. * Bring and position the window on top.
  1356. */
  1357. xxxSetWindowPos(pwndAltTab, PWND_TOPMOST, 0,0,0,0,
  1358. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW );
  1359. if (!TestWF(pwndAltTab, WFVISIBLE)) {
  1360. xxxSetWindowPos(
  1361. pwndAltTab,
  1362. PWND_TOPMOST,
  1363. (pMonitorSwitch->rcWork.left + pMonitorSwitch->rcWork.right - pswInfo->cxSwitch) / 2,
  1364. (pMonitorSwitch->rcWork.top + pMonitorSwitch->rcWork.bottom - pswInfo->cySwitch) / 2,
  1365. pswInfo->cxSwitch,
  1366. pswInfo->cySwitch,
  1367. SWP_SHOWWINDOW | SWP_NOACTIVATE);
  1368. }
  1369. #ifdef COOLSWITCHTRACE
  1370. UserAssert(TestWF(pwndAltTab, WFVISIBLE));
  1371. #endif
  1372. xxxUpdateWindow(pwndAltTab);
  1373. xxxWindowEvent(EVENT_SYSTEM_SWITCHSTART, pwndAltTab, OBJID_CLIENT,
  1374. 0, WEF_USEPWNDTHREAD);
  1375. xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndAltTab, OBJID_CLIENT,
  1376. pswInfo->iCurRow * pswInfo->iNoOfColumns + pswInfo->iCurCol + 1,
  1377. WEF_USEPWNDTHREAD);
  1378. return TRUE;
  1379. }
  1380. /***************************************************************************\
  1381. *
  1382. * xxxSwitchWndProc()
  1383. *
  1384. \***************************************************************************/
  1385. LRESULT xxxSwitchWndProc(
  1386. PWND pwnd,
  1387. UINT message,
  1388. WPARAM wParam,
  1389. LPARAM lParam)
  1390. {
  1391. TL tlpwndActivate;
  1392. PTHREADINFO ptiCurrent = PtiCurrent();
  1393. CheckLock(pwnd);
  1394. UserAssert(IsWinEventNotifyDeferredOK());
  1395. VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_SWITCH, WM_CREATE);
  1396. switch (message) {
  1397. case WM_CREATE:
  1398. /*
  1399. * When the queue was created, the cursor was set to the wait cursor.
  1400. * We want to use the normal one.
  1401. */
  1402. zzzSetCursor(pwnd->pcls->spcur);
  1403. break;
  1404. case WM_CLOSE:
  1405. /*
  1406. * Hide this window without activating anyone else.
  1407. */
  1408. xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW |
  1409. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
  1410. /*
  1411. * Get us out of Alt+Tab mode. Since the alttab information
  1412. * is stored in the gptiRit->pq, we will reference that insteatd
  1413. * of the current-thread.
  1414. */
  1415. xxxCancelCoolSwitch();
  1416. break;
  1417. case WM_ERASEBKGND:
  1418. case WM_FULLSCREEN:
  1419. ThreadLockWithPti(ptiCurrent, pwnd, &tlpwndActivate);
  1420. xxxPaintSwitchWindow(pwnd);
  1421. ThreadUnlock(&tlpwndActivate);
  1422. return 0;
  1423. case WM_DESTROY:
  1424. {
  1425. /*
  1426. * Get the switch window info for this window
  1427. */
  1428. PSWINFO pswCurrent = Getpswi(pwnd);
  1429. if (pswCurrent) {
  1430. RemoveSwitchWindowInfo(&pswCurrent);
  1431. Setpswi(pwnd, NULL);
  1432. }
  1433. }
  1434. break;
  1435. }
  1436. return xxxDefWindowProc(pwnd, message, wParam, lParam);
  1437. }
  1438. /***************************************************************************\
  1439. * xxxCancelCoolSwitch
  1440. *
  1441. * This functions destroys the cool switch window and removed the INALTTAB
  1442. * mode flag from the specified queue.
  1443. *
  1444. * History:
  1445. * 18-Sep-1995 BradG Created
  1446. \***************************************************************************/
  1447. VOID xxxCancelCoolSwitch(
  1448. void)
  1449. {
  1450. CheckCritIn();
  1451. UserAssert(IsWinEventNotifyDeferredOK());
  1452. /*
  1453. * Destroy the Cool Switch window
  1454. */
  1455. if (gspwndAltTab != NULL) {
  1456. PWND pwnd = gspwndAltTab;
  1457. /*
  1458. * Make sure that the thread calling this is the same thread which
  1459. * created the alttab window. Otherwise, we could end up with this
  1460. * window floating around until the calling process dies. Remember,
  1461. * we can't destroy windows across different threads.
  1462. */
  1463. if (gspwndAltTab->head.pti != PtiCurrent()) {
  1464. return;
  1465. }
  1466. xxxWindowEvent(EVENT_SYSTEM_SWITCHEND, gspwndAltTab, OBJID_CLIENT,
  1467. 0, WEF_USEPWNDTHREAD);
  1468. if (Unlock(&gspwndAltTab)) {
  1469. xxxDestroyWindow(pwnd);
  1470. }
  1471. }
  1472. }
  1473. /***************************************************************************\
  1474. * xxxNextWindow
  1475. *
  1476. * This function does the processing for the alt-tab/esc/F6 UI.
  1477. *
  1478. * History:
  1479. * 30-May-1991 DavidPe Created.
  1480. \***************************************************************************/
  1481. VOID xxxNextWindow(
  1482. PQ pq,
  1483. DWORD wParam)
  1484. {
  1485. PWND pwndActivateNext;
  1486. PWND pwndCurrentActivate, pwndCurrentTopFocus;
  1487. int fDir;
  1488. TL tlpwndCurrentTopFocus;
  1489. TL tlpwndActivateNext;
  1490. TL tlpwndCurrentActivate;
  1491. TL tlpwndT;
  1492. PSWINFO pswCurrent;
  1493. ULONG_PTR dwResult;
  1494. BOOL fNonRit = FALSE;
  1495. PTHREADINFO ptiCurrent = PtiCurrent();
  1496. UserAssert(!IsWinEventNotifyDeferred());
  1497. if (pq == NULL)
  1498. return;
  1499. fDir = (_GetAsyncKeyState(VK_SHIFT) < 0) ? FDIR_BACKWARD : FDIR_FORWARD;
  1500. pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus);
  1501. /*
  1502. * NOTE: As of NT 4.0 the slow Alt+Tab functionality now officially acts
  1503. * like Alt+Esc with the exception that Alt+Tab will activate the window
  1504. * where Alt+Esc will not.
  1505. */
  1506. switch (wParam) {
  1507. case VK_TAB:
  1508. if (gspwndAltTab == NULL) {
  1509. PWND pwndSwitch;
  1510. TL tlpSwitchInfo;
  1511. /*
  1512. * We are entering Alt+Tab for the first time, we need to
  1513. * initialize the Switch Window structure and if needed
  1514. * create and display the Alt+Tab window. We have two special
  1515. * cases: (1) The user does not want to use the Switch window,
  1516. * (2) The initialize switch window fails thus we will act
  1517. * just like slow Alt+Tab
  1518. */
  1519. /*
  1520. * Since Alt+Shift is the default hotkey for keyboard layout switching,
  1521. * Alt+Shift+Tab may cause a KL switching while AltTab window is up.
  1522. * To prevent it, we'd better reset the global toggle key state here,
  1523. * so that xxxScanSysQueue will not confuse when it handles keyup messages.
  1524. */
  1525. gLangToggleKeyState = KLT_NONE;
  1526. /*
  1527. * Mouse buttons sometimes get stuck down due to hardware glitches,
  1528. * usually due to input concentrator switchboxes or faulty serial
  1529. * mouse COM ports, so clear the global button state here just in case,
  1530. * otherwise we may not be able to change focus with the mouse.
  1531. * Also do this in zzzCancelJournalling (Ctr-Esc, Ctrl-Alt-Del, etc.)
  1532. */
  1533. #if DBG
  1534. if (gwMouseOwnerButton)
  1535. RIPMSG1(RIP_WARNING,
  1536. "gwMouseOwnerButton=%x, being forcibly cleared\n",
  1537. gwMouseOwnerButton);
  1538. #endif
  1539. gwMouseOwnerButton = 0;
  1540. /*
  1541. * Determine the current active window.
  1542. */
  1543. Lock(&gspwndActivate, pq->spwndActive);
  1544. if (gspwndActivate == NULL) {
  1545. Lock(&gspwndActivate, grpdeskRitInput->pDeskInfo->spwnd->spwndChild);
  1546. }
  1547. if (!gspwndActivate) {
  1548. return;
  1549. }
  1550. ThreadLockWithPti(ptiCurrent, pwndCurrentTopFocus, &tlpwndCurrentTopFocus);
  1551. /*
  1552. * Make a local copy of gspwndActivate and lock it because xxxFreeWindow will
  1553. * unlock if it is the window being freed.
  1554. */
  1555. pwndCurrentActivate = gspwndActivate;
  1556. ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
  1557. /*
  1558. * Cancel the active window's mode
  1559. */
  1560. xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
  1561. /*
  1562. * Initialize the Switch Window data structure, if we
  1563. * succeed create and display the window, otherwise act
  1564. * like slow Alt+Tab.
  1565. */
  1566. pwndActivateNext = InitSwitchWndInfo(&pswCurrent, pwndCurrentActivate, fDir);
  1567. ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
  1568. if (pswCurrent == NULL) {
  1569. /*
  1570. * Couldn't initialize our switch window data structure, so we
  1571. * will act like Alt+Esc.
  1572. */
  1573. goto DoSlowAltTab;
  1574. }
  1575. if (pwndActivateNext == NULL) {
  1576. RemoveSwitchWindowInfo(&pswCurrent);
  1577. ThreadUnlock(&tlpwndActivateNext);
  1578. ThreadUnlock(&tlpwndCurrentActivate);
  1579. ThreadUnlock(&tlpwndCurrentTopFocus);
  1580. Unlock(&gspwndActivate);
  1581. return;
  1582. }
  1583. ThreadLockPoolCleanup(ptiCurrent, &pswCurrent, &tlpSwitchInfo, RemoveSwitchWindowInfo);
  1584. /*
  1585. * Since we are in the RIT, test the physical state of the keyboard
  1586. */
  1587. pswCurrent->fJournaling = FALSE;
  1588. /*
  1589. * Create the Alt+Tab window
  1590. */
  1591. pwndSwitch =
  1592. xxxNVCreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME,
  1593. (PLARGE_STRING)SWITCHWNDCLASS, NULL,
  1594. WS_POPUP | WS_BORDER | WS_DISABLED,
  1595. 0, 0, 10, 10, NULL, NULL, NULL, NULL, VER40);
  1596. if (gspwndAltTab != NULL) {
  1597. RIPMSG0(RIP_WARNING, "xxxNextWindow: Creating a new switch window while one already exists.");
  1598. _PostMessage(gspwndAltTab, WM_CLOSE, 0, 0);
  1599. }
  1600. Lock(&gspwndAltTab, pwndSwitch);
  1601. ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
  1602. if (gspwndAltTab == NULL) {
  1603. /*
  1604. * Could not create the cool switch window, do the Alt+Esc thing
  1605. */
  1606. #ifdef COOLSWITCHTRACE
  1607. DbgPrint("CoolSwitch: Could not create window (contact bradg).\n");
  1608. UserAssert(gspwndAltTab != NULL);
  1609. #endif
  1610. RemoveSwitchWindowInfo(&pswCurrent);
  1611. goto DoSlowAltTab;
  1612. }
  1613. /*
  1614. * Save the pointer to the switch window info structure
  1615. */
  1616. Setpswi(gspwndAltTab, pswCurrent);
  1617. /*
  1618. * Set gspwndActivate so the RIT knows what window we would like
  1619. * it to activate.
  1620. */
  1621. Lock(&gspwndActivate, pwndActivateNext);
  1622. /*
  1623. * Make sure that our rit queue has the correct pdesk
  1624. */
  1625. if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) {
  1626. xxxSetThreadDesktop(NULL, grpdeskRitInput); // DeferWinEventNotify() ?? IANJA ??
  1627. }
  1628. /*
  1629. * If we're currently full screen tell console to switch to
  1630. * the desktop to GDI mode; we can't do this on the RIT because
  1631. * it can be slow.
  1632. */
  1633. if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) {
  1634. ThreadLockWithPti(ptiCurrent, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
  1635. xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd));
  1636. ThreadUnlock(&tlpwndT);
  1637. }
  1638. /*
  1639. * Show the Alt+Tab window. If it returns FALSE this means
  1640. * the ALT key has been released, so there is no need to
  1641. * paint the icons.
  1642. */
  1643. ThreadLockAlwaysWithPti(ptiCurrent, gspwndAltTab, &tlpwndT);
  1644. xxxShowSwitchWindow(gspwndAltTab);
  1645. ThreadUnlock(&tlpwndT);
  1646. /*
  1647. * Exit now because the Switch window will have been
  1648. * already updated.
  1649. */
  1650. ThreadUnlock(&tlpwndActivateNext);
  1651. ThreadUnlock(&tlpwndCurrentActivate);
  1652. ThreadUnlock(&tlpwndCurrentTopFocus);
  1653. } else {
  1654. /*
  1655. * We come here to do the actual switching and/or updating of
  1656. * the switch window when in Alt+Tab mode.
  1657. */
  1658. PWND pwndSwitch;
  1659. TL tlpwndSwitch;
  1660. HWND hwndActivateNext;
  1661. HWND hwndStop;
  1662. if (!(pwndSwitch = gspwndAltTab)) {
  1663. goto DoAltEsc;
  1664. } else {
  1665. /*
  1666. * Move the hilight rect to the next/prev task. It is possible
  1667. * that some tasks were destoryed, so we need to skip those.
  1668. */
  1669. ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
  1670. hwndStop = NULL;
  1671. do {
  1672. pswCurrent = Getpswi(pwndSwitch);
  1673. if (pswCurrent == NULL) {
  1674. ThreadUnlock(&tlpwndSwitch);
  1675. goto DoAltEsc;
  1676. }
  1677. hwndActivateNext = xxxMoveSwitchWndHilite(pwndSwitch, pswCurrent, fDir);
  1678. if (!hwndStop) {
  1679. hwndStop = hwndActivateNext;
  1680. } else {
  1681. if (hwndStop == hwndActivateNext) {
  1682. pwndActivateNext = NULL;
  1683. break;
  1684. }
  1685. }
  1686. pwndActivateNext = RevalidateHwnd(hwndActivateNext);
  1687. } while (!pwndActivateNext);
  1688. ThreadUnlock(&tlpwndSwitch);
  1689. Lock(&gspwndActivate, pwndActivateNext);
  1690. if (!gspwndActivate) {
  1691. /*
  1692. * No Window to activate, bail out of Alt+Tab mode
  1693. */
  1694. xxxCancelCoolSwitch();
  1695. }
  1696. }
  1697. }
  1698. break;
  1699. DoAltEsc:
  1700. case VK_ESCAPE:
  1701. /*
  1702. * NOTE: The RIT doesn't use gspwndActivate to activate the window when
  1703. * processing Alt+Esc, we just use it here as a convenient
  1704. * variable. The actual activation takes place below.
  1705. */
  1706. pwndCurrentActivate = pq->spwndActive;
  1707. if (pwndCurrentActivate == NULL) {
  1708. pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild;
  1709. if (pwndCurrentActivate == NULL) {
  1710. return;
  1711. }
  1712. }
  1713. ThreadLockWithPti(ptiCurrent, pwndCurrentTopFocus, &tlpwndCurrentTopFocus);
  1714. ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
  1715. /*
  1716. * Cancel the active window's mode
  1717. */
  1718. xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
  1719. /*
  1720. * Determine the next window to activate
  1721. */
  1722. pwndActivateNext = _GetNextQueueWindow(pwndCurrentActivate, fDir, TRUE);
  1723. ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
  1724. /*
  1725. * If we're going forward through the windows, move the currently
  1726. * active window to the bottom so we'll do the right thing when
  1727. * we go backwards.
  1728. */
  1729. if (pwndActivateNext != pwndCurrentActivate) {
  1730. DoSlowAltTab:
  1731. if (pwndActivateNext) {
  1732. /*
  1733. * We're about to activate another window while the ALT key is down,
  1734. * so let the current focus window know that it doesn't need the
  1735. * menu underlines anymore
  1736. */
  1737. if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) {
  1738. ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE);
  1739. }
  1740. if (fDir == FDIR_FORWARD) {
  1741. /*
  1742. * For Alt+ESC only move the window to the bottom if it's
  1743. * not a top most window
  1744. */
  1745. if (!TestWF(pwndCurrentActivate, WEFTOPMOST)) {
  1746. xxxSetWindowPos(pwndCurrentActivate, PWND_BOTTOM, 0, 0, 0, 0,
  1747. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
  1748. SWP_DEFERDRAWING | SWP_NOSENDCHANGING |
  1749. SWP_ASYNCWINDOWPOS);
  1750. }
  1751. }
  1752. /*
  1753. * The ALT key is down, so this window needs menu underlines
  1754. */
  1755. if (pwndActivateNext->spmenu != NULL) {
  1756. SetMF(pwndActivateNext->spmenu, MFUNDERLINE);
  1757. }
  1758. /*
  1759. * This little ugly hack will cause xxxSetForegroundWindow2()
  1760. * to send out an activation messages to a queue that is
  1761. * already the active queue allowing us to change the active
  1762. * window on that queue.
  1763. */
  1764. if (gpqForeground == GETPTI(pwndActivateNext)->pq)
  1765. gpqForeground = NULL;
  1766. /*
  1767. * Make the selected window thread the owner of the last input;
  1768. * since he's next, he owns the ALT-ESC.
  1769. */
  1770. glinp.ptiLastWoken = GETPTI(pwndActivateNext);
  1771. xxxSetForegroundWindow2(pwndActivateNext, NULL,
  1772. (wParam == VK_TAB) ? SFW_SWITCH | SFW_ACTIVATERESTORE : SFW_SWITCH);
  1773. /*
  1774. * Win3.1 calls SetWindowPos() with activate, which z-orders
  1775. * first regardless, then activates. Our code relies on
  1776. * xxxActivateThisWindow() to z-order, and it'll only do
  1777. * it if the window does not have the child bit set (regardless
  1778. * that the window is a child of the desktop).
  1779. *
  1780. * To be compatible, we'll just force z-order here if the
  1781. * window has the child bit set. This z-order is asynchronous,
  1782. * so this'll z-order after the activate event is processed.
  1783. * That'll allow it to come on top because it'll be foreground
  1784. * then. (Grammatik has a top level window with the child
  1785. * bit set that wants to be come the active window).
  1786. */
  1787. if (wParam == VK_TAB && TestWF(pwndActivateNext, WFCHILD)) {
  1788. xxxSetWindowPos(pwndActivateNext, (PWND)HWND_TOP, 0, 0, 0, 0,
  1789. SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS);
  1790. }
  1791. }
  1792. }
  1793. ThreadUnlock(&tlpwndActivateNext);
  1794. ThreadUnlock(&tlpwndCurrentActivate);
  1795. ThreadUnlock(&tlpwndCurrentTopFocus);
  1796. break;
  1797. case VK_F6:
  1798. if ((pwndCurrentActivate = pq->spwndActive) == NULL)
  1799. pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild;
  1800. pwndActivateNext = pwndCurrentActivate;
  1801. /*
  1802. * HACK! console sessions are all one thread but we want them
  1803. * to act like different threads so if its a console thread (csrss.exe)
  1804. * then ALT-F6 does nothing just like in Win 3.1
  1805. * Note: we never get called with wParam == VK_F6 anyway. Win NT 3.51
  1806. * doesn't seem to either, but Windows '95 does. BUG?? (IanJa)
  1807. */
  1808. if (!(GETPTI(pwndActivateNext)->TIF_flags & TIF_CSRSSTHREAD)) {
  1809. /*
  1810. * on a alt-f6, we want to keep the switch within the thread.
  1811. * We may want to rethink this because this will look strange
  1812. * when you alt-f6 on a multi-threaded app we will not rotate
  1813. * through the windows on the different threads. This works
  1814. * fine on Win 3.x because it is single threaded.
  1815. */
  1816. do {
  1817. pwndActivateNext = NextTopWindow(pq->ptiKeyboard, pwndActivateNext, NULL,
  1818. fDir ? NTW_PREVIOUS : 0);
  1819. } while( (pwndActivateNext != NULL) &&
  1820. (GETPTI(pwndActivateNext) != pq->ptiKeyboard));
  1821. if (pwndActivateNext != NULL) {
  1822. if (pwndActivateNext != pwndCurrentActivate) {
  1823. /*
  1824. * We're about to activate another window while the ALT key is down,
  1825. * so let the current focus window know that it doesn't need the
  1826. * menu underlines anymore
  1827. */
  1828. pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus);
  1829. if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) {
  1830. ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE);
  1831. }
  1832. /*
  1833. * The ALT key is down, so this window needs menu underlines
  1834. */
  1835. if (pwndActivateNext->spmenu != NULL) {
  1836. SetMF(pwndActivateNext->spmenu, MFUNDERLINE);
  1837. }
  1838. }
  1839. ThreadLockAlwaysWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
  1840. xxxSetWindowPos(pwndActivateNext, PWND_BOTTOM, 0, 0, 0, 0,
  1841. SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_NOCHANGE |
  1842. SWP_ASYNCWINDOWPOS);
  1843. xxxSetForegroundWindow2(pwndActivateNext, NULL, SFW_SWITCH);
  1844. ThreadUnlock(&tlpwndActivateNext);
  1845. }
  1846. }
  1847. break;
  1848. }
  1849. }
  1850. /***************************************************************************\
  1851. * xxxOldNextWindow
  1852. *
  1853. * This function does the processing for the alt-tab/esc/F6 UI.
  1854. *
  1855. * History:
  1856. * 03-17-92 DavidPe Ported from Win 3.1 sources
  1857. \***************************************************************************/
  1858. VOID xxxOldNextWindow(
  1859. UINT flags)
  1860. {
  1861. MSG msg;
  1862. HWND hwndSel;
  1863. PWND pwndNewSel;
  1864. PWND pwndSel;
  1865. BOOL fType = 0;
  1866. BOOL fDrawIcon;
  1867. WORD vk;
  1868. TL tlpwndT;
  1869. TL tlpwndSel;
  1870. TL tlpwndSwitch;
  1871. PSWINFO pswCurrent;
  1872. PWND pwndSwitch;
  1873. HWND hwndStop;
  1874. HWND hwndNewSel;
  1875. PTHREADINFO ptiCurrent = PtiCurrent();
  1876. /*
  1877. * Don't allow entering this routine when we're already in the AltTab
  1878. * mode. The AltTab window may have been created via xxxNextWindow.
  1879. */
  1880. if (gspwndAltTab != NULL) {
  1881. return;
  1882. }
  1883. if ((pwndSel = ptiCurrent->pq->spwndActive) == NULL)
  1884. return;
  1885. ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndSel);
  1886. xxxCapture(ptiCurrent, pwndSel, SCREEN_CAPTURE);
  1887. vk = (WORD)flags;
  1888. msg.wParam = (UINT)flags;
  1889. pwndNewSel = NULL;
  1890. if (vk == VK_TAB) {
  1891. TL tlpSwitchInfo;
  1892. /*
  1893. * Initialize the Switch window data structures
  1894. */
  1895. pwndNewSel = InitSwitchWndInfo(&pswCurrent,
  1896. pwndSel,
  1897. _GetKeyState(VK_SHIFT) < 0);
  1898. if (pswCurrent == NULL) {
  1899. /*
  1900. * We were unable to initialize the data structure used by
  1901. * the Switch window, so we will act like Alt+Esc.
  1902. */
  1903. } else {
  1904. PWND pwndSwitch;
  1905. /*
  1906. * We are doing a journal playback do use _GetKeyState to
  1907. * test the keyboard.
  1908. */
  1909. pswCurrent->fJournaling = TRUE;
  1910. ThreadLockPoolCleanup(ptiCurrent, &pswCurrent, &tlpSwitchInfo, RemoveSwitchWindowInfo);
  1911. pwndSwitch =
  1912. xxxNVCreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME,
  1913. (PLARGE_STRING)SWITCHWNDCLASS,
  1914. NULL,
  1915. WS_POPUP | WS_BORDER | WS_DISABLED,
  1916. 0,
  1917. 0,
  1918. 10,
  1919. 10,
  1920. NULL,
  1921. NULL,
  1922. NULL,
  1923. NULL,
  1924. VER40);
  1925. if (gspwndAltTab != NULL) {
  1926. RIPMSGF0(RIP_WARNING,
  1927. "Creating a new switch window while one already exists.");
  1928. _PostMessage(gspwndAltTab, WM_CLOSE, 0, 0);
  1929. }
  1930. ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
  1931. Lock(&gspwndAltTab, pwndSwitch);
  1932. if (!(pwndSwitch = gspwndAltTab)) {
  1933. RemoveSwitchWindowInfo(&pswCurrent);
  1934. } else {
  1935. /*
  1936. * Lock the switch window.
  1937. */
  1938. ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
  1939. /*
  1940. * Save the switch window info
  1941. */
  1942. Setpswi(pwndSwitch, pswCurrent);
  1943. // Don't we need to switch from full screen mode if needed?
  1944. #if 0
  1945. /*
  1946. * If we're currently full screen tell console to switch to
  1947. * the desktop to GDI mode; we can't do this on the RIT because
  1948. * it can be slow.
  1949. */
  1950. if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) {
  1951. ThreadLockWithPti(pti, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
  1952. xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LONG)HW(grpdeskRitInput->pDeskInfo->spwnd));
  1953. ThreadUnlock(&tlpwndT);
  1954. }
  1955. #endif
  1956. /*
  1957. * Show the switch window, this also will paint the window
  1958. */
  1959. xxxShowSwitchWindow(gspwndAltTab);
  1960. ThreadUnlock(&tlpwndSwitch);
  1961. }
  1962. }
  1963. }
  1964. if (!pwndNewSel)
  1965. goto StartTab;
  1966. pwndSel = pwndNewSel;
  1967. while (TRUE) {
  1968. hwndSel = PtoH(pwndSel);
  1969. /*
  1970. * Wait for a message without getting it out of the queue.
  1971. */
  1972. while (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD))
  1973. xxxWaitMessage();
  1974. if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
  1975. pwndSel = ptiCurrent->pq->spwndActive;
  1976. if (_CallMsgFilter(&msg, MSGF_NEXTWINDOW)) {
  1977. /*
  1978. * Swallow the message if the hook processed it
  1979. */
  1980. xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  1981. continue;
  1982. }
  1983. /*
  1984. * If we are doing Alt+Tab and some other key comes in (other than
  1985. * tab, escape or shift), then bomb out of this loop and leave that
  1986. * key in the queue.
  1987. */
  1988. if ((msg.message == WM_SYSKEYDOWN) && gspwndAltTab != NULL) {
  1989. vk = (WORD)msg.wParam;
  1990. if ((vk != VK_TAB) && (vk != VK_ESCAPE) && (vk != VK_SHIFT)) {
  1991. pwndSel = ptiCurrent->pq->spwndActive;
  1992. fType = 0;
  1993. goto Exit;
  1994. }
  1995. }
  1996. switch (msg.message) {
  1997. case WM_CANCELJOURNAL:
  1998. /*
  1999. * If journalling was canceled we need to exit our loop and
  2000. * remove the Alt+Tab window. We don't want to remove this
  2001. * meesage because we want the app to know that journalling
  2002. * was canceled.
  2003. */
  2004. /* > > > F A L L T H R O U G H < < < */
  2005. case WM_HOTKEY:
  2006. /*
  2007. * When pressing ALT-CTL-ESC-DEL on the logon desktop
  2008. * We eat WM_KEYUP and the queue for the wiinlogon thread will be empty so will be stuck
  2009. * in xxxWaitMessage() forever till the user do a mouse click where we will exit the loop in the below case statement.
  2010. * consider WM_HOTKEY as a valid exit case.
  2011. * [msadek -- 03/17/2001, bug# 337206]
  2012. */
  2013. /* > > > F A L L T H R O U G H < < < */
  2014. case WM_LBUTTONDOWN:
  2015. case WM_LBUTTONUP:
  2016. case WM_RBUTTONDOWN:
  2017. case WM_RBUTTONUP:
  2018. case WM_MBUTTONDOWN:
  2019. case WM_MBUTTONUP:
  2020. case WM_XBUTTONDOWN:
  2021. case WM_XBUTTONUP:
  2022. /*
  2023. * If mouse message, cancel and get out of loop.
  2024. */
  2025. pwndSel = ptiCurrent->pq->spwndActive;
  2026. fType = 0;
  2027. goto Exit;
  2028. case WM_KEYUP:
  2029. case WM_KEYDOWN:
  2030. case WM_SYSCHAR:
  2031. case WM_SYSKEYUP:
  2032. case WM_MOUSEMOVE:
  2033. /*
  2034. * Swallow the message
  2035. */
  2036. hwndSel = PtoH(pwndSel);
  2037. xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  2038. if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
  2039. pwndSel = ptiCurrent->pq->spwndActive;
  2040. if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) {
  2041. vk = (WORD)msg.wParam;
  2042. /*
  2043. * If alt-tab up, then exit.
  2044. */
  2045. if (vk == VK_MENU) {
  2046. /*
  2047. * If doing Alt+Esc, wait for up of ESC to get out.
  2048. */
  2049. if (gspwndAltTab == NULL)
  2050. break;
  2051. fType = 0;
  2052. goto Exit;
  2053. } else if (vk == VK_ESCAPE || vk == VK_F6) {
  2054. /*
  2055. * Get out on up transition of ESC or F6 keys.
  2056. */
  2057. if (gspwndAltTab != NULL) {
  2058. pwndSel = ptiCurrent->pq->spwndActive;
  2059. fType = 0;
  2060. } else {
  2061. fType = ((vk == VK_ESCAPE) ? ALT_ESCAPE : ALT_F6);
  2062. }
  2063. goto Exit;
  2064. }
  2065. } else if (msg.message == WM_KEYDOWN) {
  2066. /*
  2067. * Exit out loop is a stray key stroke comes through. In
  2068. * particular look for VK_CONTROL.
  2069. */
  2070. pwndSel = ptiCurrent->pq->spwndActive;
  2071. fType = 0;
  2072. goto Exit;
  2073. }
  2074. break;
  2075. case WM_SYSKEYDOWN:
  2076. vk = (WORD)msg.wParam;
  2077. switch (vk) {
  2078. case VK_SHIFT:
  2079. case VK_TAB:
  2080. case VK_ESCAPE:
  2081. case VK_F6:
  2082. hwndSel = PtoH(pwndSel);
  2083. xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  2084. if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
  2085. pwndSel = ptiCurrent->pq->spwndActive;
  2086. if (!(vk == VK_TAB))
  2087. break;
  2088. StartTab:
  2089. if (vk == VK_ESCAPE) {
  2090. pwndNewSel = _GetNextQueueWindow(
  2091. pwndSel,
  2092. _GetKeyState(VK_SHIFT) < 0,
  2093. TRUE);
  2094. if (pwndNewSel == NULL)
  2095. break;
  2096. fType = ALT_ESCAPE;
  2097. pwndSel = pwndNewSel;
  2098. /*
  2099. * Wait until ESC goes up to activate new window.
  2100. */
  2101. break;
  2102. }
  2103. if (vk == VK_F6) {
  2104. PWND pwndFirst;
  2105. PWND pwndSaveSel = pwndSel;
  2106. /*
  2107. * Save the first returned window to act as a limit
  2108. * to the search because NextTopWindow will return NULL
  2109. * only if pwndSel is the only window that meets its
  2110. * selection criteria.
  2111. *
  2112. * This prevents a hang that can occur in winword or
  2113. * excel when then Alt-F4-F6 key combination is hit
  2114. * and unsaved changes exist.
  2115. */
  2116. pwndFirst = pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL,
  2117. _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
  2118. while (TRUE) {
  2119. /*
  2120. * If pwndNewSel is NULL, pwndSel is the only candidate.
  2121. */
  2122. if (pwndNewSel == NULL)
  2123. break;
  2124. pwndSel = pwndNewSel;
  2125. /*
  2126. * If the window is on the same thread, wait until
  2127. * F6 goes up to activate new window.
  2128. */
  2129. if (GETPTI(pwndSel) == ptiCurrent)
  2130. break;
  2131. pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL,
  2132. _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
  2133. /*
  2134. * If we've looped around, use the original window.
  2135. * Wait until F6 goes up to activate new window.
  2136. */
  2137. if (pwndNewSel == pwndFirst) {
  2138. pwndSel = pwndSaveSel;
  2139. break;
  2140. }
  2141. }
  2142. break;
  2143. }
  2144. /*
  2145. * Here for the Alt+Tab case
  2146. */
  2147. if ((pwndSwitch = gspwndAltTab) != NULL) {
  2148. ThreadLockWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
  2149. hwndStop = NULL;
  2150. do {
  2151. pswCurrent = Getpswi(pwndSwitch);
  2152. if (pswCurrent == NULL) {
  2153. break;
  2154. }
  2155. hwndNewSel = xxxMoveSwitchWndHilite(
  2156. pwndSwitch,
  2157. pswCurrent,
  2158. _GetKeyState(VK_SHIFT) < 0);
  2159. if (!hwndStop) {
  2160. hwndStop = hwndNewSel;
  2161. } else {
  2162. if (hwndStop == hwndNewSel) {
  2163. pwndNewSel = NULL;
  2164. break;
  2165. }
  2166. }
  2167. pwndNewSel = RevalidateHwnd(hwndNewSel);
  2168. } while (!pwndNewSel);
  2169. ThreadUnlock(&tlpwndSwitch);
  2170. pwndSel = pwndNewSel;
  2171. } else {
  2172. pwndNewSel = _GetNextQueueWindow(
  2173. pwndSel,
  2174. _GetKeyState(VK_SHIFT) < 0,
  2175. FALSE);
  2176. if (pwndNewSel && pwndNewSel != pwndSel) {
  2177. if (!TestWF(pwndSel, WEFTOPMOST)) {
  2178. /*
  2179. * Force the old window to the bottom
  2180. */
  2181. ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT);
  2182. xxxSetWindowPos(pwndSel,
  2183. PWND_BOTTOM,
  2184. 0,
  2185. 0,
  2186. 0,
  2187. 0,
  2188. SWP_NOMOVE |
  2189. SWP_NOSIZE |
  2190. SWP_NOACTIVATE |
  2191. SWP_DEFERDRAWING |
  2192. SWP_NOSENDCHANGING |
  2193. SWP_ASYNCWINDOWPOS);
  2194. ThreadUnlock(&tlpwndT);
  2195. }
  2196. pwndSel = pwndNewSel; // Will be revalidated at top of loop
  2197. }
  2198. }
  2199. break;
  2200. default:
  2201. goto Exit;
  2202. }
  2203. break;
  2204. default:
  2205. hwndSel = PtoH(pwndSel);
  2206. xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
  2207. xxxTranslateMessage(&msg, 0);
  2208. xxxDispatchMessage(&msg);
  2209. if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
  2210. pwndSel = ptiCurrent->pq->spwndActive;
  2211. break;
  2212. }
  2213. }
  2214. Exit:
  2215. xxxReleaseCapture();
  2216. fDrawIcon = (gspwndAltTab != NULL);
  2217. /*
  2218. * If this is an Alt-Escape we also have to send the current window
  2219. * to the bottom.
  2220. */
  2221. if (fType == ALT_ESCAPE) {
  2222. PWND pwndActive;
  2223. if (gpqForeground) {
  2224. pwndActive = gpqForeground->spwndActive;
  2225. if (pwndActive && (pwndActive != pwndSel)) {
  2226. ThreadLockWithPti(ptiCurrent, pwndActive, &tlpwndT);
  2227. xxxSetWindowPos(pwndActive,
  2228. PWND_BOTTOM,
  2229. 0,
  2230. 0,
  2231. 0,
  2232. 0,
  2233. SWP_NOMOVE |
  2234. SWP_NOSIZE |
  2235. SWP_NOACTIVATE |
  2236. SWP_DEFERDRAWING |
  2237. SWP_NOSENDCHANGING |
  2238. SWP_ASYNCWINDOWPOS);
  2239. ThreadUnlock(&tlpwndT);
  2240. }
  2241. }
  2242. }
  2243. if (pwndSel) {
  2244. ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT);
  2245. xxxSetForegroundWindow(pwndSel, FALSE);
  2246. if (TestWF(pwndSel, WFMINIMIZED)) {
  2247. if ((fType == 0) && fDrawIcon)
  2248. _PostMessage(pwndSel, WM_SYSCOMMAND, (UINT)SC_RESTORE, 0);
  2249. }
  2250. ThreadUnlock(&tlpwndT);
  2251. }
  2252. /*
  2253. * destroy the alt-tab window
  2254. */
  2255. xxxCancelCoolSwitch();
  2256. ThreadUnlock(&tlpwndSel);
  2257. }
  2258. /*****************************************************************************\
  2259. *
  2260. * GetAltTabInfo() - Active Accessibility API for OLEACC
  2261. *
  2262. * This succeeds if we are currently in alt-tab mode.
  2263. *
  2264. \*****************************************************************************/
  2265. BOOL WINAPI
  2266. _GetAltTabInfo(
  2267. int iItem,
  2268. PALTTABINFO pati,
  2269. LPWSTR ccxpwszItemText,
  2270. UINT cchItemText OPTIONAL,
  2271. BOOL bAnsi)
  2272. {
  2273. PSWINFO pswCurrent;
  2274. if (!gspwndAltTab || ((pswCurrent = Getpswi(gspwndAltTab)) == NULL)) {
  2275. RIPERR0(ERROR_NOT_FOUND, RIP_WARNING, "no Alt-Tab window");
  2276. return FALSE;
  2277. }
  2278. /*
  2279. * Fill in general information
  2280. */
  2281. pati->cItems = pswCurrent->iTotalTasks;
  2282. pati->cColumns = pswCurrent->iNoOfColumns;
  2283. pati->cRows = pswCurrent->iNoOfRows;
  2284. pati->iColFocus = pswCurrent->iCurCol;
  2285. pati->iRowFocus = pswCurrent->iCurRow;
  2286. pati->cxItem = CXICONSLOT;
  2287. pati->cyItem = CYICONSLOT;
  2288. pati->ptStart = pswCurrent->ptFirstRowStart;
  2289. /*
  2290. * Fill in specific information if asked.
  2291. */
  2292. if (cchItemText && (iItem >= 0)) {
  2293. PWND pwndCur;
  2294. pwndCur = NULL;
  2295. try {
  2296. if ((iItem < pswCurrent->iTotalTasks) &&
  2297. (pwndCur = RevalidateHwnd(pswCurrent->pbwl->rghwnd[iItem]))) {
  2298. if (bAnsi) {
  2299. LPSTR ccxpszItemText = (LPSTR)ccxpwszItemText;
  2300. ULONG cch;
  2301. RtlUnicodeToMultiByteN(ccxpszItemText, cchItemText - 1,
  2302. &cch, pwndCur->strName.Buffer, pwndCur->strName.Length);
  2303. ccxpszItemText[cch] = '\0';
  2304. } else {
  2305. TextCopy(&pwndCur->strName, ccxpwszItemText, cchItemText);
  2306. }
  2307. } else {
  2308. // no such item
  2309. NullTerminateString(ccxpwszItemText, bAnsi);
  2310. }
  2311. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  2312. return FALSE;
  2313. }
  2314. }
  2315. return TRUE;
  2316. }