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 */ 428