[WIN32K:NTUSER]
[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 HBRUSH hBr;
154 HDC hdc;
155 RECT Rect;
156 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
157 COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID;
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 hBr = NtGdiCreateSolidBrush(color_key, NULL);
169 if (hBr)
170 {
171 TRACE("Fill Color Key %x\n",color_key);
172 FillRect(hdc, &Rect, hBr);
173 }
174
175 if (info->prcDirty)
176 {
177 ERR("prcDirty\n");
178 RECTL_bIntersectRect( &Rect, &Rect, info->prcDirty );
179 NtGdiPatBlt( hdc, Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, BLACKNESS );
180 }
181
182 if (info->dwFlags & ULW_ALPHA)
183 {
184 blend = *info->pblend;
185 TRACE("ULW_ALPHA bop %d scA %d aF %d\n", blend.BlendOp, blend.SourceConstantAlpha, blend.AlphaFormat);
186 }
187
188 ret = NtGdiAlphaBlend( hdc,
189 Rect.left,
190 Rect.top,
191 Rect.right - Rect.left,
192 Rect.bottom - Rect.top,
193 info->hdcSrc,
194 Rect.left + (info->pptSrc ? info->pptSrc->x : 0),
195 Rect.top + (info->pptSrc ? info->pptSrc->y : 0),
196 Rect.right - Rect.left, Rect.bottom - Rect.top,
197 blend,
198 0);
199
200 if (hBr) GreDeleteObject(hBr);
201 if (!info->hdcDst) UserReleaseDC(pWnd, hdc, FALSE);
202 }
203 else
204 ret = TRUE;
205
206 co_WinPosSetWindowPos(pWnd, 0, Window.left, Window.top, Window.right - Window.left, Window.bottom - Window.top, flags);
207 return ret;
208 }
209
210
211 /*
212 * @implemented
213 */
214 BOOL
215 APIENTRY
216 NtUserGetLayeredWindowAttributes(
217 HWND hwnd,
218 COLORREF *pcrKey,
219 BYTE *pbAlpha,
220 DWORD *pdwFlags)
221 {
222 PLRD_PROP pLrdProp;
223 PWND pWnd;
224 BOOL Ret = FALSE;
225
226 TRACE("Enter NtUserGetLayeredWindowAttributes\n");
227 UserEnterExclusive();
228
229 if (!(pWnd = UserGetWindowObject(hwnd)) ||
230 !(pWnd->ExStyle & WS_EX_LAYERED) )
231 {
232 ERR("Not a Layered Window!\n");
233 goto Exit;
234 }
235
236 pLrdProp = UserGetProp(pWnd, AtomLayer);
237
238 if (!pLrdProp)
239 {
240 TRACE("No Prop!\n");
241 goto Exit;
242 }
243
244 if (pLrdProp->is_Layered == 0)
245 {
246 goto Exit;
247 }
248
249 _SEH2_TRY
250 {
251 if (pcrKey)
252 {
253 ProbeForWrite(pcrKey, sizeof(*pcrKey), 1);
254 *pcrKey = pLrdProp->Key;
255 }
256 if (pbAlpha)
257 {
258 ProbeForWrite(pbAlpha, sizeof(*pbAlpha), 1);
259 *pbAlpha = pLrdProp->Alpha;
260 }
261 if (pdwFlags)
262 {
263 ProbeForWrite(pdwFlags, sizeof(*pdwFlags), 1);
264 *pdwFlags = pLrdProp->Flags;
265 }
266 }
267 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
268 {
269 SetLastNtError(_SEH2_GetExceptionCode());
270 _SEH2_YIELD(goto Exit);
271 }
272 _SEH2_END;
273
274 Ret = TRUE;
275
276 Exit:
277 TRACE("Leave NtUserGetLayeredWindowAttributes, ret=%i\n", Ret);
278 UserLeave();
279 return Ret;
280 }
281
282 /*
283 * @implemented
284 */
285 BOOL APIENTRY
286 NtUserSetLayeredWindowAttributes(HWND hwnd,
287 COLORREF crKey,
288 BYTE bAlpha,
289 DWORD dwFlags)
290 {
291 PWND pWnd;
292 BOOL Ret = FALSE;
293
294 TRACE("Enter NtUserSetLayeredWindowAttributes\n");
295 UserEnterExclusive();
296
297 if (!(pWnd = UserGetWindowObject(hwnd)) ||
298 !(pWnd->ExStyle & WS_EX_LAYERED) )
299 {
300 ERR("Not a Layered Window!\n");
301 goto Exit;
302 }
303
304 Ret = IntSetLayeredWindowAttributes(pWnd, crKey, bAlpha, dwFlags);
305 Exit:
306 TRACE("Leave NtUserSetLayeredWindowAttributes, ret=%i\n", Ret);
307 UserLeave();
308 return Ret;
309 }
310
311 /*
312 * @implemented
313 */
314 BOOL
315 APIENTRY
316 NtUserUpdateLayeredWindow(
317 HWND hwnd,
318 HDC hdcDst,
319 POINT *pptDst,
320 SIZE *psize,
321 HDC hdcSrc,
322 POINT *pptSrc,
323 COLORREF crKey,
324 BLENDFUNCTION *pblend,
325 DWORD dwFlags,
326 RECT *prcDirty)
327 {
328 UPDATELAYEREDWINDOWINFO info;
329 POINT Dst, Src;
330 SIZE Size;
331 RECT Dirty;
332 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
333 PWND pWnd;
334 BOOL Ret = FALSE;
335
336 TRACE("Enter NtUserUpdateLayeredWindow\n");
337 UserEnterExclusive();
338
339 if (!(pWnd = UserGetWindowObject(hwnd)))
340 {
341 goto Exit;
342 }
343
344 _SEH2_TRY
345 {
346 if (pptDst)
347 {
348 ProbeForRead(pptDst, sizeof(POINT), 1);
349 Dst = *pptDst;
350 }
351 if (pptSrc)
352 {
353 ProbeForRead(pptSrc, sizeof(POINT), 1);
354 Src = *pptSrc;
355 }
356 ProbeForRead(psize, sizeof(SIZE), 1);
357 Size = *psize;
358 if (pblend)
359 {
360 ProbeForRead(pblend, sizeof(BLENDFUNCTION), 1);
361 blend = *pblend;
362 }
363 if (prcDirty)
364 {
365 ProbeForRead(prcDirty, sizeof(RECT), 1);
366 Dirty = *prcDirty;
367 }
368 }
369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
370 {
371 EngSetLastError( ERROR_INVALID_PARAMETER );
372 _SEH2_YIELD(goto Exit);
373 }
374 _SEH2_END;
375
376 if ( GetLayeredStatus(pWnd) ||
377 dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
378 !(pWnd->ExStyle & WS_EX_LAYERED) )
379 {
380 ERR("Layered Window Invalid Parameters\n");
381 EngSetLastError( ERROR_INVALID_PARAMETER );
382 goto Exit;
383 }
384
385 info.cbSize = sizeof(info);
386 info.hdcDst = hdcDst;
387 info.pptDst = pptDst? &Dst : NULL;
388 info.psize = &Size;
389 info.hdcSrc = hdcSrc;
390 info.pptSrc = pptSrc ? &Src : NULL;
391 info.crKey = crKey;
392 info.pblend = &blend;
393 info.dwFlags = dwFlags;
394 info.prcDirty = prcDirty ? &Dirty : NULL;
395 Ret = IntUpdateLayeredWindowI( pWnd, &info );
396 Exit:
397 TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret);
398 UserLeave();
399 return Ret;
400 }
401
402 /* EOF */