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