|
|
/****************************** Module Header ******************************\
* Module Name: tmswitch.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * History: * 29-May-1991 DavidPe Created. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* COOLSWITCHTRACE is used to trace problems * in the CoolSwitch window */ #undef COOLSWITCHTRACE
#define ALT_F6 2
#define ALT_ESCAPE 1
#define FDIR_FORWARD 0
#define FDIR_BACKWARD 1
/*
* Win95 hard codes the size of the icon matrix, the size of * the icons, the highlight border and the icon spacing */ #define CXICONSLOT 43
#define CYICONSLOT 43
#define CXICONSIZE 32
#define CYICONSIZE 32
/*
* Pointer to the start of the SwitchInfo list. */ PSWINFO gpswiFirst;
VOID xxxPaintIconsInSwitchWindow(PWND, PSWINFO, HDC, INT, INT, INT, BOOL, BOOL, PICON);
/***************************************************************************\
* Getpswi * * 04-29-96 GerardoB Created \***************************************************************************/ __inline PSWINFO Getpswi( PWND pwnd) { UserAssert(GETFNID(pwnd) == FNID_SWITCH); return TestWF(pwnd, WFDESTROYED) ? NULL : ((PSWITCHWND)pwnd)->pswi; }
/***************************************************************************\
* Setpswi * * 04-29-96 GerardoB Created \***************************************************************************/ __inline VOID Setpswi( PWND pwnd, PSWINFO pswi) { UserAssert(GETFNID(pwnd) == FNID_SWITCH); ((PSWITCHWND)pwnd)->pswi = pswi; }
/***************************************************************************\
* DSW_GetTopLevelCreatorWindow \***************************************************************************/ PWND DSW_GetTopLevelCreatorWindow( PWND pwnd) { UserAssert(pwnd != NULL);
if (pwnd != NULL) { while (pwnd->spwndOwner) { pwnd = pwnd->spwndOwner; } }
return pwnd; }
/***************************************************************************\
* GetNextQueueWindow * * This routine is used to implement the Alt+Esc feature. This feature lets * the user switch between windows for different applications (a.k.a. "Tasks") * currently running. We keep track of the most recently active window in * each task. This routine starts with the window passed and searches for the * next window, in the "top-level" window list, that is from a different task * than the one passed. We then return the most recenly active window from * that task (or the window we found if the most recently active has been * destroyed or is currently disabled or hidden). This routine returns NULL * if no other enabled, visible window for another task can be found. * * History: * 30-May-1991 DavidPe Ported from Win 3.1 sources. \***************************************************************************/ PWND _GetNextQueueWindow( PWND pwnd, BOOL fPrev, /* 1 backward 0 forward */ BOOL fAltEsc) { PWND pwndAltTab; PWND pwndNext; PWND pwndT; PWND pwndDesktop; BOOL bBeenHereAlready = FALSE;
/*
* If the window we receive is Null then use the last topmost window */ if (!pwnd) { pwnd = GetLastTopMostWindow(); if (!pwnd) { return NULL; } }
pwndAltTab = gspwndAltTab;
pwnd = pwndNext = GetTopLevelWindow(pwnd); if (!pwndNext) { return NULL; }
/*
* Get the window's desktop */ if ((pwndDesktop = pwndNext->spwndParent) == NULL) { pwndDesktop = grpdeskRitInput->pDeskInfo->spwnd; pwnd = pwndNext = pwndDesktop->spwndChild; }
while (TRUE) {
if (pwndNext == NULL) return NULL;
/*
* Get the next window */ pwndNext = _GetWindow(pwndNext, fPrev ? GW_HWNDPREV : GW_HWNDNEXT);
if (!pwndNext) {
pwndNext = fPrev ? _GetWindow(pwndDesktop->spwndChild, GW_HWNDLAST) : pwndDesktop->spwndChild; /*
* To avoid searching the child chain forever, bale out if we get * to the end (beginning) of the chain twice. * This happens if pwnd is a partially destroyed window that has * been unlinked from its siblings but not yet unlinked from the * parent. (Happens while sending WM_NCDESTROY in xxxFreeWindow) */ if (bBeenHereAlready) { RIPMSG1(RIP_WARNING, "pwnd %#p is no longer a sibling", pwnd); return NULL; }
bBeenHereAlready = TRUE; }
/*
* If we have gone all the way around with no success, return NULL. */ if (!pwndNext || (pwndNext == pwnd)) return NULL;
/*
* Ignore the following windows: * Switch window * Tool Windows * NoActivate Windows * Hidden windows * Disabled windows * Topmost windows if via Alt+Esc * Bottommost windows if via Alt+Esc * * If we're doing Alt-Esc processing, we have to skip topmost windows. * * Because topmost windows don't really go to the back when we * send them there, alt-esc would never enumerate non-topmost windows. * So, although we're allowed to start enumeration at a topmost window, * we only allow enumeration of non-topmost windows, so the user can * enumerate his presumably more important applications. */ if ((pwndNext != pwndAltTab) && // BradG - Win95 is missing the check for Tool Windows
(!TestWF(pwndNext, WEFTOOLWINDOW)) && (!TestWF(pwndNext, WEFNOACTIVATE)) && (TestWF(pwndNext, WFVISIBLE)) && ((pwndNext->spwndLastActive == NULL) || (!TestWF(pwndNext->spwndLastActive, WFDISABLED)) && (!fAltEsc || (!TestWF(pwndNext, WEFTOPMOST) && !TestWF(pwndNext, WFBOTTOMMOST))))) { /*
* If this window is owned, don't return it unless it is the most * recently active window in its owner/ownee group. */ /*
* Hard loop to find top level owner */ for (pwndT = pwndNext; pwndT->spwndOwner; pwndT = pwndT->spwndOwner) ;
/*
* Don't return it unless it is the most recently active * window in its owner/ownee group. */ if (pwndNext == pwndT->spwndLastActive) return pwndNext; } } }
/***************************************************************************\
* * SwitchToThisWindow() * * This function was added specifically for Win386. It is called to tell * USER that a particular window has been switched to via Alt+Tab or * Alt+Esc in the Win386 environment. They call this function to maintain * Z-ordering and consistent operation of these two functions. This function * must be exported, but need not be documented. * * The parameter fTab is TRUE if this window is to be switched to via an * Alt/Ctl+Tab key sequence otherwise it must be FALSE. * * History: * 04-Feb-1991 DarrinM Created. \***************************************************************************/
VOID xxxSwitchToThisWindow( PWND pwnd, BOOL fAltTab) { CheckLock(pwnd);
/*
* If we need to, push old window to the bottom. */ if (gpqForeground && !fAltTab) {
BOOL fPush; PWND pwndActive; TL tlpwndActive;
/*
* if ALT-ESC, and the window brought forward is the next one in the * list, we must be rotating the zorder forward, so push the current * window to the back */ pwndActive = gpqForeground->spwndActive; fPush = pwndActive && _GetNextQueueWindow(pwndActive, FDIR_FORWARD, !fAltTab); if (fPush && !TestWF(pwndActive, WEFTOPMOST) && !TestWF(pwndActive, WFBOTTOMMOST)) { ThreadLock(pwndActive, &tlpwndActive); xxxSetWindowPos(pwndActive, PWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS); ThreadUnlock(&tlpwndActive); } }
/*
* Switch this new window to the foreground * This window can go away during the SetForeground call if it isn't * on the thread calling SwitchToThisWindow()! */ xxxSetForegroundWindow(pwnd, TRUE);
/*
* Restore minimized windows if the Alt+Tab case */ if (fAltTab && TestWF(pwnd,WFMINIMIZED)) {
/*
* We need to package up a special 'posted' queue message here. This * ensures that this message gets processed after the asynchronous * activation event occurs (via SetForegroundWindow). */ PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq, QEVENT_POSTMESSAGE, pwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); } }
/***************************************************************************\
* NextPrevTaskIndex * * History: * 01-Jun-1995 BradG Ported from Win95 \***************************************************************************/
INT NextPrevTaskIndex( PSWINFO pswInfo, INT iIndex, INT iCount, BOOL fNext) { UserAssert(iCount <= pswInfo->iTotalTasks);
if (fNext) { iIndex += iCount; if (iIndex >= pswInfo->iTotalTasks) { iIndex -= pswInfo->iTotalTasks; } } else { iIndex -= iCount; if (iIndex < 0) { iIndex += pswInfo->iTotalTasks; } }
UserAssert((iIndex >= 0) && (iIndex < pswInfo->iTotalTasks)); return iIndex; }
/***************************************************************************\
* NextPrevPhwnd * * Given a pointer to one entry in the window list, this can return * the pointer to the next/prev entry in a circular list fashion. * * History: * 01-Jun-1995 BradG Ported from Win95 \***************************************************************************/ PHWND NextPrevPhwnd( PSWINFO pswInfo, PHWND phwnd, BOOL fNext) { PBWL pbwl; PHWND phwndStart; PHWND phwndLast;
pbwl = pswInfo->pbwl; phwndStart = &(pbwl->rghwnd[0]); phwndLast = pswInfo->phwndLast;
UserAssert(*phwndLast == (HWND)1); // Last entry must have a 1.
UserAssert(phwndStart < phwndLast); // There must be atleast one entry.
UserAssert(phwnd != phwndLast); // Can't be passing in an invalid entry.
if (fNext) { phwnd++; if (phwnd == phwndLast) { phwnd = phwndStart; } } else { if (phwnd == phwndStart) { phwnd = phwndLast - 1; // we have atleast one valid entry.
} else { phwnd--; } }
return phwnd; }
/***************************************************************************\
* _IsTaskWindow * * History: * 01-Jun-95 BradG Ported from Win95 \***************************************************************************/
BOOL _IsTaskWindow( PWND pwnd, PWND pwndActive) { /*
* Following windows do not qualify to be shown in task list: * Switch Window, Hidden windows (unless they are the active * window), Disabled windows, Kanji Conv windows. * * Also, check for a combobox popup list which has the top-most * style (it's spwndLastActive will be NULL). */ UserAssert(pwnd != NULL); return( (TestWF(pwnd, WEFAPPWINDOW) || (!TestWF(pwnd, WEFTOOLWINDOW) && !TestWF(pwnd, WEFNOACTIVATE))) && (TestWF(pwnd, WFVISIBLE) || (pwnd == pwndActive)) && (!(pwnd->spwndLastActive && TestWF(pwnd->spwndLastActive, WFDISABLED)))); }
/***************************************************************************\
* RemoveNonTaskWindows() * * Given a list of Windows, this walks down the list and removes the * windows that do not qualify to be shown in the Task-Switch screen. * This also shrinks the list when it removes some entries. * Returns the total number of "tasks" (windows) qualified and remained * in the list. The last entry will have a 1 as usual. * It also returns a pointer to this last entry via params. It also * returns the index of the Currently active task via params. * * History: * 01-Jun-1995 BradG Ported from Win95 \***************************************************************************/
INT _RemoveNonTaskWindows( PBWL pbwl, PWND pwndActive, LPINT lpiActiveTask, PHWND *pphwndLast) { INT iTaskCount = 0; PHWND phwnd; PWND pwnd; PWND pwndUse; PWND pwndOwnee; PHWND phwndHole;
*lpiActiveTask = -1;
/*
* Walk down the window list and do the following: * 1. Remove all entries that do not qualify to be shown in the task list. * 2. Count the total number of windows that qualify. * 3. Get the pointer to the entry that contains current active window. * 4. Get the pointer to the last dummy entry (that has 1 in it) */ for (phwndHole = phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { pwnd = RevalidateHwnd(*phwnd); if (!pwnd) { continue; }
if (_IsTaskWindow(pwnd, pwndActive)) { pwndUse = pwnd;
/*
* First let's find the task-list owner of this window. */ while (!TestWF(pwndUse, WEFAPPWINDOW) && pwndUse->spwndOwner) { pwndOwnee = pwndUse; pwndUse = pwndUse->spwndOwner; if (TestWF(pwndUse, WEFTOOLWINDOW)) { /*
* If this is the owner of a top level property sheet, * show the property sheet. */ if (TestWF(pwndOwnee, WEFCONTROLPARENT) && (pwndUse->spwndOwner == NULL)) { pwndUse = pwnd; } else { pwndUse = NULL; } break; } }
if (!pwndUse || !pwndUse->spwndLastActive) { continue; }
/*
* walk up from the last active window 'til we find a valid task * list window or until we run out of windows in the ownership * chain */ for (pwndUse = pwndUse->spwndLastActive; pwndUse; pwndUse = pwndUse->spwndOwner) if (_IsTaskWindow(pwndUse, pwndActive)) break;
/*
* if we ran out of windows in the ownership chain then use the * owned window itself -- or if we didn't run out of the ownership * chain, then only include this window if it's the window in the * ownership chain that we just found (VB will love us for it !) * -- jeffbog -- 4/20/95 -- Win95C B#2821 */ if (!pwndUse || (pwndUse == pwnd)) {
/*
* Do we have any holes above this? If so, move this handle to * that hole. */ if (phwndHole < phwnd) {
/*
* Yes! There is a hole. Let us move the valid * handle there. */ *phwndHole = *phwnd; }
if (pwndActive == pwnd) *lpiActiveTask = iTaskCount; iTaskCount++; phwndHole++; // Move to the next entry.
}
/*
* Else, leave it as a hole for later filling. */ } }
*phwndHole = (HWND)1; *pphwndLast = phwndHole;
return iTaskCount; }
/***************************************************************************\
* DrawSwitchWndHilite() * * This draws or erases the Hilite we draw around the icon to show which * task we are going to switch to. * This also updates the name on the Task title window. * * History: * 01-Jun-1995 BradG Ported from Win95 \***************************************************************************/
VOID DrawSwitchWndHilite( PSWINFO pswInfo, HDC hdcSwitch, int iCol, int iRow, BOOL fShow) { BOOL fGetAndReleaseIt; RECT rcTemp;
/*
* Draw or erase the hilite depending on "fShow". */ if (fGetAndReleaseIt = (hdcSwitch == NULL)) hdcSwitch = _GetDCEx(gspwndAltTab, NULL, DCX_USESTYLE);
rcTemp.left = pswInfo->ptFirstRowStart.x + iCol * CXICONSLOT; rcTemp.top = pswInfo->ptFirstRowStart.y + iRow * CYICONSLOT; rcTemp.right = rcTemp.left + CXICONSLOT; rcTemp.bottom = rcTemp.top + CYICONSLOT;
DrawFrame(hdcSwitch, &rcTemp, 2, DF_PATCOPY | ((fShow ? COLOR_HIGHLIGHT : COLOR_3DFACE) << 3));
/*
* Update the Task title window. */ if (fShow) { WCHAR szText[CCHTITLEMAX]; INT cch; COLORREF clrOldText, clrOldBk; PWND pwnd; RECT rcRect; HFONT hOldFont; INT iLeft; ULONG_PTR dwResult = 0;
clrOldText = GreSetTextColor(hdcSwitch, SYSRGB(BTNTEXT)); clrOldBk = GreSetBkColor(hdcSwitch, SYSRGB(3DFACE)); hOldFont = GreSelectFont(hdcSwitch, gpsi->hCaptionFont);
/*
* Validate this window handle; This could be some app that terminated * in the background and the following line will GP fault in that case; * BOGUS: We should handle it some other better way. */ pwnd = RevalidateHwnd( *(pswInfo->phwndCurrent) ); if (pwnd) { /*
* Get the window's title. */ if (pwnd->strName.Length) { cch = TextCopy(&pwnd->strName, szText, CCHTITLEMAX); } else { *szText = TEXT('\0'); cch = 0; }
/*
* Draw the text */ CopyRect(&rcRect, &pswInfo->rcTaskName); iLeft = rcRect.left; FillRect(hdcSwitch, &rcRect, SYSHBR(3DFACE)); /*
* If an lpk is installed let it draw the text. */ if (CALL_LPK(PtiCurrentShared())) { TL tlpwnd; LPKDRAWSWITCHWND LpkDrawSwitchWnd;
RtlInitLargeUnicodeString(&LpkDrawSwitchWnd.strName, szText, (UINT)-1); LpkDrawSwitchWnd.rcRect = rcRect;
ThreadLock(pwnd, &tlpwnd); xxxSendMessageTimeout(pwnd, WM_LPKDRAWSWITCHWND, (WPARAM)hdcSwitch, (LPARAM)&LpkDrawSwitchWnd, SMTO_ABORTIFHUNG, 100, &dwResult); ThreadUnlock(&tlpwnd); } else { DRAWTEXTPARAMS dtp;
dtp.cbSize = sizeof(dtp); dtp.iLeftMargin = 0; dtp.iRightMargin = 0; DrawTextEx(hdcSwitch, szText, cch, &rcRect, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE, &dtp ); } }
GreSelectFont(hdcSwitch, hOldFont); GreSetBkColor(hdcSwitch, clrOldBk); GreSetTextColor(hdcSwitch, clrOldText); }
if (fGetAndReleaseIt) _ReleaseDC(hdcSwitch); }
/***************************************************************************\
* DrawIconCallBack * * This function is called by a Windows app returning his icon. * * History: * 17-Jun-1993 mikesch Created. \***************************************************************************/
VOID CALLBACK DrawIconCallBack( HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) { PWND pwndAltTab;
/*
* dwData is the pointer to the switch window handle. * If this Alt+Tab instance is still active, we need to derive this * window's index in the bwl array, otherwise, we are receiving an icon * for an old Alt+Tab window. */ pwndAltTab = RevalidateHwnd((HWND)dwData); if (pwndAltTab && TestWF(pwndAltTab, WFVISIBLE)) {
PSWINFO pswCurrent; PICON pIcon; PHWND phwnd; PWND pwnd; PWND pwndT; INT iStartTaskIndex; TL tlpwndAltTab;
/*
* Derive this window's index in the BWL array */ if ((pwnd = RevalidateHwnd(hwnd)) == NULL) return;
/*
* Get the switch window info */ pswCurrent = Getpswi(pwndAltTab); if (!pswCurrent) return;
for (iStartTaskIndex = 0, phwnd=&(pswCurrent->pbwl->rghwnd[0]); *phwnd != (HWND)1; phwnd++, iStartTaskIndex++) { /*
* Because we list the active window in the Switch Window, the * hwnd here might not be the same, so we also need to walk back * to the top-level window to see if this is the right entry * in the list. */ for(pwndT = RevalidateHwnd(*phwnd); pwndT; pwndT = pwndT->spwndOwner) { if (pwnd == pwndT) goto DrawIcon; } } return;
/*
* Convert the App's HICON into a PICON, or if the App did not return * an icon, use the Windows default icon. */ DrawIcon: pIcon = NULL; if (lResult) pIcon = HMValidateHandleNoRip((HCURSOR)lResult, TYPE_CURSOR);
if (!pIcon) pIcon = SYSICO(WINLOGO);
/*
* Paint this icon in the Alt+Tab window. */ ThreadLockAlways(pwndAltTab, &tlpwndAltTab); xxxPaintIconsInSwitchWindow(pwndAltTab, pswCurrent, NULL, iStartTaskIndex, 0, 1, FALSE, FALSE, pIcon); ThreadUnlock(&tlpwndAltTab); }
UNREFERENCED_PARAMETER(uMsg); }
/***************************************************************************\
* TSW_CalcRowAndCol * * History: * 01-Jun-1995 BradG Ported from Win95 \***************************************************************************/
BOOL TSW_CalcRowAndCol( PSWINFO pswInfo, INT iTaskIndex, LPINT lpiRow, LPINT lpiCol) { INT iDiff; INT iRow;
/*
* Calculate how far is the given task from the first task shown * on the switch window. */ if ((iDiff = (iTaskIndex - pswInfo->iFirstTaskIndex)) < 0) iDiff += pswInfo->iTotalTasks;
/*
* Calculate the Row and if this lies outside the switch window, return FALSE */ if ((iRow = iDiff / pswInfo->iNoOfColumns) >= pswInfo->iNoOfRows) return FALSE;
/*
* Return the Row and column where this task lies. */ *lpiRow = iRow; *lpiCol = iDiff - (iRow * pswInfo->iNoOfColumns);
return TRUE; // This task lies within the switch window.
}
/***************************************************************************\
* xxxPaintIconsInSwitchWindow() * * This can simply paint the icons in the switch window or Scroll the * whole window UP/DOWN and then paint the remaining area; * * If fScroll is TRUE, then the second, third and fourth params are ignored. * * If hIcon is passed in, then we're being called by DrawIconCallBack and * iStartRow parameter is ignored in this case. * * History: * 02-Jun-1995 BradG Ported from Win95 \***************************************************************************/
VOID xxxPaintIconsInSwitchWindow( PWND pwndAltTab, PSWINFO pswInfo, HDC hdc, INT iStartTaskIndex, INT iStartRow, INT iNoOfIcons, BOOL fScroll, BOOL fUp, PICON pIcon) { INT cx, cy, xStart; PHWND phwnd; BOOL fGetAndReleaseIt; INT iColumnIndex = 0; RECT rcScroll; PWND pwnd; TL tlpwnd; HICON hIcon; RECT rcIcon;
CheckLock(pwndAltTab);
/*
* If we were not supplied a DC, get ghwndSwitch's and set a flag * so we remember to release it. */ if (fGetAndReleaseIt = (hdc == NULL)) hdc = _GetDCEx(pwndAltTab, NULL, DCX_USESTYLE);
cx = pswInfo->ptFirstRowStart.x; cy = pswInfo->ptFirstRowStart.y;
if (fScroll) {
rcScroll.left = cx; rcScroll.top = cy; rcScroll.right = cx + CXICONSLOT * pswInfo->iNoOfColumns; rcScroll.bottom = cy + CYICONSLOT * pswInfo->iNoOfRows;
_ScrollDC(hdc, 0, (fUp ? -CYICONSLOT : CYICONSLOT), &rcScroll, &rcScroll, NULL, NULL);
iStartRow = (fUp ? pswInfo->iNoOfRows - 1 : 0); iNoOfIcons = pswInfo->iNoOfColumns; iStartTaskIndex = (fUp ? NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex, (pswInfo->iNoOfRows - 1) * pswInfo->iNoOfColumns, TRUE) : pswInfo->iFirstTaskIndex); }
if (pIcon) { /*
* If pIcon is given, this is to paint just one icon during callback. */ // BradG - Win95 Assert
UserAssert(iNoOfIcons == 1);
/*
* Due to earlier scrolling, the row number would have changed. So, * recalc the row and column from the iStartTaskIndex given. */ if (!TSW_CalcRowAndCol(pswInfo, iStartTaskIndex, &iStartRow, &iColumnIndex)) goto Cleanup; }
xStart = cx += (CXICONSLOT - CXICONSIZE) / 2; cx += iColumnIndex * CXICONSLOT; cy += ((CYICONSLOT - CYICONSIZE) / 2) + iStartRow * CYICONSLOT; phwnd = &(pswInfo->pbwl->rghwnd[iStartTaskIndex]);
/*
* Draw all the icons one by one. */ while (iNoOfIcons--) { /*
* If the Alt+Key is no longer down, abort painting icons. */ if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) goto Cleanup;
/*
* Check if this window is still alive. (Some task could have * terminated in the background) */ if (pwnd = RevalidateHwnd(*phwnd)) { /*
* Find the window's top-level owner */ pwnd = DSW_GetTopLevelCreatorWindow(pwnd);
/*
* If we don't have an icon, find one */ if (!pIcon) { /*
* Try window icon */ hIcon = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL); if (hIcon) { pIcon = (PICON)HMValidateHandleNoRip(hIcon, TYPE_CURSOR); }
/*
* If we don't have an icon yet, try the class icon */ if (!pIcon) { pIcon = pwnd->pcls->spicn; }
/*
* If we don't have an icon yet, use WM_QUERYDRAGICON to ask * 3,x apps for their icon. */ if (!pIcon && !TestWF(pwnd, WFWIN40COMPAT)) { /*
* The callback routine will paint the icon for * us, so just leave pIcon set to NULL */ ThreadLock(pwnd, &tlpwnd); xxxSendMessageCallback(pwnd, WM_QUERYDRAGICON, 0, 0, (SENDASYNCPROC)DrawIconCallBack, HandleToUlong(PtoH(pwndAltTab)), FALSE); ThreadUnlock(&tlpwnd); } else { /*
* If we can't find an icon, so use the Windows icon */ if (!pIcon) { pIcon = SYSICO(WINLOGO); } } } }
if (pIcon) { _DrawIconEx(hdc, cx, cy, pIcon, SYSMET(CXICON), SYSMET(CYICON), 0, SYSHBR(3DFACE), DI_NORMAL); } else if (fScroll) { /*
* NOT IN WIN95 * * No icon was available, do while we are waiting for the * application to paint it's icon, we need to "erase" the * background in case we have scrolled the window. */ rcIcon.left = cx; rcIcon.top = cy; rcIcon.right = cx + SYSMET(CXICON); rcIcon.bottom = cy + SYSMET(CYICON); FillRect(hdc, &rcIcon, SYSHBR(3DFACE)); }
/*
* Check if we are done. */ if (iNoOfIcons <= 0) break;
/*
* Reset hIcon for the next run through the loop */ pIcon = NULL;
/*
* Move all pointers to the next task/icon. */ phwnd = NextPrevPhwnd(pswInfo, phwnd, TRUE); // Get next.
/*
* Is it going to be in the same row; then adjust cx and cy. */ if (++iColumnIndex >= pswInfo->iNoOfColumns) { iColumnIndex = 0; cx = xStart; // Move to first column
cy += CYICONSLOT; // Move to next row.
iStartRow++; } else { /*
* else, adjust cx; */ cx += CXICONSLOT; }
iStartTaskIndex = NextPrevTaskIndex(pswInfo, iStartTaskIndex, 1, TRUE); }
Cleanup: if (fGetAndReleaseIt) _ReleaseDC(hdc); }
/***************************************************************************\
* PaintSwitchWindow * * History: * 02-Jun-1995 BradG Ported from Win95 \***************************************************************************/
VOID xxxPaintSwitchWindow( PWND pwndSwitch) { LPRECT lprcRect; RECT rcRgn; HDC hdcSwitch; PSWINFO pswCurrent; CheckLock(pwndSwitch);
/*
* If our window isn't visible, return */ if (!TestWF(pwndSwitch, WFVISIBLE)) return;
/*
* Get the switch window information */ pswCurrent = Getpswi(pwndSwitch); if (!pswCurrent) return;
/*
* Get the Switch windows DC so we can paint with it */ hdcSwitch = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE );
/*
* Paint the background of the Switch Screen. */ if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) goto PSWExit;
lprcRect = &(pswCurrent->rcTaskName); _GetClientRect(pwndSwitch, lprcRect); FillRect(hdcSwitch, lprcRect, SYSHBR(3DFACE));
/*
* Store this "caption" area back into the current switch * window data structure. */ InflateRect(lprcRect, -(gcxCaptionFontChar << 1), -(gcyCaptionFontChar)); lprcRect->top = lprcRect->bottom - gcyCaptionFontChar;
/*
* Draw the sunken edge for showing the task names. */ if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) goto PSWExit; CopyInflateRect(&rcRgn, lprcRect, gcxCaptionFontChar >> 1, gcyCaptionFontChar >> 1); DrawEdge(hdcSwitch, &rcRgn, EDGE_SUNKEN, BF_RECT);
/*
* Paint the icons */ if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) goto PSWExit;
xxxPaintIconsInSwitchWindow(pwndSwitch, pswCurrent, hdcSwitch, pswCurrent->iFirstTaskIndex, 0, pswCurrent->iTasksShown, FALSE, FALSE, NULL);
/*
* So, just draw the hilite. */ if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) goto PSWExit;
DrawSwitchWndHilite(pswCurrent, hdcSwitch, pswCurrent->iCurCol, pswCurrent->iCurRow, TRUE);
/*
* Release the switch windows DC */ PSWExit: _ReleaseDC(hdcSwitch); }
/***************************************************************************\
* SwitchWndCleanup() * * Clean up all the mem allocated etc., * * History: * 07-Jun-1995 BradG Ported from Win95 \***************************************************************************/
VOID SwitchWndCleanup( PSWINFO *ppswInfo) { UserAssert(ppswInfo != NULL); UserAssert(*ppswInfo != NULL);
/*
* First of all free the Window list. */ if ((*ppswInfo)->pbwl) FreeHwndList((*ppswInfo)->pbwl); UserFreePool(*ppswInfo); *ppswInfo = NULL; }
/***************************************************************************\
* AddSwitchWindowInfo * * 09-12-01 MSadek Created \***************************************************************************/ VOID AddSwitchWindowInfo( PSWINFO pswInfo) { CheckCritIn(); pswInfo->pswiNext = gpswiFirst; gpswiFirst = pswInfo; }
/***************************************************************************\
* RemoveSwitchWindowInfo * * 09-12-01 MSadek Created \***************************************************************************/ VOID RemoveSwitchWindowInfo( PSWINFO *ppswInfo) { PSWINFO* ppswi; PSWINFO pswiT;
CheckCritIn();
for (ppswi = &gpswiFirst; *ppswi != NULL; ppswi = &(*ppswi)->pswiNext) { pswiT = *ppswi; if (pswiT == *ppswInfo) { *ppswi = pswiT->pswiNext; SwitchWndCleanup(ppswInfo); }
if (*ppswi == NULL) { break; } } }
/***************************************************************************\
* RemoveThreadSwitchWindowInfo * * 09-12-01 MSadek Created \***************************************************************************/ VOID RemoveThreadSwitchWindowInfo( PTHREADINFO pti) { PSWINFO* ppswi; PSWINFO pswiT;
CheckCritIn();
for (ppswi = &gpswiFirst; *ppswi != NULL; ppswi = &(*ppswi)->pswiNext) { pswiT = *ppswi; if (pswiT->pti == pti) { *ppswi = pswiT->pswiNext; SwitchWndCleanup(&pswiT); }
if (*ppswi == NULL) { break; } } }
/***************************************************************************\
* InitSwitchWndInfo * * This function allocs and Initializes all the data structures * required the build and show the tasks in the system. * If there is insufficient mem, then this find the next window to switch * to and returns it. In this case, we will behave as if the end user hit * ALT+ESC. The SWitchScreen will not comeup in this case. * If there is only one task in the whole system, then this function * fails and returns a NULL. (No ALT+TAB processing is required). * Otherwise, it allocs one SwitchWndInfo struc, fills it up and returns * the window we gonna switch to. * * History: * 02-Jun-95 BradG Ported from Win95 \***************************************************************************/ PWND InitSwitchWndInfo( PSWINFO * lppswInfo, PWND pwndCurActive, BOOL fPrev) { PBWL pbwl; INT iTotalTasks; INT iCols, iRows, iIconsInLastRow; INT iDiff; PHWND phwndLast; PSWINFO pswInfo; INT iIconIndex; INT iCurRow, iCurCol; INT cxSwitch, cySwitch; INT iFirstRowIcons; INT iActiveTask; PWND pwnd = NULL; PTHREADINFO ptiCurrent = PtiCurrent(); PDESKTOPINFO pdeskinfo = GETDESKINFO(ptiCurrent); PMONITOR pMonitor = GetPrimaryMonitor();
/*
* Initialize the list */ *lppswInfo = (PSWINFO)NULL;
/*
* Build the Window list of all the top level windows. */ #if 0
if (!(pbwl = BuildHwndList(NULL, BWL_ENUMLIST | BWL_ALLDESKTOPS, NULL))) goto ReturnNextWnd; #else
// BradG - HACK, enumerate on current desktop!
// For the long run, we will need to enumerate all desktops
// This will be tricky because we need to check the security of
// each desktop, thus needing the user's security "token".
if (!(pbwl = BuildHwndList(pdeskinfo->spwnd->spwndChild, BWL_ENUMLIST, NULL))) { #ifdef COOLSWITCHTRACE
DbgPrint("CoolSwitch: BuildHwndList failed (contact bradg).\n"); UserAssert(pbwl != NULL); #endif
goto ReturnNextWnd; } #endif
/*
* Walk down the list and remove all non-task windows from the list. * Replace those hwnds with 0. */ if ((iTotalTasks = _RemoveNonTaskWindows(pbwl, pwndCurActive, &iActiveTask, &phwndLast)) < 2) { if (iTotalTasks == 1) { /*
* If we have only one window and it's in full screen mode, we will * return the shell window so the can switch back to GDI mode. */ pwnd = RevalidateHwnd(pbwl->rghwnd[0]); if (pwnd && GetFullScreen(pwnd) == FULLSCREEN && pwndCurActive == pwnd) pwnd = pdeskinfo->spwndShell;
} else { pwnd = pdeskinfo->spwndShell; } #ifdef COOLSWITCHTRACE
DbgPrint("CoolSwitch: Not enough windows to switch.\n"); #endif
goto FreeAndReturnNextWnd; // If there isn't even two tasks, no switch wnd processing.
}
/*
* Allocate the Switch Info structure. If we don't have enough * memory, act as if we are doing Alt+Esc. */ if (!(pswInfo = (PSWINFO)UserAllocPoolWithQuota(sizeof(SWITCHWNDINFO), TAG_ALTTAB))) { #ifdef COOLSWITCHTRACE
DbgPrint("CoolSwitch: UserAllocPool failed on 0x%X bytes (contact bradg).\n", sizeof(SWITCHWNDINFO)); UserAssert(pswInfo != NULL); #endif
goto FreeAndReturnNextWnd; // Unable to alloc SwitchWndInfo struct.
}
pswInfo->pti = ptiCurrent; pswInfo->pbwl = pbwl; pswInfo->phwndLast = phwndLast; pswInfo->iTasksShown = pswInfo->iTotalTasks = iTotalTasks;
/*
* Get the next/prev window that must become active. */ iIconIndex = NextPrevTaskIndex(pswInfo, iActiveTask, 1, !fPrev); pswInfo->phwndCurrent = &(pbwl->rghwnd[iIconIndex]);
iCols = min(gnFastAltTabColumns, iTotalTasks); iRows = iTotalTasks / iCols; // Truncation might occur.
iIconsInLastRow = iTotalTasks - iRows * iCols; iRows += (iIconsInLastRow ? 1 : 0); // Take care of earlier truncation.
/*
* Restrict the number of rows to just MAXROWSALLOWED (3) */ if (iRows > gnFastAltTabRows) { iRows = gnFastAltTabRows; pswInfo->fScroll = TRUE; // We need to scroll.
iIconsInLastRow = iCols; pswInfo->iTasksShown = iCols * iRows; } else { pswInfo->fScroll = FALSE; }
pswInfo->iNoOfColumns = iCols; pswInfo->iNoOfRows = iRows;
if (iIconsInLastRow == 0) iIconsInLastRow = pswInfo->iNoOfColumns; // Last Row is full.
pswInfo->iIconsInLastRow = iIconsInLastRow;
/*
* Find out Row and Col where the next/prev icon will lie. */ if (iIconIndex >= (iRows * iCols)) { /*
* Next Icon lies outside. Bring it to the center. */ iCurRow = (iRows >> 2) + 1; iCurCol = (iCols >> 2) + 1; iDiff = (iIconIndex - ((iCurRow * iCols) + iCurCol)); } else { iDiff = 0; iCurRow = iIconIndex / iCols; iCurCol = iIconIndex - (iCurRow * iCols); }
pswInfo->iFirstTaskIndex = iDiff; pswInfo->iCurRow = iCurRow; pswInfo->iCurCol = iCurCol;
/*
* Calculate the Switch Window Dimensions. */ cxSwitch = min( pMonitor->rcMonitor.right - pMonitor->rcMonitor.left, gnFastAltTabColumns * CXICONSLOT + CXICONSIZE / 2 + 6 * gpsi->gclBorder * SYSMET(CXBORDER) + gcxCaptionFontChar);
cySwitch = min( pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top, iRows * CYICONSLOT + CYICONSIZE + gcyCaptionFontChar * 2 + gcyCaptionFontChar / 2);
/*
* Find the number of icons in first row */ if (iRows == 1) { iFirstRowIcons = iIconsInLastRow; } else { iFirstRowIcons = iCols; }
/*
* Center the icons based on the number of icons in first row. */ pswInfo->ptFirstRowStart.x = (cxSwitch - 4*gpsi->gclBorder*SYSMET(CXBORDER) - iFirstRowIcons * CXICONSLOT) >> 1; pswInfo->ptFirstRowStart.y = (CYICONSIZE >> 1);
pswInfo->cxSwitch = cxSwitch; pswInfo->cySwitch = cySwitch;
AddSwitchWindowInfo(pswInfo); *lppswInfo = pswInfo;
return RevalidateHwnd(*(pswInfo->phwndCurrent)); // Success!
/*
* When there is insufficient mem to create the reqd structures, we simply * return the next window. We make the phwndInfo as NULL. So, we won't * attempt to draw the switch window. */
FreeAndReturnNextWnd: FreeHwndList(pbwl); ReturnNextWnd: if (pwnd) return(pwnd);
return(_GetNextQueueWindow(pwndCurActive, _GetKeyState(VK_SHIFT) < 0, FALSE)); }
/***************************************************************************\
* xxxMoveSwitchWndHilite() * * This moves the Hilite to the next/prev icon. * Checks if this move results in a scrolling. If it does, then * make sure scroll occurs. * Else, erase hilite from the current icon; * Then draw hilite on the new Icon. * fPrev indicates whether you want the prev task or next. * * History: * 02-Jun-1995 BradG Ported from Win95 \***************************************************************************/
HWND xxxMoveSwitchWndHilite( PWND pwndSwitch, PSWINFO pswInfo, BOOL fPrev) { INT iCurCol, iCurRow; INT iMaxColumns; BOOL fLastRow; BOOL fNeedToScroll = FALSE; HDC hdc; HWND hwnd;
CheckLock(pwndSwitch); UserAssert(IsWinEventNotifyDeferredOK());
iCurCol = pswInfo->iCurCol; iCurRow = pswInfo->iCurRow;
/*
* Find out the new postion (row and column) of hilite. */ if (fPrev) { if (iCurCol > 0) { /*
* Move cursor to prev column on the same row. */ iCurCol--; } else { /*
* Try to move to the previous row. */ if (iCurRow > 0) { /*
* Move to the last column on the previous row. */ iCurRow--; iCurCol = pswInfo->iNoOfColumns - 1; } else { /*
* We are already at (0,0); See if we need to scroll. */ if (pswInfo->fScroll) { /*
* Time to scroll; Scroll by one Row; * Repaint the whole window. */ fNeedToScroll = TRUE; pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex, pswInfo->iNoOfColumns, FALSE); iCurCol = pswInfo->iNoOfColumns - 1; } else { /*
* Move the hilite to the last icon shown. */ iCurRow = pswInfo->iNoOfRows - 1; iCurCol = pswInfo->iIconsInLastRow - 1; } } }
} else { /*
* !fPrev * Get the number of columns in the current row. */ if (fLastRow = (iCurRow == (pswInfo->iNoOfRows - 1))) // Are we at the last row?
iMaxColumns = pswInfo->iIconsInLastRow; else iMaxColumns = pswInfo->iNoOfColumns;
/*
* Are we at the last column yet? */ if (iCurCol < (iMaxColumns - 1)) { /*
* No! Move to the right. */ iCurCol++; } else { /*
* We are at the last column. * If we are not at last row, then move to next row. */ if (!fLastRow) { iCurCol = 0; iCurRow++; } else { /*
* We are at the last row, last col; * See if we need to scroll. */ if (pswInfo->fScroll) { fNeedToScroll = TRUE; pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex, pswInfo->iNoOfColumns, TRUE); iCurCol = 0; } else { /*
* Move to the top left corner (0, 0). */ iCurRow = iCurCol = 0; } } } }
/*
* Move the phwnd to the next/prev */ pswInfo->phwndCurrent = NextPrevPhwnd(pswInfo, pswInfo->phwndCurrent, !fPrev);
/*
* Remove Hilite from the current location. */ hdc = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE); DrawSwitchWndHilite(pswInfo, hdc, pswInfo->iCurCol, pswInfo->iCurRow, FALSE);
pswInfo->iCurRow = iCurRow; pswInfo->iCurCol = iCurCol; hwnd = (*(pswInfo->phwndCurrent));
/*
* Repaint if needed. */ if (fNeedToScroll) xxxPaintIconsInSwitchWindow(pwndSwitch, pswInfo, hdc, pswInfo->iFirstTaskIndex, 0, 0, TRUE, !fPrev, NULL);
/*
* Draw Hilite at the new location. */ DrawSwitchWndHilite(pswInfo, hdc, iCurCol, iCurRow, TRUE);
_ReleaseDC(hdc);
xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndSwitch, OBJID_CLIENT, iCurRow * pswInfo->iNoOfColumns + iCurCol + 1, WEF_USEPWNDTHREAD);
return hwnd; }
/***************************************************************************\
* xxxShowSwitchWindow() * * Show the switch Window. * Returns: TRUE if succeeded. FALSE, if the window was not shown because * of the pre-mature release of ALT key. The selection has been made already. * * History: * 07-Jun-1995 BradG Ported from Win95 \***************************************************************************/
BOOL xxxShowSwitchWindow( PWND pwndAltTab) { PSWINFO pswInfo; PMONITOR pMonitorSwitch = GetPrimaryMonitor(); CheckLock(pwndAltTab); UserAssert(IsWinEventNotifyDeferredOK());
/*
* Get the switch window information */ pswInfo = Getpswi(pwndAltTab); if (pswInfo == NULL) { return FALSE; }
/*
* If the key is not down, don't bother to display Switch Window. */ if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) || (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) { #ifdef COOLSWITCHTRACE
DbgPrint("CoolSwitch: Not displaying window because VM_MENU is up (contact bradg).\n"); #endif
return FALSE; }
/*
* Bring and position the window on top. */ xxxSetWindowPos(pwndAltTab, PWND_TOPMOST, 0,0,0,0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW );
if (!TestWF(pwndAltTab, WFVISIBLE)) { xxxSetWindowPos( pwndAltTab, PWND_TOPMOST, (pMonitorSwitch->rcWork.left + pMonitorSwitch->rcWork.right - pswInfo->cxSwitch) / 2, (pMonitorSwitch->rcWork.top + pMonitorSwitch->rcWork.bottom - pswInfo->cySwitch) / 2, pswInfo->cxSwitch, pswInfo->cySwitch, SWP_SHOWWINDOW | SWP_NOACTIVATE); }
#ifdef COOLSWITCHTRACE
UserAssert(TestWF(pwndAltTab, WFVISIBLE)); #endif
xxxUpdateWindow(pwndAltTab);
xxxWindowEvent(EVENT_SYSTEM_SWITCHSTART, pwndAltTab, OBJID_CLIENT, 0, WEF_USEPWNDTHREAD);
xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndAltTab, OBJID_CLIENT, pswInfo->iCurRow * pswInfo->iNoOfColumns + pswInfo->iCurCol + 1, WEF_USEPWNDTHREAD);
return TRUE; }
/***************************************************************************\
* * xxxSwitchWndProc() * \***************************************************************************/
LRESULT xxxSwitchWndProc( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam) { TL tlpwndActivate; PTHREADINFO ptiCurrent = PtiCurrent();
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_SWITCH, WM_CREATE);
switch (message) { case WM_CREATE: /*
* When the queue was created, the cursor was set to the wait cursor. * We want to use the normal one. */ zzzSetCursor(pwnd->pcls->spcur); break;
case WM_CLOSE: /*
* Hide this window without activating anyone else. */ xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
/*
* Get us out of Alt+Tab mode. Since the alttab information * is stored in the gptiRit->pq, we will reference that insteatd * of the current-thread. */ xxxCancelCoolSwitch(); break;
case WM_ERASEBKGND: case WM_FULLSCREEN: ThreadLockWithPti(ptiCurrent, pwnd, &tlpwndActivate); xxxPaintSwitchWindow(pwnd); ThreadUnlock(&tlpwndActivate); return 0;
case WM_DESTROY: { /*
* Get the switch window info for this window */ PSWINFO pswCurrent = Getpswi(pwnd);
if (pswCurrent) { RemoveSwitchWindowInfo(&pswCurrent); Setpswi(pwnd, NULL); } } break; }
return xxxDefWindowProc(pwnd, message, wParam, lParam); }
/***************************************************************************\
* xxxCancelCoolSwitch * * This functions destroys the cool switch window and removed the INALTTAB * mode flag from the specified queue. * * History: * 18-Sep-1995 BradG Created \***************************************************************************/ VOID xxxCancelCoolSwitch( void) { CheckCritIn(); UserAssert(IsWinEventNotifyDeferredOK());
/*
* Destroy the Cool Switch window */ if (gspwndAltTab != NULL) { PWND pwnd = gspwndAltTab; /*
* Make sure that the thread calling this is the same thread which * created the alttab window. Otherwise, we could end up with this * window floating around until the calling process dies. Remember, * we can't destroy windows across different threads. */ if (gspwndAltTab->head.pti != PtiCurrent()) { return; }
xxxWindowEvent(EVENT_SYSTEM_SWITCHEND, gspwndAltTab, OBJID_CLIENT, 0, WEF_USEPWNDTHREAD); if (Unlock(&gspwndAltTab)) { xxxDestroyWindow(pwnd); } } }
/***************************************************************************\
* xxxNextWindow * * This function does the processing for the alt-tab/esc/F6 UI. * * History: * 30-May-1991 DavidPe Created. \***************************************************************************/
VOID xxxNextWindow( PQ pq, DWORD wParam) { PWND pwndActivateNext; PWND pwndCurrentActivate, pwndCurrentTopFocus; int fDir; TL tlpwndCurrentTopFocus; TL tlpwndActivateNext; TL tlpwndCurrentActivate; TL tlpwndT; PSWINFO pswCurrent; ULONG_PTR dwResult; BOOL fNonRit = FALSE; PTHREADINFO ptiCurrent = PtiCurrent();
UserAssert(!IsWinEventNotifyDeferred());
if (pq == NULL) return;
fDir = (_GetAsyncKeyState(VK_SHIFT) < 0) ? FDIR_BACKWARD : FDIR_FORWARD;
pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus); /*
* NOTE: As of NT 4.0 the slow Alt+Tab functionality now officially acts * like Alt+Esc with the exception that Alt+Tab will activate the window * where Alt+Esc will not. */ switch (wParam) {
case VK_TAB:
if (gspwndAltTab == NULL) {
PWND pwndSwitch; TL tlpSwitchInfo;
/*
* We are entering Alt+Tab for the first time, we need to * initialize the Switch Window structure and if needed * create and display the Alt+Tab window. We have two special * cases: (1) The user does not want to use the Switch window, * (2) The initialize switch window fails thus we will act * just like slow Alt+Tab */
/*
* Since Alt+Shift is the default hotkey for keyboard layout switching, * Alt+Shift+Tab may cause a KL switching while AltTab window is up. * To prevent it, we'd better reset the global toggle key state here, * so that xxxScanSysQueue will not confuse when it handles keyup messages. */ gLangToggleKeyState = KLT_NONE;
/*
* Mouse buttons sometimes get stuck down due to hardware glitches, * usually due to input concentrator switchboxes or faulty serial * mouse COM ports, so clear the global button state here just in case, * otherwise we may not be able to change focus with the mouse. * Also do this in zzzCancelJournalling (Ctr-Esc, Ctrl-Alt-Del, etc.) */ #if DBG
if (gwMouseOwnerButton) RIPMSG1(RIP_WARNING, "gwMouseOwnerButton=%x, being forcibly cleared\n", gwMouseOwnerButton); #endif
gwMouseOwnerButton = 0;
/*
* Determine the current active window. */ Lock(&gspwndActivate, pq->spwndActive); if (gspwndActivate == NULL) { Lock(&gspwndActivate, grpdeskRitInput->pDeskInfo->spwnd->spwndChild); }
if (!gspwndActivate) { return; }
ThreadLockWithPti(ptiCurrent, pwndCurrentTopFocus, &tlpwndCurrentTopFocus);
/*
* Make a local copy of gspwndActivate and lock it because xxxFreeWindow will * unlock if it is the window being freed. */ pwndCurrentActivate = gspwndActivate; ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
/*
* Cancel the active window's mode */ xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
/*
* Initialize the Switch Window data structure, if we * succeed create and display the window, otherwise act * like slow Alt+Tab. */ pwndActivateNext = InitSwitchWndInfo(&pswCurrent, pwndCurrentActivate, fDir);
ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
if (pswCurrent == NULL) { /*
* Couldn't initialize our switch window data structure, so we * will act like Alt+Esc. */ goto DoSlowAltTab; }
if (pwndActivateNext == NULL) { RemoveSwitchWindowInfo(&pswCurrent); ThreadUnlock(&tlpwndActivateNext); ThreadUnlock(&tlpwndCurrentActivate); ThreadUnlock(&tlpwndCurrentTopFocus); Unlock(&gspwndActivate); return; }
ThreadLockPoolCleanup(ptiCurrent, &pswCurrent, &tlpSwitchInfo, RemoveSwitchWindowInfo);
/*
* Since we are in the RIT, test the physical state of the keyboard */ pswCurrent->fJournaling = FALSE;
/*
* Create the Alt+Tab window */ pwndSwitch = xxxNVCreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME, (PLARGE_STRING)SWITCHWNDCLASS, NULL, WS_POPUP | WS_BORDER | WS_DISABLED, 0, 0, 10, 10, NULL, NULL, NULL, NULL, VER40);
if (gspwndAltTab != NULL) { RIPMSG0(RIP_WARNING, "xxxNextWindow: Creating a new switch window while one already exists.");
_PostMessage(gspwndAltTab, WM_CLOSE, 0, 0); }
Lock(&gspwndAltTab, pwndSwitch);
ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
if (gspwndAltTab == NULL) { /*
* Could not create the cool switch window, do the Alt+Esc thing */ #ifdef COOLSWITCHTRACE
DbgPrint("CoolSwitch: Could not create window (contact bradg).\n"); UserAssert(gspwndAltTab != NULL); #endif
RemoveSwitchWindowInfo(&pswCurrent); goto DoSlowAltTab; }
/*
* Save the pointer to the switch window info structure */ Setpswi(gspwndAltTab, pswCurrent); /*
* Set gspwndActivate so the RIT knows what window we would like * it to activate. */ Lock(&gspwndActivate, pwndActivateNext);
/*
* Make sure that our rit queue has the correct pdesk */ if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) { xxxSetThreadDesktop(NULL, grpdeskRitInput); // DeferWinEventNotify() ?? IANJA ??
}
/*
* If we're currently full screen tell console to switch to * the desktop to GDI mode; we can't do this on the RIT because * it can be slow. */ if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) { ThreadLockWithPti(ptiCurrent, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT); xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd)); ThreadUnlock(&tlpwndT); }
/*
* Show the Alt+Tab window. If it returns FALSE this means * the ALT key has been released, so there is no need to * paint the icons. */ ThreadLockAlwaysWithPti(ptiCurrent, gspwndAltTab, &tlpwndT); xxxShowSwitchWindow(gspwndAltTab); ThreadUnlock(&tlpwndT);
/*
* Exit now because the Switch window will have been * already updated. */ ThreadUnlock(&tlpwndActivateNext); ThreadUnlock(&tlpwndCurrentActivate); ThreadUnlock(&tlpwndCurrentTopFocus);
} else { /*
* We come here to do the actual switching and/or updating of * the switch window when in Alt+Tab mode. */ PWND pwndSwitch; TL tlpwndSwitch; HWND hwndActivateNext; HWND hwndStop;
if (!(pwndSwitch = gspwndAltTab)) {
goto DoAltEsc;
} else { /*
* Move the hilight rect to the next/prev task. It is possible * that some tasks were destoryed, so we need to skip those. */ ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch); hwndStop = NULL; do { pswCurrent = Getpswi(pwndSwitch); if (pswCurrent == NULL) { ThreadUnlock(&tlpwndSwitch); goto DoAltEsc; } hwndActivateNext = xxxMoveSwitchWndHilite(pwndSwitch, pswCurrent, fDir); if (!hwndStop) { hwndStop = hwndActivateNext; } else { if (hwndStop == hwndActivateNext) { pwndActivateNext = NULL; break; } } pwndActivateNext = RevalidateHwnd(hwndActivateNext); } while (!pwndActivateNext); ThreadUnlock(&tlpwndSwitch); Lock(&gspwndActivate, pwndActivateNext); if (!gspwndActivate) { /*
* No Window to activate, bail out of Alt+Tab mode */ xxxCancelCoolSwitch(); } } } break;
DoAltEsc: case VK_ESCAPE: /*
* NOTE: The RIT doesn't use gspwndActivate to activate the window when * processing Alt+Esc, we just use it here as a convenient * variable. The actual activation takes place below. */ pwndCurrentActivate = pq->spwndActive; if (pwndCurrentActivate == NULL) { pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild; if (pwndCurrentActivate == NULL) { return; } }
ThreadLockWithPti(ptiCurrent, pwndCurrentTopFocus, &tlpwndCurrentTopFocus);
ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
/*
* Cancel the active window's mode */ xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
/*
* Determine the next window to activate */ pwndActivateNext = _GetNextQueueWindow(pwndCurrentActivate, fDir, TRUE); ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
/*
* If we're going forward through the windows, move the currently * active window to the bottom so we'll do the right thing when * we go backwards. */ if (pwndActivateNext != pwndCurrentActivate) { DoSlowAltTab: if (pwndActivateNext) {
/*
* We're about to activate another window while the ALT key is down, * so let the current focus window know that it doesn't need the * menu underlines anymore */ if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) { ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE); }
if (fDir == FDIR_FORWARD) { /*
* For Alt+ESC only move the window to the bottom if it's * not a top most window */ if (!TestWF(pwndCurrentActivate, WEFTOPMOST)) { xxxSetWindowPos(pwndCurrentActivate, PWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_ASYNCWINDOWPOS); } }
/*
* The ALT key is down, so this window needs menu underlines */ if (pwndActivateNext->spmenu != NULL) { SetMF(pwndActivateNext->spmenu, MFUNDERLINE); }
/*
* This little ugly hack will cause xxxSetForegroundWindow2() * to send out an activation messages to a queue that is * already the active queue allowing us to change the active * window on that queue. */ if (gpqForeground == GETPTI(pwndActivateNext)->pq) gpqForeground = NULL;
/*
* Make the selected window thread the owner of the last input; * since he's next, he owns the ALT-ESC. */ glinp.ptiLastWoken = GETPTI(pwndActivateNext);
xxxSetForegroundWindow2(pwndActivateNext, NULL, (wParam == VK_TAB) ? SFW_SWITCH | SFW_ACTIVATERESTORE : SFW_SWITCH);
/*
* Win3.1 calls SetWindowPos() with activate, which z-orders * first regardless, then activates. Our code relies on * xxxActivateThisWindow() to z-order, and it'll only do * it if the window does not have the child bit set (regardless * that the window is a child of the desktop). * * To be compatible, we'll just force z-order here if the * window has the child bit set. This z-order is asynchronous, * so this'll z-order after the activate event is processed. * That'll allow it to come on top because it'll be foreground * then. (Grammatik has a top level window with the child * bit set that wants to be come the active window). */ if (wParam == VK_TAB && TestWF(pwndActivateNext, WFCHILD)) { xxxSetWindowPos(pwndActivateNext, (PWND)HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS); } } } ThreadUnlock(&tlpwndActivateNext); ThreadUnlock(&tlpwndCurrentActivate); ThreadUnlock(&tlpwndCurrentTopFocus); break;
case VK_F6: if ((pwndCurrentActivate = pq->spwndActive) == NULL) pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild;
pwndActivateNext = pwndCurrentActivate;
/*
* HACK! console sessions are all one thread but we want them * to act like different threads so if its a console thread (csrss.exe) * then ALT-F6 does nothing just like in Win 3.1 * Note: we never get called with wParam == VK_F6 anyway. Win NT 3.51 * doesn't seem to either, but Windows '95 does. BUG?? (IanJa) */ if (!(GETPTI(pwndActivateNext)->TIF_flags & TIF_CSRSSTHREAD)) { /*
* on a alt-f6, we want to keep the switch within the thread. * We may want to rethink this because this will look strange * when you alt-f6 on a multi-threaded app we will not rotate * through the windows on the different threads. This works * fine on Win 3.x because it is single threaded. */ do { pwndActivateNext = NextTopWindow(pq->ptiKeyboard, pwndActivateNext, NULL, fDir ? NTW_PREVIOUS : 0); } while( (pwndActivateNext != NULL) && (GETPTI(pwndActivateNext) != pq->ptiKeyboard));
if (pwndActivateNext != NULL) {
if (pwndActivateNext != pwndCurrentActivate) { /*
* We're about to activate another window while the ALT key is down, * so let the current focus window know that it doesn't need the * menu underlines anymore */ pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus); if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) { ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE); } /*
* The ALT key is down, so this window needs menu underlines */ if (pwndActivateNext->spmenu != NULL) { SetMF(pwndActivateNext->spmenu, MFUNDERLINE); } }
ThreadLockAlwaysWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext); xxxSetWindowPos(pwndActivateNext, PWND_BOTTOM, 0, 0, 0, 0, SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_NOCHANGE | SWP_ASYNCWINDOWPOS); xxxSetForegroundWindow2(pwndActivateNext, NULL, SFW_SWITCH); ThreadUnlock(&tlpwndActivateNext); } } break; } }
/***************************************************************************\
* xxxOldNextWindow * * This function does the processing for the alt-tab/esc/F6 UI. * * History: * 03-17-92 DavidPe Ported from Win 3.1 sources \***************************************************************************/ VOID xxxOldNextWindow( UINT flags) { MSG msg; HWND hwndSel; PWND pwndNewSel; PWND pwndSel; BOOL fType = 0; BOOL fDrawIcon; WORD vk; TL tlpwndT; TL tlpwndSel; TL tlpwndSwitch; PSWINFO pswCurrent; PWND pwndSwitch; HWND hwndStop; HWND hwndNewSel; PTHREADINFO ptiCurrent = PtiCurrent();
/*
* Don't allow entering this routine when we're already in the AltTab * mode. The AltTab window may have been created via xxxNextWindow. */ if (gspwndAltTab != NULL) { return; }
if ((pwndSel = ptiCurrent->pq->spwndActive) == NULL) return;
ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndSel); xxxCapture(ptiCurrent, pwndSel, SCREEN_CAPTURE);
vk = (WORD)flags; msg.wParam = (UINT)flags;
pwndNewSel = NULL;
if (vk == VK_TAB) {
TL tlpSwitchInfo;
/*
* Initialize the Switch window data structures */ pwndNewSel = InitSwitchWndInfo(&pswCurrent, pwndSel, _GetKeyState(VK_SHIFT) < 0);
if (pswCurrent == NULL) { /*
* We were unable to initialize the data structure used by * the Switch window, so we will act like Alt+Esc. */ } else { PWND pwndSwitch;
/*
* We are doing a journal playback do use _GetKeyState to * test the keyboard. */ pswCurrent->fJournaling = TRUE;
ThreadLockPoolCleanup(ptiCurrent, &pswCurrent, &tlpSwitchInfo, RemoveSwitchWindowInfo);
pwndSwitch = xxxNVCreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME, (PLARGE_STRING)SWITCHWNDCLASS, NULL, WS_POPUP | WS_BORDER | WS_DISABLED, 0, 0, 10, 10, NULL, NULL, NULL, NULL, VER40); if (gspwndAltTab != NULL) { RIPMSGF0(RIP_WARNING, "Creating a new switch window while one already exists.");
_PostMessage(gspwndAltTab, WM_CLOSE, 0, 0); }
ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
Lock(&gspwndAltTab, pwndSwitch);
if (!(pwndSwitch = gspwndAltTab)) { RemoveSwitchWindowInfo(&pswCurrent); } else { /*
* Lock the switch window. */ ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
/*
* Save the switch window info */ Setpswi(pwndSwitch, pswCurrent);
// Don't we need to switch from full screen mode if needed?
#if 0
/*
* If we're currently full screen tell console to switch to * the desktop to GDI mode; we can't do this on the RIT because * it can be slow. */ if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) { ThreadLockWithPti(pti, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT); xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LONG)HW(grpdeskRitInput->pDeskInfo->spwnd)); ThreadUnlock(&tlpwndT); } #endif
/*
* Show the switch window, this also will paint the window */ xxxShowSwitchWindow(gspwndAltTab); ThreadUnlock(&tlpwndSwitch); } }
}
if (!pwndNewSel) goto StartTab;
pwndSel = pwndNewSel;
while (TRUE) {
hwndSel = PtoH(pwndSel); /*
* Wait for a message without getting it out of the queue. */ while (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD)) xxxWaitMessage();
if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL) pwndSel = ptiCurrent->pq->spwndActive;
if (_CallMsgFilter(&msg, MSGF_NEXTWINDOW)) { /*
* Swallow the message if the hook processed it */ xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE); continue; }
/*
* If we are doing Alt+Tab and some other key comes in (other than * tab, escape or shift), then bomb out of this loop and leave that * key in the queue. */ if ((msg.message == WM_SYSKEYDOWN) && gspwndAltTab != NULL) {
vk = (WORD)msg.wParam;
if ((vk != VK_TAB) && (vk != VK_ESCAPE) && (vk != VK_SHIFT)) { pwndSel = ptiCurrent->pq->spwndActive; fType = 0; goto Exit; } }
switch (msg.message) {
case WM_CANCELJOURNAL: /*
* If journalling was canceled we need to exit our loop and * remove the Alt+Tab window. We don't want to remove this * meesage because we want the app to know that journalling * was canceled. */
/* > > > F A L L T H R O U G H < < < */ case WM_HOTKEY: /*
* When pressing ALT-CTL-ESC-DEL on the logon desktop * We eat WM_KEYUP and the queue for the wiinlogon thread will be empty so will be stuck * in xxxWaitMessage() forever till the user do a mouse click where we will exit the loop in the below case statement. * consider WM_HOTKEY as a valid exit case. * [msadek -- 03/17/2001, bug# 337206] */
/* > > > F A L L T H R O U G H < < < */ case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_XBUTTONDOWN: case WM_XBUTTONUP: /*
* If mouse message, cancel and get out of loop. */ pwndSel = ptiCurrent->pq->spwndActive; fType = 0; goto Exit;
case WM_KEYUP: case WM_KEYDOWN: case WM_SYSCHAR: case WM_SYSKEYUP: case WM_MOUSEMOVE: /*
* Swallow the message */ hwndSel = PtoH(pwndSel); xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL) pwndSel = ptiCurrent->pq->spwndActive;
if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) {
vk = (WORD)msg.wParam;
/*
* If alt-tab up, then exit. */ if (vk == VK_MENU) { /*
* If doing Alt+Esc, wait for up of ESC to get out. */ if (gspwndAltTab == NULL) break;
fType = 0; goto Exit;
} else if (vk == VK_ESCAPE || vk == VK_F6) { /*
* Get out on up transition of ESC or F6 keys. */ if (gspwndAltTab != NULL) {
pwndSel = ptiCurrent->pq->spwndActive; fType = 0;
} else {
fType = ((vk == VK_ESCAPE) ? ALT_ESCAPE : ALT_F6); }
goto Exit; }
} else if (msg.message == WM_KEYDOWN) { /*
* Exit out loop is a stray key stroke comes through. In * particular look for VK_CONTROL. */ pwndSel = ptiCurrent->pq->spwndActive; fType = 0; goto Exit; } break;
case WM_SYSKEYDOWN: vk = (WORD)msg.wParam;
switch (vk) {
case VK_SHIFT: case VK_TAB: case VK_ESCAPE: case VK_F6:
hwndSel = PtoH(pwndSel); xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL) pwndSel = ptiCurrent->pq->spwndActive;
if (!(vk == VK_TAB)) break; StartTab: if (vk == VK_ESCAPE) { pwndNewSel = _GetNextQueueWindow( pwndSel, _GetKeyState(VK_SHIFT) < 0, TRUE);
if (pwndNewSel == NULL) break;
fType = ALT_ESCAPE; pwndSel = pwndNewSel;
/*
* Wait until ESC goes up to activate new window. */ break; } if (vk == VK_F6) {
PWND pwndFirst; PWND pwndSaveSel = pwndSel;
/*
* Save the first returned window to act as a limit * to the search because NextTopWindow will return NULL * only if pwndSel is the only window that meets its * selection criteria. * * This prevents a hang that can occur in winword or * excel when then Alt-F4-F6 key combination is hit * and unsaved changes exist. */ pwndFirst = pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL, _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
while (TRUE) {
/*
* If pwndNewSel is NULL, pwndSel is the only candidate. */ if (pwndNewSel == NULL) break;
pwndSel = pwndNewSel;
/*
* If the window is on the same thread, wait until * F6 goes up to activate new window. */ if (GETPTI(pwndSel) == ptiCurrent) break;
pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL, _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
/*
* If we've looped around, use the original window. * Wait until F6 goes up to activate new window. */ if (pwndNewSel == pwndFirst) { pwndSel = pwndSaveSel; break; } } break; }
/*
* Here for the Alt+Tab case */ if ((pwndSwitch = gspwndAltTab) != NULL) { ThreadLockWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch); hwndStop = NULL; do {
pswCurrent = Getpswi(pwndSwitch); if (pswCurrent == NULL) { break; } hwndNewSel = xxxMoveSwitchWndHilite( pwndSwitch, pswCurrent, _GetKeyState(VK_SHIFT) < 0);
if (!hwndStop) { hwndStop = hwndNewSel; } else { if (hwndStop == hwndNewSel) { pwndNewSel = NULL; break; } } pwndNewSel = RevalidateHwnd(hwndNewSel); } while (!pwndNewSel); ThreadUnlock(&tlpwndSwitch); pwndSel = pwndNewSel;
} else {
pwndNewSel = _GetNextQueueWindow( pwndSel, _GetKeyState(VK_SHIFT) < 0, FALSE);
if (pwndNewSel && pwndNewSel != pwndSel) {
if (!TestWF(pwndSel, WEFTOPMOST)) { /*
* Force the old window to the bottom */ ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT); xxxSetWindowPos(pwndSel, PWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_ASYNCWINDOWPOS); ThreadUnlock(&tlpwndT); }
pwndSel = pwndNewSel; // Will be revalidated at top of loop
} } break;
default: goto Exit; } break;
default: hwndSel = PtoH(pwndSel); xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE); xxxTranslateMessage(&msg, 0); xxxDispatchMessage(&msg);
if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL) pwndSel = ptiCurrent->pq->spwndActive;
break; } }
Exit: xxxReleaseCapture();
fDrawIcon = (gspwndAltTab != NULL);
/*
* If this is an Alt-Escape we also have to send the current window * to the bottom. */ if (fType == ALT_ESCAPE) {
PWND pwndActive;
if (gpqForeground) {
pwndActive = gpqForeground->spwndActive;
if (pwndActive && (pwndActive != pwndSel)) { ThreadLockWithPti(ptiCurrent, pwndActive, &tlpwndT); xxxSetWindowPos(pwndActive, PWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_ASYNCWINDOWPOS); ThreadUnlock(&tlpwndT); } } }
if (pwndSel) { ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT); xxxSetForegroundWindow(pwndSel, FALSE);
if (TestWF(pwndSel, WFMINIMIZED)) {
if ((fType == 0) && fDrawIcon) _PostMessage(pwndSel, WM_SYSCOMMAND, (UINT)SC_RESTORE, 0);
} ThreadUnlock(&tlpwndT); }
/*
* destroy the alt-tab window */ xxxCancelCoolSwitch();
ThreadUnlock(&tlpwndSel); }
/*****************************************************************************\
* * GetAltTabInfo() - Active Accessibility API for OLEACC * * This succeeds if we are currently in alt-tab mode. * \*****************************************************************************/ BOOL WINAPI _GetAltTabInfo( int iItem, PALTTABINFO pati, LPWSTR ccxpwszItemText, UINT cchItemText OPTIONAL, BOOL bAnsi) { PSWINFO pswCurrent;
if (!gspwndAltTab || ((pswCurrent = Getpswi(gspwndAltTab)) == NULL)) { RIPERR0(ERROR_NOT_FOUND, RIP_WARNING, "no Alt-Tab window"); return FALSE; }
/*
* Fill in general information */ pati->cItems = pswCurrent->iTotalTasks; pati->cColumns = pswCurrent->iNoOfColumns; pati->cRows = pswCurrent->iNoOfRows;
pati->iColFocus = pswCurrent->iCurCol; pati->iRowFocus = pswCurrent->iCurRow;
pati->cxItem = CXICONSLOT; pati->cyItem = CYICONSLOT; pati->ptStart = pswCurrent->ptFirstRowStart;
/*
* Fill in specific information if asked. */ if (cchItemText && (iItem >= 0)) { PWND pwndCur;
pwndCur = NULL;
try { if ((iItem < pswCurrent->iTotalTasks) && (pwndCur = RevalidateHwnd(pswCurrent->pbwl->rghwnd[iItem]))) { if (bAnsi) { LPSTR ccxpszItemText = (LPSTR)ccxpwszItemText; ULONG cch; RtlUnicodeToMultiByteN(ccxpszItemText, cchItemText - 1, &cch, pwndCur->strName.Buffer, pwndCur->strName.Length); ccxpszItemText[cch] = '\0'; } else { TextCopy(&pwndCur->strName, ccxpwszItemText, cchItemText); } } else { // no such item
NullTerminateString(ccxpwszItemText, bAnsi); } } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { return FALSE; } }
return TRUE; }
|