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
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);
|
|
}
|
|
}
|