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) {