From fca682a62e1c454c47ddb07f744e9ca6a7b1d4da Mon Sep 17 00:00:00 2001 From: James Tabor Date: Fri, 11 Sep 2015 02:34:11 +0000 Subject: [PATCH] [Win32SS] - Hackplement Layered Window Support from wine. - See CORE-1576 for more information. Three days work, ReactOS needs more support for playing with GDI bits. svn path=/trunk/; revision=69179 --- reactos/win32ss/CMakeLists.txt | 1 + reactos/win32ss/user/ntuser/layered.c | 391 +++++++++++++++++++ reactos/win32ss/user/ntuser/msgqueue.c | 2 +- reactos/win32ss/user/ntuser/ntstubs.c | 47 --- reactos/win32ss/user/ntuser/userfuncs.h | 5 + reactos/win32ss/user/ntuser/window.c | 5 + reactos/win32ss/user/user32/windows/window.c | 7 +- 7 files changed, 408 insertions(+), 50 deletions(-) create mode 100644 reactos/win32ss/user/ntuser/layered.c diff --git a/reactos/win32ss/CMakeLists.txt b/reactos/win32ss/CMakeLists.txt index ca75c75a8a5..b4b9cfaa760 100644 --- a/reactos/win32ss/CMakeLists.txt +++ b/reactos/win32ss/CMakeLists.txt @@ -122,6 +122,7 @@ list(APPEND SOURCE user/ntuser/ime.c user/ntuser/keyboard.c user/ntuser/kbdlayout.c + user/ntuser/layered.c user/ntuser/menu.c user/ntuser/message.c user/ntuser/metric.c diff --git a/reactos/win32ss/user/ntuser/layered.c b/reactos/win32ss/user/ntuser/layered.c new file mode 100644 index 00000000000..558aff145eb --- /dev/null +++ b/reactos/win32ss/user/ntuser/layered.c @@ -0,0 +1,391 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Win32k subsystem + * PURPOSE: Layered window support + * FILE: win32ss/user/ntuser/layered.c + * PROGRAMER: + */ + +#include +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); + if (pLrdProp) + { + return pLrdProp->is_Layered; + } + return FALSE; +} + +BOOL FASTCALL +SetLayeredStatus(PWND pWnd, BYTE set) +{ + PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer); + 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); + + 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)); + IntSetProp(pWnd, AtomLayer, (HANDLE)pLrdProp); + } + + 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) + { + HBRUSH hBr; + HDC hdc; + RECT Rect; + BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 }; + COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID; + + 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; + + hBr = NtGdiCreateSolidBrush(color_key, NULL); + if (hBr) + { + TRACE("Fill Color Key %x\n",color_key); + FillRect(hdc, &Rect, hBr); + } + + 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 scA %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, + 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, + blend, + 0); + + if (hBr) GreDeleteObject(hBr); + 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"); + + if (!(pWnd = UserGetWindowObject(hwnd)) || + !(pWnd->ExStyle & WS_EX_LAYERED) ) + { + return FALSE; + } + + UserEnterExclusive(); + + pLrdProp = UserGetProp(pWnd, AtomLayer); + + if (!pLrdProp) + { + TRACE("No Prop!\n"); + goto Exit; + } + + if (pLrdProp->is_Layered == 0) + { + goto Exit; + } + + _SEH2_TRY + { + if (pcrKey) *pcrKey = pLrdProp->Key; + if (pbAlpha) *pbAlpha = pLrdProp->Alpha; + if (pdwFlags) *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"); + + if (!(pWnd = UserGetWindowObject(hwnd))) + { + return FALSE; + } + + _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(return FALSE); + } + _SEH2_END; + + UserEnterExclusive(); + + 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 : 0; + info.psize = &Size; + info.hdcSrc = hdcSrc; + info.pptSrc = pptSrc ? &Src : 0; + info.crKey = crKey; + info.pblend = &blend; + info.dwFlags = dwFlags; + info.prcDirty = prcDirty ? &Dirty : 0; + Ret = IntUpdateLayeredWindowI( pWnd, &info ); +Exit: + TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret); + UserLeave(); + return Ret; +} + +/* EOF */ diff --git a/reactos/win32ss/user/ntuser/msgqueue.c b/reactos/win32ss/user/ntuser/msgqueue.c index bf12a5a58df..dce1f9b131c 100644 --- a/reactos/win32ss/user/ntuser/msgqueue.c +++ b/reactos/win32ss/user/ntuser/msgqueue.c @@ -62,7 +62,7 @@ IntTopLevelWindowFromPoint(INT x, INT y) } if ((pWnd->style & WS_VISIBLE) && - (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == 0 && + (pWnd->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) != (WS_EX_LAYERED|WS_EX_TRANSPARENT) && IntPtInWindow(pWnd, x, y)) return pWnd; } diff --git a/reactos/win32ss/user/ntuser/ntstubs.c b/reactos/win32ss/user/ntuser/ntstubs.c index d45237da3d1..6642c8ffa21 100644 --- a/reactos/win32ss/user/ntuser/ntstubs.c +++ b/reactos/win32ss/user/ntuser/ntstubs.c @@ -980,53 +980,6 @@ NtUserLockWindowUpdate(HWND hWnd) return 0; } -BOOL -APIENTRY -NtUserGetLayeredWindowAttributes( - HWND hwnd, - COLORREF *pcrKey, - BYTE *pbAlpha, - DWORD *pdwFlags) -{ - STUB; - return 0; -} - -/* - * @unimplemented - */ -BOOL APIENTRY -NtUserSetLayeredWindowAttributes(HWND hwnd, - COLORREF crKey, - BYTE bAlpha, - DWORD dwFlags) -{ - STUB; - return FALSE; -} - -/* - * @unimplemented - */ -BOOL -APIENTRY -NtUserUpdateLayeredWindow( - HWND hwnd, - HDC hdcDst, - POINT *pptDst, - SIZE *psize, - HDC hdcSrc, - POINT *pptSrc, - COLORREF crKey, - BLENDFUNCTION *pblend, - DWORD dwFlags, - RECT *prcDirty) -{ - STUB - - return 0; -} - DWORD APIENTRY NtUserQuerySendMessage(DWORD Unknown0) { diff --git a/reactos/win32ss/user/ntuser/userfuncs.h b/reactos/win32ss/user/ntuser/userfuncs.h index 2addad1176b..34e1408b04a 100644 --- a/reactos/win32ss/user/ntuser/userfuncs.h +++ b/reactos/win32ss/user/ntuser/userfuncs.h @@ -145,4 +145,9 @@ HBRUSH FASTCALL DefWndControlColor(HDC hDC,UINT ctlType); BOOL UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down); BOOL UserPaintCaption(PWND pWnd, INT Flags); +/************** LAYERED **************/ + +BOOL FASTCALL SetLayeredStatus(PWND pWnd, BYTE set); +BOOL FASTCALL GetLayeredStatus(PWND pWnd); + /* EOF */ diff --git a/reactos/win32ss/user/ntuser/window.c b/reactos/win32ss/user/ntuser/window.c index d63ec08c17a..d04475f682f 100644 --- a/reactos/win32ss/user/ntuser/window.c +++ b/reactos/win32ss/user/ntuser/window.c @@ -3546,6 +3546,11 @@ co_IntSetWindowLong(HWND hWnd, DWORD Index, LONG NewValue, BOOL Ansi, BOOL bAlte else Style.styleNew &= ~WS_EX_WINDOWEDGE; + if (!(Window->ExStyle & WS_EX_LAYERED)) + { + SetLayeredStatus(Window, 0); + } + Window->ExStyle = (DWORD)Style.styleNew; co_IntSendMessage(hWnd, WM_STYLECHANGED, GWL_EXSTYLE, (LPARAM) &Style); diff --git a/reactos/win32ss/user/user32/windows/window.c b/reactos/win32ss/user/user32/windows/window.c index 885c56f5764..3a5efa3e7df 100644 --- a/reactos/win32ss/user/user32/windows/window.c +++ b/reactos/win32ss/user/user32/windows/window.c @@ -1713,8 +1713,11 @@ UpdateLayeredWindow( HWND hwnd, BLENDFUNCTION *pbl, DWORD dwFlags) { - if ( dwFlags & ULW_EX_NORESIZE) - dwFlags = ~(ULW_EX_NORESIZE|ULW_OPAQUE|ULW_ALPHA|ULW_COLORKEY); + if (dwFlags & ULW_EX_NORESIZE) /* only valid for UpdateLayeredWindowIndirect */ + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } return NtUserUpdateLayeredWindow( hwnd, hdcDst, pptDst,