reactos/win32ss/user/ntuser/layered.c

427 lines
10 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Layered window support
* FILE: win32ss/user/ntuser/layered.c
* PROGRAMER:
*/
#include <win32k.h>
DBG_DEFAULT_CHANNEL(UserMisc);
typedef struct _LRD_PROP
{
COLORREF Key;
BYTE Alpha;
BYTE is_Layered;
BYTE NoUsed[2];
DWORD Flags;
} LRD_PROP, *PLRD_PROP;
BOOL FASTCALL
GetLayeredStatus(PWND pWnd)
{
PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
if (pLrdProp)
{
return pLrdProp->is_Layered;
}
return FALSE;
}
BOOL FASTCALL
SetLayeredStatus(PWND pWnd, BYTE set)
{
PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
if (pLrdProp)
{
pLrdProp->is_Layered = set;
return TRUE;
}
return FALSE;
}
BOOL FASTCALL
IntSetLayeredWindowAttributes(PWND pWnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags)
{
PLRD_PROP pLrdProp;
INT was_Layered;
if (!(pWnd->ExStyle & WS_EX_LAYERED) )
{
ERR("Not a Layered Window!\n");
return FALSE;
}
pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
if (!pLrdProp)
{
pLrdProp = ExAllocatePoolWithTag(PagedPool, sizeof(LRD_PROP), USERTAG_REDIRECT);
if (pLrdProp == NULL)
{
ERR("failed to allocate LRD_PROP\n");
return FALSE;
}
RtlZeroMemory(pLrdProp, sizeof(LRD_PROP));
UserSetProp(pWnd, AtomLayer, (HANDLE)pLrdProp, TRUE);
}
if (pLrdProp)
{
was_Layered = pLrdProp->is_Layered;
pLrdProp->Key = crKey;
if (dwFlags & LWA_ALPHA)
{
pLrdProp->Alpha = bAlpha;
}
else
{
if (!pLrdProp->is_Layered) pLrdProp->Alpha = 0;
}
pLrdProp->Flags = dwFlags;
pLrdProp->is_Layered = 1;
if (!was_Layered)
co_UserRedrawWindow(pWnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
}
// FIXME: Now set some bits to the Window DC!!!!
return TRUE;
}
BOOL FASTCALL
IntUpdateLayeredWindowI( PWND pWnd,
UPDATELAYEREDWINDOWINFO *info )
{
PWND Parent;
RECT Window, Client;
SIZE Offset;
BOOL ret = FALSE;
DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
Window = pWnd->rcWindow;
Client = pWnd->rcClient;
Parent = pWnd->spwndParent;
if (pWnd->style & WS_CHILD && Parent)
{
RECTL_vOffsetRect(&Window, - Parent->rcClient.left, - Parent->rcClient.top);
RECTL_vOffsetRect(&Client, - Parent->rcClient.left, - Parent->rcClient.top);
}
if (info->pptDst)
{
Offset.cx = info->pptDst->x - Window.left;
Offset.cy = info->pptDst->y - Window.top;
RECTL_vOffsetRect( &Client, Offset.cx, Offset.cy );
RECTL_vOffsetRect( &Window, Offset.cx, Offset.cy );
flags &= ~SWP_NOMOVE;
}
if (info->psize)
{
Offset.cx = info->psize->cx - (Window.right - Window.left);
Offset.cy = info->psize->cy - (Window.bottom - Window.top);
if (info->psize->cx <= 0 || info->psize->cy <= 0)
{
ERR("Update Layered Invalid Parameters\n");
EngSetLastError( ERROR_INVALID_PARAMETER );
return FALSE;
}
if ((info->dwFlags & ULW_EX_NORESIZE) && (Offset.cx || Offset.cy))
{
ERR("Wrong Size\n");
EngSetLastError( ERROR_INCORRECT_SIZE );
return FALSE;
}
Client.right += Offset.cx;
Client.bottom += Offset.cy;
Window.right += Offset.cx;
Window.bottom += Offset.cy;
flags &= ~SWP_NOSIZE;
}
if (info->hdcSrc)
{
HDC hdc, hdcBuffer;
RECT Rect;
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
HBITMAP hOldBitmap, hOldBitmap1, hbmSrc, hbmDst;
DIBSECTION dibs;
Rect = Window;
RECTL_vOffsetRect( &Rect, -Window.left, -Window.top );
TRACE("H %d W %d\n",Rect.bottom - Rect.top,Rect.right - Rect.left);
if (!info->hdcDst) hdc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
else hdc = info->hdcDst;
hbmSrc = NtGdiCreateCompatibleBitmap(info->hdcSrc, Rect.right - Rect.left, Rect.bottom - Rect.top);
hbmDst = NtGdiCreateCompatibleBitmap(info->hdcSrc, Rect.right - Rect.left, Rect.bottom - Rect.top);
GreGetObject(hbmSrc, sizeof(DIBSECTION), &dibs);
TRACE("Source Bitmap bc %d\n",dibs.dsBmih.biBitCount);
hdcBuffer = NtGdiCreateCompatibleDC(hdc);
hOldBitmap = (HBITMAP)NtGdiSelectBitmap(hdcBuffer, hbmSrc);
hOldBitmap1 = (HBITMAP)NtGdiSelectBitmap(hdc, hbmDst);
NtGdiStretchBlt( hdcBuffer,
Rect.left,
Rect.top,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
info->hdcSrc,
Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
Rect.top + (info->pptSrc ? info->pptSrc->y : 0),
Rect.right - Rect.left,
Rect.bottom - Rect.top,
SRCCOPY,
color_key );
// Need to test this, Dirty before or after StretchBlt?
if (info->prcDirty)
{
ERR("prcDirty\n");
RECTL_bIntersectRect( &Rect, &Rect, info->prcDirty );
NtGdiPatBlt( hdc, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, BLACKNESS );
}
if (info->dwFlags & ULW_ALPHA)
{
blend = *info->pblend;
TRACE("ULW_ALPHA bop %d Alpha %d aF %d\n", blend.BlendOp, blend.SourceConstantAlpha, blend.AlphaFormat);
}
ret = NtGdiAlphaBlend( hdc,
Rect.left,
Rect.top,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
hdcBuffer,
Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
Rect.top + (info->pptSrc ? info->pptSrc->y : 0),
Rect.right - Rect.left,
Rect.bottom - Rect.top,
blend,
0);
NtGdiSelectBitmap(hdc, hOldBitmap1);
NtGdiSelectBitmap(hdcBuffer, hOldBitmap);
if (hbmSrc) GreDeleteObject(hbmSrc);
if (hbmDst) GreDeleteObject(hbmDst);
if (hdcBuffer) IntGdiDeleteDC(hdcBuffer, FALSE);
if (!info->hdcDst) UserReleaseDC(pWnd, hdc, FALSE);
}
else
ret = TRUE;
co_WinPosSetWindowPos(pWnd, 0, Window.left, Window.top, Window.right - Window.left, Window.bottom - Window.top, flags);
return ret;
}
/*
* @implemented
*/
BOOL
APIENTRY
NtUserGetLayeredWindowAttributes(
HWND hwnd,
COLORREF *pcrKey,
BYTE *pbAlpha,
DWORD *pdwFlags)
{
PLRD_PROP pLrdProp;
PWND pWnd;
BOOL Ret = FALSE;
TRACE("Enter NtUserGetLayeredWindowAttributes\n");
UserEnterExclusive();
if (!(pWnd = UserGetWindowObject(hwnd)) ||
!(pWnd->ExStyle & WS_EX_LAYERED) )
{
ERR("Not a Layered Window!\n");
goto Exit;
}
pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
if (!pLrdProp)
{
TRACE("No Prop!\n");
goto Exit;
}
if (pLrdProp->is_Layered == 0)
{
goto Exit;
}
_SEH2_TRY
{
if (pcrKey)
{
ProbeForWrite(pcrKey, sizeof(*pcrKey), 1);
*pcrKey = pLrdProp->Key;
}
if (pbAlpha)
{
ProbeForWrite(pbAlpha, sizeof(*pbAlpha), 1);
*pbAlpha = pLrdProp->Alpha;
}
if (pdwFlags)
{
ProbeForWrite(pdwFlags, sizeof(*pdwFlags), 1);
*pdwFlags = pLrdProp->Flags;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
_SEH2_YIELD(goto Exit);
}
_SEH2_END;
Ret = TRUE;
Exit:
TRACE("Leave NtUserGetLayeredWindowAttributes, ret=%i\n", Ret);
UserLeave();
return Ret;
}
/*
* @implemented
*/
BOOL APIENTRY
NtUserSetLayeredWindowAttributes(HWND hwnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags)
{
PWND pWnd;
BOOL Ret = FALSE;
TRACE("Enter NtUserSetLayeredWindowAttributes\n");
UserEnterExclusive();
if (!(pWnd = UserGetWindowObject(hwnd)) ||
!(pWnd->ExStyle & WS_EX_LAYERED) )
{
ERR("Not a Layered Window!\n");
goto Exit;
}
Ret = IntSetLayeredWindowAttributes(pWnd, crKey, bAlpha, dwFlags);
Exit:
TRACE("Leave NtUserSetLayeredWindowAttributes, ret=%i\n", Ret);
UserLeave();
return Ret;
}
/*
* @implemented
*/
BOOL
APIENTRY
NtUserUpdateLayeredWindow(
HWND hwnd,
HDC hdcDst,
POINT *pptDst,
SIZE *psize,
HDC hdcSrc,
POINT *pptSrc,
COLORREF crKey,
BLENDFUNCTION *pblend,
DWORD dwFlags,
RECT *prcDirty)
{
UPDATELAYEREDWINDOWINFO info;
POINT Dst, Src;
SIZE Size;
RECT Dirty;
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
PWND pWnd;
BOOL Ret = FALSE;
TRACE("Enter NtUserUpdateLayeredWindow\n");
UserEnterExclusive();
if (!(pWnd = UserGetWindowObject(hwnd)))
{
goto Exit;
}
_SEH2_TRY
{
if (pptDst)
{
ProbeForRead(pptDst, sizeof(POINT), 1);
Dst = *pptDst;
}
if (pptSrc)
{
ProbeForRead(pptSrc, sizeof(POINT), 1);
Src = *pptSrc;
}
ProbeForRead(psize, sizeof(SIZE), 1);
Size = *psize;
if (pblend)
{
ProbeForRead(pblend, sizeof(BLENDFUNCTION), 1);
blend = *pblend;
}
if (prcDirty)
{
ProbeForRead(prcDirty, sizeof(RECT), 1);
Dirty = *prcDirty;
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
EngSetLastError( ERROR_INVALID_PARAMETER );
_SEH2_YIELD(goto Exit);
}
_SEH2_END;
if ( GetLayeredStatus(pWnd) ||
dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
!(pWnd->ExStyle & WS_EX_LAYERED) )
{
ERR("Layered Window Invalid Parameters\n");
EngSetLastError( ERROR_INVALID_PARAMETER );
goto Exit;
}
info.cbSize = sizeof(info);
info.hdcDst = hdcDst;
info.pptDst = pptDst? &Dst : NULL;
info.psize = &Size;
info.hdcSrc = hdcSrc;
info.pptSrc = pptSrc ? &Src : NULL;
info.crKey = crKey;
info.pblend = &blend;
info.dwFlags = dwFlags;
info.prcDirty = prcDirty ? &Dirty : NULL;
Ret = IntUpdateLayeredWindowI( pWnd, &info );
Exit:
TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret);
UserLeave();
return Ret;
}
/* EOF */