test: tmswitch.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# tmswitch.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: tmswitch.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * History:
    00007 * 29-May-1991 DavidPe   Created.
    00008 \***************************************************************************/
    00009
    00010 #include "precomp.h"
    00011 #pragma hdrstop
    00012
    00013 /*
    00014  * COOLSWITCHTRACE is used to trace problems
    00015  * in the CoolSwitch window
    00016  */
    00017 #undef COOLSWITCHTRACE
    00018
    00019
    00020 #define DGF_NODRAW      1
    00021
    00022 #define ALT_F6          2
    00023 #define ALT_ESCAPE      1
    00024
    00025 #define FDIR_FORWARD    0
    00026 #define FDIR_BACKWARD   1
    00027
    00028
    00029 /*
    00030  *  Win95 hard codes the size of the icon matrix, the size of
    00031  *  the icons, the highlight border and the icon spacing
    00032  */
    00033 #define CXICONSLOT      43
    00034 #define CYICONSLOT      43
    00035 #define CXICONSIZE      32
    00036 #define CYICONSIZE      32
    00037 #define MAXTASKNAMELEN  50
    00038
    00039
    00040
    00041 VOID xxxPaintIconsInSwitchWindow(PWND, PSWINFO, HDC, INT, INT, INT, BOOL, BOOL, PICON);
    00042
    00043 /***************************************************************************\
    00044 * Getpswi
    00045 *
    00046 * 04-29-96 GerardoB  Created
    00047 \***************************************************************************/
    00048 __inline PSWINFO Getpswi (PWND pwnd)
    00049 {
    00050     UserAssert(GETFNID(pwnd) == FNID_SWITCH);
    00051     return ((PSWITCHWND)pwnd)->pswi;
    00052 }
    00053 /***************************************************************************\
    00054 * Setpswi
    00055 *
    00056 * 04-29-96 GerardoB  Created
    00057 \***************************************************************************/
    00058 __inline void Setpswi (PWND pwnd, PSWINFO pswi)
    00059 {
    00060     UserAssert(GETFNID(pwnd) == FNID_SWITCH);
    00061     ((PSWITCHWND)pwnd)->pswi = pswi;
    00062 }
    00063 /***************************************************************************\
    00064 * DSW_GetTopLevelCreatorWindow
    00065 *
    00066 *
    00067 \***************************************************************************/
    00068
    00069 PWND DSW_GetTopLevelCreatorWindow(
    00070     PWND pwnd)
    00071 {
    00072     UserAssert(pwnd != NULL);
    00073
    00074     if (pwnd != NULL) {
    00075         while (pwnd->spwndOwner)
    00076             pwnd = pwnd->spwndOwner;
    00077     }
    00078
    00079     return pwnd;
    00080 }
    00081
    00082 /***************************************************************************\
    00083 * GetNextQueueWindow
    00084 *
    00085 * This routine is used to implement the Alt+Esc feature.  This feature lets
    00086 * the user switch between windows for different applications (a.k.a. "Tasks")
    00087 * currently running.  We keep track of the most recently active window in
    00088 * each task.  This routine starts with the window passed and searches for the
    00089 * next window, in the "top-level" window list, that is from a different task
    00090 * than the one passed.  We then return the most recenly active window from
    00091 * that task (or the window we found if the most recently active has been
    00092 * destroyed or is currently disabled or hidden).  This routine returns NULL
    00093 * if no other enabled, visible window for another task can be found.
    00094 *
    00095 * History:
    00096 * 30-May-1991 DavidPe   Ported from Win 3.1 sources.
    00097 \***************************************************************************/
    00098
    00099 PWND _GetNextQueueWindow(
    00100     PWND pwnd,
    00101     BOOL fPrev, /* 1 backward 0 forward */
    00102     BOOL fAltEsc)
    00103 {
    00104     PWND        pwndAltTab;
    00105     PWND        pwndNext;
    00106     PWND        pwndT;
    00107     PWND        pwndDesktop;
    00108     BOOL        bBeenHereAlready = FALSE;
    00109     PTHREADINFO ptiAltTab;
    00110
    00111     /*
    00112      * HACK: We have a problem with direct-draw full apps where an alttab
    00113      *       window is created on a queue owned other than the RIT.  This
    00114      *       shows up by alt-tabbing away from ROIDS.EXE during fullscreen.
    00115      *
    00116      *       What is happening is on a ALT-TAB, from xxxSysCommand(), the
    00117      *       thread is not a rit.  xxxSysCommand() calls xxxOldNextWindow
    00118      *       which finds that the current-thread doesn't have a switch
    00119      *       window, and then creates one on the current-thread-queue.
    00120      *
    00121      *       The hack here is to make sure the calling thread is the RIT
    00122      *       before allowing any cool-switch creation.
    00123      *
    00124      *       21-Mar-1996 : Chriswil
    00125      */
    00126 #if 0
    00127     ptiAltTab = PtiCurrent();
    00128 #else
    00129     ptiAltTab = gptiRit;
    00130 #endif
    00131
    00132     /*
    00133      * If the window we receive is Null then use the last topmost window
    00134      */
    00135     if (!pwnd) {
    00136         pwnd = GetLastTopMostWindow();
    00137         if (!pwnd) {
    00138             return NULL;
    00139         }
    00140     }
    00141
    00142     pwndAltTab = gspwndAltTab;
    00143
    00144     pwnd = pwndNext = GetTopLevelWindow(pwnd);
    00145     if (!pwndNext)
    00146         return NULL;
    00147
    00148     /*
    00149      * Get the window's desktop
    00150      */
    00151     if ((pwndDesktop = pwndNext->spwndParent) == NULL) {
    00152         pwndDesktop = grpdeskRitInput->pDeskInfo->spwnd;
    00153         pwnd = pwndNext = pwndDesktop->spwndChild;
    00154     }
    00155
    00156     while (TRUE) {
    00157
    00158         if (pwndNext == NULL)
    00159             return NULL;
    00160
    00161         /*
    00162          *  Get the next window
    00163          */
    00164         pwndNext = _GetWindow(pwndNext, fPrev ? GW_HWNDPREV : GW_HWNDNEXT);
    00165
    00166         if (!pwndNext) {
    00167
    00168             pwndNext = fPrev ? _GetWindow(pwndDesktop->spwndChild, GW_HWNDLAST)
    00169                              : pwndDesktop->spwndChild;
    00170             /*
    00171              * To avoid searching the child chain forever, bale out if we get
    00172              * to the end (beginning) of the chain twice.
    00173              * This happens if pwnd is a partially destroyed window that has
    00174              * been unlinked from its siblings but not yet unlinked from the
    00175              * parent. (Happens while sending WM_NCDESTROY in xxxFreeWindow)
    00176              */
    00177             if (bBeenHereAlready) {
    00178                 RIPMSG1(RIP_WARNING, "pwnd %#p is no longer a sibling", pwnd);
    00179                 return NULL;
    00180             }
    00181
    00182             bBeenHereAlready = TRUE;
    00183         }
    00184
    00185         /*
    00186          *  If we have gone all the way around with no success, return NULL.
    00187          */
    00188         if (!pwndNext || (pwndNext == pwnd))
    00189             return NULL;
    00190
    00191         /*
    00192          *  Ignore the following windows:
    00193          *      Switch window
    00194          *      Tool Windows
    00195          *      NoActivate Windows
    00196          *      Hidden windows
    00197          *      Disabled windows
    00198          *      Topmost windows if via Alt+Esc
    00199          *      Bottommost windows if via Alt+Esc
    00200          *
    00201          *  If we're doing Alt-Esc processing, we have to skip topmost windows.
    00202          *
    00203          *  Because topmost windows don't really go to the back when we
    00204          *  send them there, alt-esc would never enumerate non-topmost windows.
    00205          *  So, although we're allowed to start enumeration at a topmost window,
    00206          *  we only allow enumeration of non-topmost windows, so the user can
    00207          *  enumerate his presumably more important applications.
    00208          */
    00209         if ((pwndNext != pwndAltTab) &&
    00210 // BradG - Win95 is missing the check for Tool Windows
    00211             (!TestWF(pwndNext, WEFTOOLWINDOW)) &&
    00212             (!TestWF(pwndNext, WEFNOACTIVATE)) &&
    00213             (TestWF(pwndNext, WFVISIBLE)) &&
    00214             ((pwndNext->spwndLastActive == NULL) || (!TestWF(pwndNext->spwndLastActive, WFDISABLED)) &&
    00215             (!fAltEsc || (!TestWF(pwndNext, WEFTOPMOST) && !TestWF(pwndNext, WFBOTTOMMOST))))) {
    00216             /*
    00217              * If this window is owned, don't return it unless it is the most
    00218              * recently active window in its owner/ownee group.
    00219              */
    00220             /*
    00221              *  Hard loop to find top level owner
    00222              */
    00223             for (pwndT = pwndNext; pwndT->spwndOwner; pwndT = pwndT->spwndOwner)
    00224                 ;
    00225
    00226             /*
    00227              *  Don't return it unless it is the most recently active
    00228              *  window in its owner/ownee group.
    00229              */
    00230             if (pwndNext == pwndT->spwndLastActive)
    00231                 return pwndNext;
    00232         }
    00233     }
    00234 }
    00235
    00236 /***************************************************************************\
    00237 *
    00238 * SwitchToThisWindow()
    00239 *
    00240 * This function was added specifically for Win386.  It is called to tell
    00241 * USER that a particular window has been switched to via Alt+Tab or
    00242 * Alt+Esc in the Win386 environment.  They call this function to maintain
    00243 * Z-ordering and consistent operation of these two functions.  This function
    00244 * must be exported, but need not be documented.
    00245 *
    00246 * The parameter fTab is TRUE if this window is to be switched to via an
    00247 * Alt/Ctl+Tab key sequence otherwise it must be FALSE.
    00248 *
    00249 * History:
    00250 * 04-Feb-1991 DarrinM   Created.
    00251 \***************************************************************************/
    00252
    00253 VOID xxxSwitchToThisWindow(
    00254     PWND pwnd,
    00255     BOOL fAltTab)
    00256 {
    00257     CheckLock(pwnd);
    00258
    00259     /*
    00260      *  If we need to, push old window to the bottom.
    00261      */
    00262     if (gpqForeground && !fAltTab) {
    00263
    00264         BOOL fPush;
    00265         PWND pwndActive;
    00266         TL   tlpwndActive;
    00267
    00268         /*
    00269          *  if ALT-ESC, and the window brought forward is the next one in the
    00270          *  list, we must be rotating the zorder forward, so push the current
    00271          *  window to the back
    00272          */
    00273         pwndActive = gpqForeground->spwndActive;
    00274         fPush = pwndActive && _GetNextQueueWindow(pwndActive, FDIR_FORWARD, !fAltTab);
    00275         if (fPush && !TestWF(pwndActive, WEFTOPMOST) && !TestWF(pwndActive, WFBOTTOMMOST)) {
    00276             ThreadLock(pwndActive, &tlpwndActive);
    00277             xxxSetWindowPos(pwndActive, PWND_BOTTOM, 0, 0, 0, 0,
    00278                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_ASYNCWINDOWPOS);
    00279             ThreadUnlock(&tlpwndActive);
    00280         }
    00281     }
    00282
    00283     /*
    00284      *  Switch this new window to the foreground
    00285      *  This window can go away during the SetForeground call if it isn't
    00286      *  on the thread calling SwitchToThisWindow()!
    00287      */
    00288     xxxSetForegroundWindow(pwnd, TRUE);
    00289
    00290     /*
    00291      * Restore minimized windows if the Alt+Tab case
    00292      */
    00293     if (fAltTab && TestWF(pwnd,WFMINIMIZED)) {
    00294
    00295         /*
    00296          * We need to package up a special 'posted' queue message here.  This
    00297          * ensures that this message gets processed after the asynchronous
    00298          * activation event occurs (via SetForegroundWindow).
    00299          */
    00300         PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq,
    00301                          QEVENT_POSTMESSAGE, pwnd, WM_SYSCOMMAND,
    00302                          SC_RESTORE, 0 );
    00303     }
    00304 }
    00305
    00306 /***************************************************************************\
    00307 * NextPrevTaskIndex
    00308 *
    00309 * History:
    00310 * 01-Jun-1995 BradG     Ported from Win95
    00311 \***************************************************************************/
    00312
    00313 INT NextPrevTaskIndex(
    00314     PSWINFO pswInfo,
    00315     INT     iIndex,
    00316     INT     iCount,
    00317     BOOL    fNext)
    00318 {
    00319     UserAssert(iCount <= pswInfo->iTotalTasks);
    00320
    00321     if (fNext) {
    00322         iIndex += iCount;
    00323         if(iIndex >= pswInfo->iTotalTasks)
    00324             iIndex -= pswInfo->iTotalTasks;
    00325     } else {
    00326         iIndex -= iCount;
    00327         if(iIndex < 0)
    00328             iIndex += pswInfo->iTotalTasks;
    00329     }
    00330
    00331     UserAssert((iIndex >= 0) && (iIndex < pswInfo->iTotalTasks));
    00332     return iIndex;
    00333 }
    00334
    00335 /***************************************************************************\
    00336 * NextPrevPhwnd
    00337 *
    00338 * Given a pointer to one entry in the window list, this can return
    00339 * the pointer to the next/prev entry in a circular list fashion.
    00340 *
    00341 * History:
    00342 * 01-Jun-1995 BradG     Ported from Win95
    00343 \***************************************************************************/
    00344
    00345 PHWND NextPrevPhwnd(
    00346     PSWINFO pswInfo,
    00347     PHWND   phwnd,
    00348     BOOL    fNext)
    00349 {
    00350     PBWL  pbwl;
    00351     PHWND phwndStart;
    00352     PHWND phwndLast;
    00353
    00354     pbwl = pswInfo->pbwl;
    00355     phwndStart = &(pbwl->rghwnd[0]);
    00356     phwndLast = pswInfo->phwndLast;
    00357
    00358     UserAssert(*phwndLast == (HWND)1);   // Last entry must have a 1.
    00359     UserAssert(phwndStart < phwndLast);  // There must be atleast one entry.
    00360     UserAssert(phwnd != phwndLast);      // Can't be passing in an invalid entry.
    00361
    00362     if (fNext) {
    00363         phwnd++;
    00364         if(phwnd == phwndLast)
    00365             phwnd = phwndStart;
    00366     } else {
    00367         if (phwnd == phwndStart) {
    00368             phwnd = phwndLast - 1;  // we have atleast one valid entry.
    00369         } else {
    00370             phwnd--;
    00371         }
    00372     }
    00373
    00374     return phwnd;
    00375 }
    00376
    00377 /***************************************************************************\
    00378 * _IsTaskWindow
    00379 *
    00380 * History:
    00381 * 01-Jun-95 BradG       Ported from Win95
    00382 \***************************************************************************/
    00383
    00384 BOOL _IsTaskWindow(
    00385     PWND pwnd,
    00386     PWND pwndActive)
    00387 {
    00388     /*
    00389      *  Following windows do not qualify to be shown in task list:
    00390      *  Switch  Window, Hidden windows (unless they are the active
    00391      *  window), Disabled windows, Kanji Conv windows.
    00392      *
    00393      *  Also, check for a combobox popup list which has the top-most
    00394      *  style (it's spwndLastActive will be NULL).
    00395      */
    00396     UserAssert(pwnd != NULL);
    00397     return( (TestWF(pwnd, WEFAPPWINDOW)
    00398                 || (!TestWF(pwnd, WEFTOOLWINDOW) && !TestWF(pwnd, WEFNOACTIVATE))) &&
    00399             (TestWF(pwnd, WFVISIBLE) || (pwnd == pwndActive)) &&
    00400             (!(pwnd->spwndLastActive && TestWF(pwnd->spwndLastActive, WFDISABLED))));
    00401 }
    00402
    00403 /***************************************************************************\
    00404 * RemoveNonTaskWindows()
    00405 *
    00406 * Given a list of Windows, this walks down the list and removes the
    00407 * windows that do not qualify to be shown in the Task-Switch screen.
    00408 * This also shrinks the list when it removes some entries.
    00409 * Returns the total number of "tasks" (windows) qualified and remained
    00410 * in the list. The last entry will have a 1 as usual.
    00411 * It also returns a pointer to this last entry via params. It also
    00412 * returns the index of the Currently active task via params.
    00413 *
    00414 * History:
    00415 * 01-Jun-1995 BradG     Ported from Win95
    00416 \***************************************************************************/
    00417
    00418 INT _RemoveNonTaskWindows(
    00419     PBWL  pbwl,
    00420     PWND  pwndActive,
    00421     LPINT lpiActiveTask,
    00422     PHWND *pphwndLast)
    00423 {
    00424     INT   iTaskCount = 0;
    00425     PHWND phwnd;
    00426     PWND  pwnd;
    00427     PWND  pwndUse;
    00428     PWND  pwndOwnee;
    00429     PHWND phwndHole;
    00430
    00431     *lpiActiveTask = -1;
    00432
    00433     /*
    00434      * Walk down the window list and do the following:
    00435      *   1. Remove all entries that do not qualify to be shown in the task list.
    00436      *   2. Count the total number of windows that qualify.
    00437      *   3. Get the pointer to the entry that contains current active window.
    00438      *   4. Get the pointer to the last dummy entry (that has 1 in it)
    00439      */
    00440     for (phwndHole = phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
    00441         pwnd = RevalidateHwnd( *phwnd );
    00442 // BradG - Win95 Assert
    00443 //         Maybe we just want to remove this window if it is gone.
    00444 //        UserAssert(pwnd != NULL);
    00445         if (!pwnd)
    00446             continue;
    00447
    00448         if (_IsTaskWindow(pwnd, pwndActive)) {
    00449             pwndUse = pwnd;
    00450
    00451 // BradG - Why is Win95 doing this?
    00452 //         We aren't making any callbacks.
    00453 //            Assert(IsWindow32(hwndUse));
    00454
    00455             /*
    00456              *  First let's find the task-list owner of this window
    00457              */
    00458             while (!TestWF(pwndUse, WEFAPPWINDOW) && pwndUse->spwndOwner) {
    00459                 pwndOwnee = pwndUse;
    00460                 pwndUse = pwndUse->spwndOwner;
    00461                 if (TestWF(pwndUse, WEFTOOLWINDOW)) {
    00462                     /*
    00463                      * If this is the owner of a top level property sheet,
    00464                      *  show the property sheet.
    00465                      */
    00466                     if (TestWF(pwndOwnee, WEFCONTROLPARENT) && (pwndUse->spwndOwner == NULL)) {
    00467                         pwndUse = pwnd;
    00468                     } else {
    00469                         pwndUse = NULL;
    00470                     }
    00471                     break;
    00472                 }
    00473             }
    00474
    00475             if (!pwndUse || !pwndUse->spwndLastActive)
    00476                 continue;
    00477
    00478             /*
    00479              *  walk up from the last active window 'til we find a valid task
    00480              *  list window or until we run out of windows in the ownership
    00481              *  chain
    00482              */
    00483             for (pwndUse = pwndUse->spwndLastActive; pwndUse; pwndUse = pwndUse->spwndOwner)
    00484                 if (_IsTaskWindow(pwndUse, pwndActive))
    00485                     break;
    00486
    00487             /*
    00488              *  if we ran out of windows in the ownership chain then use the
    00489              *  owned window itself -- or if we didn't run out of the ownership
    00490              *  chain, then only include this window if it's the window in the
    00491              *  ownership chain that we just found (VB will love us for it !)
    00492              *  -- jeffbog -- 4/20/95 -- Win95C B#2821
    00493              */
    00494             if (!pwndUse || (pwndUse == pwnd)) {
    00495
    00496                 /*
    00497                  *  Do we have any holes above this? If so, move this handle to
    00498                  *  that hole.
    00499                  */
    00500                 if (phwndHole < phwnd) {
    00501
    00502                     /*
    00503                      * Yes! There is a hole. Let us move the valid
    00504                      * handle there.
    00505                      */
    00506                     *phwndHole = *phwnd;
    00507                 }
    00508
    00509                 if (pwndActive == pwnd)
    00510                     *lpiActiveTask = iTaskCount;
    00511                 iTaskCount++;
    00512                 phwndHole++;  // Move to the next entry.
    00513             }
    00514
    00515             /*
    00516              *  Else, leave it as a hole for later filling.
    00517              */
    00518         }
    00519     }
    00520
    00521     *phwndHole = (HWND)1;
    00522     *pphwndLast = phwndHole;
    00523
    00524     return iTaskCount;
    00525 }
    00526
    00527 /***************************************************************************\
    00528 * DrawSwitchWndHilite()
    00529 *
    00530 * This draws or erases the Hilite we draw around the icon to show which
    00531 * task we are going to switch to.
    00532 * This also updates the name on the Task title window.
    00533 *
    00534 * History:
    00535 * 01-Jun-1995 BradG     Ported from Win95
    00536 \***************************************************************************/
    00537
    00538 VOID DrawSwitchWndHilite(
    00539     PSWINFO pswInfo,
    00540     HDC     hdcSwitch,
    00541     int     iCol,
    00542     int     iRow,
    00543     BOOL    fShow)
    00544 {
    00545     BOOL        fGetAndReleaseIt;
    00546     RECT        rcTemp;
    00547     PTHREADINFO ptiAltTab;
    00548     /*
    00549      * HACK: We have a problem with direct-draw full apps where an alttab
    00550      *       window is created on a queue owned other than the RIT.  This
    00551      *       shows up by alt-tabbing away from ROIDS.EXE during fullscreen.
    00552      *
    00553      *       What is happening is on a ALT-TAB, from xxxSysCommand(), the
    00554      *       thread is not a rit.  xxxSysCommand() calls xxxOldNextWindow
    00555      *       which finds that the current-thread doesn't have a switch
    00556      *       window, and then creates one on the current-thread-queue.
    00557      *
    00558      *       The hack here is to make sure the calling thread is the RIT
    00559      *       before allowing any cool-switch creation.
    00560      *
    00561      *       21-Mar-1996 : Chriswil
    00562      */
    00563 #if 0
    00564     ptiAltTab = PtiCurrent();
    00565 #else
    00566     ptiAltTab = gptiRit;
    00567 #endif
    00568
    00569     /*
    00570      *  Draw or erase the hilite depending on "fShow".
    00571      */
    00572     if (fGetAndReleaseIt = (hdcSwitch == NULL))
    00573         hdcSwitch = _GetDCEx(gspwndAltTab, NULL, DCX_USESTYLE);
    00574
    00575     rcTemp.left   = pswInfo->ptFirstRowStart.x + iCol * CXICONSLOT;
    00576     rcTemp.top    = pswInfo->ptFirstRowStart.y + iRow * CYICONSLOT;
    00577     rcTemp.right  = rcTemp.left + CXICONSLOT;
    00578     rcTemp.bottom = rcTemp.top + CYICONSLOT;
    00579
    00580     DrawFrame(hdcSwitch,
    00581               &rcTemp,
    00582               2,
    00583               DF_PATCOPY | ((fShow ? COLOR_HIGHLIGHT : COLOR_3DFACE) << 3));
    00584
    00585
    00586     /*
    00587      *  Update the Task title window.
    00588      */
    00589     if (fShow) {
    00590         WCHAR    szText[CCHTITLEMAX];
    00591         INT      cch;
    00592         COLORREF clrOldText, clrOldBk;
    00593         PWND     pwnd;
    00594         RECT     rcRect;
    00595         HFONT    hOldFont;
    00596         INT      iLeft;
    00597         ULONG_PTR dwResult = 0;
    00598
    00599         clrOldText = GreSetTextColor(hdcSwitch, SYSRGB(BTNTEXT));
    00600         clrOldBk   = GreSetBkColor(hdcSwitch, SYSRGB(3DFACE));
    00601         hOldFont = GreSelectFont(hdcSwitch, gpsi->hCaptionFont);
    00602
    00603
    00604         /*
    00605          * Validate this window handle; This could be some app that terminated
    00606          * in the background and the following line will GP fault in that case;
    00607          * BOGUS: We should handle it some other better way.
    00608          */
    00609         pwnd = RevalidateHwnd( *(pswInfo->phwndCurrent) );
    00610         if (pwnd) {
    00611             /*
    00612              *  Get the windows title (up to MAXTASKNAMELEN's worth)
    00613              */
    00614 // BradG - We can do better than MAXTASKNAMELEN characters!
    00615             if (pwnd->strName.Length) {
    00616                 cch = TextCopy(&pwnd->strName, szText, CCHTITLEMAX);
    00617             } else {
    00618                 *szText = TEXT('\0');
    00619                 cch = 0;
    00620             }
    00621
    00622             /*
    00623              *  Draw the text
    00624              */
    00625             CopyRect(&rcRect, &pswInfo->rcTaskName);
    00626             iLeft = rcRect.left;
    00627             FillRect(hdcSwitch, &rcRect, SYSHBR(3DFACE));
    00628             /*
    00629              * If an lpk is installed let it draw the text.
    00630              */
    00631             if (GETPWNDPPI(pwnd)->dwLpkEntryPoints) {
    00632                 TL    tlpwnd;
    00633                 LPKDRAWSWITCHWND LpkDrawSwitchWnd;
    00634
    00635                 RtlInitLargeUnicodeString(&LpkDrawSwitchWnd.strName, szText, (UINT)-1);
    00636                 LpkDrawSwitchWnd.rcRect = rcRect;
    00637
    00638                 ThreadLock(pwnd, &tlpwnd);
    00639                 xxxSendMessageTimeout(pwnd, WM_LPKDRAWSWITCHWND, (WPARAM)hdcSwitch,
    00640                         (LPARAM)&LpkDrawSwitchWnd, SMTO_ABORTIFHUNG, 100, &dwResult);
    00641                 ThreadUnlock(&tlpwnd);
    00642             }
    00643             /*
    00644              * If the text wasn't draw by the lpk, draw it as best we can.
    00645              */
    00646             if (dwResult == 0) {
    00647                 DRAWTEXTPARAMS  dtp;
    00648
    00649                 dtp.cbSize = sizeof(dtp);
    00650                 dtp.iLeftMargin = 0;
    00651                 dtp.iRightMargin = 0;
    00652                 DrawTextEx(hdcSwitch, szText, cch, &rcRect, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE, &dtp );
    00653             }
    00654         }
    00655
    00656         GreSelectFont(hdcSwitch, hOldFont);
    00657         GreSetBkColor(hdcSwitch, clrOldBk);
    00658         GreSetTextColor(hdcSwitch, clrOldText);
    00659     }
    00660
    00661     if (fGetAndReleaseIt)
    00662         _ReleaseDC(hdcSwitch);
    00663 }
    00664
    00665 /***************************************************************************\
    00666 * DrawIconCallBack
    00667 *
    00668 * This function is called by a Windows app returning his icon.
    00669 *
    00670 * History:
    00671 * 17-Jun-1993 mikesch       Created.
    00672 \***************************************************************************/
    00673
    00674 VOID CALLBACK DrawIconCallBack(
    00675     HWND    hwnd,
    00676     UINT    uMsg,
    00677     ULONG_PTR dwData,
    00678     LRESULT lResult)
    00679 {
    00680     PWND pwndAltTab;
    00681
    00682     /*
    00683      *  dwData is the pointer to the switch window handle.
    00684      *  If this Alt+Tab instance is still active, we need to derive this
    00685      *  window's index in the bwl array, otherwise, we are receiving an icon
    00686      *  for an old Alt+Tab window.
    00687      */
    00688     pwndAltTab = RevalidateHwnd((HWND)dwData);
    00689     if (pwndAltTab && TestWF(pwndAltTab, WFVISIBLE)) {
    00690
    00691         PSWINFO pswCurrent;
    00692         PICON   pIcon;
    00693         PHWND   phwnd;
    00694         PWND    pwnd;
    00695         PWND    pwndT;
    00696         INT     iStartTaskIndex;
    00697         TL      tlpwndAltTab;
    00698
    00699         /*
    00700          *  Derive this window's index in the BWL array
    00701          */
    00702         if ((pwnd = RevalidateHwnd(hwnd)) == NULL)
    00703             return;
    00704
    00705         /*
    00706          *  Get the switch window info
    00707          */
    00708         pswCurrent = Getpswi(pwndAltTab);
    00709         if (!pswCurrent)
    00710             return;
    00711
    00712         for (iStartTaskIndex = 0, phwnd=&(pswCurrent->pbwl->rghwnd[0]); *phwnd != (HWND)1; phwnd++, iStartTaskIndex++) {
    00713             /*
    00714              *  Because we list the active window in the Switch Window, the
    00715              *  hwnd here might not be the same, so we also need to walk back
    00716              *  to the top-level window to see if this is the right entry
    00717              *  in the list.
    00718              */
    00719             for(pwndT = RevalidateHwnd(*phwnd); pwndT; pwndT = pwndT->spwndOwner) {
    00720                 if (pwnd == pwndT)
    00721                     goto DrawIcon;
    00722             }
    00723         }
    00724         return;
    00725
    00726         /*
    00727          *  Convert the App's HICON into a PICON, or if the App did not return
    00728          *  an icon, use the Windows default icon.
    00729          */
    00730 DrawIcon:
    00731         pIcon = NULL;
    00732         if (lResult)
    00733             pIcon = HMValidateHandleNoRip((HCURSOR)lResult, TYPE_CURSOR);
    00734
    00735         if (!pIcon)
    00736             pIcon = SYSICO(WINLOGO);
    00737
    00738         /*
    00739          *  Paint this icon in the Alt+Tab window.
    00740          */
    00741         ThreadLockAlways(pwndAltTab, &tlpwndAltTab);
    00742         xxxPaintIconsInSwitchWindow(pwndAltTab,
    00743                                     pswCurrent,
    00744                                     NULL,
    00745                                     iStartTaskIndex,
    00746                                     0,
    00747                                     1,
    00748                                     FALSE,
    00749                                     FALSE,
    00750                                     pIcon);
    00751         ThreadUnlock(&tlpwndAltTab);
    00752     }
    00753
    00754     UNREFERENCED_PARAMETER(uMsg);
    00755 }
    00756
    00757 /***************************************************************************\
    00758 * TSW_CalcRowAndCol
    00759 *
    00760 * History:
    00761 * 01-Jun-1995 BradG     Ported from Win95
    00762 \***************************************************************************/
    00763
    00764 BOOL TSW_CalcRowAndCol(
    00765     PSWINFO pswInfo,
    00766     INT     iTaskIndex,
    00767     LPINT   lpiRow,
    00768     LPINT   lpiCol)
    00769 {
    00770     INT iDiff;
    00771     INT iRow;
    00772
    00773     /*
    00774      *  Calculate how far is the given task from the first task shown
    00775      *  on the switch window.
    00776      */
    00777     if ((iDiff = (iTaskIndex - pswInfo->iFirstTaskIndex)) < 0)
    00778         iDiff += pswInfo->iTotalTasks;
    00779
    00780     /*
    00781      *  Calculate the Row and if this lies outside the switch window, return FALSE
    00782      */
    00783     if ((iRow = iDiff / pswInfo->iNoOfColumns) >= pswInfo->iNoOfRows)
    00784         return FALSE;
    00785
    00786     /*
    00787      *  Return the Row and column where this task lies.
    00788      */
    00789     *lpiRow = iRow;
    00790     *lpiCol = iDiff - (iRow * pswInfo->iNoOfColumns);
    00791
    00792     return TRUE;  // This task lies within the switch window.
    00793 }
    00794
    00795 /***************************************************************************\
    00796 * xxxPaintIconsInSwitchWindow()
    00797 *
    00798 * This can simply paint the icons in the switch window or Scroll the
    00799 * whole window UP/DOWN and then paint the remaining area;
    00800 *   * If fScroll is TRUE, then the second, third and fourth params are ignored.
    00801 *   * If hIcon is passed in, then we're being called by DrawIconCallBack and
    00802 *       iStartRow parameter is ignored in this case.
    00803 *
    00804 * History:
    00805 * 02-Jun-1995 BradG     Ported from Win95
    00806 \***************************************************************************/
    00807
    00808 VOID xxxPaintIconsInSwitchWindow(
    00809     PWND    pwndAltTab,
    00810     PSWINFO pswInfo,
    00811     HDC     hdc,
    00812     INT     iStartTaskIndex,
    00813     INT     iStartRow,
    00814     INT     iNoOfIcons,
    00815     BOOL    fScroll,
    00816     BOOL    fUp,
    00817     PICON   pIcon)
    00818 {
    00819     INT   cx, cy, xStart;
    00820     PHWND phwnd;
    00821     BOOL  fGetAndReleaseIt;
    00822     INT   iColumnIndex = 0;
    00823     RECT  rcScroll;
    00824     PWND  pwnd;
    00825     TL    tlpwnd;
    00826     HICON hIcon;
    00827     RECT  rcIcon;
    00828
    00829     CheckLock(pwndAltTab);
    00830
    00831     /*
    00832      *  If we were not supplied a DC, get ghwndSwitch's and set a flag
    00833      *  so we remember to release it.
    00834      */
    00835     if (fGetAndReleaseIt = (hdc == NULL))
    00836         hdc = _GetDCEx(pwndAltTab, NULL, DCX_USESTYLE);
    00837
    00838     cx = pswInfo->ptFirstRowStart.x;
    00839     cy = pswInfo->ptFirstRowStart.y;
    00840
    00841     if (fScroll) {
    00842
    00843         rcScroll.left   = cx;
    00844         rcScroll.top    = cy;
    00845         rcScroll.right  = cx + CXICONSLOT * pswInfo->iNoOfColumns;
    00846         rcScroll.bottom = cy + CYICONSLOT * pswInfo->iNoOfRows;
    00847
    00848         _ScrollDC(hdc,
    00849                   0,
    00850                   (fUp ? -CYICONSLOT : CYICONSLOT),
    00851                   &rcScroll,
    00852                   &rcScroll,
    00853                   NULL,
    00854                   NULL);
    00855
    00856         iStartRow = (fUp ? pswInfo->iNoOfRows - 1 : 0);
    00857         iNoOfIcons = pswInfo->iNoOfColumns;
    00858         iStartTaskIndex = (fUp ? NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
    00859                   (pswInfo->iNoOfRows - 1) * pswInfo->iNoOfColumns, TRUE) :
    00860                    pswInfo->iFirstTaskIndex);
    00861     }
    00862
    00863     if (pIcon) {
    00864         /*
    00865          *  If pIcon is given, this is to paint just one icon during callback.
    00866          */
    00867 // BradG - Win95 Assert
    00868         UserAssert(iNoOfIcons == 1);
    00869
    00870         /*
    00871          *  Due to earlier scrolling, the row number would have changed. So,
    00872          *  recalc the row and column from the iStartTaskIndex given.
    00873          */
    00874         if (!TSW_CalcRowAndCol(pswInfo, iStartTaskIndex, &iStartRow, &iColumnIndex))
    00875             goto Cleanup;
    00876     }
    00877
    00878     xStart = cx += (CXICONSLOT - CXICONSIZE) / 2;
    00879     cx += iColumnIndex * CXICONSLOT;
    00880     cy += ((CYICONSLOT - CYICONSIZE) / 2) + iStartRow * CYICONSLOT;
    00881     phwnd = &(pswInfo->pbwl->rghwnd[iStartTaskIndex]);
    00882
    00883     /*
    00884      *  Draw all the icons one by one.
    00885      */
    00886     while (iNoOfIcons--) {
    00887         /*
    00888          *  If the Alt+Key is no longer down, abort painting icons.
    00889          */
    00890         if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    00891                 (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
    00892             goto Cleanup;
    00893
    00894         /*
    00895          *  Check if this window is still alive. (Some task could have
    00896          *  terminated in the background)
    00897          */
    00898         if (pwnd = RevalidateHwnd(*phwnd)) {
    00899             /*
    00900              *  Find the window's top-level owner
    00901              */
    00902             pwnd = DSW_GetTopLevelCreatorWindow(pwnd);
    00903
    00904             /*
    00905              *  If we don't have an icon, find one
    00906              */
    00907             if (!pIcon) {
    00908                 /*
    00909                  *  Try window icon
    00910                  */
    00911                 hIcon = (HICON)_GetProp(pwnd, MAKEINTATOM(gpsi->atomIconProp), PROPF_INTERNAL);
    00912                 if (hIcon) {
    00913                     pIcon = (PICON)HMValidateHandleNoRip(hIcon, TYPE_CURSOR);
    00914                 }
    00915
    00916                 /*
    00917                  * If we don't have an icon yet, try the class icon
    00918                  */
    00919                 if (!pIcon) {
    00920                     pIcon = pwnd->pcls->spicn;
    00921                 }
    00922
    00923                 /*
    00924                  * If we don't have an icon yet, use WM_QUERYDRAGICON to ask
    00925                  * 3,x apps for their icon.
    00926                  */
    00927                 if (!pIcon && !TestWF(pwnd, WFWIN40COMPAT)) {
    00928                     /*
    00929                      *  The callback routine will paint the icon for
    00930                      *  us, so just leave pIcon set to NULL
    00931                      */
    00932                     ThreadLock(pwnd, &tlpwnd);
    00933                     xxxSendMessageCallback(pwnd, WM_QUERYDRAGICON, 0, 0,
    00934                             (SENDASYNCPROC)DrawIconCallBack,
    00935                             HandleToUlong(PtoH(pwndAltTab)), FALSE);
    00936                     ThreadUnlock(&tlpwnd);
    00937                 } else {
    00938                     /*
    00939                      *  If we can't find an icon, so use the Windows icon
    00940                      */
    00941                     if (!pIcon) {
    00942                         pIcon = SYSICO(WINLOGO);
    00943                     }
    00944                 }
    00945             }
    00946         }
    00947
    00948         if (pIcon) {
    00949             _DrawIconEx(hdc, cx, cy, pIcon, SYSMET(CXICON), SYSMET(CYICON),
    00950                 0, SYSHBR(3DFACE), DI_NORMAL);
    00951         } else if (fScroll) {
    00952             /*
    00953              *  NOT IN WIN95
    00954              *
    00955              *  No icon was available, do while we are waiting for the
    00956              *  application to paint it's icon, we need to "erase" the
    00957              *  background in case we have scrolled the window.
    00958              */
    00959             rcIcon.left = cx;
    00960             rcIcon.top = cy;
    00961             rcIcon.right = cx + SYSMET(CXICON);
    00962             rcIcon.bottom = cy + SYSMET(CYICON);
    00963             FillRect(hdc, &rcIcon, SYSHBR(3DFACE));
    00964         }
    00965
    00966         /*
    00967          *  Check if we are done.
    00968          */
    00969         if (iNoOfIcons <= 0)
    00970             break;
    00971
    00972         /*
    00973          *  Reset hIcon for the next run through the loop
    00974          */
    00975         pIcon = NULL;
    00976
    00977         /*
    00978          *  Move all pointers to the next task/icon.
    00979          */
    00980         phwnd = NextPrevPhwnd(pswInfo, phwnd, TRUE); // Get next.
    00981
    00982         /*
    00983          *  Is it going to be in the same row; then adjust cx and cy.
    00984          */
    00985         if (++iColumnIndex >= pswInfo->iNoOfColumns) {
    00986             iColumnIndex = 0;
    00987             cx = xStart;        // Move to first column
    00988             cy += CYICONSLOT;   // Move to next row.
    00989             iStartRow++;
    00990         } else {
    00991             /*
    00992              *  else, adjust cx;
    00993              */
    00994             cx += CXICONSLOT;
    00995         }
    00996
    00997         iStartTaskIndex = NextPrevTaskIndex(pswInfo, iStartTaskIndex, 1, TRUE);
    00998     }
    00999
    01000 Cleanup:
    01001     if (fGetAndReleaseIt)
    01002         _ReleaseDC(hdc);
    01003 }
    01004
    01005 /***************************************************************************\
    01006 * PaintSwitchWindow
    01007 *
    01008 * History:
    01009 * 02-Jun-1995 BradG     Ported from Win95
    01010 \***************************************************************************/
    01011
    01012 VOID xxxPaintSwitchWindow(
    01013     PWND pwndSwitch)
    01014 {
    01015     LPRECT  lprcRect;
    01016     RECT    rcRgn;
    01017     HDC     hdcSwitch;
    01018     PSWINFO pswCurrent;
    01019     CheckLock(pwndSwitch);
    01020
    01021     /*
    01022      *  If our window isn't visible, return
    01023      */
    01024     if (!TestWF(pwndSwitch, WFVISIBLE))
    01025         return;
    01026
    01027     /*
    01028      *  Get the switch window information
    01029      */
    01030     pswCurrent = Getpswi(pwndSwitch);
    01031     if (!pswCurrent)
    01032         return;
    01033
    01034     /*
    01035      * Get the Switch windows DC so we can paint with it
    01036      */
    01037     hdcSwitch = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE );
    01038
    01039     /*
    01040      *  Paint the background of the Switch Screen.
    01041      */
    01042     if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    01043             (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
    01044         goto PSWExit;
    01045
    01046     lprcRect = &(pswCurrent->rcTaskName);
    01047     _GetClientRect(pwndSwitch, lprcRect);
    01048     FillRect(hdcSwitch, lprcRect, SYSHBR(3DFACE));
    01049
    01050     /*
    01051      * Store this "caption" area back into the current switch
    01052      * window data structure.
    01053      */
    01054     InflateRect(lprcRect, -(gcxCaptionFontChar << 1), -(gcyCaptionFontChar));
    01055     lprcRect->top = lprcRect->bottom - gcyCaptionFontChar;
    01056
    01057     /*
    01058      *  Draw the sunken edge for showing the task names.
    01059      */
    01060     if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    01061             (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
    01062         goto PSWExit;
    01063     CopyInflateRect(&rcRgn, lprcRect, gcxCaptionFontChar >> 1, gcyCaptionFontChar >> 1);
    01064     DrawEdge(hdcSwitch, &rcRgn, EDGE_SUNKEN, BF_RECT);
    01065
    01066     /*
    01067      *  Paint the icons
    01068      */
    01069     if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    01070             (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
    01071         goto PSWExit;
    01072
    01073     xxxPaintIconsInSwitchWindow(pwndSwitch,
    01074                                 pswCurrent,
    01075                                 hdcSwitch,
    01076                                 pswCurrent->iFirstTaskIndex,
    01077                                 0,
    01078                                 pswCurrent->iTasksShown,
    01079                                 FALSE,
    01080                                 FALSE,
    01081                                 NULL);
    01082
    01083     /*
    01084      *  So, just draw the hilite.
    01085      */
    01086     if ((pswCurrent->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    01087             (!pswCurrent->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0))
    01088         goto PSWExit;
    01089
    01090     DrawSwitchWndHilite(pswCurrent,
    01091                         hdcSwitch,
    01092                         pswCurrent->iCurCol,
    01093                         pswCurrent->iCurRow,
    01094                         TRUE);
    01095
    01096     /*
    01097      *  Release the switch windows DC
    01098      */
    01099 PSWExit:
    01100     _ReleaseDC(hdcSwitch);
    01101 }
    01102
    01103 /***************************************************************************\
    01104 * InitSwitchWndInfo()
    01105 *
    01106 * This function allocs and Initializes all the data structures
    01107 * required the build and show the tasks in the system.
    01108 * If there is insufficient mem, then this find the next window to switch
    01109 * to and returns it. In this case, we will behave as if the end user hit
    01110 * ALT+ESC. The SWitchScreen will not comeup in this case.
    01111 * If there is only one task in the whole system, then this function
    01112 * fails and returns a NULL. (No ALT+TAB processing is required).
    01113 * Otherwise, it allocs one SwitchWndInfo struc, fills it up and returns
    01114 * the window we gonna switch to.
    01115 *
    01116 * History:
    01117 * 02-Jun-95 BradG       Ported from Win95
    01118 \***************************************************************************/
    01119
    01120 PWND InitSwitchWndInfo(
    01121     PSWINFO *   lppswInfo,
    01122     PWND        pwndCurActive,
    01123     BOOL        fPrev)
    01124 {
    01125     PBWL            pbwl;
    01126     INT             iTotalTasks;
    01127     INT             iCols, iRows, iIconsInLastRow;
    01128     INT             iDiff;
    01129     PHWND           phwndLast;
    01130     PSWINFO         pswInfo;
    01131     INT             iIconIndex;
    01132     INT             iCurRow, iCurCol;
    01133     INT             cxSwitch, cySwitch;
    01134     INT             iFirstRowIcons;
    01135     INT             iActiveTask;
    01136     PWND            pwnd = NULL;
    01137     PTHREADINFO     ptiCurrent = PtiCurrent();
    01138     PDESKTOPINFO    pdeskinfo = GETDESKINFO(ptiCurrent);
    01139     PMONITOR        pMonitor = GetPrimaryMonitor();
    01140
    01141     /*
    01142      *  Initialize the list
    01143      */
    01144     *lppswInfo = (PSWINFO)NULL;
    01145
    01146     /*
    01147      *  Build the Window list of all the top level windows.
    01148      */
    01149 #if 0
    01150     if (!(pbwl = BuildHwndList(NULL, BWL_ENUMLIST | BWL_ALLDESKTOPS, NULL)))
    01151         goto ReturnNextWnd;
    01152 #else
    01153 // BradG - HACK, enumerate on current desktop!
    01154 //   For the long run, we will need to enumerate all desktops
    01155 //   This will be tricky because we need to check the security of
    01156 //   each desktop, thus needing the user's security "token".
    01157     if (!(pbwl = BuildHwndList(pdeskinfo->spwnd->spwndChild, BWL_ENUMLIST, NULL))) {
    01158 #ifdef COOLSWITCHTRACE
    01159         DbgPrint("CoolSwitch: BuildHwndList failed (contact bradg).\n");
    01160         UserAssert(pbwl != NULL);
    01161 #endif
    01162         goto ReturnNextWnd;
    01163     }
    01164 #endif
    01165
    01166     /*
    01167      *  Walk down the list and remove all non-task windows from the list.
    01168      *  Replace those hwnds with 0.
    01169      */
    01170     if ((iTotalTasks = _RemoveNonTaskWindows(pbwl, pwndCurActive, &iActiveTask, &phwndLast)) < 2) {
    01171         if (iTotalTasks == 1) {
    01172             /*
    01173              *  If we have only one window and it's in full screen mode, we will
    01174              *  return the shell window so the can switch back to GDI mode.
    01175              */
    01176             pwnd = RevalidateHwnd(pbwl->rghwnd[0]);
    01177             if (pwnd && GetFullScreen(pwnd) == FULLSCREEN && pwndCurActive == pwnd)
    01178                 pwnd = pdeskinfo->spwndShell;
    01179
    01180         } else {
    01181             pwnd = pdeskinfo->spwndShell;
    01182         }
    01183 #ifdef COOLSWITCHTRACE
    01184         DbgPrint("CoolSwitch: Not enough windows to switch.\n");
    01185 #endif
    01186         goto FreeAndReturnNextWnd;  // If there isn't even two tasks, no switch wnd processing.
    01187     }
    01188
    01189     /*
    01190      *  Allocate the Switch Info structure.  If we don't have enough
    01191      *  memory, act as if we are doing Alt+Esc.
    01192      */
    01193     if (!(pswInfo = (PSWINFO)UserAllocPoolWithQuota(sizeof(SWITCHWNDINFO), TAG_ALTTAB))) {
    01194 #ifdef COOLSWITCHTRACE
    01195         DbgPrint("CoolSwitch: UserAllocPool failed on 0x%X bytes (contact bradg).\n", sizeof(SWITCHWNDINFO));
    01196         UserAssert(pswInfo != NULL);
    01197 #endif
    01198         goto FreeAndReturnNextWnd;  // Unable to alloc SwitchWndInfo struct.
    01199     }
    01200
    01201     pswInfo->pbwl        = pbwl;
    01202     pswInfo->phwndLast   = phwndLast;
    01203     pswInfo->iTasksShown = pswInfo->iTotalTasks = iTotalTasks;
    01204
    01205     /*
    01206      *  Get the next/prev window that must become active.
    01207      */
    01208     iIconIndex = NextPrevTaskIndex(pswInfo, iActiveTask, 1, !fPrev);
    01209     pswInfo->phwndCurrent = &(pbwl->rghwnd[iIconIndex]);
    01210
    01211     iCols = min(gnFastAltTabColumns, iTotalTasks);
    01212     iRows = iTotalTasks / iCols;  // Truncation might occur.
    01213
    01214     iIconsInLastRow = iTotalTasks - iRows * iCols;
    01215     iRows += (iIconsInLastRow ? 1 : 0);  // Take care of earlier truncation.
    01216
    01217     /*
    01218      *  Restrict the number of rows to just MAXROWSALLOWED (3)
    01219      */
    01220     if (iRows > gnFastAltTabRows) {
    01221         iRows = gnFastAltTabRows;
    01222         pswInfo->fScroll = TRUE;    // We need to scroll.
    01223         iIconsInLastRow = iCols;
    01224         pswInfo->iTasksShown = iCols * iRows;
    01225     } else {
    01226         pswInfo->fScroll = FALSE;
    01227     }
    01228
    01229     pswInfo->iNoOfColumns = iCols;
    01230     pswInfo->iNoOfRows    = iRows;
    01231
    01232     if (iIconsInLastRow == 0)
    01233        iIconsInLastRow = pswInfo->iNoOfColumns; // Last Row is full.
    01234     pswInfo->iIconsInLastRow = iIconsInLastRow;
    01235
    01236     /*
    01237      *  Find out Row and Col where the next/prev icon will lie.
    01238      */
    01239     if (iIconIndex >= (iRows * iCols)) {
    01240         /*
    01241          *  Next Icon lies outside. Bring it to the center.
    01242          */
    01243         iCurRow = (iRows >> 2) + 1;
    01244         iCurCol = (iCols >> 2) + 1;
    01245         iDiff = (iIconIndex - ((iCurRow * iCols) + iCurCol));
    01246     } else {
    01247         iDiff = 0;
    01248         iCurRow = iIconIndex / iCols;
    01249         iCurCol = iIconIndex - (iCurRow * iCols);
    01250     }
    01251
    01252     pswInfo->iFirstTaskIndex = iDiff;
    01253     pswInfo->iCurRow         = iCurRow;
    01254     pswInfo->iCurCol         = iCurCol;
    01255
    01256     /*
    01257      *  Calculate the Switch Window Dimensions.
    01258      */
    01259     cxSwitch = min(
    01260             pMonitor->rcMonitor.right - pMonitor->rcMonitor.left,
    01261             gnFastAltTabColumns * CXICONSLOT +
    01262                 CXICONSIZE / 2 +
    01263                 6 * gpsi->gclBorder * SYSMET(CXBORDER) +
    01264                 gcxCaptionFontChar);
    01265
    01266     cySwitch = min(
    01267             pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top,
    01268             iRows * CYICONSLOT +
    01269                 CYICONSIZE +
    01270                 gcyCaptionFontChar * 2 +
    01271                 gcyCaptionFontChar / 2);
    01272
    01273     /*
    01274      *  Find the number of icons in first row
    01275      */
    01276     if (iRows == 1) {
    01277         iFirstRowIcons = iIconsInLastRow;
    01278     } else {
    01279         iFirstRowIcons = iCols;
    01280     }
    01281
    01282     /*
    01283      *  Center the icons based on the number of icons in first row.
    01284      */
    01285     pswInfo->ptFirstRowStart.x = (cxSwitch - 4*gpsi->gclBorder*SYSMET(CXBORDER) - iFirstRowIcons * CXICONSLOT) >> 1;
    01286     pswInfo->ptFirstRowStart.y = (CYICONSIZE >> 1);
    01287
    01288     pswInfo->cxSwitch = cxSwitch;
    01289     pswInfo->cySwitch = cySwitch;
    01290
    01291     *lppswInfo = pswInfo;
    01292
    01293     return RevalidateHwnd(*(pswInfo->phwndCurrent));  // Success!
    01294
    01295
    01296     /*
    01297      *  When there is insufficient mem to create the reqd structures, we simply
    01298      *  return the next window. We make the phwndInfo as NULL. So, we won't
    01299      *  attempt to draw the switch window.
    01300      */
    01301
    01302 FreeAndReturnNextWnd:
    01303     FreeHwndList(pbwl);
    01304 ReturnNextWnd:
    01305     if (pwnd)
    01306         return(pwnd);
    01307
    01308     return(_GetNextQueueWindow(pwndCurActive, _GetKeyState(VK_SHIFT) < 0, FALSE));
    01309 }
    01310
    01311 /***************************************************************************\
    01312 * xxxMoveSwitchWndHilite()
    01313 *
    01314 * This moves the Hilite to the next/prev icon.
    01315 * Checks if this move results in a scrolling. If it does, then
    01316 * make sure scroll occurs.
    01317 * Else, erase hilite from the current icon;
    01318 * Then draw hilite on the new Icon.
    01319 * fPrev indicates whether you want the prev task or next.
    01320 *
    01321 * History:
    01322 * 02-Jun-1995 BradG     Ported from Win95
    01323 \***************************************************************************/
    01324
    01325 HWND xxxMoveSwitchWndHilite(
    01326     PWND    pwndSwitch,
    01327     PSWINFO pswInfo,
    01328     BOOL    fPrev)
    01329 {
    01330     INT  iCurCol, iCurRow;
    01331     INT  iMaxColumns;
    01332     BOOL fLastRow;
    01333     BOOL fNeedToScroll = FALSE;
    01334     HDC  hdc;
    01335
    01336     CheckLock(pwndSwitch);
    01337     UserAssert(IsWinEventNotifyDeferredOK());
    01338
    01339     iCurCol = pswInfo->iCurCol;
    01340     iCurRow = pswInfo->iCurRow;
    01341
    01342     /*
    01343      *  Find out the new postion (row and column) of hilite.
    01344      */
    01345     if (fPrev) {
    01346         if (iCurCol > 0) {
    01347             /*
    01348              *  Move cursor to prev column on the same row.
    01349              */
    01350             iCurCol--;
    01351         } else {
    01352             /*
    01353              *  Try to move to the previous row.
    01354              */
    01355             if (iCurRow > 0) {
    01356                 /*
    01357                  *  Move to the last column on the previous row.
    01358                  */
    01359                 iCurRow--;
    01360                 iCurCol = pswInfo->iNoOfColumns - 1;
    01361             } else {
    01362                 /*
    01363                  *  We are already at (0,0); See if we need to scroll.
    01364                  */
    01365                 if (pswInfo->fScroll) {
    01366                     /*
    01367                      * Time to scroll; Scroll by one Row;
    01368                      * Repaint the whole window.
    01369                      */
    01370                     fNeedToScroll = TRUE;
    01371                     pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
    01372                       pswInfo->iNoOfColumns, FALSE);
    01373                     iCurCol = pswInfo->iNoOfColumns - 1;
    01374                 } else {
    01375                     /*
    01376                      *  Move the hilite to the last icon shown.
    01377                      */
    01378                     iCurRow = pswInfo->iNoOfRows - 1;
    01379                     iCurCol = pswInfo->iIconsInLastRow - 1;
    01380                 }
    01381             }
    01382         }
    01383
    01384     } else {
    01385         /*
    01386          *  !fPrev
    01387          *  Get the number of columns in the current row.
    01388          */
    01389         if (fLastRow = (iCurRow == (pswInfo->iNoOfRows - 1))) // Are we at the last row?
    01390             iMaxColumns = pswInfo->iIconsInLastRow;
    01391         else
    01392             iMaxColumns = pswInfo->iNoOfColumns;
    01393
    01394         /*
    01395          *  Are we at the last column yet?
    01396          */
    01397         if (iCurCol < (iMaxColumns - 1)) {
    01398             /*
    01399              *  No! Move to the right.
    01400              */
    01401             iCurCol++;
    01402         } else {
    01403             /*
    01404              *  We are at the last column.
    01405              *  If we are not at last row, then move to next row.
    01406              */
    01407             if (!fLastRow) {
    01408                 iCurCol = 0;
    01409                 iCurRow++;
    01410             } else {
    01411                 /*
    01412                  *  We are at the last row, last col;
    01413                  *  See if we need to scroll.
    01414                  */
    01415                 if (pswInfo->fScroll) {
    01416                     fNeedToScroll = TRUE;
    01417                     pswInfo->iFirstTaskIndex = NextPrevTaskIndex(pswInfo, pswInfo->iFirstTaskIndex,
    01418                           pswInfo->iNoOfColumns, TRUE);
    01419                     iCurCol = 0;
    01420                 } else {
    01421                     /*
    01422                      *  Move to the top left corner (0, 0).
    01423                      */
    01424                     iCurRow = iCurCol = 0;
    01425                 }
    01426             }
    01427         }
    01428     }
    01429
    01430     /*
    01431      *  Move the phwnd to the next/prev
    01432      */
    01433     pswInfo->phwndCurrent = NextPrevPhwnd(pswInfo, pswInfo->phwndCurrent, !fPrev);
    01434
    01435     /*
    01436      *  Remove Hilite from the current location.
    01437      */
    01438     hdc = _GetDCEx(pwndSwitch, NULL, DCX_USESTYLE);
    01439     DrawSwitchWndHilite(pswInfo, hdc, pswInfo->iCurCol, pswInfo->iCurRow, FALSE);
    01440
    01441     /*
    01442      *  Repaint if needed.
    01443      */
    01444     if (fNeedToScroll)
    01445         xxxPaintIconsInSwitchWindow(pwndSwitch, pswInfo, hdc, pswInfo->iFirstTaskIndex, 0, 0, TRUE, !fPrev, NULL);
    01446
    01447     /*
    01448      *  Draw Hilite at the new location.
    01449      */
    01450     DrawSwitchWndHilite(pswInfo, hdc, iCurCol, iCurRow, TRUE);
    01451
    01452     _ReleaseDC(hdc);
    01453
    01454     pswInfo->iCurRow = iCurRow;
    01455     pswInfo->iCurCol = iCurCol;
    01456
    01457     if (FWINABLE()) {
    01458         xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndSwitch, OBJID_CLIENT,
    01459             iCurRow * pswInfo->iNoOfColumns + iCurCol + 1, WEF_USEPWNDTHREAD);
    01460     }
    01461
    01462     return (*(pswInfo->phwndCurrent));
    01463 }
    01464
    01465 /***************************************************************************\
    01466 * xxxShowSwitchWindow()
    01467 *
    01468 * Show the switch Window.
    01469 * Returns: TRUE if succeeded.   FALSE, if the window was not shown because
    01470 * of the pre-mature release of ALT key. The selection has been made already.
    01471 *
    01472 * History:
    01473 * 07-Jun-1995 BradG     Ported from Win95
    01474 \***************************************************************************/
    01475
    01476 BOOL xxxShowSwitchWindow(
    01477         PWND        pwndAltTab)
    01478 {
    01479     PSWINFO pswInfo;
    01480     PMONITOR pMonitorSwitch = GetPrimaryMonitor();
    01481     CheckLock(pwndAltTab);
    01482     UserAssert(IsWinEventNotifyDeferredOK());
    01483
    01484     /*
    01485      *  Get the switch window information
    01486      */
    01487     pswInfo = Getpswi(pwndAltTab);
    01488     UserAssert(pswInfo != NULL);
    01489
    01490     /*
    01491      *  If the key is not down, don't bother to display Switch Window.
    01492      */
    01493     if ((pswInfo->fJournaling && _GetKeyState(VK_MENU) >= 0) ||
    01494             (!pswInfo->fJournaling && _GetAsyncKeyState(VK_MENU) >= 0)) {
    01495 #ifdef COOLSWITCHTRACE
    01496         DbgPrint("CoolSwitch: Not displaying window because VM_MENU is up (contact bradg).\n");
    01497 #endif
    01498         return FALSE;
    01499     }
    01500
    01501     /*
    01502      *  Bring and position the window on top.
    01503      */
    01504     xxxSetWindowPos(pwndAltTab, PWND_TOPMOST, 0,0,0,0,
    01505         SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW );
    01506
    01507     if (!TestWF(pwndAltTab, WFVISIBLE)) {
    01508         xxxSetWindowPos(
    01509             pwndAltTab,
    01510             PWND_TOPMOST,
    01511             (pMonitorSwitch->rcWork.left + pMonitorSwitch->rcWork.right - pswInfo->cxSwitch) / 2,
    01512             (pMonitorSwitch->rcWork.top + pMonitorSwitch->rcWork.bottom - pswInfo->cySwitch) / 2,
    01513             pswInfo->cxSwitch,
    01514             pswInfo->cySwitch,
    01515             SWP_SHOWWINDOW | SWP_NOACTIVATE);
    01516     }
    01517 #ifdef COOLSWITCHTRACE
    01518     UserAssert(TestWF(pwndAltTab, WFVISIBLE));
    01519 #endif
    01520     xxxUpdateWindow(pwndAltTab);
    01521
    01522     if (FWINABLE()) {
    01523         xxxWindowEvent(EVENT_SYSTEM_SWITCHSTART, pwndAltTab, OBJID_CLIENT,
    01524                 0, WEF_USEPWNDTHREAD);
    01525         xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndAltTab, OBJID_CLIENT,
    01526                 pswInfo->iCurRow * pswInfo->iNoOfColumns + pswInfo->iCurCol + 1,
    01527                 WEF_USEPWNDTHREAD);
    01528     }
    01529
    01530     return TRUE;
    01531 }
    01532
    01533 /***************************************************************************\
    01534 * SwitchWndCleanup()
    01535 *
    01536 * Clean up all the mem allocated etc.,
    01537 *
    01538 * History:
    01539 * 07-Jun-1995 BradG     Ported from Win95
    01540 \***************************************************************************/
    01541
    01542 VOID SwitchWndCleanup(
    01543     PSWINFO *ppswInfo)
    01544 {
    01545     UserAssert(ppswInfo != NULL);
    01546     UserAssert(*ppswInfo != NULL);
    01547
    01548     /*
    01549      *  First of all free the Window list.
    01550      */
    01551     if ((*ppswInfo)->pbwl)
    01552         FreeHwndList((*ppswInfo)->pbwl);
    01553     UserFreePool(*ppswInfo);
    01554     *ppswInfo = NULL;
    01555 }
    01556
    01557
    01558 /***************************************************************************\
    01559 *
    01560 *  xxxSwitchWndProc()
    01561 *
    01562 \***************************************************************************/
    01563
    01564 LRESULT xxxSwitchWndProc(
    01565     PWND  pwnd,
    01566     UINT  message,
    01567     WPARAM wParam,
    01568     LPARAM lParam)
    01569 {
    01570     TL          tlpwndActivate;
    01571     PTHREADINFO ptiCurrent = PtiCurrent();
    01572
    01573     CheckLock(pwnd);
    01574     UserAssert(IsWinEventNotifyDeferredOK());
    01575
    01576     VALIDATECLASSANDSIZE(pwnd, message, wParam, lParam, FNID_SWITCH, WM_CREATE);
    01577
    01578     switch (message) {
    01579     case WM_CREATE:
    01580         /*
    01581          * When the queue was created, the cursor was set to the wait cursor.
    01582          * We want to use the normal one.
    01583          */
    01584         zzzSetCursor(pwnd->pcls->spcur);
    01585         break;
    01586
    01587     case WM_CLOSE:
    01588         /*
    01589          *  Hide this window without activating anyone else.
    01590          */
    01591         xxxSetWindowPos(pwnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW |
    01592                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
    01593
    01594         /*
    01595          * Get us out of Alt+Tab mode.  Since the alttab information
    01596          * is stored in the gptiRit->pq, we will reference that insteatd
    01597          * of the current-thread.
    01598          */
    01599         xxxCancelCoolSwitch();
    01600         break;
    01601
    01602     case WM_ERASEBKGND:
    01603     case WM_FULLSCREEN:
    01604         ThreadLockWithPti(ptiCurrent, pwnd, &tlpwndActivate);
    01605         xxxPaintSwitchWindow(pwnd);
    01606         ThreadUnlock(&tlpwndActivate);
    01607         return 0;
    01608
    01609     case WM_DESTROY:
    01610         {
    01611             /*
    01612              *  Get the switch window info for this window
    01613              */
    01614             PSWINFO pswCurrent = Getpswi(pwnd);
    01615
    01616
    01617             if (pswCurrent)
    01618                 SwitchWndCleanup(&pswCurrent);
    01619         }
    01620         break;
    01621     }
    01622
    01623     return xxxDefWindowProc(pwnd, message, wParam, lParam);
    01624 }
    01625
    01626 /***************************************************************************\
    01627 * xxxCancelCoolSwitch
    01628 *
    01629 * This functions destroys the cool switch window and removed the INALTTAB
    01630 * mode flag from the specified queue.
    01631 *
    01632 * History:
    01633 * 18-Sep-1995 BradG     Created
    01634 \***************************************************************************/
    01635 VOID xxxCancelCoolSwitch(
    01636     void)
    01637 {
    01638     CheckCritIn();
    01639     UserAssert(IsWinEventNotifyDeferredOK());
    01640
    01641     /*
    01642      *  Destroy the Cool Switch window
    01643      */
    01644     if (gspwndAltTab != NULL) {
    01645
    01646         /*
    01647          * Make sure that the thread calling this is the same
    01648          * thread which created the alttab window.  Otherwise,
    01649          * we could end up with this window floating around until
    01650          * the calling process dies.  Remember, we can't destroy
    01651          * windows across different threads.
    01652          */
    01653         if (gspwndAltTab->head.pti != PtiCurrent())
    01654             return;
    01655
    01656         if (FWINABLE()) {
    01657             xxxWindowEvent(EVENT_SYSTEM_SWITCHEND, gspwndAltTab, OBJID_CLIENT,
    01658                 0, WEF_USEPWNDTHREAD);
    01659         }
    01660         xxxDestroyWindow(gspwndAltTab);
    01661
    01662         Lock(&gspwndAltTab, NULL);
    01663     }
    01664 }
    01665
    01666 /***************************************************************************\
    01667 * xxxNextWindow
    01668 *
    01669 * This function does the processing for the alt-tab/esc/F6 UI.
    01670 *
    01671 * History:
    01672 * 30-May-1991 DavidPe       Created.
    01673 \***************************************************************************/
    01674
    01675 VOID xxxNextWindow(
    01676     PQ    pq,
    01677     DWORD wParam)
    01678 {
    01679     PWND        pwndActivateNext;
    01680     PWND        pwndCurrentActivate, pwndCurrentTopFocus;
    01681     int         fDir;
    01682     TL          tlpwndActivateNext;
    01683     TL          tlpwndCurrentActivate;
    01684     TL          tlpwndT;
    01685     PSWINFO     pswCurrent;
    01686     ULONG_PTR    dwResult;
    01687     BOOL        fNonRit = FALSE;
    01688     PTHREADINFO ptiCurrent = PtiCurrent();
    01689     PTHREADINFO ptiAltTab;
    01690
    01691     UserAssert(!IsWinEventNotifyDeferred());
    01692
    01693     /*
    01694      * HACK: We have a problem with direct-draw full apps where an alttab
    01695      *       window is created on a queue owned other than the RIT.  This
    01696      *       shows up by alt-tabbing away from ROIDS.EXE during fullscreen.
    01697      *
    01698      *       What is happening is on a ALT-TAB, from xxxSysCommand(), the
    01699      *       thread is not a rit.  xxxSysCommand() calls xxxOldNextWindow
    01700      *       which finds that the current-thread doesn't have a switch
    01701      *       window, and then creates one on the current-thread-queue.
    01702      *
    01703      *       The hack here is to make sure the calling thread is the RIT
    01704      *       before allowing any cool-switch creation.
    01705      *
    01706      *       21-Mar-1996 : Chriswil
    01707      */
    01708 #if 0
    01709     ptiAltTab = ptiCurrent;
    01710 #else
    01711     ptiAltTab = gptiRit;
    01712 #endif
    01713
    01714     if (pq == NULL)
    01715         return;
    01716
    01717     fDir = (_GetAsyncKeyState(VK_SHIFT) < 0) ? FDIR_BACKWARD : FDIR_FORWARD;
    01718
    01719     /*
    01720      *  NOTE: As of NT 4.0 the slow Alt+Tab functionality now officially acts
    01721      *  like Alt+Esc with the exception that Alt+Tab will activate the window
    01722      *  where Alt+Esc will not.
    01723      */
    01724     switch (wParam) {
    01725
    01726     case VK_TAB:
    01727
    01728         if (gspwndAltTab == NULL) {
    01729
    01730             PWND pwndSwitch;
    01731             TL   tlpSwitchInfo;
    01732
    01733             /*
    01734              *  We are entering Alt+Tab for the first time, we need to
    01735              *  initialize the Switch Window structure and if needed
    01736              *  create and display the Alt+Tab window.  We have two special
    01737              *  cases: (1) The user does not want to use the Switch window,
    01738              *  (2) The initialize switch window fails thus we will act
    01739              *  just like slow Alt+Tab
    01740              */
    01741
    01742             /*
    01743              * Since Alt+Shift is the default hotkey for keyboard layout switching,
    01744              * Alt+Shift+Tab may cause a KL switching while AltTab window is up.
    01745              * To prevent it, we'd better reset the global toggle key state here,
    01746              * so that xxxScanSysQueue will not confuse when it handles keyup messages.
    01747              */
    01748             gLangToggleKeyState = KLT_NONE;
    01749
    01750             /*
    01751              * Mouse buttons sometimes get stuck down due to hardware glitches,
    01752              * usually due to input concentrator switchboxes or faulty serial
    01753              * mouse COM ports, so clear the global button state here just in case,
    01754              * otherwise we may not be able to change focus with the mouse.
    01755              * Also do this in zzzCancelJournalling (Ctr-Esc, Ctrl-Alt-Del, etc.)
    01756              */
    01757 #if DBG
    01758             if (gwMouseOwnerButton)
    01759                 RIPMSG1(RIP_WARNING,
    01760                         "gwMouseOwnerButton=%x, being forcibly cleared\n",
    01761                         gwMouseOwnerButton);
    01762 #endif
    01763             gwMouseOwnerButton = 0;
    01764
    01765             /*
    01766              *  Determine the current active window.
    01767              */
    01768             Lock(&gspwndActivate, pq->spwndActive);
    01769             if (gspwndActivate == NULL) {
    01770                 Lock(&gspwndActivate, grpdeskRitInput->pDeskInfo->spwnd->spwndChild);
    01771             }
    01772
    01773             if (!gspwndActivate) {
    01774                 return;
    01775             }
    01776
    01777             /*
    01778              *  Make a local copy of gspwndActivate and lock it because xxxFreeWindow will
    01779              *  unlock if it is the window being freed.
    01780              */
    01781             pwndCurrentActivate = gspwndActivate;
    01782             ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
    01783
    01784             /*
    01785              *   Cancel the active window's mode
    01786              */
    01787             xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
    01788
    01789             /*
    01790              *  Initialize the Switch Window data structure, if we
    01791              *  succeed create and display the window, otherwise act
    01792              *  like slow Alt+Tab.
    01793              */
    01794             pwndActivateNext = InitSwitchWndInfo(&pswCurrent, pwndCurrentActivate, fDir);
    01795
    01796             ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
    01797
    01798             if (pswCurrent == NULL) {
    01799                 /*
    01800                  *  Couldn't initialize our switch window data structure, so we
    01801                  *  will act like Alt+Esc.
    01802                  */
    01803                 goto DoSlowAltTab;
    01804             }
    01805
    01806             if (pwndActivateNext == NULL) {
    01807                 SwitchWndCleanup(&pswCurrent);
    01808                 ThreadUnlock(&tlpwndActivateNext);
    01809                 ThreadUnlock(&tlpwndCurrentActivate);
    01810                 Unlock(&gspwndActivate);
    01811                 return;
    01812             }
    01813
    01814             ThreadLockPool(ptiCurrent, pswCurrent, &tlpSwitchInfo);
    01815
    01816             /*
    01817              * Since we are in the RIT, test the physical state of the keyboard
    01818              */
    01819             pswCurrent->fJournaling = FALSE;
    01820
    01821             /*
    01822              *  Create the Alt+Tab window
    01823              */
    01824             pwndSwitch =
    01825                   xxxCreateWindowEx( WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME,
    01826                       (PLARGE_STRING)SWITCHWNDCLASS, NULL,
    01827                       WS_POPUP | WS_BORDER | WS_DISABLED,
    01828                       0, 0, 10, 10, NULL, NULL, NULL, NULL, VER40);
    01829
    01830             if (gspwndAltTab != NULL) {
    01831                 UserAssert(0);
    01832
    01833                 _PostMessage(gspwndAltTab, WM_CLOSE, 0, 0);
    01834             }
    01835
    01836             Lock(&gspwndAltTab, pwndSwitch);
    01837
    01838             ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
    01839
    01840             if (gspwndAltTab == NULL) {
    01841                 /*
    01842                  *  Could not create the cool switch window, do the Alt+Esc thing
    01843                  */
    01844 #ifdef COOLSWITCHTRACE
    01845                 DbgPrint("CoolSwitch: Could not create window (contact bradg).\n");
    01846                 UserAssert(gspwndAltTab != NULL);
    01847 #endif
    01848                 SwitchWndCleanup(&pswCurrent);
    01849                 goto DoSlowAltTab;
    01850             }
    01851
    01852             /*
    01853              *  Save the pointer to the switch window info structure
    01854              */
    01855             Setpswi(gspwndAltTab, pswCurrent);
    01856             /*
    01857              *  Set gspwndActivate so the RIT knows what window we would like
    01858              *  it to activate.
    01859              */
    01860             Lock(&gspwndActivate, pwndActivateNext);
    01861
    01862             /*
    01863              * Make sure that our rit queue has the correct pdesk
    01864              */
    01865             if (ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD) {
    01866                 xxxSetThreadDesktop(NULL, grpdeskRitInput); // DeferWinEventNotify() ?? IANJA ??
    01867             }
    01868
    01869             /*
    01870              * If we're currently full screen tell console to switch to
    01871              * the desktop to GDI mode; we can't do this on the RIT because
    01872              * it can be slow.
    01873              */
    01874             if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) {
    01875                 ThreadLockWithPti(ptiCurrent, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
    01876                 xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LPARAM)HW(grpdeskRitInput->pDeskInfo->spwnd));
    01877                 ThreadUnlock(&tlpwndT);
    01878             }
    01879
    01880             /*
    01881              *  Show the Alt+Tab window.  If it returns FALSE this means
    01882              *  the ALT key has been released, so there is no need to
    01883              *  paint the icons.
    01884              */
    01885             ThreadLockAlwaysWithPti(ptiCurrent, gspwndAltTab, &tlpwndT);
    01886             xxxShowSwitchWindow(gspwndAltTab);
    01887             ThreadUnlock(&tlpwndT);
    01888
    01889             /*
    01890              *  Exit now because the Switch window will have been
    01891              *  already updated.
    01892              */
    01893             ThreadUnlock(&tlpwndActivateNext);
    01894             ThreadUnlock(&tlpwndCurrentActivate);
    01895
    01896         } else {
    01897
    01898             /*
    01899              *  We come here to do the actual switching and/or updating of
    01900              *  the switch window when in Alt+Tab mode.
    01901              */
    01902             PWND    pwndSwitch;
    01903             TL      tlpwndSwitch;
    01904             PSWINFO pswCurrent;
    01905             HWND    hwndActivateNext;
    01906             HWND    hwndStop;
    01907
    01908             if (!(pwndSwitch = gspwndAltTab)) {
    01909
    01910                 goto DoAltEsc;
    01911
    01912             } else {
    01913                 /*
    01914                  *  Move the hilight rect to the next/prev task.  It is possible
    01915                  *  that some tasks were destoryed, so we need to skip those.
    01916                  */
    01917                 pswCurrent = Getpswi(pwndSwitch);
    01918                 ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
    01919                 hwndStop = NULL;
    01920                 do {
    01921                     hwndActivateNext = xxxMoveSwitchWndHilite(pwndSwitch, pswCurrent, fDir);
    01922                     if (!hwndStop) {
    01923                         hwndStop = hwndActivateNext;
    01924                     } else {
    01925                         if (hwndStop == hwndActivateNext) {
    01926                             pwndActivateNext = NULL;
    01927                             break;
    01928                         }
    01929                     }
    01930                     pwndActivateNext = RevalidateHwnd(hwndActivateNext);
    01931                 } while (!pwndActivateNext);
    01932                 ThreadUnlock(&tlpwndSwitch);
    01933                 Lock(&gspwndActivate, pwndActivateNext);
    01934                 if (!gspwndActivate) {
    01935                     /*
    01936                      *  No Window to activate, bail out of Alt+Tab mode
    01937                      */
    01938                     xxxCancelCoolSwitch();
    01939                 }
    01940             }
    01941         }
    01942         break;
    01943
    01944 DoAltEsc:
    01945     case VK_ESCAPE:
    01946         /*
    01947          *  NOTE: The RIT doesn't use gspwndActivate to activate the window when
    01948          *        processing Alt+Esc, we just use it here as a convenient
    01949          *        variable.  The actual activation takes place below.
    01950          */
    01951         pwndCurrentActivate = pq->spwndActive;
    01952         if (pwndCurrentActivate == NULL) {
    01953             pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild;
    01954         }
    01955         if (!pwndCurrentActivate)
    01956             return;
    01957         ThreadLockAlwaysWithPti(ptiCurrent, pwndCurrentActivate, &tlpwndCurrentActivate);
    01958
    01959         /*
    01960          *   Cancel the active window's mode
    01961          */
    01962         xxxSendMessageTimeout(pwndCurrentActivate, WM_CANCELMODE, 0, 0, SMTO_ABORTIFHUNG, 100, &dwResult);
    01963
    01964         /*
    01965          * Determine the next window to activate
    01966          */
    01967         pwndActivateNext = _GetNextQueueWindow(pwndCurrentActivate, fDir, TRUE);
    01968         ThreadLockWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
    01969
    01970         /*
    01971          * If we're going forward through the windows, move the currently
    01972          * active window to the bottom so we'll do the right thing when
    01973          * we go backwards.
    01974          */
    01975         if (pwndActivateNext != pwndCurrentActivate) {
    01976 DoSlowAltTab:
    01977             if (pwndActivateNext) {
    01978
    01979                 /*
    01980                  * We're about to activate another window while the ALT key is down,
    01981                  *  so let the current focus window know that it doesn't need the
    01982                  *  menu underlines anymore
    01983                  */
    01984                 pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus);
    01985                 if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) {
    01986                     ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE);
    01987                 }
    01988
    01989                 if (fDir == FDIR_FORWARD) {
    01990                     /*
    01991                      * For Alt+ESC only move the window to the bottom if it's
    01992                      * not a top most window
    01993                      */
    01994                     if (!TestWF(pwndCurrentActivate, WEFTOPMOST)) {
    01995                         xxxSetWindowPos(pwndCurrentActivate, PWND_BOTTOM, 0, 0, 0, 0,
    01996                                 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
    01997                                 SWP_DEFERDRAWING | SWP_NOSENDCHANGING |
    01998                                 SWP_ASYNCWINDOWPOS);
    01999                     }
    02000                 }
    02001
    02002                 /*
    02003                  * The ALT key is down, so this window needs menu underlines
    02004                  */
    02005                 if (pwndActivateNext->spmenu != NULL) {
    02006                     SetMF(pwndActivateNext->spmenu, MFUNDERLINE);
    02007                 }
    02008
    02009
    02010                 /*
    02011                  * This little ugly hack will cause xxxSetForegroundWindow2()
    02012                  * to send out an activation messages to a queue that is
    02013                  * already the active queue allowing us to change the active
    02014                  * window on that queue.
    02015                  */
    02016                 if (gpqForeground == GETPTI(pwndActivateNext)->pq)
    02017                     gpqForeground = NULL;
    02018
    02019                 /*
    02020                  * Make the selected window thread the owner of the last input;
    02021                  *  since he's next, he owns the ALT-ESC.
    02022                  */
    02023                 glinp.ptiLastWoken = GETPTI(pwndActivateNext);
    02024
    02025                 xxxSetForegroundWindow2(pwndActivateNext, NULL,
    02026                         (wParam == VK_TAB) ? SFW_SWITCH | SFW_ACTIVATERESTORE : SFW_SWITCH);
    02027
    02028                 /*
    02029                  * Win3.1 calls SetWindowPos() with activate, which z-orders
    02030                  * first regardless, then activates. Our code relies on
    02031                  * xxxActivateThisWindow() to z-order, and it'll only do
    02032                  * it if the window does not have the child bit set (regardless
    02033                  * that the window is a child of the desktop).
    02034                  *
    02035                  * To be compatible, we'll just force z-order here if the
    02036                  * window has the child bit set. This z-order is asynchronous,
    02037                  * so this'll z-order after the activate event is processed.
    02038                  * That'll allow it to come on top because it'll be foreground
    02039                  * then. (Grammatik has a top level window with the child
    02040                  * bit set that wants to be come the active window).
    02041                  */
    02042                 if (wParam == VK_TAB && TestWF(pwndActivateNext, WFCHILD)) {
    02043                     xxxSetWindowPos(pwndActivateNext, (PWND)HWND_TOP, 0, 0, 0, 0,
    02044                             SWP_NOSIZE | SWP_NOMOVE | SWP_ASYNCWINDOWPOS);
    02045                 }
    02046             }
    02047         }
    02048         ThreadUnlock(&tlpwndActivateNext);
    02049         ThreadUnlock(&tlpwndCurrentActivate);
    02050         break;
    02051
    02052     case VK_F6:
    02053         if ((pwndCurrentActivate = pq->spwndActive) == NULL)
    02054             pwndCurrentActivate = pq->ptiKeyboard->rpdesk->pDeskInfo->spwnd->spwndChild;
    02055
    02056         pwndActivateNext = pwndCurrentActivate;
    02057
    02058         /*
    02059          * HACK! console sessions are all one thread but we want them
    02060          * to act like different threads so if its a console thread (csrss.exe)
    02061          * then ALT-F6 does nothing just like in Win 3.1
    02062          * Note: we never get called with wParam == VK_F6 anyway. Win NT 3.51
    02063          * doesn't seem to either, but Windows '95 does.  BUG?? (IanJa)
    02064          */
    02065         if (!(GETPTI(pwndActivateNext)->TIF_flags & TIF_CSRSSTHREAD)) {
    02066             /*
    02067              * on a alt-f6, we want to keep the switch within the thread.
    02068              * We may want to rethink this because this will look strange
    02069              * when you alt-f6 on a multi-threaded app we will not rotate
    02070              * through the windows on the different threads.  This works
    02071              * fine on Win 3.x because it is single threaded.
    02072              */
    02073             do {
    02074                 pwndActivateNext = NextTopWindow(pq->ptiKeyboard, pwndActivateNext, NULL,
    02075                         fDir ? NTW_PREVIOUS : 0);
    02076             } while( (pwndActivateNext != NULL) &&
    02077                     (GETPTI(pwndActivateNext) != pq->ptiKeyboard));
    02078
    02079             if (pwndActivateNext != NULL) {
    02080
    02081                 if (pwndActivateNext != pwndCurrentActivate) {
    02082                     /*
    02083                      * We're about to activate another window while the ALT key is down,
    02084                      *  so let the current focus window know that it doesn't need the
    02085                      *  menu underlines anymore
    02086                      */
    02087                     pwndCurrentTopFocus = GetTopLevelWindow(pq->spwndFocus);
    02088                     if ((pwndCurrentTopFocus != NULL) && (pwndCurrentTopFocus->spmenu != NULL)) {
    02089                         ClearMF(pwndCurrentTopFocus->spmenu, MFUNDERLINE);
    02090                     }
    02091                     /*
    02092                      * The ALT key is down, so this window needs menu underlines
    02093                      */
    02094                     if (pwndActivateNext->spmenu != NULL) {
    02095                         SetMF(pwndActivateNext->spmenu, MFUNDERLINE);
    02096                     }
    02097                 }
    02098
    02099
    02100                 ThreadLockAlwaysWithPti(ptiCurrent, pwndActivateNext, &tlpwndActivateNext);
    02101                 xxxSetWindowPos(pwndActivateNext, PWND_BOTTOM, 0, 0, 0, 0,
    02102                         SWP_DEFERDRAWING | SWP_NOSENDCHANGING | SWP_NOCHANGE |
    02103                         SWP_ASYNCWINDOWPOS);
    02104                 xxxSetForegroundWindow2(pwndActivateNext, NULL, SFW_SWITCH);
    02105                 ThreadUnlock(&tlpwndActivateNext);
    02106             }
    02107         }
    02108         break;
    02109     }
    02110 }
    02111
    02112 /***************************************************************************\
    02113 * xxxOldNextWindow
    02114 *
    02115 * This function does the processing for the alt-tab/esc/F6 UI.
    02116 *
    02117 * History:
    02118 * 03-17-92  DavidPe     Ported from Win 3.1 sources
    02119 \***************************************************************************/
    02120
    02121 VOID xxxOldNextWindow(
    02122     UINT flags)
    02123 {
    02124     MSG         msg;
    02125     HWND        hwndSel;
    02126     PWND        pwndNewSel;
    02127     PWND        pwndSel;
    02128     BOOL        fType = 0;
    02129     BOOL        fDrawIcon;
    02130     WORD        vk;
    02131     TL          tlpwndT;
    02132     TL          tlpwndSel;
    02133     TL          tlpwndSwitch;
    02134     PSWINFO     pswCurrent;
    02135     PWND        pwndSwitch;
    02136     HWND        hwndStop;
    02137     HWND        hwndNewSel;
    02138     PTHREADINFO ptiCurrent = PtiCurrent();
    02139     PTHREADINFO ptiAltTab;
    02140     UserAssert(IsWinEventNotifyDeferredOK());
    02141
    02142     /*
    02143      * HACK: We have a problem with direct-draw full apps where an alttab
    02144      *       window is created on a queue owned other than the RIT.  This
    02145      *       shows up by alt-tabbing away from ROIDS.EXE during fullscreen.
    02146      *
    02147      *       What is happening is on a ALT-TAB, from xxxSysCommand(), the
    02148      *       thread is not a rit.  xxxSysCommand() calls xxxOldNextWindow
    02149      *       which finds that the current-thread doesn't have a switch
    02150      *       window, and then creates one on the current-thread-queue.
    02151      *
    02152      *       The hack here is to make sure the calling thread is the RIT
    02153      *       before allowing any cool-switch creation.
    02154      *
    02155      *       21-Mar-1996 : Chriswil
    02156      */
    02157 #if 0
    02158     ptiAltTab = ptiCurrent;
    02159 #else
    02160     ptiAltTab = gptiRit;
    02161 #endif
    02162
    02163     /*
    02164      * Don't allow entering this routine when we're already in the AltTab
    02165      * mode. The AltTab window may have been created via xxxNextWindow.
    02166      */
    02167     if (gspwndAltTab != NULL)
    02168         return;
    02169
    02170     if ((pwndSel = ptiCurrent->pq->spwndActive) == NULL)
    02171         return;
    02172
    02173     ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndSel);
    02174     xxxCapture(ptiCurrent, pwndSel, SCREEN_CAPTURE);
    02175
    02176     vk = (WORD)flags;
    02177     msg.wParam = (UINT)flags;
    02178
    02179     pwndNewSel = NULL;
    02180
    02181     if (vk == VK_TAB) {
    02182
    02183         TL tlpSwitchInfo;
    02184
    02185         /*
    02186          *  Initialize the Switch window data structures
    02187          */
    02188         pwndNewSel = InitSwitchWndInfo(&pswCurrent,
    02189                                        pwndSel,
    02190                                        _GetKeyState(VK_SHIFT) < 0);
    02191
    02192         if (pswCurrent == NULL) {
    02193             /*
    02194              *  We were unable to initialize the data structure used by
    02195              *  the Switch window, so we will act like Alt+Esc.
    02196              */
    02197         } else {
    02198
    02199             PWND pwndSwitch;
    02200
    02201             /*
    02202              * We are doing a journal playback do use _GetKeyState to
    02203              * test the keyboard
    02204              */
    02205             pswCurrent->fJournaling = TRUE;
    02206
    02207             ThreadLockPool(ptiCurrent, pswCurrent, &tlpSwitchInfo);
    02208
    02209             /*
    02210              *  Attempt to create the Switch Window
    02211              */
    02212
    02213             pwndSwitch =
    02214                  xxxCreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME,
    02215                                    (PLARGE_STRING)SWITCHWNDCLASS,
    02216                                    NULL,
    02217                                    WS_POPUP | WS_BORDER | WS_DISABLED,
    02218                                    0,
    02219                                    0,
    02220                                    10,
    02221                                    10,
    02222                                    NULL,
    02223                                    NULL,
    02224                                    NULL,
    02225                                    NULL,
    02226                                    VER40);
    02227
    02228             if (gspwndAltTab != NULL) {
    02229                 UserAssert(0);
    02230
    02231                 _PostMessage(gspwndAltTab, WM_CLOSE, 0, 0);
    02232             }
    02233
    02234             ThreadUnlockPool(ptiCurrent, &tlpSwitchInfo);
    02235
    02236             Lock(&gspwndAltTab, pwndSwitch);
    02237
    02238
    02239             if (!(pwndSwitch = gspwndAltTab)) {
    02240
    02241                 SwitchWndCleanup(&pswCurrent);
    02242
    02243             } else {
    02244                 /*
    02245                  *  Lock the switch window
    02246                  */
    02247                 ThreadLockAlwaysWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
    02248
    02249                 /*
    02250                  *  Save the switch window info
    02251                  */
    02252                 Setpswi(pwndSwitch, pswCurrent);
    02253
    02254 // Don't we need to switch from full screen mode if needed?
    02255 #if 0
    02256                 /*
    02257                  * If we're currently full screen tell console to switch to
    02258                  * the desktop to GDI mode; we can't do this on the RIT because
    02259                  * it can be slow.
    02260                  */
    02261                 if (gspwndFullScreen != grpdeskRitInput->pDeskInfo->spwnd) {
    02262                     ThreadLockWithPti(pti, grpdeskRitInput->pDeskInfo->spwnd, &tlpwndT);
    02263                     xxxSendNotifyMessage(grpdeskRitInput->pDeskInfo->spwnd, WM_FULLSCREEN, GDIFULLSCREEN, (LONG)HW(grpdeskRitInput->pDeskInfo->spwnd));
    02264                     ThreadUnlock(&tlpwndT);
    02265                 }
    02266 #endif
    02267
    02268                 /*
    02269                  *  Show the switch window, this also will paint the window
    02270                  */
    02271                 xxxShowSwitchWindow(gspwndAltTab);
    02272                 ThreadUnlock(&tlpwndSwitch);
    02273             }
    02274         }
    02275
    02276     }
    02277
    02278     if (!pwndNewSel)
    02279         goto StartTab;
    02280
    02281     pwndSel = pwndNewSel;
    02282
    02283     while (TRUE) {
    02284
    02285         hwndSel = PtoH(pwndSel);
    02286         /*
    02287          * Wait for a message without getting it out of the queue.
    02288          */
    02289         while (!xxxPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD))
    02290             xxxWaitMessage();
    02291
    02292         if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
    02293             pwndSel = ptiCurrent->pq->spwndActive;
    02294
    02295         if (_CallMsgFilter(&msg, MSGF_NEXTWINDOW)) {
    02296             /*
    02297              * Swallow the message if the hook processed it
    02298              */
    02299             xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
    02300             continue;
    02301         }
    02302
    02303         /*
    02304          * If we are doing Alt+Tab and some other key comes in (other than
    02305          * tab, escape or shift), then bomb out of this loop and leave that
    02306          * key in the queue.
    02307          */
    02308         if ((msg.message == WM_SYSKEYDOWN) && gspwndAltTab != NULL) {
    02309
    02310             vk = (WORD)msg.wParam;
    02311
    02312             if ((vk != VK_TAB) && (vk != VK_ESCAPE) && (vk != VK_SHIFT)) {
    02313                 pwndSel = ptiCurrent->pq->spwndActive;
    02314                 fType = 0;
    02315                 goto Exit;
    02316             }
    02317         }
    02318
    02319         switch (msg.message) {
    02320
    02321         case WM_CANCELJOURNAL:
    02322             /*
    02323              *  If journalling was canceled we need to exit our loop and
    02324              *  remove the Alt+Tab window.  We don't want to remove this
    02325              *  meesage because we want the app to know that journalling
    02326              *  was canceled.
    02327              */
    02328
    02329             /* > > >  F A L L   T H R O U G H  < < < */
    02330
    02331         case WM_LBUTTONDOWN:
    02332         case WM_LBUTTONUP:
    02333         case WM_RBUTTONDOWN:
    02334         case WM_RBUTTONUP:
    02335         case WM_MBUTTONDOWN:
    02336         case WM_MBUTTONUP:
    02337         case WM_XBUTTONDOWN:
    02338         case WM_XBUTTONUP:
    02339             /*
    02340              * If mouse message, cancel and get out of loop.
    02341              */
    02342             pwndSel = ptiCurrent->pq->spwndActive;
    02343             fType = 0;
    02344             goto Exit;
    02345
    02346         case WM_KEYUP:
    02347         case WM_KEYDOWN:
    02348         case WM_SYSCHAR:
    02349         case WM_SYSKEYUP:
    02350         case WM_MOUSEMOVE:
    02351             /*
    02352              * Swallow the message
    02353              */
    02354             hwndSel = PtoH(pwndSel);
    02355             xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
    02356
    02357             if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
    02358                 pwndSel = ptiCurrent->pq->spwndActive;
    02359
    02360             if (msg.message == WM_KEYUP || msg.message == WM_SYSKEYUP) {
    02361
    02362                 vk = (WORD)msg.wParam;
    02363
    02364                 /*
    02365                  * If alt-tab up, then exit.
    02366                  */
    02367                 if (vk == VK_MENU) {
    02368                     /*
    02369                      * If doing Alt+Esc, wait for up of ESC to get out.
    02370                      */
    02371                     if (gspwndAltTab == NULL)
    02372                         break;
    02373
    02374                     fType = 0;
    02375                     goto Exit;
    02376
    02377                 } else if (vk == VK_ESCAPE || vk == VK_F6) {
    02378                     /*
    02379                      * Get out on up transition of ESC or F6 keys.
    02380                      */
    02381                     if (gspwndAltTab != NULL) {
    02382
    02383                         pwndSel = ptiCurrent->pq->spwndActive;
    02384                         fType = 0;
    02385
    02386                     } else {
    02387
    02388                         fType = ((vk == VK_ESCAPE) ? ALT_ESCAPE : ALT_F6);
    02389                     }
    02390
    02391                     goto Exit;
    02392                 }
    02393
    02394             } else if (msg.message == WM_KEYDOWN) {
    02395                 /*
    02396                  *  Exit out loop is a stray key stroke comes through.  In
    02397                  *  particular look for VK_CONTROL.
    02398                  */
    02399                 pwndSel = ptiCurrent->pq->spwndActive;
    02400                 fType = 0;
    02401                 goto Exit;
    02402             }
    02403             break;
    02404
    02405         case WM_SYSKEYDOWN:
    02406             vk = (WORD)msg.wParam;
    02407
    02408             switch (vk) {
    02409
    02410             case VK_SHIFT:
    02411             case VK_TAB:
    02412             case VK_ESCAPE:
    02413             case VK_F6:
    02414
    02415                 hwndSel = PtoH(pwndSel);
    02416                 xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
    02417
    02418                 if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
    02419                     pwndSel = ptiCurrent->pq->spwndActive;
    02420
    02421                 if (!(vk == VK_TAB))
    02422                     break;
    02423 StartTab:
    02424                 if (vk == VK_ESCAPE) {
    02425                     pwndNewSel = _GetNextQueueWindow(
    02426                             pwndSel,
    02427                             _GetKeyState(VK_SHIFT) < 0,
    02428                             TRUE);
    02429
    02430                     if (pwndNewSel == NULL)
    02431                         break;
    02432
    02433                     fType = ALT_ESCAPE;
    02434                     pwndSel = pwndNewSel;
    02435
    02436                     /*
    02437                      * Wait until ESC goes up to activate new window.
    02438                      */
    02439                     break;
    02440                 }
    02441                 if (vk == VK_F6) {
    02442
    02443                     PWND pwndFirst;
    02444                     PWND pwndSaveSel = pwndSel;
    02445
    02446                     /*
    02447                      * Save the first returned window to act as a limit
    02448                      * to the search because NextTopWindow will return NULL
    02449                      * only if pwndSel is the only window that meets its
    02450                      * selection criteria.
    02451                      *
    02452                      * This prevents a hang that can occur in winword or
    02453                      * excel when then Alt-F4-F6 key combination is hit
    02454                      * and unsaved changes exist.
    02455                      */
    02456                     pwndFirst = pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL,
    02457                             _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
    02458
    02459                     while (TRUE) {
    02460
    02461                         /*
    02462                          * If pwndNewSel is NULL, pwndSel is the only candidate.
    02463                          */
    02464                         if (pwndNewSel == NULL)
    02465                             break;
    02466
    02467                         pwndSel = pwndNewSel;
    02468
    02469                         /*
    02470                          * If the window is on the same thread, wait until
    02471                          * F6 goes up to activate new window.
    02472                          */
    02473                         if (GETPTI(pwndSel) == ptiCurrent)
    02474                             break;
    02475
    02476                         pwndNewSel = (PWND)NextTopWindow(ptiCurrent, pwndSel, NULL,
    02477                                 _GetKeyState(VK_SHIFT) < 0 ? NTW_PREVIOUS : 0);
    02478
    02479                         /*
    02480                          * If we've looped around, use the original window.
    02481                          * Wait until F6 goes up to activate new window.
    02482                          */
    02483                         if (pwndNewSel == pwndFirst) {
    02484                             pwndSel = pwndSaveSel;
    02485                             break;
    02486                         }
    02487                     }
    02488                     break;
    02489                 }
    02490
    02491                 /*
    02492                  * Here for the Alt+Tab case
    02493                  */
    02494                 if ((pwndSwitch = gspwndAltTab) != NULL) {
    02495                     pswCurrent = Getpswi(pwndSwitch);
    02496                     ThreadLockWithPti(ptiCurrent, pwndSwitch, &tlpwndSwitch);
    02497                     hwndStop = NULL;
    02498                     do {
    02499
    02500                         hwndNewSel = xxxMoveSwitchWndHilite(
    02501                                 pwndSwitch,
    02502                                 pswCurrent,
    02503                                 _GetKeyState(VK_SHIFT) < 0);
    02504
    02505                         if (!hwndStop) {
    02506                             hwndStop = hwndNewSel;
    02507                         } else {
    02508                             if (hwndStop == hwndNewSel) {
    02509                                 pwndNewSel = NULL;
    02510                                 break;
    02511                             }
    02512                         }
    02513                         pwndNewSel = RevalidateHwnd(hwndNewSel);
    02514                     } while (!pwndNewSel);
    02515                     ThreadUnlock(&tlpwndSwitch);
    02516                     pwndSel = pwndNewSel;
    02517
    02518                 } else {
    02519
    02520                     pwndNewSel = _GetNextQueueWindow(
    02521                             pwndSel,
    02522                             _GetKeyState(VK_SHIFT) < 0,
    02523                             FALSE);
    02524
    02525                     if (pwndNewSel && pwndNewSel != pwndSel) {
    02526
    02527                         if (!TestWF(pwndSel, WEFTOPMOST)) {
    02528                             /*
    02529                              *  Force the old window to the bottom
    02530                              */
    02531                             ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT);
    02532                             xxxSetWindowPos(pwndSel,
    02533                                             PWND_BOTTOM,
    02534                                             0,
    02535                                             0,
    02536                                             0,
    02537                                             0,
    02538                                             SWP_NOMOVE             |
    02539                                                 SWP_NOSIZE         |
    02540                                                 SWP_NOACTIVATE     |
    02541                                                 SWP_DEFERDRAWING   |
    02542                                                 SWP_NOSENDCHANGING |
    02543                                                 SWP_ASYNCWINDOWPOS);
    02544                             ThreadUnlock(&tlpwndT);
    02545                         }
    02546
    02547                         pwndSel = pwndNewSel; // Will be revalidated at top of loop
    02548                     }
    02549                 }
    02550                 break;
    02551
    02552             default:
    02553                 goto Exit;
    02554             }
    02555             break;
    02556
    02557         default:
    02558             hwndSel = PtoH(pwndSel);
    02559             xxxPeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
    02560             xxxTranslateMessage(&msg, 0);
    02561             xxxDispatchMessage(&msg);
    02562
    02563             if ((pwndSel = RevalidateHwnd(hwndSel)) == NULL)
    02564                 pwndSel = ptiCurrent->pq->spwndActive;
    02565
    02566             break;
    02567         }
    02568     }
    02569
    02570 Exit:
    02571     xxxReleaseCapture();
    02572
    02573     fDrawIcon = (gspwndAltTab != NULL);
    02574
    02575     /*
    02576      * If this is an Alt-Escape we also have to send the current window
    02577      * to the bottom.
    02578      */
    02579     if (fType == ALT_ESCAPE) {
    02580
    02581         PWND pwndActive;
    02582
    02583         if (gpqForeground) {
    02584
    02585             pwndActive = gpqForeground->spwndActive;
    02586
    02587             if (pwndActive && (pwndActive != pwndSel)) {
    02588                 ThreadLockWithPti(ptiCurrent, pwndActive, &tlpwndT);
    02589                 xxxSetWindowPos(pwndActive,
    02590                                 PWND_BOTTOM,
    02591                                 0,
    02592                                 0,
    02593                                 0,
    02594                                 0,
    02595                                 SWP_NOMOVE             |
    02596                                     SWP_NOSIZE         |
    02597                                     SWP_NOACTIVATE     |
    02598                                     SWP_DEFERDRAWING   |
    02599                                     SWP_NOSENDCHANGING |
    02600                                     SWP_ASYNCWINDOWPOS);
    02601                 ThreadUnlock(&tlpwndT);
    02602             }
    02603         }
    02604     }
    02605
    02606     if (pwndSel) {
    02607         ThreadLockWithPti(ptiCurrent, pwndSel, &tlpwndT);
    02608         xxxSetForegroundWindow(pwndSel, FALSE);
    02609
    02610         if (TestWF(pwndSel, WFMINIMIZED)) {
    02611
    02612             if ((fType == 0) && fDrawIcon)
    02613                 _PostMessage(pwndSel, WM_SYSCOMMAND, (UINT)SC_RESTORE, 0);
    02614
    02615         }
    02616         ThreadUnlock(&tlpwndT);
    02617     }
    02618
    02619     /*
    02620      * destroy the alt-tab window
    02621      */
    02622     xxxCancelCoolSwitch();
    02623
    02624     ThreadUnlock(&tlpwndSel);
    02625 }
    02626
    02627 /*****************************************************************************\
    02628 *
    02629 * GetAltTabInfo()   -   Active Accessibility API for OLEACC
    02630 *
    02631 * This succeeds if we are currently in alt-tab mode.
    02632 *
    02633 \*****************************************************************************/
    02634 BOOL WINAPI
    02635 _GetAltTabInfo(
    02636     int iItem,
    02637     PALTTABINFO pati,
    02638     LPWSTR ccxpwszItemText,
    02639     UINT cchItemText OPTIONAL,
    02640     BOOL bAnsi)
    02641 {
    02642     PSWINFO pswCurrent;
    02643
    02644     if (!gspwndAltTab || ((pswCurrent = Getpswi(gspwndAltTab)) == NULL)) {
    02645         RIPERR0(ERROR_NOT_FOUND, RIP_WARNING, "no Alt-Tab window");
    02646         return FALSE;
    02647     }
    02648
    02649     /*
    02650      * Fill in general information
    02651      */
    02652     pati->cItems = pswCurrent->iTotalTasks;
    02653     pati->cColumns = pswCurrent->iNoOfColumns;
    02654     pati->cRows = pswCurrent->iNoOfRows;
    02655
    02656     pati->iColFocus = pswCurrent->iCurCol;
    02657     pati->iRowFocus = pswCurrent->iCurRow;
    02658
    02659     pati->cxItem = CXICONSLOT;
    02660     pati->cyItem = CYICONSLOT;
    02661     pati->ptStart = pswCurrent->ptFirstRowStart;
    02662
    02663     /*
    02664      * Fill in specific information if asked.
    02665      */
    02666     if (cchItemText && (iItem >= 0)) {
    02667         PWND    pwndCur;
    02668
    02669         pwndCur = NULL;
    02670
    02671         try {
    02672             if ((iItem < pswCurrent->iTotalTasks) &&
    02673                     (pwndCur = RevalidateHwnd(pswCurrent->pbwl->rghwnd[iItem]))) {
    02674                 if (bAnsi) {
    02675                     LPSTR ccxpszItemText = (LPSTR)ccxpwszItemText;
    02676                     ULONG cch;
    02677                     RtlUnicodeToMultiByteN(ccxpszItemText, cchItemText - 1,
    02678                             &cch, pwndCur->strName.Buffer, pwndCur->strName.Length);
    02679                     ccxpszItemText[cch] = '\0';
    02680                 } else {
    02681                     TextCopy(&pwndCur->strName, ccxpwszItemText, cchItemText);
    02682                 }
    02683             } else {
    02684                 // no such item
    02685                 NullTerminateString(ccxpwszItemText, bAnsi);
    02686             }
    02687         } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
    02688             return FALSE;
    02689         }
    02690     }
    02691
    02692     return TRUE;
    02693 }