I reviewed the previous version of the UpdateLayeredWindow function's implementation and noticed that it did not handle the case where the source DC is a window DC separately. Instead, it applied locking uniformly.
``` BOOL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info, const RECT *window_rect ) { struct window_surface *surface; struct x11drv_win_data *data; BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 }; COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID; char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; BITMAPINFO *bmi = (BITMAPINFO *)buffer; void *src_bits, *dst_bits; RECT rect, src_rect; HDC hdc = 0; HBITMAP dib; BOOL mapped, ret = FALSE;
if (!(data = get_win_data( hwnd ))) return FALSE;
data->layered = TRUE; if (!data->embedded && argb_visual.visualid) set_window_visual( data, &argb_visual, TRUE );
rect = *window_rect; OffsetRect( &rect, -window_rect->left, -window_rect->top );
surface = data->surface; if (!surface || !EqualRect( &surface->rect, &rect )) { data->surface = create_surface( data->whole_window, &data->vis, &rect, color_key, data->use_alpha ); if (surface) window_surface_release( surface ); surface = data->surface;
surface->is_trayicon = is_trayicon(hwnd); } else set_surface_color_key( surface, color_key );
if (surface) window_surface_add_ref( surface ); mapped = data->mapped; release_win_data( data );
/* layered windows are mapped only once their attributes are set */ if (!mapped) { DWORD style = NtUserGetWindowLongW( hwnd, GWL_STYLE );
if ((style & WS_VISIBLE) && ((style & WS_MINIMIZE) || is_window_rect_mapped( window_rect ))) map_window( hwnd, style, 0 ); }
if (!surface) return FALSE; if (!info->hdcSrc) { window_surface_release( surface ); return TRUE; }
dst_bits = surface->funcs->get_info( surface, bmi );
if (!(dib = NtGdiCreateDIBSection( info->hdcDst, NULL, 0, bmi, DIB_RGB_COLORS, 0, 0, 0, &src_bits ))) goto done; if (!(hdc = NtGdiCreateCompatibleDC( 0 ))) goto done;
NtGdiSelectBitmap( hdc, dib );
surface->funcs->lock( surface );
if (info->prcDirty) { intersect_rect( &rect, &rect, info->prcDirty ); memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage ); NtGdiPatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS ); } src_rect = rect; if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y ); NtGdiTransformPoints( info->hdcSrc, (POINT *)&src_rect, (POINT *)&src_rect, 2, NtGdiDPtoLP );
if (info->dwFlags & ULW_ALPHA) blend = *info->pblend; ret = NtGdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, info->hdcSrc, src_rect.left, src_rect.top, src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, *(DWORD *)&blend, 0 ); if (ret) { memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage ); add_bounds_rect( surface->funcs->get_bounds( surface ), &rect ); }
surface->funcs->unlock( surface ); surface->funcs->flush( surface );
done: window_surface_release( surface ); if (hdc) NtGdiDeleteObjectApp( hdc ); if (dib) NtGdiDeleteObjectApp( dib ); return ret; } ```