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

sprite.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: sprite.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Windows Layering (Sprite) support. 00007 * 00008 * History: 00009 * 12/05/97 vadimg created 00010 \***************************************************************************/ 00011 00012 #include "precomp.h" 00013 #pragma hdrstop 00014 00015 /***************************************************************************\ 00016 * IncrementRedirectedCount 00017 * 00018 \***************************************************************************/ 00019 00020 VOID IncrementRedirectedCount(VOID) 00021 { 00022 gnRedirectedCount++; 00023 00024 if (gnRedirectedCount == 1) { 00025 InternalSetTimer(gTermIO.spwndDesktopOwner, IDSYS_LAYER, 100, 00026 xxxSystemTimerProc, TMRF_SYSTEM | TMRF_PTIWINDOW); 00027 } 00028 00029 UserAssert(gnRedirectedCount >= 0); 00030 } 00031 00032 /***************************************************************************\ 00033 * DecrementRedirectedCount 00034 * 00035 \***************************************************************************/ 00036 00037 VOID DecrementRedirectedCount(VOID) 00038 { 00039 gnRedirectedCount--; 00040 00041 if (gnRedirectedCount == 0) { 00042 _KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_LAYER); 00043 } 00044 00045 UserAssert(gnRedirectedCount >= 0); 00046 } 00047 00048 /***************************************************************************\ 00049 * CreateRedirectionBitmap 00050 * 00051 * 10/1/1998 vadimg created 00052 \***************************************************************************/ 00053 00054 HBITMAP CreateRedirectionBitmap(PWND pwnd) 00055 { 00056 HBITMAP hbm; 00057 00058 UserAssert(pwnd->rcWindow.right >= pwnd->rcWindow.left); 00059 UserAssert(pwnd->rcWindow.bottom >= pwnd->rcWindow.top); 00060 00061 /* 00062 * Make sure the (0,0) case doesn't fail, since the window really 00063 * can be sized this way. 00064 */ 00065 if ((hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, 00066 max(pwnd->rcWindow.right - pwnd->rcWindow.left, 1), 00067 max(pwnd->rcWindow.bottom - pwnd->rcWindow.top, 1) | 00068 CCB_NOVIDEOMEMORY)) == NULL) { 00069 RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap create failed"); 00070 return NULL; 00071 } 00072 00073 if (!GreSetBitmapOwner(hbm, OBJECT_OWNER_PUBLIC) || 00074 !GreMarkUndeletableBitmap(hbm) || 00075 !InternalSetProp(pwnd, PROP_LAYER, hbm, PROPF_INTERNAL | 00076 PROPF_NOPOOL)) { 00077 RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap set failed"); 00078 GreMarkDeletableBitmap(hbm); 00079 GreDeleteObject(hbm); 00080 return NULL; 00081 } 00082 00083 /* 00084 * Force the window to redraw if we could recreate the bitmap since 00085 * the redirection bitmap we just allocated doesn't contain anything 00086 * yet. 00087 */ 00088 BEGINATOMICCHECK(); 00089 xxxInternalInvalidate(pwnd, HRGN_FULL, RDW_INVALIDATE | RDW_ERASE | 00090 RDW_FRAME | RDW_ALLCHILDREN); 00091 ENDATOMICCHECK(); 00092 00093 IncrementRedirectedCount(); 00094 00095 return hbm; 00096 } 00097 00098 /***************************************************************************\ 00099 * ConvertRedirectionDCs 00100 * 00101 * 11/19/1998 vadimg created 00102 \***************************************************************************/ 00103 00104 VOID ConvertRedirectionDCs(PWND pwnd, HBITMAP hbm) 00105 { 00106 PDCE pdce; 00107 00108 GreLockDisplay(gpDispInfo->hDev); 00109 00110 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 00111 00112 if (!(pdce->DCX_flags & DCX_INUSE)) 00113 continue; 00114 00115 if (GetTopLevelWindow(pdce->pwndOrg) != pwnd) 00116 continue; 00117 00118 /* 00119 * Only normal DCs can be redirected. Redirection on monitor 00120 * specific DCs is not supported. 00121 */ 00122 if (pdce->pMonitor != NULL) 00123 continue; 00124 00125 SET_OR_CLEAR_FLAG(pdce->DCX_flags, DCX_LAYERED, (hbm != NULL)); 00126 00127 UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbm)); 00128 00129 InvalidateDce(pdce); 00130 } 00131 00132 GreUnlockDisplay(gpDispInfo->hDev); 00133 } 00134 00135 /***************************************************************************\ 00136 * UpdateLayeredSprite 00137 * 00138 * 11/19/1998 vadimg created 00139 \***************************************************************************/ 00140 00141 VOID UpdateLayeredSprite(PDCE pdce) 00142 { 00143 RECT rcBounds; 00144 PWND pwnd; 00145 SIZE size; 00146 POINT pt; 00147 HBITMAP hbm, hbmOld; 00148 00149 /* 00150 * Check to see if any drawing has been done into this DC 00151 * that should be transferred to the sprite. 00152 */ 00153 if (!GreGetBounds(pdce->hdc, &rcBounds, 0)) 00154 return; 00155 00156 pwnd = GetLayeredWindow(pdce->pwndOrg); 00157 00158 UserAssert(FLayeredOrRedirected(pwnd)); 00159 00160 if (TestWF(pwnd, WEFLAYERED)) { 00161 hbm = (HBITMAP)_GetProp(pwnd, PROP_LAYER, TRUE); 00162 00163 UserAssert(hbm != NULL); 00164 00165 hbmOld = GreSelectBitmap(ghdcMem, hbm); 00166 00167 size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 00168 size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 00169 00170 pt.x = pt.y = 0; 00171 GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, NULL, 00172 &size, ghdcMem, &pt, 0, NULL, ULW_DEFAULT_ATTRIBUTES, &rcBounds); 00173 00174 GreSelectBitmap(ghdcMem, hbmOld); 00175 } 00176 00177 #ifdef REDIRECTION 00178 if (FWINABLE()) { 00179 BEGINATOMICCHECK(); 00180 xxxWindowEvent(EVENT_SYSTEM_REDIRECTEDPAINT, pwnd, 00181 MAKELONG(rcBounds.left, rcBounds.top), 00182 MAKELONG(rcBounds.right, rcBounds.bottom), 00183 WEF_ASYNC); 00184 ENDATOMICCHECK(); 00185 } 00186 #endif // REDIRECTION 00187 } 00188 00189 /***************************************************************************\ 00190 * DeleteRedirectionBitmap 00191 * 00192 \***************************************************************************/ 00193 00194 VOID DeleteRedirectionBitmap(HBITMAP hbm) 00195 { 00196 GreMarkDeletableBitmap(hbm); 00197 GreDeleteObject(hbm); 00198 DecrementRedirectedCount(); 00199 } 00200 00201 /***************************************************************************\ 00202 * RemoveRedirectionBitmap 00203 * 00204 * 9/23/1998 vadimg created 00205 \***************************************************************************/ 00206 00207 VOID RemoveRedirectionBitmap(PWND pwnd) 00208 { 00209 HBITMAP hbm; 00210 00211 UserAssert(FLayeredOrRedirected(pwnd)); 00212 00213 /* 00214 * Delete the backing bitmap for this layered window. 00215 */ 00216 if ((hbm = (HBITMAP)_GetProp(pwnd, PROP_LAYER, TRUE)) == NULL) 00217 return; 00218 00219 ConvertRedirectionDCs(pwnd, NULL); 00220 UserVerify(InternalRemoveProp(pwnd, PROP_LAYER, TRUE)); 00221 DeleteRedirectionBitmap(hbm); 00222 } 00223 00224 /***************************************************************************\ 00225 * _SetLayeredWindowAttributes 00226 * 00227 * 9/24/1998 vadimg created 00228 \***************************************************************************/ 00229 00230 BOOL _SetLayeredWindowAttributes(PWND pwnd, COLORREF crKey, BYTE bAlpha, 00231 DWORD dwFlags) 00232 { 00233 BOOL bRet; 00234 BLENDFUNCTION blend; 00235 HBITMAP hbm; 00236 00237 if (!TestWF(pwnd, WEFLAYERED)) { 00238 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, 00239 "SetLayeredWindowAttributes: not a sprite %X", pwnd); 00240 return FALSE; 00241 } 00242 00243 if ((hbm = _GetProp(pwnd, PROP_LAYER, TRUE)) == NULL) { 00244 HBITMAP hbmNew; 00245 00246 if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) { 00247 return FALSE; 00248 } 00249 00250 ConvertRedirectionDCs(pwnd, hbmNew); 00251 } 00252 00253 blend.BlendOp = AC_SRC_OVER; 00254 blend.BlendFlags = 0; 00255 blend.AlphaFormat = 0; 00256 blend.SourceConstantAlpha = bAlpha; 00257 00258 dwFlags |= ULW_NEW_ATTRIBUTES; // Notify gdi that these are new attributes 00259 00260 if (hbm != NULL) { 00261 HBITMAP hbmOld; 00262 SIZE size; 00263 POINT ptSrc = {0,0}; 00264 00265 hbmOld = GreSelectBitmap(ghdcMem, hbm); 00266 00267 size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 00268 size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 00269 00270 bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, 00271 NULL, &size, ghdcMem, &ptSrc, crKey, &blend, dwFlags, NULL); 00272 00273 GreSelectBitmap(ghdcMem, hbmOld); 00274 } else { 00275 bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, 00276 NULL, NULL, NULL, NULL, crKey, &blend, dwFlags, NULL); 00277 } 00278 00279 return bRet; 00280 } 00281 00282 /***************************************************************************\ 00283 * UserRecreateRedirectionBitmap 00284 * 00285 * Called by GDI during mode changes. 00286 * 00287 * 10/6/1998 vadimg created 00288 \***************************************************************************/ 00289 00290 BOOL UserRecreateRedirectionBitmap(HWND hwnd) 00291 { 00292 PWND pwnd; 00293 00294 if ((pwnd = RevalidateHwnd(hwnd)) == NULL) { 00295 RIPMSG0(RIP_WARNING, "UserRecreateRedirectionBitmap: invalid hwnd"); 00296 return FALSE; 00297 } 00298 00299 return RecreateRedirectionBitmap(pwnd); 00300 } 00301 00302 /***************************************************************************\ 00303 * UserRemoveRedirectionBitmap 00304 * 00305 * Called by GDI during mode changes. 00306 * 00307 * 2/15/1998 OriG created 00308 \***************************************************************************/ 00309 00310 VOID UserRemoveRedirectionBitmap(HWND hwnd) 00311 { 00312 PWND pwnd; 00313 00314 if ((pwnd = RevalidateHwnd(hwnd)) == NULL) { 00315 RIPMSG0(RIP_WARNING, "UserRemoveRedirectionBitmap: invalid hwnd"); 00316 return; 00317 } 00318 00319 RemoveRedirectionBitmap(pwnd); 00320 00321 /* 00322 * Clear the layered window flag. This is because GDI is unable to 00323 * transfer the sprite to the new PDEV, and so if we keep this flag 00324 * we will have a layered window without a corresponding sprite which 00325 * can lead to all sort of nasty problems (such as redirection bitmap 00326 * not getting recreated in subsequent mode changes). 00327 */ 00328 ClrWF(pwnd, WEFLAYERED); 00329 } 00330 00331 /***************************************************************************\ 00332 * RecreateRedirectionBitmap 00333 * 00334 * 10/1/1998 vadimg created 00335 \***************************************************************************/ 00336 00337 BOOL RecreateRedirectionBitmap(PWND pwnd) 00338 { 00339 HBITMAP hbm, hbmNew, hbmMem, hbmMem2; 00340 BITMAP bm, bmNew; 00341 int cx, cy; 00342 PDCE pdce; 00343 00344 UserAssert(FLayeredOrRedirected(pwnd)); 00345 00346 /* 00347 * No need to do anything if this layered window doesn't have 00348 * a redirection bitmap. 00349 */ 00350 if ((hbm = (HBITMAP)_GetProp(pwnd, PROP_LAYER, TRUE)) == NULL) 00351 return FALSE; 00352 00353 /* 00354 * Try to create a new redirection bitmap with the new size. If failed, 00355 * delete the old one and remove it from the window property list. 00356 */ 00357 if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) { 00358 RemoveRedirectionBitmap(pwnd); 00359 return FALSE; 00360 } 00361 00362 /* 00363 * Make sure that the display is locked, so that nobody can be drawing 00364 * into the redirection DCs while we're switching bitmaps under them. 00365 */ 00366 UserAssert(GreIsDisplayLocked(gpDispInfo->hDev)); 00367 00368 /* 00369 * Get the size of the old bitmap to know how much to copy. 00370 */ 00371 GreExtGetObjectW(hbm, sizeof(bm), (LPSTR)&bm); 00372 GreExtGetObjectW(hbmNew, sizeof(bmNew), (LPSTR)&bmNew); 00373 00374 /* 00375 * Copy the bitmap from the old bitmap into the new one. 00376 */ 00377 hbmMem = GreSelectBitmap(ghdcMem, hbm); 00378 hbmMem2 = GreSelectBitmap(ghdcMem2, hbmNew); 00379 00380 cx = min(bm.bmWidth, bmNew.bmWidth); 00381 cy = min(bm.bmHeight, bmNew.bmHeight); 00382 00383 GreBitBlt(ghdcMem2, 0, 0, cx, cy, ghdcMem, 0, 0, SRCCOPY | NOMIRRORBITMAP, 0); 00384 00385 /* 00386 * Find layered DCs that are in use corresponding to this window and 00387 * replace the old redirection bitmap by the new one. 00388 */ 00389 for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) { 00390 00391 if (!(pdce->DCX_flags & DCX_LAYERED) || !(pdce->DCX_flags & DCX_INUSE)) 00392 continue; 00393 00394 if (GetTopLevelWindow(pdce->pwndOrg) != pwnd) 00395 continue; 00396 00397 UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbmNew)); 00398 } 00399 00400 GreSelectBitmap(ghdcMem, hbmMem); 00401 GreSelectBitmap(ghdcMem2, hbmMem2); 00402 00403 /* 00404 * Finally, delete the old redirection bitmap. 00405 */ 00406 DeleteRedirectionBitmap(hbm); 00407 00408 return TRUE; 00409 } 00410 00411 /***************************************************************************\ 00412 * UnsetLayeredWindow 00413 * 00414 * 1/30/1998 vadimg created 00415 \***************************************************************************/ 00416 00417 BOOL UnsetLayeredWindow(PWND pwnd) 00418 { 00419 HWND hwnd = PtoHq(pwnd); 00420 00421 /* 00422 * Remove the layered redirection bitmap. 00423 */ 00424 RemoveRedirectionBitmap(pwnd); 00425 00426 /* 00427 * If the window is still visible, leave the sprite bits on the screen. 00428 */ 00429 if (TestWF(pwnd, WFVISIBLE)) { 00430 GreUpdateSprite(gpDispInfo->hDev, hwnd, NULL, NULL, NULL, NULL, 00431 NULL, NULL, 0, NULL, ULW_NOREPAINT, NULL); 00432 } 00433 00434 /* 00435 * Delete the sprite object. 00436 */ 00437 if (!GreDeleteSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL)) { 00438 RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed %X", pwnd); 00439 return FALSE; 00440 } 00441 ClrWF(pwnd, WEFLAYERED); 00442 00443 /* 00444 * No need to jiggle the mouse when the sprite is removed. As an 00445 * added bonus that means that zzzInvalidateDCCache won't leave 00446 * the critical section. 00447 * 00448 * Make sure the window gets painted if visible. 00449 * 00450 * BUGBUG: should jiggle the mouse. Remove IDC_NOMOUSE when 00451 * SetFMouseMoved and thus InvalidateDCCache don't leave crit. 00452 */ 00453 if (TestWF(pwnd, WFVISIBLE)) { 00454 BEGINATOMICCHECK(); 00455 zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE); 00456 ENDATOMICCHECK(); 00457 } 00458 return TRUE; 00459 } 00460 00461 /***************************************************************************\ 00462 * xxxSetLayeredWindow 00463 * 00464 * 12/05/97 vadimg wrote 00465 \***************************************************************************/ 00466 00467 HANDLE xxxSetLayeredWindow(PWND pwnd, BOOL fRepaintBehind) 00468 { 00469 HANDLE hsprite; 00470 SIZE size; 00471 00472 CheckLock(pwnd); 00473 00474 #ifndef CHILD_LAYERING 00475 if (!FTopLevel(pwnd)) { 00476 RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow: not top-level %X", pwnd); 00477 return NULL; 00478 } 00479 #endif // CHILD_LAYERING 00480 00481 #ifdef REDIRECTION 00482 /* 00483 * For now disallow making a layered window redirected and vice versa. 00484 * This is because we need to come up with a clear way to expose 00485 * layered attributes for redirected windows and also because we don't 00486 * know if the redirected bitmap was created for layered redirection 00487 * or redirection in itself. We would need to store a struct with 00488 * flags and the bitmap in the window property to keep track of that. 00489 */ 00490 if (TestWF(pwnd, WEFREDIRECTED)) 00491 return NULL; 00492 #endif // REDIRECTION 00493 00494 #if DBG 00495 if (TestWF(pwnd, WEFLAYERED)) { 00496 RIPMSG1(RIP_ERROR, "xxxSetLayeredWindow: already layered %X", pwnd); 00497 } 00498 #endif 00499 00500 size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left; 00501 size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top; 00502 00503 hsprite = GreCreateSprite(gpDispInfo->hDev, PtoHq(pwnd), &pwnd->rcWindow); 00504 if (hsprite == NULL) { 00505 RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed %X", pwnd); 00506 return NULL; 00507 } 00508 00509 SetWF(pwnd, WEFLAYERED); 00510 TrackLayeredZorder(pwnd); 00511 00512 /* 00513 * Invalidate the DC cache because changing the sprite status 00514 * may change the visrgn for some windows. 00515 * 00516 * BUGBUG: should jiggle the mouse. Remove IDC_NOMOUSE when 00517 * SetFMouseMoved and thus InvalidateDCCache don't leave crit. 00518 */ 00519 BEGINATOMICCHECK(); 00520 zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE); 00521 ENDATOMICCHECK(); 00522 00523 /* 00524 * For the dynamic promotion to a sprite, put the proper bits into 00525 * the sprite itself by doing ULW with the current screen content 00526 * and into the background by invalidating windows behind. There 00527 * might be some dirty bits if the window is partially obscured, but 00528 * they will be refreshed as soon as the app calls ULW on its own. 00529 */ 00530 if (TestWF(pwnd, WFVISIBLE)) { 00531 if (fRepaintBehind) { 00532 POINT pt; 00533 00534 pt.x = pwnd->rcWindow.left; 00535 pt.y = pwnd->rcWindow.top; 00536 00537 _UpdateLayeredWindow(pwnd, gpDispInfo->hdcScreen, &pt, &size, 00538 gpDispInfo->hdcScreen, &pt, 0, NULL, ULW_OPAQUE); 00539 } 00540 } else { 00541 /* 00542 * No need to repaint behind if the window is still invisible. 00543 */ 00544 fRepaintBehind = FALSE; 00545 } 00546 00547 /* 00548 * This must be done after the DC cache is invalidated, because 00549 * the xxxUpdateWindows call will redraw some stuff. 00550 */ 00551 if (fRepaintBehind) { 00552 HRGN hrgn = GreCreateRectRgnIndirect(&pwnd->rcWindow); 00553 xxxRedrawWindow(NULL, NULL, hrgn, RDW_INVALIDATE | RDW_FRAME | 00554 RDW_ERASE | RDW_ALLCHILDREN); 00555 xxxUpdateWindows(pwnd, hrgn); 00556 GreDeleteObject(hrgn); 00557 } 00558 return hsprite; 00559 } 00560 00561 /***************************************************************************\ 00562 * UserVisrgnFromHwnd 00563 * 00564 * Calculate a non-clipchildren visrgn for sprites. This function must be 00565 * called while inside the USER critical section. 00566 * 00567 * 12/05/97 vadimg wrote 00568 \***************************************************************************/ 00569 00570 BOOL UserVisrgnFromHwnd(HRGN *phrgn, HWND hwnd) 00571 { 00572 PWND pwnd; 00573 DWORD dwFlags; 00574 RECT rcWindow; 00575 BOOL fRet; 00576 00577 CheckCritIn(); 00578 00579 if ((pwnd = RevalidateHwnd(hwnd)) == NULL) { 00580 RIPMSG0(RIP_WARNING, "VisrgnFromHwnd: invalid hwnd"); 00581 return FALSE; 00582 } 00583 00584 /* 00585 * So that we don't have to recompute the layered window's visrgn 00586 * every time the layered window is moved, we compute the visrgn once 00587 * as if the layered window covered the entire screen. GDI will 00588 * automatically intersect with this region whenever the sprite moves. 00589 */ 00590 rcWindow = pwnd->rcWindow; 00591 pwnd->rcWindow = gpDispInfo->rcScreen; 00592 00593 /* 00594 * Since we use DCX_WINDOW, only rcWindow needs to be faked and saved. 00595 */ 00596 dwFlags = DCX_WINDOW; 00597 if (TestWF(pwnd, WFCLIPSIBLINGS)) 00598 dwFlags |= DCX_CLIPSIBLINGS; 00599 00600 fRet = CalcVisRgn(phrgn, pwnd, pwnd, dwFlags); 00601 00602 pwnd->rcWindow = rcWindow; 00603 00604 return fRet; 00605 } 00606 00607 /***************************************************************************\ 00608 * SetRectRelative 00609 \***************************************************************************/ 00610 00611 void SetRectRelative(PRECT prc, int dx, int dy, int dcx, int dcy) 00612 { 00613 prc->left += dx; 00614 prc->top += dy; 00615 prc->right += (dx + dcx); 00616 prc->bottom += (dy + dcy); 00617 } 00618 00619 /***************************************************************************\ 00620 * xxxUpdateLayeredWindow 00621 * 00622 * 1/20/1998 vadimg created 00623 \***************************************************************************/ 00624 00625 BOOL _UpdateLayeredWindow( 00626 PWND pwnd, 00627 HDC hdcDst, 00628 POINT *pptDst, 00629 SIZE *psize, 00630 HDC hdcSrc, 00631 POINT *pptSrc, 00632 COLORREF crKey, 00633 BLENDFUNCTION *pblend, 00634 DWORD dwFlags) 00635 { 00636 int dx, dy, dcx, dcy; 00637 BOOL fMove = FALSE, fSize = FALSE; 00638 00639 /* 00640 * Verify that we're called with a real layered window. 00641 */ 00642 if (!TestWF(pwnd, WEFLAYERED) || 00643 _GetProp(pwnd, PROP_LAYER, TRUE) != NULL) { 00644 RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, 00645 "_UpdateLayeredWindow: can't call on window %X", pwnd); 00646 return FALSE; 00647 } 00648 00649 if (!GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, hdcDst, pptDst, 00650 psize, hdcSrc, pptSrc, crKey, pblend, dwFlags, NULL)) { 00651 RIPMSG1(RIP_WARNING, "_UpdateLayeredWindow: !UpdateSprite %X", pwnd); 00652 return FALSE; 00653 } 00654 00655 /* 00656 * Figure out relative adjustments in position and size. 00657 */ 00658 if (pptDst != NULL) { 00659 dx = pptDst->x - pwnd->rcWindow.left; 00660 dy = pptDst->y - pwnd->rcWindow.top; 00661 if (dx != 0 || dy != 0) { 00662 fMove = TRUE; 00663 } 00664 } else { 00665 dx = 0; 00666 dy = 0; 00667 } 00668 if (psize != NULL) { 00669 dcx = psize->cx - (pwnd->rcWindow.right - pwnd->rcWindow.left); 00670 dcy = psize->cy - (pwnd->rcWindow.bottom - pwnd->rcWindow.top); 00671 if (dcx != 0 || dcy != 0) { 00672 fSize = TRUE; 00673 } 00674 } else { 00675 dcx = 0; 00676 dcy = 0; 00677 } 00678 00679 if (fMove || fSize) { 00680 /* 00681 * Adjust the client rect position and size relative to 00682 * the window rect. 00683 */ 00684 SetRectRelative(&pwnd->rcWindow, dx, dy, dcx, dcy); 00685 SetRectRelative(&pwnd->rcClient, dx, dy, dcx, dcy); 00686 00687 /* 00688 * Since the client rect could be smaller than the window 00689 * rect make sure the client rect doesn't underflow! 00690 */ 00691 if ((dcx < 0) && (pwnd->rcClient.left < pwnd->rcWindow.left)) { 00692 pwnd->rcClient.left = pwnd->rcWindow.left; 00693 pwnd->rcClient.right = pwnd->rcWindow.left; 00694 } 00695 if ((dcy < 0) && (pwnd->rcClient.top < pwnd->rcWindow.top)) { 00696 pwnd->rcClient.top = pwnd->rcWindow.top; 00697 pwnd->rcClient.bottom = pwnd->rcWindow.top; 00698 } 00699 /* 00700 * BUGBUG: should jiggle the mouse, do this when SetFMouseMoved 00701 * doesn't leave crit. 00702 * 00703 * SetFMouseMoved(); 00704 */ 00705 } 00706 00707 return TRUE; 00708 } 00709 00710 /***************************************************************************\ 00711 * DeleteFadeSprite 00712 \***************************************************************************/ 00713 00714 PWND DeleteFadeSprite(void) 00715 { 00716 PWND pwnd = NULL; 00717 00718 if (gfade.dwFlags & FADE_WINDOW) { 00719 if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) { 00720 if (TestWF(pwnd, WEFLAYERED)) { 00721 UnsetLayeredWindow(pwnd); 00722 } 00723 } else { 00724 RIPMSG0(RIP_WARNING, "DeleteFadeSprite: hwnd no longer valid"); 00725 } 00726 } else { 00727 GreDeleteSprite(gpDispInfo->hDev, NULL, gfade.hsprite); 00728 } 00729 gfade.hsprite = NULL; 00730 return pwnd; 00731 } 00732 00733 /***************************************************************************\ 00734 * UpdateFade 00735 * 00736 * 2/16/1998 vadimg created 00737 \***************************************************************************/ 00738 00739 void UpdateFade(POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc, 00740 BLENDFUNCTION *pblend) 00741 { 00742 PWND pwnd; 00743 00744 if (gfade.dwFlags & FADE_WINDOW) { 00745 if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) { 00746 _UpdateLayeredWindow(pwnd, NULL, pptDst, psize, hdcSrc, 00747 pptSrc, 0, pblend, ULW_ALPHA); 00748 } 00749 } else { 00750 GreUpdateSprite(gpDispInfo->hDev, NULL, gfade.hsprite, NULL, 00751 pptDst, psize, hdcSrc, pptSrc, 0, pblend, ULW_ALPHA, NULL); 00752 } 00753 } 00754 00755 /***************************************************************************\ 00756 * CreateFade 00757 * 00758 * 2/5/1998 vadimg created 00759 \***************************************************************************/ 00760 00761 HDC CreateFade(PWND pwnd, RECT *prc, DWORD dwTime, DWORD dwFlags) 00762 { 00763 SIZE size; 00764 00765 /* 00766 * Bail if there is a fade animation going on already. 00767 */ 00768 if (gfade.hbm != NULL) { 00769 RIPMSG0(RIP_WARNING, "CreateFade: failed, fade not available"); 00770 return NULL; 00771 } 00772 00773 /* 00774 * Create a cached compatible DC. 00775 */ 00776 if (gfade.hdc == NULL) { 00777 gfade.hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen); 00778 if (gfade.hdc == NULL) { 00779 return NULL; 00780 } 00781 } 00782 00783 /* 00784 * A windowed fade must have window position and size, so 00785 * prc passed in is disregarded. 00786 */ 00787 UserAssert((pwnd == NULL) || (prc == NULL)); 00788 00789 if (pwnd != NULL) { 00790 prc = &pwnd->rcWindow; 00791 } 00792 00793 size.cx = prc->right - prc->left; 00794 size.cy = prc->bottom - prc->top; 00795 00796 if (pwnd == NULL) { 00797 gfade.hsprite = GreCreateSprite(gpDispInfo->hDev, NULL, prc); 00798 } else { 00799 gfade.dwFlags |= FADE_WINDOW; 00800 gfade.hsprite = HWq(pwnd); 00801 00802 BEGINATOMICCHECK(); 00803 xxxSetLayeredWindow(pwnd, FALSE); 00804 ENDATOMICCHECK(); 00805 } 00806 00807 if (gfade.hsprite == NULL) 00808 return FALSE; 00809 00810 /* 00811 * Create a compatible bitmap for this size animation. 00812 */ 00813 gfade.hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, size.cx, size.cy); 00814 if (gfade.hbm == NULL) { 00815 DeleteFadeSprite(); 00816 return NULL; 00817 } 00818 00819 GreSelectBitmap(gfade.hdc, gfade.hbm); 00820 00821 /* 00822 * Since this isn't necessarily the first animation and the hdc could 00823 * be set to public, make sure the owner is the current process. This 00824 * way this process will be able to draw into it. 00825 */ 00826 GreSetDCOwner(gfade.hdc, OBJECT_OWNER_CURRENT); 00827 00828 /* 00829 * Initialize all other fade animation data. 00830 */ 00831 gfade.ptDst.x = prc->left; 00832 gfade.ptDst.y = prc->top; 00833 gfade.size.cx = size.cx; 00834 gfade.size.cy = size.cy; 00835 gfade.dwTime = dwTime; 00836 gfade.dwFlags |= dwFlags; 00837 00838 return gfade.hdc; 00839 } 00840 00841 /***************************************************************************\ 00842 * ShowFade 00843 * 00844 * GDI says that for alpha fade-out it's more efficient to do the first 00845 * show as opaque alpha instead of using ULW_OPAQUE. 00846 \***************************************************************************/ 00847 00848 #define ALPHASTART 40 00849 00850 void ShowFade(void) 00851 { 00852 BLENDFUNCTION blend; 00853 POINT ptSrc; 00854 BOOL fShow; 00855 00856 UserAssert(gfade.hdc != NULL); 00857 UserAssert(gfade.hbm != NULL); 00858 00859 if (gfade.dwFlags & FADE_SHOWN) 00860 return; 00861 00862 fShow = (gfade.dwFlags & FADE_SHOW); 00863 ptSrc.x = ptSrc.y = 0; 00864 blend.BlendOp = AC_SRC_OVER; 00865 blend.BlendFlags = 0; 00866 blend.AlphaFormat = 0; 00867 blend.SourceConstantAlpha = fShow ? ALPHASTART : (255 - ALPHASTART); 00868 UpdateFade(&gfade.ptDst, &gfade.size, gfade.hdc, &ptSrc, &blend); 00869 00870 gfade.dwFlags |= FADE_SHOWN; 00871 } 00872 00873 /***************************************************************************\ 00874 * StartFade 00875 * 00876 * 2/5/1998 vadimg created 00877 \***************************************************************************/ 00878 00879 void StartFade(void) 00880 { 00881 DWORD dwElapsed; 00882 00883 UserAssert(gfade.hdc != NULL); 00884 UserAssert(gfade.hbm != NULL); 00885 00886 /* 00887 * Set dc and bitmap to public so the desktop thread can use them. 00888 */ 00889 GreSetDCOwner(gfade.hdc, OBJECT_OWNER_PUBLIC); 00890 GreSetBitmapOwner(gfade.hbm, OBJECT_OWNER_PUBLIC); 00891 00892 /* 00893 * If it's not already shown, do the initial update that makes copy of 00894 * the source. All other updates will only need to change the alpha value. 00895 */ 00896 ShowFade(); 00897 00898 /* 00899 * Get the start time for the fade animation. 00900 */ 00901 dwElapsed = (gfade.dwTime * ALPHASTART + 255) / 255; 00902 gfade.dwStart = NtGetTickCount() - dwElapsed; 00903 00904 /* 00905 * Set the timer in the desktop thread. This will insure that the 00906 * animation is smooth and won't get stuck if the current thread hangs. 00907 */ 00908 InternalSetTimer(gTermIO.spwndDesktopOwner, IDSYS_FADE, 10, 00909 xxxSystemTimerProc, TMRF_SYSTEM | TMRF_PTIWINDOW); 00910 } 00911 00912 /***************************************************************************\ 00913 * StopFade 00914 * 00915 * 2/5/1998 vadimg created 00916 \***************************************************************************/ 00917 00918 void StopFade(void) 00919 { 00920 DWORD dwRop=SRCCOPY; 00921 PWND pwnd; 00922 00923 UserAssert(gfade.hdc != NULL); 00924 UserAssert(gfade.hbm != NULL); 00925 00926 /* 00927 * Stop the fade animation timer. 00928 */ 00929 _KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_FADE); 00930 00931 pwnd = DeleteFadeSprite(); 00932 00933 /* 00934 * If showing and the animation isn't completed, blt the last frame. 00935 */ 00936 if (!(gfade.dwFlags & FADE_COMPLETED) && (gfade.dwFlags & FADE_SHOW)) { 00937 int x, y; 00938 HDC hdc; 00939 00940 /* 00941 * For a windowed fade, make sure we observe the current visrgn. 00942 */ 00943 if (pwnd != NULL) { 00944 hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_CACHE); 00945 x = 0; 00946 y = 0; 00947 } else { 00948 hdc = gpDispInfo->hdcScreen; 00949 x = gfade.ptDst.x; 00950 y = gfade.ptDst.y; 00951 } 00952 00953 #ifdef USE_MIRRORING 00954 /* 00955 * If the destination DC is RTL mirrored, then BitBlt call should mirror the 00956 * content, since we want the menu to preserve it text (i.e. not to 00957 * be flipped). [samera] 00958 */ 00959 if (GreGetLayout(hdc) & LAYOUT_RTL) { 00960 dwRop |= NOMIRRORBITMAP; 00961 } 00962 #endif 00963 00964 GreBitBlt(hdc, x, y, gfade.size.cx, gfade.size.cy, gfade.hdc, 0, 0, dwRop, 0); 00965 _ReleaseDC(hdc); 00966 } 00967 00968 /* 00969 * Clean up the animation data. 00970 */ 00971 GreSelectBitmap(gfade.hdc, GreGetStockObject(PRIV_STOCK_BITMAP)); 00972 GreDeleteObject(gfade.hbm); 00973 00974 gfade.hbm = NULL; 00975 gfade.dwFlags = 0; 00976 } 00977 00978 /***************************************************************************\ 00979 * AnimateFade 00980 * 00981 * 2/5/1998 vadimg created 00982 \***************************************************************************/ 00983 00984 void AnimateFade(void) 00985 { 00986 DWORD dwTimeElapsed; 00987 BLENDFUNCTION blend; 00988 BYTE bAlpha; 00989 BOOL fShow; 00990 00991 UserAssert(gfade.hdc != NULL); 00992 UserAssert(gfade.hbm != NULL); 00993 00994 dwTimeElapsed = NtGetTickCount() - gfade.dwStart; 00995 00996 /* 00997 * If exceeding the allowed time, stop the animation now. 00998 */ 00999 if (dwTimeElapsed > gfade.dwTime) { 01000 StopFade(); 01001 return; 01002 } 01003 01004 fShow = (gfade.dwFlags & FADE_SHOW); 01005 01006 /* 01007 * Calculate new alpha value based on time elapsed. 01008 */ 01009 if (fShow) { 01010 bAlpha = (BYTE)((255 * dwTimeElapsed) / gfade.dwTime); 01011 } else { 01012 bAlpha = (BYTE)(255 * (gfade.dwTime - dwTimeElapsed) / gfade.dwTime); 01013 } 01014 01015 blend.BlendOp = AC_SRC_OVER; 01016 blend.BlendFlags = 0; 01017 blend.AlphaFormat = 0; 01018 blend.SourceConstantAlpha = bAlpha; 01019 UpdateFade(NULL, NULL, NULL, NULL, &blend); 01020 01021 /* 01022 * Check if finished animating the fade. 01023 */ 01024 if ((fShow && bAlpha == 255) || (!fShow && bAlpha == 0)) { 01025 gfade.dwFlags |= FADE_COMPLETED; 01026 StopFade(); 01027 } 01028 } 01029 01030 #ifdef REDIRECTION 01031 #ifndef CHILD_LAYERING 01032 #error You must enable CHILD_LAYERING to use REDIRECTION 01033 #endif // CHILD_LAYERING 01034 01035 /***************************************************************************\ 01036 * SetRedirectedWindow 01037 * 01038 * 1/27/99 vadimg wrote 01039 \***************************************************************************/ 01040 01041 BOOL SetRedirectedWindow(PWND pwnd) 01042 { 01043 HBITMAP hbmNew = NULL; 01044 01045 /* 01046 * For now disallow making a layered window redirected and vice versa. 01047 * This is because we need to come up with a clear way to expose 01048 * layered attributes for redirected windows and also because we don't 01049 * know if the redirected bitmap was created for layered redirection 01050 * or redirection in itself. We would need to store a struct with 01051 * flags and the bitmap in the window property to keep track of that. 01052 */ 01053 if (TestWF(pwnd, WEFLAYERED)) 01054 return FALSE; 01055 01056 if (_GetProp(pwnd, PROP_LAYER, TRUE) == NULL) { 01057 if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) { 01058 return FALSE; 01059 } 01060 } 01061 01062 SetWF(pwnd, WEFREDIRECTED); 01063 01064 if (hbmNew != NULL) { 01065 ConvertRedirectionDCs(pwnd, hbmNew); 01066 } 01067 01068 /* 01069 * Invalidate the DC cache because changing visual state may 01070 * change the visrgn for some windows. 01071 */ 01072 BEGINATOMICCHECK(); 01073 zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE); 01074 ENDATOMICCHECK(); 01075 01076 return TRUE; 01077 } 01078 01079 /***************************************************************************\ 01080 * UnsetRedirectedWindow 01081 * 01082 * 1/27/1999 vadimg created 01083 \***************************************************************************/ 01084 01085 BOOL UnsetRedirectedWindow(PWND pwnd) 01086 { 01087 RemoveRedirectionBitmap(pwnd); 01088 01089 ClrWF(pwnd, WEFREDIRECTED); 01090 01091 /* 01092 * Invalidate the DC cache because changing visual state may 01093 * change the visrgn for some windows. 01094 */ 01095 BEGINATOMICCHECK(); 01096 zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE); 01097 ENDATOMICCHECK(); 01098 01099 return TRUE; 01100 } 01101 01102 #endif // REDIRECTION 01103 01104 #ifdef CHILD_LAYERING 01105 01106 /***************************************************************************\ 01107 * GetNextLayeredWindow 01108 * 01109 * Preorder traversal of the window tree to find the next layering window 01110 * below in zorder than pwnd. We need this because sprites are stored in a 01111 * linked list. Note that this algorithm is iterative which is cool! 01112 \***************************************************************************/ 01113 01114 PWND GetNextLayeredWindow(PWND pwnd) 01115 { 01116 PWND pwndStop = PWNDDESKTOP(pwnd); 01117 01118 while (TRUE) { 01119 if (pwnd->spwndChild != NULL) { 01120 pwnd = pwnd->spwndChild; 01121 } else if (pwnd->spwndNext != NULL) { 01122 pwnd = pwnd->spwndNext; 01123 } else { 01124 01125 do { 01126 pwnd = pwnd->spwndParent; 01127 01128 if (pwnd == pwndStop) { 01129 return NULL; 01130 } 01131 01132 } while (pwnd->spwndNext == NULL); 01133 01134 pwnd = pwnd->spwndNext; 01135 } 01136 01137 if (TestWF(pwnd, WEFLAYERED)) { 01138 return pwnd; 01139 } 01140 } 01141 } 01142 01143 /***************************************************************************\ 01144 * GetLayeredWindow 01145 * 01146 \***************************************************************************/ 01147 01148 PWND GetLayeredWindow(PWND pwnd) 01149 { 01150 while (pwnd != NULL) { 01151 if (FLayeredOrRedirected(pwnd)) 01152 break; 01153 01154 pwnd = pwnd->spwndParent; 01155 } 01156 return pwnd; 01157 } 01158 01159 #else // CHILD_LAYERING 01160 01161 /***************************************************************************\ 01162 * GetLayeredWindow 01163 * 01164 \***************************************************************************/ 01165 01166 PWND GetLayeredWindow(PWND pwnd) 01167 { 01168 pwnd = GetTopLevelWindow(pwnd); 01169 01170 if (TestWF(pwnd, WEFLAYERED)) 01171 return pwnd; 01172 01173 return NULL; 01174 } 01175 01176 #endif // CHILD_LAYERING 01177 01178 /***************************************************************************\ 01179 * TrackLayeredZorder 01180 * 01181 * Unlike USER, GDI stores sprites from bottom to top. 01182 \***************************************************************************/ 01183 01184 void TrackLayeredZorder(PWND pwnd) 01185 { 01186 #ifdef CHILD_LAYERING 01187 01188 PWND pwndT = GetNextLayeredWindow(pwnd); 01189 01190 #else // CHILD_LAYERING 01191 01192 PWND pwndT = pwnd->spwndNext; 01193 01194 while (pwndT != NULL) { 01195 01196 if (TestWF(pwndT, WEFLAYERED)) 01197 break; 01198 01199 pwndT = pwndT->spwndNext; 01200 } 01201 01202 #endif // CHILD_LAYERING 01203 01204 GreZorderSprite(gpDispInfo->hDev, PtoHq(pwnd), PtoH(pwndT)); 01205 } 01206

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