From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/user32/tests/win.c | 377 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 374 insertions(+), 3 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 097aab64eaf..6fd780a53f5 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -61,6 +61,7 @@ static BOOL (WINAPI *pSetWindowDisplayAffinity)(HWND hwnd, DWORD affinity); static BOOL (WINAPI *pAdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT); static BOOL (WINAPI *pSystemParametersInfoForDpi)(UINT,UINT,void*,UINT,UINT); static HICON (WINAPI *pInternalGetWindowIcon)(HWND window, UINT type); +static DPI_AWARENESS_CONTEXT (WINAPI *pSetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);
static BOOL test_lbuttondown_flag; static DWORD num_gettext_msgs; @@ -8881,17 +8882,63 @@ static void test_hwnd_message(void) DestroyWindow(hwnd); }
+static BOOL handle_wm_paint; + +static LRESULT WINAPI test_layered_window_proc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) +{ + switch (msg) + { + case WM_PAINT: + { + int width, height; + PAINTSTRUCT ps; + HBRUSH brush; + RECT rect; + HDC hdc; + + if (!handle_wm_paint) + break; + + hdc = wp ? (HDC)wp : BeginPaint( hwnd, &ps ); + GetClientRect( hwnd, &rect ); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + SetRect( &rect, 0, 0, width, height / 2 ); + brush = CreateSolidBrush( RGB(0xff, 0, 0) ); + FillRect( hdc, &rect, brush ); + DeleteObject( brush ); + + SetRect( &rect, 0, height / 2, width, height ); + FillRect( hdc, &rect, GetStockObject( WHITE_BRUSH ) ); + + if (!wp) + EndPaint( hwnd, &ps ); + return 0; + } + } + + return DefWindowProcA( hwnd, msg, wp, lp ); +} + static void test_layered_window(void) { - HWND hwnd, child; + static const int width = 4, height = 4; + HWND hwnd, child, bg_hwnd, layered_hwnd; + DPI_AWARENESS_CONTEXT context = NULL; + HDC hdc, mem_hdc, screen_hdc; + HBITMAP hbm, old_hbm; + BLENDFUNCTION blend; COLORREF key = 0; + BITMAPINFO bmi; BYTE alpha = 0; + WNDCLASSA cls; DWORD flags = 0; POINT pt = { 0, 0 }; SIZE sz = { 200, 200 }; - HDC hdc; - HBITMAP hbm; + unsigned char *bits; BOOL ret; + int x, y; MSG msg;
if (!pGetLayeredWindowAttributes || !pSetLayeredWindowAttributes || !pUpdateLayeredWindow) @@ -9069,6 +9116,329 @@ static void test_layered_window(void) DestroyWindow( hwnd ); DeleteDC( hdc ); DeleteObject( hbm ); + + /* Test hit-testing layered windows */ + if (pSetThreadDpiAwarenessContext) + context = pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ); + + memset( &cls, 0, sizeof(cls) ); + cls.lpfnWndProc = DefWindowProcA; + cls.hInstance = GetModuleHandleA( 0 ); + cls.hCursor = LoadCursorA( 0, (LPCSTR)IDC_ARROW ); + cls.hbrBackground = GetStockObject( GRAY_BRUSH ); + cls.lpszClassName = "background_class"; + RegisterClassA( &cls ); + + cls.lpfnWndProc = test_layered_window_proc; + cls.lpszClassName = "test_layered_window_class"; + RegisterClassA( &cls ); + + bg_hwnd = CreateWindowA( "background_class", "background", WS_POPUP | WS_VISIBLE, 50, + 50, width * 2, height * 2, 0, 0, GetModuleHandleA( NULL ), NULL ); + ok( !!bg_hwnd, "CreateWindowA failed, error %lu.\n", GetLastError() ); + + layered_hwnd = CreateWindowExA( WS_EX_LAYERED | WS_EX_TOPMOST, "test_layered_window_class", + "test", WS_POPUP | WS_VISIBLE, 50, 50, width, height, 0, 0, + GetModuleHandleA( NULL ), NULL ); + ok( !!layered_hwnd, "CreateWindowExA failed, error %lu.\n", GetLastError() ); + flush_events( TRUE ); + + /* Hit-testing after layered window creation */ + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + ok( hwnd == layered_hwnd || broken( hwnd == bg_hwnd ) /* <= Win7 */, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing after UpdateLayeredWindow() */ + screen_hdc = GetDC( 0 ); + hdc = GetDC( layered_hwnd ); + mem_hdc = CreateCompatibleDC( hdc ); + + memset( &bmi, 0, sizeof(bmi) ); + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = width * height * 4; + hbm = CreateDIBSection( hdc, &bmi, DIB_RGB_COLORS, (void **)&bits, 0, 0 ); + ok( !!hbm, "CreateDIBSection failed, error %lu.\n", GetLastError() ); + old_hbm = SelectObject( mem_hdc, hbm ); + memset( bits, 0, bmi.bmiHeader.biSizeImage / 2 ); + memset( bits + bmi.bmiHeader.biSizeImage / 2, 0x1, bmi.bmiHeader.biSizeImage / 2 ); + + /* UpdateLayeredWindow() with per-pixel alpha */ + pt.x = 0; + pt.y = 0; + sz.cx = width; + sz.cy = height; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 255; + blend.AlphaFormat = AC_SRC_ALPHA; + ret = pUpdateLayeredWindow( layered_hwnd, screen_hdc, NULL, &sz, mem_hdc, &pt, 0, &blend, ULW_ALPHA ); + ok( ret, "UpdateLayeredWindow failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + if (y < height / 2) + todo_wine + ok( hwnd == bg_hwnd, "Wrong window.\n" ); + else + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing after resizing to a larger size */ + ret = SetWindowPos( layered_hwnd, NULL, 0, 0, width * 2, height * 2, SWP_NOZORDER | SWP_NOMOVE ); + ok( ret, "SetWindowPos failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height * 2; ++y) + { + for (x = 0; x < width * 2; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + if (y >= height / 2 && x < width && y < height) + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + else + todo_wine + ok( hwnd == bg_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing after resizing to the original size */ + ret = SetWindowPos( layered_hwnd, NULL, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE ); + ok( ret, "SetWindowPos failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + if (y < height / 2) + todo_wine + ok( hwnd == bg_hwnd, "Wrong window.\n" ); + else + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing layered windows called with UpdateLayeredWindow() and set ULW_OPAQUE */ + pt.x = 0; + pt.y = 0; + ret = pUpdateLayeredWindow( layered_hwnd, screen_hdc, NULL, &sz, mem_hdc, &pt, 0, NULL, + ULW_OPAQUE ); + ok( ret, "UpdateLayeredWindow failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing layered windows called with UpdateLayeredWindow() and set the color key */ + pt.x = 0; + pt.y = 0; + ret = pUpdateLayeredWindow( layered_hwnd, screen_hdc, NULL, &sz, mem_hdc, &pt, 0x010101, NULL, + ULW_COLORKEY ); + ok( ret, "UpdateLayeredWindow failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + if (y >= height / 2) + todo_wine + ok( hwnd == bg_hwnd || broken(hwnd == layered_hwnd) /* <= Win 7*/ , + "Wrong window.\n" ); + else + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing layered windows called with UpdateLayeredWindow() and use whole window alpha */ + pt.x = 0; + pt.y = 0; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 0; + blend.AlphaFormat = 0; + ret = pUpdateLayeredWindow( layered_hwnd, screen_hdc, NULL, &sz, mem_hdc, &pt, 0, &blend, + ULW_ALPHA ); + ok( ret, "UpdateLayeredWindow failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + todo_wine + ok( hwnd == bg_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + pt.x = 0; + pt.y = 0; + blend.BlendOp = AC_SRC_OVER; + blend.BlendFlags = 0; + blend.SourceConstantAlpha = 1; + blend.AlphaFormat = 0; + ret = pUpdateLayeredWindow( layered_hwnd, screen_hdc, NULL, &sz, mem_hdc, &pt, 0, &blend, + ULW_ALPHA ); + ok( ret, "UpdateLayeredWindow failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + SelectObject( mem_hdc, old_hbm ); + DeleteObject( hbm ); + DeleteDC( mem_hdc ); + ReleaseDC( layered_hwnd, hdc ); + ReleaseDC( 0, screen_hdc ); + DestroyWindow( layered_hwnd ); + + /* Hit-testing layered windows called with SetLayeredWindowAttributes() and set color key */ + handle_wm_paint = TRUE; + layered_hwnd = CreateWindowExA( WS_EX_LAYERED | WS_EX_TOPMOST, "test_layered_window_class", + "test", WS_POPUP | WS_VISIBLE, 50, 50, width, height, 0, 0, + GetModuleHandleA( NULL ), NULL ); + ok( !!layered_hwnd, "CreateWindowExA failed, error %lu.\n", GetLastError() ); + flush_events( TRUE ); + ret = pSetLayeredWindowAttributes( layered_hwnd, RGB(0xff, 0, 0), 0, LWA_COLORKEY ); + ok( ret, "SetLayeredWindowAttributes failed, error %lu.\n", GetLastError() ); + RedrawWindow( layered_hwnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + if (y < height / 2) + todo_wine + /* On >= Win 8, color keyed pixels can't be clicked through */ + ok( hwnd == bg_hwnd || broken(hwnd == layered_hwnd) , "Wrong window.\n" ); + else + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + /* Hit-testing layered windows called with SetLayeredWindowAttributes() and use whole window alpha */ + ret = pSetLayeredWindowAttributes( layered_hwnd, 0, 0, LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + todo_wine + ok( hwnd == bg_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + + ret = pSetLayeredWindowAttributes( layered_hwnd, 0, 1, LWA_ALPHA ); + ok( ret, "SetLayeredWindowAttributes failed, error %lu.\n", GetLastError() ); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x) + { + winetest_push_context( "%d,%d", x, y ); + + pt.x = 50 + x; + pt.y = 50 + y; + hwnd = WindowFromPoint( pt ); + ok( hwnd == layered_hwnd, "Wrong window.\n" ); + + winetest_pop_context(); + } + } + handle_wm_paint = FALSE; + + DestroyWindow( layered_hwnd ); + DestroyWindow( bg_hwnd ); + UnregisterClassA( "background_class", GetModuleHandleA( NULL ) ); + UnregisterClassA( "test_layered_window_class", GetModuleHandleA( NULL ) ); + if (pSetThreadDpiAwarenessContext) + pSetThreadDpiAwarenessContext( context ); }
static MONITORINFO mi; @@ -13056,6 +13426,7 @@ START_TEST(win) pAdjustWindowRectExForDpi = (void *)GetProcAddress( user32, "AdjustWindowRectExForDpi" ); pSystemParametersInfoForDpi = (void *)GetProcAddress( user32, "SystemParametersInfoForDpi" ); pInternalGetWindowIcon = (void *)GetProcAddress( user32, "InternalGetWindowIcon" ); + pSetThreadDpiAwarenessContext = (void *)GetProcAddress( user32, "SetThreadDpiAwarenessContext" );
if (argc == 4) {
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/win32u/window.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index d6fabff2cf1..349af7289e3 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2095,9 +2095,13 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ const BLENDFUNCTION *blend, DWORD flags, const RECT *dirty ) { DWORD swp_flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW; + HBITMAP hbmp = NULL, hbmp_old = NULL; RECT window_rect, client_rect; UPDATELAYEREDWINDOWINFO info; + HDC mem_dc = NULL; + BITMAPINFO bmi; SIZE offset; + BOOL ret;
if (flags & ~(ULW_COLORKEY | ULW_ALPHA | ULW_OPAQUE | ULW_EX_NORESIZE) || !(get_window_long( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) || @@ -2153,7 +2157,35 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ info.pblend = blend; info.dwFlags = flags; info.prcDirty = dirty; - return user_driver->pUpdateLayeredWindow( hwnd, &info, &window_rect ); + + /* Do not use source alpha channel if ULW_OPAQUE is set or ULW_ALPHA is set but no AC_SRC_ALPHA */ + if ((flags & ULW_OPAQUE || (flags & ULW_ALPHA && !(blend->AlphaFormat & AC_SRC_ALPHA))) + && NtGdiGetDeviceCaps( hdc_src, BITSPIXEL ) == 32) + { + mem_dc = NtGdiCreateCompatibleDC( 0 ); + info.hdcSrc = mem_dc; + + memset( &bmi, 0, sizeof(bmi) ); + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = NtGdiGetDeviceCaps( hdc_src, HORZRES ); + bmi.bmiHeader.biHeight = NtGdiGetDeviceCaps( hdc_src, VERTRES ); + bmi.bmiHeader.biBitCount = 24; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + hbmp = NtGdiCreateDIBSection( mem_dc, NULL, 0, &bmi, DIB_RGB_COLORS, 0, 0, 0, NULL ); + hbmp_old = NtGdiSelectBitmap( mem_dc, hbmp ); + NtGdiBitBlt( mem_dc, 0, 0, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight, hdc_src, 0, 0, + SRCCOPY, 0, 0 ); + } + + ret = user_driver->pUpdateLayeredWindow( hwnd, &info, &window_rect ); + if (info.hdcSrc != hdc_src) + { + NtGdiSelectBitmap( mem_dc, hbmp_old ); + NtGdiDeleteObjectApp( hbmp ); + NtGdiDeleteObjectApp( mem_dc ); + } + return ret; }
/***********************************************************************
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/user32/tests/win.c | 7 --- dlls/winex11.drv/bitblt.c | 92 +++++++++++++++++++++++++++++++++++++-- dlls/winex11.drv/window.c | 10 ++++- dlls/winex11.drv/x11drv.h | 5 ++- server/protocol.def | 5 +++ server/window.c | 34 +++++++++++++++ 6 files changed, 138 insertions(+), 15 deletions(-)
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c index 6fd780a53f5..5fe95527ed7 100644 --- a/dlls/user32/tests/win.c +++ b/dlls/user32/tests/win.c @@ -9200,7 +9200,6 @@ static void test_layered_window(void) pt.y = 50 + y; hwnd = WindowFromPoint( pt ); if (y < height / 2) - todo_wine ok( hwnd == bg_hwnd, "Wrong window.\n" ); else ok( hwnd == layered_hwnd, "Wrong window.\n" ); @@ -9225,7 +9224,6 @@ static void test_layered_window(void) if (y >= height / 2 && x < width && y < height) ok( hwnd == layered_hwnd, "Wrong window.\n" ); else - todo_wine ok( hwnd == bg_hwnd, "Wrong window.\n" );
winetest_pop_context(); @@ -9246,7 +9244,6 @@ static void test_layered_window(void) pt.y = 50 + y; hwnd = WindowFromPoint( pt ); if (y < height / 2) - todo_wine ok( hwnd == bg_hwnd, "Wrong window.\n" ); else ok( hwnd == layered_hwnd, "Wrong window.\n" ); @@ -9294,7 +9291,6 @@ static void test_layered_window(void) pt.y = 50 + y; hwnd = WindowFromPoint( pt ); if (y >= height / 2) - todo_wine ok( hwnd == bg_hwnd || broken(hwnd == layered_hwnd) /* <= Win 7*/ , "Wrong window.\n" ); else @@ -9324,7 +9320,6 @@ static void test_layered_window(void) pt.x = 50 + x; pt.y = 50 + y; hwnd = WindowFromPoint( pt ); - todo_wine ok( hwnd == bg_hwnd, "Wrong window.\n" );
winetest_pop_context(); @@ -9384,7 +9379,6 @@ static void test_layered_window(void) pt.y = 50 + y; hwnd = WindowFromPoint( pt ); if (y < height / 2) - todo_wine /* On >= Win 8, color keyed pixels can't be clicked through */ ok( hwnd == bg_hwnd || broken(hwnd == layered_hwnd) , "Wrong window.\n" ); else @@ -9407,7 +9401,6 @@ static void test_layered_window(void) pt.x = 50 + x; pt.y = 50 + y; hwnd = WindowFromPoint( pt ); - todo_wine ok( hwnd == bg_hwnd, "Wrong window.\n" );
winetest_pop_context(); diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 10388a1cc8f..db1e00d9311 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -49,6 +49,9 @@ #include "x11drv.h" #include "winternl.h" #include "wine/debug.h" +#ifdef HAVE_LIBXSHAPE +#include "wine/server.h" +#endif
WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
@@ -1572,6 +1575,7 @@ DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo struct x11drv_window_surface { struct window_surface header; + HWND hwnd; Window window; GC gc; XImage *image; @@ -1579,6 +1583,8 @@ struct x11drv_window_surface BOOL byteswap; BOOL is_argb; DWORD alpha_bits; + BOOL use_constant_alpha; + BYTE constant_alpha; COLORREF color_key; HRGN region; void *bits; @@ -1623,6 +1629,50 @@ static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len ) if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT)) flush_rgn_data( rgn, data ); } + +/* Set layered window region that is not fully transparent */ +static int set_layered_window_region( HWND hwnd, HRGN hrgn ) +{ + static const RECT empty_rect; + BOOL ret; + + if (hrgn) + { + RGNDATA *data; + DWORD size; + + if (!(size = NtGdiGetRegionData( hrgn, 0, NULL ))) return FALSE; + if (!(data = malloc( size ))) return FALSE; + if (!NtGdiGetRegionData( hrgn, size, data )) + { + free( data ); + return FALSE; + } + SERVER_START_REQ( set_layered_window_region ) + { + req->window = wine_server_user_handle( hwnd ); + if (data->rdh.nCount) + wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) ); + else + wine_server_add_data( req, &empty_rect, sizeof(empty_rect) ); + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + free( data ); + } + else + { + /* clear existing region */ + SERVER_START_REQ( set_layered_window_region ) + { + req->window = wine_server_user_handle( hwnd ); + ret = !wine_server_call_err( req ); + } + SERVER_END_REQ; + } + + return ret; +} #endif
/*********************************************************************** @@ -1640,6 +1690,17 @@ static void update_surface_region( struct x11drv_window_surface *surface )
if (!shape_layered_windows) return;
+ if (surface->use_constant_alpha) + { + if (surface->constant_alpha == 0) + rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 ); + else + rgn = NtGdiCreateRectRgn( surface->header.rect.left, surface->header.rect.top, + surface->header.rect.right, surface->header.rect.bottom ); + + goto done; + } + if (!surface->is_argb && surface->color_key == CLR_INVALID) { XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet ); @@ -1714,11 +1775,13 @@ static void update_surface_region( struct x11drv_window_surface *surface ) { while (x < width && ((bits[x] & 0xffffff) == surface->color_key || - (surface->is_argb && !(bits[x] & 0xff000000)))) x++; + (surface->color_key == CLR_INVALID && surface->is_argb + && !(bits[x] & 0xff000000)))) x++; start = x; while (x < width && !((bits[x] & 0xffffff) == surface->color_key || - (surface->is_argb && !(bits[x] & 0xff000000)))) x++; + (surface->color_key == CLR_INVALID && surface->is_argb + && !(bits[x] & 0xff000000)))) x++; add_row( rgn, data, surface->header.rect.left + start, y, x - start ); } } @@ -1746,10 +1809,12 @@ static void update_surface_region( struct x11drv_window_surface *surface )
if (data->rdh.nCount) flush_rgn_data( rgn, data );
+done: if ((data = X11DRV_GetRegionData( rgn, 0 ))) { XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); + set_layered_window_region( surface->hwnd, rgn); free( data ); }
@@ -2007,8 +2072,8 @@ static const struct window_surface_funcs x11drv_surface_funcs = /*********************************************************************** * create_surface */ -struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect, - COLORREF color_key, BOOL use_alpha ) +struct window_surface *create_surface( HWND hwnd, Window window, const XVisualInfo *vis, + const RECT *rect, COLORREF color_key, BOOL use_alpha ) { const XPixmapFormatValues *format = pixmap_formats[vis->depth]; struct x11drv_window_surface *surface; @@ -2030,6 +2095,7 @@ struct window_surface *create_surface( Window window, const XVisualInfo *vis, co surface->header.funcs = &x11drv_surface_funcs; surface->header.rect = *rect; surface->header.ref = 1; + surface->hwnd = hwnd; surface->window = window; surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB); set_color_key( surface, color_key ); @@ -2090,6 +2156,24 @@ void set_surface_color_key( struct window_surface *window_surface, COLORREF colo window_surface->funcs->unlock( window_surface ); }
+void set_surface_constant_alpha( struct window_surface *window_surface, BOOL use_constant_alpha, BYTE alpha ) +{ + struct x11drv_window_surface *surface = get_x11_surface( window_surface ); + BOOL old_use_constant_alpha; + BYTE old_alpha; + + if (window_surface->funcs != &x11drv_surface_funcs) return; /* we may get the null surface */ + + window_surface->funcs->lock( window_surface ); + old_use_constant_alpha = surface->use_constant_alpha; + old_alpha = surface->constant_alpha; + surface->use_constant_alpha = use_constant_alpha; + surface->constant_alpha = alpha; + if (use_constant_alpha != old_use_constant_alpha || (use_constant_alpha && old_alpha != alpha)) + update_surface_region( surface ); + window_surface->funcs->unlock( window_surface ); +} + /*********************************************************************** * expose_surface */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 603314ff3bb..a2f7f152316 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2575,7 +2575,7 @@ BOOL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flags, if (!layered || !NtUserGetLayeredWindowAttributes( hwnd, &key, NULL, &flags ) || !(flags & LWA_COLORKEY)) key = CLR_INVALID;
- *surface = create_surface( data->whole_window, &data->vis, &surface_rect, key, FALSE ); + *surface = create_surface( hwnd, data->whole_window, &data->vis, &surface_rect, key, FALSE );
done: release_win_data( data ); @@ -2862,7 +2862,13 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO if (data->whole_window) sync_window_opacity( data->display, data->whole_window, key, alpha, flags ); if (data->surface) + { set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID ); + if (flags & LWA_ALPHA) + set_surface_constant_alpha( data->surface, TRUE, alpha ); + else + set_surface_constant_alpha( data->surface, FALSE, 0 ); + }
data->layered = TRUE; if (!data->mapped) /* mapping is delayed until attributes are set */ @@ -2921,7 +2927,7 @@ BOOL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info, surface = data->surface; if (!surface || !EqualRect( &surface->rect, &rect )) { - data->surface = create_surface( data->whole_window, &data->vis, &rect, + data->surface = create_surface( hwnd, data->whole_window, &data->vis, &rect, color_key, data->use_alpha ); if (surface) window_surface_release( surface ); surface = data->surface; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index b394795a326..1e72506ee53 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -265,9 +265,10 @@ extern Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const B const struct gdi_image_bits *bits, UINT coloruse ) DECLSPEC_HIDDEN; extern DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis, BITMAPINFO *info, struct gdi_image_bits *bits ) DECLSPEC_HIDDEN; -extern struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect, - COLORREF color_key, BOOL use_alpha ) DECLSPEC_HIDDEN; +extern struct window_surface *create_surface( HWND hwnd, Window window, const XVisualInfo *vis, + const RECT *rect, COLORREF color_key, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key ) DECLSPEC_HIDDEN; +extern void set_surface_constant_alpha( struct window_surface *window_surface, BOOL use_surface_alpha, BYTE alpha ) DECLSPEC_HIDDEN; extern HRGN expose_surface( struct window_surface *window_surface, const RECT *rect ) DECLSPEC_HIDDEN;
extern RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp ) DECLSPEC_HIDDEN; diff --git a/server/protocol.def b/server/protocol.def index 8c2fbeb4afe..a9d81d8dff4 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2547,6 +2547,11 @@ enum coords_relative VARARG(region,rectangles); /* list of rectangles for the region (in window coords) */ @END
+/* Set layered window region that is not fully transparent */ +@REQ(set_layered_window_region) + user_handle_t window; /* handle to the window */ + VARARG(region,rectangles); /* list of rectangles for the region (in window coords) */ +@END
/* Get the window update region */ @REQ(get_update_region) diff --git a/server/window.c b/server/window.c index f713ed224aa..b6108610d80 100644 --- a/server/window.c +++ b/server/window.c @@ -72,6 +72,7 @@ struct window rectangle_t client_rect; /* client rectangle (relative to parent client area) */ struct region *win_region; /* region for shaped windows (relative to window rect) */ struct region *update_region; /* update region (relative to window rect) */ + struct region *layered_win_region; /* layered window region that is not fully transparent */ unsigned int style; /* window style */ unsigned int ex_style; /* window extended style */ lparam_t id; /* window id */ @@ -177,6 +178,7 @@ static void window_destroy( struct object *obj )
if (win->win_region) free_region( win->win_region ); if (win->update_region) free_region( win->update_region ); + if (win->layered_win_region) free_region( win->layered_win_region ); if (win->class) release_class( win->class ); free( win->text );
@@ -565,6 +567,7 @@ static struct window *create_window( struct window *parent, struct window *owner win->last_active = win->handle; win->win_region = NULL; win->update_region = NULL; + win->layered_win_region = NULL; win->style = 0; win->ex_style = 0; win->id = 0; @@ -822,6 +825,9 @@ static int is_point_in_window( struct window *win, int *x, int *y, unsigned int if (win->win_region && !point_in_region( win->win_region, *x - win->window_rect.left, *y - win->window_rect.top )) return 0; /* not in window region */ + if (win->layered_win_region && + !point_in_region( win->layered_win_region, *x - win->window_rect.left, *y - win->window_rect.top )) + return 0; /* not in layered window region that is not fully transparent */ return 1; }
@@ -2702,6 +2708,34 @@ DECL_HANDLER(set_window_region) }
+/* set layered window region that is not fully transparent, update the region if necessary */ +static void set_layered_window_region( struct window *win, struct region *region ) +{ + if (win->layered_win_region) free_region( win->layered_win_region ); + win->layered_win_region = region; + + clear_error(); /* we ignore out of memory errors since the region has been set */ +} + + +/* set layered window region that is not fully transparent */ +DECL_HANDLER(set_layered_window_region) +{ + struct region *region = NULL; + struct window *win = get_window( req->window ); + + if (!win) return; + + if (get_req_data_size()) /* no data means remove the region completely */ + { + if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() ))) + return; + if (win->ex_style & WS_EX_LAYOUTRTL) mirror_region( &win->window_rect, region ); + } + set_layered_window_region( win, region ); +} + + /* get a window update region */ DECL_HANDLER(get_update_region) {
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=126925
Your paranoid android.
=== w10pro64 (32 bit report) ===
user32: win.c:4580: Test failed: hwnd 000301BA/000301BA message 0200 win.c:4584: Test failed: hwnd 000301BA/000301BA message 0201 win.c:4593: Test failed: hwnd 0010027A/0010027A message 0202 win.c:4596: Test failed: hwnd 0010027A/0010027A message 0200
=== w10pro64 (64 bit report) ===
user32: win.c:11238: Test failed: pos = 014a015e
=== w10pro64_ar (64 bit report) ===
user32: win.c:2689: Test failed: style 0x200000: expected !100 win.c:2689: Test failed: style 0x300000: expected !100 win.c:1542: Test failed: Expected color 0xc0c0c0, got 0xffffffff. win.c:1542: Test failed: Expected color 0xc0c0c0, got 0xffffffff. win.c:1552: Test failed: Expected color 0xffffffff, got 0xc0c0c0.
=== w10pro64_ja (64 bit report) ===
user32: win.c:2689: Test failed: style 0x200000: expected !100 win.c:2689: Test failed: style 0x300000: expected !100