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; } ``` -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9180#note_119028