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.
 
 
 
 
 
 

806 lines
24 KiB

/****************************** Module Header ******************************\
* Module Name: shadow.c
*
* Copyright (c) 1985 - 2000, Microsoft Corporation
*
* Drop shadow support.
*
* History:
* 04/12/2000 vadimg created
* 02/12/2001 msadek added rounded rectangular shadow support
* for rectangular windows
* 05/08/2001 msadek rewrote the non rounded corners shadow algorithm
* to work well with regional windows, correct visuall effect.
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
// shadow horizontal and veritcal offsets
#define CX_SHADOW 5
#define CY_SHADOW 5
#define C_SHADOW CX_SHADOW
// black as the shadow color
#define RGBA_SHADOW 0x00FFFFFF
// white as the transparent color
#define RGBA_TRANSPARENT 0x00000000
typedef struct tagSHADOW *PSHADOW;
typedef struct tagSHADOW {
PWND pwnd; // window we're shadowing
PWND pwndShadow; // the shadow window we create
PSHADOW pshadowNext; // link to the next shadow struct
} SHADOW;
PSHADOW gpshadowFirst;
// Macro used to map gray scale shadow values to alpha blending scale.
#define ALPHA(x) ((255 - (x)) << 24)
#define ARGB(a, r, g, b) (((DWORD)a<<24)|((DWORD)r<<16)|((DWORD)g<<8)|b)
// Gray scale values for the shadow grades
#define GS01 255
#define GS02 254
#define GS03 253
#define GS04 252
#define GS05 250
#define GS06 246
#define GS07 245
#define GS08 242
#define GS09 241
#define GS10 227
#define GS11 217
#define GS12 213
#define GS13 212
#define GS14 199
#define GS15 180
#define GS16 172
#define GS17 171
#define GS18 155
#define GS19 144
#define GS20 142
// pre-computed alpha values for the shadow
CONST BYTE grgShadow[C_SHADOW] = {
GS04, GS09, GS13, GS17, GS20,
};
CONST ULONG TopRightLTR [CY_SHADOW][CX_SHADOW] = {
ALPHA(GS08), ALPHA(GS06), ALPHA(GS05), ALPHA(GS03), ALPHA(GS02),
ALPHA(GS11), ALPHA(GS10), ALPHA(GS09), ALPHA(GS05), ALPHA(GS02),
ALPHA(GS15), ALPHA(GS14), ALPHA(GS10), ALPHA(GS07), ALPHA(GS03),
ALPHA(GS18), ALPHA(GS15), ALPHA(GS11), ALPHA(GS08), ALPHA(GS03),
ALPHA(GS19), ALPHA(GS16), ALPHA(GS12), ALPHA(GS09), ALPHA(GS04),
};
CONST ULONG RightLTR [CX_SHADOW] = {
ALPHA(GS20), ALPHA(GS17), ALPHA(GS13), ALPHA(GS09), ALPHA(GS04),
};
CONST ULONG BottomRightLTR [CY_SHADOW][CX_SHADOW] = {
ALPHA(GS18), ALPHA(GS15), ALPHA(GS11), ALPHA(GS08), ALPHA(GS03),
ALPHA(GS15), ALPHA(GS14), ALPHA(GS10), ALPHA(GS07), ALPHA(GS03),
ALPHA(GS11), ALPHA(GS10), ALPHA(GS09), ALPHA(GS05), ALPHA(GS02),
ALPHA(GS08), ALPHA(GS06), ALPHA(GS05), ALPHA(GS03), ALPHA(GS02),
ALPHA(GS03), ALPHA(GS03), ALPHA(GS02), ALPHA(GS02), ALPHA(GS01),
};
CONST ULONG Bottom [CY_SHADOW] = {
ALPHA(GS20), ALPHA(GS17), ALPHA(GS13), ALPHA(GS09), ALPHA(GS04),
};
CONST ULONG BottomLeftLTR [CY_SHADOW][CX_SHADOW] = {
ALPHA(GS08), ALPHA(GS11), ALPHA(GS15), ALPHA(GS18), ALPHA(GS19),
ALPHA(GS06), ALPHA(GS10), ALPHA(GS14), ALPHA(GS15), ALPHA(GS16),
ALPHA(GS05), ALPHA(GS09), ALPHA(GS10), ALPHA(GS11), ALPHA(GS12),
ALPHA(GS03), ALPHA(GS05), ALPHA(GS07), ALPHA(GS08), ALPHA(GS09),
ALPHA(GS02), ALPHA(GS02), ALPHA(GS03), ALPHA(GS03), ALPHA(GS04),
};
/***************************************************************************\
* DrawWindowShadow
*
\***************************************************************************/
BOOL DrawWindowShadow(PWND pwnd, HDC hdc, BOOL fRTL, BOOL fForceComplexRgn, PBOOL pfSimpleRgn)
{
HRGN hrgn1, hrgn2;
RECT rc;
HBRUSH hBrushShadow;
BOOL bRet = FALSE;
UserAssert(pfSimpleRgn != NULL);
hrgn1 = GreCreateRectRgn(0, 0, 0, 0);
hrgn2 = GreCreateRectRgn(0, 0, 0, 0);
if (hrgn1 == NULL || hrgn2 == NULL) {
goto Cleanup;
}
/*
* Handle the case when the window is a rectangle or a regional window.
*/
if (pwnd->hrgnClip == NULL || TestWF(pwnd, WFMAXFAKEREGIONAL)) {
rc = pwnd->rcWindow;
OffsetRect(&rc, -rc.left, -rc.top);
GreSetRectRgn(hrgn1, 0, 0, rc.right, rc.bottom);
*pfSimpleRgn = TRUE;
} else {
GreCombineRgn(hrgn1, pwnd->hrgnClip, NULL, RGN_COPY);
GreOffsetRgn(hrgn1, -pwnd->rcWindow.left, -pwnd->rcWindow.top);
*pfSimpleRgn = FALSE;
}
/*
* Offset the window by the shadow offsets and fill the difference
* with the shadow color. The result will be window's shadow.
*/
GreCombineRgn(hrgn2, hrgn1, NULL, RGN_COPY);
if (fRTL) {
GreOffsetRgn(hrgn1, CX_SHADOW, 0);
GreOffsetRgn(hrgn2, 0, CY_SHADOW);
} else {
GreOffsetRgn(hrgn2, CX_SHADOW, CY_SHADOW);
}
bRet = TRUE;
if (!*pfSimpleRgn || fForceComplexRgn) {
int i;
BYTE gs;
for (i = C_SHADOW ; i > 0; i--) {
gs = grgShadow[i - 1];
hBrushShadow = GreCreateSolidBrush(RGB(gs , gs , gs));
if (hBrushShadow == NULL) {
bRet = FALSE;
goto Cleanup;
}
NtGdiFrameRgn(hdc, hrgn2, hBrushShadow, i, i);
GreDeleteObject(hBrushShadow);
}
GreFillRgn(hdc, hrgn1, (HBRUSH)GreGetStockObject(BLACK_BRUSH));
} else {
GreCombineRgn(hrgn2, hrgn2, hrgn1, RGN_DIFF);
GreFillRgn(hdc, hrgn2, (HBRUSH)GreGetStockObject(WHITE_BRUSH));
}
Cleanup:
GreDeleteObject(hrgn1);
GreDeleteObject(hrgn2);
return bRet;
}
/***************************************************************************\
* DrawTopLogicallyRightCorner
*
* Draw the shadow effect of the top, logically right (visually right for LTR, left for RTL window layout)
* corner of a rounded rectangular shadow.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawTopLogicallyRightCorner(VOID* pBits, LONG cx, LONG cy, BOOL fRTL)
{
LONG i, j;
ULONG* ppixel;
if (fRTL) {
for (i = CY_SHADOW; i < (2 * CY_SHADOW); i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((cy - i - 1) * cx) + j;
*ppixel = TopRightLTR[i - CY_SHADOW][CX_SHADOW - 1 - j];
}
}
}
else {
for (i = CY_SHADOW; i < (2 * CY_SHADOW); i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((cy - i) * cx) - CX_SHADOW + j;
*ppixel = TopRightLTR[i - CY_SHADOW][j];
}
}
}
}
/***************************************************************************\
* DrawLogicallyRightSide
*
* Draw the shadow effect of the logically right (visually right for LTR, left for RTL window layout)
* side of a rounded rectangular shadow.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawLogicallyRightSide(VOID* pBits, LONG cx, LONG cy, BOOL fRTL)
{
LONG i, j;
ULONG* ppixel;
if (fRTL) {
for (i = (2 * CY_SHADOW); i < (cy - CY_SHADOW); i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + (cx * ( cy - i -1)) + j;
*ppixel = RightLTR[CX_SHADOW - 1 - j];
}
}
} else {
for (i = (2 * CY_SHADOW); i < (cy - CY_SHADOW); i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + (cx * ( cy - i -1)) + (cx - CX_SHADOW) + j;
*ppixel = RightLTR[j];
}
}
}
}
/***************************************************************************\
* DrawBottomLogicallyRightCorner
*
* Draw the shadow effect of the bottom logically right (visually right for LTR, left for RTL window layout)
* side of a rounded rectangular shadow.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawBottomLogicallyRightCorner(VOID* pBits, LONG cx, BOOL fRTL)
{
LONG i, j;
ULONG* ppixel;
if (fRTL) {
for (i = 0; i < CY_SHADOW; i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i - 1) * cx) + j;
*ppixel = BottomRightLTR[i][CX_SHADOW - 1 - j];
}
}
} else {
for (i = 0; i < CY_SHADOW; i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i) * cx) - CX_SHADOW + j;
*ppixel = BottomRightLTR[i][j];
}
}
}
}
/***************************************************************************\
* DrawBottomSide
*
* Draw the shadow effect of the bottom side of a rounded rectangular shadow.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawBottomSide(VOID* pBits, LONG cx, BOOL fRTL)
{
LONG i, j;
ULONG* ppixel;
if (fRTL) {
for (i = 0; i < CY_SHADOW; i++) {
for (j = CX_SHADOW; j < (cx - (2 * CX_SHADOW)); j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i - 1) * cx) + j;
*ppixel = Bottom[i];
}
}
} else {
for (i = 0; i < CY_SHADOW; i++) {
for (j = (2 * CX_SHADOW); j < (cx - CX_SHADOW); j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i - 1) * cx) + j;
*ppixel = Bottom[i];
}
}
}
}
/***************************************************************************\
* DrawBottomLogicallyLeftCorner
*
* Draw the shadow effect of the bottom logically left (visually left for LTR, right for RTL window layout)
* side of a rounded rectangular shadow.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawBottomLogicallyLeftCorner(VOID* pBits, LONG cx, BOOL fRTL)
{
LONG i, j;
ULONG* ppixel;
if (fRTL) {
for (i = 0; i < CY_SHADOW; i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i) * cx) - (2 * CX_SHADOW) + j;
*ppixel = BottomLeftLTR[i][CX_SHADOW - 1 -j];
}
}
} else {
for (i = 0; i < CY_SHADOW; i++) {
for (j = 0; j < CX_SHADOW; j++) {
ppixel = (ULONG*)pBits + ((CY_SHADOW - i - 1) * cx) + CX_SHADOW + j;
*ppixel = BottomLeftLTR[i][j];
}
}
}
}
/***************************************************************************\
* DrawRoundedRectangularShadow
* Draw a rounded rectangular shadow effect.
* Does not search for shadow pixel location in the bitmap but rather assumes
* it to be the corners of the bitmap.
*
* History:
* 02/12/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawRoundedRectangularShadow(VOID* pBits, LONG cx, LONG cy, BOOL fRTL)
{
DrawTopLogicallyRightCorner(pBits, cx, cy, fRTL);
DrawLogicallyRightSide(pBits, cx, cy, fRTL);
DrawBottomLogicallyRightCorner(pBits, cx, fRTL);
DrawBottomSide(pBits, cx, fRTL);
DrawBottomLogicallyLeftCorner(pBits, cx, fRTL);
}
/***************************************************************************\
* DrawRegionalShadow
* Search for shadow pixel location in the bitmap (those with gray scale in grgShadow
* and adjust the alpha values.
*
*
* History:
* 05/08/2001 Mohamed Sadek [msadek] created
\***************************************************************************/
_inline void DrawRegionalShadow(VOID* pBits, LONG cx, LONG cy)
{
LONG i, j, k;
ULONG* pixel;
BYTE gs;
for (i = 0; i < cy; i++) {
for (j = 0; j < cx; j++) {
pixel = (ULONG*)pBits + (cy - 1 - i) * cx + j;
for (k = 0; k < C_SHADOW; k++) {
gs = grgShadow[k];
if (*pixel == ARGB(0, gs, gs, gs)) {
*pixel = ALPHA(gs);
}
}
}
}
}
/***************************************************************************\
* GenerateWindowShadow
*
\***************************************************************************/
HBITMAP GenerateWindowShadow(PWND pwnd, HDC hdc)
{
BITMAPINFO bmi;
HBITMAP hbm;
VOID* pBits;
LONG cx, cy;
RECT rc;
BOOL fRTL = TestWF(pwnd, WEFLAYOUTRTL);
BOOL fSimpleRgn, fForceComplexRgn = FALSE;
rc = pwnd->rcWindow;
OffsetRect(&rc, -rc.left, -rc.top);
/*
* Doesn't make sense to have a shadow for a window with zero height or width
*/
if (IsRectEmpty(&rc)) {
return NULL;
}
rc.right += CX_SHADOW;
rc.bottom += CY_SHADOW;
cx = rc.right;
cy = rc.bottom;
/*
* Create the DIB section.
*/
RtlZeroMemory(&bmi, sizeof(bmi));
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = cx;
bmi.bmiHeader.biHeight = cy;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
hbm = GreCreateDIBitmapReal(hdc, 0, NULL, &bmi, DIB_RGB_COLORS,
sizeof(bmi), 0, NULL, 0, NULL, 0, 0, &pBits);
if (hbm == NULL) {
return NULL;
}
/*
* Fill the dib section with the transparent color and then
* draw the shadow on top of it.
*/
GreSelectBitmap(hdc, hbm);
FillRect(hdc, &rc, (HBRUSH)GreGetStockObject(BLACK_BRUSH));
/*
* Rectangular window shadow assumes the bitmap dimension to be greater than
* or equal 2 * CX_SHADOW and 2 * CY_SHADOW else it will overrun bitmap buffer.
* and in order to get a real rectangular shadow, the dimension should be 3 * CX_SHADOW
* amd 3 * CY_SHADOW.
*/
if ( (cx < 3 * CX_SHADOW) || (cy < 3 * CY_SHADOW)) {
fForceComplexRgn = TRUE;
}
if (!DrawWindowShadow(pwnd, hdc, fRTL, fForceComplexRgn, &fSimpleRgn)) {
return NULL;
}
if (fSimpleRgn && !fForceComplexRgn) {
DrawRoundedRectangularShadow(pBits, cx, cy, fRTL);
return hbm;
}
DrawRegionalShadow(pBits, cx, cy);
return hbm;
}
/***************************************************************************\
* FindShadow
*
\***************************************************************************/
PSHADOW FindShadow(PWND pwnd)
{
PSHADOW pshadow;
for (pshadow = gpshadowFirst; pshadow != NULL; pshadow = pshadow->pshadowNext) {
if (pshadow->pwnd == pwnd) {
return pshadow;
}
}
return NULL;
}
/***************************************************************************\
* WindowHasShadow
*
\***************************************************************************/
BOOL WindowHasShadow(PWND pwnd)
{
BOOL fHasShadow = FALSE;
if (TestWF(pwnd, WFVISIBLE)) {
PSHADOW pshadow = FindShadow(pwnd);
fHasShadow = (pshadow != NULL);
} else {
/*
* The window isn't currently visible, so there is no shadow window.
* We need to return if the window *would* have a shadow if it were
* shown.
*/
if (TestCF(pwnd, CFDROPSHADOW)) {
fHasShadow = TRUE;
if ((GETFNID(pwnd) == FNID_MENU) && (!TestALPHA(MENUFADE)) && TestEffectUP(MENUANIMATION)) {
fHasShadow = FALSE;
}
}
if (!TestALPHA(DROPSHADOW)) {
fHasShadow = FALSE;
}
}
return fHasShadow;
}
/***************************************************************************\
* ApplyShadow
*
\***************************************************************************/
BOOL ApplyShadow(PWND pwnd, PWND pwndShadow)
{
POINT pt, ptSrc = {0, 0};
SIZE size;
BLENDFUNCTION blend;
HDC hdcShadow;
HBITMAP hbmShadow;
BOOL fRet;
hdcShadow = GreCreateCompatibleDC(gpDispInfo->hdcScreen);
if (hdcShadow == NULL) {
return FALSE;
}
hbmShadow = GenerateWindowShadow(pwnd, hdcShadow);
if (hbmShadow == NULL) {
GreDeleteDC(hdcShadow);
return FALSE;
}
pt.x = pwnd->rcWindow.left;
pt.y = pwnd->rcWindow.top;
size.cx = pwnd->rcWindow.right - pwnd->rcWindow.left + CX_SHADOW;
size.cy = pwnd->rcWindow.bottom - pwnd->rcWindow.top + CY_SHADOW;
if (TestWF(pwnd, WEFLAYOUTRTL)) {
pt.x -= CX_SHADOW;
}
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.AlphaFormat = AC_SRC_ALPHA;
blend.SourceConstantAlpha = 255;
fRet = _UpdateLayeredWindow(pwndShadow, NULL, &pt, &size, hdcShadow, &ptSrc, 0,
&blend, ULW_ALPHA);
GreDeleteDC(hdcShadow);
GreDeleteObject(hbmShadow);
return fRet;
}
/***************************************************************************\
* MoveShadow
*
\***************************************************************************/
VOID MoveShadow(PWND pwnd)
{
PSHADOW pshadow = FindShadow(pwnd);
POINT pt;
if (pshadow == NULL) {
return;
}
pt.x = pwnd->rcWindow.left;
pt.y = pwnd->rcWindow.top;
_UpdateLayeredWindow(pshadow->pwndShadow, NULL, &pt, NULL, NULL, NULL, 0, NULL, 0);
}
/***************************************************************************\
* UpdateShadowShape
*
\***************************************************************************/
VOID UpdateShadowShape(PWND pwnd)
{
PSHADOW pshadow = FindShadow(pwnd);
if (pshadow == NULL) {
return;
}
ApplyShadow(pshadow->pwnd, pshadow->pwndShadow);
}
/***************************************************************************\
* xxxUpdateShadowZorder
*
\***************************************************************************/
VOID xxxUpdateShadowZorder(PWND pwnd)
{
TL tlpwnd;
PWND pwndShadow;
PSHADOW pshadow = FindShadow(pwnd);
if (pshadow == NULL) {
return;
}
pwndShadow = pshadow->pwndShadow;
if (TestWF(pwnd, WEFTOPMOST) && !TestWF(pwndShadow, WEFTOPMOST)) {
SetWF(pwndShadow, WEFTOPMOST);
} else if (!TestWF(pwnd, WEFTOPMOST) && TestWF(pwndShadow, WEFTOPMOST)) {
ClrWF(pwndShadow, WEFTOPMOST);
}
ThreadLock(pwndShadow, &tlpwnd);
xxxSetWindowPos(pwndShadow, pwnd, 0, 0, 0, 0, SWP_NOACTIVATE |
SWP_NOSIZE | SWP_NOMOVE);
ThreadUnlock(&tlpwnd);
}
/***************************************************************************\
* xxxRemoveShadow
*
* Given the shadowed window, destroy the shadow window, cleanup the
* memory used by the shadow structure and remove it from the list.
\***************************************************************************/
VOID xxxRemoveShadow(PWND pwnd)
{
PSHADOW* ppshadow;
PSHADOW pshadow;
PWND pwndT;
CheckLock(pwnd);
ppshadow = &gpshadowFirst;
while (*ppshadow != NULL) {
pshadow = *ppshadow;
if (pshadow->pwnd == pwnd) {
pwndT = pshadow->pwndShadow;
*ppshadow = pshadow->pshadowNext;
UserFreePool(pshadow);
xxxDestroyWindow(pwndT);
break;
}
ppshadow = &pshadow->pshadowNext;
}
}
/***************************************************************************\
* RemoveShadow
*
* Given a shadow structure pointer, search for it in the list and remove it
\***************************************************************************/
VOID RemoveShadow(PSHADOW pshadow)
{
PSHADOW* ppshadow;
PSHADOW pshadowT;
ppshadow = &gpshadowFirst;
while (*ppshadow != NULL) {
pshadowT = *ppshadow;
if (pshadowT == pshadow) {
*ppshadow = pshadowT->pshadowNext;
UserFreePool(pshadowT);
break;
}
ppshadow = &pshadowT->pshadowNext;
}
}
/***************************************************************************\
* CleanupShadow
*
* Given the shadow window, remove the shadow structure from the list and
* cleanup the memory used by the shadow structure.
\***************************************************************************/
VOID CleanupShadow(PWND pwndShadow)
{
PSHADOW* ppshadow;
PSHADOW pshadow;
CheckLock(pwndShadow);
ppshadow = &gpshadowFirst;
while (*ppshadow != NULL) {
pshadow = *ppshadow;
if (pshadow->pwndShadow == pwndShadow) {
*ppshadow = pshadow->pshadowNext;
UserFreePool(pshadow);
break;
}
ppshadow = &pshadow->pshadowNext;
}
}
/***************************************************************************\
* xxxAddShadow
*
\***************************************************************************/
BOOL xxxAddShadow(PWND pwnd)
{
PWND pwndShadow;
DWORD ExStyle;
TL tlpwnd;
TL tlpool;
PSHADOW pshadow;
CheckLock(pwnd);
if (!TestALPHA(DROPSHADOW)) {
return FALSE;
}
if (FindShadow(pwnd)) {
return TRUE;
}
if ((pshadow = (PSHADOW)UserAllocPool(sizeof(SHADOW), TAG_SHADOW)) == NULL) {
return FALSE;
}
ThreadLockPool(PtiCurrent(), pshadow, &tlpool);
ExStyle = WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TRANSPARENT;
if (TestWF(pwnd, WEFTOPMOST)) {
ExStyle |= WS_EX_TOPMOST;
}
pwndShadow = xxxNVCreateWindowEx(ExStyle, (PLARGE_STRING)gatomShadow,
NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, hModuleWin, NULL, WINVER);
if (pwndShadow == NULL || !ApplyShadow(pwnd, pwndShadow)) {
UserFreePool(pshadow);
ThreadUnlockPool(PtiCurrent(), &tlpool);
if (pwndShadow != NULL) {
ThreadLock(pwndShadow, &tlpwnd);
xxxDestroyWindow(pwndShadow);
ThreadUnlock(&tlpwnd);
}
return FALSE;
}
pshadow->pshadowNext = gpshadowFirst;
gpshadowFirst = pshadow;
pshadow->pwnd = pwnd;
pshadow->pwndShadow = pwndShadow;
/*
* Since we added it the global list, we need to change the way
* we lock its pool.
*/
ThreadUnlockPool(PtiCurrent(), &tlpool);
ThreadLockPoolCleanup(PtiCurrent(), pshadow, &tlpool, RemoveShadow);
ThreadLock(pwndShadow, &tlpwnd);
xxxSetWindowPos(pwndShadow, pwnd, 0, 0, 0, 0, SWP_SHOWWINDOW |
SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
ThreadUnlock(&tlpwnd);
ThreadUnlockPool(PtiCurrent(), &tlpool);
return TRUE;
}
/***************************************************************************\
* FAnyShadows
*
\***************************************************************************/
BOOL FAnyShadows(VOID)
{
return (gpshadowFirst != NULL);
}