[Win32k]
[reactos.git] / reactos / win32ss / user / ntuser / layered.c
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
23 GetLayeredStatus(PWND pWnd)
24 {
25 PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer);
26 if (pLrdProp)
27 {
28 return pLrdProp->is_Layered;
29 }
30 return FALSE;
31 }
32
33 BOOL FASTCALL
34 SetLayeredStatus(PWND pWnd, BYTE set)
35 {
36 PLRD_PROP pLrdProp = UserGetProp(pWnd, AtomLayer);
37 if (pLrdProp)
38 {
39 pLrdProp->is_Layered = set;
40 return TRUE;
41 }
42 return FALSE;
43 }
44
45 BOOL FASTCALL
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);
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 IntSetProp(pWnd, AtomLayer, (HANDLE)pLrdProp);
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
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 hBitmapBuffer, hOldBitmap;
158
159 Rect = Window;
160
161 RECTL_vOffsetRect( &Rect, -Window.left, -Window.top );
162
163 TRACE("H %d W %d\n",Rect.bottom - Rect.top,Rect.right - Rect.left);
164
165 if (!info->hdcDst) hdc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
166 else hdc = info->hdcDst;
167
168 hdcBuffer = NtGdiCreateCompatibleDC(hdc);
169 hBitmapBuffer = NtGdiCreateCompatibleBitmap(hdc, Rect.right - Rect.left, Rect.bottom - Rect.top);
170 hOldBitmap = (HBITMAP)NtGdiSelectBitmap(hdcBuffer, hBitmapBuffer);
171
172 NtGdiStretchBlt( hdcBuffer,
173 Rect.left,
174 Rect.top,
175 Rect.right - Rect.left,
176 Rect.bottom - Rect.top,
177 info->hdcSrc,
178 Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
179 Rect.top + (info->pptSrc ? info->pptSrc->y : 0),
180 Rect.right - Rect.left,
181 Rect.bottom - Rect.top,
182 SRCCOPY,
183 color_key );
184
185 // Need to test this, Dirty before or after StretchBlt?
186 if (info->prcDirty)
187 {
188 ERR("prcDirty\n");
189 RECTL_bIntersectRect( &Rect, &Rect, info->prcDirty );
190 NtGdiPatBlt( hdc, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, BLACKNESS );
191 }
192
193 if (info->dwFlags & ULW_ALPHA)
194 {
195 blend = *info->pblend;
196 TRACE("ULW_ALPHA bop %d Alpha %d aF %d\n", blend.BlendOp, blend.SourceConstantAlpha, blend.AlphaFormat);
197 }
198
199 ret = NtGdiAlphaBlend( hdc,
200 Rect.left,
201 Rect.top,
202 Rect.right - Rect.left,
203 Rect.bottom - Rect.top,
204 hdcBuffer,
205 Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
206 Rect.top + (info->pptSrc ? info->pptSrc->y : 0),
207 Rect.right - Rect.left,
208 Rect.bottom - Rect.top,
209 blend,
210 0);
211
212 NtGdiSelectBitmap(hdcBuffer, hOldBitmap);
213 if (hBitmapBuffer) GreDeleteObject(hBitmapBuffer);
214 if (hdcBuffer) IntGdiDeleteDC(hdcBuffer, FALSE);
215 if (!info->hdcDst) UserReleaseDC(pWnd, hdc, FALSE);
216 }
217 else
218 ret = TRUE;
219
220 co_WinPosSetWindowPos(pWnd, 0, Window.left, Window.top, Window.right - Window.left, Window.bottom - Window.top, flags);
221 return ret;
222 }
223
224
225 /*
226 * @implemented
227 */
228 BOOL
229 APIENTRY
230 NtUserGetLayeredWindowAttributes(
231 HWND hwnd,
232 COLORREF *pcrKey,
233 BYTE *pbAlpha,
234 DWORD *pdwFlags)
235 {
236 PLRD_PROP pLrdProp;
237 PWND pWnd;
238 BOOL Ret = FALSE;
239
240 TRACE("Enter NtUserGetLayeredWindowAttributes\n");
241 UserEnterExclusive();
242
243 if (!(pWnd = UserGetWindowObject(hwnd)) ||
244 !(pWnd->ExStyle & WS_EX_LAYERED) )
245 {
246 ERR("Not a Layered Window!\n");
247 goto Exit;
248 }
249
250 pLrdProp = UserGetProp(pWnd, AtomLayer);
251
252 if (!pLrdProp)
253 {
254 TRACE("No Prop!\n");
255 goto Exit;
256 }
257
258 if (pLrdProp->is_Layered == 0)
259 {
260 goto Exit;
261 }
262
263 _SEH2_TRY
264 {
265 if (pcrKey)
266 {
267 ProbeForWrite(pcrKey, sizeof(*pcrKey), 1);
268 *pcrKey = pLrdProp->Key;
269 }
270 if (pbAlpha)
271 {
272 ProbeForWrite(pbAlpha, sizeof(*pbAlpha), 1);
273 *pbAlpha = pLrdProp->Alpha;
274 }
275 if (pdwFlags)
276 {
277 ProbeForWrite(pdwFlags, sizeof(*pdwFlags), 1);
278 *pdwFlags = pLrdProp->Flags;
279 }
280 }
281 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
282 {
283 SetLastNtError(_SEH2_GetExceptionCode());
284 _SEH2_YIELD(goto Exit);
285 }
286 _SEH2_END;
287
288 Ret = TRUE;
289
290 Exit:
291 TRACE("Leave NtUserGetLayeredWindowAttributes, ret=%i\n", Ret);
292 UserLeave();
293 return Ret;
294 }
295
296 /*
297 * @implemented
298 */
299 BOOL APIENTRY
300 NtUserSetLayeredWindowAttributes(HWND hwnd,
301 COLORREF crKey,
302 BYTE bAlpha,
303 DWORD dwFlags)
304 {
305 PWND pWnd;
306 BOOL Ret = FALSE;
307
308 TRACE("Enter NtUserSetLayeredWindowAttributes\n");
309 UserEnterExclusive();
310
311 if (!(pWnd = UserGetWindowObject(hwnd)) ||
312 !(pWnd->ExStyle & WS_EX_LAYERED) )
313 {
314 ERR("Not a Layered Window!\n");
315 goto Exit;
316 }
317
318 Ret = IntSetLayeredWindowAttributes(pWnd, crKey, bAlpha, dwFlags);
319 Exit:
320 TRACE("Leave NtUserSetLayeredWindowAttributes, ret=%i\n", Ret);
321 UserLeave();
322 return Ret;
323 }
324
325 /*
326 * @implemented
327 */
328 BOOL
329 APIENTRY
330 NtUserUpdateLayeredWindow(
331 HWND hwnd,
332 HDC hdcDst,
333 POINT *pptDst,
334 SIZE *psize,
335 HDC hdcSrc,
336 POINT *pptSrc,
337 COLORREF crKey,
338 BLENDFUNCTION *pblend,
339 DWORD dwFlags,
340 RECT *prcDirty)
341 {
342 UPDATELAYEREDWINDOWINFO info;
343 POINT Dst, Src;
344 SIZE Size;
345 RECT Dirty;
346 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
347 PWND pWnd;
348 BOOL Ret = FALSE;
349
350 TRACE("Enter NtUserUpdateLayeredWindow\n");
351 UserEnterExclusive();
352
353 if (!(pWnd = UserGetWindowObject(hwnd)))
354 {
355 goto Exit;
356 }
357
358 _SEH2_TRY
359 {
360 if (pptDst)
361 {
362 ProbeForRead(pptDst, sizeof(POINT), 1);
363 Dst = *pptDst;
364 }
365 if (pptSrc)
366 {
367 ProbeForRead(pptSrc, sizeof(POINT), 1);
368 Src = *pptSrc;
369 }
370 ProbeForRead(psize, sizeof(SIZE), 1);
371 Size = *psize;
372 if (pblend)
373 {
374 ProbeForRead(pblend, sizeof(BLENDFUNCTION), 1);
375 blend = *pblend;
376 }
377 if (prcDirty)
378 {
379 ProbeForRead(prcDirty, sizeof(RECT), 1);
380 Dirty = *prcDirty;
381 }
382 }
383 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
384 {
385 EngSetLastError( ERROR_INVALID_PARAMETER );
386 _SEH2_YIELD(goto Exit);
387 }
388 _SEH2_END;
389
390 if ( GetLayeredStatus(pWnd) ||
391 dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
392 !(pWnd->ExStyle & WS_EX_LAYERED) )
393 {
394 ERR("Layered Window Invalid Parameters\n");
395 EngSetLastError( ERROR_INVALID_PARAMETER );
396 goto Exit;
397 }
398
399 info.cbSize = sizeof(info);
400 info.hdcDst = hdcDst;
401 info.pptDst = pptDst? &Dst : NULL;
402 info.psize = &Size;
403 info.hdcSrc = hdcSrc;
404 info.pptSrc = pptSrc ? &Src : NULL;
405 info.crKey = crKey;
406 info.pblend = &blend;
407 info.dwFlags = dwFlags;
408 info.prcDirty = prcDirty ? &Dirty : NULL;
409 Ret = IntUpdateLayeredWindowI( pWnd, &info );
410 Exit:
411 TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret);
412 UserLeave();
413 return Ret;
414 }
415
416 /* EOF */