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

focusact.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: focusact.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * History: 00007 * 11-08-90 DavidPe Created. 00008 * 02-11-91 JimA Multi-desktop support. 00009 * 02-13-91 mikeke Added Revalidation code. 00010 * 06-10-91 DavidPe Changed to desynchronized model. 00011 \***************************************************************************/ 00012 00013 #include "precomp.h" 00014 #pragma hdrstop 00015 00016 BOOL RemoveEventMessage(PQ pq, DWORD dwQEvent, DWORD dwQEventStop); 00017 00018 /***************************************************************************\ 00019 * xxxDeactivate 00020 * 00021 * This routine does the processing for the event posted when the foreground 00022 * thread changes. Note the difference in order of assignment vs. message 00023 * sending in the focus and active windows. This is consistent with how 00024 * things are done in Win 3.1. 00025 * 00026 * 00027 * PTHREADINFO pti May not be ptiCurrent if SetForegroundWindow called from 00028 * minmax 00029 * 00030 * History: 00031 * 06-07-91 DavidPe Created. 00032 \***************************************************************************/ 00033 00034 void xxxDeactivate( 00035 PTHREADINFO pti, // May not be ptiCurrent 00036 DWORD tidSetForeground) 00037 { 00038 PWND pwndLose; 00039 AAS aas; 00040 TL tlpwndCapture; 00041 TL tlpwndChild; 00042 TL tlpwndLose; 00043 TL tlpti; 00044 TL tlptiLose; 00045 WPARAM wParam; 00046 PTHREADINFO ptiLose; 00047 PTHREADINFO ptiCurrent = PtiCurrent(); 00048 BOOL fSetActivateAppBit = FALSE; 00049 00050 /* 00051 * If we're not active, we have nothing to deactivate, so just return. 00052 * If we don't return, we'll send redundant WM_ACTIVATEAPP messages. 00053 * Micrografx Draw, for example, calls FreeProcInstance() twice when 00054 * this occurs, thereby crashing. 00055 */ 00056 if (pti->pq->spwndActive == NULL) 00057 return; 00058 00059 /* 00060 * If pti != ptiCurrent, thread lock pti because we may leave 00061 * the critical section. 00062 */ 00063 if (pti != ptiCurrent) 00064 ThreadLockPti(ptiCurrent, pti, &tlpti); 00065 00066 /* 00067 * Prevent an activating WM_ACTIVATEAPP from being sent 00068 * while we're processing this event. 00069 */ 00070 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG)) { 00071 pti->TIF_flags |= TIF_INACTIVATEAPPMSG; 00072 fSetActivateAppBit = TRUE; 00073 } 00074 00075 /* 00076 * Cancel any modes like move/size and menu tracking. 00077 */ 00078 if (pti->pq->spwndCapture != NULL) { 00079 ThreadLockAlwaysWithPti(ptiCurrent, pti->pq->spwndCapture, &tlpwndCapture); 00080 xxxSendMessage(pti->pq->spwndCapture, WM_CANCELMODE, 0, 0); 00081 ThreadUnlock(&tlpwndCapture); 00082 00083 /* 00084 * Set QS_MOUSEMOVE so any sleeping modal loops, 00085 * like the move/size code, will wake up and figure 00086 * out that it should abort. 00087 */ 00088 SetWakeBit(pti, QS_MOUSEMOVE); 00089 } 00090 00091 /* 00092 * See the comments in xxxActivateThisWindow about Harvard Graphics. 00093 * WinWord's Equation editor does some games when it gets the WM_ACTIVATE 00094 * so we have to remember to send the WM_ACTIVATEAPP to ptiLose. 22510 00095 */ 00096 if (pti->pq->spwndActive != NULL) { 00097 pwndLose = pti->pq->spwndActive; 00098 ptiLose = GETPTI(pwndLose); 00099 00100 ThreadLockPti(ptiCurrent, ptiLose, &tlptiLose); 00101 ThreadLockAlwaysWithPti(ptiCurrent, pwndLose, &tlpwndLose); 00102 wParam = MAKELONG(WA_INACTIVE, TestWF(pwndLose, WFMINIMIZED)); 00103 if (!xxxSendMessage(pwndLose, WM_NCACTIVATE, WA_INACTIVE, 0)) { 00104 ThreadUnlock(&tlpwndLose); 00105 ThreadUnlockPti(ptiCurrent, &tlptiLose); 00106 goto Exit; 00107 } 00108 xxxSendMessage(pwndLose, WM_ACTIVATE, wParam, 0); 00109 00110 /* 00111 * Only update the queue's active windows if they weren't 00112 * changed while we were off calling SendMessage. 00113 */ 00114 if (pti->pq->spwndActive == pwndLose) { 00115 Lock(&pti->pq->spwndActivePrev, pti->pq->spwndActive); 00116 Unlock(&pti->pq->spwndActive); 00117 } 00118 00119 /* 00120 * The flag WFFRAMEON is cleared in the default processing of 00121 * WM_NCACTIVATE message. 00122 * We want to clear this flag again here since it might of been 00123 * set in xxxSendNCPaint. 00124 * Pbrush calls DrawMenuBar when it gets the WM_ACTIVATE message 00125 * sent above and this causes xxxSendNCPaint to get called and the 00126 * WFFRAMEON flag gets reset. 00127 */ 00128 ClrWF(pwndLose, WFFRAMEON); 00129 ThreadUnlock(&tlpwndLose); 00130 00131 /* 00132 * Revalidate ptiLose because the thread may have gone away 00133 * when the activation messages were sent above. 00134 */ 00135 aas.ptiNotify = (ptiLose->TIF_flags & TIF_INCLEANUP) ? NULL : ptiLose; 00136 ThreadUnlockPti(ptiCurrent, &tlptiLose); 00137 } else { 00138 00139 /* 00140 * Use a non-NULL special value for the test after 00141 * the xxxActivateApp calls. 00142 */ 00143 pwndLose = (PWND)-1; 00144 aas.ptiNotify = pti; 00145 } 00146 00147 if (aas.ptiNotify) { 00148 aas.tidActDeact = tidSetForeground; 00149 aas.fActivating = FALSE; 00150 aas.fQueueNotify = FALSE; 00151 00152 ThreadLockWithPti(ptiCurrent, 00153 pti->rpdesk->pDeskInfo->spwnd->spwndChild, &tlpwndChild); 00154 xxxInternalEnumWindow(pti->rpdesk->pDeskInfo->spwnd->spwndChild, 00155 (WNDENUMPROC_PWND)xxxActivateApp, (LPARAM)&aas, BWL_ENUMLIST); 00156 ThreadUnlock(&tlpwndChild); 00157 } 00158 00159 /* 00160 * If an app (i.e. Harvard Graphics/Windows Install) tries to 00161 * reactivate itself during a deactivating WM_ACTIVATEAPP 00162 * message, force deactivation. 00163 */ 00164 if (pti->pq->spwndActive == pwndLose) { 00165 00166 ThreadLockWithPti(ptiCurrent, pwndLose, &tlpwndLose); 00167 if (!xxxSendMessage(pwndLose, WM_NCACTIVATE, WA_INACTIVE, 0)) { 00168 ThreadUnlock(&tlpwndLose); 00169 goto Exit; 00170 } 00171 xxxSendMessage(pwndLose, WM_ACTIVATE, WA_INACTIVE, 0); 00172 ThreadUnlock(&tlpwndLose); 00173 00174 /* 00175 * Only update the queue's active windows if they weren't 00176 * changed while we were off calling SendMessage. 00177 */ 00178 if (pti->pq->spwndActive == pwndLose) { 00179 Lock(&pti->pq->spwndActivePrev, pti->pq->spwndActive); 00180 Unlock(&pti->pq->spwndActive); 00181 } 00182 } 00183 00184 if (pti->pq->spwndFocus != NULL) { 00185 pwndLose = Unlock(&pti->pq->spwndFocus); 00186 if (pwndLose != NULL) { 00187 ThreadLockAlwaysWithPti(ptiCurrent, pwndLose, &tlpwndLose); 00188 xxxSendMessage(pwndLose, WM_KILLFOCUS, 0, 0); 00189 #ifdef FE_IME 00190 if (IS_IME_ENABLED()) { 00191 xxxFocusSetInputContext(pwndLose, FALSE, FALSE); 00192 } 00193 #endif 00194 ThreadUnlock(&tlpwndLose); 00195 } 00196 } 00197 00198 Exit: 00199 if (fSetActivateAppBit) { 00200 pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 00201 } 00202 if (pti != ptiCurrent) 00203 ThreadUnlockPti(ptiCurrent, &tlpti); 00204 } 00205 00206 00207 /***************************************************************************\ 00208 * xxxSendFocusMessages 00209 * 00210 * Common routine for xxxSetFocus() and xxxActivateWindow() that sends the 00211 * WM_KILLFOCUS and WM_SETFOCUS messages to the windows losing and 00212 * receiving the focus. This function also sets the local pwndFocus 00213 * to the pwnd receiving the focus. 00214 * 00215 * History: 00216 * 11-08-90 DavidPe Ported. 00217 * 06-06-91 DavidPe Rewrote for local pwndFocus/pwndActive in THREADINFO. 00218 \***************************************************************************/ 00219 00220 void xxxSendFocusMessages( 00221 PTHREADINFO pti, 00222 PWND pwndReceive) 00223 { 00224 PWND pwndLose; 00225 TL tlpwndLose; 00226 00227 CheckLock(pwndReceive); 00228 00229 /* 00230 * Remember if this app set the focus to NULL on purpose after it was 00231 * activated (needed in ActivateThisWindow()). 00232 */ 00233 pti->pq->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE; 00234 if (pwndReceive == NULL && pti->pq->spwndActive != NULL) 00235 pti->pq->QF_flags |= QF_FOCUSNULLSINCEACTIVE; 00236 00237 pwndLose = pti->pq->spwndFocus; 00238 ThreadLockWithPti(pti, pwndLose, &tlpwndLose); 00239 00240 /* 00241 * We shouldn't be locking a valid pwnd from another queue. 00242 */ 00243 UserAssert((pwndReceive == NULL) 00244 || TestWF(pwndReceive, WFDESTROYED) 00245 || (pti->pq == GETPTI(pwndReceive)->pq)); 00246 Lock(&pti->pq->spwndFocus, pwndReceive); 00247 00248 if (pwndReceive == NULL) { 00249 if (pwndLose != NULL) { 00250 /* 00251 * Tell the client that nobody is gaining focus. 00252 */ 00253 if (FWINABLE()) { 00254 xxxWindowEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, INDEXID_OBJECT, 0); 00255 } 00256 xxxSendMessage(pwndLose, WM_KILLFOCUS, 0, 0); 00257 #ifdef FE_IME 00258 if (IS_IME_ENABLED()) { 00259 xxxFocusSetInputContext(pwndLose, FALSE, FALSE); 00260 } 00261 #endif 00262 } 00263 } else { 00264 00265 /* 00266 * Make this thread foreground so its base 00267 * priority get set higher. 00268 */ 00269 if (pti->pq == gpqForeground) 00270 SetForegroundThread(GETPTI(pwndReceive)); 00271 00272 if (pwndLose != NULL) { 00273 xxxSendMessage(pwndLose, WM_KILLFOCUS, (WPARAM)HWq(pwndReceive), 0); 00274 #ifdef FE_IME 00275 if (IS_IME_ENABLED()) { 00276 xxxFocusSetInputContext(pwndLose, FALSE, FALSE); 00277 } 00278 #endif 00279 } 00280 00281 /* 00282 * Send the WM_SETFOCUS message, but only if the window we're 00283 * setting the focus to still has the focus! This allows apps 00284 * to prevent themselves from losing the focus by catching 00285 * the WM_NCACTIVATE message and returning FALSE or by calling 00286 * SetFocus() inside their WM_KILLFOCUS handler. 00287 */ 00288 if (pwndReceive == pti->pq->spwndFocus) { 00289 #ifdef FE_IME 00290 if (IS_IME_ENABLED()) { 00291 xxxFocusSetInputContext(pwndReceive, TRUE, FALSE); 00292 } 00293 #endif 00294 /* 00295 * We have to do this BEFORE sending the WM_SETFOCUS message. 00296 * The app, upon receiving it, very well may turn around and 00297 * SetFocus() to a child window. 00298 */ 00299 if (FWINABLE()) { 00300 xxxWindowEvent(EVENT_OBJECT_FOCUS, pwndReceive, OBJID_CLIENT, 00301 INDEXID_OBJECT, 0); 00302 } 00303 xxxSendMessage(pwndReceive, WM_SETFOCUS, (WPARAM)HW(pwndLose), 0); 00304 } 00305 } 00306 00307 ThreadUnlock(&tlpwndLose); 00308 } 00309 00310 00311 /***************************************************************************\ 00312 * xxxActivateApp 00313 * 00314 * xxxEnumWindows call-back function to send the WM_ACTIVATEAPP 00315 * message to the appropriate windows. 00316 * 00317 * We search for windows whose pq == HIWORD(lParam). Once we find 00318 * one, we send a WM_ACTIVATEAPP message to that window. The wParam 00319 * of the message is FALSE if the app is losing the activation and 00320 * TRUE if the app is gaining the activation. The lParam is the 00321 * task handle of the app gaining the activation if wParam is FALSE 00322 * and the task handle of the app losing the activation if wParam 00323 * is TRUE. 00324 * 00325 * lParam = (HIWORD) : pq of app that we are searching for 00326 * (LOWORD) : pq of app that we notify about 00327 * 00328 * fDoActivate = TRUE : Send activate 00329 * FALSE : Send deactivate 00330 * 00331 * History: 00332 * 11-08-90 DavidPe Ported. 00333 * 06-26-91 DavidPe Changed for desync focus/activation. 00334 \***************************************************************************/ 00335 00336 BOOL xxxActivateApp( 00337 PWND pwnd, 00338 AAS *paas) 00339 { 00340 CheckLock(pwnd); 00341 00342 if (GETPTI(pwnd) == paas->ptiNotify) { 00343 00344 if (paas->fQueueNotify) { 00345 QueueNotifyMessage(pwnd, WM_ACTIVATEAPP, paas->fActivating, 00346 paas->tidActDeact); 00347 } else { 00348 xxxSendMessage(pwnd, WM_ACTIVATEAPP, paas->fActivating, 00349 paas->tidActDeact); 00350 } 00351 } 00352 00353 return TRUE; 00354 } 00355 00356 00357 /***************************************************************************\ 00358 * FBadWindow 00359 * 00360 * 00361 * History: 00362 * 11-08-90 DavidPe Ported. 00363 \***************************************************************************/ 00364 00365 BOOL FBadWindow( 00366 PWND pwnd) 00367 { 00368 return (pwnd == NULL 00369 || !TestWF(pwnd, WFVISIBLE) 00370 || TestWF(pwnd, WFDISABLED)); 00371 } 00372 00373 00374 void xxxUpdateTray(PWND pwnd) 00375 { 00376 PWND pwndT; 00377 00378 CheckLock(pwnd); 00379 if (!TestWF(pwnd, WFVISIBLE)) { 00380 return; 00381 } 00382 00383 for (pwndT = pwnd; pwndT->spwndOwner; pwndT = pwndT->spwndOwner) { 00384 } 00385 00386 // Notify the shell hook about this activation change 00387 if ( GETPTI(pwndT)->pq == gpqForeground && 00388 FDoTray() && 00389 (FCallHookTray() || FPostTray(pwndT->head.rpdesk)) && 00390 FTopLevel(pwndT) && 00391 TestWF(pwndT, WFVISIBLE)) 00392 { 00393 BOOL fFirstTry; 00394 BOOL fTryAgain; 00395 PWND pwndArg; 00396 TL tlpwndArg; 00397 00398 fFirstTry = TRUE; 00399 do { 00400 fTryAgain = FALSE; 00401 if (TestWF(pwndT, WFWIN40COMPAT)) { 00402 if (TestWF(pwnd, WFWIN40COMPAT) && IsTrayWindow(pwnd)) { 00403 pwndArg = pwnd; 00404 } else { 00405 pwndArg = IsTrayWindow(pwndT) ? pwndT : NULL; 00406 } 00407 } else { 00408 if (TestWF(pwndT, WEFTOOLWINDOW)) { 00409 pwndArg = NULL; 00410 } else if (FHas31TrayStyles(pwndT)) { 00411 pwndArg = Is31TrayWindow(pwndT) ? pwndT : NULL; 00412 } else if (fFirstTry && (pwndT = pwndT->spwndLastActive)) { 00413 fFirstTry = FALSE; 00414 fTryAgain = TRUE; 00415 } else { 00416 return; 00417 } 00418 } 00419 } while (fTryAgain); 00420 00421 ThreadLock(pwndArg, &tlpwndArg); 00422 xxxSetTrayWindow( 00423 (pwndArg) ? pwndArg->head.rpdesk : pwndT->head.rpdesk, 00424 pwndArg, 00425 NULL); 00426 00427 ThreadUnlock(&tlpwndArg); 00428 } 00429 } 00430 00431 /***************************************************************************\ 00432 * xxxActivateThisWindow 00433 * 00434 * This function is the workhorse for window activation. It will attempt to 00435 * activate the pwnd specified. The other parameters are defined as: 00436 * 00437 * fFlags This is a flag-mask which defines how the routine is called. 00438 * These flags are defined as follows: 00439 * 00440 * ATW_MOUSE This is set if activation is changing due to a 00441 * mouse click and not set if some other action 00442 * caused this window to be activated. This bit 00443 * determines the value of wParam on the 00444 * WM_ACTIVATE message. 00445 * 00446 * ATW_SETFOCUS This parameter is set if this routine should 00447 * set the focus to NULL. If we are called from 00448 * the xsxSetFocus() function this will not be 00449 * set indicating that we shouldn't screw with the 00450 * focus. Normally (if we are not called from 00451 * xxxSetFocus), we set the focus to NULL here 00452 * and either the app or xxxDefWindowProc() sets 00453 * the focus to the appropriate window. If the 00454 * bit is not set, we don't want to do anything 00455 * with focus. The app may still do a call to 00456 * xxxSetFocus() when the WM_ACTIVATE comes 00457 * through, but it will just be redundant on its 00458 * part. 00459 * 00460 * ATW_ASYNC This bit is set if we are processing this 00461 * routine from an asynchronous activate (i.e. 00462 * xxxProcessEventMessage()). In this case, we 00463 * make sure that we are the foreground queue 00464 * before determining if we bring the window to 00465 * top. 00466 * 00467 * History: 00468 * 11-08-90 DavidPe Ported. 00469 * 05-01-95 ChrisWil changed bool-flags to 1 ATW_ type. 00470 \***************************************************************************/ 00471 00472 BOOL xxxActivateThisWindow( 00473 PWND pwnd, 00474 DWORD tidLoseForeground, 00475 DWORD fFlags) 00476 { 00477 PTHREADINFO ptiCurrent = PtiCurrent(); 00478 PWND pwndT, pwndActivePrev, pwndActiveSave; 00479 TL tlpwndActive; 00480 TL tlpwndChild; 00481 TL tlpwndActivePrev; 00482 WPARAM wParam; 00483 BOOL fSetActivateAppBit; 00484 00485 BOOL fMouse = (BOOL)(fFlags & ATW_MOUSE); 00486 BOOL fSetFocus = (BOOL)(fFlags & ATW_SETFOCUS); 00487 BOOL fAsync = (BOOL)(fFlags & ATW_ASYNC); 00488 00489 #if DBG 00490 PQ pqSave = ptiCurrent->pq; 00491 #endif 00492 00493 00494 CheckLock(pwnd); 00495 00496 /* 00497 * If pwnd is NULL, then we can't do anything. 00498 */ 00499 if ((pwnd == NULL) || (pwnd == PWNDDESKTOP(pwnd))) { 00500 return FALSE; 00501 } 00502 00503 /* 00504 * Don't activate a window that has been destroyed. 00505 */ 00506 if (HMIsMarkDestroy(pwnd)) 00507 return FALSE; 00508 00509 /* 00510 * We don't activate top-level windows of a different queue. 00511 */ 00512 if (GETPTI(pwnd)->pq != ptiCurrent->pq) { 00513 return FALSE; 00514 } 00515 00516 pwndActiveSave = ptiCurrent->pq->spwndActive; 00517 00518 /* 00519 * Do the change-in-activation if the two-windows are different, 00520 * and if we're not recursing 00521 */ 00522 if ((pwnd != pwndActiveSave) && !TestWF(pwnd, WFBEINGACTIVATED)) { 00523 00524 /* 00525 * Ask the CBT hook whether it is OK to activate this window. 00526 */ 00527 { 00528 CBTACTIVATESTRUCT CbtActivateParams; 00529 00530 if (IsHooked(ptiCurrent, WHF_CBT)) { 00531 00532 CbtActivateParams.fMouse = fMouse; 00533 CbtActivateParams.hWndActive = HW(pwndActiveSave); 00534 00535 if (xxxCallHook(HCBT_ACTIVATE, 00536 (WPARAM)HWq(pwnd), (LPARAM)&CbtActivateParams, WH_CBT)) { 00537 return FALSE; 00538 } 00539 } 00540 } 00541 00542 ptiCurrent->pq->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED; 00543 00544 /* 00545 * If the active window went away but somehow was left referenced 00546 * in the queue, then we do not want to do any deactivation of 00547 * that window. 00548 * 00549 * Don't thread lock this because the next thing we do with it 00550 * is just an equality check. 00551 * 00552 * A DBG check is placed in xxxDestroyWindow to attempt to 00553 * catch the situation where we return from the function with 00554 * the destroyed window set in the active (pq). If that situation 00555 * can be detected and solved, then this conditional might be 00556 * removed: ChrisWil - 08/22/95. 00557 */ 00558 if (ptiCurrent->pq->spwndActive && TestWF(ptiCurrent->pq->spwndActive, WFDESTROYED)) { 00559 Lock(&ptiCurrent->pq->spwndActive, NULL); 00560 } else { 00561 Lock(&ptiCurrent->pq->spwndActivePrev, ptiCurrent->pq->spwndActive); 00562 } 00563 pwndActivePrev = ptiCurrent->pq->spwndActive; 00564 00565 /* 00566 * If there was a previously active window, 00567 * and we're in the foreground then assign 00568 * gpqForegroundPrev to ourself. 00569 */ 00570 if ((pwndActivePrev != NULL) && (ptiCurrent->pq == gpqForeground)) { 00571 gpqForegroundPrev = ptiCurrent->pq; 00572 } 00573 00574 /* 00575 * Deactivate currently active window if possible. 00576 */ 00577 if (pwndActivePrev != NULL) { 00578 ThreadLockWithPti(ptiCurrent, pwndActivePrev, &tlpwndActive); 00579 00580 /* 00581 * The active window can prevent itself from losing the 00582 * activation by returning FALSE to this WM_NCACTIVATE message 00583 */ 00584 wParam = MAKELONG(WA_INACTIVE, TestWF(pwndActivePrev, WFMINIMIZED)); 00585 if (!xxxSendMessage(pwndActivePrev, WM_NCACTIVATE, 00586 wParam, (LPARAM)HWq(pwnd))) { 00587 ThreadUnlock(&tlpwndActive); 00588 return FALSE; 00589 } 00590 00591 xxxSendMessage(pwndActivePrev, WM_ACTIVATE, wParam, (LPARAM)HWq(pwnd)); 00592 00593 ThreadUnlock(&tlpwndActive); 00594 } 00595 00596 /* 00597 * If the activation changed while we were gone, we'd better 00598 * not send any more messages, since they'd go to the wrong window. 00599 * (and, they've already been sent anyhow) 00600 */ 00601 if (ptiCurrent->pq->spwndActivePrev != ptiCurrent->pq->spwndActive || 00602 pwndActiveSave != ptiCurrent->pq->spwndActive) { 00603 #if DBG 00604 if (ptiCurrent->pq->spwndActivePrev == ptiCurrent->pq->spwndActive) { 00605 RIPMSG0(RIP_WARNING, "xxxActivateThisWindow: ptiCurrent->pq->spwndActive changed in callbacks"); 00606 } 00607 #endif 00608 return FALSE; 00609 } 00610 00611 /* 00612 * If the window being activated has been destroyed, don't 00613 * do anything else. Making it the active window in this 00614 * case can cause console to hang during shutdown. 00615 */ 00616 if (HMIsMarkDestroy(pwnd)) 00617 return FALSE; 00618 00619 /* 00620 * Before we lock the new pwndActivate, make sure we're still 00621 * on the same queue. 00622 */ 00623 if (GETPTI(pwnd)->pq != ptiCurrent->pq) { 00624 RIPMSG1(RIP_WARNING, "xxxActivateThisWindow: Queue unattached:%#p", pqSave); 00625 return FALSE; 00626 } 00627 00628 /* 00629 * This bit, which means the app set the focus to NULL after becoming 00630 * active, doesn't make sense if the app is just becoming active, so 00631 * clear it in this case. It is used below in this routine to 00632 * determine whether to send focus messages (read comment in this 00633 * routine). 00634 */ 00635 if (ptiCurrent->pq->spwndActive == NULL) 00636 ptiCurrent->pq->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE; 00637 00638 Lock(&ptiCurrent->pq->spwndActive, pwnd); 00639 00640 /* 00641 * Tp prevent recursion, set pwnd's WFBEINGACTIVATED bit. 00642 * Recursion can happen if we have an activation battle with other 00643 * threads which keep changing ptiCurrent->pq->spwndActive behind our 00644 * callbacks. 00645 * WARNING: Do NOT return from this routine without clearing this bit! 00646 */ 00647 SetWF(pwnd, WFBEINGACTIVATED); 00648 00649 if (FWINABLE()) { 00650 xxxWindowEvent(EVENT_SYSTEM_FOREGROUND, pwnd, OBJID_WINDOW, INDEXID_OBJECT, WEF_USEPWNDTHREAD); 00651 } 00652 00653 /* 00654 * Remove all async activates up to the next async deactivate. We 00655 * do this so that any queued activates don't reset this synchronous 00656 * activation state we're now setting. Only remove up till the next 00657 * deactivate because active state is synchronized with reading 00658 * input from the input queue. 00659 * 00660 * For example, an activate event gets put in an apps queue. Before 00661 * processing it the app calls ActivateWindow(), which is synchronous. 00662 * You want the ActivateWindow() to win because it is newer 00663 * information. 00664 * 00665 * msmail32 demonstrates this. Minimize msmail. Alt-tab to it. It 00666 * brings up the password dialog, but it isn't active. It correctly 00667 * activates the password dialog but then processes an old activate 00668 * event activating the icon, so the password dialog is not active. 00669 */ 00670 RemoveEventMessage(ptiCurrent->pq, QEVENT_ACTIVATE, QEVENT_DEACTIVATE); 00671 00672 xxxMakeWindowForegroundWithState(NULL, 0); 00673 00674 pwndActivePrev = ptiCurrent->pq->spwndActivePrev; 00675 ThreadLockWithPti(ptiCurrent, pwndActivePrev, &tlpwndActivePrev); 00676 00677 if (TEST_PUSIF(PUSIF_PALETTEDISPLAY) && xxxSendMessage(pwnd, WM_QUERYNEWPALETTE, 0, 0)) { 00678 xxxSendNotifyMessage(PWND_BROADCAST, WM_PALETTEISCHANGING, 00679 (WPARAM)HWq(pwnd), 0); 00680 } 00681 00682 /* 00683 * If the window becoming active is not already the top window in the 00684 * Z-order, then call xxxBringWindowToTop() to do so. 00685 */ 00686 00687 /* 00688 * If this isn't a child window, first check to see if the 00689 * window isn't already 'on top'. If not, then call 00690 * xxxBringWindowToTop(). 00691 */ 00692 if (!(fFlags & ATW_NOZORDER) && !TestWF(pwnd, WFCHILD)) { 00693 00694 /* 00695 * Look for the first visible child of the desktop. 00696 * ScottLu changed this to start looking at the desktop 00697 * window. Since the desktop window was always visible, 00698 * BringWindowToTop was always called regardless of whether 00699 * it was needed or not. No one can remember why this 00700 * change was made, so I'll change it back to the way it 00701 * was in Windows 3.1. - JerrySh 00702 */ 00703 pwndT = PWNDDESKTOP(pwnd)->spwndChild; 00704 00705 while (pwndT && (!TestWF(pwndT, WFVISIBLE))) { 00706 pwndT = pwndT->spwndNext; 00707 } 00708 00709 /* 00710 * If this activation came from an async call (i.e. 00711 * xxxProcessEventMessage), we need to check to see 00712 * if the thread is the foreground-queue. If not, then 00713 * we do not want to bring the window to the top. This 00714 * is because another window could have already been 00715 * place on top w/foreground. Bringing the window to 00716 * the top in this case would result in a top-level window 00717 * without activation. - ChrisWil 00718 * 00719 * Added a check to see if the previous-active window went 00720 * invisible during the deactivation time. This will ensure 00721 * that we bring the new window to the top. Otherwise, we 00722 * could end up skipping over the previous-window from the 00723 * above tests. Office95 apps demonstrate this behaviour by 00724 * turning their windows invisible during the painting of their 00725 * captionbars. By the time we use to get here, we failed to 00726 * bring the new window to top. 00727 */ 00728 if ((pwnd != pwndT) || (pwndActivePrev && !IsVisible(pwndActivePrev))) { 00729 00730 if (!(fAsync && (gpqForeground != ptiCurrent->pq))) { 00731 DWORD dwFlags; 00732 00733 /* 00734 * Bring the window to the top. If we're already 00735 * activating the window, don't reactivate it. 00736 */ 00737 dwFlags = SWP_NOSIZE | SWP_NOMOVE; 00738 if (pwnd == pwndT) 00739 dwFlags |= SWP_NOACTIVATE; 00740 00741 xxxSetWindowPos(pwnd, PWND_TOP, 0, 0, 0, 0, dwFlags); 00742 } 00743 } 00744 } 00745 00746 /* 00747 * If there was no previous active window, or if the 00748 * previously active window belonged to another thread 00749 * send the WM_ACTIVATEAPP messages. The fActivate == FALSE 00750 * case is handled in xxxDeactivate when 'hwndActivePrev == NULL'. 00751 * 00752 * Harvard Graphics/Windows setup calls SetActiveWindow when it 00753 * receives a deactivationg WM_ACTIVATEAPP. The TIF_INACTIVATEAPPMSG 00754 * prevents an activating WM_ACTIVATEAPP(TRUE) from being sent while 00755 * deactivation is occuring. 00756 */ 00757 fSetActivateAppBit = FALSE; 00758 if (!(ptiCurrent->TIF_flags & TIF_INACTIVATEAPPMSG) && 00759 ((pwndActivePrev == NULL) || 00760 (GETPTI(pwndActivePrev) != GETPTI(pwnd)))) { 00761 AAS aas; 00762 00763 /* 00764 * First send the deactivating WM_ACTIVATEAPP if there 00765 * was a previously active window of another thread in 00766 * the current queue. 00767 */ 00768 if (pwndActivePrev != NULL) { 00769 PTHREADINFO ptiPrev = GETPTI(pwndActivePrev); 00770 TL tlptiPrev; 00771 00772 /* 00773 * Ensure that the other thread can't recurse 00774 * and send more WM_ACTIVATEAPP msgs. 00775 */ 00776 ptiPrev->TIF_flags |= TIF_INACTIVATEAPPMSG; 00777 00778 aas.ptiNotify = ptiPrev; 00779 aas.tidActDeact = TIDq(ptiCurrent); 00780 aas.fActivating = FALSE; 00781 aas.fQueueNotify = FALSE; 00782 00783 ThreadLockPti(ptiCurrent, ptiPrev, &tlptiPrev); 00784 ThreadLockWithPti(ptiCurrent, pwndActivePrev->head.rpdesk->pDeskInfo->spwnd->spwndChild, &tlpwndChild); 00785 xxxInternalEnumWindow(pwndActivePrev->head.rpdesk->pDeskInfo->spwnd->spwndChild, 00786 (WNDENUMPROC_PWND)xxxActivateApp, (LPARAM)&aas, BWL_ENUMLIST); 00787 ThreadUnlock(&tlpwndChild); 00788 ptiPrev->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 00789 ThreadUnlockPti(ptiCurrent, &tlptiPrev); 00790 } 00791 00792 /* 00793 * This will ensure that the current thread will not 00794 * send any more WM_ACTIVATEAPP messages until it 00795 * is done performing its activation. 00796 */ 00797 ptiCurrent->TIF_flags |= TIF_INACTIVATEAPPMSG; 00798 fSetActivateAppBit = TRUE; 00799 00800 aas.ptiNotify = GETPTI(pwnd); 00801 aas.tidActDeact = tidLoseForeground; 00802 aas.fActivating = TRUE; 00803 aas.fQueueNotify = FALSE; 00804 00805 ThreadLockWithPti(ptiCurrent, ptiCurrent->rpdesk->pDeskInfo->spwnd->spwndChild, &tlpwndChild); 00806 xxxInternalEnumWindow(ptiCurrent->rpdesk->pDeskInfo->spwnd->spwndChild, 00807 (WNDENUMPROC_PWND)xxxActivateApp, (LPARAM)&aas, BWL_ENUMLIST); 00808 ThreadUnlock(&tlpwndChild); 00809 } 00810 00811 /* 00812 * If this window has already been drawn as active, set the 00813 * flag so that we don't draw it again. 00814 */ 00815 if (TestWF(pwnd, WFFRAMEON)) { 00816 SetWF(pwnd, WFNONCPAINT); 00817 } 00818 00819 /* 00820 * If the window is marked for destruction, don't do 00821 * the lock because xxxFreeWindow has already been called 00822 * and a lock here will result in the window locking itself 00823 * and never being freed. 00824 */ 00825 if (!HMIsMarkDestroy(pwnd)) { 00826 00827 /* 00828 * Set most recently active window in owner/ownee list. 00829 */ 00830 pwndT = pwnd; 00831 while (pwndT->spwndOwner != NULL) { 00832 pwndT = pwndT->spwndOwner; 00833 } 00834 Lock(&pwndT->spwndLastActive, pwnd); 00835 } 00836 00837 00838 xxxSendMessage(pwnd, WM_NCACTIVATE, 00839 MAKELONG(GETPTI(pwnd)->pq == gpqForeground, 00840 ptiCurrent->pq->spwndActive != NULL ? 00841 TestWF(ptiCurrent->pq->spwndActive, WFMINIMIZED) : 0), 00842 (LPARAM)HW(pwndActivePrev)); 00843 00844 if (ptiCurrent->pq->spwndActive != NULL) { 00845 xxxSendMessage(pwnd, WM_ACTIVATE, 00846 MAKELONG((fMouse ? WA_CLICKACTIVE : WA_ACTIVE), 00847 TestWF(ptiCurrent->pq->spwndActive, WFMINIMIZED)), 00848 (LPARAM)HW(pwndActivePrev)); 00849 } else { 00850 xxxSendMessage(pwnd, WM_ACTIVATE, 00851 MAKELONG((fMouse ? WA_CLICKACTIVE : WA_ACTIVE), 0), 00852 (LPARAM)HW(pwndActivePrev)); 00853 } 00854 00855 xxxUpdateTray(pwnd); 00856 00857 ThreadUnlock(&tlpwndActivePrev); 00858 00859 ClrWF(pwnd, WFNONCPAINT); 00860 00861 /* 00862 * If xxxActivateThisWindow() is called from xxxSetFocus() then 00863 * fSetFocus is FALSE. In this case, we don't set the focus since 00864 * xxxSetFocus() will do that for us. Otherwise, we set the focus 00865 * to the newly activated window if the window with the focus is 00866 * not the new active window or one of its children. Normally, 00867 * xxxDefWindowProc() will set the focus. 00868 */ 00869 ThreadLockWithPti(ptiCurrent, ptiCurrent->pq->spwndActive, &tlpwndActive); 00870 00871 /* 00872 * Win3.1 checks spwndFocus != NULL - we check QF_FOCUSNULLSINCEACTIVE, 00873 * which is the win32 equivalent. On win32, 32 bit apps each have their 00874 * own focus. If the app is not foreground, most of the time spwndFocus 00875 * is NULL when the window is being activated and brought to the 00876 * foreground. It wouldn't go through this code in this case. Win3.1 in 00877 * effect is checking if the previous active application had an 00878 * hwndFocus != NULL. Win32 effectively assumes the last window has a 00879 * non-NULL hwndFocus, so win32 instead checks to see if the focus has 00880 * been set to NULL since this application became active (meaning, did 00881 * it purposefully set the focus to NULL). If it did, don't go through 00882 * this codepath (like win3.1). If it didn't, go through this code path 00883 * because the previous application had an hwndFocus != NULL 00884 * (like win3.1). Effectively it is the same check as win3.1, but 00885 * updated to deal with async input. 00886 * 00887 * Case in point: bring up progman, hit f1 (to get win32 help). Click 00888 * history to get a popup (has the focus in a listbox in the client 00889 * area). Activate another app, now click on title bar only of history 00890 * popup. The focus should get set by going through this code path. 00891 * 00892 * Alternate case: Ventura Publisher brings up "Special Effects" 00893 * dialog. If "Bullet" from this dialog was clicked last time the 00894 * dialog was brought up, sending focus messages here when 00895 * hwndFocus == NULL, would reset the focus to "None" incorrectly 00896 * because Ventura does its state setting when it gets the focus 00897 * messages. The real focus messages it is depending on are the 00898 * ones that come from the SetFocus() call in DlgSetFocus() in 00899 * the dialog management code. (In this case, before the dialog 00900 * comes up, focus == active window. When the dialog comes up 00901 * and EnableWindow(hwndOwner, FALSE) is called, EnableWindow() calls 00902 * SetFocus(NULL) (because it is disabling the window that is also 00903 * the focus window). When the dialog comes up it gets activated via 00904 * SwpActivate(), but since the focus is NULL vpwin does not expect 00905 * to go through this code path.) 00906 * 00907 * - scottlu 00908 */ 00909 #if 0 00910 // this is what win3.1 does - which won't work for win32 00911 00912 if (fSetFocus && ptiCurrent->pq->spwndFocus != NULL && ptiCurrent->pq->spwndActive != 00913 GetTopLevelWindow(ptiCurrent->pq->spwndFocus)) 00914 #else 00915 if (fSetFocus && !(ptiCurrent->pq->QF_flags & QF_FOCUSNULLSINCEACTIVE) && 00916 ptiCurrent->pq->spwndActive != GetTopLevelWindow(ptiCurrent->pq->spwndFocus)) { 00917 #endif 00918 00919 xxxSendFocusMessages(ptiCurrent, 00920 (ptiCurrent->pq->spwndActive != NULL && 00921 TestWF(ptiCurrent->pq->spwndActive, WFMINIMIZED)) ? 00922 NULL : ptiCurrent->pq->spwndActive); 00923 } 00924 00925 ThreadUnlock(&tlpwndActive); 00926 00927 /* 00928 * This flag is examined in the menu loop code so that we exit from 00929 * menu mode if another window was activated while we were tracking 00930 * menus. 00931 */ 00932 ptiCurrent->pq->QF_flags |= QF_ACTIVATIONCHANGE; 00933 00934 if (gppiScreenSaver == NULL) { 00935 00936 /* 00937 * Activation has occurred, update our last idle time counter if 00938 * we're on the input desktop. 00939 */ 00940 if (ptiCurrent->rpdesk == grpdeskRitInput) { 00941 glinp.timeLastInputMessage = NtGetTickCount(); 00942 } 00943 00944 } else { 00945 00946 if (GETPTI(pwnd)->ppi != gppiScreenSaver) { 00947 /* 00948 * Activation ocurred by an app other than the screen saver. 00949 * Update the idle time counter and mark our screen saver as 00950 * active (so it can quit). 00951 */ 00952 00953 #if 0 00954 // LATER 00955 if (ptiCurrent->rpdesk != gppiScreenSaver->rpdeskStartup) { 00956 /* 00957 * Activation is occurring on different desktops, let WinLogon decide 00958 * if it wants to switch. 00959 */ 00960 } 00961 #endif 00962 00963 glinp.timeLastInputMessage = NtGetTickCount(); 00964 gppiScreenSaver->W32PF_Flags &= ~W32PF_IDLESCREENSAVER; 00965 SetForegroundPriorityProcess(gppiScreenSaver, gppiScreenSaver->ptiMainThread, TRUE); 00966 } 00967 } 00968 00969 /* 00970 * If WM_ACTIVATEAPP messages were sent, it is now 00971 * safe to allow them to be sent again. 00972 */ 00973 if (fSetActivateAppBit) 00974 ptiCurrent->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 00975 00976 00977 } else { 00978 #if DBG 00979 if (TestWF(pwnd, WFBEINGACTIVATED)) { 00980 RIPMSG1(RIP_WARNING, "xxxActivateThisWindow recursing on pwnd %#p\n", pwnd); 00981 } 00982 #endif 00983 ptiCurrent->pq->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED; 00984 if (TEST_PUSIF(PUSIF_PALETTEDISPLAY) && xxxSendMessage(pwnd, WM_QUERYNEWPALETTE, 0, 0)) { 00985 xxxSendNotifyMessage(PWND_BROADCAST, WM_PALETTEISCHANGING, 00986 (WPARAM)HWq(pwnd), 0); 00987 } 00988 } 00989 00990 ClrWF(pwnd, WFBEINGACTIVATED); 00991 return ptiCurrent->pq->spwndActive == pwnd; 00992 } 00993 00994 00995 /***************************************************************************\ 00996 * RemoveEventMessage 00997 * 00998 * Removes events dwQEvent until finding dwQEventStop. Used for removing 00999 * activate and deactivate events. 01000 * 01001 * 04-01-93 ScottLu Created. 01002 \***************************************************************************/ 01003 01004 BOOL RemoveEventMessage( 01005 PQ pq, 01006 DWORD dwQEvent, 01007 DWORD dwQEventStop) 01008 { 01009 PQMSG pqmsgT; 01010 PQMSG pqmsgPrev; 01011 BOOL bRemovedEvent = FALSE; 01012 01013 /* 01014 * Remove all events dwQEvent until finding dwQEventStop. 01015 */ 01016 for (pqmsgT = pq->mlInput.pqmsgWriteLast; pqmsgT != NULL; ) { 01017 01018 if (pqmsgT->dwQEvent == dwQEventStop) 01019 return(bRemovedEvent); 01020 01021 pqmsgPrev = pqmsgT->pqmsgPrev; 01022 01023 /* 01024 * If the event is found and is not the one being peeked, 01025 * delete it. 01026 */ 01027 if (pqmsgT->dwQEvent == dwQEvent && 01028 pqmsgT != (PQMSG)pq->idSysPeek) { 01029 DelQEntry(&(pq->mlInput), pqmsgT); 01030 bRemovedEvent = TRUE; 01031 } 01032 pqmsgT = pqmsgPrev; 01033 } 01034 return(bRemovedEvent); 01035 } 01036 01037 01038 /***************************************************************************\ 01039 * CanForceForeground 01040 * 01041 * A process can NOT force a new foreground when: 01042 * -There is a last input owner glinp.ptiLastWoken), and 01043 * -The process didn't get the last hot key, key or mouse click, and 01044 * -There is a thread with foreground priority gptiForeground), and 01045 * -The process doesn't own the foreground thread, and 01046 * -The process doesn't have foreground activation right, and 01047 * -The process was not the last one to do SendInput/JournalPlayBack 01048 * -There is a foreground queue, and 01049 * -The last input owner is not being debugged, and 01050 * -The foreground process is not being debugged, and 01051 * -The last input was not long ago 01052 * 01053 * History: 01054 * 05/12/97 GerardoB Extracted from xxxSetForegroundWindow 01055 \***************************************************************************/ 01056 BOOL CanForceForeground(PPROCESSINFO ppi) 01057 { 01058 01059 if ((glinp.ptiLastWoken != NULL) 01060 && (glinp.ptiLastWoken->ppi != ppi) 01061 && (gptiForeground != NULL) 01062 && (gptiForeground->ppi != ppi) 01063 && !(ppi->W32PF_Flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_ALLOWSETFOREGROUND)) 01064 && (ppi != gppiInputProvider) 01065 && (gpqForeground != NULL) 01066 && 01067 #if DBG 01068 /* 01069 * When attaching the debugger to the foreground app, this function always 01070 * returns TRUE. In order to be able to debug anything related to this 01071 * function in such case, set this global to TRUE. 01072 */ 01073 (gfDebugForegroundIgnoreDebugPort 01074 || ( 01075 #endif 01076 (glinp.ptiLastWoken->ppi->Process->DebugPort == NULL) 01077 && (gptiForeground->ppi->Process->DebugPort == NULL) 01078 #if DBG 01079 )) 01080 #endif 01081 && !IsTimeFromLastRITEvent(UP(FOREGROUNDLOCKTIMEOUT))) { 01082 01083 return FALSE; 01084 } else { 01085 return TRUE; 01086 } 01087 01088 } 01089 /***************************************************************************\ 01090 * AllowSetForegroundWindow (5.0 API) 01091 * 01092 * This API is meant to be called by the foreground process to allow another 01093 * process to take the foreground. 01094 * This is implemented by making a thread in dwProcessId the owner of the last 01095 * input event. This means that dwProcessId keeps the right to take the foreground 01096 * until the user generates new input (unless the input is direct to dwProcessId itself). 01097 * 01098 * History: 01099 * 01-28-98 GerardoB Created. 01100 \***************************************************************************/ 01101 BOOL xxxAllowSetForegroundWindow( 01102 DWORD dwProcessId) 01103 { 01104 DWORD dwError; 01105 PEPROCESS pep; 01106 NTSTATUS Status; 01107 PPROCESSINFO ppi; 01108 /* 01109 * Get the ppi for dwProcessId 01110 * ASFW_ANY NULLs out the input owner so any process can take the foreground 01111 */ 01112 if (dwProcessId != ASFW_ANY) { 01113 LeaveCrit(); 01114 Status = LockProcessByClientId((HANDLE)LongToHandle( dwProcessId ), &pep); 01115 EnterCrit(); 01116 if (!NT_SUCCESS(Status)) { 01117 RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, ""); 01118 return FALSE; 01119 } 01120 ppi = PpiFromProcess(pep); 01121 if (ppi == NULL) { 01122 dwError = ERROR_INVALID_PARAMETER; 01123 goto UnlockAndFail; 01124 } 01125 } 01126 /* 01127 * Do nothing if the current process cannot force a foreground change. 01128 * We could have checked this upfront but we didn't since we had to 01129 * leave the crit section and the state could have changed. 01130 */ 01131 if (!CanForceForeground(PpiCurrent())) { 01132 dwError = ERROR_ACCESS_DENIED; 01133 goto UnlockAndFail; 01134 } 01135 /* 01136 * Let's make a thread (if any) of this process be the last input owner 01137 */ 01138 if (dwProcessId != ASFW_ANY) { 01139 TAGMSG2(DBGTAG_FOREGROUND, "xxxAllowSetForegroundWindow by %#p to %#p", PpiCurrent(), ppi); 01140 glinp.ptiLastWoken = ppi->ptiList; 01141 UnlockProcess(pep); 01142 } else { 01143 TAGMSG1(DBGTAG_FOREGROUND, "xxxAllowSetForegroundWindow by %#p to ANY", PpiCurrent()); 01144 glinp.ptiLastWoken = NULL; 01145 } 01146 return TRUE; 01147 01148 UnlockAndFail: 01149 if (dwProcessId != ASFW_ANY) { 01150 UnlockProcess(pep); 01151 } 01152 RIPERR0(dwError, RIP_VERBOSE, ""); 01153 return FALSE; 01154 } 01155 /***************************************************************************\ 01156 * LockSetForegroundWindow (5.0 API) 01157 * 01158 * This API allows application to prevent any call to SetForegroundWindow. 01159 * This is mainly intended for application implementing their own menus 01160 * so they can block SFW just like we do for our own menus. 01161 * Certain actions like hitting the ALT key or any foreground change (ie, by a click) 01162 * will automatically unlock SFW (so apps cannot hose SFW) 01163 * 01164 * History: 01165 * 07-04-98 GerardoB Created. 01166 \***************************************************************************/ 01167 BOOL _LockSetForegroundWindow( 01168 UINT uLockCode) 01169 { 01170 DWORD dwError; 01171 PPROCESSINFO ppiCurrent = PpiCurrent(); 01172 01173 switch (uLockCode) { 01174 case LSFW_LOCK: 01175 /* 01176 * If the caller cannot lock it or already locked, fail the call 01177 */ 01178 if (CanForceForeground(ppiCurrent) && (gppiLockSFW == NULL)) { 01179 gppiLockSFW = ppiCurrent; 01180 TAGMSG1(DBGTAG_FOREGROUND, "_LockSetForegroundWindow locked by %#p", ppiCurrent); 01181 } else { 01182 dwError = ERROR_ACCESS_DENIED; 01183 goto FailIt; 01184 } 01185 break; 01186 01187 case LSFW_UNLOCK: 01188 /* 01189 * If the caller didn't lock it, fail the call 01190 */ 01191 if (ppiCurrent == gppiLockSFW) { 01192 gppiLockSFW = NULL; 01193 TAGMSG0(DBGTAG_FOREGROUND, "_LockSetForegroundWindow UNLOCKED"); 01194 } else { 01195 dwError = ERROR_ACCESS_DENIED; 01196 goto FailIt; 01197 } 01198 break; 01199 01200 default: 01201 dwError = ERROR_INVALID_PARAMETER; 01202 goto FailIt; 01203 } 01204 01205 return TRUE; 01206 01207 FailIt: 01208 RIPERR0(dwError, RIP_VERBOSE, ""); 01209 return FALSE; 01210 } 01211 /***************************************************************************\ 01212 * CleanupDecSFWLockCount 01213 * 01214 * Wrapper to be passed to PushW32ThreadLock, which wants an actual function. 01215 * History: 01216 * 10/19/98 GerardoB Created. 01217 \***************************************************************************/ 01218 void CleanupDecSFWLockCount(PVOID pIgnore) 01219 { 01220 DecSFWLockCount(); 01221 UNREFERENCED_PARAMETER(pIgnore); 01222 } 01223 01224 /***************************************************************************\ 01225 * xxxSetForegroundWindow (API) 01226 * 01227 * History: 01228 * 06-07-91 DavidPe Created. 01229 \***************************************************************************/ 01230 BOOL xxxStubSetForegroundWindow( 01231 PWND pwnd) 01232 { 01233 return xxxSetForegroundWindow(pwnd, TRUE); 01234 } 01235 BOOL xxxSetForegroundWindow( 01236 PWND pwnd, 01237 BOOL fFlash) 01238 { 01239 BOOL fNiceCall = TRUE; 01240 BOOL fSyncActivate, fActive; 01241 DWORD dwFlashFlags; 01242 PTHREADINFO ptiCurrent = PtiCurrent(); 01243 PWND pwndFlash; 01244 TL tlpwndFlash; 01245 01246 CheckLock(pwnd); 01247 01248 /* 01249 * If we're trying to set a window on our own thread to the foreground, 01250 * and we're already in the foreground, treat it just like a call to 01251 * SetActiveWindow(). 01252 */ 01253 if ((pwnd != NULL) && (GETPTI(pwnd)->pq == gpqForeground)) { 01254 fSyncActivate = (gpqForeground == ptiCurrent->pq); 01255 if (fSyncActivate) { 01256 gppiWantForegroundPriority = ptiCurrent->ppi; 01257 } else { 01258 gppiWantForegroundPriority = GETPTI(pwnd)->ppi; 01259 } 01260 01261 goto JustActivateIt; 01262 } 01263 /* 01264 * If the foregrond is not locked 01265 * and this thread has the right to changethe foreground, 01266 * then remove the activation right (it's a one-shot deal) 01267 * and do it. 01268 */ 01269 01270 /* 01271 * Bug 247768 - joejo 01272 * Add compatibility hack for foreground activation problems. 01273 * 01274 * To Fix Winstone99, ignore the foreground lock if the input 01275 * provider is making this call. GerardoB. 01276 * 01277 */ 01278 01279 if ((!IsForegroundLocked() || (ptiCurrent->ppi == gppiInputProvider)) 01280 && (ptiCurrent->TIF_flags & (TIF_ALLOWFOREGROUNDACTIVATE | TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD) 01281 || CanForceForeground(ptiCurrent->ppi) 01282 || GiveUpForeground())) { 01283 01284 TAGMSG1(DBGTAG_FOREGROUND, "xxxSetForegroundWindow FRemoveForegroundActivate %#p", ptiCurrent); 01285 01286 FRemoveForegroundActivate(ptiCurrent); 01287 return xxxSetForegroundWindow2(pwnd, ptiCurrent, 0); 01288 } 01289 fNiceCall = FALSE; 01290 TAGMSG3(DBGTAG_FOREGROUND, "xxxSetForegroundWindow: rude call by %#p to %#p-%#p", 01291 ptiCurrent, pwnd, (pwnd != NULL ? GETPTI(pwnd) : NULL)); 01292 if (pwnd == NULL) { 01293 return FALSE; 01294 } 01295 /* 01296 * Notify the user that this pwnd wants to come to the foreground. 01297 * Try to flash a tray button only; otherwise, flash pwnd 01298 */ 01299 if (fFlash) { 01300 pwndFlash = DSW_GetTopLevelCreatorWindow(GetTopLevelWindow(pwnd)); 01301 if (IsTrayWindow(pwndFlash)) { 01302 dwFlashFlags = FLASHW_TRAY; 01303 } else { 01304 pwndFlash = pwnd; 01305 dwFlashFlags = FLASHW_ALL; 01306 } 01307 ThreadLockAlways(pwndFlash, &tlpwndFlash); 01308 xxxFlashWindow(pwndFlash, 01309 MAKELONG(dwFlashFlags | FLASHW_TIMERNOFG, UP(FOREGROUNDFLASHCOUNT)), 01310 0); 01311 ThreadUnlock(&tlpwndFlash); 01312 } 01313 /* 01314 * Activate the window. 01315 */ 01316 fSyncActivate = (ptiCurrent->pq == GETPTI(pwnd)->pq); 01317 01318 JustActivateIt: 01319 01320 if (fSyncActivate) { 01321 fActive = xxxActivateWindow(pwnd, AW_USE); 01322 } else if (pwnd == GETPTI(pwnd)->pq->spwndActive) { 01323 fActive = TRUE; 01324 } else { 01325 fActive = PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq, 01326 QEVENT_ACTIVATE, NULL, 0, 01327 0, (LPARAM)HWq(pwnd)) ; 01328 } 01329 01330 /* 01331 * Return FALSE if we failed the set foreground request. 01332 */ 01333 return fNiceCall && fActive; 01334 } 01335 /***************************************************************************\ 01336 * xxxSetForegroundWindow2 01337 * 01338 * History: 01339 * 07-19-91 DavidPe Created. 01340 \***************************************************************************/ 01341 01342 BOOL xxxSetForegroundWindow2( 01343 PWND pwnd, 01344 PTHREADINFO pti, 01345 DWORD fFlags) 01346 { 01347 PTHREADINFO ptiForegroundOld; 01348 PTHREADINFO ptiForegroundNew; 01349 PQ pqForegroundOld, pqForegroundNew, pqCurrent; 01350 HWND hwnd; 01351 PQMSG pqmsgDeactivate, pqmsgActivate; 01352 BOOL bRemovedEvent; 01353 PTHREADINFO ptiCurrent = PtiCurrent(); 01354 BOOL retval = TRUE; 01355 UINT uMsg; 01356 CheckLock(pwnd); 01357 01358 /* 01359 * Queue pointers and threadinfo pointers can go away when calling xxx 01360 * calls. Also, queues can get recalced via AttachThreadInput() during 01361 * xxx calls - so we want to reference the application becoming foreground. 01362 * PQs cannot be refcount locked (either thread locked or structure locked) 01363 * so must (re)calculate them after returning from xxx calls. 01364 * 01365 * NOTE: gpqForeground and gpqForegroundPrev are always current and don't 01366 * need special handling. 01367 */ 01368 01369 /* 01370 * Don't allow the foreground to be set to a window that is not 01371 * on the current desktop. 01372 */ 01373 if (pwnd != NULL && (pwnd->head.rpdesk != grpdeskRitInput || 01374 HMIsMarkDestroy(pwnd))) { 01375 return FALSE; 01376 } 01377 01378 /* 01379 * Unlock SetForegroundWindow (if someone had it locked) 01380 */ 01381 gppiLockSFW = NULL; 01382 TAGMSG3(DBGTAG_FOREGROUND, "xxxSetForegroundWindow2 by %#p to %#p-%#p", 01383 ptiCurrent, pwnd, (pwnd != NULL ? GETPTI(pwnd) : NULL)); 01384 01385 /* 01386 * Calculate who is becoming foreground. Also, remember who we want 01387 * foreground (for priority setting reasons). 01388 */ 01389 if ((gptiForeground != NULL) && !(gptiForeground->TIF_flags & TIF_INCLEANUP)) { 01390 ptiForegroundOld = gptiForeground; 01391 } else { 01392 ptiForegroundOld = NULL; 01393 } 01394 pqForegroundOld = NULL; 01395 pqForegroundNew = NULL; 01396 pqCurrent = NULL; 01397 01398 gpqForegroundPrev = gpqForeground; 01399 01400 if (pwnd != NULL) { 01401 ptiForegroundNew = GETPTI(pwnd); 01402 UserAssert(ptiForegroundNew->rpdesk == grpdeskRitInput); 01403 gppiWantForegroundPriority = GETPTI(pwnd)->ppi; 01404 gpqForeground = GETPTI(pwnd)->pq; 01405 UserAssert(gpqForeground->cThreads != 0); 01406 UserAssert(gpqForeground->ptiMouse->rpdesk == grpdeskRitInput); 01407 // Assert to catch AV in xxxNextWindow doing Alt-Esc: If we have a non-NULL 01408 // gpqForeground, its kbd input thread better have an rpdesk! -IanJa 01409 UserAssert(!gpqForeground || (gpqForeground->ptiKeyboard && gpqForeground->ptiKeyboard->rpdesk)); 01410 SetForegroundThread(GETPTI(pwnd)); 01411 } else { 01412 ptiForegroundNew = NULL; 01413 gppiWantForegroundPriority = NULL; 01414 gpqForeground = NULL; 01415 SetForegroundThread(NULL); 01416 } 01417 01418 /* 01419 * Are we switching the foreground queue? 01420 */ 01421 if (gpqForeground != gpqForegroundPrev) { 01422 TL tlptiForegroundOld; 01423 TL tlptiForegroundNew; 01424 TL tlpti; 01425 01426 ThreadLockPti(ptiCurrent, ptiForegroundOld, &tlptiForegroundOld); 01427 ThreadLockPti(ptiCurrent, ptiForegroundNew, &tlptiForegroundNew); 01428 ThreadLockPti(ptiCurrent, pti, &tlpti); 01429 01430 /* 01431 * If this call didn't come from the RIT, cancel tracking 01432 * and other global states. 01433 */ 01434 if (pti != NULL) { 01435 01436 /* 01437 * Clear any visible tracking going on in system. 01438 */ 01439 xxxCancelTracking(); 01440 01441 /* 01442 * Remove the clip cursor rectangle - it is a global mode that 01443 * gets removed when switching. Also remove any LockWindowUpdate() 01444 * that's still around. 01445 */ 01446 zzzClipCursor(NULL); 01447 LockWindowUpdate2(NULL, TRUE); 01448 01449 /* 01450 * Make sure the desktop of the newly activated window is the 01451 * foreground fullscreen window 01452 */ 01453 xxxMakeWindowForegroundWithState(NULL, 0); 01454 } 01455 01456 /* 01457 * We've potentially done callbacks. Calculate pqForegroundOld 01458 * based on our locked local variable ptiForegroundOld. 01459 */ 01460 pqForegroundOld = NULL; 01461 if (ptiForegroundOld && !(ptiForegroundOld->TIF_flags & TIF_INCLEANUP)) { 01462 pqForegroundOld = ptiForegroundOld->pq; 01463 } 01464 01465 pqCurrent = NULL; 01466 if (pti != NULL) 01467 pqCurrent = pti->pq; 01468 01469 /* 01470 * Now allocate message for the deactivation 01471 */ 01472 pqmsgDeactivate = pqmsgActivate = NULL; 01473 01474 if ((pqForegroundOld != NULL) && (pqForegroundOld != pqCurrent)) { 01475 if ((pqmsgDeactivate = AllocQEntry(&pqForegroundOld->mlInput)) == 01476 NULL) { 01477 retval = FALSE; 01478 goto Exit; 01479 } 01480 } 01481 01482 /* 01483 * Do any appropriate deactivation. 01484 */ 01485 if (pqForegroundOld != NULL) { 01486 01487 /* 01488 * If we're already on the foreground queue we'll call 01489 * xxxDeactivate() directly later in this routine since 01490 * it'll cause us to leave the critical section. 01491 */ 01492 if (pqForegroundOld != pqCurrent) { 01493 StoreQMessage(pqmsgDeactivate, NULL, 0, 01494 gptiForeground != NULL ? (WPARAM)gptiForeground->pEThread->Cid.UniqueThread : 0, 01495 0, 0, QEVENT_DEACTIVATE, 0); 01496 01497 /* 01498 * If there was an old foreground thread, make it perform 01499 * the deactivation. Otherwise, any thread on the queue 01500 * can perform the deactivation. 01501 */ 01502 if (ptiForegroundOld != NULL) { 01503 SetWakeBit(ptiForegroundOld, QS_EVENTSET); 01504 01505 StoreQMessagePti(pqmsgDeactivate, ptiForegroundOld); 01506 01507 } 01508 01509 if (pqForegroundOld->spwndActive != NULL) { 01510 if (ptiForegroundOld != NULL && FHungApp(ptiForegroundOld, CMSHUNGAPPTIMEOUT)) { 01511 TL tlpwnd; 01512 ThreadLockAlwaysWithPti(ptiCurrent, pqForegroundOld->spwndActive, &tlpwnd); 01513 xxxRedrawHungWindowFrame(pqForegroundOld->spwndActive, FALSE); 01514 ThreadUnlock(&tlpwnd); 01515 } else { 01516 SetHungFlag(pqForegroundOld->spwndActive, WFREDRAWFRAMEIFHUNG); 01517 } 01518 } 01519 } 01520 } 01521 01522 /* 01523 * We've potentially done callbacks. Calculate pqForegroundNew 01524 * based on our locked local variable ptiForegroundNew. 01525 */ 01526 pqForegroundNew = NULL; 01527 if (ptiForegroundNew && !(ptiForegroundNew->TIF_flags & TIF_INCLEANUP)) { 01528 pqForegroundNew = ptiForegroundNew->pq; 01529 } 01530 01531 /* 01532 * Update pqCurrent since we may have made an xxx call, 01533 * and this variable may be invalid. 01534 */ 01535 pqCurrent = NULL; 01536 if (pti != NULL) { 01537 pqCurrent = pti->pq; 01538 } 01539 01540 if ((pqForegroundNew != NULL) && (pqForegroundNew != pqCurrent)) { 01541 pqmsgActivate = AllocQEntry(&pqForegroundNew->mlInput); 01542 if (pqmsgActivate == NULL) { 01543 retval = FALSE; 01544 goto Exit; 01545 } 01546 } 01547 01548 /* 01549 * Do any appropriate activation. 01550 */ 01551 if (pqForegroundNew != NULL) { 01552 /* 01553 * We're going to activate (synchronously or async with an activate 01554 * event). We want to remove the last deactivate event if there is 01555 * one because this is new state. If we don't, then 1> we could 01556 * synchronously activate and then asynchronously deactivate, 01557 * thereby processing these events out of order, or 2> we could 01558 * pile up a chain of deactivate / activate events which would 01559 * make the titlebar flash alot if the app wasn't responding to 01560 * input for awhile (in this case, it doesn't matter if we 01561 * put a redundant activate in the queue, since the app is already 01562 * active. Remove all deactivate events because this app is 01563 * setting a state that is not meant to be synchronized with 01564 * existing queued input. 01565 * 01566 * Case: run setup, switch away (it gets deactivate event). setup 01567 * is not reading messages so it hasn't go it yet. It finally 01568 * comes up, calls SetForegroundWindow(). It's synchronous, 01569 * it activates ok and sets foreground. Then the app calls 01570 * GetMessage() and gets the deactivate. Now it isn't active. 01571 */ 01572 bRemovedEvent = RemoveEventMessage(pqForegroundNew, QEVENT_DEACTIVATE, (DWORD)-1); 01573 01574 /* 01575 * Now do any appropriate activation. See comment below 01576 * for special cases. If we're already on the foreground 01577 * queue we'll call xxxActivateThisWindow() directly. 01578 */ 01579 if (pqForegroundNew != pqCurrent) { 01580 01581 /* 01582 * We do the 'pqCurrent == NULL' test to see if we're being 01583 * called from the RIT. In this case we pass NULL for the 01584 * HWND which will check to see if there is already an active 01585 * window for the thread and redraw its frame as truly active 01586 * since it's in the foreground now. It will also cancel any 01587 * global state like LockWindowUpdate() and ClipRect(). 01588 */ 01589 if ((pqCurrent == NULL) && (!(fFlags & SFW_SWITCH))) { 01590 hwnd = NULL; 01591 } else { 01592 hwnd = HW(pwnd); 01593 } 01594 01595 if (bRemovedEvent) { 01596 pqForegroundNew->QF_flags |= QF_EVENTDEACTIVATEREMOVED; 01597 } 01598 /* 01599 * MSMail relies on a specific order to how win3.1 does 01600 * fast switch alt-tab activation. On win3.1, it essentially 01601 * activates the window, then restores it. MsMail gets confused 01602 * if it isn't active when it gets restored, so this logic 01603 * will make sure msmail gets restore after it gets activated. 01604 * 01605 * Click on a message line in the in-box, minimize msmail, 01606 * alt-tab to it. The same line should have the focus if msmail 01607 * got restored after it got activated. 01608 * 01609 * This is the history behind SFW_ACTIVATERESTORE. 01610 */ 01611 if (fFlags & SFW_ACTIVATERESTORE) { 01612 uMsg = PEM_ACTIVATE_RESTORE; 01613 } else { 01614 uMsg = 0; 01615 } 01616 01617 if (fFlags & SFW_NOZORDER) { 01618 uMsg |= PEM_ACTIVATE_NOZORDER; 01619 } 01620 01621 StoreQMessage(pqmsgActivate, NULL, uMsg, 01622 (fFlags & SFW_STARTUP) ? 0 : (WPARAM)TID(ptiForegroundOld), 01623 (LPARAM)hwnd, 0, QEVENT_ACTIVATE, 0); 01624 01625 01626 /* 01627 * Signal the window's thread to perform activation. We 01628 * know that ptiForegroundNew is valid because pqForegroundNew 01629 * is not NULL. 01630 */ 01631 01632 StoreQMessagePti(pqmsgActivate, ptiForegroundNew); 01633 01634 SetWakeBit(ptiForegroundNew, QS_EVENTSET); 01635 01636 if (pqForegroundNew->spwndActive != NULL) { 01637 if (FHungApp(ptiForegroundNew, CMSHUNGAPPTIMEOUT)) { 01638 TL tlpwnd; 01639 ThreadLockAlwaysWithPti(ptiCurrent, pqForegroundNew->spwndActive, &tlpwnd); 01640 xxxRedrawHungWindowFrame(pqForegroundNew->spwndActive, TRUE); 01641 ThreadUnlock(&tlpwnd); 01642 } else { 01643 SetHungFlag(pqForegroundNew->spwndActive, WFREDRAWFRAMEIFHUNG); 01644 } 01645 } 01646 01647 } else { 01648 if (pwnd != pqCurrent->spwndActive) { 01649 if (!(fFlags & SFW_STARTUP)) { 01650 retval = xxxActivateThisWindow(pwnd, TID(ptiForegroundOld), 01651 ((fFlags & SFW_SETFOCUS) ? 0 : ATW_SETFOCUS)); 01652 01653 /* 01654 * Make sure the mouse is on this window. 01655 */ 01656 if (retval && TestUP(ACTIVEWINDOWTRACKING)) { 01657 zzzActiveCursorTracking(pwnd); 01658 } 01659 goto Exit; 01660 } 01661 01662 } else { 01663 01664 /* 01665 * If pwnd is already the active window, just make sure 01666 * it's drawn active and on top (if requested). 01667 */ 01668 xxxSendMessage(pwnd, WM_NCACTIVATE, 01669 TRUE, 01670 (LPARAM)HW(pwnd)); 01671 xxxUpdateTray(pwnd); 01672 if (!(fFlags & SFW_NOZORDER)) { 01673 xxxSetWindowPos(pwnd, PWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); 01674 } 01675 } 01676 } 01677 01678 01679 } /* if (pqForegroundNew != NULL) */ 01680 01681 /* 01682 * First update pqForegroundOld and pqCurrent since we may have 01683 * made an xxx call, and these variables may be invalid. 01684 */ 01685 pqForegroundOld = NULL; 01686 if (ptiForegroundOld && !(ptiForegroundOld->TIF_flags & TIF_INCLEANUP)) { 01687 pqForegroundOld = ptiForegroundOld->pq; 01688 } 01689 01690 pqCurrent = NULL; 01691 if (pti != NULL) 01692 pqCurrent = pti->pq; 01693 01694 /* 01695 * Now check to see if we needed to do any 'local' deactivation. 01696 * (ie. were we on the queue that is being deactivated by this 01697 * SetForegroundWindow() call?) 01698 */ 01699 if ((pqForegroundOld != NULL) && (pqForegroundOld == pqCurrent)) { 01700 xxxDeactivate(pti, (pwnd != NULL) ? TIDq(GETPTI(pwnd)) : 0); 01701 } 01702 Exit: 01703 ThreadUnlockPti(ptiCurrent, &tlpti); 01704 ThreadUnlockPti(ptiCurrent, &tlptiForegroundNew); 01705 ThreadUnlockPti(ptiCurrent, &tlptiForegroundOld); 01706 } 01707 01708 return retval; 01709 } 01710 /***************************************************************************\ 01711 * FRemoveForegroundActivate 01712 * 01713 * Returns TRUE if the foreground activate right was removed. 01714 * 01715 * 05-12-97 GerardoB Extracted from FAllowForegroundActivate. 01716 \***************************************************************************/ 01717 BOOL FRemoveForegroundActivate(PTHREADINFO pti) 01718 { 01719 BOOL fRemoved; 01720 PPROCESSINFO ppi; 01721 /* 01722 * W32PF_APPSTARTING gets turned off the first activate this process does. 01723 * We assume it's ready now for action. 01724 */ 01725 ppi = pti->ppi; 01726 if (ppi->W32PF_Flags & W32PF_APPSTARTING) { 01727 ClearAppStarting(ppi); 01728 } 01729 01730 /* 01731 * Remove the right if present. 01732 */ 01733 fRemoved = (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE); 01734 if (fRemoved) { 01735 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE ; 01736 TAGMSG1(DBGTAG_FOREGROUND, "FRemoveForegroundActivate clear TIF %#p", pti); 01737 } else { 01738 fRemoved = (ppi->W32PF_Flags & W32PF_ALLOWFOREGROUNDACTIVATE); 01739 } 01740 if (fRemoved) { 01741 ppi->W32PF_Flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE; 01742 TAGMSG1(DBGTAG_FOREGROUND, "FRemoveForegroundActivate clear W32PF %#p", ppi); 01743 } 01744 01745 return fRemoved; 01746 01747 } 01748 /***************************************************************************\ 01749 * FAllowForegroundActivate 01750 * 01751 * Checks to see if we previously have allowed this process or thread to 01752 * do a foreground activate - meaning, next time it becomes active, whether 01753 * we'll allow it to come to the foreground. Sometimes processes are granted 01754 * the right to foreground activate themselves, if they aren't foreground, 01755 * like when starting up (there are other cases). Grant this if this process 01756 * is allowed. 01757 * 01758 * 09-08-92 ScottLu Created. 01759 \***************************************************************************/ 01760 01761 BOOL FAllowForegroundActivate( 01762 PQ pq, 01763 PWND pwnd) 01764 { 01765 PTHREADINFO ptiCurrent = PtiCurrent(); 01766 UserAssert(pwnd != NULL); 01767 /* 01768 * Bail if this guy doesn't have the foreground activate right. 01769 */ 01770 TAGMSG1(DBGTAG_FOREGROUND, "FAllowForegroundActivate FRemoveForegroundActivate %#p", ptiCurrent); 01771 if (!FRemoveForegroundActivate(ptiCurrent)) { 01772 return FALSE; 01773 } 01774 /* 01775 * Don't try to foreground activate if: 01776 * we're not on the right desktop. 01777 * we're already in the foreground 01778 * the foreground is locked 01779 * It'll fail in SetForegroundWindow2() anyway. This way 01780 * ActivateWindow() will still locally activate the window. 01781 */ 01782 if ((ptiCurrent->rpdesk != grpdeskRitInput) 01783 || (gpqForeground == pq) 01784 || IsForegroundLocked()) { 01785 TAGMSG0(DBGTAG_FOREGROUND, "FAllowForegroundActivate FALSE due to addtional checks"); 01786 return FALSE; 01787 } 01788 /* 01789 * noactivate windows cannot take the foreground unless explicitly requested. 01790 * Note that windows passed to this function are expected to be toplevel, which is 01791 * where this style has meaning. This might not be the case if AW_SKIP picked an 01792 * owner window which is not top level. Since noactivate doesn't apply to the owner 01793 * chain, it's OK to ignore this. 01794 */ 01795 #if DBG 01796 if (TestwndChild(pwnd)) { 01797 RIPMSG1(RIP_WARNING, "FAllowForegroundActivate pwnd %#p is not top level", pwnd); 01798 } 01799 #endif 01800 if (TestWF(pwnd, WEFNOACTIVATE)) { 01801 TAGMSG1(DBGTAG_FOREGROUND, "FAllowForegroundActivate noactivate window:%#p", pwnd); 01802 return FALSE; 01803 } 01804 01805 return TRUE; 01806 } 01807 01808 /***************************************************************************\ 01809 * xxxSetFocus (API) 01810 * 01811 * History: 01812 * 11-08-90 DavidPe Ported. 01813 \***************************************************************************/ 01814 01815 PWND xxxSetFocus( 01816 PWND pwnd) 01817 { 01818 HWND hwndTemp; 01819 PTHREADINFO ptiCurrent = PtiCurrent(); 01820 PTHREADINFO ptiActiveKL; 01821 PWND pwndTemp = NULL; 01822 TL tlpwndTemp; 01823 01824 CheckLock(pwnd); 01825 /* 01826 * Special case if we are setting the focus to a null window. 01827 */ 01828 if (pwnd == NULL) { 01829 if (IsHooked(ptiCurrent, WHF_CBT) && xxxCallHook(HCBT_SETFOCUS, 0, 01830 (LPARAM)HW(ptiCurrent->pq->spwndFocus), WH_CBT)) { 01831 return NULL; 01832 } 01833 01834 /* 01835 * Save old focus so that we can return it. 01836 */ 01837 hwndTemp = HW(ptiCurrent->pq->spwndFocus); 01838 xxxSendFocusMessages(ptiCurrent, pwnd); 01839 return RevalidateHwnd(hwndTemp); 01840 } 01841 01842 /* 01843 * We no longer allow inter-thread set focuses. 01844 */ 01845 if (GETPTI(pwnd)->pq != ptiCurrent->pq) { 01846 return NULL; 01847 } 01848 01849 /* 01850 * If the window recieving the focus or any of its ancestors is either 01851 * minimized or disabled, don't set the focus. 01852 */ 01853 for (pwndTemp = pwnd; pwndTemp != NULL; pwndTemp = pwndTemp->spwndParent) { 01854 if (TestWF(pwndTemp, WFMINIMIZED) || TestWF(pwndTemp, WFDISABLED)) { 01855 01856 /* 01857 * Don't change the focus if going to a minimized or disabled 01858 * window. 01859 */ 01860 return NULL; 01861 } 01862 01863 if (!TestwndChild(pwndTemp)) { 01864 break; 01865 } 01866 } 01867 UserAssert(pwndTemp != NULL); 01868 01869 /* 01870 * pwndTemp should now be the top level ancestor of pwnd. 01871 */ 01872 ThreadLockWithPti(ptiCurrent, pwndTemp, &tlpwndTemp); 01873 if (pwnd != ptiCurrent->pq->spwndFocus) { 01874 if (IsHooked(ptiCurrent, WHF_CBT) && xxxCallHook(HCBT_SETFOCUS, (WPARAM)HWq(pwnd), 01875 (LPARAM)HW(ptiCurrent->pq->spwndFocus), WH_CBT)) { 01876 ThreadUnlock(&tlpwndTemp); 01877 return NULL; 01878 } 01879 01880 /* 01881 * Activation must follow the focus. That is, setting the focus to 01882 * a particualr window means that the top-level parent of this window 01883 * must be the active window (top-level parent is determined by 01884 * following the parent chain until you hit a top-level guy). So, 01885 * we must activate this top-level parent if it is different than 01886 * the current active window. 01887 * 01888 * Only change activation if top-level parent is not the currently 01889 * active window. 01890 */ 01891 if (pwndTemp != ptiCurrent->pq->spwndActive) { 01892 01893 /* 01894 * If this app is not in the foreground, see if foreground 01895 * activation is allowed. 01896 */ 01897 if (ptiCurrent->pq != gpqForeground && FAllowForegroundActivate(ptiCurrent->pq, pwndTemp)) { 01898 /* 01899 * If the process lost the foreground activation right by giving 01900 * focus to a hidden window, then give it the right back. See 01901 * bug #401932 for how this might affect an app 01902 */ 01903 if (!TestWF(pwndTemp, WFVISIBLE)){ 01904 ptiCurrent->ppi->W32PF_Flags |= W32PF_ALLOWFOREGROUNDACTIVATE; 01905 } 01906 if (!xxxSetForegroundWindow2(pwndTemp, ptiCurrent, SFW_SETFOCUS)) { 01907 ThreadUnlock(&tlpwndTemp); 01908 return NULL; 01909 } 01910 } 01911 01912 /* 01913 * This will return FALSE if something goes wrong. 01914 */ 01915 if (pwndTemp != ptiCurrent->pq->spwndActive) { 01916 if (!xxxActivateThisWindow(pwndTemp, 0, 0)) { 01917 ThreadUnlock(&tlpwndTemp); 01918 return NULL; 01919 } 01920 } 01921 } 01922 01923 /* 01924 * Save current pwndFocus since we must return this. 01925 */ 01926 pwndTemp = ptiCurrent->pq->spwndFocus; 01927 ThreadUnlock(&tlpwndTemp); 01928 ThreadLockWithPti(ptiCurrent, pwndTemp, &tlpwndTemp); 01929 01930 /* 01931 * Change the global pwndFocus and send the WM_{SET/KILL}FOCUS 01932 * messages. 01933 */ 01934 xxxSendFocusMessages(ptiCurrent, pwnd); 01935 01936 } else { 01937 pwndTemp = ptiCurrent->pq->spwndFocus; 01938 } 01939 01940 if (ptiCurrent->pq->spwndFocus) { 01941 /* 01942 * For the shell notification hook, we should use the pti->spkl 01943 * of the window with the focus. This could be a different thread, 01944 * (or even different process) when the queue is attached. The typical 01945 * case would be OLE out-of-process server. 01946 * #352877 01947 */ 01948 ptiActiveKL = GETPTI(ptiCurrent->pq->spwndFocus); 01949 } else { 01950 /* 01951 * Preserving the NT4 behavior, otherwise. 01952 */ 01953 ptiActiveKL = ptiCurrent; 01954 } 01955 UserAssert(ptiActiveKL); 01956 01957 /* 01958 * Update the keyboard icon on the tray if the layout changed during focus change. 01959 * Before winlogon loads kbd layouts, pti->spkActive is NULL. #99321 01960 */ 01961 if (ptiActiveKL->spklActive) { 01962 HKL hklActive = ptiActiveKL->spklActive->hkl; 01963 01964 if ((gLCIDSentToShell != hklActive) && IsHooked(ptiCurrent, WHF_SHELL)) { 01965 gLCIDSentToShell = hklActive; 01966 xxxCallHook(HSHELL_LANGUAGE, (WPARAM)NULL, (LPARAM)hklActive, WH_SHELL); 01967 } 01968 } 01969 01970 hwndTemp = HW(pwndTemp); 01971 ThreadUnlock(&tlpwndTemp); 01972 01973 /* 01974 * Return the pwnd of the window that lost the focus. 01975 * Return the validated hwndTemp: since we locked/unlocked pwndTemp, 01976 * it may be gone. 01977 */ 01978 return RevalidateHwnd(hwndTemp); 01979 } 01980 01981 01982 /***************************************************************************\ 01983 * xxxSetActiveWindow (API) 01984 * 01985 * 01986 * History: 01987 * 11-08-90 DavidPe Created. 01988 \***************************************************************************/ 01989 01990 PWND xxxSetActiveWindow( 01991 PWND pwnd) 01992 { 01993 HWND hwndActiveOld; 01994 PTHREADINFO pti; 01995 01996 CheckLock(pwnd); 01997 01998 pti = PtiCurrent(); 01999 02000 /* 02001 * 32 bit apps must call SetForegroundWindow (to be NT 3.1 compatible) 02002 * but 16 bit apps that are foreground can make other apps foreground. 02003 * xxxActivateWindow makes sure an app is foreground. 02004 */ 02005 if (!(pti->TIF_flags & TIF_16BIT) && (pwnd != NULL) && (GETPTI(pwnd)->pq != pti->pq)) { 02006 return NULL; 02007 } 02008 02009 hwndActiveOld = HW(pti->pq->spwndActive); 02010 02011 xxxActivateWindow(pwnd, AW_USE); 02012 02013 return RevalidateHwnd(hwndActiveOld); 02014 } 02015 02016 02017 /***************************************************************************\ 02018 * xxxActivateWindow 02019 * 02020 * Changes the active window. Given the pwnd and cmd parameters, changes the 02021 * activation according to the following rules: 02022 * 02023 * If cmd == 02024 * AW_USE Use the pwnd passed as the new active window. If this 02025 * window cannot be activated, return FALSE. 02026 * 02027 * AW_TRY Try to use the pwnd passed as the new active window. If 02028 * this window cannot be activated activate another window 02029 * using the rules for AW_SKIP. 02030 * 02031 * AW_SKIP Activate any other window than pwnd passed. The order of 02032 * searching for a candidate is as follows: 02033 * - If pwnd is a popup, try its owner 02034 * - else scan the top-level window list for the first 02035 * window that is not pwnd that can be activated. 02036 * 02037 * AW_USE2 Same as AW_USE except that the wParam on the WM_ACTIVATE 02038 * message will be set to 2 rather than the default of 1. This 02039 * indicates the activation is being changed due to a mouse 02040 * click. 02041 * 02042 * AW_TRY2 Same as AW_TRY except that the wParam on the WM_ACTIVATE 02043 * message will be set to 2 rather than the default of 1. This 02044 * indicates the activation is being changed due to a mouse 02045 * click. 02046 * 02047 * AW_SKIP2 Same as AW_SKIP, but we skip the first check that AW_SKIP 02048 * performes (the pwndOwner test). This is used when 02049 * the pwnd parameter is NULL when this function is called. 02050 * 02051 * This function returns TRUE if the activation changed and FALSE if 02052 * it did not change. 02053 * 02054 * This function calls xxxActivateThisWindow() to actually do the activation. 02055 * 02056 * History: 02057 * 11-08-90 DavidPe Ported. 02058 \***************************************************************************/ 02059 02060 BOOL xxxActivateWindow( 02061 PWND pwnd, 02062 UINT cmd) 02063 { 02064 DWORD fFlags = ATW_SETFOCUS; 02065 PTHREADINFO ptiCurrent = PtiCurrent(); 02066 TL tlpwnd; 02067 BOOL fSuccess; 02068 BOOL fAllowForeground, fSetForegroundRight; 02069 02070 CheckLock(pwnd); 02071 02072 02073 if (pwnd != NULL) { 02074 02075 /* 02076 * See if this window is OK to activate 02077 * (Cannot activate child windows). 02078 */ 02079 if (TestwndChild(pwnd)) 02080 return FALSE; 02081 02082 } else { 02083 cmd = AW_SKIP2; 02084 } 02085 02086 switch (cmd) { 02087 02088 case AW_TRY2: 02089 fFlags |= ATW_MOUSE; 02090 02091 /* 02092 *** FALL THRU ** 02093 */ 02094 case AW_TRY: 02095 02096 /* 02097 * See if this window is OK to activate. 02098 */ 02099 if (!FBadWindow(pwnd)) { 02100 break; 02101 } 02102 02103 /* 02104 * If pwnd can not be activated, drop into the AW_SKIP case. 02105 */ 02106 case AW_SKIP: 02107 02108 /* 02109 * Try the owner of this popup. 02110 */ 02111 if (TestwndPopup(pwnd) && !FBadWindow(pwnd->spwndOwner)) { 02112 pwnd = pwnd->spwndOwner; 02113 break; 02114 } 02115 02116 /* 02117 * fall through 02118 */ 02119 02120 case AW_SKIP2: 02121 02122 /* 02123 * Try the previously active window but don't activate a shell window 02124 */ 02125 if ((gpqForegroundPrev != NULL) 02126 && !FBadWindow(gpqForegroundPrev->spwndActivePrev) 02127 /* 02128 * Bug 290129 - joejo 02129 * 02130 * Test for WFBOTTOMMOST as opposed to WEFTOOLWINDOW to fix 02131 * issue with Office2000 assistant and balloon help. 02132 */ 02133 && !TestWF(gpqForegroundPrev->spwndActivePrev, WFBOTTOMMOST)) { 02134 02135 pwnd = gpqForegroundPrev->spwndActivePrev; 02136 break; 02137 } 02138 02139 { 02140 PWND pwndSave = pwnd; 02141 DWORD flags = NTW_IGNORETOOLWINDOW; 02142 02143 TryAgain: 02144 /* 02145 * Find a new active window from the top-level window list, 02146 * skip tool windows the first time through. 02147 */ 02148 pwnd = NextTopWindow(ptiCurrent, pwndSave, (cmd == AW_SKIP ? pwndSave : NULL), 02149 flags); 02150 02151 if (pwnd) { 02152 if (!FBadWindow(pwnd->spwndLastActive)) 02153 pwnd = pwnd->spwndLastActive; 02154 } else { 02155 if (flags == NTW_IGNORETOOLWINDOW) { 02156 flags = 0; 02157 goto TryAgain; 02158 } 02159 } 02160 } 02161 02162 02163 case AW_USE: 02164 break; 02165 02166 case AW_USE2: 02167 fFlags |= ATW_MOUSE; 02168 break; 02169 02170 default: 02171 return FALSE; 02172 } 02173 02174 if (pwnd == NULL) 02175 return FALSE; 02176 02177 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 02178 02179 if (GETPTI(pwnd)->pq == ptiCurrent->pq) { 02180 /* 02181 * Activation is within this queue. Usually this means just do 02182 * all the normal message sending. But if this queue isn't the 02183 * foreground queue, check to see if it is allowed to become 02184 * foreground. 02185 */ 02186 02187 /* 02188 * Sometimes processes are granted the right to foreground 02189 * activate themselves, if they aren't foreground, like 02190 * when starting up (there are other cases). Grant this if 02191 * this process is allowed. 02192 */ 02193 02194 /* 02195 * Removed the first clause from the following if statement 02196 * if (pti->pq == gpqForeground || !FAllowForegroundActivate(pti->pq)) { 02197 * This fixes the problem where foreground app A activates app B 02198 * the user switches to app C, then B does something to activate A 02199 * (like destroy an owned window). A now comes to the foreground 02200 * unexpectedly. This clause is not in Win95 code and was added in 02201 * 3.51 code to fix some test script hang (Bug 7461) 02202 */ 02203 02204 if (!FAllowForegroundActivate(ptiCurrent->pq, pwnd)) { 02205 fSuccess = xxxActivateThisWindow(pwnd, 0, fFlags); 02206 ThreadUnlock(&tlpwnd); 02207 return fSuccess; 02208 } 02209 02210 fAllowForeground = TRUE; 02211 /* 02212 * If this thread doesn't have any top-level non-minimized visible windows, 02213 * let it keep the right since it's probably not done with activation yet. 02214 * Bug 274383 - joejo 02215 */ 02216 fSetForegroundRight = (ptiCurrent->cVisWindows == 0); 02217 02218 } else { 02219 /* 02220 * If the caller is in the foreground, it has the right to change 02221 * the foreground itself. 02222 */ 02223 fAllowForeground = (gpqForeground == ptiCurrent->pq) 02224 || (gpqForeground == NULL); 02225 /* 02226 * Give the right to change the foreground to this thread only if it already 02227 * has it, it has more visible windows or this is an explicit request to 02228 * activate the given window. 02229 * When an app destroys/hides the active (foreground) window, we choose a new 02230 * active window and will probably hit this code. We don't want to give them the 02231 * right to change the foreground in this case since it's us making the activation 02232 * (See comments below). We let them keep the right so apps destroying their last 02233 * visible window (ie a splash initialization window) can take the foreground again 02234 * when they create another window (the main window). 02235 */ 02236 if (fAllowForeground) { 02237 fSetForegroundRight = ((ptiCurrent->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE) 02238 || (ptiCurrent->cVisWindows != 0) 02239 || (cmd == AW_USE)); 02240 } else { 02241 fSetForegroundRight = FALSE; 02242 } 02243 } 02244 02245 fSuccess = FALSE; 02246 if (fAllowForeground) { 02247 /* 02248 * Hack! Temporarily give this thread a foreground right to make sure 02249 * this call succeds. 02250 */ 02251 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 02252 TAGMSG1(DBGTAG_FOREGROUND, "xxxActivateWindow temporarly set TIF %#p", ptiCurrent); 02253 fSuccess = xxxSetForegroundWindow(pwnd, (cmd == AW_USE)); 02254 02255 if (fSetForegroundRight) { 02256 /* 02257 * We activated some other app on purpose. If so that means this 02258 * thread is probably controlling this window and will probably want 02259 * to set itself active and foreground really soon again (for example, 02260 * a setup program doing dde to progman). A real live case: wingz - 02261 * bring up page setup..., options..., ok, ok. Under Win3.1 the 02262 * activation goes somewhere strange and then wingz calls 02263 * SetActiveWindow() to bring it back. This'll make sure that works. 02264 * 02265 * We used to set this before calling xxxSetForegeroundWindow above. 02266 * This would cause callers doing an intra-queue activation to 02267 * retain their foreground right eventhough it is supposed to be 02268 * a one shot deal (that's why FAllowForeground clears the bits). 02269 * In addtion, xxxSetForegroundWindow might clear the bits (it didnt' 02270 * used to); so we do it here, and only if we did an inter-queue 02271 * activation 02272 */ 02273 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 02274 TAGMSG1(DBGTAG_FOREGROUND, "xxxActivateWindow set TIF %#p", ptiCurrent); 02275 } else { 02276 /* 02277 * Make sure to remove the temporary right. 02278 */ 02279 ptiCurrent->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; 02280 TAGMSG1(DBGTAG_FOREGROUND, "xxxActivateWindow clear TIF %#p", ptiCurrent); 02281 } 02282 } 02283 02284 ThreadUnlock(&tlpwnd); 02285 return fSuccess; 02286 } 02287 02288 02289 /***************************************************************************\ 02290 * GNT_NextTopScan 02291 * 02292 * Starting at hwnd (or hwndDesktop->hwndChild if hwnd == NULL), find 02293 * the next window owned by hwndOwner. 02294 * 02295 * History: 02296 * 11-08-90 DavidPe Ported. 02297 * 02-11-91 JimA Multi-desktop support. 02298 \***************************************************************************/ 02299 02300 PWND GNT_NextTopScan( 02301 PTHREADINFO pti, 02302 PWND pwnd, 02303 PWND pwndOwner) 02304 { 02305 if (pwnd == NULL) { 02306 UserAssert(pti->rpdesk != NULL && 02307 (pti->rpdesk->dwDTFlags & DF_DESKWNDDESTROYED) == 0); 02308 pwnd = pti->rpdesk->pDeskInfo->spwnd->spwndChild; 02309 } else { 02310 pwnd = pwnd->spwndNext; 02311 } 02312 02313 for (; pwnd != NULL; pwnd = pwnd->spwndNext) { 02314 if (pwnd->spwndOwner == pwndOwner) 02315 break; 02316 } 02317 02318 return pwnd; 02319 } 02320 02321 02322 /***************************************************************************\ 02323 * NTW_GetNextTop 02324 * 02325 * <brief description> 02326 * 02327 * History: 02328 * 11-08-90 DavidPe Ported. 02329 * 02-11-91 JimA Multi-desktop support. 02330 \***************************************************************************/ 02331 02332 PWND NTW_GetNextTop( 02333 PTHREADINFO pti, 02334 PWND pwnd) 02335 { 02336 PWND pwndOwner; 02337 02338 if (pwnd == NULL) { 02339 goto ReturnFirst; 02340 } 02341 02342 /* 02343 * First look for any windows owned by this window 02344 * If that fails, then go up one level to our owner, 02345 * and look for next window owned by his owner. 02346 * This results in a depth-first ordering of the windows. 02347 */ 02348 02349 pwndOwner = pwnd; 02350 pwnd = NULL; 02351 02352 do { 02353 if ((pwnd = GNT_NextTopScan(pti, pwnd, pwndOwner)) != NULL) { 02354 return pwnd; 02355 } 02356 02357 pwnd = pwndOwner; 02358 if (pwnd != NULL) 02359 pwndOwner = pwnd->spwndOwner; 02360 02361 } while (pwnd != NULL); 02362 02363 ReturnFirst: 02364 02365 /* 02366 * If no more windows to enumerate, return the first unowned window. 02367 */ 02368 return GNT_NextTopScan(pti, NULL, NULL); 02369 } 02370 02371 02372 /***************************************************************************\ 02373 * NTW_GetPrevTop 02374 * 02375 * <brief description> 02376 * 02377 * History: 02378 * 11-08-90 DavidPe Ported. 02379 * 02-11-91 JimA Multi-desktop support. 02380 \***************************************************************************/ 02381 02382 PWND NTW_GetPrevTop( 02383 PTHREADINFO pti, 02384 PWND pwndCurrent) 02385 { 02386 PWND pwnd; 02387 PWND pwndPrev; 02388 02389 /* 02390 * Starting from beginning, loop thru the windows, saving the previous 02391 * one, until we find the window we're currently at. 02392 */ 02393 pwndPrev = NULL; 02394 02395 do { 02396 pwnd = NTW_GetNextTop(pti, pwndPrev); 02397 if (pwnd == pwndCurrent && pwndPrev != NULL) { 02398 break; 02399 } 02400 } while ((pwndPrev = pwnd) != NULL); 02401 02402 return pwndPrev; 02403 } 02404 02405 02406 /***************************************************************************\ 02407 * NextTopWindow 02408 * 02409 * <brief description> 02410 * 02411 * History: 02412 * 11-08-90 DavidPe Ported. 02413 * 02-11-91 JimA Multi-desktop support. 02414 \***************************************************************************/ 02415 02416 PWND CheckTopLevelOnly( 02417 PWND pwnd) 02418 { 02419 /* 02420 * fnid == -1 means this is a desktop window - find the first child 02421 * of this desktop, if it is one. 02422 */ 02423 while (pwnd != NULL && GETFNID(pwnd) == FNID_DESKTOP) { 02424 pwnd = pwnd->spwndChild; 02425 } 02426 02427 return pwnd; 02428 } 02429 02430 02431 PWND NextTopWindow( 02432 PTHREADINFO pti, 02433 PWND pwnd, 02434 PWND pwndSkip, 02435 DWORD flags ) 02436 { 02437 BOOL fFoundFirstUnowned; 02438 PWND pwndPrev; 02439 PWND pwndStart = pwnd; 02440 PWND pwndFirstUnowned; 02441 02442 /* 02443 * If the search gets to the first unowned window TWICE (See NTW_GetNextTop), 02444 * we couldn't find a window 02445 */ 02446 pwndFirstUnowned = GNT_NextTopScan(pti, NULL, NULL); 02447 fFoundFirstUnowned = FALSE; 02448 02449 if (pwnd == NULL) { 02450 pwnd = NTW_GetNextTop(pti, NULL); 02451 02452 /* 02453 * Don't allow desktop windows. 02454 */ 02455 pwnd = pwndStart = CheckTopLevelOnly(pwnd); 02456 02457 if (pwnd == NULL) 02458 return NULL; // No more windows owned by the thread 02459 02460 goto Loop; 02461 } 02462 02463 /* 02464 * Don't allow desktop windows. 02465 */ 02466 pwnd = pwndStart = CheckTopLevelOnly(pwnd); 02467 if (pwnd == NULL) 02468 return NULL; // No more windows owned by this thread 02469 02470 /* 02471 * Don't allow desktop windows. 02472 */ 02473 pwndSkip = CheckTopLevelOnly(pwndSkip); 02474 02475 02476 02477 while (TRUE) { 02478 pwndPrev = pwnd; 02479 pwnd = ((flags & NTW_PREVIOUS) ? NTW_GetPrevTop(pti, pwnd) : NTW_GetNextTop(pti, pwnd)); 02480 02481 /* 02482 * If we've cycled to where we started, couldn't find one: return NULL 02483 */ 02484 if (pwnd == pwndStart) 02485 break; 02486 02487 if (pwnd == pwndFirstUnowned) { 02488 if (fFoundFirstUnowned) { 02489 break; 02490 } else { 02491 fFoundFirstUnowned = TRUE; 02492 } 02493 } 02494 02495 if (pwnd == NULL) 02496 break; 02497 02498 /* 02499 * If we've cycled over desktops, then return NULL because we'll 02500 * never hit pwndStart. 02501 */ 02502 if (PWNDDESKTOP(pwndStart) != PWNDDESKTOP(pwnd)) 02503 break; 02504 02505 /* 02506 * going nowhere is a bad sign. 02507 */ 02508 if (pwndPrev == pwnd) { 02509 /* 02510 * This is a temporary fix chosen because its safe. This case 02511 * was hit when a window failed the NCCREATE message and fell 02512 * into xxxFreeWindow and left the critical section after being 02513 * unlinked. The app then died and entered cleanup code and 02514 * tried to destroy this window again. 02515 */ 02516 break; 02517 } 02518 02519 Loop: 02520 if (pwnd == pwndSkip) 02521 continue; 02522 02523 /* 02524 * If it's visible, not disabled, not a noactivate window 02525 * and either we're not ignoringtool windows or it's not a 02526 * tool window, then we've got it. 02527 */ 02528 if (TestWF(pwnd, WFVISIBLE) && 02529 !TestWF(pwnd, WFDISABLED) && 02530 !TestWF(pwnd, WEFNOACTIVATE) && 02531 (!(flags & NTW_IGNORETOOLWINDOW) || !TestWF(pwnd, WEFTOOLWINDOW))) { 02532 02533 return pwnd; 02534 } 02535 } 02536 02537 return NULL; 02538 } 02539 02540 02541 /***************************************************************************\ 02542 * xxxCheckFocus 02543 * 02544 * 02545 * History: 02546 * 11-08-90 DarrinM Ported. 02547 \***************************************************************************/ 02548 02549 void xxxCheckFocus( 02550 PWND pwnd) 02551 { 02552 TL tlpwndParent; 02553 PTHREADINFO pti; 02554 02555 CheckLock(pwnd); 02556 02557 pti = PtiCurrent(); 02558 02559 if (pwnd == pti->pq->spwndFocus) { 02560 02561 /* 02562 * Set focus to parent of child window. 02563 */ 02564 if (TestwndChild(pwnd)) { 02565 ThreadLockWithPti(pti, pwnd->spwndParent, &tlpwndParent); 02566 xxxSetFocus(pwnd->spwndParent); 02567 ThreadUnlock(&tlpwndParent); 02568 } else { 02569 xxxSetFocus(NULL); 02570 } 02571 } 02572 02573 if (pwnd == pti->pq->caret.spwnd) { 02574 zzzDestroyCaret(); 02575 } 02576 } 02577 02578 02579 /***************************************************************************\ 02580 * SetForegroundThread 02581 * 02582 * 02583 * History: 02584 * 12-xx-91 MarkL Created. 02585 * 02-12-92 DavidPe Rewrote as SetForegroundThread(). 02586 \***************************************************************************/ 02587 02588 VOID SetForegroundThread( 02589 PTHREADINFO pti) 02590 { 02591 PKL pklPrev; 02592 02593 if (pti == gptiForeground) 02594 return; 02595 02596 /* 02597 * The foregorund thread must be on the foreground queue. 02598 * xxxSendFocusMessages obtains this pti from a window 02599 * received as a parameter. If the owner of the window 02600 * exited during a callback (in the caller), then the pti 02601 * will be gptiRit,which might not be in the foreground queue 02602 */ 02603 UserAssert((pti == NULL) 02604 || (pti->pq == gpqForeground) 02605 || (pti == gptiRit)); 02606 02607 /* 02608 * If we're changing gptiForeground to another process, 02609 * change the base priorities of the two processes. We 02610 * know that if either 'pti' or 'gptiForeground' is NULL 02611 * that both aren't NULL due to the first test in this 02612 * function. 02613 */ 02614 if ((pti == NULL) || (gptiForeground == NULL) || 02615 (pti->ppi != gptiForeground->ppi)) { 02616 if (gptiForeground != NULL) { 02617 gptiForeground->ppi->W32PF_Flags &= ~W32PF_FORCEBACKGROUNDPRIORITY; 02618 SetForegroundPriority(gptiForeground, FALSE); 02619 } 02620 02621 if (pti != NULL) { 02622 SetForegroundPriority(pti, TRUE); 02623 } 02624 } 02625 02626 if (gptiForeground) { 02627 pklPrev = gptiForeground->spklActive; 02628 } else { 02629 pklPrev = NULL; 02630 } 02631 gptiForeground = pti; 02632 if (gptiForeground && gptiForeground->spklActive) { 02633 ChangeForegroundKeyboardTable(pklPrev, gptiForeground->spklActive); 02634 } 02635 02636 /* 02637 * Clear recent down information in the async key state to prevent 02638 * spying by apps. 02639 */ 02640 RtlZeroMemory(gafAsyncKeyStateRecentDown, CBKEYSTATERECENTDOWN); 02641 02642 /* 02643 * Update the async key cache index. 02644 */ 02645 gpsi->dwAsyncKeyCache++; 02646 } 02647 02648 VOID SetForegroundPriorityProcess( 02649 PPROCESSINFO ppi, 02650 PTHREADINFO pti, 02651 BOOL fSetForeground) 02652 { 02653 PEPROCESS Process; 02654 UCHAR PriorityClassSave; 02655 02656 UserAssert(ppi != NULL); 02657 02658 Process = ppi->Process; 02659 UserAssert(ppi->Process != NULL); 02660 02661 if (ppi->W32PF_Flags & W32PF_IDLESCREENSAVER) { 02662 fSetForeground = FALSE; 02663 PriorityClassSave = Process->PriorityClass; 02664 Process->PriorityClass = PROCESS_PRIORITY_CLASS_IDLE; 02665 } 02666 02667 /* 02668 * If we previously delayed setting some process to the background 02669 * because a screen saver was starting up, do it now. 02670 */ 02671 if (gppiForegroundOld != NULL) { 02672 if (gppiForegroundOld == ppi) { 02673 gppiForegroundOld = NULL; 02674 } else if (ppi != gppiScreenSaver) { 02675 PsSetProcessPriorityByClass(gppiForegroundOld->Process, PsProcessPriorityBackground); 02676 gppiForegroundOld = NULL; 02677 } 02678 } 02679 02680 /* 02681 * If this app should be background, don't let it go foreground. 02682 * Foreground apps run at a higher base priority. 02683 */ 02684 if (ppi->W32PF_Flags & W32PF_FORCEBACKGROUNDPRIORITY) { 02685 if (pti != NULL && !(pti->TIF_flags & TIF_GLOBALHOOKER)) { 02686 PsSetProcessPriorityByClass(Process, PsProcessPrioritySpinning); 02687 } 02688 } else if (fSetForeground) { 02689 PsSetProcessPriorityByClass(Process, PsProcessPriorityForeground); 02690 } else if (pti != NULL && !(pti->TIF_flags & TIF_GLOBALHOOKER)) { 02691 /* 02692 * Don't adjust the priority of the current foreground process if 02693 * the new foreground process is a screen saver. 02694 */ 02695 if (gppiScreenSaver && gppiScreenSaver != ppi) { 02696 gppiForegroundOld = ppi; 02697 } else { 02698 PsSetProcessPriorityByClass(Process, PsProcessPriorityBackground); 02699 } 02700 } 02701 02702 if (ppi->W32PF_Flags & W32PF_IDLESCREENSAVER) { 02703 Process->PriorityClass = PriorityClassSave; 02704 } 02705 } 02706 02707 02708 VOID SetForegroundPriority( 02709 PTHREADINFO pti, 02710 BOOL fSetForeground) 02711 { 02712 UserAssert(pti != NULL); 02713 02714 /* 02715 * We don't want to change the priority of system or console threads 02716 */ 02717 if (pti->TIF_flags & (TIF_SYSTEMTHREAD | TIF_CSRSSTHREAD)) 02718 return; 02719 02720 SetForegroundPriorityProcess(pti->ppi, pti, fSetForeground); 02721 }

Generated on Sat May 15 19:40:03 2004 for test by doxygen 1.3.7