xref: /reactos/win32ss/user/ntuser/layered.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS Win32k subsystem
4  * PURPOSE:          Layered window support
5  * FILE:             win32ss/user/ntuser/layered.c
6  * PROGRAMER:
7  */
8 
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMisc);
11 
12 
13 typedef struct _LRD_PROP
14 {
15    COLORREF Key;
16    BYTE     Alpha;
17    BYTE     is_Layered;
18    BYTE     NoUsed[2];
19    DWORD    Flags;
20 } LRD_PROP, *PLRD_PROP;
21 
22 BOOL FASTCALL
GetLayeredStatus(PWND pWnd)23 GetLayeredStatus(PWND pWnd)
24 {
25    PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
26    if (pLrdProp)
27    {
28       return pLrdProp->is_Layered;
29    }
30    return FALSE;
31 }
32 
33 BOOL FASTCALL
SetLayeredStatus(PWND pWnd,BYTE set)34 SetLayeredStatus(PWND pWnd, BYTE set)
35 {
36    PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
37    if (pLrdProp)
38    {
39       pLrdProp->is_Layered = set;
40       return TRUE;
41    }
42    return FALSE;
43 }
44 
45 BOOL FASTCALL
IntSetLayeredWindowAttributes(PWND pWnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags)46 IntSetLayeredWindowAttributes(PWND pWnd,
47                               COLORREF crKey,
48                               BYTE bAlpha,
49                               DWORD dwFlags)
50 {
51    PLRD_PROP pLrdProp;
52    INT was_Layered;
53 
54    if (!(pWnd->ExStyle & WS_EX_LAYERED) )
55    {
56       ERR("Not a Layered Window!\n");
57       return FALSE;
58    }
59 
60    pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
61 
62    if (!pLrdProp)
63    {
64       pLrdProp = ExAllocatePoolWithTag(PagedPool, sizeof(LRD_PROP), USERTAG_REDIRECT);
65       if (pLrdProp == NULL)
66       {
67          ERR("failed to allocate LRD_PROP\n");
68          return FALSE;
69       }
70       RtlZeroMemory(pLrdProp, sizeof(LRD_PROP));
71       UserSetProp(pWnd, AtomLayer, (HANDLE)pLrdProp, TRUE);
72    }
73 
74    if (pLrdProp)
75    {
76       was_Layered = pLrdProp->is_Layered;
77 
78       pLrdProp->Key = crKey;
79 
80       if (dwFlags & LWA_ALPHA)
81       {
82          pLrdProp->Alpha = bAlpha;
83       }
84       else
85       {
86          if (!pLrdProp->is_Layered) pLrdProp->Alpha = 0;
87       }
88 
89       pLrdProp->Flags = dwFlags;
90 
91       pLrdProp->is_Layered = 1;
92 
93       if (!was_Layered)
94          co_UserRedrawWindow(pWnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME );
95    }
96    // FIXME: Now set some bits to the Window DC!!!!
97    return TRUE;
98 }
99 
100 BOOL FASTCALL
IntUpdateLayeredWindowI(PWND pWnd,UPDATELAYEREDWINDOWINFO * info)101 IntUpdateLayeredWindowI( PWND pWnd,
102                          UPDATELAYEREDWINDOWINFO *info )
103 {
104    PWND Parent;
105    RECT Window, Client;
106    SIZE Offset;
107    BOOL ret = FALSE;
108    DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW;
109 
110    Window = pWnd->rcWindow;
111    Client = pWnd->rcClient;
112 
113    Parent = pWnd->spwndParent;
114    if (pWnd->style & WS_CHILD && Parent)
115    {
116       RECTL_vOffsetRect(&Window, - Parent->rcClient.left, - Parent->rcClient.top);
117       RECTL_vOffsetRect(&Client, - Parent->rcClient.left, - Parent->rcClient.top);
118    }
119 
120    if (info->pptDst)
121    {
122       Offset.cx = info->pptDst->x - Window.left;
123       Offset.cy = info->pptDst->y - Window.top;
124       RECTL_vOffsetRect( &Client, Offset.cx, Offset.cy );
125       RECTL_vOffsetRect( &Window, Offset.cx, Offset.cy );
126       flags &= ~SWP_NOMOVE;
127    }
128    if (info->psize)
129    {
130       Offset.cx = info->psize->cx - (Window.right  - Window.left);
131       Offset.cy = info->psize->cy - (Window.bottom - Window.top);
132       if (info->psize->cx <= 0 || info->psize->cy <= 0)
133       {
134           ERR("Update Layered Invalid Parameters\n");
135           EngSetLastError( ERROR_INVALID_PARAMETER );
136           return FALSE;
137       }
138       if ((info->dwFlags & ULW_EX_NORESIZE) && (Offset.cx || Offset.cy))
139       {
140           ERR("Wrong Size\n");
141           EngSetLastError( ERROR_INCORRECT_SIZE );
142           return FALSE;
143       }
144       Client.right  += Offset.cx;
145       Client.bottom += Offset.cy;
146       Window.right  += Offset.cx;
147       Window.bottom += Offset.cy;
148       flags &= ~SWP_NOSIZE;
149    }
150 
151    if (info->hdcSrc)
152    {
153       HDC hdc, hdcBuffer;
154       RECT Rect;
155       BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
156       COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
157       HBITMAP hOldBitmap, hOldBitmap1, hbmSrc, hbmDst;
158       DIBSECTION dibs;
159 
160       Rect = Window;
161 
162       RECTL_vOffsetRect( &Rect, -Window.left, -Window.top );
163 
164       TRACE("H %d W %d\n",Rect.bottom - Rect.top,Rect.right - Rect.left);
165 
166       if (!info->hdcDst) hdc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
167       else hdc = info->hdcDst;
168 
169       hbmSrc = NtGdiCreateCompatibleBitmap(info->hdcSrc, Rect.right - Rect.left, Rect.bottom - Rect.top);
170       hbmDst = NtGdiCreateCompatibleBitmap(info->hdcSrc, Rect.right - Rect.left, Rect.bottom - Rect.top);
171 
172       GreGetObject(hbmSrc, sizeof(DIBSECTION), &dibs);
173 
174       TRACE("Source Bitmap bc %d\n",dibs.dsBmih.biBitCount);
175 
176       hdcBuffer = NtGdiCreateCompatibleDC(hdc);
177 
178       hOldBitmap = (HBITMAP)NtGdiSelectBitmap(hdcBuffer, hbmSrc);
179       hOldBitmap1 = (HBITMAP)NtGdiSelectBitmap(hdc, hbmDst);
180 
181       NtGdiStretchBlt( hdcBuffer,
182                        Rect.left,
183                        Rect.top,
184                        Rect.right - Rect.left,
185                        Rect.bottom - Rect.top,
186                        info->hdcSrc,
187                        Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
188                        Rect.top  + (info->pptSrc ? info->pptSrc->y : 0),
189                        Rect.right - Rect.left,
190                        Rect.bottom - Rect.top,
191                        SRCCOPY,
192                        color_key );
193 
194       // Need to test this, Dirty before or after StretchBlt?
195       if (info->prcDirty)
196       {
197          ERR("prcDirty\n");
198          RECTL_bIntersectRect( &Rect, &Rect, info->prcDirty );
199          NtGdiPatBlt( hdc, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, BLACKNESS );
200       }
201 
202       if (info->dwFlags & ULW_ALPHA)
203       {
204          blend = *info->pblend;
205          TRACE("ULW_ALPHA bop %d Alpha %d aF %d\n", blend.BlendOp, blend.SourceConstantAlpha, blend.AlphaFormat);
206       }
207 
208       ret = NtGdiAlphaBlend( hdc,
209                              Rect.left,
210                              Rect.top,
211                              Rect.right - Rect.left,
212                              Rect.bottom - Rect.top,
213                              hdcBuffer,
214                              Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
215                              Rect.top  + (info->pptSrc ? info->pptSrc->y : 0),
216                              Rect.right - Rect.left,
217                              Rect.bottom - Rect.top,
218                              blend,
219                              0);
220 
221       NtGdiSelectBitmap(hdc, hOldBitmap1);
222       NtGdiSelectBitmap(hdcBuffer, hOldBitmap);
223       if (hbmSrc) GreDeleteObject(hbmSrc);
224       if (hbmDst) GreDeleteObject(hbmDst);
225       if (hdcBuffer) IntGdiDeleteDC(hdcBuffer, FALSE);
226       if (!info->hdcDst) UserReleaseDC(pWnd, hdc, FALSE);
227    }
228    else
229       ret = TRUE;
230 
231    co_WinPosSetWindowPos(pWnd, 0, Window.left, Window.top, Window.right - Window.left, Window.bottom - Window.top, flags);
232    return ret;
233 }
234 
235 
236 /*
237  * @implemented
238  */
239 BOOL
240 APIENTRY
NtUserGetLayeredWindowAttributes(HWND hwnd,COLORREF * pcrKey,BYTE * pbAlpha,DWORD * pdwFlags)241 NtUserGetLayeredWindowAttributes(
242     HWND hwnd,
243     COLORREF *pcrKey,
244     BYTE *pbAlpha,
245     DWORD *pdwFlags)
246 {
247    PLRD_PROP pLrdProp;
248    PWND pWnd;
249    BOOL Ret = FALSE;
250 
251    TRACE("Enter NtUserGetLayeredWindowAttributes\n");
252    UserEnterExclusive();
253 
254    if (!(pWnd = UserGetWindowObject(hwnd)) ||
255        !(pWnd->ExStyle & WS_EX_LAYERED) )
256    {
257       ERR("Not a Layered Window!\n");
258       goto Exit;
259    }
260 
261    pLrdProp = UserGetProp(pWnd, AtomLayer, TRUE);
262 
263    if (!pLrdProp)
264    {
265       TRACE("No Prop!\n");
266       goto Exit;
267    }
268 
269    if (pLrdProp->is_Layered == 0)
270    {
271       goto Exit;
272    }
273 
274    _SEH2_TRY
275    {
276       if (pcrKey)
277       {
278           ProbeForWrite(pcrKey, sizeof(*pcrKey), 1);
279           *pcrKey = pLrdProp->Key;
280       }
281       if (pbAlpha)
282       {
283           ProbeForWrite(pbAlpha, sizeof(*pbAlpha), 1);
284           *pbAlpha = pLrdProp->Alpha;
285       }
286       if (pdwFlags)
287       {
288           ProbeForWrite(pdwFlags, sizeof(*pdwFlags), 1);
289           *pdwFlags = pLrdProp->Flags;
290       }
291    }
292    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
293    {
294       SetLastNtError(_SEH2_GetExceptionCode());
295       _SEH2_YIELD(goto Exit);
296    }
297    _SEH2_END;
298 
299    Ret = TRUE;
300 
301 Exit:
302    TRACE("Leave NtUserGetLayeredWindowAttributes, ret=%i\n", Ret);
303    UserLeave();
304    return Ret;
305 }
306 
307 /*
308  * @implemented
309  */
310 BOOL APIENTRY
NtUserSetLayeredWindowAttributes(HWND hwnd,COLORREF crKey,BYTE bAlpha,DWORD dwFlags)311 NtUserSetLayeredWindowAttributes(HWND hwnd,
312 			   COLORREF crKey,
313 			   BYTE bAlpha,
314 			   DWORD dwFlags)
315 {
316    PWND pWnd;
317    BOOL Ret = FALSE;
318 
319    TRACE("Enter NtUserSetLayeredWindowAttributes\n");
320    UserEnterExclusive();
321 
322    if (!(pWnd = UserGetWindowObject(hwnd)) ||
323        !(pWnd->ExStyle & WS_EX_LAYERED) )
324    {
325       ERR("Not a Layered Window!\n");
326       goto Exit;
327    }
328 
329    Ret = IntSetLayeredWindowAttributes(pWnd, crKey, bAlpha, dwFlags);
330 Exit:
331    TRACE("Leave NtUserSetLayeredWindowAttributes, ret=%i\n", Ret);
332    UserLeave();
333    return Ret;
334 }
335 
336 /*
337  * @implemented
338  */
339 BOOL
340 APIENTRY
NtUserUpdateLayeredWindow(HWND hwnd,HDC hdcDst,POINT * pptDst,SIZE * psize,HDC hdcSrc,POINT * pptSrc,COLORREF crKey,BLENDFUNCTION * pblend,DWORD dwFlags,RECT * prcDirty)341 NtUserUpdateLayeredWindow(
342    HWND hwnd,
343    HDC hdcDst,
344    POINT *pptDst,
345    SIZE *psize,
346    HDC hdcSrc,
347    POINT *pptSrc,
348    COLORREF crKey,
349    BLENDFUNCTION *pblend,
350    DWORD dwFlags,
351    RECT *prcDirty)
352 {
353    UPDATELAYEREDWINDOWINFO info;
354    POINT Dst, Src;
355    SIZE Size;
356    RECT Dirty;
357    BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
358    PWND pWnd;
359    BOOL Ret = FALSE;
360 
361    TRACE("Enter NtUserUpdateLayeredWindow\n");
362    UserEnterExclusive();
363 
364    if (!(pWnd = UserGetWindowObject(hwnd)))
365    {
366       goto Exit;
367    }
368 
369    _SEH2_TRY
370    {
371       if (pptDst)
372       {
373          ProbeForRead(pptDst, sizeof(POINT), 1);
374          Dst = *pptDst;
375       }
376       if (pptSrc)
377       {
378          ProbeForRead(pptSrc, sizeof(POINT), 1);
379          Src = *pptSrc;
380       }
381       ProbeForRead(psize, sizeof(SIZE), 1);
382       Size = *psize;
383       if (pblend)
384       {
385          ProbeForRead(pblend, sizeof(BLENDFUNCTION), 1);
386          blend = *pblend;
387       }
388       if (prcDirty)
389       {
390          ProbeForRead(prcDirty, sizeof(RECT), 1);
391          Dirty = *prcDirty;
392       }
393    }
394    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
395    {
396       EngSetLastError( ERROR_INVALID_PARAMETER );
397       _SEH2_YIELD(goto Exit);
398    }
399    _SEH2_END;
400 
401    if ( GetLayeredStatus(pWnd) ||
402         dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
403        !(pWnd->ExStyle & WS_EX_LAYERED) )
404    {
405       ERR("Layered Window Invalid Parameters\n");
406       EngSetLastError( ERROR_INVALID_PARAMETER );
407       goto Exit;
408    }
409 
410    info.cbSize   = sizeof(info);
411    info.hdcDst   = hdcDst;
412    info.pptDst   = pptDst? &Dst : NULL;
413    info.psize    = &Size;
414    info.hdcSrc   = hdcSrc;
415    info.pptSrc   = pptSrc ? &Src : NULL;
416    info.crKey    = crKey;
417    info.pblend   = &blend;
418    info.dwFlags  = dwFlags;
419    info.prcDirty = prcDirty ? &Dirty : NULL;
420    Ret = IntUpdateLayeredWindowI( pWnd, &info );
421 Exit:
422    TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret);
423    UserLeave();
424    return Ret;
425 }
426 
427 /* EOF */
428