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

winmgr.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: winmgr.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Core Window Manager APIs and support routines. 00007 * 00008 * History: 00009 * 24-Sep-1990 darrinm Generated stubs. 00010 * 22-Jan-1991 IanJa Handle revalidation added 00011 * 19-Feb-1991 JimA Added enum access checks 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 /***************************************************************************\ 00018 * xxxFlashWindow (API) 00019 * 00020 * New for 5.0: HIWORD(dwFlags) contains the number of times the window should be 00021 * flashed. LOWORD(dwFlags) contains the FLASHW_ bits. 00022 * 00023 * History: 00024 * 27-Nov-1990 DarrinM Ported. 00025 * 15-Nov-1997 MCostea Added dwTimeout and windowing the maximised cmd 00026 \***************************************************************************/ 00027 BOOL xxxFlashWindow( 00028 PWND pwnd, 00029 DWORD dwFlags, 00030 DWORD dwTimeout) 00031 { 00032 00033 BOOL fStatePrev = FALSE; 00034 BOOL fFlashOn; 00035 DWORD dwState; 00036 00037 CheckLock(pwnd); 00038 /* 00039 * Get the previous state. If not available (FLASHW_STOP) then 00040 * initialize on/off based on frame 00041 */ 00042 dwState = GetFlashWindowState(pwnd); 00043 if (dwState == FLASHW_DONE) { 00044 /* 00045 * We just need to clean up and to set the activation correctly 00046 */ 00047 dwState |= FLASHW_KILLTIMER; 00048 dwFlags = FLASHW_STOP; 00049 goto flash; 00050 } 00051 if (dwState == FLASHW_STOP) { 00052 #if defined(_X86_) 00053 /* 00054 * If there is a fullscreen cmd window, switch it to window mode 00055 * so that the user gets a chance to see the flashing one 00056 */ 00057 if (gbFullScreen == FULLSCREEN) { 00058 _PostMessage(gspwndFullScreen, WM_USER + 6, (WPARAM)WINDOWED, (LPARAM)0); 00059 } 00060 #endif // _X86_ 00061 if (TestWF(pwnd, WFFRAMEON)) { 00062 dwState = FLASHW_ON | FLASHW_STARTON; 00063 } 00064 } else if (dwFlags == FLASHW_TIMERCALL) { 00065 dwFlags = dwState; 00066 } 00067 dwFlags &= FLASHW_CALLERBITS; 00068 fStatePrev = (dwState & FLASHW_ON); 00069 /* 00070 * Later5.0 Gerardob 00071 * Not sure why we do this check but it used to be here. 00072 */ 00073 if (pwnd == gspwndAltTab) { 00074 return fStatePrev; 00075 } 00076 /* 00077 * Check if we're waiting to come to the foreground to stop. 00078 */ 00079 if (dwState & FLASHW_FLASHNOFG) { 00080 if (gpqForeground == GETPTI(pwnd)->pq) 00081 dwFlags = FLASHW_STOP; 00082 } 00083 00084 flash: 00085 /* 00086 * Figure out new state 00087 */ 00088 if (dwFlags != FLASHW_STOP) { 00089 fFlashOn = !fStatePrev; 00090 } else { 00091 fFlashOn = (gpqForeground != NULL) && (gpqForeground->spwndActive == pwnd); 00092 } 00093 /* 00094 * Flash'em 00095 */ 00096 if ((dwFlags == FLASHW_STOP) || (dwFlags & FLASHW_CAPTION)) { 00097 xxxSendMessage(pwnd, WM_NCACTIVATE, fFlashOn, 0L); 00098 } 00099 if ((dwFlags == FLASHW_STOP) || (dwFlags & FLASHW_TRAY)) { 00100 if (IsTrayWindow(pwnd)) { 00101 HWND hw = HWq(pwnd); 00102 BOOL fShellFlash; 00103 if (dwState & FLASHW_DONE) { 00104 /* 00105 * If the window is not the active one when we're done flashing, 00106 * let the tray icon remain activated. The Shell is going to 00107 * take care to restore it at the when the window gets activated 00108 */ 00109 fShellFlash = !fFlashOn; 00110 } else { 00111 fShellFlash = (dwFlags == FLASHW_STOP ? FALSE : fFlashOn); 00112 } 00113 xxxCallHook(HSHELL_REDRAW, (WPARAM) hw, (LPARAM) fShellFlash, WH_SHELL); 00114 PostShellHookMessages(fShellFlash? HSHELL_FLASH:HSHELL_REDRAW, (LPARAM)hw); 00115 } 00116 } 00117 /* 00118 * If we're to continue, check count, set timer and store 00119 * state as appropriate. Otherwise, kill timer and remove 00120 * state 00121 */ 00122 if (dwFlags != FLASHW_STOP) { 00123 /* 00124 * If counting, decrement count when we complete a cycle 00125 */ 00126 if (HIWORD(dwFlags) != 0) { 00127 dwState |= FLASHW_COUNTING; 00128 if (!(fFlashOn ^ !!(dwState & FLASHW_STARTON))) { 00129 dwFlags -= MAKELONG(0,1); 00130 } 00131 /* 00132 * Make sure we have a timer going. 00133 */ 00134 if (!(dwState & FLASHW_KILLTIMER)) { 00135 dwFlags |= FLASHW_TIMER; 00136 } 00137 } 00138 /* 00139 * Set a timer if needed. 00140 */ 00141 if (dwFlags & FLASHW_TIMER) { 00142 dwState |= FLASHW_KILLTIMER; 00143 InternalSetTimer(pwnd, 00144 IDSYS_FLASHWND, 00145 dwTimeout ? dwTimeout : gpsi->dtCaretBlink, 00146 xxxSystemTimerProc, 00147 TMRF_SYSTEM); 00148 } 00149 /* 00150 * Remember on/off state, propagate public flags 00151 * and count then save the state 00152 */ 00153 if (dwState & FLASHW_COUNTING && 00154 HIWORD(dwFlags) == 0) { 00155 dwState = FLASHW_DONE; 00156 } 00157 else { 00158 SET_OR_CLEAR_FLAG(dwState, FLASHW_ON, fFlashOn); 00159 COPY_FLAG(dwState, dwFlags, FLASHW_CALLERBITS & ~FLASHW_TIMER); 00160 } 00161 SetFlashWindowState(pwnd, dwState); 00162 00163 } else { 00164 /* 00165 * We're done. 00166 */ 00167 if (dwState & FLASHW_KILLTIMER) { 00168 _KillSystemTimer(pwnd, IDSYS_FLASHWND); 00169 } 00170 RemoveFlashWindowState(pwnd); 00171 } 00172 00173 return fStatePrev; 00174 } 00175 00176 /***************************************************************************\ 00177 * xxxEnableWindow (API) 00178 * 00179 * 00180 * History: 00181 * 12-Nov-1990 DarrinM Ported. 00182 \***************************************************************************/ 00183 00184 BOOL xxxEnableWindow( 00185 PWND pwnd, 00186 BOOL fEnable) 00187 { 00188 BOOL fOldState, fChange; 00189 00190 CheckLock(pwnd); 00191 UserAssert(IsWinEventNotifyDeferredOK()); 00192 00193 fOldState = TestWF(pwnd, WFDISABLED); 00194 00195 if (!fEnable) { 00196 fChange = !TestWF(pwnd, WFDISABLED); 00197 00198 xxxSendMessage(pwnd, WM_CANCELMODE, 0, 0); 00199 00200 if (pwnd == PtiCurrent()->pq->spwndFocus) { 00201 xxxSetFocus(NULL); 00202 } 00203 SetWF(pwnd, WFDISABLED); 00204 00205 } else { 00206 fChange = TestWF(pwnd, WFDISABLED); 00207 ClrWF(pwnd, WFDISABLED); 00208 } 00209 00210 if (fChange) { 00211 if (FWINABLE()) { 00212 xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_WINDOW, 00213 INDEXID_CONTAINER, 0); 00214 } 00215 xxxSendMessage(pwnd, WM_ENABLE, fEnable, 0L); 00216 } 00217 00218 return fOldState; 00219 } 00220 00221 /***************************************************************************\ 00222 * xxxDoSend 00223 * 00224 * The following code is REALLY BOGUS!!!! Basically it prevents an 00225 * app from hooking the WM_GET/SETTEXT messages if they're going to 00226 * be called from another app. 00227 * 00228 * History: 00229 * 04-Mar-1992 JimA Ported from Win 3.1 sources. 00230 \***************************************************************************/ 00231 00232 LRESULT xxxDoSend( 00233 PWND pwnd, 00234 UINT message, 00235 WPARAM wParam, 00236 LPARAM lParam) 00237 { 00238 /* 00239 * We compare PROCESSINFO sturctures here so multi-threaded 00240 * app can do what the want. 00241 */ 00242 if (GETPTI(pwnd)->ppi == PtiCurrent()->ppi) { 00243 return xxxSendMessage(pwnd, message, wParam, lParam); 00244 } else { 00245 return xxxDefWindowProc(pwnd, message, wParam, lParam); 00246 } 00247 } 00248 00249 /***************************************************************************\ 00250 * xxxGetWindowText (API) 00251 * 00252 * 00253 * History: 00254 * 09-Nov-1990 DarrinM Wrote. 00255 \***************************************************************************/ 00256 00257 int xxxGetWindowText( 00258 PWND pwnd, 00259 LPTSTR psz, 00260 int cchMax) 00261 { 00262 LARGE_UNICODE_STRING str; 00263 UINT nRet, nLen; 00264 00265 CheckLock(pwnd); 00266 00267 if (cchMax) { 00268 /* 00269 * Initialize string empty, in case xxxSendMessage aborts validation 00270 * If a bogus value was returned, rely on str.Length 00271 */ 00272 str.bAnsi = FALSE; 00273 str.MaximumLength = cchMax * sizeof(WCHAR); 00274 str.Buffer = psz; 00275 str.Length = 0; 00276 00277 *psz = TEXT('\0'); 00278 00279 nRet = (UINT)xxxDoSend(pwnd, WM_GETTEXT, cchMax, (LPARAM)&str); 00280 nLen = str.Length / sizeof(WCHAR); 00281 return (nRet > nLen) ? nLen : nRet; 00282 } 00283 00284 return 0; 00285 } 00286 00287 /***************************************************************************\ 00288 * xxxSetParent (API) 00289 * 00290 * Change a windows parent to a new window. These steps are taken: 00291 * 00292 * 1. The window is hidden (if visible), 00293 * 2. Its coordinates are mapped into the new parent's space such that the 00294 * window's screen-relative position is unchanged. 00295 * 3. The window is unlinked from its old parent and relinked to the new. 00296 * 4. xxxSetWindowPos is used to move the window to its new position. 00297 * 5. The window is shown again (if originally visible) 00298 * 00299 * NOTE: If you have a child window and set its parent to be NULL (the 00300 * desktop), the WS_CHILD style isn't removed from the window. This bug has 00301 * been in windows since 2.x. It turns out the apps group depends on this for 00302 * their combo boxes to work. Basically, you end up with a top level window 00303 * that never gets activated (our activation code blows it off due to the 00304 * WS_CHILD bit). 00305 * 00306 * History: 00307 * 12-Nov-1990 DarrinM Ported. 00308 * 19-Feb-1991 JimA Added enum access check 00309 \***************************************************************************/ 00310 00311 PWND xxxSetParent( 00312 PWND pwnd, 00313 PWND pwndNewParent) 00314 { 00315 POINT pt; 00316 BOOL fVisible; 00317 PWND pwndOldParent; 00318 TL tlpwndOldParent; 00319 TL tlpwndNewParent; 00320 PVOID pvRet; 00321 PWND pwndDesktop; 00322 PWND pwndT; 00323 int flags = SWP_NOZORDER | SWP_NOSIZE; 00324 00325 CheckLock(pwnd); 00326 CheckLock(pwndNewParent); 00327 00328 if (!ValidateParentDepth(pwnd, pwndNewParent)) { 00329 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "Exceeded nested children limit"); 00330 return NULL; 00331 } 00332 00333 pwndDesktop = PWNDDESKTOP(pwnd); 00334 00335 /* 00336 * In 1.0x, an app's parent was null, but now it is pwndDesktop. 00337 * Need to remember to lock pwndNewParent because we're reassigning 00338 * it here. 00339 */ 00340 if (pwndNewParent == NULL) 00341 pwndNewParent = pwndDesktop; 00342 00343 /* 00344 * Don't ever change the parent of the desktop. 00345 */ 00346 if ((pwnd == pwndDesktop) || (pwnd == PWNDMESSAGE(pwnd))) { 00347 RIPERR0(ERROR_ACCESS_DENIED, 00348 RIP_WARNING, 00349 "Access denied: can't change parent of the desktop"); 00350 00351 return NULL; 00352 } 00353 00354 /* 00355 * Don't let the window become its own parent, grandparent, etc. 00356 */ 00357 for (pwndT = pwndNewParent; pwndT != NULL; pwndT = pwndT->spwndParent) { 00358 00359 if (pwnd == pwndT) { 00360 RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, 00361 "Attempting to creating a parent-child relationship loop"); 00362 return NULL; 00363 } 00364 } 00365 00366 /* 00367 * We still need pwndNewParent across callbacks... and even though 00368 * it was passed in, it may have been reassigned above. 00369 */ 00370 ThreadLock(pwndNewParent, &tlpwndNewParent); 00371 00372 /* 00373 * Make the thing disappear from original parent. 00374 */ 00375 fVisible = xxxShowWindow(pwnd, MAKELONG(SW_HIDE, TEST_PUDF(PUDF_ANIMATE))); 00376 00377 /* 00378 * Ensure that the window being changed and the new parent 00379 * are not in a destroyed state. 00380 * 00381 * IMPORTANT: After this check, do not leave the critical section 00382 * until the window links have been rearranged. 00383 */ 00384 if (TestWF(pwnd, WFDESTROYED) || TestWF(pwndNewParent, WFDESTROYED)) { 00385 ThreadUnlock(&tlpwndNewParent); 00386 return NULL; 00387 } 00388 00389 pwndOldParent = pwnd->spwndParent; 00390 ThreadLock(pwndOldParent, &tlpwndOldParent); 00391 00392 #ifdef USE_MIRRORING 00393 if (TestWF(pwndOldParent, WEFLAYOUTRTL)) { 00394 pt.x = pwnd->rcWindow.right; 00395 } else 00396 #endif 00397 { 00398 pt.x = pwnd->rcWindow.left; 00399 } 00400 pt.y = pwnd->rcWindow.top; 00401 _ScreenToClient(pwndOldParent, &pt); 00402 00403 UnlinkWindow(pwnd, pwndOldParent); 00404 Lock(&pwnd->spwndParent, pwndNewParent); 00405 00406 if (pwndNewParent == PWNDDESKTOP(pwnd) && !TestWF(pwnd, WEFTOPMOST)) { 00407 00408 /* 00409 * Make sure a child who's owner is topmost inherits the topmost 00410 * bit. - win31 bug 7568 00411 */ 00412 if (TestWF(pwnd, WFCHILD) && 00413 (pwnd->spwndOwner) && 00414 TestWF(pwnd->spwndOwner, WEFTOPMOST)) { 00415 00416 SetWF(pwnd, WEFTOPMOST); 00417 } 00418 00419 /* 00420 * BACKWARD COMPATIBILITY HACK ALERT 00421 * 00422 * All top level windows must be WS_CLIPSIBLINGs bit set. 00423 * The SDM ComboBox() code calls SetParent() with a listbox 00424 * window that does not have this set. This causes problems 00425 * with InternalInvalidate2() because it does not subtract off 00426 * the window from the desktop's update region. 00427 * 00428 * We must invalidate the DC cache here, too, because if there is 00429 * a cache entry lying around, its clipping region will be incorrect. 00430 */ 00431 if ((pwndNewParent == _GetDesktopWindow()) && 00432 !TestWF(pwnd, WFCLIPSIBLINGS)) { 00433 00434 SetWF(pwnd, WFCLIPSIBLINGS); 00435 zzzInvalidateDCCache(pwnd, IDC_DEFAULT); 00436 } 00437 00438 /* 00439 * This is a top level window but it isn't a topmost window so we 00440 * have to link it below all topmost windows. 00441 */ 00442 LinkWindow(pwnd, 00443 CalcForegroundInsertAfter(pwnd), 00444 pwndNewParent); 00445 } else { 00446 00447 /* 00448 * If this is a child window or if this is a TOPMOST window, we can 00449 * link at the head of the parent chain. 00450 */ 00451 LinkWindow(pwnd, NULL, pwndNewParent); 00452 } 00453 00454 /* 00455 * If we're a child window, do any necessary attaching and 00456 * detaching. 00457 */ 00458 if (TestwndChild(pwnd)) { 00459 00460 /* 00461 * Make sure we're not a WFCHILD window that got SetParent()'ed 00462 * to the desktop. 00463 */ 00464 if ((pwnd->spwndParent != PWNDDESKTOP(pwnd)) && 00465 GETPTI(pwnd) != GETPTI(pwndOldParent)) { 00466 00467 zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndOldParent), FALSE); 00468 } 00469 00470 /* 00471 * If the new parent window is on a different thread, and also 00472 * isn't the desktop window, attach ourselves appropriately. 00473 */ 00474 if (pwndNewParent != PWNDDESKTOP(pwnd) && 00475 GETPTI(pwnd) != GETPTI(pwndNewParent)) { 00476 00477 zzzAttachThreadInput(GETPTI(pwnd), GETPTI(pwndNewParent), TRUE); 00478 } 00479 } 00480 00481 if (pwndNewParent == PWNDMESSAGE(pwnd) || pwndOldParent == PWNDMESSAGE(pwnd)) 00482 flags |= SWP_NOACTIVATE; 00483 00484 if (FWINABLE()) { 00485 xxxWindowEvent(EVENT_OBJECT_PARENTCHANGE, pwnd, OBJID_WINDOW, 00486 INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 00487 } 00488 00489 /* 00490 * We mustn't return an invalid pwndOldParent 00491 */ 00492 xxxSetWindowPos(pwnd, NULL, pt.x, pt.y, 0, 0, flags); 00493 00494 if (fVisible) { 00495 xxxShowWindow(pwnd, MAKELONG(SW_SHOWNORMAL, TEST_PUDF(PUDF_ANIMATE))); 00496 } 00497 00498 /* 00499 * returns pwndOldParent if still valid, else NULL. 00500 */ 00501 pvRet = ThreadUnlock(&tlpwndOldParent); 00502 ThreadUnlock(&tlpwndNewParent); 00503 00504 return pvRet; 00505 } 00506 00507 /***************************************************************************\ 00508 * xxxFindWindowEx (API) 00509 * 00510 * Searches for a window among top level windows. The keys used are pszClass, 00511 * (the class name) and/or pszName, (the window title name). Either can be 00512 * NULL. 00513 * 00514 * History: 00515 * 06-Jun-1994 JohnL Converted xxxFindWindow to xxxFindWindowEx 00516 * 10-Nov-1992 mikeke Added 16bit and 32bit only flag 00517 * 24-Sep-1990 DarrinM Generated stubs. 00518 * 02-Jun-1991 ScottLu Ported from Win3. 00519 * 19-Feb-1991 JimA Added enum access check 00520 \***************************************************************************/ 00521 00522 #define CCHMAXNAME 80 00523 00524 PWND _FindWindowEx( 00525 PWND pwndParent, 00526 PWND pwndChild, 00527 LPCWSTR ccxlpszClass, 00528 LPCWSTR ccxlpszName, 00529 DWORD dwType) 00530 { 00531 /* 00532 * Note that the Class and Name pointers are client-side addresses. 00533 */ 00534 00535 PBWL pbwl; 00536 HWND *phwnd; 00537 PWND pwnd; 00538 WORD atomClass = 0; 00539 LPCWSTR lpName; 00540 BOOL fTryMessage = FALSE; 00541 00542 if (ccxlpszClass != NULL) { 00543 00544 atomClass = FindClassAtom(ccxlpszClass); 00545 00546 if (atomClass == 0) { 00547 return NULL; 00548 } 00549 } 00550 00551 /* 00552 * Setup parent window 00553 */ 00554 if (!pwndParent) { 00555 pwndParent = _GetDesktopWindow(); 00556 /* 00557 * If we are starting from the root and no child window 00558 * was specified, then check the message window tree too 00559 * in case we don't find it on the desktop tree. 00560 */ 00561 00562 if (!pwndChild) 00563 fTryMessage = TRUE; 00564 } 00565 00566 TryAgain: 00567 /* 00568 * Setup first child 00569 */ 00570 if (!pwndChild) { 00571 pwndChild = pwndParent->spwndChild; 00572 } else { 00573 if (pwndChild->spwndParent != pwndParent) { 00574 RIPMSG0(RIP_WARNING, 00575 "FindWindowEx: Child window doesn't have proper parent"); 00576 return NULL; 00577 } 00578 00579 pwndChild = pwndChild->spwndNext; 00580 } 00581 00582 /* 00583 * Generate a list of top level windows. 00584 */ 00585 if ((pbwl = BuildHwndList(pwndChild, BWL_ENUMLIST, NULL)) == NULL) { 00586 return NULL; 00587 } 00588 00589 /* 00590 * Set pwnd to NULL in case the window list is empty. 00591 */ 00592 pwnd = NULL; 00593 00594 try { 00595 for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) { 00596 00597 /* 00598 * Validate this hwnd since we left the critsec earlier (below 00599 * in the loop we send a message! 00600 */ 00601 if ((pwnd = RevalidateHwnd(*phwnd)) == NULL) 00602 continue; 00603 00604 /* 00605 * make sure this window is of the right type 00606 */ 00607 if (dwType != FW_BOTH) { 00608 if (((dwType == FW_16BIT) && !(GETPTI(pwnd)->TIF_flags & TIF_16BIT)) || 00609 ((dwType == FW_32BIT) && (GETPTI(pwnd)->TIF_flags & TIF_16BIT))) 00610 continue; 00611 } 00612 00613 /* 00614 * If the class is specified and doesn't match, skip this window 00615 */ 00616 if (!atomClass || (atomClass == pwnd->pcls->atomClassName)) { 00617 if (!ccxlpszName) 00618 break; 00619 00620 if (pwnd->strName.Length) { 00621 lpName = pwnd->strName.Buffer; 00622 } else { 00623 lpName = szNull; 00624 } 00625 00626 /* 00627 * Is the text the same? If so, return with this window! 00628 */ 00629 if (_wcsicmp(ccxlpszName, lpName) == 0) 00630 break; 00631 } 00632 00633 /* 00634 * The window did not match. 00635 */ 00636 pwnd = NULL; 00637 } 00638 } except (W32ExceptionHandler(FALSE, RIP_WARNING)) { 00639 pwnd = NULL; 00640 } 00641 00642 FreeHwndList(pbwl); 00643 00644 if (!pwnd && fTryMessage) { 00645 fTryMessage = FALSE; 00646 pwndParent = _GetMessageWindow(); 00647 pwndChild = NULL; 00648 goto TryAgain; 00649 } 00650 00651 return ((*phwnd == (HWND)1) ? NULL : pwnd); 00652 } 00653 00654 /***************************************************************************\ 00655 * UpdateCheckpoint 00656 * 00657 * Checkpoints the current window size/position/state and returns a pointer 00658 * to the structure. 00659 * 00660 * History: 00661 \***************************************************************************/ 00662 00663 PCHECKPOINT UpdateCheckpoint( 00664 PWND pwnd) 00665 { 00666 RECT rc; 00667 00668 GetRect(pwnd, &rc, GRECT_WINDOW | GRECT_PARENTCOORDS); 00669 return CkptRestore(pwnd, &rc); 00670 } 00671 00672 /***************************************************************************\ 00673 * GetWindowPlacement 00674 * 00675 * History: 00676 * 02-Mar-1992 MikeKe From Win 3.1 00677 \***************************************************************************/ 00678 00679 BOOL _GetWindowPlacement( 00680 PWND pwnd, 00681 PWINDOWPLACEMENT pwp) 00682 { 00683 CHECKPOINT * pcp; 00684 00685 /* 00686 * this will set the normal or the minimize point in the checkpoint, 00687 * so that all elements will be up to date. 00688 */ 00689 pcp = UpdateCheckpoint(pwnd); 00690 00691 if (!pcp) 00692 return FALSE; 00693 00694 if (TestWF(pwnd, WFMINIMIZED)) { 00695 pwp->showCmd = SW_SHOWMINIMIZED; 00696 } else if (TestWF(pwnd, WFMAXIMIZED)) { 00697 pwp->showCmd = SW_SHOWMAXIMIZED; 00698 } else { 00699 pwp->showCmd = SW_SHOWNORMAL; 00700 } 00701 00702 CopyRect(&pwp->rcNormalPosition, &pcp->rcNormal); 00703 00704 if (pcp->fMinInitialized) { 00705 pwp->ptMinPosition = pcp->ptMin; 00706 } else { 00707 pwp->ptMinPosition.x = pwp->ptMinPosition.y = -1; 00708 } 00709 00710 /* 00711 * We never ever save the position of "normal" maximized windows. Other 00712 * wise, when the size border changes dimensions, the max pos would be 00713 * invalid, and you would never be able to reset it. 00714 */ 00715 if (pcp->fMaxInitialized && !TestWF(pwnd, WFREALLYMAXIMIZABLE)) { 00716 pwp->ptMaxPosition = pcp->ptMax; 00717 } else { 00718 pwp->ptMaxPosition.x = pwp->ptMaxPosition.y = -1; 00719 } 00720 00721 if ((pwnd->spwndParent == PWNDDESKTOP(pwnd)) && 00722 !TestWF(pwnd, WEFTOOLWINDOW)) { 00723 00724 PMONITOR pMonitor; 00725 00726 pMonitor = _MonitorFromRect(&pwp->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY); 00727 00728 /* 00729 * Convert min, normal positions to be relative to the working area. 00730 * The max pos already is (always is saved that way). 00731 * 00732 * working area, except for maximized position, which is always 00733 * working area relative. 00734 */ 00735 if (pcp->fMinInitialized) { 00736 pwp->ptMinPosition.x -= (pMonitor->rcWork.left - pMonitor->rcMonitor.left); 00737 pwp->ptMinPosition.y -= (pMonitor->rcWork.top - pMonitor->rcMonitor.top); 00738 } 00739 00740 OffsetRect(&pwp->rcNormalPosition, 00741 pMonitor->rcMonitor.left - pMonitor->rcWork.left, 00742 pMonitor->rcMonitor.top - pMonitor->rcWork.top); 00743 } 00744 00745 pwp->flags = 0; 00746 00747 /* 00748 * B#3276 00749 * Don't allow WPF_SETMINPOSITION on top-level windows. 00750 */ 00751 if (TestwndChild(pwnd) && pcp->fDragged) 00752 pwp->flags |= WPF_SETMINPOSITION; 00753 00754 if (pcp->fWasMaximizedBeforeMinimized || TestWF(pwnd, WFMAXIMIZED)) 00755 pwp->flags |= WPF_RESTORETOMAXIMIZED; 00756 00757 pwp->length = sizeof(WINDOWPLACEMENT); 00758 00759 return TRUE; 00760 } 00761 00762 /***************************************************************************\ 00763 * CheckPlacementBounds 00764 * 00765 * History: 00766 * 02-Mar-1992 MikeKe From Win 3.1 00767 \***************************************************************************/ 00768 00769 VOID CheckPlacementBounds( 00770 LPRECT lprc, 00771 LPPOINT ptMin, 00772 LPPOINT ptMax, 00773 PMONITOR pMonitor) 00774 { 00775 int xIcon; 00776 int yIcon; 00777 int sTop; 00778 int sBottom; 00779 int sLeft; 00780 int sRight; 00781 00782 /* 00783 * Check Normal Window Placement 00784 */ 00785 00786 /* 00787 * Possible values for these sign variables are : 00788 * -1 : less than the minimum for that dimension 00789 * 0 : within the range for that dimension 00790 * 1 : more than the maximum for that dimension 00791 */ 00792 sTop = (lprc->top < pMonitor->rcWork.top) ? -1 : 00793 ((lprc->top > pMonitor->rcWork.bottom) ? 1 : 0); 00794 00795 sBottom = (lprc->bottom < pMonitor->rcWork.top) ? -1 : 00796 ((lprc->bottom > pMonitor->rcWork.bottom) ? 1 : 0); 00797 00798 sLeft = (lprc->left < pMonitor->rcWork.left) ? -1 : 00799 ((lprc->left > pMonitor->rcWork.right) ? 1 : 0); 00800 00801 sRight = (lprc->right < pMonitor->rcWork.left) ? -1 : 00802 ((lprc->right > pMonitor->rcWork.right) ? 1 : 0); 00803 00804 if ((sTop * sBottom > 0) || (sLeft * sRight > 0)) { 00805 00806 /* 00807 * Window is TOTALLY outside monitor bounds. The resolution and/or 00808 * configuration of monitors probably changed since the last time 00809 * we ran this app. 00810 * 00811 * Slide it FULLY onto the monitor at the nearest position. 00812 */ 00813 int size; 00814 00815 if (sTop < 0) { 00816 lprc->bottom -= lprc->top; 00817 lprc->top = pMonitor->rcWork.top; 00818 } else if (sBottom > 0) { 00819 size = lprc->bottom - lprc->top; 00820 lprc->top = max(pMonitor->rcWork.bottom - size, pMonitor->rcWork.top); 00821 lprc->bottom = lprc->top + size; 00822 } 00823 00824 if (sLeft < 0) { 00825 lprc->right -= lprc->left; 00826 lprc->left = pMonitor->rcWork.left; 00827 } else if (sRight > 0) { 00828 size = lprc->right - lprc->left; 00829 lprc->left = max(pMonitor->rcWork.right - size, pMonitor->rcWork.left); 00830 lprc->right = lprc->left + size; 00831 } 00832 } 00833 00834 /* 00835 * Check Iconic Window Placement 00836 */ 00837 if (ptMin->x != -1) { 00838 00839 xIcon = SYSMET(CXMINSPACING); 00840 yIcon = SYSMET(CYMINSPACING); 00841 00842 sTop = (ptMin->y < pMonitor->rcWork.top) ? -1 : 00843 ((ptMin->y > pMonitor->rcWork.bottom) ? 1 : 0); 00844 00845 sBottom = (ptMin->y + yIcon < pMonitor->rcWork.top) ? -1 : 00846 ((ptMin->y + yIcon > pMonitor->rcWork.bottom) ? 1 : 0); 00847 00848 sLeft = (ptMin->x < pMonitor->rcWork.left) ? -1 : 00849 ((ptMin->x > pMonitor->rcWork.right) ? 1 : 0); 00850 00851 sRight = (ptMin->x + xIcon < pMonitor->rcWork.left) ? -1 : 00852 ((ptMin->x + xIcon > pMonitor->rcWork.right) ? 1 : 0); 00853 00854 /* 00855 * Icon is TOTALLY outside monitor bounds; repark it. 00856 */ 00857 if ((sTop * sBottom > 0) || (sLeft * sRight > 0)) 00858 ptMin->x = ptMin->y = -1; 00859 } 00860 00861 /* 00862 * Check Maximized Window Placement 00863 */ 00864 if (ptMax->x != -1 && 00865 (ptMax->x + pMonitor->rcWork.left >= pMonitor->rcWork.right || 00866 ptMax->y + pMonitor->rcWork.top >= pMonitor->rcWork.bottom)) { 00867 00868 /* 00869 * window is TOTALLY below beyond maximum dimensions; zero the 00870 * position so that the window will at least be clipped to the 00871 * monitor. 00872 */ 00873 ptMax->x = 0; 00874 ptMax->y = 0; 00875 } 00876 } 00877 00878 /***************************************************************************\ 00879 * WPUpdateCheckPointSettings 00880 * 00881 * History: 00882 * 02/23/98 GerardoB Extracted from xxxSetWindowPlacement 00883 \***************************************************************************/ 00884 void WPUpdateCheckPointSettings (PWND pwnd, UINT uWPFlags) 00885 { 00886 CHECKPOINT * pcp; 00887 00888 UserAssert(TestWF(pwnd, WFMINIMIZED)); 00889 if (pcp = UpdateCheckpoint(pwnd)) { 00890 00891 /* 00892 * Save settings in the checkpoint struct 00893 */ 00894 if (uWPFlags & WPF_SETMINPOSITION) 00895 pcp->fDragged = TRUE; 00896 00897 if (uWPFlags & WPF_RESTORETOMAXIMIZED) { 00898 pcp->fWasMaximizedBeforeMinimized = TRUE; 00899 } else { 00900 pcp->fWasMaximizedBeforeMinimized = FALSE; 00901 } 00902 } 00903 } 00904 /***************************************************************************\ 00905 * xxxSetWindowPlacement 00906 * 00907 * History: 00908 * 02-Mar-1992 MikeKe From Win 3.1 00909 \***************************************************************************/ 00910 00911 BOOL xxxSetWindowPlacement( 00912 PWND pwnd, 00913 PWINDOWPLACEMENT pwp) 00914 { 00915 CHECKPOINT * pcp; 00916 PMONITOR pMonitor; 00917 RECT rc; 00918 POINT ptMin; 00919 POINT ptMax; 00920 BOOL fMin; 00921 BOOL fMax; 00922 UINT uSWPFlags; 00923 BOOL fRealAsync; 00924 00925 CheckLock(pwnd); 00926 00927 CopyRect(&rc, &pwp->rcNormalPosition); 00928 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00929 pMonitor = _MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY); 00930 } 00931 00932 ptMin = pwp->ptMinPosition; 00933 fMin = ((ptMin.x != -1) && (ptMin.y != -1)); 00934 00935 ptMax = pwp->ptMaxPosition; 00936 fMax = ((ptMax.x != -1) && (ptMax.y != -1)); 00937 00938 /* 00939 * Convert back to working rectangle coordinates 00940 */ 00941 if ( pwnd->spwndParent == PWNDDESKTOP(pwnd) && 00942 !TestWF(pwnd, WEFTOOLWINDOW)) { 00943 00944 OffsetRect( 00945 &rc, 00946 pMonitor->rcWork.left - pMonitor->rcMonitor.left, 00947 pMonitor->rcWork.top - pMonitor->rcMonitor.top); 00948 00949 if (fMin) { 00950 ptMin.x += pMonitor->rcWork.left - pMonitor->rcMonitor.left; 00951 ptMin.y += pMonitor->rcWork.top - pMonitor->rcMonitor.top; 00952 } 00953 00954 CheckPlacementBounds(&rc, &ptMin, &ptMax, pMonitor); 00955 } 00956 00957 if (pcp = UpdateCheckpoint(pwnd)) { 00958 00959 /* 00960 * Save settings in the checkpoint struct 00961 */ 00962 CopyRect(&pcp->rcNormal, &rc); 00963 00964 pcp->ptMin = ptMin; 00965 pcp->fMinInitialized = fMin; 00966 pcp->fDragged = (pwp->flags & WPF_SETMINPOSITION) ? 00967 TRUE : FALSE; 00968 pcp->ptMax = ptMax; 00969 pcp->fMaxInitialized = fMax; 00970 pcp->fWasMaximizedBeforeMinimized = FALSE; 00971 } 00972 00973 /* 00974 * WPF_ASYNCWINDOWPLACEMENT new for NT5. 00975 */ 00976 uSWPFlags = SWP_NOZORDER | SWP_NOACTIVATE 00977 | ((pwp->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0); 00978 00979 if (TestWF(pwnd, WFMINIMIZED)) { 00980 00981 if ((!pcp || pcp->fDragged) && fMin) { 00982 xxxSetWindowPos(pwnd, 00983 PWND_TOP, 00984 ptMin.x, 00985 ptMin.y, 00986 0, 00987 0, 00988 SWP_NOSIZE | uSWPFlags); 00989 } 00990 00991 } else if (TestWF(pwnd, WFMAXIMIZED)) { 00992 00993 if (pcp != NULL) { 00994 if (TestWF(pwnd, WFREALLYMAXIMIZABLE)) 00995 pcp->fMaxInitialized = FALSE; 00996 00997 if (pcp->fMaxInitialized) { 00998 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00999 ptMax.x += pMonitor->rcWork.left; 01000 ptMax.y += pMonitor->rcWork.top; 01001 } 01002 01003 xxxSetWindowPos(pwnd, 01004 PWND_TOP, 01005 ptMax.x, 01006 ptMax.y, 01007 0, 01008 0, 01009 SWP_NOSIZE | uSWPFlags); 01010 } 01011 } 01012 01013 01014 } else { 01015 01016 xxxSetWindowPos(pwnd, 01017 PWND_TOP, 01018 rc.left, 01019 rc.top, 01020 rc.right - rc.left, 01021 rc.bottom - rc.top, 01022 uSWPFlags); 01023 } 01024 /* 01025 * xxxSetWindowPos is only assync when the window's thread is on a 01026 * different queue than the current thread's. See AsyncWindowPos. 01027 */ 01028 fRealAsync = (pwp->flags & WPF_ASYNCWINDOWPLACEMENT) 01029 && (GETPTI(pwnd)->pq != PtiCurrent()->pq); 01030 01031 if (fRealAsync) { 01032 _ShowWindowAsync(pwnd, pwp->showCmd, pwp->flags); 01033 } else { 01034 xxxShowWindow(pwnd, MAKELONG(pwp->showCmd, TEST_PUDF(PUDF_ANIMATE))); 01035 } 01036 01037 if (TestWF(pwnd, WFMINIMIZED) && !fRealAsync) { 01038 WPUpdateCheckPointSettings(pwnd, pwp->flags); 01039 } 01040 01041 return TRUE; 01042 } 01043 01044 /***************************************************************************\ 01045 * xxxSetInternalWindowPos 01046 * 01047 * Sets a window to the size, position and state it was most recently 01048 * in. Side effect (possibly bug): shows and activates the window as well. 01049 * 01050 * History: 01051 * 28-Mar-1991 DavidPe Ported from Win 3.1 sources. 01052 \***************************************************************************/ 01053 01054 BOOL xxxSetInternalWindowPos( 01055 PWND pwnd, 01056 UINT cmdShow, 01057 LPRECT lprcWin, 01058 LPPOINT lpptMin) 01059 { 01060 CHECKPOINT * pcp; 01061 PMONITOR pMonitor; 01062 01063 CheckLock(pwnd); 01064 01065 if ((pcp = UpdateCheckpoint(pwnd)) == NULL) { 01066 return FALSE; 01067 } 01068 01069 if (lprcWin) { 01070 01071 pcp->rcNormal = *lprcWin; 01072 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01073 pMonitor = _MonitorFromRect(lprcWin, MONITOR_DEFAULTTOPRIMARY); 01074 OffsetRect( 01075 &pcp->rcNormal, 01076 pMonitor->rcWork.left - pMonitor->rcMonitor.left, 01077 pMonitor->rcWork.top - pMonitor->rcMonitor.top); 01078 } 01079 } 01080 01081 if (lpptMin && (lpptMin->x != -1)) { 01082 01083 pcp->ptMin = *lpptMin; 01084 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01085 pMonitor = _MonitorFromRect(&pcp->rcNormal, MONITOR_DEFAULTTOPRIMARY); 01086 pcp->ptMin.x += pMonitor->rcWork.left - pMonitor->rcMonitor.left; 01087 pcp->ptMin.y += pMonitor->rcWork.top - pMonitor->rcMonitor.top; 01088 } 01089 01090 pcp->fDragged = TRUE; 01091 pcp->fMinInitialized = TRUE; 01092 01093 } else { 01094 pcp->fMinInitialized = FALSE; 01095 pcp->fDragged = FALSE; 01096 } 01097 01098 if (TestWF(pwnd, WFMINIMIZED)) { 01099 01100 /* 01101 * need to move the icon 01102 */ 01103 if (pcp->fMinInitialized) { 01104 xxxSetWindowPos(pwnd, 01105 PWND_TOP, 01106 pcp->ptMin.x, 01107 pcp->ptMin.y, 01108 0, 01109 0, 01110 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); 01111 } 01112 01113 } else if (!TestWF(pwnd, WFMAXIMIZED) && lprcWin) { 01114 /* 01115 * need to set the size and the position 01116 */ 01117 xxxSetWindowPos(pwnd, 01118 NULL, 01119 lprcWin->left, 01120 lprcWin->top, 01121 lprcWin->right - lprcWin->left, 01122 lprcWin->bottom - lprcWin->top, 01123 SWP_NOZORDER); 01124 } 01125 01126 xxxShowWindow(pwnd, MAKELONG(cmdShow, TEST_PUDF(PUDF_ANIMATE))); 01127 01128 return TRUE; 01129 } 01130 01131 /***************************************************************************\ 01132 * _GetDesktopWindow (API) 01133 * 01134 * History: 01135 * 07-Nov-1990 DarrinM Implemented. 01136 \***************************************************************************/ 01137 01138 PWND _GetDesktopWindow(VOID) 01139 { 01140 PTHREADINFO pti = PtiCurrent(); 01141 PDESKTOPINFO pdi; 01142 01143 if (pti == NULL) 01144 return NULL; 01145 01146 pdi = pti->pDeskInfo; 01147 01148 return pdi == NULL ? NULL : pdi->spwnd; 01149 } 01150 01151 /***************************************************************************\ 01152 * _GetDesktopWindow (API) 01153 * 01154 * History: 01155 * 07-Nov-1990 DarrinM Implemented. 01156 \***************************************************************************/ 01157 01158 PWND _GetMessageWindow(VOID) 01159 { 01160 PTHREADINFO pti = PtiCurrent(); 01161 PDESKTOP pdi; 01162 01163 if (pti == NULL) 01164 return NULL; 01165 01166 pdi = pti->rpdesk; 01167 01168 return pdi == NULL ? NULL : pdi->spwndMessage; 01169 } 01170 01171 /**************************************************************************\ 01172 * TestWindowProcess 01173 * 01174 * History: 01175 * 14-Nov-1994 JimA Created. 01176 \**************************************************************************/ 01177 01178 BOOL TestWindowProcess( 01179 PWND pwnd) 01180 { 01181 return (PpiCurrent() == GETPTI(pwnd)->ppi); 01182 } 01183 01184 /***************************************************************************\ 01185 * ValidateDepth 01186 * 01187 * The function conveniently simulates recursion by utilizing the fact 01188 * that from any sibling in the Next chain we can correctly get to the 01189 * parent window and that two siblings in the Next chain cannot have 01190 * different parents. 01191 * 01192 * 12-Mar-1997 vadimg created 01193 \***************************************************************************/ 01194 01195 #define NESTED_WINDOW_LIMIT 100 01196 01197 BOOL ValidateParentDepth(PWND pwnd, PWND pwndParent) 01198 { 01199 UINT cDepth = 1, cDepthMax; 01200 PWND pwndStop; 01201 01202 /* 01203 * Calculate the depth of the parent chain. 01204 */ 01205 while (pwndParent != NULL) { 01206 pwndParent = pwndParent->spwndParent; 01207 cDepth++; 01208 } 01209 01210 cDepthMax = cDepth; 01211 01212 /* 01213 * When pwnd is NULL, it means that we want to add one more 01214 * level to the existing depth of pwndParent. 01215 */ 01216 if (pwnd == NULL || pwnd->spwndChild == NULL) { 01217 goto Exit; 01218 } else { 01219 pwndStop = pwnd->spwndParent; 01220 } 01221 01222 Restart: 01223 if (pwnd->spwndChild != NULL) { 01224 pwnd = pwnd->spwndChild; 01225 cDepth++; 01226 } else if (pwnd->spwndNext != NULL) { 01227 pwnd = pwnd->spwndNext; 01228 } else { 01229 if (cDepth > cDepthMax) { 01230 cDepthMax = cDepth; 01231 } 01232 01233 /* 01234 * Find a parent with siblings and recurse on them. Terminate 01235 * when we reach the parent of the original pwnd. 01236 */ 01237 do { 01238 pwnd = pwnd->spwndParent; 01239 cDepth--; 01240 01241 if (pwnd == pwndStop) 01242 goto Exit; 01243 01244 } while (pwnd->spwndNext == NULL); 01245 01246 pwnd = pwnd->spwndNext; 01247 } 01248 goto Restart; 01249 01250 Exit: 01251 return (cDepthMax <= NESTED_WINDOW_LIMIT); 01252 } 01253 01254 /***************************************************************************\ 01255 * ValidateOwnerDepth 01256 * 01257 * pwndOwner is the new intended owner, we basically add 1 to the current 01258 * nested owner chain depth. We assume that the actual window does not have 01259 * any ownees. In reality, it can through SetWindowLong, but finding the 01260 * maximum depth of the ownee chain is really tricky - just look in swp.c. 01261 * 01262 * 12-Mar-1997 vadimg created 01263 \***************************************************************************/ 01264 01265 BOOL ValidateOwnerDepth(PWND pwnd, PWND pwndOwner) 01266 { 01267 UINT cDepth = 1; 01268 01269 while (pwndOwner != NULL) { 01270 01271 /* 01272 * Do not allow loops in the owner chain. 01273 */ 01274 if (pwndOwner == pwnd) { 01275 return FALSE; 01276 } 01277 01278 pwndOwner = pwndOwner->spwndOwner; 01279 cDepth++; 01280 } 01281 01282 return (cDepth <= NESTED_WINDOW_LIMIT); 01283 }

Generated on Sat May 15 19:42:25 2004 for test by doxygen 1.3.7