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

minmax.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: minmax.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Window Minimize/Maximize Routines 00007 * 00008 \***************************************************************************/ 00009 00010 #include "precomp.h" 00011 #pragma hdrstop 00012 00013 /* 00014 * How long we want animation to last, in milliseconds 00015 */ 00016 #define CMS_ANIMATION 250 00017 #define DX_GAP (SYSMET(CXMINSPACING) - SYSMET(CXMINIMIZED)) 00018 #define DY_GAP (SYSMET(CYMINSPACING) - SYSMET(CYMINIMIZED)) 00019 00020 00021 /***************************************************************************\ 00022 * xxxInitSendValidateMinMaxInfo() 00023 * 00024 * Routine which initializes the minmax array, sends WM_GETMINMAXINFO to 00025 * the caller, and validates the results. 00026 * 00027 * Returns FALSE is the window went away in the middle. 00028 * 00029 \***************************************************************************/ 00030 00031 void 00032 xxxInitSendValidateMinMaxInfo(PWND pwnd, LPMINMAXINFO lpmmi) 00033 { 00034 PTHREADINFO ptiCurrent; 00035 PMONITOR pMonitorReal; 00036 PMONITOR pMonitorPrimary; 00037 TL tlpMonitorReal; 00038 TL tlpMonitorPrimary; 00039 CHECKPOINT * pcp; 00040 RECT rcParent; 00041 int cBorders; 00042 int xMin, yMin; 00043 00044 CheckLock(pwnd); 00045 00046 ptiCurrent = PtiCurrent(); 00047 00048 /* 00049 * FILL IN THE MINMAXINFO WE THINK IS APPROPRIATE 00050 */ 00051 00052 /* 00053 * Minimized Size 00054 */ 00055 lpmmi->ptReserved.x = SYSMET(CXMINIMIZED); 00056 lpmmi->ptReserved.y = SYSMET(CYMINIMIZED); 00057 00058 /* 00059 * Maximized Position and Size 00060 * Figure out where the window would be maximized within its parent. 00061 */ 00062 pMonitorPrimary = GetPrimaryMonitor(); 00063 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00064 /* What monitor is the window really going to maximize to? */ 00065 pMonitorReal = _MonitorFromWindow(pwnd, MONITOR_DEFAULTTOPRIMARY); 00066 00067 /* Send dimensions based on the primary only. */ 00068 rcParent = pMonitorPrimary->rcMonitor; 00069 } else { 00070 pMonitorReal = NULL; 00071 _GetClientRect(pwnd->spwndParent, &rcParent); 00072 } 00073 00074 cBorders = GetWindowBorders(pwnd->style, pwnd->ExStyle, TRUE, FALSE); 00075 00076 InflateRect(&rcParent, 00077 cBorders * SYSMET(CXBORDER), 00078 cBorders * SYSMET(CYBORDER)); 00079 00080 rcParent.right -= rcParent.left; 00081 rcParent.bottom -= rcParent.top; 00082 00083 /* rcParent.right, bottom are width and height now. */ 00084 lpmmi->ptMaxSize.x = rcParent.right; 00085 lpmmi->ptMaxSize.y = rcParent.bottom; 00086 00087 pcp = (CHECKPOINT *)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL); 00088 if (pcp && pcp->fMaxInitialized) { 00089 /* 00090 * Note: For top level windows, we will fix this point up after 00091 * the fact if it has gotten out of date because the size border 00092 * changed. 00093 */ 00094 lpmmi->ptMaxPosition = pcp->ptMax; 00095 } else { 00096 lpmmi->ptMaxPosition = *((LPPOINT)&rcParent.left); 00097 } 00098 00099 /* 00100 * Normal minimum tracking size 00101 * Only enforce min tracking size for windows with captions 00102 */ 00103 xMin = cBorders*SYSMET(CXEDGE); 00104 yMin = cBorders*SYSMET(CYEDGE); 00105 00106 if (TestWF(pwnd, WFCAPTION) && !TestWF(pwnd, WEFTOOLWINDOW)) { 00107 lpmmi->ptMinTrackSize.x = SYSMET(CXMINTRACK); 00108 lpmmi->ptMinTrackSize.y = SYSMET(CYMINTRACK); 00109 } else { 00110 lpmmi->ptMinTrackSize.x = max(SYSMET(CXEDGE), xMin); 00111 lpmmi->ptMinTrackSize.y = max(SYSMET(CYEDGE), yMin); 00112 } 00113 00114 /* 00115 * Normal maximum tracking size 00116 */ 00117 lpmmi->ptMaxTrackSize.x = SYSMET(CXMAXTRACK); 00118 lpmmi->ptMaxTrackSize.y = SYSMET(CYMAXTRACK); 00119 00120 /* 00121 * SEND THE WM_GETMINMAXINFO MESSAGE 00122 */ 00123 00124 ThreadLockWithPti(ptiCurrent, pMonitorReal, &tlpMonitorReal); 00125 ThreadLockAlwaysWithPti(ptiCurrent, pMonitorPrimary, &tlpMonitorPrimary); 00126 xxxSendMessage(pwnd, WM_GETMINMAXINFO, 0, (LPARAM)lpmmi); 00127 00128 /* 00129 * VALIDATE THE MINMAXINFO 00130 */ 00131 00132 /* 00133 * Minimized Size (this is read only) 00134 */ 00135 lpmmi->ptReserved.x = SYSMET(CXMINIMIZED); 00136 lpmmi->ptReserved.y = SYSMET(CYMINIMIZED); 00137 00138 /* 00139 * Maximized Postion and Size (only for top level windows) 00140 */ 00141 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 00142 LPRECT lprcRealMax; 00143 00144 GetMonitorMaxArea(pwnd, pMonitorReal, &lprcRealMax); 00145 00146 /* 00147 * Is the window a TRUE maximized dude, or somebody like the DOS box 00148 * who can maximize but not take up the entire screen? 00149 * 00150 * Is the window really maximizeable? 00151 */ 00152 if ((lpmmi->ptMaxSize.x >= (pMonitorPrimary->rcMonitor.right - pMonitorPrimary->rcMonitor.left)) && 00153 (lpmmi->ptMaxSize.y >= (pMonitorPrimary->rcMonitor.bottom - pMonitorPrimary->rcMonitor.top))) { 00154 00155 SetWF(pwnd, WFREALLYMAXIMIZABLE); 00156 00157 /* 00158 * Need to reload the checkpoint here, since it might have gotten 00159 * blown away while we were in the xxxSendMessage call above. 00160 */ 00161 pcp = (CHECKPOINT *)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL); 00162 00163 if ( pcp && 00164 pcp->fMaxInitialized && 00165 TestWF(pwnd, WFSIZEBOX) && 00166 (lpmmi->ptMaxPosition.x != rcParent.left) && 00167 (pcp->ptMax.x == lpmmi->ptMaxPosition.x)) { 00168 00169 /* 00170 * If this window has a weird maximize point that doesn't jibe 00171 * with what we'd expect and it has a checkpoint, fix up the 00172 * checkpoint. It means that somebody's WINDOWPLACEMENT 00173 * got out of date when the size border changed dimensions. 00174 */ 00175 pcp->fMaxInitialized = FALSE; 00176 00177 lpmmi->ptMaxPosition.y += (rcParent.left - lpmmi->ptMaxPosition.x); 00178 lpmmi->ptMaxPosition.x = rcParent.left; 00179 } 00180 00181 /* 00182 * Transfer the maximum size over to the monitor we are REALLY 00183 * moving to. And fix up guys going fullscreen. A whole bunch 00184 * of Consumer titles + Word '95 and XL '95 move their caption 00185 * above the top of the monitor when going fullscreen. Detect 00186 * these guys now, and let them take up the monitor. 00187 */ 00188 if ( lpmmi->ptMaxPosition.y + SYSMET(CYCAPTION) <= 00189 pMonitorPrimary->rcMonitor.top 00190 && 00191 lpmmi->ptMaxPosition.y + lpmmi->ptMaxSize.y >= 00192 pMonitorPrimary->rcMonitor.bottom) { 00193 00194 lprcRealMax = &pMonitorReal->rcMonitor; 00195 } 00196 00197 /* 00198 * Compensate for the difference between the primary monitor 00199 * and the monitor we are actually on. 00200 */ 00201 lpmmi->ptMaxSize.x = lpmmi->ptMaxSize.x - 00202 (pMonitorPrimary->rcMonitor.right - pMonitorPrimary->rcMonitor.left) + 00203 (lprcRealMax->right - lprcRealMax->left); 00204 00205 lpmmi->ptMaxSize.y = lpmmi->ptMaxSize.y - 00206 (pMonitorPrimary->rcMonitor.bottom - pMonitorPrimary->rcMonitor.top) + 00207 (lprcRealMax->bottom - lprcRealMax->top); 00208 } else { 00209 ClrWF(pwnd, WFREALLYMAXIMIZABLE); 00210 } 00211 00212 /* 00213 * Now transfer the max position over to the monitor we are REALLY 00214 * moving to. 00215 */ 00216 lpmmi->ptMaxPosition.x += lprcRealMax->left; 00217 lpmmi->ptMaxPosition.y += lprcRealMax->top; 00218 } 00219 00220 ThreadUnlock(&tlpMonitorPrimary); 00221 ThreadUnlock(&tlpMonitorReal); 00222 00223 /* 00224 * Normal minimum tracking size. 00225 */ 00226 00227 /* 00228 * WFCAPTION == WFBORDER | WFDLGFRAME; So, when we want to test for the 00229 * presence of CAPTION, we must test for both the bits. Otherwise we 00230 * might mistake WFBORDER or WFDLGFRAME to be a CAPTION. 00231 * 00232 * 00233 * We must not allow a window to be sized smaller than the border 00234 * thickness -- SANKAR -- 06/12/91 -- 00235 */ 00236 if (TestWF(pwnd, WFCPRESENT)) { 00237 00238 /* 00239 * NOTE THAT IF YOU CHANGE THE SPACING OF STUFF IN THE CAPTION, 00240 * YOU NEED TO KEEP THE FOLLOWING IN SSYNC: 00241 * (1) Default CXMINTRACK, CYMINTRACK in inctlpan.c 00242 * (2) The default minimum right below 00243 * (3) Hit testing 00244 * 00245 * The minimum size should be space for: 00246 * * The borders 00247 * * The buttons 00248 * * Margins 00249 * * 4 chars of text 00250 * * Caption icon 00251 */ 00252 yMin = SYSMET(CYMINTRACK); 00253 00254 /* 00255 * Min track size is determined by the number of buttons in 00256 * the caption. 00257 */ 00258 if (TestWF(pwnd, WEFTOOLWINDOW)) { 00259 00260 /* 00261 * Add in space for close button. 00262 */ 00263 if (TestWF(pwnd, WFSYSMENU)) 00264 xMin += SYSMET(CXSMSIZE); 00265 00266 /* 00267 * DON'T add in space for 2 characters--breaks 00268 * MFC toolbar stuff. They want to make vertical undocked 00269 * toolbars narrower than what that would produce. 00270 */ 00271 xMin += (2 * SYSMET(CXEDGE)); 00272 00273 } else { 00274 00275 if (TestWF(pwnd, WFSYSMENU)) { 00276 00277 /* 00278 * Add in space for min/max/close buttons. Otherwise, 00279 * if it's a contexthelp window, then add in space 00280 * for help/close buttons. 00281 */ 00282 if (TestWF(pwnd, (WFMINBOX | WFMAXBOX))) 00283 xMin += 3 * SYSMET(CXSIZE); 00284 else if (TestWF(pwnd, WEFCONTEXTHELP)) 00285 xMin += 2 * SYSMET(CXSIZE); 00286 00287 00288 /* 00289 * Add in space for system menu icon. 00290 */ 00291 if (_HasCaptionIcon(pwnd)) 00292 xMin += SYSMET(CYSIZE); 00293 } 00294 00295 /* 00296 * Add in space for 4 characters and margins. 00297 */ 00298 xMin += 4 * gcxCaptionFontChar + 2 * SYSMET(CXEDGE); 00299 } 00300 } 00301 00302 lpmmi->ptMinTrackSize.x = max(lpmmi->ptMinTrackSize.x, xMin); 00303 lpmmi->ptMinTrackSize.y = max(lpmmi->ptMinTrackSize.y, yMin); 00304 } 00305 00306 00307 00308 /***************************************************************************\ 00309 * ParkIcon 00310 * 00311 * Called when minimizing a window. This parks the minwnd in the position 00312 * given in the checkpoint or calculates a new position for it. 00313 * 00314 * LauraBu 10/15/92 00315 * We now let the user specify two things that affect parking and arranging: 00316 * (1) The corner to start arranging from 00317 * (2) The direction to move in first 00318 * MCostea 11/13/98 #246397 00319 * Add sanity check for the number of tries. If the metrics are messed up 00320 * and pwnd has a lot of siblings, the for-ever loop would make us timeout 00321 * 00322 \***************************************************************************/ 00323 00324 VOID ParkIcon( 00325 PWND pwnd, 00326 PCHECKPOINT pcp) 00327 { 00328 RECT rcTest; 00329 RECT rcT; 00330 UINT xIconPositions; 00331 UINT xIconT; 00332 PWND pwndTest; 00333 PWND pwndParent; 00334 int xOrg; 00335 int yOrg; 00336 int dx; 00337 int dy; 00338 int dxSlot; 00339 int dySlot; 00340 int iteration; 00341 BOOL fHorizontal; 00342 PCHECKPOINT pncp; 00343 00344 /* 00345 * Put these into local vars immediately. The compiler is too dumb to 00346 * know that we're using a constant offset into a constant address, and 00347 * thus a resulting constant address. 00348 */ 00349 dxSlot = SYSMET(CXMINSPACING); 00350 dySlot = SYSMET(CYMINSPACING); 00351 00352 if (IsTrayWindow(pwnd)) { 00353 00354 pcp->fMinInitialized = TRUE; 00355 pcp->ptMin.x = WHERE_NOONE_CAN_SEE_ME; 00356 pcp->ptMin.y = WHERE_NOONE_CAN_SEE_ME; 00357 00358 return; 00359 } 00360 00361 /* We need to adjust the client rectangle for scrollbars, just like we 00362 * do in ArrangeIconicWindows(). If one thing is clear, it is that 00363 * parking and arranging must follow the same principles. This is to 00364 * avoid the user arranging some windows, creating a new one, and parking 00365 * it in a place not consistent with the arrangement of the others. 00366 */ 00367 pwndParent = pwnd->spwndParent; 00368 GetRealClientRect(pwndParent, &rcT, GRC_SCROLLS, NULL); 00369 00370 /* 00371 * Get gravity & move vars. We want gaps to start on the sides that 00372 * we begin arranging from. 00373 * 00374 * Horizontal gravity 00375 */ 00376 if (SYSMET(ARRANGE) & ARW_STARTRIGHT) { 00377 00378 /* 00379 * Starting on right side 00380 */ 00381 rcTest.left = xOrg = rcT.right - dxSlot; 00382 dx = -dxSlot; 00383 00384 } else { 00385 00386 /* 00387 * Starting on left 00388 */ 00389 rcTest.left = xOrg = rcT.left + DX_GAP; 00390 dx = dxSlot; 00391 } 00392 00393 /* 00394 * Vertical gravity 00395 */ 00396 if (SYSMET(ARRANGE) & ARW_STARTTOP) { 00397 00398 /* 00399 * Starting on top side 00400 */ 00401 rcTest.top = yOrg = rcT.top + DY_GAP; 00402 dy = dySlot; 00403 00404 } else { 00405 00406 /* 00407 * Starting on bottom 00408 */ 00409 rcTest.top = yOrg = rcT.bottom - dySlot; 00410 dy = -dySlot; 00411 } 00412 00413 /* 00414 * Get arrangement direction. Note that ARW_HORIZONTAL is 0, so we 00415 * can't test for it. 00416 */ 00417 fHorizontal = ((SYSMET(ARRANGE) & ARW_DOWN) ? FALSE : TRUE); 00418 00419 if (fHorizontal) 00420 xIconPositions = xIconT = max(1, (rcT.right / dxSlot)); 00421 else 00422 xIconPositions = xIconT = max(1, (rcT.bottom / dySlot)); 00423 00424 /* 00425 * BOGUS 00426 * LauraBu 10/15/92 00427 * What happens if the parent is scrolled over horizontally or 00428 * vertically? Just like when you drop an object... 00429 */ 00430 iteration = 0; 00431 while (iteration < 5000) { 00432 00433 /* 00434 * Make a rectangle representing this position, in screen coords 00435 */ 00436 rcTest.right = rcTest.left + dxSlot; 00437 rcTest.bottom = rcTest.top + dySlot; 00438 00439 /* 00440 * Look for intersections with existing iconic windows 00441 */ 00442 for (pwndTest = pwndParent->spwndChild; pwndTest; pwndTest = pwndTest->spwndNext) { 00443 00444 if (!TestWF(pwndTest, WFVISIBLE)) 00445 continue; 00446 00447 if (pwndTest == pwnd) 00448 continue; 00449 00450 if (!TestWF(pwndTest, WFMINIMIZED)) { 00451 00452 /* 00453 * This is a non-minimized window. See if it has a checkpoint 00454 * and find out where it would be if it were minimized. We 00455 * will try not to park an icon in this spot. 00456 */ 00457 pncp = (PCHECKPOINT)_GetProp(pwndTest, 00458 PROP_CHECKPOINT, 00459 PROPF_INTERNAL); 00460 00461 if (!pncp || !pncp->fDragged || !pncp->fMinInitialized) 00462 continue; 00463 00464 /* 00465 * Get parent coordinates of minimized window pos. 00466 */ 00467 rcT.right = rcT.left = pncp->ptMin.x; 00468 rcT.right += dxSlot; 00469 rcT.bottom = rcT.top = pncp->ptMin.y; 00470 rcT.bottom += dySlot; 00471 00472 } else { 00473 00474 /* 00475 * Get parent coordinates of currently minimized window 00476 */ 00477 GetRect(pwndTest, &rcT, GRECT_WINDOW | GRECT_PARENTCOORDS); 00478 } 00479 00480 iteration++; 00481 /* 00482 * Get out of loop if they overlap 00483 */ 00484 if (IntersectRect(&rcT, &rcT, &rcTest)) 00485 break; 00486 } 00487 00488 /* 00489 * Found a position that doesn't overlap, so get out of search loop 00490 */ 00491 if (!pwndTest) 00492 break; 00493 00494 /* 00495 * Else setup to process the next position 00496 */ 00497 if (--xIconT == 0) { 00498 00499 /* 00500 * Setup next pass 00501 */ 00502 xIconT = xIconPositions; 00503 00504 if (fHorizontal) { 00505 rcTest.left = xOrg; 00506 rcTest.top += dy; 00507 } else { 00508 rcTest.left += dx; 00509 rcTest.top = yOrg; 00510 } 00511 00512 } else { 00513 00514 /* 00515 * Same pass. 00516 */ 00517 if (fHorizontal) 00518 rcTest.left += dx; 00519 else 00520 rcTest.top += dy; 00521 } 00522 } 00523 00524 /* 00525 * Note that rcTest is in parent coordinates already. 00526 */ 00527 pcp->fMinInitialized = TRUE; 00528 pcp->ptMin.x = rcTest.left; 00529 pcp->ptMin.y = rcTest.top; 00530 } 00531 00532 /***************************************************************************\ 00533 * xxxAnimateCaption 00534 * 00535 * 00536 \***************************************************************************/ 00537 00538 ULONG_PTR SaveScreen(PWND pwnd, ULONG iMode, ULONG_PTR iSave, int x, int y, int cx, int cy) 00539 { 00540 RECT rc; 00541 00542 /* 00543 * x and y are in the DC coordinates, make the screen in the 00544 * (meta hdev) coordinates for the call to Gre/driver. 00545 */ 00546 rc.left = x + pwnd->rcWindow.left; 00547 rc.right = x + cx; 00548 rc.top = y + pwnd->rcWindow.top; 00549 rc.bottom = y + cy; 00550 00551 if (IntersectRect(&rc, &rc, &gpDispInfo->rcScreen)) { 00552 return GreSaveScreenBits(gpDispInfo->hDev, iMode, iSave, (RECTL*)&rc); 00553 } else { 00554 return 0; 00555 } 00556 } 00557 00558 VOID xxxAnimateCaption( 00559 PWND pwnd, 00560 HDC hdc, 00561 LPRECT lprcStart, 00562 LPRECT lprcEnd) 00563 { 00564 DWORD dwTimeStart; 00565 DWORD iTimeElapsed; 00566 int iLeftStart; 00567 int iTopStart; 00568 int cxStart; 00569 int dLeft; 00570 int dTop; 00571 int dcx; 00572 int iLeft; 00573 int iTop; 00574 int cx; 00575 int iLeftNew; 00576 int iTopNew; 00577 int cxNew; 00578 int cBorders; 00579 HBITMAP hbmpOld; 00580 RECT rc; 00581 int cy; 00582 HDC hdcMem; 00583 ULONG_PTR uSave; 00584 PWND pwndOrg; 00585 00586 CheckLock(pwnd); 00587 00588 if ((pwndOrg = _WindowFromDC(hdc)) == NULL) { 00589 RIPMSG0(RIP_WARNING, "SaveScreen: invalid DC passed in"); 00590 return; 00591 } 00592 00593 cy = SYSMET(CYCAPTION) - 1; 00594 00595 /* 00596 * kurtp: 29-Jan-1997 00597 * 00598 * We don't do anything when animating the caption, 00599 * because we couldn't get the desired effect at the 00600 * client. If we do use it then the 00601 * cache gets a bunch of bitmaps (size: 2xCaption by CXScreen) 00602 * that are never re-used. This slows down clients 00603 * because the GreBitBlts always generate new bitmaps 00604 * and the cache is displaced by the new bitmaps (yuk!). 00605 */ 00606 00607 if (gbRemoteSession) 00608 return; 00609 00610 if ((hdcMem = GreCreateCompatibleDC(ghdcMem)) == NULL) 00611 return; 00612 00613 /* 00614 * If the caption strip doesn't exist, then attempt to recreate it. This 00615 * might be necessary if the user does a mode-switch during low memory 00616 * and is not able to recreate the surface. When the memory becomes 00617 * available, we'll attempt to recreate it here. 00618 */ 00619 if (ghbmCaption == NULL) { 00620 ghbmCaption = CreateCaptionStrip(); 00621 } 00622 00623 hbmpOld = GreSelectBitmap(hdcMem, ghbmCaption); 00624 00625 /* 00626 * initialize start values 00627 */ 00628 iTopStart = lprcStart->top; 00629 iLeftStart = lprcStart->left; 00630 cxStart = lprcStart->right - iLeftStart; 00631 00632 /* 00633 * initialize delta values to the destination dimensions 00634 */ 00635 dLeft = lprcEnd->left; 00636 dTop = lprcEnd->top; 00637 dcx = lprcEnd->right - dLeft; 00638 00639 /* 00640 * adjust for window borders as appropriate 00641 */ 00642 cBorders = GetWindowBorders(pwnd->style, 00643 pwnd->ExStyle, 00644 TRUE, 00645 FALSE); 00646 00647 if ((lprcStart->bottom - iTopStart) > SYSMET(CYCAPTION)) { 00648 00649 iLeftStart += cBorders; 00650 iTopStart += cBorders; 00651 cxStart -= 2*cBorders; 00652 } 00653 00654 if ((lprcEnd->bottom - dTop) > SYSMET(CYCAPTION)) { 00655 00656 dLeft += cBorders; 00657 dTop += cBorders; 00658 dcx -= 2*cBorders; 00659 } 00660 00661 /* 00662 * initialize step values 00663 */ 00664 iLeft = iLeftStart; 00665 iTop = iTopStart; 00666 cx = cxStart; 00667 00668 /* 00669 * initialize off screen bitmap with caption drawing and first saved rect 00670 */ 00671 rc.left = 0; 00672 rc.top = cy; 00673 rc.right = max(cxStart, dcx); 00674 rc.bottom = cy * 2; 00675 00676 xxxDrawCaptionTemp(pwnd, 00677 hdcMem, 00678 &rc, 00679 NULL, 00680 NULL, 00681 NULL, 00682 DC_ACTIVE | DC_ICON | DC_TEXT | 00683 (TestALPHA(GRADIENTCAPTIONS) ? DC_GRADIENT : 0)); 00684 00685 if ((uSave = SaveScreen(pwndOrg, SS_SAVE, 0,iLeft, iTop, cx, cy)) == 0) { 00686 if (!GreBitBlt(hdcMem, 00687 0, 00688 0, 00689 cx, 00690 cy, 00691 hdc, 00692 iLeft, 00693 iTop, 00694 SRCCOPY, 00695 0)) { 00696 goto Cleanup; 00697 } 00698 } 00699 00700 /* 00701 * compute delta values by subtracting source dimensions 00702 */ 00703 dLeft -= iLeftStart; 00704 dTop -= iTopStart; 00705 dcx -= cxStart; 00706 00707 /* 00708 * blt and time first caption on screen 00709 * WARNING: If you use *lpSystemTickCount here, 00710 * the compiler may not generate code to do a DWORD fetch; 00711 */ 00712 dwTimeStart = NtGetTickCount(); 00713 GreBitBlt(hdc, 00714 iLeft, 00715 iTop, 00716 cx, 00717 cy, 00718 hdcMem, 00719 0, 00720 cy, 00721 SRCCOPY, 00722 0); 00723 00724 iTimeElapsed = (NtGetTickCount() - dwTimeStart); 00725 00726 while (LOWORD(iTimeElapsed) <= CMS_ANIMATION) { 00727 00728 iLeftNew = iLeftStart + MultDiv(dLeft, LOWORD(iTimeElapsed), CMS_ANIMATION); 00729 iTopNew = iTopStart + MultDiv(dTop, LOWORD(iTimeElapsed), CMS_ANIMATION); 00730 cxNew = cxStart + MultDiv(dcx, LOWORD(iTimeElapsed), CMS_ANIMATION); 00731 00732 /* 00733 * Delay before next frame 00734 */ 00735 UserSleep(1); 00736 00737 /* 00738 * restore saved rect 00739 */ 00740 if (uSave != 0) { 00741 SaveScreen(pwndOrg, SS_RESTORE, uSave, iLeft, iTop, cx, cy); 00742 } else { 00743 GreBitBlt(hdc, 00744 iLeft, 00745 iTop, 00746 cx, 00747 cy, 00748 hdcMem, 00749 0, 00750 0, 00751 SRCCOPY, 00752 0); 00753 } 00754 00755 iLeft = iLeftNew; 00756 iTop = iTopNew; 00757 cx = cxNew; 00758 00759 /* 00760 * save new rect offscreen and then draw over it onscreen. 00761 */ 00762 if (uSave != 0) { 00763 uSave = SaveScreen(pwndOrg, SS_SAVE, 0, iLeft, iTop, cx, cy); 00764 } else { 00765 GreBitBlt(hdcMem, 00766 0, 00767 0, 00768 cx, 00769 cy, 00770 hdc, 00771 iLeft, 00772 iTop, 00773 SRCCOPY, 00774 0); 00775 } 00776 GreBitBlt(hdc, 00777 iLeft, 00778 iTop, 00779 cx, 00780 cy, 00781 hdcMem, 00782 0, 00783 cy, 00784 SRCCOPY, 00785 0); 00786 00787 /* 00788 * update elapsed time 00789 * WARNING: If you use *lpSystemTickCount here, 00790 * the compiler may not generate code to do a DWORD fetch; 00791 */ 00792 iTimeElapsed = (NtGetTickCount() - dwTimeStart); 00793 } 00794 00795 /* 00796 * restore saved rect 00797 */ 00798 if (uSave != 0) { 00799 SaveScreen(pwndOrg, SS_RESTORE, uSave, iLeft, iTop, cx, cy); 00800 } else { 00801 GreBitBlt(hdc, 00802 iLeft, 00803 iTop, 00804 cx, 00805 cy, 00806 hdcMem, 00807 0, 00808 0, 00809 SRCCOPY, 00810 0); 00811 } 00812 00813 Cleanup: 00814 GreSelectBitmap(hdcMem, hbmpOld); 00815 GreDeleteDC(hdcMem); 00816 } 00817 00818 #if 0 // DISABLE OLD ANIMATION FOR M7 00819 /***************************************************************************\ 00820 * DrawWireFrame 00821 * 00822 * Draws wire frame trapezoid 00823 * 00824 * 00825 \***************************************************************************/ 00826 00827 VOID DrawWireFrame( 00828 HDC hdc, 00829 LPRECT prcFront, 00830 LPRECT prcBack) 00831 { 00832 RECT rcFront; 00833 RECT rcBack; 00834 RECT rcT; 00835 HRGN hrgnSave; 00836 BOOL fClip; 00837 00838 /* 00839 * Save these locally 00840 */ 00841 CopyRect(&rcFront, prcFront); 00842 CopyRect(&rcBack, prcBack); 00843 00844 /* 00845 * Front face 00846 */ 00847 GreMoveTo(hdc, rcFront.left, rcFront.top); 00848 GreLineTo(hdc, rcFront.left, rcFront.bottom); 00849 GreLineTo(hdc, rcFront.right, rcFront.bottom); 00850 GreLineTo(hdc, rcFront.right, rcFront.top); 00851 GreLineTo(hdc, rcFront.left, rcFront.top); 00852 00853 /* 00854 * Exclude front face from clipping area, only if back face isn't 00855 * entirely within interior. We need variable because SaveClipRgn() 00856 * can return NULL. 00857 */ 00858 fClip = (EqualRect(&rcFront, &rcBack) || 00859 !IntersectRect(&rcT, &rcFront, &rcBack) || 00860 !EqualRect(&rcT, &rcBack)); 00861 00862 if (fClip) { 00863 00864 hrgnSave = GreSaveClipRgn(hdc); 00865 00866 GreExcludeClipRect(hdc, 00867 rcFront.left, 00868 rcFront.top, 00869 rcFront.right, 00870 rcFront.bottom); 00871 } 00872 00873 /* 00874 * Edges 00875 */ 00876 GreMoveTo(hdc, rcBack.left, rcBack.top); 00877 LineTo(hdc, rcFront.left, rcFront.top); 00878 00879 GreMoveTo(hdc, rcBack.right, rcBack.top); 00880 GreLineTo(hdc, rcFront.right, rcFront.top); 00881 00882 GreMoveTo(hdc, rcBack.right, rcBack.bottom); 00883 GreLineTo(hdc, rcFront.right, rcFront.bottom); 00884 00885 GreMoveTo(hdc, rcBack.left, rcBack.bottom); 00886 GreLineTo(hdc, rcFront.left, rcFront.bottom); 00887 00888 /* 00889 * Back face 00890 */ 00891 MoveTo(hdc, rcBack.left, rcBack.top); 00892 LineTo(hdc, rcBack.left, rcBack.bottom); 00893 LineTo(hdc, rcBack.right, rcBack.bottom); 00894 LineTo(hdc, rcBack.right, rcBack.top); 00895 LineTo(hdc, rcBack.left, rcBack.top); 00896 00897 if (fClip) 00898 GreRestoreClipRgn(hdc, hrgnSave); 00899 } 00900 00901 /***************************************************************************\ 00902 * AnimateFrame 00903 * 00904 * Draws wire frame 3D trapezoid 00905 * 00906 * 00907 \***************************************************************************/ 00908 00909 VOID AnimateFrame( 00910 HDC hdc, 00911 LPRECT prcStart, 00912 LPRECT prcEnd, 00913 BOOL fGrowing) 00914 { 00915 RECT rcBack; 00916 RECT rcFront; 00917 RECT rcT; 00918 HPEN hpen; 00919 int nMode; 00920 int iTrans; 00921 int nTrans; 00922 DWORD dwTimeStart; 00923 DWORD dwTimeCur; 00924 00925 /* 00926 * Get pen for drawing lines 00927 */ 00928 hpen = GreSelectPen(hdc, GetStockObject(WHITE_PEN)); 00929 nMode = GreSetROP2(hdc, R2_XORPEN); 00930 00931 /* 00932 * Save these locally 00933 */ 00934 if (fGrowing) { 00935 00936 CopyRect(&rcBack, prcStart); 00937 CopyRect(&rcFront, prcStart); 00938 00939 } else { 00940 00941 /* 00942 * Initial is trapezoid entire way from small to big. We're going 00943 * to shrink it from the front face. 00944 */ 00945 CopyRect(&rcFront, prcStart); 00946 CopyRect(&rcBack, prcEnd); 00947 } 00948 00949 /* 00950 * Offset left & top edges of rects, due to way that lines work. 00951 */ 00952 rcFront.left -= 1; 00953 rcFront.top -= 1; 00954 rcBack.left -= 1; 00955 rcBack.top -= 1; 00956 00957 /* 00958 * Get tick count. We'll draw then check how much time elapsed. From 00959 * that we can calculate how many more transitions to draw. For the first 00960 * We basically want whole animation to last 3/4 of a second, or 750 00961 * milliseconds. 00962 * 00963 * WARNING: If you use *lpSystemTickCount here, 00964 * the compiler may not generate code to do a DWORD fetch; 00965 */ 00966 dwTimeStart = GetSystemMsecCount(); 00967 00968 DrawWireFrame(hdc, &rcFront, &rcBack); 00969 00970 /* 00971 * WARNING: If you use *lpSystemTickCount here, 00972 * the compiler may not generate code to do a DWORD fetch; 00973 */ 00974 dwTimeCur = GetSystemMsecCount(); 00975 00976 /* 00977 * Get rough estimate for how much time it took. 00978 */ 00979 if (dwTimeCur == dwTimeStart) 00980 nTrans = CMS_ANIMATION / 55; 00981 else 00982 nTrans = CMS_ANIMATION / ((int)(dwTimeCur - dwTimeStart)); 00983 00984 iTrans = 1; 00985 while (iTrans <= nTrans) { 00986 00987 /* 00988 * Grow the trapezoid out or shrink it in. Fortunately, prcStart 00989 * and prcEnd are already set up for us. 00990 */ 00991 rcT.left = prcStart->left + 00992 MultDiv(prcEnd->left - prcStart->left, iTrans, nTrans); 00993 rcT.top = prcStart->top + 00994 MultDiv(prcEnd->top - prcStart->top, iTrans, nTrans); 00995 rcT.right = prcStart->right + 00996 MultDiv(prcEnd->right - prcStart->right, iTrans, nTrans); 00997 rcT.bottom = prcStart->bottom + 00998 MultDiv(prcEnd->bottom - prcStart->bottom, iTrans, nTrans); 00999 01000 /* 01001 * Undraw old and draw new 01002 */ 01003 DrawWireFrame(hdc, &rcFront, &rcBack); 01004 CopyRect(&rcFront, &rcT); 01005 DrawWireFrame(hdc, &rcFront, &rcBack); 01006 01007 /* 01008 * Check the time. How many more transitions left? 01009 * iTrans / nTrans AS (dwTimeCur-dwTimeStart) / 750 01010 * 01011 * WARNING: If you use *lpSystemTickCount here, 01012 * the compiler may not generate code to do a DWORD fetch; 01013 */ 01014 dwTimeCur = GetSystemMsecCount(); 01015 iTrans = MultDiv(nTrans, 01016 (int)(dwTimeCur - dwTimeStart), 01017 CMS_ANIMATION); 01018 } 01019 01020 /* 01021 * Undraw wire frame 01022 */ 01023 DrawWireFrame(hdc, &rcFront, &rcBack); 01024 01025 /* 01026 * Clean up 01027 */ 01028 GreSetROP2(hdc, nMode); 01029 hpen = GreSelectPen(hdc, hpen); 01030 } 01031 #endif // END DISABLE OLD ANIMATION FOR M7 01032 01033 /***************************************************************************\ 01034 * xxxDrawAnimatedRects 01035 * 01036 * General routine, like PlaySoundEvent(), that calls other routines for 01037 * various animation effects. Currently used for changing state from/to 01038 * minimized. 01039 * 01040 \***************************************************************************/ 01041 01042 BOOL xxxDrawAnimatedRects( 01043 PWND pwndClip, 01044 int idAnimation, 01045 LPRECT lprcStart, 01046 LPRECT lprcEnd) 01047 { 01048 HDC hdc; 01049 POINT rgPt[4]; 01050 RECT rcClip; 01051 HRGN hrgn; 01052 PWND pwndAnimate = NULL; 01053 int iPt; 01054 01055 CheckLock(pwndClip); 01056 01057 /* 01058 * Get rects into variables 01059 */ 01060 CopyRect((LPRECT)&rgPt[0], lprcStart); 01061 CopyRect((LPRECT)&rgPt[2], lprcEnd); 01062 01063 /* 01064 * DISABLE OLD ANIMATION FOR M7 01065 */ 01066 if (idAnimation != IDANI_CAPTION) 01067 return TRUE; 01068 01069 pwndAnimate = pwndClip; 01070 if (!pwndAnimate || pwndAnimate == PWNDDESKTOP(pwndAnimate)) 01071 return FALSE; 01072 01073 pwndClip = pwndClip->spwndParent; 01074 if (!pwndClip) { 01075 RIPMSG0(RIP_WARNING, "xxxDrawAnimatedRects: pwndClip->spwndParent is NULL"); 01076 } else if (pwndClip == PWNDDESKTOP(pwndClip)) { 01077 pwndClip = NULL; 01078 } 01079 01080 /* 01081 * NOTE: 01082 * We do NOT need to do LockWindowUpdate(). We never yield within this 01083 * function! Anything that was invalid will stay invalid, etc. So our 01084 * XOR drawing won't leave remnants around. 01085 * 01086 * WIN32NT may need to take display critical section or do LWU(). 01087 * 01088 * Get clipping area 01089 * Neat feature: 01090 * NULL window means whole screen, don't clip out children 01091 * hwndDesktop means working area, don't clip out children 01092 */ 01093 if (pwndClip == NULL) { 01094 pwndClip = _GetDesktopWindow(); 01095 CopyRect(&rcClip, &pwndClip->rcClient); 01096 if ((hrgn = GreCreateRectRgnIndirect(&rcClip)) == NULL) { 01097 hrgn = HRGN_FULL; 01098 } 01099 01100 /* 01101 * Get drawing DC 01102 */ 01103 hdc = _GetDCEx(pwndClip, 01104 hrgn, 01105 DCX_WINDOW | 01106 DCX_CACHE | 01107 DCX_INTERSECTRGN | 01108 DCX_LOCKWINDOWUPDATE); 01109 } else { 01110 01111 hdc = _GetDCEx(pwndClip, 01112 HRGN_FULL, 01113 DCX_WINDOW | DCX_USESTYLE | DCX_INTERSECTRGN); 01114 01115 /* 01116 * We now have a window DC. We need to convert client coords 01117 * to window coords. 01118 */ 01119 for (iPt = 0; iPt < 4; iPt++) { 01120 01121 rgPt[iPt].x += (pwndClip->rcClient.left - pwndClip->rcWindow.left); 01122 rgPt[iPt].y += (pwndClip->rcClient.top - pwndClip->rcWindow.top); 01123 } 01124 } 01125 01126 /* 01127 * Get drawing DC: 01128 * Unclipped if desktop, clipped otherwise. 01129 * Note that ReleaseDC() will free the region if needed. 01130 */ 01131 if (idAnimation == IDANI_CAPTION) { 01132 CheckLock(pwndAnimate); 01133 xxxAnimateCaption(pwndAnimate, hdc, (LPRECT)&rgPt[0], (LPRECT)&rgPt[2]); 01134 } 01135 01136 /* 01137 * DISABLE OLD ANIMATION FOR M7 01138 */ 01139 #if 0 01140 else { 01141 AnimateFrame(hdc, 01142 (LPRECT)&rgPt[0], 01143 (LPRECT)&rgPt[2], 01144 (idAnimation == IDANI_OPEN)); 01145 } 01146 #endif 01147 /* 01148 * END DISABLE OLD ANIMATION FOR M7 01149 */ 01150 01151 /* 01152 * Clean up 01153 */ 01154 _ReleaseDC(hdc); 01155 01156 return TRUE; 01157 } 01158 01159 01160 /***************************************************************************\ 01161 * CalcMinZOrder 01162 * 01163 * 01164 * Compute the Z-order of a window to be minimized. 01165 * 01166 * The strategy is to find the bottom-most sibling of pwndMinimize that 01167 * shares the same owner, and insert ourself behind that. We must also 01168 * take into account that a TOPMOST window should stay among other TOPMOST, 01169 * and vice versa. 01170 * 01171 * We must make sure never to insert after a bottom-most window. 01172 * 01173 * This code works for child windows too, since they don't have owners 01174 * and never have WEFTOPMOST set. 01175 * 01176 * If NULL is returned, the window shouldn't be Z-ordered. 01177 * 01178 \***************************************************************************/ 01179 01180 PWND CalcMinZOrder( 01181 PWND pwndMinimize) 01182 { 01183 BYTE bTopmost; 01184 PWND pwndAfter; 01185 PWND pwnd; 01186 01187 bTopmost = TestWF(pwndMinimize, WEFTOPMOST); 01188 pwndAfter = NULL; 01189 01190 for (pwnd = pwndMinimize->spwndNext; pwnd && !TestWF(pwnd, WFBOTTOMMOST); pwnd = pwnd->spwndNext) { 01191 01192 /* 01193 * If we've enumerated a window that isn't the same topmost-wise 01194 * as pwndMinimize, we've gone as far as we can. 01195 */ 01196 if (TestWF(pwnd, WEFTOPMOST) != bTopmost) 01197 break; 01198 01199 if (pwnd->spwndOwner == pwndMinimize->spwndOwner) 01200 pwndAfter = pwnd; 01201 } 01202 01203 return pwndAfter; 01204 } 01205 01206 /***************************************************************************\ 01207 * xxxActivateOnMinimize 01208 * 01209 * Activate the previously active window, provided that window still exists 01210 * and is a NORMAL window (not bottomost, minimized, disabled, or invisible). 01211 * If it's not NORMAL, then activate the first non WS_EX_TOPMOST window 01212 * that's normal. Return TRUE when no activation is needed or the activation 01213 * has been done in this function. Return FALSE if failed to find a window 01214 * to activate. 01215 * 01216 \***************************************************************************/ 01217 01218 BOOL xxxActivateOnMinimize(PWND pwnd) 01219 { 01220 PTHREADINFO ptiCurrent = PtiCurrent(); 01221 PWND pwndStart, pwndFirstTool, pwndT; 01222 BOOL fTryTopmost = TRUE; 01223 BOOL fPrevCheck = (ptiCurrent->pq->spwndActivePrev != NULL); 01224 TL tlpwndT; 01225 01226 /* 01227 * We should always have a last-topmost window. 01228 */ 01229 pwndStart = GetLastTopMostWindow(); 01230 if (pwndStart) { 01231 pwndStart = pwndStart->spwndNext; 01232 } else { 01233 pwndStart = pwnd->spwndParent->spwndChild; 01234 } 01235 01236 UserAssert(HIBYTE(WFMINIMIZED) == HIBYTE(WFVISIBLE)); 01237 UserAssert(HIBYTE(WFVISIBLE) == HIBYTE(WFDISABLED)); 01238 01239 SearchAgain: 01240 01241 pwndT = (fPrevCheck ? ptiCurrent->pq->spwndActivePrev : pwndStart); 01242 pwndFirstTool = NULL; 01243 01244 for ( ; pwndT ; pwndT = pwndT->spwndNext) { 01245 01246 TryThisWindow: 01247 01248 /* 01249 * Use the first nonminimized, visible, nondisabled, and 01250 * nonbottommost window 01251 */ 01252 if (!HMIsMarkDestroy(pwndT) && 01253 !TestWF(pwndT, WEFNOACTIVATE) && 01254 (TestWF(pwndT, WFVISIBLE | WFDISABLED) == LOBYTE(WFVISIBLE)) && 01255 (!TestWF(pwndT, WFMINIMIZED) || GetFullScreen(pwndT) == FULLSCREEN)) { 01256 01257 if (TestWF(pwndT, WEFTOOLWINDOW)) { 01258 if (!pwndFirstTool) { 01259 pwndFirstTool = pwndT; 01260 } 01261 } else { 01262 break; 01263 } 01264 } 01265 01266 if (fPrevCheck) { 01267 fPrevCheck = FALSE; 01268 pwndT = pwndStart; 01269 goto TryThisWindow; 01270 } 01271 } 01272 01273 if (!pwndT) { 01274 01275 if (fTryTopmost) { 01276 01277 fTryTopmost = FALSE; 01278 if (pwndStart != NULL) { 01279 pwndStart = pwndStart->spwndParent->spwndChild; 01280 } else { 01281 PWND pwndDesktop = _GetDesktopWindow(); 01282 pwndStart = (pwndDesktop != NULL) ? pwndDesktop->spwndChild : NULL; 01283 } 01284 goto SearchAgain; 01285 } 01286 01287 pwndT = pwndFirstTool; 01288 } 01289 01290 if (pwndT) { 01291 ThreadLockAlwaysWithPti(ptiCurrent, pwndT, &tlpwndT); 01292 xxxSetForegroundWindow(pwndT, FALSE); 01293 ThreadUnlock(&tlpwndT); 01294 } else { 01295 return FALSE; 01296 } 01297 01298 return TRUE; 01299 } 01300 01301 01302 01303 /***************************************************************************\ 01304 * xxxMinMaximize 01305 * 01306 * cmd = SW_MINIMIZE, SW_SHOWMINNOACTIVE, SW_SHOWMINIZED, 01307 * SW_SHOWMAXIMIZED, SW_SHOWNOACTIVE, SW_NORMAL 01308 * 01309 * If MINMAX_KEEPHIDDEN is set in dwFlags, keep it hidden, otherwise show it. 01310 * This is always cleared, except in the case we call it from 01311 * createwindow(), where the wnd is iconic, but hidden. we 01312 * need to call this func, to set it up correctly so that when 01313 * the app shows the wnd, it is displayed correctly. 01314 * 01315 * When changing state, we always add on SWP_STATECHANGE. This lets 01316 * SetWindowPos() know to always send WM_WINDOWPOSCHANGING/CHANGED messages 01317 * even if the new size is the same as the old size. This is because 01318 * apps watch the WM_SIZE wParam field to see when they are changing state. 01319 * If SWP doesn't send WM_WINDOWPOSCHANGED, then they won't get a WM_SIZE 01320 * message at all. 01321 * 01322 * Furthermore, when changing state to/from maximized, if we are really 01323 * maximizing and are in multiple monitor mode, we want to set the window's 01324 * region so that it can't draw outside of the monitor. Otherwise, it 01325 * will spill over onto another. The borders are really annoying. 01326 * 01327 \***************************************************************************/ 01328 01329 PWND xxxMinMaximize( 01330 PWND pwnd, 01331 UINT cmd, 01332 DWORD dwFlags) 01333 { 01334 RECT rc; 01335 RECT rcWindow; 01336 RECT rcRestore; 01337 BOOL fShow = FALSE; 01338 BOOL fSetFocus = FALSE; 01339 BOOL fShowOwned = FALSE; 01340 BOOL fSendActivate = FALSE; 01341 BOOL fMaxStateChanging = FALSE; 01342 int idAnimation = 0; 01343 BOOL fFlushPalette = FALSE; 01344 UINT swpFlags = 0; 01345 HWND hwndAfter = NULL; 01346 PWND pwndT; 01347 PCHECKPOINT pcp; 01348 PTHREADINFO ptiCurrent; 01349 TL tlpwndParent; 01350 TL tlpwndT; 01351 PSMWP psmwp; 01352 BOOL fIsTrayWindowNow = FALSE; 01353 NTSTATUS Status; 01354 MINMAXINFO mmi; 01355 UINT uEvent = 0; 01356 #if defined(USE_MIRRORING) 01357 PWND pwndParent = pwnd->spwndParent; 01358 BOOL bMirroredParent=FALSE; 01359 #endif 01360 01361 CheckLock(pwnd); 01362 01363 /* 01364 * Get window rect, in parent client coordinates. 01365 */ 01366 GetRect(pwnd, &rcWindow, GRECT_WINDOW | GRECT_PARENTCOORDS); 01367 01368 /* 01369 * If this is NULL, we're out of memory, so punt now. 01370 */ 01371 pcp = CkptRestore(pwnd, &rcWindow); 01372 if (!pcp) 01373 goto Exit; 01374 01375 #if defined(USE_MIRRORING) 01376 /* 01377 * If this top-level window is placed in a mirrored desktop, 01378 * its coordinates should be mirrored here so that xxxAnimateCaptions 01379 * works properly, however we shouldn't change the actual screen coordinates 01380 * of the window. This is why I do it after CkptRestore(...). [samera] 01381 */ 01382 if (TestWF(pwndParent,WEFLAYOUTRTL) && 01383 (!TestWF(pwnd,WFCHILD))) { 01384 int iLeft = rcWindow.left; 01385 rcWindow.left = pwndParent->rcWindow.right - rcWindow.right; 01386 rcWindow.right = pwndParent->rcWindow.right - iLeft; 01387 bMirroredParent = TRUE; 01388 } 01389 #endif 01390 01391 01392 /* 01393 * Save the previous restore size. 01394 */ 01395 CopyRect(&rcRestore, &pcp->rcNormal); 01396 01397 /* 01398 * First ask the CBT hook if we can do this operation. 01399 */ 01400 if ( IsHooked(PtiCurrent(), WHF_CBT) && 01401 xxxCallHook(HCBT_MINMAX, (WPARAM)HWq(pwnd), (DWORD)cmd, WH_CBT)) { 01402 01403 goto Exit; 01404 } 01405 01406 /* 01407 * If another MDI window is being maximized, and we want to restore this 01408 * one to its previous state, we can't change the zorder or the 01409 * activation. We'd screw things up that way. BTW, this SW_ value is 01410 * internal. 01411 */ 01412 if (cmd == SW_MDIRESTORE) { 01413 01414 swpFlags |= SWP_NOZORDER | SWP_NOACTIVATE; 01415 01416 cmd = (pcp->fWasMinimizedBeforeMaximized ? 01417 SW_SHOWMINIMIZED : SW_SHOWNORMAL); 01418 } 01419 01420 ptiCurrent = PtiCurrent(); 01421 01422 switch (cmd) { 01423 case SW_MINIMIZE: // Bottom of zorder, make top-level active 01424 case SW_SHOWMINNOACTIVE: // Bottom of zorder, don't change activation 01425 01426 if (gpqForeground && gpqForeground->spwndActive) 01427 swpFlags |= SWP_NOACTIVATE; 01428 01429 if ((pwndT = CalcMinZOrder(pwnd)) == NULL) { 01430 swpFlags |= SWP_NOZORDER; 01431 } else { 01432 hwndAfter = PtoHq(pwndT); 01433 } 01434 01435 01436 /* 01437 * FALL THRU 01438 */ 01439 01440 case SW_SHOWMINIMIZED: // Top of zorder, make active 01441 01442 /* 01443 * Force a show. 01444 */ 01445 fShow = TRUE; 01446 01447 /* 01448 * If already minimized, then don't change the existing 01449 * parking spot. 01450 */ 01451 if (TestWF(pwnd, WFMINIMIZED)) { 01452 01453 /* 01454 * If we're already minimized and we're properly visible 01455 * or not visible, don't do anything 01456 */ 01457 if (TestWF(pwnd, WFVISIBLE)) 01458 return NULL; 01459 01460 swpFlags |= SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE; 01461 01462 goto Showit; 01463 } 01464 01465 /* 01466 * We're becoming minimized although we currently are not. So 01467 * we want to draw the transition animation, and ALWAYS send 01468 * sizing messages. 01469 */ 01470 idAnimation = IDANI_CLOSE; 01471 01472 if (!pcp->fDragged) 01473 pcp->fMinInitialized = FALSE; 01474 01475 if (!pcp->fMinInitialized) 01476 ParkIcon(pwnd, pcp); 01477 01478 rc.left = pcp->ptMin.x; 01479 rc.top = pcp->ptMin.y; 01480 rc.right = pcp->ptMin.x + SYSMET(CXMINIMIZED); 01481 rc.bottom = pcp->ptMin.y + SYSMET(CYMINIMIZED); 01482 01483 xxxShowOwnedWindows(pwnd, SW_PARENTCLOSING, NULL); 01484 01485 pwndT = ptiCurrent->pq->spwndFocus; 01486 01487 while (pwndT) { 01488 01489 /* 01490 * if we or any child has the focus, punt it away 01491 */ 01492 if (pwndT != pwnd) { 01493 pwndT = pwndT->spwndParent; 01494 continue; 01495 } 01496 01497 ThreadLockAlwaysWithPti(ptiCurrent, pwndT, &tlpwndT); 01498 01499 if (TestwndChild(pwnd)) { 01500 01501 ThreadLockWithPti(ptiCurrent, pwnd->spwndParent, &tlpwndParent); 01502 xxxSetFocus(pwnd->spwndParent); 01503 ThreadUnlock(&tlpwndParent); 01504 01505 } else { 01506 xxxSetFocus(NULL); 01507 } 01508 01509 ThreadUnlock(&tlpwndT); 01510 break; 01511 } 01512 01513 /* 01514 * Save the maximized state so that we can restore the window maxed 01515 */ 01516 if (TestWF(pwnd, WFMAXIMIZED)) { 01517 pcp->fWasMaximizedBeforeMinimized = TRUE; 01518 fMaxStateChanging = TRUE; 01519 } else{ 01520 pcp->fWasMaximizedBeforeMinimized = FALSE; 01521 } 01522 01523 if (!TestWF(pwnd, WFWIN40COMPAT)) 01524 fIsTrayWindowNow = IsTrayWindow(pwnd); 01525 01526 /* 01527 * Decrement the visible-windows count only if the 01528 * window is visible. If the window is marked for 01529 * destruction, we will not decrement for that as 01530 * well. Let SetMinimize take care of this. 01531 */ 01532 SetMinimize(pwnd, SMIN_SET); 01533 ClrWF(pwnd, WFMAXIMIZED); 01534 01535 uEvent = EVENT_SYSTEM_MINIMIZESTART; 01536 01537 if (!TestWF(pwnd, WFWIN40COMPAT)) 01538 fIsTrayWindowNow = (fIsTrayWindowNow != IsTrayWindow(pwnd)); 01539 01540 /* 01541 * The children of this window are now no longer visible. 01542 * Ensure that they no longer have any update regions... 01543 */ 01544 for (pwndT = pwnd->spwndChild; pwndT; pwndT = pwndT->spwndNext) 01545 ClrFTrueVis(pwndT); 01546 01547 /* 01548 * B#2919 01549 * Ensure that the client area gets recomputed, and make 01550 * sure that no bits are copied when the size is changed. And 01551 * make sure that WM_SIZE messages get sent, even if our client 01552 * size is staying the same. 01553 */ 01554 swpFlags |= (SWP_DRAWFRAME | SWP_NOCOPYBITS | SWP_STATECHANGE); 01555 01556 /* 01557 * We are going minimized, so we want to give palette focus to 01558 * another app. 01559 */ 01560 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01561 fFlushPalette = (BOOL)TestWF(pwnd, WFHASPALETTE); 01562 } 01563 01564 break; 01565 01566 case SW_SHOWNOACTIVATE: 01567 if (gpqForeground && gpqForeground->spwndActive) 01568 swpFlags |= SWP_NOACTIVATE; 01569 01570 /* 01571 * FALL THRU 01572 */ 01573 01574 case SW_RESTORE: 01575 01576 /* 01577 * If restoring a minimized window that was maximized before 01578 * being minimized, go back to being maximized. 01579 */ 01580 if (TestWF(pwnd, WFMINIMIZED) && pcp->fWasMaximizedBeforeMinimized) 01581 cmd = SW_SHOWMAXIMIZED; 01582 else 01583 cmd = SW_NORMAL; 01584 01585 /* 01586 * FALL THRU 01587 */ 01588 01589 case SW_NORMAL: 01590 case SW_SHOWMAXIMIZED: 01591 01592 if (cmd == SW_SHOWMAXIMIZED) { 01593 01594 /* 01595 * If already maximized and visible, we have nothing to do 01596 * Otherwise, for the DOSbox, still set fMaxStateChanging 01597 * to TRUE so we recalc the monitor region if need be. 01598 * That way WinOldAp can change its "changing from maxed to 01599 * maxed with new bigger font" code to work right. 01600 */ 01601 if (TestWF(pwnd, WFMAXIMIZED)) { 01602 if (TestWF(pwnd, WFVISIBLE)) { 01603 return NULL; 01604 } 01605 } else { 01606 /* 01607 * We're changing from normal to maximized, so always 01608 * send WM_SIZE. 01609 */ 01610 swpFlags |= SWP_STATECHANGE; 01611 } 01612 fMaxStateChanging = TRUE; 01613 01614 /* 01615 * If calling from CreateWindow, don't let the thing become 01616 * activated by the SWP call below. Acitvation will happen 01617 * on the ShowWindow done by CreateWindow or the app. 01618 */ 01619 if (dwFlags & MINMAX_KEEPHIDDEN) 01620 swpFlags |= SWP_NOACTIVATE; 01621 01622 /* 01623 * This is for MDI's auto-restore behaviour (craigc) 01624 */ 01625 if (TestWF(pwnd, WFMINIMIZED)) 01626 pcp->fWasMinimizedBeforeMaximized = TRUE; 01627 01628 xxxInitSendValidateMinMaxInfo(pwnd, &mmi); 01629 01630 } else { 01631 01632 /* 01633 * We're changing state from non-normal to normal. Make 01634 * sure WM_SIZE gets sents. 01635 */ 01636 UserAssert(HIBYTE(WFMINIMIZED) == HIBYTE(WFMAXIMIZED)); 01637 if (TestWF(pwnd, WFMINIMIZED | WFMAXIMIZED)) { 01638 swpFlags |= SWP_STATECHANGE; 01639 } 01640 if (TestWF(pwnd, WFMAXIMIZED)) { 01641 fMaxStateChanging = TRUE; 01642 } 01643 } 01644 01645 /* 01646 * If currently minimized, show windows' popups 01647 */ 01648 if (TestWF(pwnd, WFMINIMIZED)) { 01649 01650 /* 01651 * Send WM_QUERYOPEN to make sure this guy should unminimize 01652 */ 01653 if (!xxxSendMessage(pwnd, WM_QUERYOPEN, 0, 0L)) 01654 return NULL; 01655 01656 idAnimation = IDANI_OPEN; 01657 fShowOwned = TRUE; 01658 fSetFocus = TRUE; 01659 01660 /* 01661 * JEFFBOG B#2868 01662 * Condition added before setting fSendActivate prevents 01663 * WM_ACTIVATE message from reaching a child window. Might 01664 * be backwards compatibility problems if a pre 3.1 app 01665 * relies on WM_ACTIVATE reaching a child. 01666 */ 01667 if (!TestWF(pwnd, WFCHILD)) 01668 fSendActivate = TRUE; 01669 01670 swpFlags |= SWP_NOCOPYBITS; 01671 } else { 01672 idAnimation = IDANI_CAPTION; 01673 } 01674 01675 if (cmd == SW_SHOWMAXIMIZED) { 01676 rc.left = mmi.ptMaxPosition.x; 01677 rc.top = mmi.ptMaxPosition.y; 01678 rc.right = rc.left + mmi.ptMaxSize.x; 01679 rc.bottom = rc.top + mmi.ptMaxSize.y; 01680 01681 SetWF(pwnd, WFMAXIMIZED); 01682 01683 } else { 01684 CopyRect(&rc, &rcRestore); 01685 ClrWF(pwnd, WFMAXIMIZED); 01686 } 01687 01688 /* 01689 * We do this TestWF again since we left the critical section 01690 * above and someone might have already 'un-minimized us'. 01691 */ 01692 if (TestWF(pwnd, WFMINIMIZED)) { 01693 01694 if (!TestWF(pwnd, WFWIN40COMPAT)) 01695 fIsTrayWindowNow = IsTrayWindow(pwnd); 01696 01697 /* 01698 * Mark it as minimized and adjust cVisWindows. 01699 */ 01700 SetMinimize(pwnd, SMIN_CLEAR); 01701 01702 uEvent = EVENT_SYSTEM_MINIMIZEEND; 01703 01704 /* 01705 * if we're unminimizing a window that is now 01706 * not seen in maximized/restore mode then remove him 01707 * from the tray 01708 */ 01709 if (!TestWF(pwnd, WFWIN40COMPAT) && 01710 (fIsTrayWindowNow != IsTrayWindow(pwnd)) && 01711 FDoTray()) { 01712 01713 HWND hw = HWq(pwnd); 01714 01715 if (FCallHookTray()) { 01716 xxxCallHook(HSHELL_WINDOWDESTROYED, 01717 (WPARAM)hw, 01718 (LPARAM)0, 01719 WH_SHELL); 01720 } 01721 01722 /* 01723 * NT specific code. Post the window-destroyed message 01724 * to the shell. 01725 */ 01726 if (FPostTray(pwnd->head.rpdesk)) 01727 PostShellHookMessages(HSHELL_WINDOWDESTROYED, (LPARAM)hw); 01728 } 01729 01730 fIsTrayWindowNow = FALSE; 01731 01732 /* 01733 * If we're un-minimizing a visible top-level window, cVisWindows 01734 * was zero, and we're either activating a window or showing 01735 * the currently active window, set ourselves into the 01736 * foreground. If the window isn't currently visible 01737 * then we can rely on SetWindowPos() to do the right 01738 * thing for us. 01739 */ 01740 if (!TestwndChild(pwnd) && 01741 TestWF(pwnd, WFVISIBLE) && 01742 (GETPTI(pwnd)->cVisWindows == 1) && 01743 (GETPTI(pwnd)->pq != gpqForeground) && 01744 (!(swpFlags & SWP_NOACTIVATE) 01745 || (GETPTI(pwnd)->pq->spwndActive == pwnd))) { 01746 01747 xxxSetForegroundWindow2(pwnd, GETPTI(pwnd), SFW_STARTUP); 01748 } 01749 } 01750 01751 /* 01752 * Ensure that client area gets recomputed, and that 01753 * the frame gets redrawn to reflect the new state. 01754 */ 01755 swpFlags |= SWP_DRAWFRAME; 01756 break; 01757 } 01758 01759 /* 01760 * For the iconic case, we need to also show the window because it 01761 * might not be visible yet. 01762 */ 01763 01764 Showit: 01765 01766 if (!(dwFlags & MINMAX_KEEPHIDDEN)) { 01767 01768 if (TestWF(pwnd, WFVISIBLE)) { 01769 01770 if (fShow) 01771 swpFlags |= SWP_SHOWWINDOW; 01772 01773 /* if we're full screening a DOS BOX then don't draw 01774 * the animation 'cause it looks bad. 01775 * overloaded WFFULLSCREEN bit for MDI child windows -- 01776 * use it to indicate to not animate size change. 01777 */ 01778 if (IsVisible(pwnd) && 01779 (dwFlags & MINMAX_ANIMATE) && 01780 idAnimation && 01781 (!TestWF(pwnd, WFCHILD) || !TestWF(pwnd, WFNOANIMATE))) { 01782 01783 #if defined(USE_MIRRORING) 01784 /* 01785 * If this top-level window is placed in a mirrored desktop, 01786 * its coordinates should be mirrored here so that xxxAnimateCaptions 01787 * works properly, however we shouldn't change the actual screen coordinates 01788 * of the window. This is why I do it here and restore it afterwards before 01789 * doing the _DeferWindowPos(...). [samera] 01790 */ 01791 RECT rcT; 01792 if (bMirroredParent) { 01793 int iLeft = rc.left; 01794 rcT = rc; 01795 rc.left = pwndParent->rcWindow.right - rc.right; 01796 rc.right = pwndParent->rcWindow.right - iLeft; 01797 } 01798 #endif 01799 01800 if ((idAnimation != IDANI_CAPTION) && IsTrayWindow(pwnd)) { 01801 01802 RECT rcMin; 01803 01804 SetRectEmpty(&rcMin); 01805 #if 0 // Win95 call. 01806 CallHook(HSHELL_GETMINRECT, (WPARAM)HW16(hwnd), (LPARAM)(LPRECT)&rcMin, WH_SHELL); 01807 #else 01808 xxxSendMinRectMessages(pwnd, &rcMin); 01809 #endif 01810 01811 if (!IsRectEmpty(&rcMin)) { 01812 01813 if (idAnimation == IDANI_CLOSE) { 01814 01815 xxxDrawAnimatedRects(pwnd, 01816 IDANI_CAPTION, 01817 &rcWindow, 01818 &rcMin); 01819 01820 } else { 01821 01822 xxxDrawAnimatedRects(pwnd, 01823 IDANI_CAPTION, 01824 &rcMin, 01825 &rc); 01826 } 01827 } 01828 01829 } else { 01830 xxxDrawAnimatedRects(pwnd, IDANI_CAPTION, &rcWindow, &rc); 01831 } 01832 01833 #if defined(USE_MIRRORING) 01834 /* 01835 * Restore the original rect, after doing the animation 01836 */ 01837 if (bMirroredParent) { 01838 rc = rcT; 01839 } 01840 #endif 01841 } 01842 01843 } else { 01844 swpFlags |= SWP_SHOWWINDOW; 01845 } 01846 } 01847 01848 /* 01849 * hack for VB - we add their window in when their minimizing. 01850 */ 01851 if (!TestWF(pwnd, WFWIN40COMPAT) && fIsTrayWindowNow && FDoTray()) { 01852 01853 HWND hw = HWq(pwnd); 01854 01855 if (FCallHookTray()) { 01856 xxxCallHook(HSHELL_WINDOWCREATED, 01857 (WPARAM)hw, 01858 (LPARAM)0, 01859 WH_SHELL); 01860 } 01861 01862 /* 01863 * NT specific code. Post the window-created message 01864 * to the shell. 01865 */ 01866 if (FPostTray(pwnd->head.rpdesk)) 01867 PostShellHookMessages(HSHELL_WINDOWCREATED, (LPARAM)hw); 01868 } 01869 01870 /* 01871 * BACKWARD COMPATIBILITY HACK: 01872 * 01873 * Because SetWindowPos() won't honor sizing, moving and SWP_SHOWWINDOW 01874 * at the same time in version 3.0 or below, we call DeferWindowPos() 01875 * directly here. 01876 */ 01877 if (psmwp = InternalBeginDeferWindowPos(1)) { 01878 01879 psmwp = _DeferWindowPos(psmwp, 01880 pwnd, 01881 ((hwndAfter != NULL) ? RevalidateHwnd(hwndAfter) : NULL), 01882 rc.left, rc.top, 01883 rc.right - rc.left, 01884 rc.bottom - rc.top, 01885 swpFlags); 01886 01887 if (psmwp) { 01888 01889 /* 01890 * HACK FOR MULTIPLE MONITOR TRUE MAXIMIZATION CLIPPING 01891 * On a multiple monitor system, we would like the 01892 * borders not to spill over onto another monitor when a 01893 * window 'really' maximizes. The only way to get this 01894 * to work right is to set a rectangular region, namely 01895 * a copy of the monitor region, on the window. We can 01896 * only do this if the window isn't currently regional. 01897 * 01898 * Going to maximized: Add the monitor region 01899 * Coming from maximized: Remove the monitor region 01900 */ 01901 if (fMaxStateChanging && gpDispInfo->cMonitors > 1) { 01902 if ( TestWF(pwnd, WFMAXIMIZED) && 01903 pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 01904 01905 psmwp->acvr[0].hrgnClip = HRGN_MONITOR; 01906 01907 } else if (TestWF(pwnd, WFMAXFAKEREGIONAL)) { 01908 UserAssert(pwnd->hrgnClip); 01909 psmwp->acvr[0].hrgnClip = HRGN_FULL; 01910 } 01911 } 01912 01913 xxxEndDeferWindowPosEx(psmwp, FALSE); 01914 } 01915 } 01916 01917 if (FWINABLE() && uEvent) { 01918 xxxWindowEvent(uEvent, pwnd, OBJID_WINDOW, 0, WEF_USEPWNDTHREAD); 01919 } 01920 01921 /* 01922 * COMPATIBILITY HACK: 01923 * Borland's OBEX expects a WM_PAINT message when it starts running 01924 * minimized and initializes all it's data during that message. 01925 * So, we generate a bogus WM_PAINT message here. 01926 * Also, Visionware's XServer can not handle getting a WM_PAINT msg, as it 01927 * would always get a WM_PAINTICON msg in 3.1, so make sure the logic is here 01928 * to generate the correct message. 01929 */ 01930 if((cmd == SW_SHOWMINIMIZED) && 01931 (!TestWF(pwnd, WFWIN40COMPAT)) && 01932 TestWF(pwnd, WFVISIBLE) && 01933 TestWF(pwnd, WFTOPLEVEL)) { 01934 01935 if (pwnd->pcls->spicn) 01936 _PostMessage(pwnd, WM_PAINTICON, (WPARAM)TRUE, 0L); 01937 else 01938 _PostMessage(pwnd, WM_PAINT, 0, 0L); 01939 } 01940 01941 if (fShowOwned) 01942 xxxShowOwnedWindows(pwnd, SW_PARENTOPENING, NULL); 01943 01944 if ((cmd == SW_MINIMIZE) && (pwnd->spwndParent == PWNDDESKTOP(pwnd))) { 01945 if (!xxxActivateOnMinimize(pwnd)) { 01946 xxxActivateWindow(pwnd, AW_SKIP); 01947 } 01948 01949 { 01950 PEPROCESS p; 01951 01952 if (gptiForeground && ptiCurrent->ppi != gptiForeground->ppi && !(ptiCurrent->TIF_flags & TIF_SYSTEMTHREAD)) { 01953 01954 p = THREAD_TO_PROCESS(ptiCurrent->pEThread); 01955 KeAttachProcess(&p->Pcb); 01956 Status = MmAdjustWorkingSetSize((SIZE_T)-1, (SIZE_T)-1, FALSE); 01957 KeDetachProcess(); 01958 01959 if (!NT_SUCCESS(Status)) { 01960 RIPMSG1(RIP_ERROR, "Error adjusting working set, status = %x\n", Status); 01961 } 01962 } 01963 } 01964 01965 /* 01966 * If any app is starting, restore its right to foreground activate 01967 * (activate and come on top of everything else) because we just 01968 * minimized what we were working on. 01969 */ 01970 RestoreForegroundActivate(); 01971 } 01972 01973 /* 01974 * If going from iconic, insure the focus is in the window. 01975 */ 01976 if (fSetFocus) 01977 xxxSetFocus(pwnd); 01978 01979 /* 01980 * This was added for 1.03 compatibility reasons. If apps watch 01981 * WM_ACTIVATE to set their focus, sending this message will appear 01982 * as if the window just got activated (like in 1.03). Before this 01983 * was added, opening an iconic window never sent this message since 01984 * it was already active (but HIWORD(lParam) != 0). 01985 */ 01986 if (fSendActivate) 01987 xxxSendMessage(pwnd, WM_ACTIVATE, WA_ACTIVE, 0); 01988 01989 /* 01990 * Flush the palette. We do this on a minimize of a palette app. 01991 */ 01992 if (fFlushPalette) 01993 xxxFlushPalette(pwnd); 01994 01995 Exit: 01996 return NULL; 01997 } 01998 01999 /***************************************************************************\ 02000 * xxxMinimizeHungWindow 02001 * 02002 * 10/31/96 vadimg created 02003 \***************************************************************************/ 02004 02005 void xxxMinimizeHungWindow(PWND pwnd) 02006 { 02007 RECT rcMin; 02008 HRGN hrgnHung; 02009 02010 02011 CheckLock(pwnd); 02012 02013 /* 02014 * If the window is already minimized or not visible don't do anything. 02015 */ 02016 if (TestWF(pwnd, WFMINIMIZED) || !TestWF(pwnd, WFVISIBLE)) 02017 return; 02018 02019 /* 02020 * Animate the caption to the minimized state. 02021 */ 02022 if (TEST_PUDF(PUDF_ANIMATE)) { 02023 SetRectEmpty(&rcMin); 02024 xxxSendMinRectMessages(pwnd, &rcMin); 02025 if (!IsRectEmpty(&rcMin)) { 02026 xxxDrawAnimatedRects(pwnd, IDANI_CAPTION, &pwnd->rcWindow, &rcMin); 02027 } 02028 } 02029 02030 /* 02031 * Reset the visible bit on the window itself and ownees. At the same 02032 * time calculate how much needs to be repainted. We must invalidate 02033 * the DC cache to make sure that the visible regions get recalculated. 02034 */ 02035 SetVisible(pwnd, SV_UNSET); 02036 hrgnHung = GreCreateRectRgnIndirect(&pwnd->rcWindow); 02037 xxxShowOwnedWindows(pwnd, SW_PARENTCLOSING, hrgnHung); 02038 zzzInvalidateDCCache(pwnd, IDC_DEFAULT); 02039 xxxRedrawWindow(NULL, NULL, hrgnHung, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); 02040 GreDeleteObject(hrgnHung); 02041 02042 /* 02043 * Deal with activating some other window for top-level windows. 02044 */ 02045 if (pwnd->spwndParent == PWNDDESKTOP(pwnd)) { 02046 xxxActivateOnMinimize(pwnd); 02047 } 02048 PostEventMessage(GETPTI(pwnd), GETPTI(pwnd)->pq, QEVENT_HUNGTHREAD, pwnd, 0, 0, 0); 02049 }

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