[USERSRV] Hard-error improvements 3/7
[reactos.git] / 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, TRUE);
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, TRUE);
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, 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
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
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
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
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 */