[Win32SS]
[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
228 if (!(pWnd = UserGetWindowObject(hwnd)) ||
229 !(pWnd->ExStyle & WS_EX_LAYERED) )
230 {
231 return FALSE;
232 }
233
234 UserEnterExclusive();
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) *pcrKey = pLrdProp->Key;
252 if (pbAlpha) *pbAlpha = pLrdProp->Alpha;
253 if (pdwFlags) *pdwFlags = pLrdProp->Flags;
254 }
255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
256 {
257 SetLastNtError(_SEH2_GetExceptionCode());
258 _SEH2_YIELD(goto Exit);
259 }
260 _SEH2_END;
261
262 Ret = TRUE;
263
264 Exit:
265 TRACE("Leave NtUserGetLayeredWindowAttributes, ret=%i\n", Ret);
266 UserLeave();
267 return Ret;
268 }
269
270 /*
271 * @implemented
272 */
273 BOOL APIENTRY
274 NtUserSetLayeredWindowAttributes(HWND hwnd,
275 COLORREF crKey,
276 BYTE bAlpha,
277 DWORD dwFlags)
278 {
279 PWND pWnd;
280 BOOL Ret = FALSE;
281
282 TRACE("Enter NtUserSetLayeredWindowAttributes\n");
283 UserEnterExclusive();
284
285 if (!(pWnd = UserGetWindowObject(hwnd)) ||
286 !(pWnd->ExStyle & WS_EX_LAYERED) )
287 {
288 ERR("Not a Layered Window!\n");
289 goto Exit;
290 }
291
292 Ret = IntSetLayeredWindowAttributes(pWnd, crKey, bAlpha, dwFlags);
293 Exit:
294 TRACE("Leave NtUserSetLayeredWindowAttributes, ret=%i\n", Ret);
295 UserLeave();
296 return Ret;
297 }
298
299 /*
300 * @implemented
301 */
302 BOOL
303 APIENTRY
304 NtUserUpdateLayeredWindow(
305 HWND hwnd,
306 HDC hdcDst,
307 POINT *pptDst,
308 SIZE *psize,
309 HDC hdcSrc,
310 POINT *pptSrc,
311 COLORREF crKey,
312 BLENDFUNCTION *pblend,
313 DWORD dwFlags,
314 RECT *prcDirty)
315 {
316 UPDATELAYEREDWINDOWINFO info;
317 POINT Dst, Src;
318 SIZE Size;
319 RECT Dirty;
320 BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 };
321 PWND pWnd;
322 BOOL Ret = FALSE;
323
324 TRACE("Enter NtUserUpdateLayeredWindow\n");
325
326 if (!(pWnd = UserGetWindowObject(hwnd)))
327 {
328 return FALSE;
329 }
330
331 _SEH2_TRY
332 {
333 if (pptDst)
334 {
335 ProbeForRead(pptDst, sizeof(POINT), 1);
336 Dst = *pptDst;
337 }
338 if (pptSrc)
339 {
340 ProbeForRead(pptSrc, sizeof(POINT), 1);
341 Src = *pptSrc;
342 }
343 ProbeForRead(psize, sizeof(SIZE), 1);
344 Size = *psize;
345 if (pblend)
346 {
347 ProbeForRead(pblend, sizeof(BLENDFUNCTION), 1);
348 blend = *pblend;
349 }
350 if (prcDirty)
351 {
352 ProbeForRead(prcDirty, sizeof(RECT), 1);
353 Dirty = *prcDirty;
354 }
355 }
356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
357 {
358 EngSetLastError( ERROR_INVALID_PARAMETER );
359 _SEH2_YIELD(return FALSE);
360 }
361 _SEH2_END;
362
363 UserEnterExclusive();
364
365 if ( GetLayeredStatus(pWnd) ||
366 dwFlags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) ||
367 !(pWnd->ExStyle & WS_EX_LAYERED) )
368 {
369 ERR("Layered Window Invalid Parameters\n");
370 EngSetLastError( ERROR_INVALID_PARAMETER );
371 goto Exit;
372 }
373
374 info.cbSize = sizeof(info);
375 info.hdcDst = hdcDst;
376 info.pptDst = pptDst? &Dst : 0;
377 info.psize = &Size;
378 info.hdcSrc = hdcSrc;
379 info.pptSrc = pptSrc ? &Src : 0;
380 info.crKey = crKey;
381 info.pblend = &blend;
382 info.dwFlags = dwFlags;
383 info.prcDirty = prcDirty ? &Dirty : 0;
384 Ret = IntUpdateLayeredWindowI( pWnd, &info );
385 Exit:
386 TRACE("Leave NtUserUpdateLayeredWindow, ret=%i\n", Ret);
387 UserLeave();
388 return Ret;
389 }
390
391 /* EOF */