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

swp.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: swp.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Contains the xxxSetWindowPos API and related functions. 00007 * 00008 * History: 00009 * 20-Oct-1990 DarrinM Created. 00010 * 25-Jan-1991 IanJa added window revalidation 00011 * 11-Jul-1991 DarrinM Replaced everything with re-ported Win 3.1 code. 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 #define CTM_NOCHANGE 0 00018 #define CTM_TOPMOST 1 00019 #define CTM_NOTOPMOST 2 00020 00021 void 00022 FixBogusSWP(PWND pwnd, int * px, int * py, int cx, int cy, UINT flags); 00023 void PreventInterMonitorBlts(PCVR pcvr); 00024 00025 /***************************************************************************\ 00026 * DBGCheskSMWP 00027 * 00028 * SMWP can be a HM object, a cached structure or just a pool allocation 00029 * 00030 * History: 00031 * 05/21/98 GerardoB Created. 00032 \***************************************************************************/ 00033 #if DBG 00034 void DBGCheskSMWP (PSMWP psmwp) 00035 { 00036 if (psmwp->bHandle) { 00037 UserAssert(psmwp->head.h != NULL); 00038 UserAssert(psmwp == HtoPqCat(PtoHq(psmwp))); 00039 UserAssert(psmwp != &gSMWP); 00040 } else { 00041 UserAssert((psmwp->head.h == NULL) && (psmwp->head.cLockObj == 0)); 00042 if (psmwp == &gSMWP) { 00043 UserAssert(TEST_PUDF(PUDF_GSMWPINUSE)); 00044 } 00045 } 00046 00047 UserAssert(psmwp->ccvr <= psmwp->ccvrAlloc); 00048 UserAssert(psmwp->acvr != NULL); 00049 00050 } 00051 #else 00052 #define DBGCheskSMWP(psmwp) 00053 #endif 00054 /***************************************************************************\ 00055 * DestroySMWP 00056 * 00057 * Destroys an SMWP object. 00058 * 00059 * History: 00060 * 24-Feb-1997 adams Created. 00061 \***************************************************************************/ 00062 00063 void 00064 DestroySMWP(PSMWP psmwp) 00065 { 00066 BOOL fFree; 00067 00068 CheckCritIn(); 00069 00070 DBGCheskSMWP(psmwp); 00071 /* 00072 * First mark the object for destruction. This tells the locking code 00073 * that we want to destroy this object when the lock count goes to 0. 00074 * If this returns FALSE, we can't destroy the object yet. 00075 */ 00076 if (psmwp->bHandle) { 00077 if (!HMMarkObjectDestroy(psmwp)) { 00078 return; 00079 } 00080 fFree = TRUE; 00081 } else { 00082 /* 00083 * Is this the global cached structure? 00084 */ 00085 fFree = (psmwp != &gSMWP); 00086 } 00087 00088 if (psmwp->acvr) { 00089 00090 /* 00091 * Free any hrgnInterMonitor stuff we accumulated. 00092 */ 00093 PCVR pcvr; 00094 int ccvr; 00095 00096 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 00097 if (pcvr->hrgnInterMonitor != NULL) { 00098 GreDeleteObject(pcvr->hrgnInterMonitor); 00099 } 00100 } 00101 00102 if (fFree) { 00103 UserFreePool(psmwp->acvr); 00104 } 00105 } 00106 00107 /* 00108 * Ok to destroy... Free the handle (which will free the object 00109 * and the handle). 00110 */ 00111 if (psmwp->bHandle) { 00112 HMFreeObject(psmwp); 00113 } else if (fFree) { 00114 UserFreePool(psmwp); 00115 } else { 00116 UserAssert(TEST_PUDF(PUDF_GSMWPINUSE)); 00117 CLEAR_PUDF(PUDF_GSMWPINUSE); 00118 /* 00119 * If acvr grew too much, shrink it. 00120 * Don't use realloc since we don't care about the left over data 00121 */ 00122 if (psmwp->ccvrAlloc > 8) { 00123 PCVR pcvr = UserAllocPool(4 * sizeof(CVR), TAG_SWP); 00124 if (pcvr != NULL) { 00125 UserFreePool(psmwp->acvr); 00126 psmwp->acvr = pcvr; 00127 psmwp->ccvrAlloc = 4; 00128 } 00129 } 00130 } 00131 } 00132 00133 /***************************************************************************\ 00134 * MoveWindow (API) 00135 * 00136 * 00137 * History: 00138 * 25-Jul-1991 DarrinM Ported from Win 3.1 sources. 00139 \***************************************************************************/ 00140 00141 #define MW_FLAGS_REDRAW (SWP_NOZORDER | SWP_NOACTIVATE) 00142 #define MW_FLAGS_NOREDRAW (SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW) 00143 00144 BOOL xxxMoveWindow( 00145 PWND pwnd, 00146 int x, 00147 int y, 00148 int cx, 00149 int cy, 00150 BOOL fRedraw) 00151 { 00152 CheckLock(pwnd); 00153 00154 if ((pwnd == PWNDDESKTOP(pwnd)) || 00155 TestWF(pwnd, WFWIN31COMPAT) || 00156 (pwnd->spwndParent != PWNDDESKTOP(pwnd))) { 00157 00158 return xxxSetWindowPos( 00159 pwnd, 00160 NULL, 00161 x, 00162 y, 00163 cx, 00164 cy, 00165 (fRedraw ? MW_FLAGS_REDRAW : MW_FLAGS_NOREDRAW)); 00166 } else { 00167 00168 /* 00169 * BACKWARD COMPATIBILITY CODE FOR WIN 3.00 AND BELOW 00170 * 00171 * Everyone and their brother seems to depend on this behavior for 00172 * top-level windows. Specific examples are: 00173 * 00174 * AfterDark help window animation 00175 * Finale Speedy Note Editing 00176 * 00177 * If the window is a top-level window and fRedraw is FALSE, 00178 * we must call SetWindowPos with SWP_NOREDRAW CLEAR anyway so that 00179 * the frame and window background get drawn. We then validate the 00180 * entire client rectangle to avoid repainting that. 00181 */ 00182 BOOL fResult = xxxSetWindowPos(pwnd, 00183 NULL, 00184 x, 00185 y, 00186 cx, 00187 cy, 00188 MW_FLAGS_REDRAW); 00189 00190 if (!fRedraw) 00191 xxxValidateRect(pwnd, NULL); 00192 00193 return fResult; 00194 } 00195 } 00196 00197 /***************************************************************************\ 00198 * AllocateCvr 00199 * 00200 * History: 00201 * 05/20/98 GerardoB Extracted from old _BeginDeferWindowPos 00202 \***************************************************************************/ 00203 BOOL AllocateCvr (PSMWP psmwp, int cwndHint) 00204 { 00205 PCVR acvr; 00206 00207 UserAssert(cwndHint != 0); 00208 acvr = (PCVR)UserAllocPoolWithQuota(sizeof(CVR) * cwndHint, TAG_SWP); 00209 00210 if (acvr == NULL) { 00211 return FALSE; 00212 } 00213 00214 /* 00215 * Initialize psmwp related fields. 00216 * CVR array is initialized by _DeferWindowPos 00217 */ 00218 00219 psmwp->acvr = acvr; 00220 psmwp->ccvrAlloc = cwndHint; 00221 psmwp->ccvr = 0; 00222 return TRUE; 00223 } 00224 /***************************************************************************\ 00225 * InternalBeginDeferWindowPos 00226 * 00227 * History: 00228 * 05/20/98 GerardoB Created 00229 \***************************************************************************/ 00230 00231 PSMWP InternalBeginDeferWindowPos(int cwndHint) 00232 { 00233 PSMWP psmwp; 00234 00235 CheckCritIn(); 00236 00237 /* 00238 * If gSMWP in being used, allocate one. 00239 * Note that SMWP is zero init but CVR is not; _DeferWindowPos initializes it 00240 */ 00241 if (TEST_PUDF(PUDF_GSMWPINUSE) || (cwndHint > gSMWP.ccvrAlloc)) { 00242 psmwp = (PSMWP)UserAllocPoolWithQuotaZInit(sizeof(SMWP), TAG_SWP); 00243 if (psmwp == NULL) { 00244 return NULL; 00245 } 00246 if (!AllocateCvr(psmwp, cwndHint)) { 00247 UserFreePool(psmwp); 00248 return NULL; 00249 } 00250 } else { 00251 SET_PUDF(PUDF_GSMWPINUSE); 00252 psmwp = &gSMWP; 00253 RtlZeroMemory(&gSMWP, FIELD_OFFSET(SMWP, ccvrAlloc)); 00254 UserAssert(gSMWP.ccvr == 0); 00255 UserAssert(gSMWP.acvr != NULL); 00256 } 00257 00258 DBGCheskSMWP(psmwp); 00259 return psmwp; 00260 } 00261 /***************************************************************************\ 00262 * BeginDeferWindowPos (API) 00263 * 00264 * This must be called from the client side only. Internally we should 00265 * call InternalBeginDeferWindowPos to avoid going through the handle table 00266 * and perhaps even use the cached strucuture. 00267 * 00268 * History: 00269 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 00270 \***************************************************************************/ 00271 00272 PSMWP _BeginDeferWindowPos(int cwndHint) 00273 { 00274 PSMWP psmwp; 00275 00276 psmwp = (PSMWP)HMAllocObject(PtiCurrent(), NULL, TYPE_SETWINDOWPOS, sizeof(SMWP)); 00277 if (psmwp == NULL) { 00278 return NULL; 00279 } 00280 00281 if (cwndHint == 0) { 00282 cwndHint = 8; 00283 } 00284 00285 if (!AllocateCvr(psmwp, cwndHint)) { 00286 HMFreeObject(psmwp); 00287 return NULL; 00288 } 00289 00290 psmwp->bHandle = TRUE; 00291 DBGCheskSMWP(psmwp); 00292 return psmwp; 00293 } 00294 00295 /***************************************************************************\ 00296 * PWInsertAfter 00297 * HWInsertAfter 00298 * History: 00299 * 04-Mar-1992 MikeKe From win31 00300 \***************************************************************************/ 00301 PWND PWInsertAfter( 00302 HWND hwnd) 00303 { 00304 PWND pwnd; 00305 00306 /* 00307 * HWND_GROUPTOTOP and HWND_TOPMOST are the same thing. 00308 */ 00309 switch ((ULONG_PTR)hwnd) { 00310 case (ULONG_PTR)HWND_TOP: 00311 case (ULONG_PTR)HWND_BOTTOM: 00312 case (ULONG_PTR)HWND_TOPMOST: 00313 case (ULONG_PTR)HWND_NOTOPMOST: 00314 return (PWND)hwnd; 00315 00316 default: 00317 00318 /* 00319 * Don't insert after a destroyed window! It will cause the 00320 * window being z-ordered to become unlinked from it's siblings. 00321 */ 00322 if (pwnd = RevalidateHwnd(hwnd)) { 00323 00324 /* 00325 * Do not insert after a destroyed window. Put it at the 00326 * bottom of the list, if it is z-ordered at all. 00327 */ 00328 if (TestWF(pwnd, WFDESTROYED) || pwnd->spwndParent == NULL) 00329 return NULL; 00330 00331 UserAssert(_IsDescendant(pwnd->spwndParent, pwnd)); 00332 return pwnd; 00333 } 00334 00335 return NULL; 00336 } 00337 } 00338 00339 HWND HWInsertAfter( 00340 PWND pwnd) 00341 { 00342 /* 00343 * HWND_GROUPTOTOP and HWND_TOPMOST are the same thing. 00344 */ 00345 switch ((ULONG_PTR)pwnd) { 00346 case (ULONG_PTR)HWND_TOP: 00347 case (ULONG_PTR)HWND_BOTTOM: 00348 case (ULONG_PTR)HWND_TOPMOST: 00349 case (ULONG_PTR)HWND_NOTOPMOST: 00350 return (HWND)pwnd; 00351 00352 default: 00353 return HW(pwnd); 00354 } 00355 } 00356 00357 /***************************************************************************\ 00358 * DeferWindowPos (API) 00359 * 00360 * 00361 * History: 00362 * 07-11-91 darrinm Ported from Win 3.1 sources. 00363 \***************************************************************************/ 00364 00365 PSMWP _DeferWindowPos( 00366 PSMWP psmwp, 00367 PWND pwnd, 00368 PWND pwndInsertAfter, 00369 int x, 00370 int y, 00371 int cx, 00372 int cy, 00373 UINT flags) 00374 { 00375 PWINDOWPOS ppos; 00376 PCVR pcvr; 00377 00378 DBGCheskSMWP(psmwp); 00379 if (psmwp->ccvr + 1 > psmwp->ccvrAlloc) { 00380 00381 /* 00382 * Make space for 4 more windows 00383 */ 00384 DWORD dwNewAlloc = psmwp->ccvrAlloc + 4; 00385 00386 pcvr = (PCVR)UserReAllocPoolWithQuota(psmwp->acvr, 00387 psmwp->ccvrAlloc * sizeof(CVR), 00388 sizeof(CVR) * dwNewAlloc, 00389 TAG_SWP); 00390 00391 if (pcvr == NULL) { 00392 DestroySMWP(psmwp); 00393 return NULL; 00394 } 00395 00396 psmwp->acvr = pcvr; 00397 psmwp->ccvrAlloc = dwNewAlloc; 00398 } 00399 00400 pcvr = &psmwp->acvr[psmwp->ccvr++]; 00401 ppos = &pcvr->pos; 00402 00403 ppos->hwnd = HWq(pwnd); 00404 ppos->hwndInsertAfter = (TestWF(pwnd, WFBOTTOMMOST)) ? 00405 HWND_BOTTOM : HWInsertAfter(pwndInsertAfter); 00406 ppos->x = x; 00407 ppos->y = y; 00408 ppos->cx = cx; 00409 ppos->cy = cy; 00410 ppos->flags = flags; 00411 00412 pcvr->hrgnClip = NULL; 00413 pcvr->hrgnInterMonitor = NULL; 00414 00415 return psmwp; 00416 } 00417 /***************************************************************************\ 00418 * ValidateWindowPos 00419 * 00420 * checks validity of SWP structure 00421 * 00422 * NOTE: For performance reasons, this routine is only called 00423 * in the DEBUG version of USER. 00424 * 00425 * History: 00426 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 00427 \***************************************************************************/ 00428 00429 BOOL ValidateWindowPos(PCVR pcvr, PWND pwndParent) 00430 { 00431 PWND pwnd; 00432 PWND pwndInsertAfter; 00433 HWND hwndInsertAfter; 00434 00435 if ((pwnd = RevalidateHwnd(pcvr->pos.hwnd)) == NULL) 00436 return FALSE; 00437 00438 /* 00439 * Save the pti 00440 */ 00441 pcvr->pti = GETPTI(pwnd); 00442 00443 00444 /* 00445 * If the SWP_NOZORDER bit is not set, validate the Insert behind window. 00446 */ 00447 if (!(pcvr->pos.flags & SWP_NOZORDER)) { 00448 BOOL fTopLevel = (pwnd->spwndParent == PWNDDESKTOP(pwnd)); 00449 /* 00450 * Do not z-order destroyed windows 00451 */ 00452 if (TestWF(pwnd, WFDESTROYED)) 00453 return FALSE; 00454 00455 hwndInsertAfter = pcvr->pos.hwndInsertAfter; 00456 /* 00457 * If pwndParent is provided, we're about to link this window so we 00458 * need to validate LinkWindow assumptions. 00459 * We have to do this since we callback after determining hwndInsertAfter. 00460 */ 00461 00462 if ((hwndInsertAfter == HWND_TOPMOST) || 00463 (hwndInsertAfter == HWND_NOTOPMOST)) { 00464 00465 if (!fTopLevel) { 00466 return FALSE; 00467 } 00468 } else if (hwndInsertAfter == HWND_TOP) { 00469 /* 00470 * if pwnd is not topmost, the first child must not be topmost. 00471 */ 00472 if ((pwndParent != NULL) && fTopLevel 00473 && !FSwpTopmost(pwnd) 00474 && (pwndParent->spwndChild != NULL) 00475 && FSwpTopmost(pwndParent->spwndChild)) { 00476 00477 RIPMSG2(RIP_WARNING, "ValidateWindowPos: pwnd is not SWPTopMost." 00478 " pwnd:%#p. hwndInsertAfter:%#p", 00479 pwnd, hwndInsertAfter); 00480 return FALSE; 00481 } 00482 } else if (hwndInsertAfter != HWND_BOTTOM) { 00483 00484 /* 00485 * Ensure pwndInsertAfter is valid 00486 */ 00487 if (((pwndInsertAfter = RevalidateHwnd(hwndInsertAfter)) == NULL) || 00488 TestWF(pwndInsertAfter, WFDESTROYED)) { 00489 00490 RIPERR1(ERROR_INVALID_HANDLE, RIP_WARNING, "Invalid hwndInsertAfter (%#p)", hwndInsertAfter); 00491 00492 return FALSE; 00493 } 00494 00495 /* 00496 * Ensure that pwndInsertAfter is a sibling of pwnd 00497 */ 00498 if (pwnd == pwndInsertAfter || 00499 pwnd->spwndParent != pwndInsertAfter->spwndParent) { 00500 RIPMSG2(RIP_WARNING, "hwndInsertAfter (%#p) is not a sibling " 00501 "of hwnd (%#p)", hwndInsertAfter, pcvr->pos.hwnd); 00502 return FALSE; 00503 } 00504 /* 00505 * Ensure proper topmost/nontopmost insert position 00506 */ 00507 if ((pwndParent != NULL) && fTopLevel) { 00508 if (FSwpTopmost(pwnd)) { 00509 /* 00510 * Check if we're trying to insert a topmost window after a non-topmost one. 00511 */ 00512 if (!FSwpTopmost(pwndInsertAfter)) { 00513 RIPMSG2(RIP_WARNING, "ValidateWindowPos: pwndInsertAfter is not SWPTopMost." 00514 " pwnd:%#p. pwndInsertAfter:%#p", 00515 pwnd, pwndInsertAfter); 00516 return FALSE; 00517 } 00518 } else { 00519 /* 00520 * Check if we're trying to insert a non-top most window between two 00521 * top-most ones. 00522 */ 00523 if ((pwndInsertAfter->spwndNext != NULL) 00524 && FSwpTopmost(pwndInsertAfter->spwndNext)) { 00525 00526 RIPMSG2(RIP_WARNING, "ValidateWindowPos: pwndInsertAfter->spwndNext is SWPTopMost." 00527 " pwnd:%#p. pwndInsertAfter:%#p", 00528 pwnd, pwndInsertAfter); 00529 return FALSE; 00530 } 00531 } 00532 00533 } 00534 00535 } /* if (hwndInsertAfter != HWND_TOP && hwndInsertAfter != HWND_BOTTOM) */ 00536 00537 /* 00538 * Check that the parent hasn't changed. 00539 */ 00540 if (pwndParent != NULL) { 00541 if (pwndParent != pwnd->spwndParent) { 00542 RIPMSG3(RIP_WARNING, "ValidateWindowPos: parent has changed." 00543 " pwnd:%#p. Old Parent:%#p. Current Parent:%#p", 00544 pwnd, pwndParent, pwnd->spwndParent); 00545 return FALSE; 00546 } 00547 } 00548 00549 } /* if (!(pcvr->pos.flags & SWP_NOZORDER)) */ 00550 00551 return TRUE; 00552 } 00553 00554 /***************************************************************************\ 00555 * IsStillWindowC 00556 * 00557 * Checks if window is valid HWNDC still, and child of proper dude. 00558 * 00559 * History: 00560 \***************************************************************************/ 00561 00562 BOOL IsStillWindowC( 00563 HWND hwndc) 00564 { 00565 switch ((ULONG_PTR)hwndc) { 00566 case (ULONG_PTR)HWND_TOP: 00567 case (ULONG_PTR)HWND_BOTTOM: 00568 case (ULONG_PTR)HWND_TOPMOST: 00569 case (ULONG_PTR)HWND_NOTOPMOST: 00570 return TRUE; 00571 00572 default: 00573 /* 00574 * Make sure we're going to insert after a window that's 00575 * (1) Valid 00576 * (2) Peer 00577 */ 00578 return (RevalidateHwnd(hwndc) != 0); 00579 } 00580 } 00581 00582 /***************************************************************************\ 00583 * ValidateSmwp 00584 * 00585 * Validate the SMWP and figure out which window should get activated, 00586 * 00587 * History: 00588 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 00589 \***************************************************************************/ 00590 00591 BOOL ValidateSmwp( 00592 PSMWP psmwp, 00593 BOOL *pfSyncPaint) 00594 { 00595 PCVR pcvr; 00596 PWND pwndParent; 00597 PWND pwndT; 00598 int ccvr; 00599 00600 *pfSyncPaint = TRUE; 00601 00602 pwndT = RevalidateHwnd(psmwp->acvr[0].pos.hwnd); 00603 00604 if (pwndT == NULL) 00605 return FALSE; 00606 00607 pwndParent = pwndT->spwndParent; 00608 00609 /* 00610 * Validate the passed-in WINDOWPOS structs, and find a window to activate. 00611 */ 00612 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 00613 00614 if (!ValidateWindowPos(pcvr, NULL)) { 00615 pcvr->pos.hwnd = NULL; 00616 continue; 00617 } 00618 00619 /* 00620 * All windows in the pos list must have the same parent. 00621 * If not, yell and return FALSE. 00622 */ 00623 UserAssert(IsStillWindowC(pcvr->pos.hwnd)); 00624 00625 UserAssert(PW(pcvr->pos.hwnd)); 00626 if (PW(pcvr->pos.hwnd)->spwndParent != pwndParent) { 00627 RIPERR0(ERROR_HWNDS_HAVE_DIFF_PARENT, RIP_VERBOSE, ""); 00628 return FALSE; 00629 } 00630 00631 /* 00632 * If SWP_DEFERDRAWING is set for any of the windows, suppress 00633 * DoSyncPaint() call later. 00634 */ 00635 if (pcvr->pos.flags & SWP_DEFERDRAWING) 00636 *pfSyncPaint = FALSE; 00637 } 00638 00639 return TRUE; 00640 } 00641 00642 /***************************************************************************\ 00643 * FindValidWindowPos 00644 * 00645 * Some of the windows in the SMWP list may be NULL at ths point (removed 00646 * because they'll be handled by their creator's thread) so we've got to 00647 * look for the first non-NULL window and return it. 00648 * 00649 * History: 00650 * 10-Sep-1991 DarrinM Created. 00651 \***************************************************************************/ 00652 00653 PWINDOWPOS FindValidWindowPos( 00654 PSMWP psmwp) 00655 { 00656 int i; 00657 00658 for (i = 0; i < psmwp->ccvr; i++) { 00659 00660 if (psmwp->acvr[i].pos.hwnd != NULL) 00661 return &psmwp->acvr[i].pos; 00662 } 00663 00664 return NULL; 00665 } 00666 00667 /***************************************************************************\ 00668 * 00669 * GetLastNonBottomMostWindow() 00670 * 00671 * Returns the last non bottom-most window in the z-order, NULL if 00672 * there isn't one. When figuring out whom to insert after, we want to 00673 * skip ourself. But when figuring out if we're already in place, we don't 00674 * want to skip ourself on enum. 00675 * 00676 * History: 00677 \***************************************************************************/ 00678 00679 PWND GetLastNonBottomMostWindow( 00680 PWND pwnd, 00681 BOOL fSkipSelf) 00682 { 00683 PWND pwndT; 00684 PWND pwndLast = NULL; 00685 00686 for (pwndT = pwnd->spwndParent->spwndChild; 00687 pwndT && !TestWF(pwndT, WFBOTTOMMOST); 00688 pwndT = pwndT->spwndNext) { 00689 00690 if (!fSkipSelf || (pwnd != pwndT)) 00691 pwndLast = pwndT; 00692 } 00693 00694 return pwndLast; 00695 } 00696 00697 /***************************************************************************\ 00698 * ValidateZorder 00699 * 00700 * Checks to see if the specified window is already in the specified Z order 00701 * position, by comparing the current Z position with the specified 00702 * pwndInsertAfter. 00703 * 00704 * History: 00705 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 00706 \***************************************************************************/ 00707 00708 BOOL ValidateZorder( 00709 PCVR pcvr) 00710 { 00711 PWND pwnd; 00712 PWND pwndPrev; 00713 PWND pwndInsertAfter; 00714 BYTE bTopmost; 00715 00716 /* 00717 * Validate just to make sure this routine doesn't do anything bogus. 00718 * Its caller will actually redetect and handle the error. 00719 */ 00720 UserAssert(RevalidateCatHwnd(pcvr->pos.hwnd)); 00721 pwnd = PWCat(pcvr->pos.hwnd); // Known to be valid at this point. 00722 00723 /* 00724 * Don't z-order a destroyed window 00725 */ 00726 if (TestWF(pwnd, WFDESTROYED)) 00727 return TRUE; 00728 00729 UserAssert((HMPheFromObject(pwnd)->bFlags & HANDLEF_DESTROY) == 0); 00730 00731 pwndInsertAfter = PWInsertAfter(pcvr->pos.hwndInsertAfter); 00732 if (pcvr->pos.hwndInsertAfter != NULL && pwndInsertAfter == NULL) 00733 return TRUE; 00734 00735 if (pwndInsertAfter == PWND_BOTTOM) { 00736 00737 if (TestWF(pwnd, WFBOTTOMMOST)) 00738 return(pwnd->spwndNext == NULL); 00739 else 00740 return(pwnd == GetLastNonBottomMostWindow(pwnd, FALSE)); 00741 } 00742 00743 pwndPrev = pwnd->spwndParent->spwndChild; 00744 if (pwndInsertAfter == PWND_TOP) 00745 return pwndPrev == pwnd; 00746 00747 if (TestWF(pwndInsertAfter, WFDESTROYED)) 00748 return TRUE; 00749 00750 /* 00751 * When we compare the state of the window, we must use 00752 * the EVENTUAL state of the window that is moving, but 00753 * the CURRENT state of the window it's inserted behind. 00754 * 00755 * Prevent nonbottommost windows from going behind the bottommost one 00756 */ 00757 if (TestWF(pwndInsertAfter, WFBOTTOMMOST)) { 00758 pcvr->pos.hwndInsertAfter = HWInsertAfter(GetLastNonBottomMostWindow(pwnd, TRUE)); 00759 return FALSE; 00760 } 00761 00762 /* 00763 * If we are not topmost, but pwndInsertAfter is, OR 00764 * if we are topmost, but pwndInsertAfter is not, 00765 * we need to adjust pwndInsertAfter to be the last of 00766 * the topmost windows. 00767 */ 00768 bTopmost = TestWF(pwnd, WEFTOPMOST); 00769 00770 if (TestWF(pwnd, WFTOGGLETOPMOST)) 00771 bTopmost ^= LOBYTE(WEFTOPMOST); 00772 00773 if (bTopmost != (BYTE)TestWF(pwndInsertAfter, WEFTOPMOST)) { 00774 00775 pwndInsertAfter = GetLastTopMostWindow(); 00776 00777 /* 00778 * We're correctly positioned if we're already at the bottom 00779 */ 00780 if (pwndInsertAfter == pwnd) 00781 return TRUE; 00782 00783 pcvr->pos.hwndInsertAfter = HW(pwndInsertAfter); 00784 } 00785 00786 /* 00787 * Look for our previous window in the list... 00788 */ 00789 if (pwndPrev != pwnd) { 00790 00791 for ( ; pwndPrev != NULL; pwndPrev = pwndPrev->spwndNext) { 00792 00793 if (pwndPrev->spwndNext == pwnd) 00794 return pwndInsertAfter == pwndPrev; 00795 } 00796 00797 /* 00798 * If we get to here, pwnd is not in the sibling list. 00799 * REALLY BAD NEWS! 00800 */ 00801 UserAssert(FALSE); 00802 return TRUE; 00803 } 00804 00805 return FALSE; 00806 } 00807 00808 /***************************************************************************\ 00809 * xxxCalcValidRects 00810 * 00811 * Based on the WINDOWPOS flags in the fs parameter in each WINDOWPOS structure, 00812 * this routine calcs the new position and size of each window, determines if 00813 * its changing Z order, or whether its showing or hiding. Any redundant 00814 * flags are AND'ed out of the fs parameter. If no redrawing is needed, 00815 * SWP_NOREDRAW is OR'ed into the flags. This is called from EndDeferWindowPos. 00816 * 00817 * History: 00818 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 00819 \***************************************************************************/ 00820 00821 BOOL xxxCalcValidRects( 00822 PSMWP psmwp, 00823 HWND *phwndNewActive) 00824 { 00825 PCVR pcvr; 00826 PWND pwnd; 00827 PWND pwndParent; 00828 HWND hwnd; 00829 HWND hwndNewActive = NULL; 00830 PWINDOWPOS ppos; 00831 BOOL fNoZorder; 00832 BOOL fForceNCCalcSize; 00833 NCCALCSIZE_PARAMS params; 00834 int cxSrc; 00835 int cySrc; 00836 int cxDst; 00837 int cyDst; 00838 int cmd; 00839 int ccvr; 00840 int xClientOld; 00841 int yClientOld; 00842 int cxClientOld; 00843 int cyClientOld; 00844 int xWindowOld; 00845 int yWindowOld; 00846 int cxWindowOld; 00847 int cyWindowOld; 00848 TL tlpwndParent; 00849 TL tlpwnd; 00850 00851 /* 00852 * Some of the windows in the SMWP list may be NULL at ths point 00853 * (removed because they'll be handled by their creator's thread) 00854 * so we've got to look for the first non-NULL window before we can 00855 * execute some of the tests below. FindValidWindowPos returns NULL if 00856 * the list has no valid windows in it. 00857 */ 00858 if ((ppos = FindValidWindowPos(psmwp)) == NULL) 00859 return FALSE; 00860 00861 UserAssert(PW(ppos->hwnd)); 00862 pwndParent = PW(ppos->hwnd)->spwndParent; 00863 00864 UserAssert(HMRevalidateCatHandle(PtoH(pwndParent))); 00865 00866 ThreadLock(pwndParent, &tlpwndParent); 00867 00868 fNoZorder = TRUE; 00869 00870 /* 00871 * Go through the SMWP list, enumerating each WINDOWPOS, and compute 00872 * its new window and client rectangles. 00873 */ 00874 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 00875 00876 /* 00877 * This loop may leave the critsect during each iteration so 00878 * we revalidate pos.hwnd before use. 00879 */ 00880 if ((hwnd = pcvr->pos.hwnd) == NULL) 00881 continue; 00882 00883 pwnd = RevalidateHwnd(hwnd); 00884 00885 if ((pwnd == NULL) || !IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 00886 pcvr->pos.hwnd = NULL; 00887 pcvr->pos.flags = SWP_NOREDRAW | SWP_NOCHANGE; 00888 continue; 00889 } 00890 00891 ThreadLockAlways(pwnd, &tlpwnd); 00892 00893 /* 00894 * Used for 3.0 compatibility. 3.0 sent the NCCALCSIZE message even if 00895 * the size of the window wasn't changing. 00896 */ 00897 fForceNCCalcSize = FALSE; 00898 00899 if (!hwndNewActive && !(pcvr->pos.flags & SWP_NOACTIVATE)) 00900 hwndNewActive = HWq(pwnd); 00901 00902 if (!(pcvr->pos.flags & SWP_NOSENDCHANGING)) { 00903 00904 PWND pwndT; 00905 00906 xxxSendMessage(pwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)&pcvr->pos); 00907 00908 00909 /* 00910 * Don't let them change pcvr->pos.hwnd. It doesn't make sense 00911 * plus it'll mess us up. 00912 * I'm making this RIP_ERROR because we're too close to RTM (7/11/96) 00913 * just to make sure that we won't break anyone. This should be 00914 * changed to a RIP_WARNING after we ship. Use LOWORD to ignore 00915 * "changes" by NTVDM 00916 */ 00917 #if DBG 00918 if (LOWORD(pcvr->pos.hwnd) != LOWORD(hwnd)) { 00919 RIPMSG0(RIP_ERROR, 00920 "xxxCalcValidRects: Ignoring pcvr->pos.hwnd change by WM_WINDOWPOSCHANGING"); 00921 } 00922 #endif 00923 pcvr->pos.hwnd = hwnd; 00924 00925 /* 00926 * If the window sets again 'hwndInsertAfter' to HWND_NOTOPMOST 00927 * or HWND_TOPMOST, we need to set this member appropriately. 00928 * See CheckTopmost for details. 00929 */ 00930 if (pcvr->pos.hwndInsertAfter == HWND_NOTOPMOST) { 00931 if (TestWF(pwnd, WEFTOPMOST)) { 00932 00933 pwndT = GetLastTopMostWindow(); 00934 pcvr->pos.hwndInsertAfter = HW(pwndT); 00935 00936 if (pcvr->pos.hwndInsertAfter == pcvr->pos.hwnd) { 00937 pwndT = _GetWindow(pwnd, GW_HWNDPREV); 00938 pcvr->pos.hwndInsertAfter = HW(pwndT); 00939 } 00940 } else { 00941 pwndT = _GetWindow(pwnd, GW_HWNDPREV); 00942 pcvr->pos.hwndInsertAfter = HW(pwndT); 00943 } 00944 } else if (pcvr->pos.hwndInsertAfter == HWND_TOPMOST) { 00945 pcvr->pos.hwndInsertAfter = HWND_TOP; 00946 } 00947 } 00948 /* 00949 * make sure the rectangle still matches the window's region 00950 * 00951 * Remember the old window rectangle in parent coordinates 00952 */ 00953 xWindowOld = pwnd->rcWindow.left; 00954 yWindowOld = pwnd->rcWindow.top; 00955 if (pwndParent != PWNDDESKTOP(pwnd)) { 00956 xWindowOld -= pwndParent->rcClient.left; 00957 yWindowOld -= pwndParent->rcClient.top; 00958 } 00959 00960 00961 cxWindowOld = pwnd->rcWindow.right - pwnd->rcWindow.left; 00962 cyWindowOld = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 00963 00964 /* 00965 * Assume the client is not moving or sizing 00966 */ 00967 pcvr->pos.flags |= SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE; 00968 00969 if (!(pcvr->pos.flags & SWP_NOMOVE)) { 00970 00971 if (pcvr->pos.x == xWindowOld && pcvr->pos.y == yWindowOld) 00972 pcvr->pos.flags |= SWP_NOMOVE; 00973 00974 00975 #ifdef USE_MIRRORING 00976 /* 00977 * Since we are comparing client coordinates to see whether 00978 * to move the window or not : 00979 * We've to check if the parent of the window-to-be-positioned is RTL 00980 * mirrored, then let's measure the client old x-coordinate from 00981 * the right visual edge. This is because the position of a window 00982 * is mirrored in the parent client area if the parent is RTL mirrored. 00983 */ 00984 if (TestWF(pwndParent, WEFLAYOUTRTL) && TestwndChild(pwnd) && 00985 (pwndParent->rcClient.right - pwnd->rcWindow.right + 1) != pcvr->pos.x) 00986 pcvr->pos.flags &= ~SWP_NOMOVE; 00987 #endif 00988 00989 if (TestWF(pwnd, WFMINIMIZED) && IsTrayWindow(pwnd)) { 00990 pcvr->pos.x = WHERE_NOONE_CAN_SEE_ME; 00991 pcvr->pos.y = WHERE_NOONE_CAN_SEE_ME; 00992 } 00993 00994 } else { 00995 pcvr->pos.x = xWindowOld; 00996 pcvr->pos.y = yWindowOld; 00997 } 00998 00999 if (!(pcvr->pos.flags & SWP_NOSIZE)) { 01000 01001 /* 01002 * Don't allow an invalid window rectangle. 01003 * BOGUS HACK: For Norton Antivirus, they call 01004 * MoveWindow at WM_CREATE Time EVEN though 01005 * the window is minimzed, but they assume its 01006 * restored at WM_CREATE time.... B#11185, t-arthb 01007 */ 01008 if (TestWF(pwnd, WFMINIMIZED) && 01009 _GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL)) { 01010 01011 pcvr->pos.cx = SYSMET(CXMINIMIZED); 01012 pcvr->pos.cy = SYSMET(CYMINIMIZED); 01013 01014 } else { 01015 if (pcvr->pos.cx < 0) 01016 pcvr->pos.cx = 0; 01017 01018 if (pcvr->pos.cy < 0) 01019 pcvr->pos.cy = 0; 01020 } 01021 01022 if (pcvr->pos.cx == cxWindowOld && pcvr->pos.cy == cyWindowOld) { 01023 pcvr->pos.flags |= SWP_NOSIZE; 01024 if (!TestWF(pwnd, WFWIN31COMPAT)) 01025 fForceNCCalcSize = TRUE; 01026 } 01027 } else { 01028 pcvr->pos.cx = cxWindowOld; 01029 pcvr->pos.cy = cyWindowOld; 01030 } 01031 01032 #ifdef USE_MIRRORING 01033 if (TestWF(pwndParent, WEFLAYOUTRTL) && TestwndChild(pwnd) && (pwndParent != PWNDDESKTOP(pwnd))) { 01034 if (!(pcvr->pos.flags & SWP_NOMOVE)) { 01035 pcvr->pos.x = (pwndParent->rcClient.right - pwndParent->rcClient.left) - (pcvr->pos.x + pcvr->pos.cx); 01036 } else { 01037 if (!(pcvr->pos.flags & SWP_NOSIZE)) { 01038 pcvr->pos.x -= (pcvr->pos.cx - cxWindowOld); 01039 } 01040 } 01041 } 01042 #endif 01043 01044 /* 01045 * If showing and already visible, or hiding and already hidden, 01046 * turn off the appropriate bit. 01047 */ 01048 if (TestWF(pwnd, WFVISIBLE)) { 01049 pcvr->pos.flags &= ~SWP_SHOWWINDOW; 01050 } else { 01051 pcvr->pos.flags &= ~SWP_HIDEWINDOW; 01052 01053 /* 01054 * If hidden, and we're NOT showing, then we won't be drawing, 01055 * no matter what else is going on. 01056 */ 01057 if (!(pcvr->pos.flags & SWP_SHOWWINDOW)) 01058 pcvr->pos.flags |= SWP_NOREDRAW; 01059 } 01060 01061 /* 01062 * Muck with the zorder for bottommost windows, again 01063 * See comment in DeferWindowPos 01064 */ 01065 if (TestWF(pwnd, WFBOTTOMMOST)) { 01066 pcvr->pos.flags &= ~SWP_NOZORDER; 01067 pcvr->pos.hwndInsertAfter = HWND_BOTTOM; 01068 } 01069 01070 /* 01071 * If we're Z-ordering, we can try to remove the Z order 01072 * bit, as long as all previous windows in the WINDOWPOS list 01073 * have SWP_NOZORDER set. 01074 * 01075 * The reason we don't do this for each window individually 01076 * is that a window's eventual Z order depends on changes that 01077 * may have occured on windows earlier in the WINDOWPOS list, 01078 * so we can only call ValidateZorder if none of the previous 01079 * windows have changed. 01080 */ 01081 if (fNoZorder && !(pcvr->pos.flags & SWP_NOZORDER)) { 01082 01083 /* 01084 * If the TOPMOST bit is changing, the Z order is "changing", 01085 * so don't clear the bit even if it's in the right place in the 01086 * list. 01087 */ 01088 fNoZorder = FALSE; 01089 if (!TestWF(pwnd, WFTOGGLETOPMOST) && ValidateZorder(pcvr)) { 01090 fNoZorder = TRUE; 01091 pcvr->pos.flags |= SWP_NOZORDER; 01092 } 01093 } 01094 01095 /* 01096 * If no change is occuring, or if a parent is invisible, 01097 * we won't be redrawing. 01098 */ 01099 if (!(pcvr->pos.flags & SWP_NOREDRAW)) { 01100 if ((pcvr->pos.flags & SWP_CHANGEMASK) == SWP_NOCHANGE || 01101 !_FChildVisible(pwnd)) { 01102 pcvr->pos.flags |= SWP_NOREDRAW; 01103 } 01104 } 01105 01106 /* 01107 * BACKWARD COMPATIBILITY HACK 01108 * 01109 * In 3.0, if a window was moving but not sizing, we'd send the 01110 * WM_NCCALCSIZE message anyhow. Lotus Notes 2.1 depends on this 01111 * in order to move its "navigation bar" when the main window moves. 01112 */ 01113 if (!(pcvr->pos.flags & SWP_NOMOVE) && 01114 !TestWF(pwnd, WFWIN31COMPAT) && 01115 (GetAppCompatFlags(NULL) & GACF_NCCALCSIZEONMOVE)) { 01116 01117 fForceNCCalcSize = TRUE; 01118 } 01119 01120 /* 01121 * If the window rect is sizing, or if the frame has changed, 01122 * send the WM_NCCALCSIZE message and deal with valid areas. 01123 */ 01124 if (((pcvr->pos.flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) != SWP_NOSIZE) || 01125 fForceNCCalcSize) { 01126 01127 WINDOWPOS pos; 01128 01129 /* 01130 * check for full screen main app window 01131 */ 01132 if (!TestWF(pwnd, WFCHILD) && !TestWF(pwnd, WEFTOOLWINDOW)) { 01133 xxxCheckFullScreen(pwnd, (PSIZERECT)&pcvr->pos.x); 01134 } 01135 01136 /* 01137 * Set up NCCALCSIZE message parameters (in parent coords) 01138 * wParam = fClientOnly = TRUE 01139 * lParam = &params 01140 */ 01141 pos = pcvr->pos; // Make a local stack copy 01142 params.lppos = &pos; 01143 01144 /* 01145 * params.rgrc[0] = rcWindowNew = New window rectangle 01146 * params.rgrc[1] = rcWindowOld = Old window rectangle 01147 * params.rgrc[2] = rcClientOld = Old client rectangle 01148 */ 01149 #define rcWindowNew params.rgrc[0] 01150 #define rcWindowOld params.rgrc[1] 01151 #define rcClientOld params.rgrc[2] 01152 01153 /* 01154 * Set up rcWindowNew in parent relative coordinates 01155 */ 01156 rcWindowNew.left = pcvr->pos.x; 01157 rcWindowNew.right = rcWindowNew.left + pcvr->pos.cx; 01158 rcWindowNew.top = pcvr->pos.y; 01159 rcWindowNew.bottom = rcWindowNew.top + pcvr->pos.cy; 01160 01161 /* 01162 * Set up rcWindowOld in parent relative coordinates 01163 */ 01164 GetRect(pwnd, &rcWindowOld, GRECT_WINDOW | GRECT_PARENTCOORDS); 01165 01166 /* 01167 * Set up rcClientOld in parent relative coordinates 01168 */ 01169 GetRect(pwnd, &rcClientOld, GRECT_CLIENT | GRECT_PARENTCOORDS); 01170 01171 /* 01172 * Keep around a copy of the old client position 01173 */ 01174 xClientOld = rcClientOld.left; 01175 cxClientOld = rcClientOld.right - rcClientOld.left; 01176 yClientOld = rcClientOld.top; 01177 cyClientOld = rcClientOld.bottom - rcClientOld.top; 01178 01179 cmd = (UINT)xxxSendMessage(pwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params); 01180 01181 if (!IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 01182 ThreadUnlock(&tlpwnd); 01183 ThreadUnlock(&tlpwndParent); 01184 return FALSE; 01185 } 01186 01187 /* 01188 * Upon return from NCCALCSIZE: 01189 * 01190 * params.rgrc[0] = rcClientNew = New client rect 01191 * params.rgrc[1] = rcValidDst = Destination valid rectangle 01192 * params.rgrc[2] = rcValidSrc = Source valid rectangle 01193 */ 01194 #undef rcWindowNew 01195 #undef rcWindowOld 01196 #undef rcClientOld 01197 01198 #define rcClientNew params.rgrc[0] 01199 #define rcValidDst params.rgrc[1] 01200 #define rcValidSrc params.rgrc[2] 01201 01202 /* 01203 * Calculate the distance the window contents are 01204 * moving. If 0 or an invalid value was returned 01205 * from the WM_NCCALCSIZE message, assume the 01206 * entire client area is valid and top-left aligned. 01207 */ 01208 if (cmd < WVR_MINVALID || cmd > WVR_MAXVALID) { 01209 01210 /* 01211 * We don't need to copy rcValidSrc to rcClientOld, 01212 * because it's already stored in rgrc[2]. 01213 * 01214 * rcValidSrc = rcClientOld 01215 */ 01216 rcValidDst = rcClientNew; 01217 01218 cmd = WVR_ALIGNTOP | WVR_ALIGNLEFT; 01219 } 01220 01221 /* 01222 * Calculate the distance we'll be shifting bits... 01223 */ 01224 #ifdef USE_MIRRORING 01225 if (TestWF(pwnd, WEFLAYOUTRTL)) { 01226 pcvr->dxBlt = rcValidDst.right - rcValidSrc.right; 01227 } else 01228 #endif 01229 { 01230 pcvr->dxBlt = rcValidDst.left - rcValidSrc.left; 01231 } 01232 pcvr->dyBlt = rcValidDst.top - rcValidSrc.top; 01233 01234 /* 01235 * Calculate new client rect size and position 01236 */ 01237 pcvr->xClientNew = rcClientNew.left; 01238 pcvr->yClientNew = rcClientNew.top; 01239 01240 pcvr->cxClientNew = rcClientNew.right - rcClientNew.left; 01241 pcvr->cyClientNew = rcClientNew.bottom - rcClientNew.top; 01242 01243 /* 01244 * Figure out whether the client rectangle is moving or sizing, 01245 * and diddle the appropriate bit if not. 01246 */ 01247 if (xClientOld != rcClientNew.left || yClientOld != rcClientNew.top) 01248 pcvr->pos.flags &= ~SWP_NOCLIENTMOVE; 01249 01250 if (cxClientOld != pcvr->cxClientNew || cyClientOld != pcvr->cyClientNew) { 01251 pcvr->pos.flags &= ~SWP_NOCLIENTSIZE; 01252 } 01253 01254 /* 01255 * If the caller doesn't want us to save any bits, then don't. 01256 */ 01257 if (pcvr->pos.flags & SWP_NOCOPYBITS) { 01258 AllInvalid: 01259 01260 /* 01261 * The entire window is invalid: Set the blt rectangle 01262 * to empty, to ensure nothing gets bltted. 01263 */ 01264 SetRectEmpty(&pcvr->rcBlt); 01265 ThreadUnlock(&tlpwnd); 01266 continue; 01267 } 01268 01269 /* 01270 * If this is a transparent window, be sure to invalidate 01271 * everything, because only some of the window's bits are 01272 * blittable. 01273 */ 01274 if (TestWF(pwnd, WEFTRANSPARENT)) 01275 goto AllInvalid; 01276 01277 /* 01278 * We never want to try to copy screen bits for a redirected or a 01279 * layered window. For child windows we may be able to do the 01280 * copy in our redirection bitmap, but that would add a bunch of 01281 * work in zzzBltValidBits. We should consider that for later. 01282 */ 01283 if (GetLayeredWindow(pwnd) != NULL) 01284 goto AllInvalid; 01285 01286 /* 01287 * If both client and window did not change size, the frame didn't 01288 * change, and the blt rectangle moved the same distance as the 01289 * rectangle, then the entire window area is valid. 01290 */ 01291 if (((pcvr->pos.flags & 01292 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_FRAMECHANGED)) 01293 == (SWP_NOSIZE | SWP_NOCLIENTSIZE)) && 01294 pcvr->dxBlt == (pcvr->pos.x - xWindowOld) && 01295 pcvr->dyBlt == (pcvr->pos.y - yWindowOld)) { 01296 01297 goto AllValid; 01298 } 01299 01300 /* 01301 * Now compute the valid blt rectangle. 01302 * 01303 * Check for horz or vert client size changes 01304 * 01305 * NOTE: Assumes WVR_REDRAW == WVR_HREDRAW | WVR_VREDRAW 01306 */ 01307 if (cxClientOld != pcvr->cxClientNew) { 01308 01309 if ((cmd & WVR_HREDRAW) || TestCF(pwnd, CFHREDRAW)) 01310 goto AllInvalid; 01311 } 01312 01313 if (cyClientOld != pcvr->cyClientNew) { 01314 01315 if ((cmd & WVR_VREDRAW) || TestCF(pwnd, CFVREDRAW)) 01316 goto AllInvalid; 01317 } 01318 01319 cxSrc = rcValidSrc.right - rcValidSrc.left; 01320 cySrc = rcValidSrc.bottom - rcValidSrc.top; 01321 01322 cxDst = rcValidDst.right - rcValidDst.left; 01323 cyDst = rcValidDst.bottom - rcValidDst.top; 01324 01325 #ifdef USE_MIRRORING 01326 if ((!!(cmd & WVR_ALIGNRIGHT)) ^ (!!TestWF(pwnd, WEFLAYOUTRTL))) 01327 rcValidDst.left += ((TestWF(pwnd, WEFLAYOUTRTL) && (cxSrc > cxDst)) ? (cxSrc-cxDst) : (cxDst - cxSrc)); 01328 #else 01329 if (cmd & WVR_ALIGNRIGHT) 01330 rcValidDst.left += (cxDst - cxSrc); 01331 #endif 01332 01333 if (cmd & WVR_ALIGNBOTTOM) 01334 rcValidDst.top += (cyDst - cySrc); 01335 01336 /* 01337 * Superimpose the source on the destination, and intersect 01338 * the rectangles. This is done by looking at the 01339 * extent of the rectangles, and pinning as appropriate. 01340 */ 01341 01342 if (cxSrc < cxDst) 01343 rcValidDst.right = rcValidDst.left + cxSrc; 01344 01345 if (cySrc < cyDst) 01346 rcValidDst.bottom = rcValidDst.top + cySrc; 01347 01348 /* 01349 * Finally map the blt rectangle to screen coordinates. 01350 */ 01351 pcvr->rcBlt = rcValidDst; 01352 if (pwndParent != PWNDDESKTOP(pwnd)) { 01353 01354 OffsetRect( 01355 &pcvr->rcBlt, 01356 pwndParent->rcClient.left, 01357 pwndParent->rcClient.top); 01358 } 01359 } else { // if !SWP_NOSIZE or SWP_FRAMECHANGED 01360 01361 AllValid: 01362 01363 /* 01364 * No client size change: Blt the entire window, 01365 * including the frame. Offset everything by 01366 * the distance the window rect changed. 01367 */ 01368 if (pcvr->pos.flags & SWP_NOCOPYBITS) { 01369 SetRectEmpty(&pcvr->rcBlt); 01370 } else { 01371 pcvr->rcBlt.left = pcvr->pos.x; 01372 pcvr->rcBlt.top = pcvr->pos.y; 01373 01374 if (pwndParent != PWNDDESKTOP(pwnd)) { 01375 pcvr->rcBlt.left += pwndParent->rcClient.left; 01376 pcvr->rcBlt.top += pwndParent->rcClient.top; 01377 } 01378 01379 pcvr->rcBlt.right = pcvr->rcBlt.left + pcvr->pos.cx; 01380 pcvr->rcBlt.bottom = pcvr->rcBlt.top + pcvr->pos.cy; 01381 } 01382 01383 /* 01384 * Offset everything by the distance the window moved. 01385 */ 01386 #ifdef USE_MIRRORING 01387 if (TestWF(pwnd, WEFLAYOUTRTL)) { 01388 pcvr->dxBlt = (pcvr->pos.x + pcvr->pos.cx) - (xWindowOld + cxWindowOld); 01389 } else 01390 #endif 01391 { 01392 pcvr->dxBlt = pcvr->pos.x - xWindowOld; 01393 } 01394 01395 pcvr->dyBlt = pcvr->pos.y - yWindowOld; 01396 01397 /* 01398 * If we're moving, we need to set up the client. 01399 */ 01400 if (!(pcvr->pos.flags & SWP_NOMOVE)) { 01401 pcvr->pos.flags &= ~SWP_NOCLIENTMOVE; 01402 01403 pcvr->xClientNew = pwnd->rcClient.left + pcvr->dxBlt; 01404 pcvr->yClientNew = pwnd->rcClient.top + pcvr->dyBlt; 01405 if (pwndParent != PWNDDESKTOP(pwnd)) { 01406 pcvr->xClientNew -= pwndParent->rcClient.left; 01407 pcvr->yClientNew -= pwndParent->rcClient.top; 01408 } 01409 01410 pcvr->cxClientNew = pwnd->rcClient.right - pwnd->rcClient.left; 01411 pcvr->cyClientNew = pwnd->rcClient.bottom - pwnd->rcClient.top; 01412 } 01413 } 01414 01415 ThreadUnlock(&tlpwnd); 01416 01417 } // for (... pcvr ...) 01418 01419 ThreadUnlock(&tlpwndParent); 01420 *phwndNewActive = hwndNewActive; 01421 01422 return TRUE; 01423 } 01424 01425 /***************************************************************************\ 01426 * GetLastTopMostWindow 01427 * 01428 * Returns the last topmost window in the window list. Returns NULL if no 01429 * topmost windows. Used so that we can fill in the pwndInsertAfter field 01430 * in various SWP calls. 01431 * 01432 * History: 01433 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 01434 \***************************************************************************/ 01435 01436 PWND GetLastTopMostWindow(VOID) 01437 { 01438 PWND pwndT; 01439 PDESKTOP pdesk = PtiCurrent()->rpdesk; 01440 01441 if (pdesk == NULL) 01442 return NULL; 01443 01444 pwndT = pdesk->pDeskInfo->spwnd->spwndChild; 01445 01446 if (!pwndT || !TestWF(pwndT, WEFTOPMOST)) 01447 return NULL; 01448 01449 while (pwndT->spwndNext) { 01450 01451 if (!TestWF(pwndT->spwndNext, WEFTOPMOST)) 01452 break; 01453 01454 pwndT = pwndT->spwndNext; 01455 } 01456 01457 return pwndT; 01458 } 01459 01460 /***************************************************************************\ 01461 * SetWindowPos (API) 01462 * 01463 * 01464 * History: 01465 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 01466 \***************************************************************************/ 01467 01468 BOOL xxxSetWindowPos( 01469 PWND pwnd, 01470 PWND pwndInsertAfter, 01471 int x, 01472 int y, 01473 int cx, 01474 int cy, 01475 UINT flags) 01476 { 01477 PSMWP psmwp; 01478 BOOL fInval = FALSE; 01479 01480 #if DBG 01481 CheckLock(pwnd); 01482 01483 switch((ULONG_PTR)pwndInsertAfter) { 01484 case 0x0000FFFF: 01485 case (ULONG_PTR)HWND_TOPMOST: 01486 case (ULONG_PTR)HWND_NOTOPMOST: 01487 case (ULONG_PTR)HWND_TOP: 01488 case (ULONG_PTR)HWND_BOTTOM: 01489 break; 01490 01491 default: 01492 CheckLock(pwndInsertAfter); 01493 break; 01494 } 01495 #endif 01496 01497 /* 01498 * BACKWARD COMPATIBILITY HACKS 01499 * 01500 * Hack 1: For Win 3.0 and below, SetWindowPos() must ignore the 01501 * move and size flags if SWP_SHOWWINDOW or SWP_HIDEWINDOW 01502 * is specified. KnowledgePro is one application that depends on 01503 * this behavior for the positioning of its MDI icons. 01504 * 01505 * Hack 2: In 3.0, if SetWindowPos() is called with SWP_SHOWWINDOW 01506 * and the window is already visible, then the window was 01507 * completely invalidated anyway. So, we do that here too. 01508 * 01509 * NOTE: The placement of the invalidation AFTER the EndDeferWindowPos() 01510 * call means that if the guy is Z-ordering and showing a 3.0 window, 01511 * it may flash, because EndDefer calls DoSyncPaint, and we invalidate 01512 * again after that. Could be fixed with some major hackery in EndDefer, 01513 * and it's probably not worth the trouble. 01514 */ 01515 if (flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)) { 01516 01517 if (!TestWF(pwnd, WFWIN31COMPAT)) { 01518 01519 flags |= SWP_NOMOVE | SWP_NOSIZE; 01520 if ((flags & SWP_SHOWWINDOW) && TestWF(pwnd, WFVISIBLE)) 01521 fInval = TRUE; 01522 } 01523 } 01524 01525 /* 01526 * MULTIMONITOR HACKS 01527 * 01528 * if a app is centering or cliping a hidden owned window 01529 * to the primary monitor we should center the window to the owner 01530 * 01531 * this makes apps that center/position their own dialogs 01532 * work when the app is on a secondary monitor. 01533 */ 01534 if ( !TestWF(pwnd, WFWIN50COMPAT) && 01535 gpDispInfo->cMonitors > 1 && 01536 !(flags & SWP_NOMOVE) && 01537 !TestWF(pwnd, WFCHILD) && 01538 !TestWF(pwnd, WFVISIBLE) && 01539 (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION)) && 01540 pwnd->spwndOwner && 01541 TestWF(pwnd->spwndOwner, WFVISIBLE) && 01542 !IsRectEmpty(&pwnd->spwndOwner->rcWindow)) { 01543 01544 FixBogusSWP(pwnd, &x, &y, cx, cy, flags); 01545 01546 } 01547 01548 if (!(psmwp = InternalBeginDeferWindowPos(1)) || 01549 !(psmwp = _DeferWindowPos(psmwp, 01550 pwnd, 01551 pwndInsertAfter, 01552 x, 01553 y, 01554 cx, 01555 cy, 01556 flags))) { 01557 01558 return FALSE; 01559 } 01560 01561 01562 if (xxxEndDeferWindowPosEx(psmwp, flags & SWP_ASYNCWINDOWPOS)) { 01563 01564 if (fInval) { 01565 xxxRedrawWindow( 01566 pwnd, 01567 NULL, 01568 NULL, 01569 RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN); 01570 } 01571 01572 return TRUE; 01573 } 01574 01575 return FALSE; 01576 } 01577 01578 /***************************************************************************\ 01579 * xxxSwpActivate 01580 * 01581 * 01582 * History: 01583 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 01584 \***************************************************************************/ 01585 01586 BOOL xxxSwpActivate( 01587 PWND pwndNewActive) 01588 { 01589 PTHREADINFO pti; 01590 01591 CheckLock(pwndNewActive); 01592 01593 if (pwndNewActive == NULL) 01594 return FALSE; 01595 01596 pti = PtiCurrent(); 01597 01598 if (TestwndChild(pwndNewActive)) { 01599 01600 xxxSendMessage(pwndNewActive, WM_CHILDACTIVATE, 0, 0L); 01601 01602 } else if (pti->pq->spwndActive != pwndNewActive) { 01603 01604 /* 01605 * Remember if this window wants to be active. We are either setting 01606 * our own window active (most likely), or setting a window of 01607 * another thread active on purpose. If so that means this thread is 01608 * controlling this window and will probably want to set itself 01609 * active and foreground really soon (for example, a setup 01610 * program doing dde to progman). Allow this thread and the target 01611 * thread to do forground activates. 01612 * 01613 * Let's stop doing this for NT5 in an effort to close the number 01614 * of ways applications can force a foreground change. This is not 01615 * quite needed anyway, because: 01616 * -If the current thread is already in the foreground, then it doesn't need 01617 * the TIF_ALLOWFOREGROUNDACTIVATE to make a foreground change. 01618 * -Since FRemoveForegroundActive removes this bit, the current thread 01619 * will lose it anyway during the xxxActivateWindow call. 01620 * -But xxxActivateWindow will set it back anyway because we're activating 01621 * a window from a different queue. 01622 * -The destination window/thread will take the foreground 01623 * as a result of the xxxActivateWindow call, hence it doesn't 01624 * need the bit on (if you're in the foreground, you don't need it). 01625 */ 01626 #ifdef DONTDOTHISANYMORE 01627 if ((pti->pq == gpqForeground) && (pti != GETPTI(pwndNewActive))) { 01628 /* 01629 * Allow foreground activate on the source and dest. 01630 */ 01631 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 01632 TAGMSG1(DBGTAG_FOREGROUND, "xxxSwpActivate set TIF %#p", pti); 01633 GETPTI(pwndNewActive)->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 01634 TAGMSG1(DBGTAG_FOREGROUND, "xxxSwpActivate set TIF %#p", GETPTI(pwndNewActive)); 01635 } 01636 #endif 01637 01638 if (!xxxActivateWindow(pwndNewActive, AW_USE)) 01639 return FALSE; 01640 01641 /* 01642 * HACK ALERT: We set these bits to prevent 01643 * the frames from redrawing themselves in 01644 * the later call to DoSyncPaint(). 01645 * 01646 * Prevent these captions from being repainted during 01647 * the DoSyncPaint(). (bobgu 6/10/87) 01648 */ 01649 if (pti->pq->spwndActive != NULL) 01650 SetWF(pti->pq->spwndActive, WFNONCPAINT); 01651 01652 if (pti->pq->spwndActivePrev != NULL) 01653 SetWF(pti->pq->spwndActivePrev, WFNONCPAINT); 01654 01655 return TRUE; // Indicate that we diddled these bits 01656 } 01657 01658 return FALSE; 01659 } 01660 /***************************************************************************\ 01661 * xxxSendChangedMsgs 01662 * 01663 * Send WM_WINDOWPOSCHANGED messages as needed 01664 * 01665 * History: 01666 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 01667 \***************************************************************************/ 01668 01669 VOID xxxSendChangedMsgs( 01670 PSMWP psmwp) 01671 { 01672 PWND pwnd; 01673 PCVR pcvr; 01674 int ccvr; 01675 TL tlpwnd; 01676 01677 /* 01678 * Send all the messages that need to be sent... 01679 */ 01680 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 01681 01682 if (pcvr->pos.hwnd == NULL) 01683 continue; 01684 01685 /* 01686 * If the window's state didn't change, don't send the message. 01687 */ 01688 if ((pcvr->pos.flags & SWP_CHANGEMASK) == SWP_NOCHANGE) 01689 continue; 01690 01691 if ((pwnd = RevalidateHwnd(pcvr->pos.hwnd)) == NULL) { 01692 RIPMSG0(RIP_WARNING, "xxxSendChangedMsgs: window went away in middle"); 01693 pcvr->pos.flags = SWP_NOREDRAW | SWP_NOCHANGE; 01694 pcvr->pos.hwnd = NULL; 01695 continue; 01696 } 01697 01698 if (!IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 01699 pcvr->pos.hwnd = NULL; 01700 continue; 01701 } 01702 01703 /* 01704 * Send the WM_WINDOWPOSCHANGED message... 01705 * 01706 * Make a frame copy of the WINDOWPOS, because the pcvr 01707 * info may get reused if SetWindowPos() 01708 * is called by the message handler: see the comments in 01709 * AllocSmwp(). 01710 * 01711 * WM_SIZE, WM_MOVE and WM_SHOW messages are sent by the 01712 * DefWindowProc() WM_WINDOWPOSCHANGED message processing. 01713 * 01714 * Note: It's okay to destroy the window while processing this 01715 * message, since this is the last call made by the window manager 01716 * with the window handle before returning from SetWindowPos(). 01717 * This also means we don't have to revalidate the pwnd. 01718 */ 01719 ThreadLockAlways(pwnd, &tlpwnd); 01720 xxxSendMessage(pwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)&pcvr->pos); 01721 01722 /* 01723 * Only send a shape change when moving/sizing/minimizing/restoring/ 01724 * maximizing (or framechange for NetMeeting to detect SetWindowRgn) 01725 */ 01726 if (FWINABLE() && 01727 (!(pcvr->pos.flags & SWP_NOCLIENTMOVE) || 01728 !(pcvr->pos.flags & SWP_NOCLIENTSIZE) || 01729 (pcvr->pos.flags & SWP_STATECHANGE) || 01730 (pcvr->pos.flags & SWP_FRAMECHANGED))) { 01731 xxxWindowEvent(EVENT_OBJECT_LOCATIONCHANGE, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 01732 } 01733 ThreadUnlock(&tlpwnd); 01734 } // for (... pcvr ...) 01735 01736 01737 } 01738 01739 /***************************************************************************\ 01740 * AsyncWindowPos 01741 * 01742 * This functions pulls from the passed-in SMWP all windows not owned by the 01743 * current thread and passes them off to their owners to be handled. This 01744 * eliminates synchronization where thread B won't get a chance to paint 01745 * until thread A has completed painting (or at least returned from handling 01746 * painting-related messages). Such synchronizations are bad because they 01747 * can cause threads of unrelated process to hang each other. 01748 * 01749 * History: 01750 * 09-10-91 darrinm Created. 01751 \***************************************************************************/ 01752 01753 void AsyncWindowPos( 01754 PSMWP psmwp) 01755 { 01756 BOOL fFinished; 01757 PCVR pcvrFirst; 01758 PCVR pcvr; 01759 PCVR pcvrT; 01760 int ccvrRemaining; 01761 int ccvr; 01762 int chwnd; 01763 PTHREADINFO ptiT; 01764 PTHREADINFO ptiCurrent; 01765 PSMWP psmwpNew; 01766 01767 pcvrFirst = psmwp->acvr; 01768 ccvrRemaining = psmwp->ccvr; 01769 01770 ptiCurrent = PtiCurrent(); 01771 01772 while (TRUE) { 01773 01774 fFinished = TRUE; 01775 01776 /* 01777 * Loop through all windows in the SMWP list searching for windows 01778 * owned by other threads. Return if none are found. 01779 */ 01780 for (; ccvrRemaining != 0; pcvrFirst++, ccvrRemaining--) { 01781 01782 if (pcvrFirst->pos.hwnd == NULL) 01783 continue; 01784 01785 ptiT = pcvrFirst->pti; 01786 if (ptiT->pq != ptiCurrent->pq) { 01787 fFinished = FALSE; 01788 break; 01789 } 01790 } 01791 01792 if (fFinished) { 01793 return; 01794 } 01795 01796 /* 01797 * We've found a window of another thread. Count how many other 01798 * windows in the list are owned by the same thread so we can 01799 * allocate a CVR array for them. 01800 */ 01801 chwnd = 0; 01802 01803 for (pcvr = pcvrFirst, ccvr = ccvrRemaining; --ccvr >= 0; pcvr++) { 01804 01805 if (pcvr->pos.hwnd == NULL) 01806 continue; 01807 01808 if (pcvr->pti->pq == ptiT->pq) 01809 chwnd++; 01810 } 01811 01812 /* 01813 * Allocate temp SMWP/CVR structure to be passed to the other thread. 01814 */ 01815 psmwpNew = (PSMWP)UserAllocPool(sizeof(SMWP) + (sizeof(CVR) * chwnd), 01816 TAG_SWP); 01817 01818 /* 01819 * Even if we can't allocate memory to pass the SMWP to another 01820 * thread we still need to remove its windows from the current list. 01821 */ 01822 if (psmwpNew == NULL) { 01823 01824 for (pcvr = pcvrFirst; chwnd != 0; pcvr++) { 01825 01826 if (pcvr->pti->pq == ptiT->pq) { 01827 pcvr->pos.hwnd = NULL; 01828 chwnd--; 01829 } 01830 } 01831 01832 continue; 01833 } 01834 01835 psmwpNew->ccvr = chwnd; 01836 psmwpNew->acvr = (PCVR)((PBYTE)psmwpNew + sizeof(SMWP)); 01837 01838 for (pcvr = pcvrFirst, pcvrT = psmwpNew->acvr; chwnd != 0; pcvr++) { 01839 01840 if (pcvr->pos.hwnd == NULL) 01841 continue; 01842 01843 /* 01844 * Copy the appropriate CVR structs into our temp array. 01845 */ 01846 if (pcvr->pti->pq == ptiT->pq) { 01847 01848 *pcvrT++ = *pcvr; 01849 chwnd--; 01850 01851 /* 01852 * Remove this window from the list of windows to be handled 01853 * by the current thread. 01854 */ 01855 pcvr->pos.hwnd = NULL; 01856 } 01857 } 01858 01859 /* 01860 * This lets the other thread know it needs to do some windowposing. 01861 * The other thread is responsible for freeing the temp SMWP/CVR array. 01862 */ 01863 if (!PostEventMessage(ptiT, ptiT->pq, QEVENT_SETWINDOWPOS, NULL, 0, 01864 (WPARAM)psmwpNew, (LPARAM)ptiT)) { 01865 // IANJA RIP only to catch what was previously a bug: psmwpNew not freed 01866 RIPMSG1(RIP_WARNING, "PostEventMessage swp to pti %#p failed", ptiT); 01867 UserFreePool(psmwpNew); 01868 } 01869 } 01870 01871 } 01872 01873 /***************************************************************************\ 01874 * xxxProcessSetWindowPosEvent 01875 * 01876 * This function is called from xxxProcessEvent (QUEUE.C) to respond to 01877 * posted QEVENT_SETWINDOWPOS events which originate at the AsyncWindowPos 01878 * function above. 01879 * 01880 * History: 01881 * 10-Sep-1991 DarrinM Created. 01882 \***************************************************************************/ 01883 01884 VOID xxxProcessSetWindowPosEvent( 01885 PSMWP psmwpT) 01886 { 01887 PSMWP psmwp; 01888 01889 /* 01890 * Create a bonafide SMWP/CVR array that xxxEndDeferWindowPos can use 01891 * and later free. 01892 */ 01893 if ((psmwp = InternalBeginDeferWindowPos(psmwpT->ccvr)) == NULL) { 01894 UserFreePool(psmwpT); 01895 return; 01896 } 01897 01898 /* 01899 * Copy the contents of the temp SMWP/CVR array into the real one. 01900 */ 01901 RtlCopyMemory(psmwp->acvr, psmwpT->acvr, sizeof(CVR) * psmwpT->ccvr); 01902 psmwp->ccvr = psmwpT->ccvr; 01903 01904 /* 01905 * Complete the MultWindowPos operation now that we're on the correct 01906 * context. 01907 */ 01908 xxxEndDeferWindowPosEx(psmwp, FALSE); 01909 01910 /* 01911 * Free the temp SMWP/CVR array. 01912 */ 01913 UserFreePool(psmwpT); 01914 } 01915 01916 #define SWP_BOZO ( SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE ) 01917 01918 /***************************************************************************\ 01919 * DBGValidateSibblingZOrder 01920 * 01921 * History: 01922 * 04/01/98 GerardoB Created 01923 \***************************************************************************/ 01924 #if DBG 01925 void DBGValidateSibblingZOrder(PWND pwndParent) 01926 { 01927 PWND pwndT = pwndParent->spwndChild; 01928 /* 01929 * Check that the sibbling list looks OK right now 01930 * We don't really care about the z-order of message windows. 01931 */ 01932 if ((pwndT != NULL) && (pwndParent != PWNDMESSAGE(pwndParent))) { 01933 BOOL fFoundNonTopMost = !TestWF(pwndT, WEFTOPMOST); 01934 while (pwndT != NULL) { 01935 if (TestWF(pwndT, WEFTOPMOST)) { 01936 UserAssert(!fFoundNonTopMost); 01937 } else { 01938 fFoundNonTopMost = TRUE; 01939 } 01940 pwndT = pwndT->spwndNext; 01941 } 01942 } 01943 } 01944 #else 01945 #define DBGValidateSibblingZOrder(pwndParent) 01946 #endif 01947 01948 /***************************************************************************\ 01949 * zzzChangeStates 01950 * 01951 * History: 01952 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 01953 \***************************************************************************/ 01954 01955 VOID zzzChangeStates( 01956 PWND pwndParent, 01957 PSMWP psmwp) 01958 { 01959 int ccvr; 01960 PCVR pcvr; 01961 PWND pwnd; 01962 TL tlpwnd; 01963 TL tlpwndParent; 01964 int czorder = 0; 01965 01966 BEGINATOMICCHECK(); 01967 ThreadLockAlways(pwndParent, &tlpwndParent); 01968 01969 /* 01970 * Check that the sibbling list looks OK right now 01971 * 01972 * Here's the reason why this DBG code is commented out: 01973 * Owned windows are always expected to be on top of the owner. 01974 * However, an app can call SetWindowPos and insert the ownee after 01975 * the owner. IME somehow does this too. 01976 * This causes us to have A to be inserted after B and later in the 01977 * windowpos array, B to be inserted somewhere else. Hence, A won't be in the 01978 * expected position, because B will be moved after A is inserted. 01979 * In other words, a window in hwndInsertAfter must not appear later 01980 * as a hwnd to be z-ordered. Ownees below owners cause this situation. 01981 */ 01982 // DBGValidateSibblingZOrder(pwndParent); 01983 01984 01985 /* 01986 * Now change the window states 01987 */ 01988 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 01989 01990 if (pcvr->pos.hwnd == NULL) 01991 continue; 01992 01993 UserAssert(0 == (pcvr->pos.flags & SWP_NOTIFYALL)); 01994 01995 pwnd = RevalidateHwnd(pcvr->pos.hwnd); 01996 01997 if ((pwnd == NULL) || !IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 01998 RIPMSG0(RIP_WARNING, "zzzChangeStates: Window went away in middle"); 01999 pcvr->pos.flags = SWP_NOREDRAW | SWP_NOCHANGE; 02000 pcvr->pos.hwnd = NULL; 02001 } 02002 02003 #if DBG 02004 /* 02005 * This can happen when we get re-entered during a callback or mulitple 02006 * threads are z-ordering the same window. The tray does stuff like this. 02007 * We would need to keep the toggle state in the windowpos structure to 02008 * have each call have its own state. 02009 */ 02010 if (TestWF(pwnd, WFTOGGLETOPMOST) && (pcvr->pos.flags & SWP_NOZORDER)) 02011 RIPMSG0(RIP_WARNING, "zzzChangeState: WFTOGGLETOPMOST should not be set"); 02012 02013 // UserAssert(!(TestWF(pwnd, WFTOGGLETOPMOST) && (pcvr->pos.flags & SWP_NOZORDER))); 02014 #endif 02015 02016 /* 02017 * Check to se if there is any state to change. If not, just 02018 * continue. 02019 */ 02020 if ((pcvr->pos.flags & SWP_CHANGEMASK) == SWP_NOCHANGE) { 02021 02022 pcvr->pos.flags |= SWP_NOREDRAW; 02023 continue; 02024 } 02025 02026 /* 02027 * Change the window region if needed 02028 * 02029 * Before we do anything, check to see if we're only Z-ordering. 02030 * If so, then check to see if we're already in the right place, 02031 * and if so, clear the ZORDER flag. 02032 * 02033 * We have to make this test in the state-change loop if previous 02034 * windows in the WINDOWPOS list were Z-ordered, since the test depends 02035 * on any ordering that may have happened previously. 02036 * 02037 * We don't bother to do this redundancy check if there are 02038 * other bits set, because the amount of time saved in that 02039 * case is about as much as the amount of time it takes to 02040 * test for redundancy. 02041 */ 02042 if (((pcvr->pos.flags & SWP_CHANGEMASK) == 02043 (SWP_NOCHANGE & ~SWP_NOZORDER))) { 02044 02045 /* 02046 * If the window's Z order won't be changing, then 02047 * we can clear the ZORDER bit and set NOREDRAW. 02048 */ 02049 if ((!TestWF(pwnd, WFTOGGLETOPMOST)) && ValidateZorder(pcvr)) { 02050 02051 /* 02052 * The window's already in the right place: 02053 * Set SWP_NOZORDER bit, set SWP_NOREDRAW, 02054 * and destroy the visrgn that we created earlier. 02055 */ 02056 pcvr->pos.flags |= SWP_NOZORDER | SWP_NOREDRAW; 02057 02058 if (pcvr->hrgnVisOld) { 02059 GreDeleteObject(pcvr->hrgnVisOld); 02060 pcvr->hrgnVisOld = NULL; 02061 } 02062 continue; 02063 } 02064 } 02065 02066 /* 02067 * Change the window state, as appropriate... 02068 */ 02069 if ((pcvr->pos.flags & 02070 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)) != 02071 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)) { 02072 02073 PCARET pcaret = &PtiCurrent()->pq->caret; 02074 BOOL fRecreateRedirectionBitmap = FALSE; 02075 02076 if (FLayeredOrRedirected(pwnd)) { 02077 int cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 02078 int cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 02079 02080 if (cx != pcvr->pos.cx || cy != pcvr->pos.cy) { 02081 fRecreateRedirectionBitmap = TRUE; 02082 } 02083 } 02084 02085 /* 02086 * Set up the new window and client rectangles. 02087 */ 02088 pwnd->rcWindow.left = pcvr->pos.x; 02089 pwnd->rcWindow.top = pcvr->pos.y; 02090 if (pwndParent != PWNDDESKTOP(pwnd)) { 02091 pwnd->rcWindow.left += pwndParent->rcClient.left; 02092 pwnd->rcWindow.top += pwndParent->rcClient.top; 02093 } 02094 02095 pwnd->rcWindow.right = pwnd->rcWindow.left + pcvr->pos.cx; 02096 pwnd->rcWindow.bottom = pwnd->rcWindow.top + pcvr->pos.cy; 02097 02098 if (pwnd->rcWindow.right < pwnd->rcWindow.left) { 02099 RIPMSG1(RIP_WARNING, "SWP: cx changed for pwnd %#p", pwnd); 02100 pwnd->rcWindow.right = pwnd->rcWindow.left; 02101 } 02102 02103 if (pwnd->rcWindow.bottom < pwnd->rcWindow.top) { 02104 RIPMSG1(RIP_WARNING, "SWP: cy changed for pwnd %#p", pwnd); 02105 pwnd->rcWindow.bottom = pwnd->rcWindow.top; 02106 } 02107 02108 /* 02109 * If the client moved relative to its parent, 02110 * offset the caret by the amount that rcBlt moved 02111 * relative to the client rect. 02112 */ 02113 if (pwnd == pcaret->spwnd) { 02114 02115 /* 02116 * Calculate the distance the contents of the client area 02117 * is moving, in client-relative coordinates. 02118 * 02119 * Calculates dBlt + (old position - new position) 02120 */ 02121 int dx = pcvr->dxBlt + pwnd->rcClient.left - pcvr->xClientNew; 02122 int dy = pcvr->dyBlt + pwnd->rcClient.top - pcvr->yClientNew; 02123 02124 if (pwndParent != PWNDDESKTOP(pwnd)) 02125 { 02126 dx -= pwndParent->rcClient.left; 02127 dy -= pwndParent->rcClient.top; 02128 } 02129 02130 if ((dx | dy) != 0) { 02131 pcaret->x += dx; 02132 pcaret->y += dy; 02133 } 02134 } 02135 02136 /* 02137 * Set up the new client rect 02138 * coordinates provided. 02139 */ 02140 pwnd->rcClient.left = pcvr->xClientNew; 02141 pwnd->rcClient.top = pcvr->yClientNew; 02142 if (pwndParent != PWNDDESKTOP(pwnd)) 02143 { 02144 pwnd->rcClient.left += pwndParent->rcClient.left; 02145 pwnd->rcClient.top += pwndParent->rcClient.top; 02146 } 02147 02148 pwnd->rcClient.right = pwnd->rcClient.left + pcvr->cxClientNew; 02149 pwnd->rcClient.bottom = pwnd->rcClient.top + pcvr->cyClientNew; 02150 02151 /* 02152 * If the window becomes smaller than the monitor, the system 02153 * allows it to be moved (see SetSysMenu) and so we must remove 02154 * the monitor region. 02155 */ 02156 if (TestWF(pwnd, WFMAXFAKEREGIONAL) && IsSmallerThanScreen(pwnd)) { 02157 SelectWindowRgn(pwnd, NULL); 02158 } 02159 02160 /* 02161 * If the layered window is resizing, try to resize the 02162 * redirection bitmap associated with it. 02163 */ 02164 if (fRecreateRedirectionBitmap) { 02165 RecreateRedirectionBitmap(pwnd); 02166 } 02167 02168 /* 02169 * Offset the absolute positions of the window's update region, 02170 * and the position and update regions of its children. 02171 */ 02172 if ((pcvr->dxBlt | pcvr->dyBlt) != 0) { 02173 /* 02174 * Change position of window region, if it has one 02175 * and it isn't a monitor region for a maximized window 02176 */ 02177 if ( pwnd->hrgnClip > HRGN_FULL && 02178 !TestWF(pwnd, WFMAXFAKEREGIONAL)) { 02179 GreOffsetRgn(pwnd->hrgnClip, pcvr->dxBlt, pcvr->dyBlt); 02180 } 02181 02182 if (pwnd->hrgnUpdate > HRGN_FULL) { 02183 GreOffsetRgn(pwnd->hrgnUpdate, pcvr->dxBlt, pcvr->dyBlt); 02184 } 02185 OffsetChildren(pwnd, pcvr->dxBlt, pcvr->dyBlt, NULL); 02186 02187 /* 02188 * Change the position of the sprite associated with 02189 * this window. 02190 */ 02191 if (TestWF(pwnd, WEFLAYERED)) { 02192 POINT ptPos = {pcvr->pos.x, pcvr->pos.y}; 02193 02194 GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, 02195 &ptPos, NULL, NULL, NULL, 0, NULL, 0, NULL); 02196 } 02197 } 02198 } 02199 02200 /* 02201 * Change the Z order if the flag is set. Revalidate 02202 * hwndInsertAfter to make sure that it is still valid 02203 */ 02204 if (!(pcvr->pos.flags & SWP_NOZORDER)) { 02205 02206 if (ValidateWindowPos(pcvr, pwndParent)) { 02207 02208 UnlinkWindow(pwnd, pwndParent); 02209 02210 LinkWindow(pwnd, 02211 PWInsertAfter(pcvr->pos.hwndInsertAfter), 02212 pwndParent); 02213 czorder++; 02214 02215 /* 02216 * HACK ALERT MERGE 02217 * 02218 * ValidateZOrder() depends on rational, consistent setting of the 02219 * WEFTOPMOST bit in order for it to work properly. What this means 02220 * is that we can't set or clear these bits ahead of time based on 02221 * where the window is moving to: instead we have to change the bit 02222 * after we've moved it. Enter the WFTOGGLETOPMOST bit: that bit 02223 * is set in ZOrderByOwner() based on what the topmost bit will 02224 * eventually be set to. To maintain a consistent state, we make 02225 * any changes AFTER the window has been Z-ordered. 02226 */ 02227 if (TestWF(pwnd, WFTOGGLETOPMOST)) { 02228 PBYTE pb; 02229 02230 ClrWF(pwnd, WFTOGGLETOPMOST); 02231 pb = ((BYTE *)&pwnd->state); 02232 pb[HIBYTE(WEFTOPMOST)] ^= LOBYTE(WEFTOPMOST); 02233 } 02234 } else { 02235 pcvr->pos.flags |= SWP_NOZORDER; 02236 ClrWF(pwnd, WFTOGGLETOPMOST); 02237 } 02238 } 02239 02240 02241 /* 02242 * Handle SWP_HIDEWINDOW and SWP_SHOWWINDOW, by clearing or setting 02243 * the WS_VISIBLE bit. 02244 */ 02245 UserAssert(pwndParent != NULL); 02246 ThreadLockAlways(pwnd, &tlpwnd); 02247 if (pcvr->pos.flags & SWP_SHOWWINDOW) { 02248 02249 /* 02250 * Window is showing. If this app is still in startup mode, 02251 * (still starting), give the the app starting cursor 5 more 02252 * seconds. 02253 */ 02254 if (GETPTI(pwnd)->ppi->W32PF_Flags & W32PF_APPSTARTING) 02255 zzzCalcStartCursorHide((PW32PROCESS)GETPTI(pwnd)->ppi, 5000); 02256 02257 /* 02258 * Set the WS_VISIBLE bit. 02259 */ 02260 SetVisible(pwnd, SV_SET); 02261 02262 if (FWINABLE()) 02263 zzzWindowEvent(EVENT_OBJECT_SHOW, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 02264 02265 if (IsTrayWindow(pwnd)) { 02266 psmwp->bShellNotify = TRUE; 02267 pcvr->pos.flags |= TestWF(pwnd, WFFRAMEON) ? SWP_NOTIFYACTIVATE|SWP_NOTIFYCREATE: SWP_NOTIFYCREATE; 02268 02269 /* 02270 * This Chicago code is replaced by the preceding code, 02271 * which exits the critical section only after the Gre 02272 * lock is removed. Fritz 02273 * 02274 * xxxCallHook(HSHELL_WINDOWCREATED, 02275 * (WPARAM)HWq(pwnd), 02276 * (LPARAM)0, 02277 * WH_SHELL); 02278 * 02279 * PostShellHookMessages(HSHELL_WINDOWCREATED, pwnd); 02280 * 02281 * if (TestWF(pwnd, WFFRAMEON)) { 02282 * 02283 * xxxSetTrayWindow(pwnd); 02284 */ 02285 02286 } else if (TestWF(pwnd, WFFULLSCREEN)) { 02287 /* 02288 * Wake up the tray so it can notice that there is now 02289 * a fullscreen visible window. This deals with bugs 02290 * 32164, 141563, and 150217. FritzS 02291 */ 02292 psmwp->bShellNotify = TRUE; 02293 pcvr->pos.flags |= SWP_NOTIFYFS; 02294 } 02295 02296 /* 02297 * If we're redrawing, create an SPB for this window if 02298 * needed. 02299 */ 02300 if (!(pcvr->pos.flags & SWP_NOREDRAW) || 02301 (pcvr->pos.flags & SWP_CREATESPB)) { 02302 02303 /* 02304 * ONLY create an SPB if this window happens to be 02305 * on TOP of all others. NOTE: We could optimize this by 02306 * passing in the new vis rgn to CreateSpb() so that the 02307 * non-visible part of the window is automatically 02308 * invalid in the SPB. 02309 */ 02310 /* 02311 * Make sure this window's desktop is on top ! 02312 */ 02313 if (TestCF(pwnd, CFSAVEBITS) && 02314 pwnd->head.rpdesk == grpdeskRitInput) { 02315 02316 /* 02317 * If this window is the topmost VISIBLE window, 02318 * then we can create an SPB. 02319 */ 02320 PWND pwndT; 02321 RECT rcT; 02322 02323 for (pwndT = pwnd->spwndParent->spwndChild ; 02324 pwndT; 02325 pwndT = pwndT->spwndNext) { 02326 02327 if (pwndT == pwnd) { 02328 CreateSpb(pwnd, FALSE, gpDispInfo->hdcScreen); 02329 break; 02330 } 02331 02332 if (TestWF(pwndT, WFVISIBLE)) { 02333 02334 /* 02335 * Does this window intersect the SAVEBITS 02336 * window at all? If so, bail out. 02337 */ 02338 if (IntersectRect(&rcT, 02339 &pwnd->rcWindow, 02340 &pwndT->rcWindow)) { 02341 break; 02342 } 02343 } 02344 } 02345 } 02346 } 02347 02348 } else if (pcvr->pos.flags & SWP_HIDEWINDOW) { 02349 02350 /* 02351 * for idiots like MS-Access 2.0 who SetWindowPos( SWP_BOZO 02352 * and blow away themselves on the shell, then lets 02353 * just ignore their plea to be removed from the tray 02354 */ 02355 if (((pcvr->pos.flags & SWP_BOZO ) != SWP_BOZO) && 02356 IsTrayWindow(pwnd)) { 02357 02358 psmwp->bShellNotify = TRUE; 02359 pcvr->pos.flags |= SWP_NOTIFYDESTROY; 02360 02361 /* 02362 * This Chicago code is replaced by the preceding code, 02363 * which exits the critical section only after the Gre 02364 * lock is removed. Fritz 02365 * 02366 * xxxCallHook(HSHELL_WINDOWDESTROYED, 02367 * (WPARAM)HWq(pwnd), 02368 * (LPARAM)0, 02369 * WH_SHELL); 02370 * 02371 * PostShellHookMessages(HSHELL_WINDOWDESTROYED, pwnd); 02372 */ 02373 } 02374 02375 /* 02376 * Clear the WS_VISIBLE bit. 02377 */ 02378 SetVisible(pwnd, SV_UNSET | SV_CLRFTRUEVIS); 02379 02380 if (FWINABLE()) 02381 zzzWindowEvent(EVENT_OBJECT_HIDE, pwnd, OBJID_WINDOW, INDEXID_CONTAINER, WEF_USEPWNDTHREAD); 02382 } 02383 02384 /* 02385 * BACKWARD COMPATIBILITY HACK 02386 * 02387 * Under 3.0, window frames were always redrawn, even if 02388 * SWP_NOREDRAW was specified. If we've gotten this far 02389 * and we're visible, and SWP_NOREDRAW was specified, set 02390 * the WFSENDNCPAINT bit. 02391 * 02392 * Apps such as ABC Flowcharter and 123W assume this. 02393 * Typical offending code is MoveWindow(pwnd, ..., FALSE); 02394 * followed by InvalidateRect(pwnd, NULL, TRUE); 02395 */ 02396 if (TestWF(pwnd, WFVISIBLE)) { 02397 if ((pcvr->pos.flags & SWP_STATECHANGE) || 02398 (!TestWF(pwnd, WFWIN31COMPAT) && (pcvr->pos.flags & SWP_NOREDRAW))) { 02399 02400 SetWF(pwnd, WFSENDNCPAINT); 02401 } 02402 } 02403 02404 /* 02405 * If this window has a clipping region set it now 02406 */ 02407 if (pcvr->hrgnClip != NULL) { 02408 SelectWindowRgn(pwnd, pcvr->hrgnClip); 02409 } 02410 ThreadUnlock(&tlpwnd); 02411 } 02412 02413 /* 02414 * Check that the sibbling list looks OK now that we're done 02415 */ 02416 // DBGValidateSibblingZOrder(pwndParent); 02417 02418 if (FWINABLE() && czorder) 02419 zzzWindowEvent(EVENT_OBJECT_REORDER, pwndParent, OBJID_CLIENT, INDEXID_CONTAINER, 0); 02420 ThreadUnlock(&tlpwndParent); 02421 02422 ENDATOMICCHECK(); 02423 } 02424 02425 /***************************************************************************\ 02426 * SwpCalcVisRgn 02427 * 02428 * This routine calculates a non-clipchildren visrgn for pwnd into hrgn. 02429 * 02430 * History: 02431 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 02432 \***************************************************************************/ 02433 02434 BOOL SwpCalcVisRgn( 02435 PWND pwnd, 02436 HRGN hrgn) 02437 { 02438 /* 02439 * If this window is invisible, then 02440 * the visrgn will be empty, so return FALSE. 02441 */ 02442 if (!TestWF(pwnd, WFVISIBLE)) 02443 return FALSE; 02444 02445 /* 02446 * Otherwise do it the hard way... 02447 */ 02448 return CalcVisRgn(&hrgn, 02449 pwnd, 02450 pwnd, 02451 (TestWF(pwnd, WFCLIPSIBLINGS) ? 02452 (DCX_CLIPSIBLINGS | DCX_WINDOW) : (DCX_WINDOW))); 02453 } 02454 02455 /***************************************************************************\ 02456 * CombineOldNewVis 02457 * 02458 * ORs or DIFFs hrgnOldVis and hrgnNewVis, depending on crgn, and the 02459 * RE_* bits of fsRgnEmpty. Basically, this routine handles the optimization 02460 * where if either region is empty, the other can be copied. Returns FALSE 02461 * if the result is empty. 02462 * 02463 * History: 02464 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 02465 \***************************************************************************/ 02466 02467 BOOL CombineOldNewVis( 02468 HRGN hrgn, 02469 HRGN hrgnVisOld, 02470 HRGN hrgnVisNew, 02471 UINT crgn, 02472 UINT fsRgnEmpty) 02473 { 02474 switch (fsRgnEmpty & (RE_VISOLD | RE_VISNEW)) { 02475 case RE_VISOLD: 02476 02477 /* 02478 * If we're calculating old - new and old is empty, then result is 02479 * empty. Otherwise, result is new. 02480 */ 02481 if (crgn == RGN_DIFF) 02482 return FALSE; 02483 02484 CopyRgn(hrgn, hrgnVisNew); 02485 break; 02486 02487 case RE_VISNEW: 02488 02489 /* 02490 * New is empty: result will be the old. 02491 */ 02492 CopyRgn(hrgn, hrgnVisOld); 02493 break; 02494 02495 case RE_VISNEW | RE_VISOLD: 02496 02497 /* 02498 * Both empty: so's the result. 02499 */ 02500 return FALSE; 02501 02502 case 0: 02503 02504 /* 02505 * Neither are empty: do the real combine. 02506 */ 02507 switch (GreCombineRgn(hrgn, hrgnVisOld, hrgnVisNew, crgn)) { 02508 case NULLREGION: 02509 case ERROR: 02510 return FALSE; 02511 02512 default: 02513 break; 02514 } 02515 break; 02516 } 02517 02518 return TRUE; 02519 } 02520 02521 /***************************************************************************\ 02522 * BltValidInit 02523 * 02524 * 02525 * History: 02526 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 02527 \***************************************************************************/ 02528 02529 int BltValidInit( 02530 PSMWP psmwp) 02531 { 02532 int ccvr; 02533 int cIter = 0; 02534 PCVR pcvr; 02535 PWND pwnd; 02536 BOOL fChangeState = FALSE; 02537 02538 /* 02539 * Before we change any window state, calculate the old visrgn 02540 */ 02541 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 02542 02543 UINT flags = pcvr->pos.flags; 02544 02545 /* 02546 * Make sure this is initialized to NULL; we may be sticking something 02547 * in it, and we want to know later if we need to free that thing. 02548 */ 02549 pcvr->hrgnVisOld = NULL; 02550 02551 if (pcvr->pos.hwnd == NULL) 02552 continue; 02553 02554 pwnd = RevalidateHwnd(pcvr->pos.hwnd); 02555 02556 if ((pwnd == NULL) || !IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 02557 pcvr->pos.hwnd = NULL; 02558 pcvr->pos.flags = SWP_NOREDRAW | SWP_NOCHANGE; 02559 continue; 02560 } 02561 02562 /* 02563 * Before we change any window's state, ensure that any SPBs 02564 * over the window's old location are invalidated if necessary. 02565 * This must be done because no WM_PAINT messages will be 02566 * sent to anyone for the covered area if the area is obscured 02567 * by other windows. 02568 */ 02569 if (AnySpbs() && !(flags & SWP_NOREDRAW)) 02570 SpbCheckRect(pwnd, &pwnd->rcWindow, DCX_WINDOW); 02571 02572 /* 02573 * Count the number of passes through the loop 02574 */ 02575 cIter++; 02576 02577 /* 02578 * Remember if any SWPs need their state changed. 02579 */ 02580 if ((flags & SWP_CHANGEMASK) != SWP_NOCHANGE) 02581 fChangeState = TRUE; 02582 02583 /* 02584 * If we're not redrawing, no need to calculate visrgn 02585 */ 02586 if (pcvr->pos.flags & SWP_NOREDRAW) 02587 continue; 02588 02589 if (!SYSMET(SAMEDISPLAYFORMAT)) 02590 PreventInterMonitorBlts(pcvr); 02591 02592 pcvr->fsRE = 0; 02593 pcvr->hrgnVisOld = CreateEmptyRgn(); 02594 02595 if (pcvr->hrgnVisOld == NULL || 02596 !SwpCalcVisRgn(pwnd, pcvr->hrgnVisOld)) { 02597 02598 pcvr->fsRE = RE_VISOLD; 02599 } 02600 } 02601 02602 return (fChangeState ? cIter : 0); 02603 } 02604 02605 /***************************************************************************\ 02606 * zzzBltValidBits 02607 * 02608 * NOTE: Although zzzBltValidBits calls 'xxxInternalInvalidate' it does not 02609 * specify any of the flags that will cause immediate updating. This means 02610 * that it does not actually leave the critsect and therefore is not an 'xxx' 02611 * routine and doesn't have to bother with revalidation. 02612 * 02613 * This is the routine that blts the windows around on the screen, taking 02614 * into account SPBs. 02615 * 02616 * Here is the basic algebra going on here: 02617 * 02618 * ASSUMES: - rcBlt is aligned to the DESTINATION 02619 * - offset() offsets from source to destination 02620 * 02621 * 1. hrgnSrc = offset(rcBlt) & hrgnVisOld 02622 * 02623 * Source region is the blt rectangle aligned with the old visrgn, 02624 * intersected with the old visrgn. 02625 * 02626 * 2. hrgnDst = rcBlt & hrgnVisNew 02627 * 02628 * Dest region is the blt rectangle intersected with the new visrgn. 02629 * 02630 * 3. ghrgnValid = offset(hrgnSrc) & hrgnDst 02631 * 02632 * Valid area is the intersection of the destination with the source 02633 * superimposed on the destination. 02634 * 02635 * 3.1 ghrgnValid = ghrgnValid - hrgnInterMonitor 02636 * 02637 * Subtract out any pieces that are moving across monitors. 02638 * 02639 * 4. ghrgnValid -= ghrgnValidSum 02640 * 02641 * This step takes into account the possibility that another window's 02642 * valid bits were bltted on top of this windows valid bits. So, as we 02643 * blt a window's bits, we accumulate where it went, and subtract it 02644 * from subsequent window's valid area. 02645 * 02646 * 5. ghrgnInvalid = (hrgnSrc | hrgnDst) - ghrgnValid 02647 * 02648 * 6. ghrgnInvalid += RestoreSpb(ghrgnInvalid) (sort of) 02649 * 02650 * This is the wild part, because of the grungy way that the device 02651 * driver SaveBits() routine works. We call RestoreSpb() with 02652 * a copy of ghrgnInvalid. If the SPB valid region doesn't intersect 02653 * ghrgnInvalid, RestoreSpb() does nothing. But if it DOES intersect, 02654 * it blts down the ENTIRE saved SPB bitmap, which may include area 02655 * of the old window position that IS NOT part of ghrgnValid! 02656 * 02657 * To correct for this, ghrgnValid is adjusted by subtracting off 02658 * the ghrgnInvalid computed by RestoreSpb, if it modified it. 02659 * 02660 * 7. ghrgnInvalidSum |= ghrgnInvalid 02661 * 02662 * We save up the sum of all the invalid areas, and invalidate the 02663 * whole schmear in one fell swoop at the end. 02664 * 02665 * 8. ghrgnValidSum |= ghrgnValid 02666 * 02667 * We keep track of the valid areas so far, which are subtracted 02668 * in step 4. 02669 * 02670 * The actual steps occur in a slightly different order than above, and 02671 * there are numerous optimizations that are taken advantage of (the 02672 * most important having to do with hiding and showing, and complete 02673 * SPB restoration). 02674 * 02675 * Returns TRUE if some drawing was done, FALSE otherwise. 02676 * 02677 * History: 02678 * 10-Jul-1991 DarrinM Ported from Win 3.1 sources. 02679 \***************************************************************************/ 02680 02681 BOOL zzzBltValidBits( 02682 PSMWP psmwp) 02683 { 02684 int ccvr; 02685 int cIter; 02686 PCVR pcvr; 02687 PWND pwnd; 02688 PWND pwndParent; 02689 PWND pwndT; 02690 PWINDOWPOS ppos; 02691 HRGN hrgnInvalidate; 02692 UINT fsRgnEmpty; 02693 UINT fsSumEmpty; 02694 int cwndShowing; 02695 BOOL fSyncPaint = FALSE; 02696 BOOL fInvalidateLayers = FALSE; 02697 HDC hdcScreen = NULL; 02698 02699 DeferWinEventNotify(); 02700 GreLockDisplay(gpDispInfo->hDev); 02701 02702 /* 02703 * Compute old visrgns and count total CVRs in list. A side-effect of 02704 * BltValidInit is that revalidates all the windows in the SMWP array. 02705 */ 02706 02707 02708 if ((cIter = BltValidInit(psmwp)) == 0) { 02709 02710 CleanupAndExit: 02711 02712 /* 02713 * Go through the cvr list and free the regions that BltValidInit() 02714 * created. 02715 */ 02716 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 02717 02718 if (pcvr->hrgnVisOld) { 02719 GreDeleteObject(pcvr->hrgnVisOld); 02720 pcvr->hrgnVisOld = NULL; 02721 } 02722 } 02723 02724 goto UnlockAndExit; 02725 } 02726 02727 /* 02728 * We left the crit sect since last time we validated the smwp. Validate 02729 * it again, and find the first WINDOWPOS structure with a non-NULL 02730 * hwnd in it. 02731 */ 02732 ppos = NULL; 02733 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 02734 02735 /* 02736 * Revalidate window and if it's invalid, NULL it out in the WINDOWPOS 02737 * struct. 02738 */ 02739 pwnd = RevalidateHwnd(pcvr->pos.hwnd); 02740 02741 if ((pwnd == NULL) || 02742 (pwnd->spwndParent == NULL) || 02743 !IsStillWindowC(pcvr->pos.hwndInsertAfter)) { 02744 02745 pcvr->pos.hwnd = NULL; 02746 pcvr->pos.flags = SWP_NOREDRAW | SWP_NOCHANGE; 02747 continue; 02748 } 02749 02750 /* 02751 * Remember the first WINDOWPOS structure that has a non-NULL 02752 * hwnd. 02753 */ 02754 if (ppos == NULL) 02755 ppos = &pcvr->pos; 02756 } 02757 02758 if (ppos == NULL) 02759 goto CleanupAndExit; 02760 02761 UserAssert(PW(ppos->hwnd)); 02762 pwndParent = PW(ppos->hwnd)->spwndParent; 02763 UserAssert(pwndParent); 02764 02765 /* 02766 * Go account for any dirty DCs at this point, to ensure that: 02767 * - any drawing done before we create an SPB will not 02768 * later invalidate that SPB 02769 * - the SPB regions reflect the true state of the screen, 02770 * so that we don't validate parts of windows that are dirty. 02771 * 02772 * We must make this call before we change any window state. 02773 */ 02774 if (AnySpbs()) 02775 SpbCheck(); 02776 02777 /* 02778 * Change the window states 02779 */ 02780 zzzChangeStates(pwndParent, psmwp); 02781 02782 /* 02783 * move window bits around 02784 * 02785 * Invalidate the DCs for the siblings of this window. 02786 * 02787 * If our parent is not clipchildren, then we don't need to 02788 * invalidate its DCs. If it IS clipchildren, its client visrgn 02789 * will be changing, so we must invalidate it too. 02790 * 02791 * Note, because IDC_MOVEBLT is set, final completion of WNDOBJ 02792 * notification is delayed until GreClientRgnDone is called. 02793 * This final notification does not happen until after the 02794 * window move blts have completed. 02795 */ 02796 zzzInvalidateDCCache(pwndParent, 02797 IDC_MOVEBLT | 02798 (TestWF(pwndParent, WFCLIPCHILDREN) ? 02799 IDC_CLIENTONLY : IDC_CHILDRENONLY)); 02800 02801 /* 02802 * Now, do the bltting or whatever that is required. 02803 */ 02804 fsSumEmpty = RE_VALIDSUM | RE_INVALIDSUM; 02805 hrgnInvalidate = ghrgnInvalidSum; 02806 02807 /* 02808 * Init count of windows being shown with SWP_SHOWWINDOW 02809 * for our backward compatibility hack later. 02810 */ 02811 cwndShowing = 0; 02812 02813 for (pcvr = psmwp->acvr, ccvr = psmwp->ccvr; --ccvr >= 0; pcvr++) { 02814 02815 /* 02816 * Decrement loop count. When cIter is 0, then 02817 * we're on the last pass through the loop. 02818 */ 02819 cIter--; 02820 02821 if (pcvr->pos.hwnd == NULL) 02822 continue; 02823 02824 /* 02825 * If we're not redrawing, try the next one. 02826 */ 02827 if (pcvr->pos.flags & SWP_NOREDRAW) 02828 continue; 02829 02830 /* 02831 * Some drawing has been done 02832 */ 02833 fSyncPaint = TRUE; 02834 02835 pwnd = PW(pcvr->pos.hwnd); 02836 02837 fsRgnEmpty = pcvr->fsRE; 02838 02839 /* 02840 * Sprites should not be invalidated or cause invalidation. 02841 */ 02842 if (FLayeredOrRedirected(pwnd)) { 02843 if (_GetProp(pwnd, PROP_LAYER, TRUE) == NULL) 02844 goto InvalidEmpty; 02845 02846 /* 02847 * Sizing or showing uncovers new bits for a window, so 02848 * do the normal invalidation in this case. When sizing makes a 02849 * window smaller setting fInvalidateLayers to TRUE has the side 02850 * effect of allowing other layered windows to be invalidated. 02851 * Ideally, it should only allow invlalidating just the windows 02852 * that resized or showed. This would be a bunch of work, but we 02853 * should consider it for later. 02854 */ 02855 if ((pcvr->pos.flags & SWP_NOSIZE) && 02856 !(pcvr->pos.flags & SWP_SHOWWINDOW)) { 02857 goto InvalidEmpty; 02858 } else { 02859 fInvalidateLayers = TRUE; 02860 } 02861 } 02862 02863 /* 02864 * Calculate the new visrgn 02865 */ 02866 if (!SwpCalcVisRgn(pwnd, ghrgnVisNew)) 02867 fsRgnEmpty |= RE_VISNEW; 02868 02869 /* 02870 * If the window is obscured by another window with an SPB, 02871 * we have to ensure that that SPB gets invalidated properly 02872 * since the app may not be getting a WM_PAINT msg or anything 02873 * to invalidate the bits. 02874 */ 02875 if (AnySpbs()) 02876 SpbCheckRect(pwnd, &pwnd->rcWindow, DCX_WINDOW); 02877 02878 /* 02879 * Calculate ghrgnValid: 02880 * 02881 * ghrgnValid = OffsetRgn(rcBlt, -dxBlt, -dyBlt) & hrgnVisOld 02882 * ghrgnValid = ghrgnValid - ghrgnValidSum 02883 * OffsetRgn(ghrgnValid, dxBlt, dyBlt); 02884 * ghrgnValid = ghrgnValid - hrgnUpdate 02885 * ghrgnValid = ghrgnValid & hrgnVisNew; 02886 * 02887 * If either the old or new visrgns are empty, there 02888 * can be no valid bits... 02889 */ 02890 if (fsRgnEmpty & (RE_VISOLD | RE_VISNEW)) 02891 goto ValidEmpty; 02892 02893 /* 02894 * If the entire window is already completely invalid, blow out. 02895 */ 02896 if (pwnd->hrgnUpdate == HRGN_FULL) 02897 goto ValidEmpty; 02898 02899 /* 02900 * If the blt rectangle is empty, there can be no valid bits. 02901 */ 02902 if ((pcvr->rcBlt.right <= pcvr->rcBlt.left) || 02903 (pcvr->rcBlt.bottom <= pcvr->rcBlt.top)) { 02904 02905 goto ValidEmpty; 02906 } 02907 02908 GreSetRectRgn(ghrgnSWP1, 02909 pcvr->rcBlt.left - pcvr->dxBlt, 02910 pcvr->rcBlt.top - pcvr->dyBlt, 02911 pcvr->rcBlt.right - pcvr->dxBlt, 02912 pcvr->rcBlt.bottom - pcvr->dyBlt); 02913 02914 switch (IntersectRgn(ghrgnValid, ghrgnSWP1, pcvr->hrgnVisOld)) { 02915 case NULLREGION: 02916 case ERROR: 02917 goto ValidEmpty; 02918 break; 02919 } 02920 02921 if (!(fsSumEmpty & RE_VALIDSUM)) { 02922 switch (SubtractRgn(ghrgnValid, ghrgnValid, ghrgnValidSum)) { 02923 case NULLREGION: 02924 case ERROR: 02925 goto ValidEmpty; 02926 break; 02927 } 02928 } 02929 02930 if ((pcvr->dxBlt | pcvr->dyBlt) != 0) 02931 GreOffsetRgn(ghrgnValid, pcvr->dxBlt, pcvr->dyBlt); 02932 02933 /* 02934 * Now subtract off the update regions of ourself and any 02935 * non-clipchildren parents... 02936 */ 02937 pwndT = pwnd; 02938 02939 do { 02940 02941 if (pwndT->hrgnUpdate == HRGN_FULL) 02942 goto ValidEmpty; 02943 02944 if (pwndT->hrgnUpdate != NULL) { 02945 switch (SubtractRgn(ghrgnValid, ghrgnValid, pwndT->hrgnUpdate)) { 02946 case NULLREGION: 02947 case ERROR: 02948 goto ValidEmpty; 02949 break; 02950 } 02951 } 02952 02953 pwndT = pwndT->spwndParent; 02954 02955 } while (pwndT && !TestWF(pwndT, WFCLIPCHILDREN)); 02956 02957 /* 02958 * Subtract out the intermonitor blt pieces. 02959 */ 02960 if (pcvr->hrgnInterMonitor != NULL) { 02961 switch (SubtractRgn(ghrgnValid, ghrgnValid, pcvr->hrgnInterMonitor)) { 02962 case NULLREGION: 02963 case ERROR: 02964 goto ValidEmpty; 02965 } 02966 } 02967 02968 switch (IntersectRgn(ghrgnValid, ghrgnValid, ghrgnVisNew)) { 02969 case NULLREGION: 02970 case ERROR: 02971 02972 ValidEmpty: 02973 02974 fsRgnEmpty |= RE_VALID; 02975 break; 02976 } 02977 02978 /* 02979 * Before we restore the restore bits over part of our 02980 * image, we need to first copy any valid bits to their 02981 * final destination. 02982 */ 02983 if (!(fsRgnEmpty & RE_VALID) && ((pcvr->dxBlt | pcvr->dyBlt) != 0)) { 02984 02985 if (hdcScreen == NULL) 02986 hdcScreen = gpDispInfo->hdcScreen; 02987 02988 GreSelectVisRgn(hdcScreen, ghrgnValid, SVR_COPYNEW); 02989 02990 #ifdef _WINDOWBLT_NOTIFICATION_ 02991 /* 02992 * Define _WINDOWBLT_NOTIFICATION_ to turn on Window BLT notification. 02993 * This notification will set a special flag in the SURFOBJ passed to 02994 * drivers when the DrvCopyBits operation is called to move a window. 02995 * 02996 * See also: 02997 * ntgdi\gre\maskblt.cxx 02998 */ 02999 NtGdiBitBlt(hdcScreen, 03000 pcvr->rcBlt.left, 03001 pcvr->rcBlt.top, 03002 pcvr->rcBlt.right - pcvr->rcBlt.left, 03003 pcvr->rcBlt.bottom - pcvr->rcBlt.top, 03004 hdcScreen, 03005 pcvr->rcBlt.left - pcvr->dxBlt, 03006 pcvr->rcBlt.top - pcvr->dyBlt, 03007 SRCCOPY, 03008 0, 03009 GBB_WINDOWBLT); 03010 #else 03011 GreBitBlt(hdcScreen, 03012 pcvr->rcBlt.left, 03013 pcvr->rcBlt.top, 03014 pcvr->rcBlt.right - pcvr->rcBlt.left, 03015 pcvr->rcBlt.bottom - pcvr->rcBlt.top, 03016 hdcScreen, 03017 pcvr->rcBlt.left - pcvr->dxBlt, 03018 pcvr->rcBlt.top - pcvr->dyBlt, 03019 SRCCOPY, 03020 0); 03021 #endif 03022 } 03023 03024 /* 03025 * Now take care of any SPB bit restoration we need to do. 03026 * 03027 * Calculate the region to clip the RestoreSpb() output to: 03028 * 03029 * ghrgnInvalid = hrgnVisOld - hrgnVisNew 03030 */ 03031 if (TestWF(pwnd, WFHASSPB) && 03032 !(fsRgnEmpty & RE_VISOLD) && 03033 CombineOldNewVis(ghrgnInvalid, pcvr->hrgnVisOld, ghrgnVisNew, RGN_DIFF, fsRgnEmpty)) { 03034 03035 UINT retRSPB; 03036 03037 /* 03038 * Perform SPB bits restore. We pass RestoreSpb() the region of 03039 * the part of the SPB that got uncovered by this window rearrangement. 03040 * It tries to restore as much of this area as it can from the SPB, 03041 * and returns the area that could not be restored from the SPB. 03042 * 03043 * The device driver's SaveBitmap() function does not clip at all 03044 * when it restores bits, which means that it might write bits 03045 * in an otherwise valid area. This means that the invalid area 03046 * returned by RestoreSpb() may actually be LARGER than the original 03047 * hrgnSpb passed in. 03048 * 03049 * RestoreSpb() returns TRUE if some part of ghrgnInvalid needs 03050 * to be invalidated. 03051 */ 03052 if ((retRSPB = RestoreSpb(pwnd, ghrgnInvalid, &hdcScreen)) == RSPB_NO_INVALIDATE) { 03053 03054 /* 03055 * If hrgnVisNew is empty, then we know the whole invalid 03056 * area is empty. 03057 */ 03058 if (fsRgnEmpty & RE_VISNEW) 03059 goto InvalidEmpty; 03060 03061 } else if (retRSPB == RSPB_INVALIDATE_SSB) { 03062 03063 /* 03064 * If RestoreSpb actually invalidated some area and we already 03065 * have a ghrgnValidSum then subtract the newly invalidated area 03066 * Warning this region subtract is not in the Win 3.1 code but 03067 * they probably did not have the problem as severe because their 03068 * drivers were limited to one level of SaveScreenBits 03069 */ 03070 if (!(fsSumEmpty & RE_VALIDSUM)) 03071 SubtractRgn(ghrgnValidSum, ghrgnValidSum, ghrgnInvalid); 03072 } 03073 03074 /* 03075 * ghrgnInvalid += hrgnVisNew 03076 */ 03077 if (!(fsRgnEmpty & RE_VISNEW)) 03078 UnionRgn(ghrgnInvalid, ghrgnInvalid, ghrgnVisNew); 03079 03080 /* 03081 * Some of the area we calculated as valid may have gotten 03082 * obliterated by the SPB restore. To ensure this isn't 03083 * the case, subtract off the ghrgnInvalid returned by RestoreSpb. 03084 */ 03085 // LATER mikeke VALIDSUM / ghrgnValid mismatch 03086 if (!(fsRgnEmpty & RE_VALIDSUM)) { 03087 switch (SubtractRgn(ghrgnValid, ghrgnValid, ghrgnInvalid)) { 03088 case NULLREGION: 03089 case ERROR: 03090 fsRgnEmpty |= RE_VALIDSUM; 03091 break; 03092 } 03093 } 03094 03095 } else { 03096 03097 /* 03098 * No SPB. Simple ghrgnInvalid calculation is: 03099 * 03100 * ghrgnInvalid = hrgnVisNew + hrgnVisOld; 03101 */ 03102 if (pcvr->hrgnVisOld == NULL) { 03103 03104 /* 03105 * If we couldn't create hrgnVisOld, then 03106 * invalidate the entire parent 03107 */ 03108 SetRectRgnIndirect(ghrgnInvalid, &pwndParent->rcWindow); 03109 } else { 03110 03111 if (!CombineOldNewVis(ghrgnInvalid, 03112 pcvr->hrgnVisOld, 03113 ghrgnVisNew, 03114 RGN_OR, 03115 fsRgnEmpty)) { 03116 03117 goto InvalidEmpty; 03118 } 03119 } 03120 } 03121 03122 /* 03123 * Update ghrgnValidSum 03124 * 03125 * ghrgnValidSum += ghrgnValid 03126 */ 03127 if (!(fsRgnEmpty & RE_VALID)) { 03128 03129 /* 03130 * If the sum region is empty, then COPY instead of OR 03131 */ 03132 if (fsSumEmpty & RE_VALIDSUM) 03133 CopyRgn(ghrgnValidSum, ghrgnValid); 03134 else 03135 UnionRgn(ghrgnValidSum, ghrgnValid, ghrgnValidSum); 03136 fsSumEmpty &= ~RE_VALIDSUM; 03137 } 03138 03139 /* 03140 * Subtract ghrgnValidSum from ghrgnInvalid if non-empty, 03141 * otherwise use ghrgnValid. Note, ghrgnValid has been OR'ed 03142 * into ghrgnValidSum already. 03143 */ 03144 if (!(fsSumEmpty & RE_VALIDSUM) || !(fsRgnEmpty & RE_VALID)) { 03145 switch (SubtractRgn(ghrgnInvalid, ghrgnInvalid, 03146 !(fsSumEmpty & RE_VALIDSUM) ? ghrgnValidSum : ghrgnValid)) { 03147 case NULLREGION: 03148 case ERROR: 03149 InvalidEmpty: 03150 fsRgnEmpty |= RE_INVALID; 03151 break; 03152 } 03153 } 03154 03155 /* 03156 * If there are any SPB bits left over, it wasn't just created 03157 * (SWP_SHOWWINDOW), and an operation occured that invalidates 03158 * the spb bits, get rid of the spb. A move, size, hide, or 03159 * zorder operation will invalidate the bits. Note that we do this 03160 * outside of the SWP_NOREDRAW case in case the guy set that flag 03161 * when he had some SPB bits lying around. 03162 */ 03163 if (TestWF(pwnd, WFHASSPB) && !(pcvr->pos.flags & SWP_SHOWWINDOW) && 03164 (pcvr->pos.flags & 03165 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW)) 03166 != (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)) { 03167 03168 FreeSpb(FindSpb(pwnd)); 03169 } 03170 03171 /* 03172 * Finally, free up hrgnVisOld. 03173 */ 03174 if (pcvr->hrgnVisOld) { 03175 GreDeleteObject(pcvr->hrgnVisOld); 03176 pcvr->hrgnVisOld = NULL; 03177 } 03178 03179 /* 03180 * BACKWARD COMPATIBILITY HACK 03181 * 03182 * In 3.0, a ShowWindow() NEVER invalidated any of the children. 03183 * It would invalidate the parent and the window being shown, but 03184 * no others. 03185 * 03186 * We only apply hack (a) to 3.0 apps when all the windows involved 03187 * are doing a SWP_SHOWWINDOW: if any aren't, then we have to make 03188 * sure the siblings are invalidated too. So, we count the windows 03189 * doing a SHOWWINDOW and compare it to the total count in the CVR. 03190 */ 03191 if (!TestWF(pwnd, WFWIN31COMPAT) && (pcvr->pos.flags & SWP_SHOWWINDOW)) 03192 cwndShowing++; 03193 03194 /* 03195 * Update ghrgnInvalidSum: 03196 * 03197 * ghrgnInvalidSum += ghrgnInvalid 03198 */ 03199 if (!(fsRgnEmpty & RE_INVALID)) { 03200 03201 /* 03202 * BACKWARD COMPATIBILITY HACK 03203 * 03204 * In many cases including ShowWindow, CS_V/HREDRAW, 03205 * SWP_NOCOPYBITS, etc, 3.0 always invalidated the window with 03206 * (HRGN)1, regardless of how it was clipped by children, siblings, 03207 * or parents. Besides being more efficient, this caused child 03208 * windows that would otherwise not get update regions to get 03209 * invalidated -- see the hack notes in InternalInvalidate2. 03210 * 03211 * This is a performance hack (usually) because (HRGN)1 can save 03212 * a lot of region calculations in the normal case. So, we do this 03213 * for 3.1 apps as well as 3.0 apps. 03214 * 03215 * We detect the case as follows: invalid area not empty, 03216 * valid area empty, and new visrgn not empty. 03217 */ 03218 if ((fsRgnEmpty & RE_VALID) && !(fsRgnEmpty & RE_VISNEW)) { 03219 03220 /* 03221 * With the parameters we use InternalInvalidate() does 03222 * not leave the critical section 03223 */ 03224 BEGINATOMICCHECK(); 03225 xxxInternalInvalidate(pwnd, 03226 HRGN_FULL, 03227 RDW_INVALIDATE | 03228 RDW_FRAME | 03229 RDW_ERASE | 03230 RDW_ALLCHILDREN); 03231 ENDATOMICCHECK(); 03232 } 03233 03234 /* 03235 * If the sum region is empty, then COPY instead of OR 03236 */ 03237 if (fsSumEmpty & RE_INVALIDSUM) { 03238 03239 /* 03240 * HACK ALERT: 03241 * If this is the last pass through the loop (cIter == 0) 03242 * and ghrgnInvalidSum is currently empty, 03243 * then instead of copying ghrgnInvalid to ghrgnInvalidSum, 03244 * just set hrgnInvalidate to ghrgnInvalid. This saves 03245 * a region copy in the single-window case. 03246 */ 03247 if (cIter == 0) { 03248 hrgnInvalidate = ghrgnInvalid; 03249 } else { 03250 CopyRgn(ghrgnInvalidSum, ghrgnInvalid); 03251 } 03252 03253 } else { 03254 03255 UnionRgn(ghrgnInvalidSum, ghrgnInvalid, ghrgnInvalidSum); 03256 } 03257 03258 fsSumEmpty &= ~RE_INVALIDSUM; 03259 } 03260 } // for (... pcvr ...) 03261 03262 /* 03263 * Now, invalidate as needed. 03264 */ 03265 if (!(fsSumEmpty & RE_INVALIDSUM)) { 03266 03267 /* 03268 * BACKWARD COMPATIBILITY HACK (see above) 03269 * 03270 * If all the windows involved were being shown, then 03271 * invalidate the parent ONLY -- don't enumerate any children. 03272 * (the windows involved have already been invalidated above). 03273 * This hack is only applied to 3.0 apps (see above). 03274 */ 03275 03276 /* 03277 * More hack-o-rama. On Win3.1, the desktop paint would only 03278 * repaint those portions inside the rect returned from GetClipBox(). 03279 * Dialogs with spbs outside the rect returned from GetClipBox() would 03280 * not get their spbs invalidated until later, when you clicked on 03281 * them to make them active. The only dialog that wouldn't really loose 03282 * its bits is the control panel desktop dialog, which would restore 03283 * its bad bits when it went away (in certain configurations). On 03284 * NT, the desktop would repaint and then the dialog would go away. 03285 * On Win3.1, the dialog would go away and then the desktop would 03286 * repaint. On NT, because of preemption and little differences in 03287 * painting order between applications, there was an opportunity to 03288 * put bad bits on the screen, on Win3.1 there wasn't. 03289 * 03290 * Now... the below code that passes RDW_NOCHILDREN only gets executed 03291 * if the app is marked as a win3.0 app (latest CorelDraw, also wep 03292 * freecell demonstrates the same problem). This code would get 03293 * executed when a dialog got shown. So for a win3.0 app, spb would get 03294 * saved, the dialog would get shown, the desktop invalidated, the 03295 * desktop would paint, the spb would get clobbered. In short, when 03296 * a win3.0 app would put up a dialog, all spbs would get freed because 03297 * of the new (and correct) way the desktop repaints. 03298 * 03299 * So the desktop check hack will counter-act the invalidate 03300 * RDW_NOCHILDREN case if all windows are hiding / showing and the 03301 * desktop is being invalidated. Note that in the no RDW_NOCHILDREN 03302 * case, the invalid area gets distributed to the children first (in 03303 * this case, children of the desktop), so if the children cover the 03304 * desktop, the desktop won't get any invalid region, which is what 03305 * we want. - scottlu 03306 */ 03307 03308 /* 03309 * With the parameters we use InternalInvalidate() does not leave 03310 * the critical section 03311 */ 03312 03313 DWORD dwFlags = RDW_INVALIDATE | RDW_ERASE; 03314 if (cwndShowing == psmwp->ccvr && 03315 pwndParent != PWNDDESKTOP(pwndParent)) { 03316 dwFlags |= RDW_NOCHILDREN; 03317 } else { 03318 dwFlags |= RDW_ALLCHILDREN; 03319 } 03320 if (fInvalidateLayers) { 03321 dwFlags |= RDW_INVALIDATELAYERS; 03322 } 03323 03324 BEGINATOMICCHECK(); 03325 xxxInternalInvalidate(pwndParent, hrgnInvalidate, dwFlags); 03326 ENDATOMICCHECK(); 03327 } 03328 03329 /* 03330 * Since zzzInvalidateDCCache was called with IDC_MOVEBLT specified, 03331 * we must complete the WNDOBJ notification with a call to 03332 * GreClientRgnDone. 03333 * 03334 * Note: in zzzInvalidateDCCache, it is necessary to call 03335 * GreClientRgnUpdated even if gcountPWO is 0. However, 03336 * GreClientRgnDone only does something if gcountPWO is non-zero, 03337 * so we can optimize slightly. 03338 */ 03339 if (gcountPWO != 0) { 03340 GreClientRgnDone(GCR_WNDOBJEXISTS); 03341 } 03342 03343 UnlockAndExit: 03344 03345 /* 03346 * If necessary, release the screen DC 03347 */ 03348 if (hdcScreen != NULL) { 03349 03350 /* 03351 * Reset the visrgn before we go... 03352 */ 03353 GreSelectVisRgn(hdcScreen, NULL, SVR_DELETEOLD); 03354 03355 /* 03356 * Make sure that the drawing we did in this DC does not affect 03357 * any SPBs. Clear the dirty rect. 03358 */ 03359 GreGetBounds(hdcScreen, NULL, 0); // NULL means reset 03360 } 03361 03362 /* 03363 * All the dirty work is done. Ok to leave the critsects we entered 03364 * earlier and dispatch any deferred Window Event notifications. 03365 */ 03366 GreUnlockDisplay(gpDispInfo->hDev); 03367 zzzEndDeferWinEventNotify(); 03368 03369 return fSyncPaint; 03370 } 03371 03372 /***************************************************************************\ 03373 * xxxHandleWindowPosChanged 03374 * 03375 * DefWindowProc() HandleWindowPosChanged handler. 03376 * 03377 * History: 03378 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 03379 \***************************************************************************/ 03380 03381 VOID xxxHandleWindowPosChanged( 03382 PWND pwnd, 03383 PWINDOWPOS ppos) 03384 { 03385 CheckLock(pwnd); 03386 03387 if (!(ppos->flags & SWP_NOCLIENTMOVE)) { 03388 POINT pt; 03389 PWND pwndParent; 03390 03391 pt.x = pwnd->rcClient.left; 03392 pt.y = pwnd->rcClient.top; 03393 03394 pwndParent = pwnd->spwndParent; 03395 UserAssert(pwndParent); 03396 03397 if (pwndParent != PWNDDESKTOP(pwnd)) { 03398 pt.x -= pwndParent->rcClient.left; 03399 pt.y -= pwndParent->rcClient.top; 03400 } 03401 03402 xxxSendMessage( 03403 pwnd, 03404 WM_MOVE, 03405 FALSE, 03406 MAKELONG(pt.x, pt.y)); 03407 } 03408 03409 if ((ppos->flags & SWP_STATECHANGE) || !(ppos->flags & SWP_NOCLIENTSIZE)) { 03410 03411 if (TestWF(pwnd, WFMINIMIZED)) 03412 xxxSendSizeMessage(pwnd, SIZEICONIC); 03413 else if (TestWF(pwnd, WFMAXIMIZED)) 03414 xxxSendSizeMessage(pwnd, SIZEFULLSCREEN); 03415 else 03416 xxxSendSizeMessage(pwnd, SIZENORMAL); 03417 } 03418 } 03419 03420 /***************************************************************************\ 03421 * PWND GetRealOwner(pwnd) 03422 * 03423 * Returns the owner of pwnd, normalized so that it shares the same parent 03424 * of pwnd. 03425 * 03426 * History: 03427 * 04-Mar-1992 MikeKe From win31 03428 \***************************************************************************/ 03429 03430 PWND GetRealOwner( 03431 PWND pwnd) 03432 { 03433 PWND pwndParent = pwnd->spwndParent; 03434 03435 /* 03436 * A frame window owned by itself is "unowned" 03437 */ 03438 if (pwnd != pwnd->spwndOwner && (pwnd = pwnd->spwndOwner) != NULL) { 03439 03440 /* 03441 * The NULL test is in case the owner is higher than the 03442 * passed in window (e.g. your owner IS your parent) 03443 */ 03444 while (pwnd != NULL && pwnd->spwndParent != pwndParent) 03445 pwnd = pwnd->spwndParent; 03446 } 03447 03448 return pwnd; 03449 } 03450 03451 /***************************************************************************\ 03452 * 03453 * Starting at pwnd (or pwndParent->spwndChild if pwnd == NULL), find 03454 * next window owned by pwndOwner 03455 * 03456 * History: 03457 * 04-Mar-1992 MikeKe From win31 03458 \***************************************************************************/ 03459 03460 PWND NextOwnedWindow( 03461 PWND pwnd, 03462 PWND pwndOwner, 03463 PWND pwndParent) 03464 { 03465 if (pwnd == NULL) { 03466 pwnd = pwndParent->spwndChild; 03467 goto loop; 03468 } 03469 03470 while ((pwnd = pwnd->spwndNext) != NULL) { 03471 03472 loop: 03473 03474 /* 03475 * If owner of pwnd is pwndOwner, break out of here... 03476 */ 03477 if (pwndOwner == GetRealOwner(pwnd)) 03478 break; 03479 } 03480 03481 return pwnd; 03482 } 03483 03484 /***************************************************************************\ 03485 * 03486 * Recursively enumerate owned windows starting from pwndRoot, 03487 * to set the state of WEFTOPMOST. Doesn't actually diddle 03488 * this bit yet: the work gets done in zzzChangeStates(): 03489 * instead we just set the WFTOGGLETOPMOST bit as appropriate. 03490 * 03491 * We can't diddle the state until the Z order changes are done, 03492 * or else GetTopMostWindow() and the like will do the wrong thing. 03493 * 03494 * History: 03495 * 04-Mar-1992 MikeKe From win31 03496 \***************************************************************************/ 03497 03498 VOID SetTopmost( 03499 PWND pwndRoot, 03500 BOOL fTopmost) 03501 { 03502 PWND pwnd; 03503 03504 /* 03505 * If the new state is different than the current state, 03506 * then set the TOGGLETOPMOST bit, so it'll get toggled 03507 * in ChangeStates(). 03508 */ 03509 UserAssert((fTopmost == TRUE) || (fTopmost == FALSE)); 03510 if (!!TestWF(pwndRoot, WEFTOPMOST) ^ fTopmost) { 03511 SetWF(pwndRoot, WFTOGGLETOPMOST); 03512 } else { 03513 ClrWF(pwndRoot, WFTOGGLETOPMOST); 03514 } 03515 03516 pwnd = NULL; 03517 while (pwnd = NextOwnedWindow(pwnd, pwndRoot, pwndRoot->spwndParent)) { 03518 SetTopmost(pwnd, fTopmost); 03519 } 03520 03521 } 03522 03523 /* 03524 * LATER: (hiroyama) #88810 03525 * The IME code here broke the US regression test, so backing it up until we 03526 * hit the problem on NT. 03527 */ 03528 #ifdef LATER 03529 /***************************************************************************\ 03530 * IsBottomIMEWindow() 03531 * 03532 * returns TRUE if pwnd is IME window and its toplevel window is BOTTOMMOST 03533 * 03534 * Ported: 18-Apr-1997 Hiroyama from Memphis 03535 \***************************************************************************/ 03536 BOOL IsBottomIMEWindow( 03537 PWND pwnd) 03538 { 03539 if (TestCF(pwnd, CFIME) || 03540 (pwnd->pcls->atomClassName == gpsi->atomSysClass[ICLS_IME])) { 03541 PWND pwndT2 = pwnd; 03542 PWND pwndTopOwner = pwnd; 03543 PWND pwndDesktop; 03544 03545 if (grpdeskRitInput == NULL || grpdeskRitInput->pDeskInfo == NULL) { 03546 // Desktop is being created or not yet created 03547 RIPMSG1(RIP_WARNING, "IsBottomIMEWindow: Desktop is being created or not yet created. pwnd=%#p\n", 03548 pwnd); 03549 return FALSE; 03550 } 03551 03552 pwndDesktop = grpdeskRitInput->pDeskInfo->spwnd; 03553 03554 UserAssert(pwndDesktop); 03555 03556 /* 03557 * search the toplevel owner window of the IME window. 03558 */ 03559 while (pwndT2 && (pwndT2 != pwndDesktop)) { 03560 pwndTopOwner = pwndT2; 03561 pwndT2 = pwndT2->spwndOwner; 03562 } 03563 /* 03564 * TRUE if the toplevel owner window of the IME window is BOTTOMMOST 03565 */ 03566 return (BOOL)(TestWF(pwndTopOwner, WFBOTTOMMOST)); 03567 } 03568 return FALSE; 03569 } 03570 03571 /***************************************************************************\ 03572 * ImeCheckBottomIMEWindow() 03573 * 03574 * returns TRUE if pwndT->spwndNext's owner is BOTTOMMOST 03575 * 03576 * Ported: 18-Apr-1997 Hiroyama from Memphis 03577 \***************************************************************************/ 03578 BOOL ImeCheckBottomIMEWindow( 03579 PWND pwndT) 03580 { 03581 /* 03582 * pwnd is IME window and its toplevel window is BOTTOMMOST 03583 */ 03584 PWND pwndDesktop; 03585 PWND pwndT2 = pwndT->spwndNext; 03586 PWND pwndTopOwner = pwndT2; 03587 03588 UserAssert(grpdeskRipInput != NULL && grpdeskRitInput->pDeskInfo != NULL); 03589 pwndDesktop = grpdeskRitInput->pDeskInfo->spwnd; 03590 03591 /* 03592 * check if toplevel owner window of pwnd->spwndNext is bottommost 03593 */ 03594 while (pwndT2 && (pwndT2 != pwndDesktop)) { 03595 pwndTopOwner = pwndT2; 03596 pwndT2 = pwndT2->spwndOwner; 03597 } 03598 03599 if (pwndTopOwner && TestWF(pwndTopOwner, WFBOTTOMMOST)) { 03600 /* 03601 * yes, pwndT is the last one whose toplevel window is *not* BOTTOMMOST 03602 */ 03603 return TRUE; 03604 } 03605 03606 return FALSE; 03607 } 03608 #endif // LATER 03609 03610 /***************************************************************************\ 03611 * CalcForegroundInsertAfter 03612 * 03613 * Calculates where to zorder a window that doesn't belong to the foreground 03614 * thread and is not topmost but wants to come to the top. This routine 03615 * calculates what "top" means under those conditions. 03616 * 03617 * 14-Sep-1992 ScottLu Created. 03618 \***************************************************************************/ 03619 03620 PWND CalcForegroundInsertAfter( 03621 PWND pwnd) 03622 { 03623 PWND pwndInsertAfter, pwndInsertAfterSave; 03624 PWND pwndT; 03625 PTHREADINFO ptiTop; 03626 #ifdef LATER // see #88810 03627 BOOLEAN fImeOwnerIsBottom = FALSE; 03628 #endif 03629 03630 /* 03631 * If we're allowing this application to make this top 03632 * level window foreground active, then this app may 03633 * not be foreground yet, but we want any windows it 03634 * zorders to appear on top because it is probably about 03635 * to activate them (this is a guess!) If this is the case, 03636 * let it do what it wants. A good example of this is an 03637 * application like toolbook that creates a window without a 03638 * caption, doesn't activate it, and wants that to appear on top. 03639 */ 03640 03641 if (TestWF(pwnd, WFBOTTOMMOST)) { 03642 pwndInsertAfter = GetLastNonBottomMostWindow(pwnd, TRUE); 03643 } else { 03644 pwndInsertAfter = GetLastTopMostWindow(); 03645 #ifdef LATER // see #88810 03646 if (IS_IME_ENABLED()) { 03647 fImeOwnerIsBottom = IsBottomIMEWindow(pwnd); 03648 if (fImeOwnerIsBottom) { 03649 for (pwndT = pwndInsertAfter; pwndT; pwndT = pwndT->spwndNext) { 03650 if (ImeCheckBottomIMEWindow(pwndT)) { 03651 /* 03652 * toplevel owner of pwndT->spwndNext is BOTTOMMOST 03653 */ 03654 break; 03655 } 03656 pwndInsertAfter = pwndT; 03657 } 03658 } 03659 } 03660 #endif // LATER 03661 } 03662 03663 03664 if (!TestwndChild(pwnd)) { 03665 // if (hwnd->hwndParent == hwndDesktop) -- Chicago conditional FritzS 03666 03667 if ((GETPTI(pwnd)->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE) || 03668 (GETPTI(pwnd)->ppi->W32PF_Flags & W32PF_ALLOWFOREGROUNDACTIVATE)) { 03669 03670 return pwndInsertAfter; 03671 } 03672 } 03673 03674 /* 03675 * If there is no foreground thread or this pwnd is of the foreground 03676 * thread, then let it come to the top. 03677 */ 03678 if (gpqForeground == NULL) 03679 return pwndInsertAfter; 03680 03681 if (GETPTI(pwnd)->pq == gpqForeground) 03682 return pwndInsertAfter; 03683 03684 /* 03685 * This thread is not of the foreground queue, so search for a window 03686 * of this thread to zorder above. 03687 */ 03688 pwndT = ((pwndInsertAfter == NULL) ? 03689 pwnd->spwndParent->spwndChild : 03690 pwndInsertAfter); 03691 03692 /* 03693 * Remember the top insert after in case this first loop 03694 * fails to find a window 03695 */ 03696 pwndInsertAfterSave = pwndInsertAfter; 03697 03698 for (; pwndT != NULL; pwndT = pwndT->spwndNext) { 03699 03700 /* 03701 * This window wants to come to the top if possible. 03702 * If we're passing our own window, get out of this loop: 03703 * by now we already have pwndInsertAfter set up to the 03704 * last available window to insert after. 03705 */ 03706 if ((pwndT == pwnd) || TestWF(pwndT, WFBOTTOMMOST)) 03707 break; 03708 03709 /* 03710 * If this window isn't owned by this thread, continue. 03711 */ 03712 if (GETPTI(pwndT) != GETPTI(pwnd)) { 03713 pwndInsertAfter = pwndT; 03714 continue; 03715 } 03716 03717 /* 03718 * Don't want a window zordering below one of its top most windows 03719 * if it isn't foreground. 03720 */ 03721 if (TestWF(pwndT, WEFTOPMOST)) { 03722 pwndInsertAfter = pwndT; 03723 continue; 03724 } 03725 03726 #ifdef LATER // see #88810 03727 // FE_IME 03728 if (fImeOwnerIsBottom && ImeCheckBottomIMEWindow(pwndT)) { 03729 /* 03730 * owner of pwndT->spwndNext is BOTTOMMOST 03731 * so pwndT is the last one whose owner is not bottommost. 03732 */ 03733 pwndInsertAfter = pwndT; 03734 continue; 03735 } 03736 // end FE_IME 03737 #endif 03738 03739 /* 03740 * Ok to change zorder of top level windows because of 03741 * invisible windows laying around, but not children: 03742 * applications would go nuts if we did this. 03743 */ 03744 if (!TestwndChild(pwndT)) { 03745 if (!TestWF(pwndT, WFVISIBLE)) { 03746 pwndInsertAfter = pwndT; 03747 continue; 03748 } 03749 } 03750 03751 break; 03752 } 03753 03754 /* 03755 * If we didn't find a window in the previous loop, 03756 * it means that the thread has no 03757 * other sibling windows, so we need to put it after the 03758 * foreground window (foreground thread). Search for the 03759 * first unowned window of the foreground app to zorder 03760 * after. 03761 */ 03762 if ((pwndT == NULL) || TestWF(pwndT, WFBOTTOMMOST)) { 03763 /* 03764 * This is our first guess in case nothing works out. 03765 */ 03766 pwndInsertAfter = pwndInsertAfterSave; 03767 03768 /* 03769 * Start below the last topmost or from the top if no 03770 * topmost windows. 03771 */ 03772 if ((pwndT = pwndInsertAfter) == NULL) 03773 pwndT = pwnd->spwndParent->spwndChild; 03774 03775 /* 03776 * ptiTop is the pti of the active window in the foreground queue! 03777 */ 03778 ptiTop = NULL; 03779 if (gpqForeground->spwndActive != NULL) 03780 ptiTop = GETPTI(gpqForeground->spwndActive); 03781 03782 for (; pwndT != NULL; pwndT = pwndT->spwndNext) { 03783 03784 if (TestWF(pwndT, WFBOTTOMMOST)) 03785 break; 03786 03787 /* 03788 * If not the top most thread, continue. 03789 */ 03790 if (GETPTI(pwndT) != ptiTop) 03791 continue; 03792 03793 /* 03794 * Found one of the foreground thread. Remember this 03795 * as the next best guess. Try to find an unowned 03796 * visible window, which would indicate the main 03797 * window of the foreground thread. If owned, 03798 * continue. 03799 */ 03800 if (pwndT->spwndOwner != NULL) { 03801 pwndInsertAfter = pwndT; 03802 continue; 03803 } 03804 03805 /* 03806 * Unowned and of the foreground thread. Is it visible? 03807 * If not, get out of here. 03808 */ 03809 if (!TestWF(pwndT, WFVISIBLE)) 03810 continue; 03811 #ifdef LATER // see #88810 03812 // FE_IME 03813 if (fImeOwnerIsBottom && ImeCheckBottomIMEWindow(pwndT)) { 03814 continue; 03815 } 03816 // end FE_IME 03817 #endif 03818 03819 /* 03820 * Best possible match so far: unowned visible window 03821 * of the foreground thread. 03822 */ 03823 pwndInsertAfter = pwndT; 03824 } 03825 } 03826 03827 UserAssert(pwnd != pwndInsertAfter); 03828 03829 return pwndInsertAfter; 03830 } 03831 03832 /***************************************************************************\ 03833 * GetTopMostInsertAfter 03834 * 03835 * We don't want any one to get in front of a hard error box, except menus, 03836 * screen savers, etc. 03837 * 03838 * Don't call it directly, use the GETTOPMOSTINSERTAFTER macro to avoid 03839 * the call when there is no hard error box up (gHardErrorHandler.pti == NULL). 03840 * 03841 * 04-25-96 GerardoB Created 03842 \***************************************************************************/ 03843 PWND GetTopMostInsertAfter (PWND pwnd) 03844 { 03845 PWND pwndT; 03846 PTHREADINFO ptiCurrent; 03847 PDESKTOP pdesk; 03848 WORD wfnid; 03849 03850 /* 03851 * If you hit this assertion, you're probably not using the 03852 * GETTOPMOSTINSERTAFTER macro to make this call. 03853 */ 03854 UserAssert(gHardErrorHandler.pti != NULL); 03855 /* 03856 * pwnd: Menu and switch (ALT-TAB) windows can go on top. 03857 */ 03858 wfnid = GETFNID(pwnd); 03859 if ((wfnid == FNID_MENU) || (wfnid == FNID_SWITCH)) { 03860 return NULL; 03861 } 03862 03863 /* 03864 * pti: If this is the error handler thread, don't bother any longer. 03865 * Screen saver can go on top too. 03866 */ 03867 ptiCurrent = PtiCurrent(); 03868 UserAssert(ptiCurrent != NULL); 03869 03870 if (ptiCurrent == gHardErrorHandler.pti || (ptiCurrent->ppi->W32PF_Flags & W32PF_SCREENSAVER)) { 03871 return NULL; 03872 } 03873 03874 /* 03875 * pdesk: Leave the logon desktop alone. 03876 * Make sure the hard error box is on this desktop 03877 */ 03878 pdesk = ptiCurrent->rpdesk; 03879 UserAssert(pdesk != NULL); 03880 UserAssert(pdesk->rpwinstaParent); 03881 UserAssert(pdesk->rpwinstaParent->pTerm); 03882 03883 if ((pdesk == grpdeskLogon) 03884 || (pdesk != gHardErrorHandler.pti->rpdesk)) { 03885 return NULL; 03886 } 03887 03888 /* 03889 * Walk the window list looking for the hard error box. 03890 * Start searching from the current desktop's first child. 03891 * Note that the harderror box migth not be created yet. 03892 */ 03893 UserAssert(pdesk->pDeskInfo); 03894 UserAssert(pdesk->pDeskInfo->spwnd); 03895 03896 for (pwndT = pdesk->pDeskInfo->spwnd->spwndChild; 03897 pwndT != NULL; pwndT = pwndT->spwndNext) { 03898 03899 /* 03900 * Hard error boxes are always top most. 03901 */ 03902 if (!TestWF(pwndT, WEFTOPMOST)) { 03903 break; 03904 } 03905 03906 /* 03907 * If this window was created by the hard error handler thread, 03908 * then this is it 03909 */ 03910 if (gHardErrorHandler.pti == GETPTI(pwndT)) { 03911 return pwndT; 03912 } 03913 } 03914 03915 return NULL; 03916 } 03917 03918 /***************************************************************************\ 03919 * 03920 * This routine maps the special HWND_* values of ppos->hwndInsertAfter, 03921 * and returns whether or not the window's owner group should be labelled 03922 * TOPMOST or not, or left alone. 03923 * 03924 * Here are the TOPMOST rules. If pwndInsertAfter is: 03925 * 03926 * 1. HWND_BOTTOM == (HWND)1: 03927 * 03928 * The group is made non-TOPMOST. 03929 * 03930 * 2. HWND_TOPMOST == (HWND)-1: 03931 * 03932 * hwndInsertAfter is set to HWND_TOP, and the group is made TOPMOST. 03933 * 03934 * 3. HWND_NOTOPMOST == (HWND)-2: 03935 * 03936 * Treated same as HWND_TOP, except that the TOPMOST bit is cleared. 03937 * and the entire group is made non-topmost. 03938 * Used to make a topmost window non-topmost, but still leave it at 03939 * the top of the non-topmost pile. 03940 * The group is not changed if the window is already non-topmost. 03941 * 03942 * 4. HWND_TOP == (HWND)NULL: 03943 * 03944 * pwndInsertAfter is set to the last TOPMOST window if pwnd 03945 * is not itself TOPMOST. If pwnd IS TOPMOST, then pwndInsertAfter 03946 * remains HWND_TOP. 03947 * 03948 * 5. A TOPMOST window: 03949 * 03950 * If a window is being inserted among the TOPMOST windows, then 03951 * the group becomes topmost too, EXCEPT if it's being inserted behind 03952 * the bottom-most topmost window: in that case the window retains 03953 * its current TOPMOST bit. 03954 * 03955 * 6. A non-TOPMOST window: 03956 * 03957 * If a window is being inserted among non-TOPMOST windows, the group is made 03958 * non-TOPMOST and inserted there. 03959 * 03960 * Whenever a group is made TOPMOST, only that window and its ownees are made 03961 * topmost. When a group is made NOTOPMOST, the entire window is made non-topmost. 03962 * 03963 * This routine must NOT set SWP_NOZORDER if the topmost state is changing: 03964 * this would prevent the topmost bits from getting toggled in ChangeStates. 03965 * 03966 * History: 03967 * 04-Mar-1992 MikeKe From win31 03968 \***************************************************************************/ 03969 03970 int CheckTopmost( 03971 PWINDOWPOS ppos) 03972 { 03973 PWND pwnd, pwndInsertAfter, pwndT; 03974 03975 /* 03976 * BACKWARD COMPATIBILITY HACK 03977 * 03978 * If we're activating a window and Z-ordering too, we must ignore the 03979 * specified Z order and bring the window to the top, EXCEPT in the 03980 * following conditions: 03981 * 03982 * 1. The window is already active (in which case, the activation code 03983 * will not be bringing the window to the top) 03984 * 03985 * 2. HWND_TOP or HWND_NOTOPMOST is specified. This allows us to 03986 * activate and move to topmost or nontopmost at the same time. 03987 * 03988 * NOTE: It would have been possible to modify ActivateWindow() to 03989 * take a flag to prevent it from ever doing the BringWindowToTop, 03990 * thus allowing SetWindowPos() to properly honor pwndInsertBehind 03991 * AND activation, but this change was considered too late in the 03992 * game -- there could be problems with existing 3.1 apps, such as 03993 * PenWin, etc. 03994 */ 03995 pwnd = PW(ppos->hwnd); 03996 if (!(ppos->flags & SWP_NOACTIVATE) && 03997 !(ppos->flags & SWP_NOZORDER) && 03998 (ppos->hwndInsertAfter != HWND_TOPMOST && 03999 ppos->hwndInsertAfter != HWND_NOTOPMOST) && 04000 (pwnd != GETPTI(pwnd)->pq->spwndActive)) { 04001 ppos->hwndInsertAfter = HWND_TOP; 04002 } 04003 04004 /* 04005 * If we're not Z-ordering, don't do anything. 04006 */ 04007 if (ppos->flags & SWP_NOZORDER) 04008 return CTM_NOCHANGE; 04009 04010 04011 if (ppos->hwndInsertAfter == HWND_BOTTOM) { 04012 04013 return CTM_NOTOPMOST; 04014 04015 } else if (ppos->hwndInsertAfter == HWND_NOTOPMOST) { 04016 04017 /* 04018 * If currently topmost, move to top of non-topmost list. 04019 * Otherwise, no change. 04020 * 04021 * Note that we don't set SWP_NOZORDER -- we still need to 04022 * check the TOGGLETOPMOST bits in ChangeStates() 04023 */ 04024 if (TestWF(pwnd, WEFTOPMOST)) { 04025 04026 pwndT = GetLastTopMostWindow(); 04027 ppos->hwndInsertAfter = HW(pwndT); 04028 04029 if (ppos->hwndInsertAfter == ppos->hwnd) { 04030 pwndT = _GetWindow(pwnd, GW_HWNDPREV); 04031 ppos->hwndInsertAfter = HW(pwndT); 04032 } 04033 04034 } else { 04035 04036 pwndT = _GetWindow(pwnd, GW_HWNDPREV); 04037 ppos->hwndInsertAfter = HW(pwndT); 04038 } 04039 04040 return CTM_NOTOPMOST; 04041 04042 } else if (ppos->hwndInsertAfter == HWND_TOPMOST) { 04043 pwndT = GETTOPMOSTINSERTAFTER(pwnd); 04044 if (pwndT != NULL) { 04045 ppos->hwndInsertAfter = HW(pwndT); 04046 } else { 04047 ppos->hwndInsertAfter = HWND_TOP; 04048 } 04049 04050 return CTM_TOPMOST; 04051 04052 } else if (ppos->hwndInsertAfter == HWND_TOP) { 04053 04054 /* 04055 * If we're not topmost, position ourself after 04056 * the last topmost window. 04057 * Otherwise, make sure that no one gets in front 04058 * of a hard error box. 04059 */ 04060 if (TestWF(pwnd, WEFTOPMOST)) { 04061 pwndT = GETTOPMOSTINSERTAFTER(pwnd); 04062 if (pwndT != NULL) { 04063 ppos->hwndInsertAfter = HW(pwndT); 04064 } 04065 return CTM_NOCHANGE; 04066 } 04067 04068 /* 04069 * Calculate the window to zorder after for this window, taking 04070 * into account foreground status. 04071 */ 04072 pwndInsertAfter = CalcForegroundInsertAfter(pwnd); 04073 ppos->hwndInsertAfter = HW(pwndInsertAfter); 04074 04075 return CTM_NOCHANGE; 04076 } 04077 04078 /* 04079 * If we're being inserted after the last topmost window, 04080 * then don't change the topmost status. 04081 */ 04082 pwndT = GetLastTopMostWindow(); 04083 if (ppos->hwndInsertAfter == HW(pwndT)) 04084 return CTM_NOCHANGE; 04085 04086 /* 04087 * Otherwise, if we're inserting a TOPMOST among non-TOPMOST, 04088 * or vice versa, change the status appropriately. 04089 */ 04090 if (TestWF(PW(ppos->hwndInsertAfter), WEFTOPMOST)) { 04091 04092 if (!TestWF(pwnd, WEFTOPMOST)) { 04093 return CTM_TOPMOST; 04094 } 04095 04096 pwndT = GETTOPMOSTINSERTAFTER(pwnd); 04097 if (pwndT != NULL) { 04098 ppos->hwndInsertAfter = HW(pwndT); 04099 } 04100 04101 } else { 04102 04103 if (TestWF(pwnd, WEFTOPMOST)) 04104 return CTM_NOTOPMOST; 04105 } 04106 04107 return CTM_NOCHANGE; 04108 } 04109 04110 /***************************************************************************\ 04111 * IsOwnee(pwndOwnee, pwndOwner) 04112 * 04113 * Returns TRUE if pwndOwnee is owned by pwndOwner 04114 * 04115 * 04116 * History: 04117 * 04-Mar-1992 MikeKe From win31 04118 \***************************************************************************/ 04119 04120 BOOL IsOwnee( 04121 PWND pwndOwnee, 04122 PWND pwndOwner) 04123 { 04124 PWND pwnd; 04125 04126 while (pwndOwnee != NULL) { 04127 04128 /* 04129 * See if pwndOwnee is a child of pwndOwner... 04130 */ 04131 for (pwnd = pwndOwnee; pwnd != NULL; pwnd = pwnd->spwndParent) { 04132 if (pwnd == pwndOwner) 04133 return TRUE; 04134 } 04135 04136 /* 04137 * If the window doesn't own itself, then set the owner 04138 * to itself. 04139 */ 04140 pwndOwnee = (pwndOwnee->spwndOwner != pwndOwnee ? 04141 pwndOwnee->spwndOwner : NULL); 04142 } 04143 04144 return FALSE; 04145 } 04146 04147 /***************************************************************************\ 04148 * 04149 * History: 04150 * 04-Mar-1992 MikeKe From win31 04151 \***************************************************************************/ 04152 04153 BOOL IsBehind( 04154 PWND pwnd, 04155 PWND pwndReference) 04156 { 04157 04158 /* 04159 * Starting at pwnd, move down until we reach the end of the window 04160 * list, or until we reach pwndReference. If we encounter pwndReference, 04161 * then pwnd is above pwndReference, so return FALSE. If we get to the 04162 * end of the window list, pwnd is behind, so return TRUE. 04163 */ 04164 if (pwndReference == (PWND)HWND_TOP) 04165 return TRUE; 04166 04167 if (pwndReference == (PWND)HWND_BOTTOM) 04168 return FALSE; 04169 04170 for ( ; pwnd != NULL; pwnd = pwnd->spwndNext) { 04171 if (pwnd == pwndReference) 04172 return FALSE; 04173 } 04174 04175 return TRUE; 04176 } 04177 04178 /***************************************************************************\ 04179 * 04180 * Add pwnd to the SMWP. pwndChange is the "real" pwnd being repositioned 04181 * and pwndInsertAfter is the place where it's being inserted. 04182 * 04183 * pwndTopInsert is the window handle where the top of the owner tree should be 04184 * inserted. The special value of (HWND)-2 is used to indicate recursion, in 04185 * which case newly added SWPs are added to the previous element. 04186 * 04187 * History: 04188 * 04-Mar-1992 MikeKe From win31 04189 \***************************************************************************/ 04190 04191 PSMWP AddSelfAndOwnees( 04192 PSMWP psmwp, 04193 PWND pwnd, 04194 PWND pwndChange, 04195 PWND pwndInsertAfter, 04196 int iTop) 04197 { 04198 PWND pwndChgOwnee; 04199 PWND pwndT; 04200 BOOL fChgOwneeInserted; 04201 CVR *pcvr; 04202 04203 /* 04204 * The general idea here is to first add our ownees, then add ourself. 04205 * When we add our ownees though, we add them as appropriate based 04206 * on the pwndInsertAfter parameter. 04207 * 04208 * Find out if any of our ownees are on a direct path between pwndChange 04209 * and the root of the owner tree. If one is, then its Z order relative 04210 * to its owner-siblings will be changing. If none are, then 04211 * we want to add our ownees to the list in their current order. 04212 */ 04213 pwndChgOwnee = pwndChange; 04214 while (pwndChgOwnee != NULL) { 04215 04216 pwndT = GetRealOwner(pwndChgOwnee); 04217 04218 if (pwnd == pwndT) 04219 break; 04220 04221 pwndChgOwnee = pwndT; 04222 } 04223 04224 /* 04225 * Now enumerate all other ownees, and insert them in their 04226 * current order. 04227 */ 04228 fChgOwneeInserted = FALSE; 04229 pwndT = NULL; 04230 while ((pwndT = NextOwnedWindow(pwndT, pwnd, pwnd->spwndParent)) != NULL) { 04231 04232 /* 04233 * If these siblings are to be reordered, compare the sibling's 04234 * current Z order with pwndInsertAfter. 04235 */ 04236 if (pwndChgOwnee == NULL) { 04237 04238 /* 04239 * No Z change for our ownees: just add them in their current order 04240 */ 04241 psmwp = AddSelfAndOwnees(psmwp, pwndT, NULL, NULL, iTop); 04242 04243 } else { 04244 04245 /* 04246 * If we haven't already inserted the ChgOwnee, and the 04247 * enumerated owner-sibling is behind pwndInsertAfter, then 04248 * add ChgOwnee. 04249 */ 04250 if (!fChgOwneeInserted && IsBehind(pwndT, pwndInsertAfter)) { 04251 04252 psmwp = AddSelfAndOwnees(psmwp, 04253 pwndChgOwnee, 04254 pwndChange, 04255 pwndInsertAfter, 04256 iTop); 04257 04258 if (psmwp == NULL) 04259 return NULL; 04260 04261 fChgOwneeInserted = TRUE; 04262 } 04263 04264 if (pwndT != pwndChgOwnee) { 04265 04266 /* 04267 * Not the change ownee: add it in its current order. 04268 */ 04269 psmwp = AddSelfAndOwnees(psmwp, pwndT, NULL, NULL, iTop); 04270 } 04271 } 04272 04273 if (psmwp == NULL) 04274 return NULL; 04275 } 04276 04277 /* 04278 * If we never added the change ownee in the loop, add it now. 04279 */ 04280 if ((pwndChgOwnee != NULL) && !fChgOwneeInserted) { 04281 04282 psmwp = AddSelfAndOwnees(psmwp, 04283 pwndChgOwnee, 04284 pwndChange, 04285 pwndInsertAfter, 04286 iTop); 04287 04288 if (psmwp == NULL) 04289 return NULL; 04290 } 04291 04292 /* 04293 * Finally, add this window to the list. 04294 */ 04295 psmwp = _DeferWindowPos(psmwp, pwnd, NULL, 04296 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); 04297 04298 if (psmwp == NULL) 04299 return NULL; 04300 04301 /* 04302 * If we aren't inserting the topmost entry, 04303 * link this entry to the previous one. 04304 * The topmost entry will get set by our caller. 04305 */ 04306 if (iTop != psmwp->ccvr - 1) { 04307 pcvr = &psmwp->acvr[psmwp->ccvr - 1]; 04308 pcvr->pos.hwndInsertAfter = (pcvr - 1)->pos.hwnd; 04309 } 04310 return psmwp; 04311 } 04312 04313 /***************************************************************************\ 04314 * 04315 * ZOrderByOwner2 - Add the current window and all it owns to the SWP list, 04316 * and arrange them in the new Z ordering. Called only if the Z order of the 04317 * window is changing. 04318 * 04319 * History: 04320 * 04-Mar-1992 MikeKe From win31 04321 \***************************************************************************/ 04322 04323 PSMWP ZOrderByOwner2( 04324 PSMWP psmwp, 04325 int iTop) 04326 { 04327 PWND pwndT; 04328 PWND pwndOwnerRoot; 04329 PWND pwndTopInsert; 04330 PWINDOWPOS ppos; 04331 PWND pwnd; 04332 PWND pwndInsertAfter; 04333 BOOL fHasOwnees; 04334 04335 ppos = &psmwp->acvr[iTop].pos; 04336 04337 /* 04338 * If inside message box processing, not Z ordering, 04339 * or if SWP_NOOWNERZORDER specified, all done. 04340 */ 04341 // LATER 04-Mar-1992 MikeKe 04342 // do we have a substitue for fMessageBox 04343 if ((ppos->flags & SWP_NOZORDER) || 04344 (ppos->flags & SWP_NOOWNERZORDER)) { 04345 04346 return psmwp; 04347 } 04348 04349 pwnd = PW(ppos->hwnd); 04350 pwndInsertAfter = PWInsertAfter(ppos->hwndInsertAfter); 04351 04352 fHasOwnees = (NextOwnedWindow(NULL, pwnd, pwnd->spwndParent) != NULL); 04353 04354 /* 04355 * If the window isn't owned, and it doesn't own any other window, 04356 * do nothing. 04357 */ 04358 if (!pwnd->spwndOwner && !fHasOwnees) 04359 return psmwp; 04360 04361 /* 04362 * Find the unowned window to start building the tree from. 04363 * This is easy: just zip upwards until we find a window with no owner. 04364 */ 04365 pwndOwnerRoot = pwndT = pwnd; 04366 while ((pwndT = GetRealOwner(pwndT)) != NULL) 04367 pwndOwnerRoot = pwndT; 04368 04369 /* 04370 * We need to calculate what pwndInsertAfter should be for 04371 * the first (topmost) window of the SWP list. 04372 * 04373 * If pwndInsertAfter is part of the owner tree we'll be building, 04374 * then we want to reorder windows within the owner group, so the 04375 * entire group should maintain it's relative order. 04376 * 04377 * If pwndInsertAfter is part of another owner tree, then we want 04378 * the whole group relative to that. 04379 * 04380 * If pwndInsertAfter is HWND_BOTTOM, then we want the whole 04381 * group to go to the bottom, so we position it relative to 04382 * the bottom most window that is not part of the tree. We also 04383 * want to put pwnd on the bottom relative to its owner siblings. 04384 * 04385 * If pwndInsertAfter is HWND_TOP, then bring the whole group 04386 * to the top, as well as bringing pwnd to the top relative to its 04387 * owner siblings. 04388 * 04389 * Assume the topmost of group is same as topmost 04390 * (true for all cases except where rearranging subtree of group) 04391 */ 04392 pwndTopInsert = pwndInsertAfter; 04393 if (pwndInsertAfter == (PWND)HWND_TOP) { 04394 04395 /* 04396 * Bring the whole group to the top: nothing fancy to do. 04397 */ 04398 04399 } else if (pwndInsertAfter == (PWND)HWND_BOTTOM) { 04400 04401 /* 04402 * Put the whole group on the bottom. pwndTopInsert should 04403 * be the bottommost window unowned by pwndOwnerRoot. 04404 */ 04405 for (pwndT = pwnd->spwndParent->spwndChild; 04406 (pwndT != NULL) && !TestWF(pwndT, WFBOTTOMMOST); pwndT = pwndT->spwndNext) { 04407 04408 /* 04409 * If it's not owned, then this is the bottommost so far. 04410 */ 04411 if (!IsOwnee(pwndT, pwndOwnerRoot)) 04412 pwndTopInsert = pwndT; 04413 } 04414 04415 /* 04416 * If there were no other windows not in our tree, 04417 * then there is no Z ordering change to be done. 04418 */ 04419 if (pwndTopInsert == (PWND)HWND_BOTTOM) 04420 ppos->flags |= SWP_NOZORDER; 04421 04422 } else { 04423 04424 /* 04425 * pwndInsertAfter is a window. Compute pwndTopInsert 04426 */ 04427 if (IsOwnee(pwndInsertAfter, pwndOwnerRoot)) { 04428 04429 /* 04430 * SPECIAL CASE: If we do not own any windows, and we're 04431 * being moved within our owner group in such a way that 04432 * we remain above our owner, then no other windows will 04433 * be moving with us, and we can just exit 04434 * without building our tree. This can save a LOT of 04435 * extra work, especially with the MS apps CBT tutorials, 04436 * which do this kind of thing a lot. 04437 */ 04438 if (!fHasOwnees) { 04439 04440 /* 04441 * Make sure we will still be above our owner by searching 04442 * for our owner starting from pwndInsertAfter. If we 04443 * find our owner, then pwndInsertAfter is above it. 04444 */ 04445 for (pwndT = pwndInsertAfter; pwndT != NULL; 04446 pwndT = pwndT->spwndNext) { 04447 04448 if (pwndT == pwnd->spwndOwner) 04449 return psmwp; 04450 } 04451 } 04452 04453 /* 04454 * Part of same group: Find out which window the topmost 04455 * of the group is currently inserted behind. 04456 */ 04457 pwndTopInsert = (PWND)HWND_TOP; 04458 for (pwndT = pwnd->spwndParent->spwndChild; pwndT != NULL; 04459 pwndT = pwndT->spwndNext) { 04460 04461 if (IsOwnee(pwndT, pwndOwnerRoot)) 04462 break; 04463 04464 pwndTopInsert = pwndT; 04465 } 04466 } 04467 } 04468 04469 /* 04470 * Okay, now go recursively build the owned window list... 04471 */ 04472 if (!(ppos->flags & SWP_NOZORDER)) { 04473 04474 /* 04475 * First "delete" the last entry (the one we're sorting with) 04476 */ 04477 psmwp->ccvr--; 04478 04479 psmwp = AddSelfAndOwnees(psmwp, 04480 pwndOwnerRoot, 04481 pwnd, 04482 pwndInsertAfter, 04483 iTop); 04484 04485 /* 04486 * Now set the place where the whole group is going. 04487 */ 04488 if (psmwp != NULL) 04489 psmwp->acvr[iTop].pos.hwndInsertAfter = HW(pwndTopInsert); 04490 } 04491 04492 return psmwp; 04493 } 04494 04495 /***************************************************************************\ 04496 * TrackBackground 04497 * 04498 * Adjust zorder if we're crossing a TOPMOST boundary. Make sure that a 04499 * non-topmost window in a background thread doesn't come in front of 04500 * non-topmost windows in the foreground thread. 04501 \***************************************************************************/ 04502 04503 BOOL TrackBackground(WINDOWPOS *ppos, PWND pwndPrev, PWND pwnd) 04504 { 04505 PWND pwndT; 04506 04507 if (pwndPrev == NULL) 04508 return FALSE; 04509 04510 /* 04511 * Is this window foreground? If so, let it go. For wow apps, 04512 * check to see if any thread of the process is foreground. 04513 */ 04514 if (GETPTI(pwnd)->TIF_flags & TIF_16BIT) { 04515 04516 if (gptiForeground == NULL) 04517 return FALSE; 04518 04519 if (GETPTI(pwnd)->ppi == gptiForeground->ppi) 04520 return FALSE; 04521 04522 } else { 04523 04524 if (GETPTI(pwnd) == gptiForeground) 04525 return FALSE; 04526 } 04527 04528 /* 04529 * Make sure the previous window is either staying or becoming 04530 * topmost. If not, continue: no top most boundary. 04531 */ 04532 if (!FSwpTopmost(pwndPrev)) 04533 return FALSE; 04534 04535 /* 04536 * Is the current window already top-most? If so then don't 04537 * calculate a special insert after. If we don't check for 04538 * this, then pwnd's insert after may be calculated as what 04539 * pwnd already is, if pwnd is the last top most window. That 04540 * would cause window links to get corrupted. 04541 */ 04542 if (TestWF(pwnd, WEFTOPMOST)) 04543 return FALSE; 04544 04545 /* 04546 * Doing this assign prevents this routine from being called 04547 * twice, since HW() is a conditional macro. 04548 */ 04549 pwndT = CalcForegroundInsertAfter(pwnd); 04550 ppos->hwndInsertAfter = HW(pwndT); 04551 return TRUE; 04552 } 04553 04554 /***************************************************************************\ 04555 * TrackZorder, TrackZorderHelper 04556 * 04557 * Set up hwndInsertAfter links to point to the previous window in the 04558 * CVR array and partition them in TOPMOST and non-TOPMOST chains. 04559 * 04560 * 05/16/97 vadimg created 04561 \***************************************************************************/ 04562 04563 void TrackZorderHelper(WINDOWPOS *ppos, HWND *phwnd) 04564 { 04565 /* 04566 * phwnd (hwndTopmost or hwndRegular) have been initialized to NULL before 04567 * the beginning of the scan. This way the first hwndInsertAfter that 04568 * we process remains with the value that was previously calculated. 04569 */ 04570 if (*phwnd != NULL) { 04571 04572 #if DBG 04573 if (ppos->hwndInsertAfter != *phwnd) { 04574 RIPMSG0(RIP_WARNING, "TrackZorder: modified hwndInsertAfter"); 04575 } 04576 #endif 04577 04578 ppos->hwndInsertAfter = *phwnd; 04579 } 04580 *phwnd = ppos->hwnd; 04581 } 04582 04583 PWND TrackZorder(WINDOWPOS* ppos, PWND pwndPrev, HWND *phwndTop, HWND *phwndReg) 04584 { 04585 PWND pwnd = PW(ppos->hwnd); 04586 04587 if (pwnd == NULL) 04588 return NULL; 04589 04590 if (TrackBackground(ppos, pwndPrev, pwnd)) { 04591 *phwndReg = ppos->hwnd; 04592 } else if (FSwpTopmost(pwnd)) { 04593 TrackZorderHelper(ppos, phwndTop); 04594 } else { 04595 TrackZorderHelper(ppos, phwndReg); 04596 } 04597 04598 return pwnd; 04599 } 04600 04601 /***************************************************************************\ 04602 * ZOrderByOwner 04603 * 04604 * This routine Z-Orders windows by their owners. 04605 * 04606 * LATER 04607 * This code currently assumes that all of the window handles are valid 04608 * 04609 * History: 04610 * 04-Mar-1992 MikeKe from win31 04611 \***************************************************************************/ 04612 04613 PSMWP ZOrderByOwner( 04614 PSMWP psmwp) 04615 { 04616 int i; 04617 PWND pwnd; 04618 PWND pwndT; 04619 WINDOWPOS pos; 04620 PTHREADINFO ptiT; 04621 HRGN hrgnClipSave; 04622 04623 /* 04624 * Some of the windows in the SMWP list may be NULL at ths point 04625 * (removed because they'll be handled by their creator's thread) 04626 * so we've got to look for the first non-NULL window before we can 04627 * execute some of the tests below. FindValidWindowPos returns NULL if 04628 * the list has no valid windows in it. 04629 */ 04630 if (FindValidWindowPos(psmwp) == NULL) 04631 return psmwp; 04632 04633 /* 04634 * For each SWP in the array, move it to the end of the array 04635 * and generate its entire owner tree in sorted order. 04636 */ 04637 for (i = psmwp->ccvr; i-- != 0; ) { 04638 04639 int iScan; 04640 int iTop; 04641 int code; 04642 WINDOWPOS *ppos; 04643 HWND hwndTopmost; 04644 HWND hwndRegular; 04645 04646 if (psmwp->acvr[0].pos.hwnd == NULL) 04647 continue; 04648 04649 code = CheckTopmost(&psmwp->acvr[0].pos); 04650 04651 /* 04652 * Make a local copy for later... 04653 * 04654 * Why don't we copy all CVR fields? This seems pretty hard to maintain. 04655 * Perhaps because most of them haven't been used yet.... 04656 * 04657 */ 04658 pos = psmwp->acvr[0].pos; 04659 ptiT = psmwp->acvr[0].pti; 04660 hrgnClipSave = psmwp->acvr[0].hrgnClip; 04661 04662 /* 04663 * Move the CVR to the end (if it isn't already) 04664 */ 04665 iTop = psmwp->ccvr - 1; 04666 04667 if (iTop != 0) { 04668 04669 RtlCopyMemory(&psmwp->acvr[0], 04670 &psmwp->acvr[1], 04671 iTop * sizeof(CVR)); 04672 04673 psmwp->acvr[iTop].pos = pos; 04674 psmwp->acvr[iTop].pti = ptiT; 04675 psmwp->acvr[iTop].hrgnClip = hrgnClipSave; 04676 } 04677 04678 if ((psmwp = ZOrderByOwner2(psmwp, iTop)) == NULL) 04679 break; 04680 04681 /* 04682 * Deal with WEFTOPMOST bits. If we're SETTING the TOPMOST bits, 04683 * we want to set them for this window and 04684 * all its owned windows -- the owners stay unchanged. If we're 04685 * CLEARING, though, we need to enumerate ALL the windows, since 04686 * they all need to lose the topmost bit when one loses it. 04687 * 04688 * Note that since a status change doesn't necessarily mean that 04689 * the true Z order of the windows have changed, so ZOrderByOwner2 04690 * may not have enumerated all of the owned and owner windows. 04691 * So, we enumerate them separately here. 04692 */ 04693 if (code != CTM_NOCHANGE) { 04694 PWND pwndRoot = PW(pos.hwnd); 04695 #if DBG 04696 PWND pwndOriginal = pwndRoot; 04697 #endif 04698 04699 /* 04700 * Make sure we're z-ordering this window. Or settting topmost 04701 * is bad. 04702 */ 04703 UserAssert(!(pos.flags & SWP_NOZORDER)); 04704 04705 /* 04706 * If we're CLEARING the topmost, then we want to enumerate 04707 * the owners and ownees, so start our enumeration at the root. 04708 */ 04709 if (code == CTM_NOTOPMOST) { 04710 04711 while (pwnd = GetRealOwner(pwndRoot)) 04712 pwndRoot = pwnd; 04713 } 04714 04715 #if DBG 04716 if ((pos.flags & SWP_NOOWNERZORDER) 04717 && ((pwndOriginal != pwndRoot) 04718 || (NextOwnedWindow(NULL, pwndRoot, pwndRoot->spwndParent) != NULL))) { 04719 /* 04720 * We're not doing owner z-order but pwndOriginal has an owner and/or 04721 * owns some windows. The problem is, SetTopMost always affects the whole 04722 * owner/ownee group. So we might end up with WFTOGGLETOPMOST windows 04723 * that won't be z-ordered. It has always been like that. 04724 */ 04725 RIPMSG2(RIP_WARNING, "ZOrderByOwner: Topmost change while using SWP_NOOWNERZORDER." 04726 " pwndRoot:%p pwndOriginal:%p", 04727 pwndRoot, pwndOriginal); 04728 } 04729 #endif 04730 04731 SetTopmost(pwndRoot, code == CTM_TOPMOST); 04732 } 04733 04734 /* 04735 * Now scan the list forwards (from the bottom of the 04736 * owner tree towards the root) looking for the window 04737 * we were positioning originally (it may have been in 04738 * the middle of the owner tree somewhere). Update the 04739 * window pos structure stored there with the original 04740 * information (though the z-order info is retained from 04741 * the sort). 04742 */ 04743 pwnd = NULL; 04744 hwndTopmost = hwndRegular = NULL; 04745 for (iScan = iTop; iScan != psmwp->ccvr; iScan++) { 04746 04747 ppos = &psmwp->acvr[iScan].pos; 04748 04749 if (ppos->hwnd == pos.hwnd) { 04750 ppos->x = pos.x; 04751 ppos->y = pos.y; 04752 ppos->cx = pos.cx; 04753 ppos->cy = pos.cy; 04754 ppos->flags ^= ((ppos->flags ^ pos.flags) & ~SWP_NOZORDER); 04755 psmwp->acvr[iScan].hrgnClip = hrgnClipSave; 04756 } 04757 04758 pwndT = pwnd; 04759 pwnd = TrackZorder(ppos, pwndT, &hwndTopmost, &hwndRegular); 04760 } 04761 } 04762 04763 return psmwp; 04764 } 04765 /***************************************************************************\ 04766 * xxxEndDeferWindowPosEx 04767 * 04768 * 04769 * History: 04770 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 04771 \***************************************************************************/ 04772 04773 BOOL xxxEndDeferWindowPosEx( 04774 PSMWP psmwp, 04775 BOOL fAsync) 04776 { 04777 PWND pwndNewActive; 04778 PWND pwndParent; 04779 PWND pwndActive; 04780 PWND pwndActivePrev; 04781 HWND hwndNewActive; 04782 PWINDOWPOS pwp; 04783 BOOL fClearBits; 04784 BOOL fSyncPaint; 04785 UINT cVisWindowsPrev; 04786 PTHREADINFO ptiCurrent = PtiCurrent(); 04787 TL tlpwndNewActive; 04788 TL tlpwndParent; 04789 TL tlcuSMWP; 04790 BOOL fForegroundPrev; 04791 04792 UserAssert(IsWinEventNotifyDeferredOK()); 04793 04794 DBGCheskSMWP(psmwp); 04795 if (psmwp->bHandle) { 04796 CheckLock(psmwp); 04797 } 04798 04799 /* 04800 * Validate the window pos structures and find a window to activate. 04801 */ 04802 if ((psmwp->ccvr != 0) && ValidateSmwp(psmwp, &fSyncPaint)) { 04803 04804 if ((pwp = FindValidWindowPos(psmwp)) == NULL) 04805 goto lbFinished; 04806 04807 /* 04808 * Make sure to stop at the mother desktop window. In Win95 04809 * a SetWindowPos() on a desktop window will have a NULL parent 04810 * window. This is not true in NT, but our mother desktop 04811 * window does have a NULL rpdesk, so check it too. 04812 */ 04813 UserAssert(PW(pwp->hwnd)); 04814 pwndParent = PW(pwp->hwnd)->spwndParent; 04815 if (pwndParent == NULL || pwndParent->head.rpdesk == NULL) 04816 goto lbFinished; 04817 04818 /* 04819 * Usually all window positioning happens synchronously across threads. 04820 * This is because apps expect that behavior now - if it was async, 04821 * callers could not expect the state to be set once the api returned. 04822 * This is not the semantics of SetWindowPos(). The downside of this 04823 * synchronicity is that a SetWindowPos() on an hwnd created by another 04824 * thread will cause the caller to wait for that thread - even if that 04825 * thread is hung. That's what you get. 04826 * 04827 * We don't want task manager to hang though, no matter who else is 04828 * hung, so when taskman calls, it calls a special entry point for 04829 * tiling / cascading, which does SetWindowPos() asynchronously - 04830 * by posting an event in each thread's queue that makes it set its 04831 * own window position - that way if the thread is hung, who cares - 04832 * it doesn't effect taskman. 04833 * 04834 * Do async window pos positioning before zorder by owner so that 04835 * we retain any cross thread ownership relationships synchronously. 04836 */ 04837 if (fAsync) { 04838 AsyncWindowPos(psmwp); 04839 } 04840 04841 /* 04842 * If needed, Z order the windows by owner. 04843 * This may grow the SMWP, if new CVRs are added. 04844 */ 04845 if (pwndParent == PWNDDESKTOP(pwndParent)) { 04846 04847 if ((psmwp = ZOrderByOwner(psmwp)) == NULL) { 04848 return FALSE; 04849 } 04850 } 04851 04852 ThreadLockAlwaysWithPti(ptiCurrent, pwndParent, &tlpwndParent); 04853 ThreadLockPoolCleanup(ptiCurrent, psmwp, &tlcuSMWP, DestroySMWP); 04854 04855 /* 04856 * Calc new window positions. 04857 */ 04858 if (xxxCalcValidRects(psmwp, &hwndNewActive)) { 04859 04860 int i; 04861 04862 pwndNewActive = RevalidateHwnd(hwndNewActive); 04863 04864 ThreadLockWithPti(ptiCurrent, pwndNewActive, &tlpwndNewActive); 04865 04866 cVisWindowsPrev = ptiCurrent->cVisWindows; 04867 fForegroundPrev = (ptiCurrent == gptiForeground); 04868 04869 /* 04870 * The call to zzzBltValidBits will leave the critical section 04871 * if there are any notifications to make. 04872 */ 04873 UserAssert(IsWinEventNotifyDeferredOK()); 04874 if (!zzzBltValidBits(psmwp)) 04875 fSyncPaint = FALSE; 04876 UserAssert(IsWinEventNotifyDeferredOK()); 04877 04878 if (psmwp->bShellNotify) { 04879 for (i = psmwp->ccvr; i-- != 0; ) { 04880 /* 04881 * Loop through the windows, looking for notifications. 04882 */ 04883 04884 if (0 == (psmwp->acvr[i].pos.flags & SWP_NOTIFYALL)) 04885 continue; 04886 04887 if (psmwp->acvr[i].pos.flags & SWP_NOTIFYCREATE) { 04888 PostShellHookMessages(HSHELL_WINDOWCREATED, 04889 (LPARAM)psmwp->acvr[i].pos.hwnd); 04890 04891 xxxCallHook(HSHELL_WINDOWCREATED, 04892 (WPARAM)psmwp->acvr[i].pos.hwnd, 04893 (LPARAM)0, 04894 WH_SHELL); 04895 } 04896 04897 if (psmwp->acvr[i].pos.flags & SWP_NOTIFYDESTROY) { 04898 PostShellHookMessages(HSHELL_WINDOWDESTROYED, 04899 (LPARAM)psmwp->acvr[i].pos.hwnd); 04900 04901 xxxCallHook(HSHELL_WINDOWDESTROYED, 04902 (WPARAM)psmwp->acvr[i].pos.hwnd, 04903 (LPARAM)0, 04904 WH_SHELL); 04905 } 04906 04907 if (psmwp->acvr[i].pos.flags & SWP_NOTIFYACTIVATE) { 04908 PWND pwnd = RevalidateHwnd(psmwp->acvr[i].pos.hwnd); 04909 if (pwnd != NULL){ 04910 TL tlpwnd; 04911 ThreadLockAlwaysWithPti(ptiCurrent, pwnd, &tlpwnd); 04912 xxxSetTrayWindow(pwnd->head.rpdesk, pwnd, NULL); 04913 ThreadUnlock(&tlpwnd); 04914 } 04915 } 04916 04917 if (psmwp->acvr[i].pos.flags & SWP_NOTIFYFS) { 04918 xxxSetTrayWindow(ptiCurrent->rpdesk, STW_SAME, NULL); 04919 } 04920 } 04921 } 04922 04923 04924 /* 04925 * If this process went from some windows to no windows visible 04926 * and it was in the foreground, then let its next activate 04927 * come to the foreground. 04928 */ 04929 if (fForegroundPrev && cVisWindowsPrev && !ptiCurrent->cVisWindows) { 04930 04931 ptiCurrent->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 04932 TAGMSG1(DBGTAG_FOREGROUND, "xxxEndDeferWindowPosEx set TIF %#p", ptiCurrent); 04933 04934 /* 04935 * Also if any apps were in the middle of starting when 04936 * this happened, allow them to foreground activate again. 04937 */ 04938 RestoreForegroundActivate(); 04939 } 04940 04941 /* 04942 * Deal with any activation... 04943 */ 04944 fClearBits = FALSE; 04945 if (pwndNewActive != NULL) 04946 fClearBits = xxxSwpActivate(pwndNewActive); 04947 04948 /* 04949 * Now draw frames and erase backgrounds of all the windows 04950 * involved. 04951 */ 04952 UserAssert(pwndParent); 04953 if (fSyncPaint) 04954 xxxDoSyncPaint(pwndParent, DSP_ENUMCLIPPEDCHILDREN); 04955 04956 ThreadUnlock(&tlpwndNewActive); 04957 04958 /* 04959 * If SwpActivate() set the NONCPAINT bits, clear them now. 04960 */ 04961 if (fClearBits) { 04962 04963 if (pwndActive = ptiCurrent->pq->spwndActive) 04964 ClrWF(pwndActive, WFNONCPAINT); 04965 04966 if (pwndActivePrev = ptiCurrent->pq->spwndActivePrev) 04967 ClrWF(pwndActivePrev, WFNONCPAINT); 04968 } 04969 04970 /* 04971 * Send WM_WINDOWPOSCHANGED messages 04972 */ 04973 xxxSendChangedMsgs(psmwp); 04974 } 04975 04976 ThreadUnlockPoolCleanup(ptiCurrent, &tlcuSMWP); 04977 ThreadUnlock(&tlpwndParent); 04978 } 04979 04980 lbFinished: 04981 04982 /* 04983 * All done. Free everything up and return. 04984 */ 04985 DestroySMWP(psmwp); 04986 return TRUE; 04987 } 04988 04989 04990 /***************************************************************************\ 04991 * IncVisWindows 04992 * DecVisWindows 04993 * 04994 * These routines deal with incrementing/decrementing the visible windows 04995 * on the thread. 04996 * 04997 \***************************************************************************/ 04998 #if DBG 04999 05000 BOOL gfVisVerify = FALSE; 05001 05002 void VerifycVisWindows(PWND pwnd) 05003 { 05004 BOOL fShowMeTheWindows = FALSE; 05005 PTHREADINFO pti = GETPTI(pwnd); 05006 PWND pwndNext; 05007 UINT uVisWindows = 0; 05008 05009 if (!gfVisVerify) { 05010 return; 05011 } 05012 05013 /* 05014 * Make sure the count makes sense 05015 */ 05016 if ((int)pti->cVisWindows < 0) { 05017 RIPMSG0(RIP_ERROR, "VerifycVisWindows: pti->cVisWindows underflow!"); 05018 fShowMeTheWindows = TRUE; 05019 } 05020 05021 /* 05022 * This window might be owned by a desktop-less service 05023 */ 05024 if (pti->rpdesk == NULL || (pti->TIF_flags & TIF_SYSTEMTHREAD)) { 05025 return; 05026 } 05027 05028 /* 05029 * Child windows don't affect cVisWindows 05030 */ 05031 if (!FTopLevel(pwnd)) { 05032 return; 05033 } 05034 05035 ShowMeTheWindows: 05036 /* 05037 * We're going to count all the windows owned by this pti 05038 * that should be included in cVisWindows 05039 */ 05040 pwndNext = pti->rpdesk->pDeskInfo->spwnd; 05041 /* 05042 * If this is a top level window, start with the first child. 05043 * If not, it should be a desktop thread window 05044 */ 05045 if (pwndNext == pwnd->spwndParent) { 05046 pwndNext = pwndNext->spwndChild; 05047 } else if (pwndNext->spwndParent != pwnd->spwndParent) { 05048 RIPMSG1(RIP_WARNING, "VerifycVisWindows: Non top level window:%#p", pwnd); 05049 return; 05050 } 05051 05052 if (fShowMeTheWindows) { 05053 RIPMSG1(RIP_WARNING, "VerifycVisWindows: Start window walk at:%#p", pwndNext); 05054 } 05055 05056 /* 05057 * Count the visble-not-minimized windows owned by this pti 05058 */ 05059 while (pwndNext != NULL) { 05060 if (pti == GETPTI(pwndNext)) { 05061 if (fShowMeTheWindows) { 05062 RIPMSG1(RIP_WARNING, "VerifycVisWindows: pwndNext:%#p", pwndNext); 05063 } 05064 if (!TestWF(pwndNext, WFMINIMIZED) 05065 && TestWF(pwndNext, WFVISIBLE)) { 05066 05067 uVisWindows++; 05068 05069 if (fShowMeTheWindows) { 05070 RIPMSG1(RIP_WARNING, "VerifycVisWindows: Counted:%#p", pwndNext); 05071 } 05072 } 05073 } 05074 pwndNext = pwndNext->spwndNext; 05075 } 05076 05077 /* 05078 * It must match. 05079 */ 05080 if (pti->cVisWindows != uVisWindows) { 05081 RIPMSG2(RIP_WARNING, "VerifycVisWindows: pti->cVisWindows:%#lx. uVisWindows:%#lx", 05082 pti->cVisWindows, uVisWindows); 05083 05084 /* 05085 * Disable going through the list and make the error into a warning. 05086 * There are many loopholes as to how the cVisWindow count may get 05087 * messed up. See bug 109807. 05088 */ 05089 fShowMeTheWindows = TRUE; 05090 05091 if (!fShowMeTheWindows) { 05092 fShowMeTheWindows = TRUE; 05093 uVisWindows = 0; 05094 goto ShowMeTheWindows; 05095 } 05096 } 05097 } 05098 #endif 05099 05100 /***************************************************************************\ 05101 * FVisCountable 05102 * 05103 * Desktops and top-level i.e. whose parent is the desktop) non-minimized 05104 * windows should be counted in the per-thread visible window counts. 05105 \***************************************************************************/ 05106 05107 BOOL FVisCountable(PWND pwnd) 05108 { 05109 if (!TestWF(pwnd, WFDESTROYED)) { 05110 if ((GETFNID(pwnd) == FNID_DESKTOP) || 05111 (FTopLevel(pwnd) && !TestWF(pwnd, WFMINIMIZED))) { 05112 return TRUE; 05113 } 05114 } 05115 return FALSE; 05116 } 05117 05118 /***************************************************************************\ 05119 * IncVisWindows 05120 * 05121 \***************************************************************************/ 05122 05123 VOID IncVisWindows( 05124 PWND pwnd) 05125 { 05126 if (FVisCountable(pwnd)) 05127 GETPTI(pwnd)->cVisWindows++; 05128 05129 #if DBG 05130 if (!ISTS()) 05131 VerifycVisWindows(pwnd); 05132 #endif 05133 } 05134 05135 /***************************************************************************\ 05136 * cDecVis 05137 * 05138 * An inline that allows debug code to decrement the vis window count 05139 * without doing verification right away. Also alled by DecVisWindows 05140 * to do the actual work. 05141 \***************************************************************************/ 05142 05143 __inline void cDecVis(PWND pwnd) 05144 { 05145 UserAssert(pwnd != NULL); 05146 05147 if (FVisCountable(pwnd)) 05148 GETPTI(pwnd)->cVisWindows--; 05149 } 05150 05151 /***************************************************************************\ 05152 * DecVisWindows 05153 * 05154 \***************************************************************************/ 05155 05156 VOID DecVisWindows( 05157 PWND pwnd) 05158 { 05159 cDecVis(pwnd); 05160 05161 #if DBG 05162 if (!ISTS()) 05163 VerifycVisWindows(pwnd); 05164 #endif 05165 } 05166 05167 /***************************************************************************\ 05168 * SetMiminize 05169 * 05170 * This routine must be used to flip the WS_MIMIMIZE style bit. 05171 * It adjusts cVisWindows count if appropriate. 05172 * 05173 * 06/06/96 GerardoB Created 05174 \***************************************************************************/ 05175 05176 VOID SetMinimize( 05177 PWND pwnd, 05178 UINT uFlags) 05179 { 05180 /* 05181 * Note that Dec and IncVisWindows check the WFMINIMIZED flag, so the order 05182 * in which we set/clear the flag and call these functions is important 05183 * If the window is not WFVISIBLE, cVisWindows must not change. 05184 */ 05185 if (uFlags & SMIN_SET) { 05186 UserAssert(!TestWF(pwnd, WFMINIMIZED)); 05187 if (TestWF(pwnd, WFVISIBLE)) { 05188 /* 05189 * Decrement the count because the window is not minimized 05190 * and visible, and we're about to mark it as minimized 05191 */ 05192 05193 #if DBG 05194 cDecVis(pwnd); 05195 #else 05196 DecVisWindows(pwnd); 05197 #endif 05198 } 05199 SetWF(pwnd, WFMINIMIZED); 05200 05201 #if DBG 05202 VerifycVisWindows(pwnd); 05203 #endif 05204 } else { 05205 05206 UserAssert(TestWF(pwnd, WFMINIMIZED)); 05207 ClrWF(pwnd, WFMINIMIZED); 05208 if (TestWF(pwnd, WFVISIBLE)) { 05209 /* 05210 * Increment the count because the window is visible 05211 * and it's no longer marked as minimized 05212 */ 05213 IncVisWindows(pwnd); 05214 } 05215 } 05216 } 05217 /***************************************************************************\ 05218 * SetVisible 05219 * 05220 * This routine must be used to set or clear the WS_VISIBLE style bit. 05221 * It also handles the setting or clearing of the WF_TRUEVIS bit. 05222 * 05223 * Note that we don't check if the window is already in the (in)visible 05224 * state before setting/clearing the WFVISIBLE bit and calling 05225 * Inc/DecVisWindows. If the window is already in the given state and 05226 * someone calls SetVisible to change into the same state, the VisCount 05227 * will get out of sync. This could happen, for example, if someone 05228 * passed two SWP_SHOWWINDOW for the same hwnd CVR's in the same 05229 * EndDeferWindowPos call. It would be ideal to do the check here, but 05230 * most of the time the caller does the check and we don't want to 05231 * penalize everybody just because of the weird cases. 05232 * 05233 * History: 05234 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 05235 \***************************************************************************/ 05236 05237 VOID SetVisible( 05238 PWND pwnd, 05239 UINT flags) 05240 { 05241 if (flags & SV_SET) { 05242 05243 #if DBG 05244 if (TestWF(pwnd, WFINDESTROY)) { 05245 RIPMSG1(RIP_WARNING, "SetVisible: show INDESTROY %#p", pwnd); 05246 } 05247 #endif 05248 05249 if (TestWF(pwnd, WFVISIBLE)) { 05250 RIPMSG1(RIP_WARNING, "SetVisible: already visible %#p", pwnd); 05251 } else { 05252 SetWF(pwnd, WFVISIBLE); 05253 IncVisWindows(pwnd); 05254 } 05255 } else { 05256 05257 if (flags & SV_CLRFTRUEVIS) 05258 ClrFTrueVis(pwnd); 05259 05260 #if DBG 05261 if (TestWF(pwnd, WFDESTROYED)) { 05262 RIPMSG1(RIP_WARNING, "SetVisible: hide DESTROYED %#p", pwnd); 05263 } 05264 #endif 05265 05266 if (TestWF(pwnd, WFVISIBLE)) { 05267 ClrWF(pwnd, WFVISIBLE); 05268 DecVisWindows(pwnd); 05269 } else { 05270 RIPMSG1(RIP_WARNING, "SetVisible: already hidden %#p", pwnd); 05271 } 05272 } 05273 } 05274 05275 /***************************************************************************\ 05276 * IsMaxedRect 05277 * 05278 * Determines if a window is "maximizing" to a certain area 05279 * 05280 * History: 05281 \***************************************************************************/ 05282 05283 BOOL IsMaxedRect( 05284 LPRECT lprcWithin, 05285 PCSIZERECT psrcMaybe) 05286 { 05287 return(psrcMaybe->x <= lprcWithin->left && 05288 psrcMaybe->y <= lprcWithin->top && 05289 psrcMaybe->cx >= lprcWithin->right - lprcWithin->left && 05290 psrcMaybe->cy >= lprcWithin->bottom - lprcWithin->top); 05291 } 05292 05293 /***************************************************************************\ 05294 * xxxCheckFullScreen 05295 * 05296 * Sees if a window is really fullscreen or just a maximized window in 05297 * disguise. If the latter, it will be forced to the proper maximized 05298 * size. 05299 * 05300 * This is called from both CalcValidRects() and CreateWindowEx(). 05301 * 05302 * History: 05303 \***************************************************************************/ 05304 05305 BOOL xxxCheckFullScreen( 05306 PWND pwnd, 05307 PSIZERECT psrc) 05308 { 05309 BOOL fYielded = FALSE; 05310 PMONITOR pMonitor; 05311 PMONITOR pMonitorPrimary; 05312 TL tlpMonitor; 05313 RECT rc; 05314 BOOL fIsPrimary; 05315 05316 05317 CheckLock(pwnd); 05318 05319 /* 05320 * SINCE THIS IS ONLY CALLED IN 2 PLACES, make the checks there 05321 * instead of the overhead of calling this function in time critical 05322 * places. 05323 * 05324 * If 3 or more places call it, put the child/toolwindow checks here 05325 */ 05326 UserAssert(!TestWF(pwnd, WFCHILD)); 05327 UserAssert(!TestWF(pwnd, WEFTOOLWINDOW)); 05328 05329 pMonitorPrimary = GetPrimaryMonitor(); 05330 if (gpDispInfo->cMonitors == 1) { 05331 pMonitor = pMonitorPrimary; 05332 } else { 05333 /* 05334 * In multiple monitor mode, windows that take up the entire 05335 * virtual screen are not considered 'full screen'. 'Full screen' 05336 * means full single monitor only. This detection is so that any 05337 * docked bars--tray, office'95 tools--can get out of the way for 05338 * the application. 05339 * 05340 * There are only three types of windows that ought to go full 05341 * virtual screen. None of them need the tray et al. to get out of 05342 * the way: 05343 * (1) Normal app windows that want a lot of space 05344 * * Those guys just activate and deactivate normally. 05345 * (2) Desktop windows 05346 * * Shell, User desktop sit behind everything else. 05347 * (3) Screen savers, demos, etc. 05348 * * These guys should be WS_EX_TOPMOST to ensure they sit 05349 * over everybody. 05350 */ 05351 if (IsMaxedRect(&gpDispInfo->rcScreen, psrc)) 05352 return fYielded; 05353 05354 RECTFromSIZERECT(&rc, psrc); 05355 pMonitor = _MonitorFromRect(&rc, MONITOR_DEFAULTTOPRIMARY); 05356 } 05357 05358 fIsPrimary = (pMonitor == pMonitorPrimary); 05359 ThreadLockAlways(pMonitor, &tlpMonitor); 05360 05361 if (IsMaxedRect(&pMonitor->rcWork, psrc)) { 05362 if (TestWF(pwnd, WFMAXIMIZED)) { 05363 SetWF(pwnd, WFREALLYMAXIMIZABLE); 05364 05365 if (gpDispInfo->cMonitors > 1) { 05366 /* 05367 * BUGBUG: Check if app is before 4.1? 05368 */ 05369 05370 /* 05371 * This is for XL '95 going fullscreen when already maxed. It 05372 * always uses the primary display. Let's hack them, and any 05373 * other old app that tries to move its truly maximized window. 05374 * They will be clipped otherwise by our fake regional stuff. 05375 */ 05376 PMONITOR pMonitorReal; 05377 05378 pMonitorReal = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY); 05379 if (pMonitorReal != pMonitor && fIsPrimary) { 05380 /* 05381 * Transfer over the shape to the REAL monitor. 05382 */ 05383 psrc->x += pMonitorReal->rcMonitor.left; 05384 psrc->y += pMonitorReal->rcMonitor.top; 05385 psrc->cx -= (pMonitor->rcMonitor.right - pMonitor->rcMonitor.left) + 05386 (pMonitorReal->rcMonitor.right - pMonitorReal->rcMonitor.left); 05387 05388 psrc->cy -= (pMonitor->rcMonitor.bottom - pMonitor->rcMonitor.top) + 05389 (pMonitorReal->rcMonitor.bottom - pMonitorReal->rcMonitor.top); 05390 05391 ThreadUnlock(&tlpMonitor); 05392 pMonitor = pMonitorReal; 05393 fIsPrimary = FALSE; 05394 ThreadLockAlways(pMonitor, &tlpMonitor); 05395 } 05396 } 05397 } 05398 05399 if ( TestWF(pwnd, WFMAXIMIZED) && 05400 TestWF(pwnd, WFMAXBOX) && 05401 (TestWF(pwnd, WFBORDERMASK) == LOBYTE(WFCAPTION))) { 05402 05403 if ( psrc->y + SYSMET(CYCAPTION) <= pMonitor->rcMonitor.top && 05404 psrc->y + psrc->cy >= pMonitor->rcMonitor.bottom) { 05405 05406 if (!TestWF(pwnd, WFFULLSCREEN)) { 05407 /* 05408 * Only want to do full screen stuff on the tray 05409 * monitor. 05410 */ 05411 fYielded = xxxAddFullScreen(pwnd, pMonitor); 05412 } 05413 } else { 05414 int iRight; 05415 int iBottom; 05416 int dxy; 05417 05418 if (TestWF(pwnd, WFFULLSCREEN)) { 05419 fYielded = xxxRemoveFullScreen(pwnd, pMonitor); 05420 } 05421 05422 /* 05423 * Despite the code in GetMinMaxInfo() to fix up 05424 * the max rect, we still have to hack old apps. 05425 * Word '95 & XL '95 do weird things when going to/from 05426 * full screen when maximized already. 05427 * 05428 * NOTE: you can have more than one docked bar on a 05429 * monitor. Win '95 code doesn't work right in that 05430 * case. 05431 */ 05432 dxy = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 05433 dxy *= SYSMET(CXBORDER); 05434 05435 psrc->x = pMonitor->rcWork.left - dxy; 05436 psrc->y = pMonitor->rcWork.top - dxy; 05437 05438 dxy *= 2; 05439 iRight = 05440 pMonitor->rcWork.right - pMonitor->rcWork.left + dxy; 05441 iBottom = 05442 pMonitor->rcWork.bottom - pMonitor->rcWork.top + dxy; 05443 05444 /* 05445 * Let console windows maximize smaller than defaults. 05446 */ 05447 if (pwnd->pcls->atomClassName == gatomConsoleClass) { 05448 psrc->cx = min(iRight, psrc->cx); 05449 psrc->cy = min(iBottom, psrc->cy); 05450 } else { 05451 psrc->cx = iRight; 05452 05453 /* 05454 * B#14012 save QuickLink II that wants 4 pixels hanging off 05455 * the screen for every edge except the bottom edge, which 05456 * they only want to overhang by 2 pixels -- jeffbog 5/17/95 05457 * 05458 * BUT THIS CODE DOESN'T WORK FOR MULTIPLE MONITORS, so don't 05459 * do it on secondary dudes. Else, XL '95 flakes out. 05460 */ 05461 if (fIsPrimary && !TestWF(pwnd, WFWIN40COMPAT)) { 05462 psrc->cy = min(iBottom, psrc->cy); 05463 } else { 05464 psrc->cy = iBottom; 05465 } 05466 } 05467 } 05468 05469 } else if (IsMaxedRect(&pMonitor->rcMonitor, psrc)) { 05470 fYielded = xxxAddFullScreen(pwnd, pMonitor); 05471 } 05472 } else { 05473 if (TestWF(pwnd, WFMAXIMIZED)) { 05474 ClrWF(pwnd, WFREALLYMAXIMIZABLE); 05475 } 05476 05477 fYielded = xxxRemoveFullScreen(pwnd, pMonitor); 05478 } 05479 05480 ThreadUnlock(&tlpMonitor); 05481 return fYielded; 05482 } 05483 05484 /***************************************************************************\ 05485 * ClrFTrueVis 05486 * 05487 * Called when making a window invisible. This routine destroys any update 05488 * regions that may exist, and clears the WF_TRUEVIS of all windows below 05489 * the passed in window. 05490 * 05491 * History: 05492 * 11-Jul-1991 DarrinM Ported from Win 3.1 sources. 05493 \***************************************************************************/ 05494 05495 VOID ClrFTrueVis( 05496 PWND pwnd) 05497 { 05498 /* 05499 * Destroy pwnd and its children's update regions. 05500 * We do this here to guarantee that a hidden window 05501 * and its children don't have update regions. 05502 * 05503 * This fixes bugs when destroying windows that have 05504 * update regions (SendDestroyMessages) among others 05505 * and allows us to simplify SetParent(). This was 05506 * deemed better than hacking DoPaint() and/or 05507 * DestroyWindow(). 05508 * 05509 * We can stop recursing when we find a window that doesn't 05510 * have the visible bit set, because by definition it won't 05511 * have any update regions below it (this routine will have been called) 05512 */ 05513 if (NEEDSPAINT(pwnd)) { 05514 05515 DeleteMaybeSpecialRgn(pwnd->hrgnUpdate); 05516 05517 ClrWF(pwnd, WFINTERNALPAINT); 05518 05519 pwnd->hrgnUpdate = NULL; 05520 DecPaintCount(pwnd); 05521 } 05522 05523 for (pwnd = pwnd->spwndChild; pwnd != NULL; pwnd = pwnd->spwndNext) { 05524 05525 /* 05526 * pwnd->fs &= ~WF_TRUEVIS; 05527 */ 05528 if (TestWF(pwnd, WFVISIBLE)) 05529 ClrFTrueVis(pwnd); 05530 } 05531 } 05532 05533 /***************************************************************************\ 05534 * OffsetChildren 05535 * 05536 * Offsets the window and client rects of all children of hwnd. 05537 * Also deals with the children's update regions and SPB rects. 05538 * 05539 * History: 05540 * 22-Jul-1991 DarrinM Ported from Win 3.1 sources. 05541 \***************************************************************************/ 05542 05543 VOID OffsetChildren( 05544 PWND pwnd, 05545 int dx, 05546 int dy, 05547 LPRECT prcHitTest) 05548 { 05549 RECT rc; 05550 PWND pwndStop; 05551 05552 if (!pwnd->spwndChild) 05553 return; 05554 05555 pwndStop = pwnd; 05556 pwnd = pwndStop->spwndChild; 05557 for (;;) { 05558 /* 05559 * Skip windows that don't intersect prcHitTest... 05560 */ 05561 if (prcHitTest && !IntersectRect(&rc, prcHitTest, &pwnd->rcWindow)) 05562 goto NextWindow; 05563 05564 pwnd->rcWindow.left += dx; 05565 pwnd->rcWindow.right += dx; 05566 pwnd->rcWindow.top += dy; 05567 pwnd->rcWindow.bottom += dy; 05568 05569 pwnd->rcClient.left += dx; 05570 pwnd->rcClient.right += dx; 05571 pwnd->rcClient.top += dy; 05572 pwnd->rcClient.bottom += dy; 05573 05574 if (pwnd->hrgnUpdate > HRGN_FULL && !TestWF(pwnd, WFMAXFAKEREGIONAL)) { 05575 GreOffsetRgn(pwnd->hrgnUpdate, dx, dy); 05576 } 05577 05578 /* 05579 * Change position of window region, if it has one 05580 */ 05581 if (pwnd->hrgnClip != NULL) 05582 GreOffsetRgn(pwnd->hrgnClip, dx, dy); 05583 05584 if (TestWF(pwnd, WFHASSPB)) 05585 OffsetRect(&(FindSpb(pwnd))->rc, dx, dy); 05586 05587 #ifdef CHILD_LAYERING 05588 if (TestWF(pwnd, WEFLAYERED)) { 05589 POINT ptPos = {pwnd->rcWindow.left, pwnd->rcWindow.top}; 05590 05591 GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, 05592 &ptPos, NULL, NULL, NULL, 0, NULL, 0, NULL); 05593 } 05594 #endif // CHILD_LAYERING 05595 05596 /* 05597 * Recurse into the child tree if there are children. 05598 */ 05599 if (pwnd->spwndChild) { 05600 pwnd = pwnd->spwndChild; 05601 continue; 05602 } 05603 05604 NextWindow: 05605 if (pwnd->spwndNext) { 05606 /* 05607 * Recurse to the next sibling in the list. 05608 */ 05609 pwnd = pwnd->spwndNext; 05610 } else { 05611 for (;;) { 05612 /* 05613 * We're at the end of the sibling window list. 05614 * Go to the parent's next window. 05615 */ 05616 pwnd = pwnd->spwndParent; 05617 if (pwnd == pwndStop) 05618 return; 05619 05620 if (pwnd->spwndNext) { 05621 pwnd = pwnd->spwndNext; 05622 break; 05623 } 05624 } 05625 } 05626 } 05627 } 05628 05629 /***************************************************************************\ 05630 * SetWindowRgn 05631 * 05632 * Parameters: 05633 * hwnd -- Window handle 05634 * hrgn -- Region to set into window. NULL can be accepted. 05635 * fRedraw -- TRUE to go through SetWindowPos() and calculate 05636 * update regions correctly. If the window is visible 05637 * this will usually be TRUE. 05638 * 05639 * Returns: 05640 * TRUE for success, FALSE for failure 05641 * 05642 * Comments: 05643 * This is a very simple routine to set a window region. It goes through 05644 * SetWindowPos() to get perfect update region calculation, and to deal 05645 * with other related issues like vis rgn change & dc invalidation, 05646 * display lock holding, spb invalidation, etc. Also since it sends 05647 * WM_WINDOWPOSCHANGING & WM_WINDOWPOSCHANGED, we'll be able to expand 05648 * SetWindowPos() in the future to take hrgns directly for efficient 05649 * window state change control (like setting the rect and region at 05650 * the same time, among others) without harming compatibility. 05651 * 05652 * hrgn is in window rect coordinates (not client rect coordinates). 05653 * Once set, hrgn is owned by the system. A copy is not made! 05654 * 05655 * 30-Jul-1994 ScottLu Created. 05656 \***************************************************************************/ 05657 05658 #define SWR_FLAGS_REDRAW (SWP_NOCHANGE | SWP_FRAMECHANGED | SWP_NOACTIVATE) 05659 #define SWR_FLAGS_NOREDRAW (SWP_NOCHANGE | SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOREDRAW) 05660 05661 BOOL xxxSetWindowRgn( 05662 PWND pwnd, 05663 HRGN hrgn, 05664 BOOL fRedraw) 05665 { 05666 PSMWP psmwp; 05667 HRGN hrgnClip = NULL; 05668 BOOL bRet = FALSE; 05669 05670 /* 05671 * Validate the region handle. We did this for 3.51, so 05672 * we better do it for later versions. Our validation will 05673 * make a copy of the clip-rgn and send it through to the 05674 * SetWIndowRgn code. Once this is set in the kernel, we 05675 * will return to the client and the old region will be deleted 05676 * there. 05677 * 05678 * If the region passed in is NULL, then we get rid of the 05679 * current retion. Map it to HRGN_FULL so that SetWindowPos() 05680 * can tell this is what the caller wants. 05681 */ 05682 if (hrgn) { 05683 05684 if ((hrgnClip = UserValidateCopyRgn(hrgn)) == NULL) { 05685 05686 #if DBG 05687 RIPMSG0(RIP_WARNING, "xxxSetWindowRgn: Failed to create region!"); 05688 #endif 05689 goto swrClean; 05690 } 05691 #ifdef USE_MIRRORING 05692 MirrorRegion(pwnd, hrgnClip, FALSE); 05693 #endif 05694 } else { 05695 05696 hrgnClip = HRGN_FULL; 05697 } 05698 05699 /* 05700 * Get a psmwp, and put the region in it, correctly offset. 05701 * Use SWP_FRAMECHANGED with acts really as a "empty" SetWindowPos 05702 * that still sends WM_WINDOWPOSCHANGING and CHANGED messages. 05703 * SWP_NOCHANGE ensures that we don't size, move, activate, zorder. 05704 */ 05705 if (psmwp = InternalBeginDeferWindowPos(1)) { 05706 05707 /* 05708 * psmwp gets freed automatically if this routine fails. 05709 */ 05710 if (psmwp = _DeferWindowPos( 05711 psmwp, 05712 pwnd, 05713 PWND_TOP, 05714 0, 05715 0, 05716 0, 05717 0, 05718 fRedraw ? SWR_FLAGS_REDRAW : SWR_FLAGS_NOREDRAW)) { 05719 05720 /* 05721 * Do the operation. Note that hrgn is still in window coordinates. 05722 * SetWindowPos() will change it to screen coordinates before 05723 * selecting into the window. 05724 */ 05725 psmwp->acvr[0].hrgnClip = hrgnClip; 05726 bRet = xxxEndDeferWindowPosEx(psmwp, FALSE); 05727 } 05728 } 05729 05730 /* 05731 * If the call failed, then delete our region we created. A FALSE 05732 * return means it should've never made it to the xxxSelectWindowRgn 05733 * call, so everything should be as it was. 05734 */ 05735 if (!bRet && (hrgnClip != HRGN_FULL)) { 05736 05737 swrClean: 05738 05739 GreDeleteObject(hrgnClip); 05740 } 05741 05742 return bRet; 05743 } 05744 05745 /***************************************************************************\ 05746 * SelectWindowRgn 05747 * 05748 * This routine does the work of actually selecting in the window region. 05749 * 05750 * 30-Jul-1994 ScottLu Created. 05751 \***************************************************************************/ 05752 05753 void SelectWindowRgn( 05754 PWND pwnd, 05755 HRGN hrgnClip) 05756 { 05757 /* 05758 * If there is a region already there, delete it because 05759 * a new one is being set. For maximized windows in multiple monitor 05760 * mode, we always use the monitor HRGN. We don't make a copy. This 05761 * way, when the hrgn changes because of monitor config, the window's 05762 * monitor region automatically gets updated. Clever huh? Also saves 05763 * memory. 05764 */ 05765 if (pwnd->hrgnClip != NULL) { 05766 if (TestWF(pwnd, WFMAXFAKEREGIONAL)) { 05767 ClrWF(pwnd, WFMAXFAKEREGIONAL); 05768 } else { 05769 /* 05770 * Do NOT select in a monitor region if the window is normally 05771 * regional. The MinMaximize code will always pass HRGN_MONITOR 05772 * to us no matter what. But when we get here, bail out and 05773 * don't destroy the app's region if it has one. 05774 */ 05775 if (hrgnClip == HRGN_MONITOR) 05776 return; 05777 05778 GreDeleteObject(pwnd->hrgnClip); 05779 } 05780 05781 pwnd->hrgnClip = NULL; 05782 } 05783 05784 /* 05785 * NULL or HRGN_FULL means "set to NULL". If we have a real region, 05786 * use it. USER needs to own it, and it needs to be in screen 05787 * coordinates. 05788 */ 05789 if (hrgnClip > HRGN_FULL) { 05790 05791 if (hrgnClip == HRGN_MONITOR) { 05792 PMONITOR pMonitor; 05793 05794 /* 05795 * Use the monitor region if the window is really maxed 05796 * on a monitor. It's already happened by the time we get here, 05797 * if so. And xxxCheckFullScreen will clear the reallymaximed 05798 * style for a maximized window if it doesn't cover the whole 05799 * max area. 05800 */ 05801 UserAssert(pwnd->spwndParent == PWNDDESKTOP(pwnd)); 05802 05803 if (!TestWF(pwnd, WFMAXIMIZED) || !TestWF(pwnd, WFREALLYMAXIMIZABLE)) 05804 return; 05805 05806 /* 05807 * Do nothing for windows off screen. 05808 */ 05809 pMonitor = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTONULL); 05810 if (!pMonitor) 05811 return; 05812 05813 hrgnClip = pMonitor->hrgnMonitor; 05814 SetWF(pwnd, WFMAXFAKEREGIONAL); 05815 } else { 05816 if (pwnd != PWNDDESKTOP(pwnd)) { 05817 GreOffsetRgn(hrgnClip, pwnd->rcWindow.left, pwnd->rcWindow.top); 05818 } 05819 05820 GreSetRegionOwner(hrgnClip, OBJECT_OWNER_PUBLIC); 05821 } 05822 05823 pwnd->hrgnClip = hrgnClip; 05824 } 05825 } 05826 05827 05828 /***************************************************************************\ 05829 * TestRectBogus 05830 * 05831 * Returns TRUE if the window rect [x,y,cx,cy] is centered or 05832 * clipped to the monitor or work rect [prc], FALSE otherwise. 05833 * 05834 * History: 05835 * 26-Mar-1997 adams Created. 05836 \***************************************************************************/ 05837 05838 #define SLOP_X 8 05839 #define SLOP_Y 8 05840 05841 BOOL 05842 TestRectBogus(RECT * prc, int x, int y, int cx, int cy) 05843 { 05844 // 05845 // check for a fullscreen (or offscreen) window 05846 // 05847 if ( x <= prc->left && 05848 y <= prc->top && 05849 cx >= (prc->right - prc->left) && 05850 cy >= (prc->bottom - prc->top)) { 05851 05852 // rect is fullscreen 05853 return FALSE; 05854 } 05855 05856 // 05857 // check for the window being centered to the work area 05858 // use <= for y to catch dialogs centered "high" 05859 // (like the network logon dialog) 05860 // 05861 if ( abs(x - (prc->right + prc->left - cx) / 2) <= SLOP_X && 05862 abs(y - (prc->bottom + prc->top - cy) / 2) <= SLOP_Y ) { 05863 05864 // rect centered 05865 return TRUE; 05866 } 05867 05868 // 05869 // check for the window being cliped to the work area 05870 // 05871 if ( x == prc->left || 05872 y == prc->top || 05873 x == (prc->right - cx) || 05874 y == (prc->bottom - cy)) { 05875 05876 // rect is clipped 05877 return TRUE; 05878 } 05879 05880 return FALSE; 05881 } 05882 05883 05884 /***************************************************************************\ 05885 * IsRectBogus 05886 * 05887 * Returns TRUE if the window rect [x,y,cx,cy] is centered or 05888 * clipped to the monitor or work rect of the primary monitor. 05889 * 05890 * History: 05891 * 26-Mar-1997 adams Created. 05892 \***************************************************************************/ 05893 05894 BOOL 05895 IsRectBogus(int x, int y, int cx, int cy) 05896 { 05897 PMONITOR pMonitorPrimary = GetPrimaryMonitor(); 05898 05899 return TestRectBogus(&pMonitorPrimary->rcWork, x, y, cx, cy) || 05900 TestRectBogus(&pMonitorPrimary->rcMonitor, x, y, cx, cy); 05901 } 05902 05903 05904 05905 /***************************************************************************\ 05906 * FixBogusSWP 05907 * 05908 * Detects if a rect is being centered or clipped to the primary monitor, 05909 * and centers it in its owner's window if so. This prevents apps that 05910 * are not multimon aware from having their "main" window displayed on 05911 * one monitor but their dialogs moved to the primary monitor 05912 * because they believe the dialog is offscreen. 05913 * 05914 * History: 05915 * 26-Mar-1997 adams Created. 05916 \***************************************************************************/ 05917 05918 void 05919 FixBogusSWP(PWND pwnd, int * px, int * py, int cx, int cy, UINT flags) 05920 { 05921 PMONITOR pMonitor; 05922 05923 pMonitor = _MonitorFromWindow(pwnd->spwndOwner, MONITOR_DEFAULTTONEAREST); 05924 05925 // 05926 // only check for a bogus SWP if the owner is not on the primary 05927 // 05928 if (pMonitor != GetPrimaryMonitor()) { 05929 05930 // 05931 // get the current size if SWP_NOSIZE is set 05932 // 05933 if (flags & SWP_NOSIZE) { 05934 cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 05935 cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 05936 } 05937 05938 // 05939 // see if the app is trying to center or clip the window 05940 // 05941 if (IsRectBogus(*px, *py, cx, cy)) 05942 { 05943 RECT rc; 05944 05945 #if DBG 05946 int oldX = *px; 05947 int oldY = *py; 05948 #endif 05949 05950 // 05951 // the app wants to center/clip the window 05952 // we will have to do it for them. 05953 // 05954 // get the window rect of the parent and 05955 // intersect that with the work area of 05956 // the owning monitor, then center the 05957 // window to this rect. 05958 // 05959 IntersectRect(&rc, &pMonitor->rcWork, &pwnd->spwndOwner->rcWindow); 05960 05961 // 05962 // new multimonior friendly position. 05963 // 05964 *px = rc.left + (rc.right - rc.left - cx) / 2; 05965 *py = rc.top + (rc.bottom - rc.top - cy) / 2; 05966 05967 // 05968 // now clip to the work area. 05969 // 05970 if (*px + cx > pMonitor->rcWork.right) { 05971 *px = pMonitor->rcWork.right - cx; 05972 } 05973 05974 if (*py + cy > pMonitor->rcWork.bottom) { 05975 *py = pMonitor->rcWork.bottom - cy; 05976 } 05977 05978 if (*px < pMonitor->rcWork.left) { 05979 *px = pMonitor->rcWork.left; 05980 } 05981 05982 if (*py < pMonitor->rcWork.top) { 05983 *py = pMonitor->rcWork.top; 05984 } 05985 05986 RIPMSG0(RIP_WARNING | RIP_THERESMORE, "SetWindowPos detected that your app is centering or clipping"); 05987 RIPMSG0(RIP_WARNING | RIP_THERESMORE | RIP_NONAME, "a window to the primary monitor when its owner is on a different monitor."); 05988 RIPMSG0(RIP_WARNING | RIP_THERESMORE | RIP_NONAME, "Consider fixing your app to use the Window Manager Multimonitor APIs."); 05989 RIPMSG4(RIP_WARNING | RIP_NONAME, "SetWindowPos moved the window from (%d,%d) to (%d,%d).\n", 05990 oldX, oldY, *px, *py); 05991 } 05992 } 05993 } 05994 05995 /***************************************************************************\ 05996 * PreventInterMonitorBlts() 05997 * 05998 * Prevents monitor-to-monitor blts when they are different caps. This 05999 * way we redraw the part of a window that moves to a different monitor. 06000 * We try to blt as much as possible. 06001 * 06002 * We look at the source rect and what monitor owns it, and how much that 06003 * monitor also contains of the destination rect. Then we compare that 06004 * with the destination rect and what monitor owns that, and how much it 06005 * contains of the source rect. The larger wins. 06006 * 06007 * rcBlt is in screen coordinates and is the DESTINATION. 06008 * 06009 * History: 06010 * 11-11-1997 vadimg ported from Memphis 06011 \***************************************************************************/ 06012 06013 void PreventInterMonitorBlts(PCVR pcvr) 06014 { 06015 RECT rcSrc; 06016 RECT rcDst; 06017 RECT rcSrcT; 06018 RECT rcDstT; 06019 PMONITOR pMonitor; 06020 // 06021 // If the destination is empty do nothing. 06022 // 06023 if (IsRectEmpty(&pcvr->rcBlt)) 06024 return; 06025 06026 // 06027 // Get the source rect (rcBlt is the destination, dxBlt/dyBlt are the 06028 // distance moved from the source). 06029 // 06030 CopyOffsetRect(&rcSrc, &pcvr->rcBlt, -pcvr->dxBlt, -pcvr->dyBlt); 06031 06032 // 06033 // Split up the source into its monitor pieces. If the source intersects 06034 // a monitor, then figure out where that part will be in the destination. 06035 // Intersect the destination part with the same monitor. The result is 06036 // the amount we can blt from the source to the dest on that monitor. 06037 // 06038 // We do this for each monitor to find the biggest blt rect. We want 06039 // the biggest because we want to repaint as little as possible. We do 06040 // bail out if both the source and dest are fully contained on the same 06041 // monitor. 06042 // 06043 for (pMonitor = gpDispInfo->pMonitorFirst; 06044 pMonitor != NULL; 06045 pMonitor = pMonitor->pMonitorNext) { 06046 06047 // 06048 // We're only interested in visible monitors 06049 // 06050 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) 06051 continue; 06052 // 06053 // If this monitor doesn't contain a piece of the source, we don't 06054 // care about it. We won't be doing a same monitor blt on it for sure. 06055 // 06056 if (!IntersectRect(&rcSrcT, &rcSrc, &pMonitor->rcMonitor)) 06057 continue; 06058 06059 // 06060 // See where this rect would be in the destination. 06061 // 06062 CopyOffsetRect(&rcDst, &rcSrcT, pcvr->dxBlt, pcvr->dyBlt); 06063 06064 // 06065 // Intersect this rect with the same monitor rect to see what piece 06066 // can be safely blted on the same monitor. 06067 // 06068 IntersectRect(&rcDstT, &rcDst, &pMonitor->rcMonitor); 06069 06070 // 06071 // Is this piece of the source staying on this monitor? 06072 // 06073 if (EqualRect(&rcDstT, &rcDst)) { 06074 // 06075 // This source piece is staying completely on this monitor when 06076 // it becomes the destination. Hence there is nothing to add 06077 // to our invalid sum, hrgnInterMonitor. 06078 // 06079 if (EqualRect(&rcSrcT, &rcSrc)) { 06080 // 06081 // The source is completely ON one monitor and moving to 06082 // a location also completely ON this monitor. Great, no 06083 // intermonitor blts whatsoever. We are done. 06084 // 06085 UserAssert(pcvr->hrgnInterMonitor == NULL); 06086 return; 06087 } else { 06088 continue; 06089 } 06090 } 06091 06092 // 06093 // OK, some piece of the source is moving across monitors. Figure 06094 // out what it is and where that piece is in the destination. That 06095 // piece in the destination must be invalidated and not blted. 06096 // 06097 if (pcvr->hrgnInterMonitor == NULL) { 06098 pcvr->hrgnInterMonitor = CreateEmptyRgn(); 06099 } 06100 06101 // 06102 // The difference between the transposed source to the dest, and the 06103 // real part of the dest that lies on this monitor, is the amount 06104 // of the source that will move across a monitor boundary. Add this 06105 // to our accumulated invalid region. 06106 // 06107 // rcDst is the whole source chunk, rcDstT is the part on the same 06108 // monitor as the source chunk. 06109 // 06110 GreSetRectRgn(ghrgnInv2, rcDst.left, rcDst.top, rcDst.right, rcDst.bottom); 06111 GreSetRectRgn(ghrgnGDC, rcDstT.left, rcDstT.top, rcDstT.right, rcDstT.bottom); 06112 SubtractRgn(ghrgnInv2, ghrgnInv2, ghrgnGDC); 06113 UnionRgn(pcvr->hrgnInterMonitor, pcvr->hrgnInterMonitor, ghrgnInv2); 06114 } 06115 #if DBG 06116 VerifyVisibleMonitorCount(); 06117 #endif 06118 } 06119

Generated on Sat May 15 19:41:55 2004 for test by doxygen 1.3.7