Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1870 lines
52 KiB

/****************************** Module Header ******************************\
* Module Name: sprite.c
*
* Copyright (c) 1985 - 1999, Microsoft Corporation
*
* Windows Layering (Sprite) support.
*
* History:
* 12/05/97 vadimg created
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifdef MOUSE_IP
#define MOUSE_SONAR_RADIUS_INIT 100
#define MOUSE_SONAR_LINE_WIDTH 4
#define MOUSE_SONAR_RADIUS_DELTA 20
#define MOUSE_SONAR_RADIUS_TIMER 50
#define COLORKEY_COLOR RGB(255, 0, 255)
VOID DrawSonar(HDC hdc);
#endif
#ifdef REDIRECTION
/***************************************************************************\
* UserGetRedirectionBitmap
*
\***************************************************************************/
HBITMAP UserGetRedirectionBitmap(
HWND hwnd)
{
HBITMAP hbm;
PWND pwnd;
EnterCrit();
if ((pwnd = RevalidateHwnd(hwnd)) == NULL) {
return NULL;
}
hbm = GetRedirectionBitmap(pwnd);
LeaveCrit();
return hbm;
}
/***************************************************************************\
* SetRedirectionMode
*
\***************************************************************************/
BOOL SetRedirectionMode(
PBWL pbwl,
PPROCESSINFO ppi)
{
HWND *phwnd;
PWND pwndT;
BOOL fRet = TRUE;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
if ((pwndT = RevalidateHwnd(*phwnd)) == NULL) {
continue;
}
if (TestWF(pwndT, WFVISIBLE) && (ppi == NULL || GETPTI(pwndT)->ppi != ppi)) {
if (SetRedirectedWindow(pwndT, REDIRECT_EXTREDIRECTED)) {
SetWF(pwndT, WEFEXTREDIRECTED);
} else {
fRet = FALSE;
break;
}
}
}
return fRet;
}
/***************************************************************************\
* UnsetRedirectionMode
*
\***************************************************************************/
VOID UnsetRedirectionMode(
PBWL pbwl,
PPROCESSINFO ppi)
{
HWND *phwnd;
PWND pwndT;
for (phwnd = pbwl->rghwnd; *phwnd != (HWND)1; phwnd++) {
if ((pwndT = RevalidateHwnd(*phwnd)) == NULL) {
continue;
}
if (TestWF(pwndT, WFVISIBLE) && ppi == NULL || GETPTI(pwndT)->ppi != ppi) {
UnsetRedirectedWindow(pwndT, REDIRECT_EXTREDIRECTED);
ClrWF(pwndT, WEFEXTREDIRECTED);
}
}
}
/***************************************************************************\
* xxxSetRedirectionMode
*
\***************************************************************************/
BOOL xxxSetRedirectionMode(
BOOL fEnable,
PDESKTOP pDesk,
PTHREADINFO pti,
PPROCESSINFO ppi)
{
PBWL pbwl;
PWND pwndDesktop = pDesk->pDeskInfo->spwnd;
pbwl = BuildHwndList(pwndDesktop->spwndChild, BWL_ENUMLIST, pti);
if (pbwl == NULL) {
return FALSE;
}
if (fEnable) {
if (!SetRedirectionMode(pbwl, ppi)) {
UnsetRedirectionMode(pbwl, ppi);
}
} else {
UnsetRedirectionMode(pbwl, ppi);
}
FreeHwndList(pbwl);
GreEnableDirectDrawRedirection(gpDispInfo->hDev, fEnable);
xxxBroadcastDisplaySettingsChange(PtiCurrent()->rpdesk, FALSE);
pwndDesktop = PtiCurrent()->rpdesk->pDeskInfo->spwnd;
BEGINATOMICCHECK();
xxxInternalInvalidate(pwndDesktop, HRGN_FULL, RDW_INVALIDATE |
RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
ENDATOMICCHECK();
return TRUE;
}
/***************************************************************************\
* xxxSetProcessRedirectionMode
*
\***************************************************************************/
BOOL xxxSetProcessRedirectionMode(
BOOL fEnable,
PPROCESSINFO ppi)
{
PTHREADINFO pti = ppi->ptiList;
TL tl;
while (pti != NULL) {
ThreadLockPti(PtiCurrent(), pti, &tl);
if (!xxxSetRedirectionMode(fEnable, pti->rpdesk, pti, NULL)) {
ThreadUnlockPti(PtiCurrent(), &tl);
return FALSE;
}
pti = pti->ptiSibling;
ThreadUnlockPti(PtiCurrent(), &tl);
}
return TRUE;
}
/***************************************************************************\
* xxxSetDesktopRedirectionMode
*
\***************************************************************************/
BOOL xxxSetDesktopRedirectionMode(
BOOL fEnable,
PDESKTOP pDesk,
PPROCESSINFO ppi)
{
return xxxSetRedirectionMode(fEnable, pDesk, NULL, ppi);
}
#endif
/***************************************************************************\
* IncrementRedirectedCount
*
\***************************************************************************/
VOID IncrementRedirectedCount(
PWND pwnd)
{
if (TestWF(pwnd, WFVISIBLE)) {
gnVisibleRedirectedCount++;
if (gnVisibleRedirectedCount == 1) {
InternalSetTimer(gTermIO.spwndDesktopOwner,
IDSYS_LAYER,
100,
xxxSystemTimerProc,
TMRF_SYSTEM | TMRF_PTIWINDOW);
}
}
}
/***************************************************************************\
* DecrementRedirectedCount
*
\***************************************************************************/
VOID DecrementRedirectedCount(
PWND pwnd)
{
if (TestWF(pwnd, WFVISIBLE)) {
if (gnVisibleRedirectedCount > 0) {
gnVisibleRedirectedCount--;
if (gnVisibleRedirectedCount == 0) {
_KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_LAYER);
}
}
}
}
/***************************************************************************\
* CreateRedirectionBitmap
*
* 10/1/1998 vadimg created
\***************************************************************************/
HBITMAP CreateRedirectionBitmap(
PWND pwnd)
{
HBITMAP hbm;
UserAssert(pwnd->rcWindow.right >= pwnd->rcWindow.left);
UserAssert(pwnd->rcWindow.bottom >= pwnd->rcWindow.top);
/*
* Make sure the (0,0) case doesn't fail, since the window really
* can be sized this way.
*/
if ((hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen,
max(pwnd->rcWindow.right - pwnd->rcWindow.left, 1),
max(pwnd->rcWindow.bottom - pwnd->rcWindow.top, 1) |
CCB_NOVIDEOMEMORY)) == NULL) {
RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap create failed");
return NULL;
}
if (!GreSetBitmapOwner(hbm, OBJECT_OWNER_PUBLIC) ||
!GreMarkUndeletableBitmap(hbm) ||
!SetRedirectionBitmap(pwnd, hbm)) {
RIPMSG0(RIP_WARNING, "CreateRedirectionBitmap: bitmap set failed");
GreMarkDeletableBitmap(hbm);
GreDeleteObject(hbm);
return NULL;
}
SetWF(pwnd, WEFPREDIRECTED);
/*
* Force the window to redraw if we could recreate the bitmap since
* the redirection bitmap we just allocated doesn't contain anything
* yet.
*/
BEGINATOMICCHECK();
xxxInternalInvalidate(pwnd,
HRGN_FULL,
RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN);
ENDATOMICCHECK();
IncrementRedirectedCount(pwnd);
return hbm;
}
/***************************************************************************\
* ConvertRedirectionDCs
*
* 11/19/1998 vadimg created
\***************************************************************************/
VOID ConvertRedirectionDCs(
PWND pwnd,
HBITMAP hbm)
{
PDCE pdce;
GreLockDisplay(gpDispInfo->hDev);
for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
if (pdce->DCX_flags & DCX_DESTROYTHIS) {
continue;
}
if (!(pdce->DCX_flags & DCX_INUSE)) {
continue;
}
if (!_IsDescendant(pwnd, pdce->pwndOrg)) {
continue;
}
/*
* Only normal DCs can be redirected. Redirection on monitor
* specific DCs is not supported.
*/
if (pdce->pMonitor != NULL) {
continue;
}
SET_OR_CLEAR_FLAG(pdce->DCX_flags, DCX_REDIRECTED, (hbm != NULL));
UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbm));
InvalidateDce(pdce);
}
GreUnlockDisplay(gpDispInfo->hDev);
}
/***************************************************************************\
* UpdateRedirectedDC
*
* 11/19/1998 vadimg created
\***************************************************************************/
VOID UpdateRedirectedDC(
PDCE pdce)
{
RECT rcBounds;
PWND pwnd;
SIZE size;
POINT pt;
HBITMAP hbm, hbmOld;
PREDIRECT prdr;
UserAssert(pdce->DCX_flags & DCX_REDIRECTED);
/*
* Check to see if any drawing has been done into this DC
* that should be transferred to the sprite.
*/
if (!GreGetBounds(pdce->hdc, &rcBounds, 0)) {
return;
}
pwnd = GetStyleWindow(pdce->pwndOrg, WEFPREDIRECTED);
UserAssert(pwnd);
prdr = (PREDIRECT)_GetProp(pwnd, PROP_LAYER, TRUE);
#ifdef REDIRECTION
BEGINATOMICCHECK();
xxxWindowEvent(EVENT_SYSTEM_REDIRECTEDPAINT,
pwnd,
MAKELONG(rcBounds.left, rcBounds.top),
MAKELONG(rcBounds.right, rcBounds.bottom),
WEF_ASYNC);
ENDATOMICCHECK();
#endif
if (TestWF(pwnd, WEFCOMPOSITED)) {
if (TestWF(pwnd, WEFPCOMPOSITING)) {
UnionRect(&prdr->rcUpdate, &prdr->rcUpdate, &rcBounds);
} else {
HRGN hrgn;
OffsetRect(&rcBounds, pwnd->rcWindow.left, pwnd->rcWindow.top);
hrgn = GreCreateRectRgnIndirect(&rcBounds);
BEGINATOMICCHECK();
xxxInternalInvalidate(pwnd,
hrgn,
RDW_ALLCHILDREN | RDW_INVALIDATE |
RDW_ERASE | RDW_FRAME);
ENDATOMICCHECK();
GreDeleteObject(hrgn);
}
} else if (TestWF(pwnd, WEFLAYERED)) {
hbm = prdr->hbm;
hbmOld = GreSelectBitmap(ghdcMem, hbm);
size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
pt.x = pt.y = 0;
GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL, NULL,
&size, ghdcMem, &pt, 0, NULL, ULW_DEFAULT_ATTRIBUTES, &rcBounds);
GreSelectBitmap(ghdcMem, hbmOld);
}
}
/***************************************************************************\
* DeleteRedirectionBitmap
*
\***************************************************************************/
VOID DeleteRedirectionBitmap(
PWND pwnd,
HBITMAP hbm)
{
GreMarkDeletableBitmap(hbm);
GreDeleteObject(hbm);
DecrementRedirectedCount(pwnd);
}
/***************************************************************************\
* RemoveRedirectionBitmap
*
* 9/23/1998 vadimg created
\***************************************************************************/
VOID RemoveRedirectionBitmap(
PWND pwnd)
{
HBITMAP hbm;
/*
* Delete the backing bitmap for this layered window.
*/
if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
return;
}
UserAssert(TestWF(pwnd, WEFPREDIRECTED));
ClrWF(pwnd, WEFPREDIRECTED);
ConvertRedirectionDCs(pwnd, NULL);
SetRedirectionBitmap(pwnd, NULL);
DeleteRedirectionBitmap(pwnd, hbm);
}
/***************************************************************************\
* _GetLayeredWindowAttributes
*
* 3/14/2000 jstall created
\***************************************************************************/
BOOL _GetLayeredWindowAttributes(
PWND pwnd,
COLORREF *pcrKey,
BYTE *pbAlpha,
DWORD *pdwFlags)
{
BLENDFUNCTION bf;
UserAssert(pcrKey != NULL);
UserAssert(pbAlpha != NULL);
UserAssert(pdwFlags != NULL);
if (!TestWF(pwnd, WEFLAYERED)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"GetLayeredWindowAttributes: not a sprite 0x%p",
pwnd);
return FALSE;
}
/*
* Check that the window has a redirection bitmap and is marked as
* layered through WS_EX_LAYERED. If the window is layered through
* UpdateLayeredWindow, this function should fail.
*/
if ((GetRedirectionFlags(pwnd) & REDIRECT_LAYER) == 0 ||
!TestWF(pwnd, WEFLAYERED)) {
return FALSE;
}
if (GreGetSpriteAttributes(gpDispInfo->hDev, PtoHq(pwnd), NULL, pcrKey, &bf, pdwFlags)) {
*pbAlpha = bf.SourceConstantAlpha;
return TRUE;
}
return FALSE;
}
/***************************************************************************\
* _SetLayeredWindowAttributes
*
* 9/24/1998 vadimg created
\***************************************************************************/
BOOL _SetLayeredWindowAttributes(
PWND pwnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags)
{
BOOL bRet;
BLENDFUNCTION blend;
HBITMAP hbm;
if (!TestWF(pwnd, WEFLAYERED)) {
RIPERR1(ERROR_INVALID_PARAMETER,
RIP_WARNING,
"SetLayeredWindowAttributes: not a sprite 0x%p",
pwnd);
return FALSE;
}
if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
if (!SetRedirectedWindow(pwnd, REDIRECT_LAYER)) {
return FALSE;
}
}
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = 0;
blend.SourceConstantAlpha = bAlpha;
dwFlags |= ULW_NEW_ATTRIBUTES; // Notify gdi that these are new attributes
if (hbm != NULL) {
HBITMAP hbmOld;
SIZE size;
POINT ptSrc = {0,0};
hbmOld = GreSelectBitmap(ghdcMem, hbm);
size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL,
NULL, &size, ghdcMem, &ptSrc, crKey, &blend, dwFlags, NULL);
GreSelectBitmap(ghdcMem, hbmOld);
} else {
bRet = GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, NULL,
NULL, NULL, NULL, NULL, crKey, &blend, dwFlags, NULL);
}
return bRet;
}
/***************************************************************************\
* RecreateRedirectionBitmap
*
* 10/1/1998 vadimg created
\***************************************************************************/
BOOL RecreateRedirectionBitmap(
PWND pwnd)
{
HBITMAP hbm, hbmNew, hbmMem, hbmMem2;
BITMAP bm, bmNew;
int cx, cy;
PDCE pdce;
/*
* No need to do anything if this layered window doesn't have
* a redirection bitmap.
*/
if ((hbm = GetRedirectionBitmap(pwnd)) == NULL) {
return FALSE;
}
UserAssert(TestWF(pwnd, WEFPREDIRECTED));
/*
* Try to create a new redirection bitmap with the new size. If failed,
* delete the old one and remove it from the window property list.
*/
if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) {
RemoveRedirectionBitmap(pwnd);
return FALSE;
}
/*
* Make sure that the display is locked, so that nobody can be drawing
* into the redirection DCs while we're switching bitmaps under them.
*/
UserAssert(GreIsDisplayLocked(gpDispInfo->hDev));
/*
* Get the size of the old bitmap to know how much to copy.
*/
GreExtGetObjectW(hbm, sizeof(bm), (LPSTR)&bm);
GreExtGetObjectW(hbmNew, sizeof(bmNew), (LPSTR)&bmNew);
/*
* Copy the bitmap from the old bitmap into the new one.
*/
hbmMem = GreSelectBitmap(ghdcMem, hbm);
hbmMem2 = GreSelectBitmap(ghdcMem2, hbmNew);
cx = min(bm.bmWidth, bmNew.bmWidth);
cy = min(bm.bmHeight, bmNew.bmHeight);
GreBitBlt(ghdcMem2, 0, 0, cx, cy, ghdcMem, 0, 0, SRCCOPY | NOMIRRORBITMAP, 0);
/*
* Find layered DCs that are in use corresponding to this window and
* replace the old redirection bitmap by the new one.
*/
for (pdce = gpDispInfo->pdceFirst; pdce != NULL; pdce = pdce->pdceNext) {
if (pdce->DCX_flags & DCX_DESTROYTHIS) {
continue;
}
if (!(pdce->DCX_flags & DCX_REDIRECTED) || !(pdce->DCX_flags & DCX_INUSE)) {
continue;
}
if (!_IsDescendant(pwnd, pdce->pwndOrg)) {
continue;
}
UserVerify(GreSelectRedirectionBitmap(pdce->hdc, hbmNew));
}
GreSelectBitmap(ghdcMem, hbmMem);
GreSelectBitmap(ghdcMem2, hbmMem2);
/*
* Finally, delete the old redirection bitmap.
*/
DeleteRedirectionBitmap(pwnd, hbm);
return TRUE;
}
/***************************************************************************\
* ResetRedirectedWindows
*
\***************************************************************************/
VOID ResetRedirectedWindows(
VOID)
{
PHE phe, pheMax;
PWND pwnd;
GreLockDisplay(gpDispInfo->hDev);
pheMax = &gSharedInfo.aheList[giheLast];
for (phe = gSharedInfo.aheList; phe <= pheMax; phe++) {
if (phe->bType != TYPE_WINDOW) {
continue;
}
pwnd = (PWND)phe->phead;
if (!TestWF(pwnd, WEFPREDIRECTED)) {
continue;
}
RecreateRedirectionBitmap(pwnd);
/*
* Recreate the sprite so the surfaces are at the proper color depth.
*/
if (TestWF(pwnd, WEFLAYERED)) {
COLORREF cr;
BLENDFUNCTION blend;
DWORD dwFlags;
GreGetSpriteAttributes(gpDispInfo->hDev, PtoHq(pwnd), NULL,
&cr, &blend, &dwFlags);
GreDeleteSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL);
if (GreCreateSprite(gpDispInfo->hDev, PtoHq(pwnd), &pwnd->rcWindow)) {
_SetLayeredWindowAttributes(pwnd, cr, blend.SourceConstantAlpha,
dwFlags);
} else {
RemoveRedirectionBitmap(pwnd);
ClrWF(pwnd, WEFLAYERED);
}
}
}
GreUnlockDisplay(gpDispInfo->hDev);
}
/***************************************************************************\
* UnsetLayeredWindow
*
* 1/30/1998 vadimg created
\***************************************************************************/
VOID UnsetLayeredWindow(
PWND pwnd)
{
HWND hwnd = PtoHq(pwnd);
UnsetRedirectedWindow(pwnd, REDIRECT_LAYER);
/*
* If the window is still visible, leave the sprite bits on the screen.
*/
if (TestWF(pwnd, WFVISIBLE)) {
GreUpdateSprite(gpDispInfo->hDev,
hwnd,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
ULW_NOREPAINT,
NULL);
}
/*
* Delete the sprite object.
*/
if (!GreDeleteSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL)) {
RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed 0x%p", pwnd);
}
ClrWF(pwnd, WEFLAYERED);
/*
* Make sure the window gets painted if visible.
*
* RAID 143578.
* Should consider to jiggle the mouse. Remove IDC_NOMOUSE when
* SetFMouseMoved and thus InvalidateDCCache don't leave crit.
* This is because the hit-testing by a window may change when it
* transitions the layering state.
*/
if (TestWF(pwnd, WFVISIBLE)) {
BEGINATOMICCHECK();
zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
ENDATOMICCHECK();
}
}
/***************************************************************************\
* xxxSetLayeredWindow
*
* 12/05/97 vadimg wrote
\***************************************************************************/
HANDLE xxxSetLayeredWindow(
PWND pwnd,
BOOL fRepaintBehind)
{
HANDLE hsprite;
SIZE size;
CheckLock(pwnd);
#ifndef CHILD_LAYERING
if (!FTopLevel(pwnd)) {
RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow: not top-level 0x%p", pwnd);
return NULL;
}
#endif
UserAssertMsg1(!TestWF(pwnd, WEFLAYERED),
"xxxSetLayeredWindow: already layered 0x%p",
pwnd);
size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
hsprite = GreCreateSprite(gpDispInfo->hDev, PtoHq(pwnd), &pwnd->rcWindow);
if (hsprite == NULL) {
RIPMSG1(RIP_WARNING, "xxxSetLayeredWindow failed 0x%p", pwnd);
return NULL;
}
SetWF(pwnd, WEFLAYERED);
TrackLayeredZorder(pwnd);
/*
* Invalidate the DC cache because changing the sprite status
* may change the visrgn for some windows.
*
* RAID 143578.
* Should jiggle the mouse. Remove IDC_NOMOUSE when
* SetFMouseMoved and thus InvalidateDCCache don't leave crit.
* This is because the hit-testing by a window may change when it
* transitions the layering state.
*/
BEGINATOMICCHECK();
zzzInvalidateDCCache(pwnd, IDC_DEFAULT | IDC_NOMOUSE);
ENDATOMICCHECK();
/*
* For the dynamic promotion to a sprite, put the proper bits into
* the sprite itself by doing ULW with the current screen content
* and into the background by invalidating windows behind. There
* might be some dirty bits if the window is partially obscured, but
* they will be refreshed as soon as the app calls ULW on its own.
*/
if (TestWF(pwnd, WFVISIBLE)) {
if (fRepaintBehind) {
POINT pt;
pt.x = pwnd->rcWindow.left;
pt.y = pwnd->rcWindow.top;
_UpdateLayeredWindow(pwnd, gpDispInfo->hdcScreen, &pt, &size,
gpDispInfo->hdcScreen, &pt, 0, NULL, ULW_OPAQUE);
}
} else {
/*
* No need to repaint behind if the window is still invisible.
*/
fRepaintBehind = FALSE;
}
/*
* This must be done after the DC cache is invalidated, because
* the xxxUpdateWindows call will redraw some stuff.
*/
if (fRepaintBehind) {
HRGN hrgn = GreCreateRectRgnIndirect(&pwnd->rcWindow);
xxxRedrawWindow(NULL, NULL, hrgn,
RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN);
xxxUpdateWindows(pwnd, hrgn);
GreDeleteObject(hrgn);
}
return hsprite;
}
/***************************************************************************\
* UserVisrgnFromHwnd
*
* Calculate a non-clipchildren visrgn for sprites. This function must be
* called while inside the USER critical section.
*
* 12/05/97 vadimg wrote
\***************************************************************************/
BOOL UserVisrgnFromHwnd(HRGN *phrgn, HWND hwnd)
{
PWND pwnd;
DWORD dwFlags;
RECT rcWindow;
BOOL fRet;
CheckCritIn();
if ((pwnd = RevalidateHwnd(hwnd)) == NULL) {
RIPMSG0(RIP_WARNING, "VisrgnFromHwnd: invalid hwnd");
return FALSE;
}
/*
* So that we don't have to recompute the layered window's visrgn
* every time the layered window is moved, we compute the visrgn once
* as if the layered window covered the entire screen. GDI will
* automatically intersect with this region whenever the sprite moves.
*/
rcWindow = pwnd->rcWindow;
pwnd->rcWindow = gpDispInfo->rcScreen;
/*
* Since we use DCX_WINDOW, only rcWindow needs to be faked and saved.
* Never specify DCX_REDIRECTEDBITMAP here. See comments in CalcVisRgn().
*/
dwFlags = DCX_WINDOW | DCX_LOCKWINDOWUPDATE;
if (TestWF(pwnd, WFCLIPSIBLINGS))
dwFlags |= DCX_CLIPSIBLINGS;
fRet = CalcVisRgn(phrgn, pwnd, pwnd, dwFlags);
pwnd->rcWindow = rcWindow;
return fRet;
}
/***************************************************************************\
* SetRectRelative
\***************************************************************************/
void SetRectRelative(PRECT prc, int dx, int dy, int dcx, int dcy)
{
prc->left += dx;
prc->top += dy;
prc->right += (dx + dcx);
prc->bottom += (dy + dcy);
}
/***************************************************************************\
* xxxUpdateLayeredWindow
*
* 1/20/1998 vadimg created
\***************************************************************************/
BOOL _UpdateLayeredWindow(
PWND pwnd,
HDC hdcDst,
POINT *pptDst,
SIZE *psize,
HDC hdcSrc,
POINT *pptSrc,
COLORREF crKey,
BLENDFUNCTION *pblend,
DWORD dwFlags)
{
int dx, dy, dcx, dcy;
BOOL fMove = FALSE, fSize = FALSE;
/*
* Verify that we're called with a real layered window.
*/
if (!TestWF(pwnd, WEFLAYERED) ||
GetRedirectionBitmap(pwnd) != NULL) {
RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING,
"_UpdateLayeredWindow: can't call on window 0x%p", pwnd);
return FALSE;
}
if (!GreUpdateSprite(gpDispInfo->hDev, PtoHq(pwnd), NULL, hdcDst, pptDst,
psize, hdcSrc, pptSrc, crKey, pblend, dwFlags, NULL)) {
RIPMSG1(RIP_WARNING, "_UpdateLayeredWindow: !UpdateSprite 0x%p", pwnd);
return FALSE;
}
/*
* Figure out relative adjustments in position and size.
*/
if (pptDst != NULL) {
dx = pptDst->x - pwnd->rcWindow.left;
dy = pptDst->y - pwnd->rcWindow.top;
if (dx != 0 || dy != 0) {
fMove = TRUE;
}
} else {
dx = 0;
dy = 0;
}
if (psize != NULL) {
dcx = psize->cx - (pwnd->rcWindow.right - pwnd->rcWindow.left);
dcy = psize->cy - (pwnd->rcWindow.bottom - pwnd->rcWindow.top);
if (dcx != 0 || dcy != 0) {
fSize = TRUE;
}
} else {
dcx = 0;
dcy = 0;
}
if (fMove || fSize) {
/*
* Adjust the client rect position and size relative to
* the window rect.
*/
SetRectRelative(&pwnd->rcWindow, dx, dy, dcx, dcy);
SetRectRelative(&pwnd->rcClient, dx, dy, dcx, dcy);
/*
* Since the client rect could be smaller than the window
* rect make sure the client rect doesn't underflow!
*/
if ((dcx < 0) && (pwnd->rcClient.left < pwnd->rcWindow.left)) {
pwnd->rcClient.left = pwnd->rcWindow.left;
pwnd->rcClient.right = pwnd->rcWindow.left;
}
if ((dcy < 0) && (pwnd->rcClient.top < pwnd->rcWindow.top)) {
pwnd->rcClient.top = pwnd->rcWindow.top;
pwnd->rcClient.bottom = pwnd->rcWindow.top;
}
/*
* RAID 143578.
* The shape of the layered window may have changed and thus
* ideally we should jiggle the mouse. Currently, that would
* make us leave the critical section which we don't want to do.
*
* SetFMouseMoved();
*/
}
return TRUE;
}
/***************************************************************************\
* DeleteFadeSprite
\***************************************************************************/
PWND DeleteFadeSprite(void)
{
PWND pwnd = NULL;
if (gfade.dwFlags & FADE_WINDOW) {
if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) {
if (TestWF(pwnd, WEFLAYERED)) {
UnsetLayeredWindow(pwnd);
}
} else {
RIPMSG0(RIP_WARNING, "DeleteFadeSprite: hwnd no longer valid");
}
} else {
GreDeleteSprite(gpDispInfo->hDev, NULL, gfade.hsprite);
}
gfade.hsprite = NULL;
return pwnd;
}
/***************************************************************************\
* UpdateFade
*
* 2/16/1998 vadimg created
\***************************************************************************/
void UpdateFade(POINT *pptDst, SIZE *psize, HDC hdcSrc, POINT *pptSrc,
BLENDFUNCTION *pblend)
{
PWND pwnd;
if (gfade.dwFlags & FADE_WINDOW) {
if ((pwnd = RevalidateHwnd(gfade.hsprite)) != NULL) {
_UpdateLayeredWindow(pwnd, NULL, pptDst, psize, hdcSrc,
pptSrc, 0, pblend, ULW_ALPHA);
}
} else {
#ifdef MOUSE_IP
DWORD dwShape = ULW_ALPHA;
if (gfade.dwFlags & FADE_COLORKEY) {
dwShape = ULW_COLORKEY;
}
GreUpdateSprite(gpDispInfo->hDev, NULL, gfade.hsprite, NULL,
pptDst, psize, hdcSrc, pptSrc, gfade.crColorKey, pblend, dwShape, NULL);
#else
GreUpdateSprite(gpDispInfo->hDev, NULL, gfade.hsprite, NULL,
pptDst, psize, hdcSrc, pptSrc, 0, pblend, ULW_ALPHA, NULL);
#endif
}
}
/***************************************************************************\
* CreateFade
*
* 2/5/1998 vadimg created
\***************************************************************************/
HDC CreateFade(PWND pwnd, RECT *prc, DWORD dwTime, DWORD dwFlags)
{
SIZE size;
/*
* Bail if there is a fade animation going on already.
*/
if (gfade.hbm != NULL) {
RIPMSG0(RIP_WARNING, "CreateFade: failed, fade not available");
return NULL;
}
/*
* Create a cached compatible DC.
*/
if (gfade.hdc == NULL) {
gfade.hdc = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
if (gfade.hdc == NULL) {
return NULL;
}
} else {
/*
* Reset the hdc before reusing it.
*/
GreSetLayout(gfade.hdc , -1, 0);
}
/*
* A windowed fade must have window position and size, so
* prc passed in is disregarded.
*/
UserAssert((pwnd == NULL) || (prc == NULL));
if (pwnd != NULL) {
prc = &pwnd->rcWindow;
}
size.cx = prc->right - prc->left;
size.cy = prc->bottom - prc->top;
if (pwnd == NULL) {
gfade.hsprite = GreCreateSprite(gpDispInfo->hDev, NULL, prc);
} else {
gfade.dwFlags |= FADE_WINDOW;
gfade.hsprite = HWq(pwnd);
BEGINATOMICCHECK();
xxxSetLayeredWindow(pwnd, FALSE);
ENDATOMICCHECK();
}
if (gfade.hsprite == NULL)
return FALSE;
/*
* Create a compatible bitmap for this size animation.
*/
gfade.hbm = GreCreateCompatibleBitmap(gpDispInfo->hdcScreen, size.cx, size.cy);
if (gfade.hbm == NULL) {
DeleteFadeSprite();
return NULL;
}
GreSelectBitmap(gfade.hdc, gfade.hbm);
/*
* Mirror the hdc if it will be used to fade a mirrored window.
*/
if ((pwnd != NULL) && TestWF(pwnd, WEFLAYOUTRTL)) {
GreSetLayout(gfade.hdc , -1, LAYOUT_RTL);
}
/*
* Since this isn't necessarily the first animation and the hdc could
* be set to public, make sure the owner is the current process. This
* way this process will be able to draw into it.
*/
GreSetDCOwner(gfade.hdc, OBJECT_OWNER_CURRENT);
/*
* Initialize all other fade animation data.
*/
gfade.ptDst.x = prc->left;
gfade.ptDst.y = prc->top;
gfade.size.cx = size.cx;
gfade.size.cy = size.cy;
gfade.dwTime = dwTime;
gfade.dwFlags |= dwFlags;
#ifdef MOUSE_IP
if (gfade.dwFlags & FADE_COLORKEY) {
gfade.crColorKey = COLORKEY_COLOR;
} else {
gfade.crColorKey = 0;
}
#endif
return gfade.hdc;
}
/***************************************************************************\
* ShowFade
*
* GDI says that for alpha fade-out it's more efficient to do the first
* show as opaque alpha instead of using ULW_OPAQUE.
\***************************************************************************/
#define ALPHASTART 40
VOID ShowFade(
VOID)
{
BLENDFUNCTION blend;
POINT ptSrc;
BOOL fShow;
UserAssert(gfade.hdc != NULL);
UserAssert(gfade.hbm != NULL);
if (gfade.dwFlags & FADE_SHOWN) {
return;
}
fShow = (gfade.dwFlags & FADE_SHOW);
ptSrc.x = ptSrc.y = 0;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = 0;
blend.SourceConstantAlpha = fShow ? ALPHASTART : (255 - ALPHASTART);
UpdateFade(&gfade.ptDst, &gfade.size, gfade.hdc, &ptSrc, &blend);
gfade.dwFlags |= FADE_SHOWN;
}
/***************************************************************************\
* StartFade
*
* 2/5/1998 vadimg created
\***************************************************************************/
VOID StartFade(
VOID)
{
DWORD dwTimer = 10;
DWORD dwElapsed;
UserAssert(gfade.hdc != NULL);
UserAssert(gfade.hbm != NULL);
/*
* Set dc and bitmap to public so the desktop thread can use them.
*/
GreSetDCOwner(gfade.hdc, OBJECT_OWNER_PUBLIC);
GreSetBitmapOwner(gfade.hbm, OBJECT_OWNER_PUBLIC);
/*
* If it's not already shown, do the initial update that makes copy of
* the source. All other updates will only need to change the alpha value.
*/
ShowFade();
/*
* Get the start time for the fade animation.
*/
dwElapsed = (gfade.dwTime * ALPHASTART + 255) / 255;
gfade.dwStart = NtGetTickCount() - dwElapsed;
/*
* Set the timer in the desktop thread. This will insure that the
* animation is smooth and won't get stuck if the current thread hangs.
*/
#ifdef MOUSE_IP
if (gfade.dwFlags & FADE_SONAR) {
/*
* Sonar requires slower timer.
*/
dwTimer = MOUSE_SONAR_RADIUS_TIMER;
}
#endif
InternalSetTimer(gTermIO.spwndDesktopOwner,
IDSYS_FADE,
dwTimer,
xxxSystemTimerProc,
TMRF_SYSTEM | TMRF_PTIWINDOW);
}
/***************************************************************************\
* StopFade
*
* 2/5/1998 vadimg created
\***************************************************************************/
VOID StopFade(
VOID)
{
DWORD dwRop = SRCCOPY;
PWND pwnd;
UserAssert(gfade.hdc != NULL);
UserAssert(gfade.hbm != NULL);
/*
* Stop the fade animation timer.
*/
_KillSystemTimer(gTermIO.spwndDesktopOwner, IDSYS_FADE);
pwnd = DeleteFadeSprite();
/*
* If showing and the animation isn't completed, blt the last frame.
*/
if (!(gfade.dwFlags & FADE_COMPLETED) && (gfade.dwFlags & FADE_SHOW)) {
int x, y;
HDC hdc;
/*
* For a windowed fade, make sure we observe the current visrgn.
*/
if (pwnd != NULL) {
hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_CACHE);
x = 0;
y = 0;
} else {
hdc = gpDispInfo->hdcScreen;
x = gfade.ptDst.x;
y = gfade.ptDst.y;
}
/*
* If the destination DC is RTL mirrored, then BitBlt call should mirror the
* content, since we want the menu to preserve it text (i.e. not to
* be flipped). [samera]
*/
if (GreGetLayout(hdc) & LAYOUT_RTL) {
dwRop |= NOMIRRORBITMAP;
}
GreBitBlt(hdc, x, y, gfade.size.cx, gfade.size.cy, gfade.hdc, 0, 0, dwRop, 0);
_ReleaseDC(hdc);
}
/*
* Clean up the animation data.
*/
GreSelectBitmap(gfade.hdc, GreGetStockObject(PRIV_STOCK_BITMAP));
GreCleanDC(gfade.hdc);
GreSetDCOwner(gfade.hdc, OBJECT_OWNER_PUBLIC);
GreDeleteObject(gfade.hbm);
gfade.hbm = NULL;
gfade.dwFlags = 0;
}
/***************************************************************************\
* AnimateFade
*
* 2/5/1998 vadimg created
\***************************************************************************/
VOID AnimateFade(
VOID)
{
DWORD dwTimeElapsed;
BLENDFUNCTION blend;
BYTE bAlpha;
BOOL fShow;
UserAssert(gfade.hdc != NULL);
UserAssert(gfade.hbm != NULL);
dwTimeElapsed = NtGetTickCount() - gfade.dwStart;
/*
* If exceeding the allowed time, stop the animation now.
*/
if (dwTimeElapsed > gfade.dwTime) {
StopFade();
return;
}
fShow = (gfade.dwFlags & FADE_SHOW);
/*
* Calculate new alpha value based on time elapsed.
*/
if (fShow) {
bAlpha = (BYTE)((255 * dwTimeElapsed) / gfade.dwTime);
} else {
bAlpha = (BYTE)(255 * (gfade.dwTime - dwTimeElapsed) / gfade.dwTime);
}
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = 0;
blend.SourceConstantAlpha = bAlpha;
#ifdef MOUSE_IP
if (gfade.dwFlags & FADE_SONAR) {
DrawSonar(gfade.hdc);
UpdateFade(&gfade.ptDst, &gfade.size, gfade.hdc, (LPPOINT)&gZero.pt, NULL);
giSonarRadius -= MOUSE_SONAR_RADIUS_DELTA;
} else {
UpdateFade(NULL, NULL, NULL, NULL, &blend);
}
/*
* Check if finished animating the fade.
*/
if ((fShow && bAlpha == 255) || (!fShow && bAlpha == 0) || ((gfade.dwFlags & FADE_SONAR) && giSonarRadius < 0)) {
gfade.dwFlags |= FADE_COMPLETED;
StopFade();
}
#else
UpdateFade(NULL, NULL, NULL, NULL, &blend);
/*
* Check if finished animating the fade.
*/
if ((fShow && bAlpha == 255) || (!fShow && bAlpha == 0)) {
gfade.dwFlags |= FADE_COMPLETED;
StopFade();
}
#endif
}
/***************************************************************************\
* SetRedirectedWindow
*
* 1/27/99 vadimg wrote
\***************************************************************************/
BOOL SetRedirectedWindow(
PWND pwnd,
UINT uFlags)
{
HBITMAP hbmNew = NULL;
PREDIRECT prdr;
PCLS pcls;
if (!TestWF(pwnd, WEFPREDIRECTED)) {
/*
* Setup the window for Redirection. This will create a new bitmap to
* redirect drawing into, and then converting all HDC's to that window
* to draw into that bitmap. The contents of the bitmap will be copied
* to the screen in UpdateRedirectedDC().
*/
UserAssert(GetRedirectionBitmap(pwnd) == NULL);
/*
* NOTE: We can only redirect windows that don't use CS_CLASSDC or
* CS_PARENTDC. This is because we need to setup a new to draw into
* that is not the screen HDC. When we do this, we explicitely mark
* the DC with DCX_REDIRECTED.
*
* In the case of CS_CLASSDC or CS_PARENTDC, that DC may be shared
* between a redirected window and a non-redirected window, causing a
* conflict.
*
* This is not a problem for CS_OWNDC, since the window has its own
* HDC that will not be shared. It does however require that we setup
* redirection after this HDC is already built. This behavior was
* changed in Whistler (NT 5.1).
*/
pcls = pwnd->pcls;
if (TestCF2(pcls, CFPARENTDC) || TestCF2(pcls, CFCLASSDC)) {
RIPMSG0(RIP_WARNING, "Cannot enable redirection on CS_PARENTDC, or CS_CLASSDC window");
return FALSE;
}
if ((hbmNew = CreateRedirectionBitmap(pwnd)) == NULL) {
return FALSE;
}
ConvertRedirectionDCs(pwnd, hbmNew);
}
prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
prdr->uFlags |= uFlags;
#if DBG
prdr->pwnd = pwnd;
#endif
return TRUE;
}
/***************************************************************************\
* UnsetRedirectedWindow
*
* 1/27/1999 vadimg created
\***************************************************************************/
VOID UnsetRedirectedWindow(
PWND pwnd,
UINT uFlags)
{
if (TestWF(pwnd, WEFPREDIRECTED)) {
PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
prdr->uFlags &= ~uFlags;
if (prdr->uFlags != 0) {
return;
}
RemoveRedirectionBitmap(pwnd);
}
}
#ifdef CHILD_LAYERING
/***************************************************************************\
* GetNextLayeredWindow
*
* Preorder traversal of the window tree to find the next layering window
* below in zorder than pwnd. We need this because sprites are stored in a
* linked list. Note that this algorithm is iterative which is cool!
\***************************************************************************/
PWND GetNextLayeredWindow(
PWND pwnd)
{
while (TRUE) {
if (pwnd->spwndChild != NULL) {
pwnd = pwnd->spwndChild;
} else if (pwnd->spwndNext != NULL) {
pwnd = pwnd->spwndNext;
} else {
do {
pwnd = pwnd->spwndParent;
if (pwnd == NULL) {
return NULL;
}
} while (pwnd->spwndNext == NULL);
pwnd = pwnd->spwndNext;
}
if (TestWF(pwnd, WEFLAYERED)) {
return pwnd;
}
}
}
#endif
/***************************************************************************\
* GetStyleWindow
*
\***************************************************************************/
PWND GetStyleWindow(
PWND pwnd,
DWORD dwStyle)
{
while (pwnd != NULL) {
if (TestWF(pwnd, dwStyle)) {
break;
}
pwnd = pwnd->spwndParent;
}
return pwnd;
}
/***************************************************************************\
* TrackLayeredZorder
*
* Unlike USER, GDI stores sprites from bottom to top.
\***************************************************************************/
VOID TrackLayeredZorder(
PWND pwnd)
{
#ifdef CHILD_LAYERING
PWND pwndT = GetNextLayeredWindow(pwnd);
#else
PWND pwndT = pwnd->spwndNext;
while (pwndT != NULL) {
if (TestWF(pwndT, WEFLAYERED)) {
break;
}
pwndT = pwndT->spwndNext;
}
#endif
GreZorderSprite(gpDispInfo->hDev, PtoHq(pwnd), PtoH(pwndT));
}
/***************************************************************************\
* GetRedirectionBitmap
*
\***************************************************************************/
HBITMAP GetRedirectionBitmap(
PWND pwnd)
{
PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
if (prdr != NULL) {
return prdr->hbm;
}
return NULL;
}
/***************************************************************************\
* SetRedirectionBitmap
*
\***************************************************************************/
BOOL SetRedirectionBitmap(
PWND pwnd,
HBITMAP hbm)
{
PREDIRECT prdr;
if (hbm == NULL) {
prdr = (PREDIRECT)InternalRemoveProp(pwnd, PROP_LAYER, TRUE);
if (prdr != NULL) {
UserFreePool(prdr);
}
} else {
prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
if (prdr == NULL) {
if ((prdr = (PREDIRECT)UserAllocPool(sizeof(REDIRECT),
TAG_REDIRECT)) == NULL) {
return FALSE;
}
if (!InternalSetProp(pwnd, PROP_LAYER, (HANDLE)prdr, PROPF_INTERNAL)) {
UserFreePool(prdr);
return FALSE;
}
} else {
DeleteMaybeSpecialRgn(prdr->hrgnComp);
}
prdr->hbm = hbm;
prdr->uFlags = 0;
prdr->hrgnComp = NULL;
SetRectEmpty(&prdr->rcUpdate);
}
return TRUE;
}
#ifdef MOUSE_IP
CONST RECT grcSonar = {0, 0, MOUSE_SONAR_RADIUS_INIT * 2, MOUSE_SONAR_RADIUS_INIT * 2};
VOID DrawSonar(
HDC hdc)
{
HBRUSH hbrBackground;
HBRUSH hbrRing, hbrOld;
HPEN hpen, hpenOld;
hbrBackground = GreCreateSolidBrush(COLORKEY_COLOR);
if (hbrBackground == NULL) {
RIPMSG0(RIP_WARNING, "DrawSonar: failed to create background brush.");
return;
}
FillRect(hdc, &grcSonar, hbrBackground);
/*
* Pen for the edges.
*/
hpen = GreCreatePen(PS_SOLID, 0, RGB(255, 255, 255), NULL);
if (hpen == NULL) {
RIPMSG0(RIP_WARNING, "DrawSonar: failed to create pen.");
goto return1;
}
hpenOld = GreSelectPen(hdc, hpen);
/*
* Draw the ring.
*/
hbrRing = GreCreateSolidBrush(RGB(128, 128, 128));
if (hbrRing == NULL) {
goto return2;
}
hbrOld = GreSelectBrush(hdc, hbrRing);
NtGdiEllipse(hdc, MOUSE_SONAR_RADIUS_INIT - giSonarRadius, MOUSE_SONAR_RADIUS_INIT - giSonarRadius,
MOUSE_SONAR_RADIUS_INIT + giSonarRadius, MOUSE_SONAR_RADIUS_INIT + giSonarRadius);
/*
* Draw innter hollow area (this draws inner edge as well).
*/
GreSelectBrush(hdc, hbrBackground);
NtGdiEllipse(hdc, MOUSE_SONAR_RADIUS_INIT - giSonarRadius + MOUSE_SONAR_LINE_WIDTH,
MOUSE_SONAR_RADIUS_INIT - giSonarRadius + MOUSE_SONAR_LINE_WIDTH,
MOUSE_SONAR_RADIUS_INIT + giSonarRadius - MOUSE_SONAR_LINE_WIDTH,
MOUSE_SONAR_RADIUS_INIT + giSonarRadius - MOUSE_SONAR_LINE_WIDTH);
/*
* Clean up things.
*/
GreSelectBrush(hdc, hbrOld);
UserAssert(hbrRing);
GreDeleteObject(hbrRing);
return2:
GreSelectPen(hdc, hpenOld);
if (hpen) {
GreDeleteObject(hpen);
}
return1:
if (hbrBackground) {
GreDeleteObject(hbrBackground);
}
}
/***************************************************************************\
* SonarAction
*
\***************************************************************************/
BOOL StartSonar(
VOID)
{
HDC hdc;
RECT rc;
UserAssert(TestUP(MOUSESONAR));
gptSonarCenter = gpsi->ptCursor;
/*
* LATER: Is this the right thing?
*/
if (gfade.dwFlags) {
/*
* Some other animation is going on.
* Stop it first.
*/
UserAssert(!TestFadeFlags(FADE_SONAR));
StopSonar();
UserAssert(gfade.dwFlags == 0);
}
rc.left = gptSonarCenter.x - MOUSE_SONAR_RADIUS_INIT;
rc.right = gptSonarCenter.x + MOUSE_SONAR_RADIUS_INIT;
rc.top = gptSonarCenter.y - MOUSE_SONAR_RADIUS_INIT;
rc.bottom = gptSonarCenter.y + MOUSE_SONAR_RADIUS_INIT;
giSonarRadius = MOUSE_SONAR_RADIUS_INIT;
hdc = CreateFade(NULL, &rc, CMS_SONARTIMEOUT, FADE_SONAR | FADE_COLORKEY);
if (hdc == NULL) {
RIPMSG0(RIP_WARNING, "StartSonar: failed to create a new sonar.");
return FALSE;
}
/*
* Start sonar animation.
*/
DrawSonar(hdc);
StartFade();
AnimateFade();
return TRUE;
}
VOID StopSonar(
VOID)
{
UserAssert(TestUP(MOUSESONAR));
StopFade();
giSonarRadius = -1;
}
#endif // MOUSE_IP
/***************************************************************************\
* GetRedirectionFlags
*
* GetRedirectionFlags returns the current redirection flags for a given
* window.
*
* 2/8/2000 JStall created
\***************************************************************************/
UINT GetRedirectionFlags(
PWND pwnd)
{
PREDIRECT prdr = _GetProp(pwnd, PROP_LAYER, TRUE);
if (prdr != NULL) {
return prdr->uFlags;
}
return 0;
}
/***************************************************************************\
* xxxPrintWindow
*
* xxxPrintWindow uses redirection to get a complete bitmap of a window. If
* the window already has a redirection bitmap, the bits will be directly
* copied. If the window doesn't have a redirection bitmap, it will be
* temporarily redirected, forcibly redrawn, and then returned to its
* previous state.
*
* 2/8/2000 JStall created
\***************************************************************************/
BOOL xxxPrintWindow(
PWND pwnd,
HDC hdcBlt,
UINT nFlags)
{
HDC hdcSrc;
SIZE sizeBmpPxl;
POINT ptOffsetPxl;
BOOL fTempRedir;
BOOL fSuccess;
CheckLock(pwnd);
/*
* Determine the area of the window to copy.
*/
if ((nFlags & PW_CLIENTONLY) != 0) {
/*
* Only get the client area
*/
ptOffsetPxl.x = pwnd->rcWindow.left - pwnd->rcClient.left;
ptOffsetPxl.y = pwnd->rcWindow.top - pwnd->rcClient.top;
sizeBmpPxl.cx = pwnd->rcClient.right - pwnd->rcClient.left;
sizeBmpPxl.cy = pwnd->rcClient.bottom - pwnd->rcClient.top;
} else {
/*
* Return the entire window
*/
ptOffsetPxl.x = 0;
ptOffsetPxl.y = 0;
sizeBmpPxl.cx = pwnd->rcWindow.right - pwnd->rcWindow.left;
sizeBmpPxl.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top;
}
/*
* Redirect the window so that we can get the bits. Since this flag never
* is turned on outside this function call, always safe to turn it on here.
*/
fTempRedir = (GetRedirectionFlags(pwnd) == 0);
if (!SetRedirectedWindow(pwnd, REDIRECT_PRINT)) {
/*
* Unable to redirect the window, so can't get the bits.
*/
fSuccess = FALSE;
goto Done;
} else {
fSuccess = TRUE;
}
if (fTempRedir) {
xxxUpdateWindow(pwnd);
}
hdcSrc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_CACHE);
GreBitBlt(hdcBlt, 0, 0, sizeBmpPxl.cx, sizeBmpPxl.cy,
hdcSrc, ptOffsetPxl.x, ptOffsetPxl.y, SRCCOPY | NOMIRRORBITMAP, 0);
_ReleaseDC(hdcSrc);
/*
* Cleanup
*/
UnsetRedirectedWindow(pwnd, REDIRECT_PRINT);
Done:
return fSuccess;
}
/***************************************************************************\
* xxxEnumTurnOffCompositing
*
* xxxEnumTurnOffCompositing() is called for each window, giving an
* opportunity to turn off WS_EX_COMPOSITED for that window.
*
* 8/21/2000 JStall created
\***************************************************************************/
BOOL APIENTRY xxxEnumTurnOffCompositing(PWND pwnd, LPARAM lParam)
{
CheckLock(pwnd);
UNREFERENCED_PARAMETER(lParam);
if (TestWF(pwnd, WEFCOMPOSITED)) {
DWORD dwStyle = (pwnd->ExStyle & ~WS_EX_COMPOSITED) & WS_EX_ALLVALID;
xxxSetWindowStyle(pwnd, GWL_EXSTYLE, dwStyle);
}
return TRUE;
}
/***************************************************************************\
* xxxTurnOffCompositing
*
* xxxTurnOffCompositing() turns off WS_EX_COMPOSITED for (optionally a
* PWND and) its children. This is used when reparenting under
* a parent-chain that has WS_EX_COMPOSITED already turned on. If we don't
* turn off WS_EX_COMPOSITED for the children, it takes extra bitmaps and the
* compositing will not properly work.
*
* 8/21/2000 JStall created
\***************************************************************************/
VOID xxxTurnOffCompositing(
PWND pwndStart,
BOOL fChild)
{
TL tlpwnd;
UINT nFlags = BWL_ENUMCHILDREN;
CheckLock(pwndStart);
/*
* If they want to skip over the wnd itself and start with this WND's
* child, we need to get and lock that child. We will unlock it when
* finished. We also need to mark BWL_ENUMLIST so that we will enumerate
* all of the children.
*/
if (fChild) {
pwndStart = pwndStart->spwndChild;
if (pwndStart == NULL) {
return;
}
nFlags |= BWL_ENUMLIST;
ThreadLockAlways(pwndStart, &tlpwnd);
}
/*
* Enumerate the windows.
*/
xxxInternalEnumWindow(pwndStart, xxxEnumTurnOffCompositing, 0, nFlags);
if (fChild) {
ThreadUnlock(&tlpwnd);
}
}