From edea44f0ff995aadaaadb866a022832c16301e4a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 12 Sep 2012 16:00:18 +0200 Subject: [PATCH] winex11: Add support for the LWA_COLORKEY layered window attribute. --- dlls/winex11.drv/bitblt.c | 194 +++++++++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/window.c | 24 ++++-- dlls/winex11.drv/x11drv.h | 3 +- 3 files changed, 213 insertions(+), 8 deletions(-) diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c index 12035566762..d8bd62e8b15 100644 --- a/dlls/winex11.drv/bitblt.c +++ b/dlls/winex11.drv/bitblt.c @@ -26,12 +26,19 @@ #include #include +#include +#include +#include +#ifdef HAVE_LIBXSHAPE +#include +#endif + #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" -#include "winternl.h" #include "x11drv.h" +#include "winternl.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(bitblt); @@ -1538,6 +1545,7 @@ struct x11drv_window_surface XImage *image; RECT bounds; BOOL is_r8g8b8; + COLORREF color_key; struct gdi_image_bits bits; CRITICAL_SECTION crit; BITMAPINFO info; /* variable size, must be last */ @@ -1548,6 +1556,169 @@ static struct x11drv_window_surface *get_x11_surface( struct window_surface *sur return (struct x11drv_window_surface *)surface; } +static inline UINT get_color_component( UINT color, UINT mask ) +{ + int shift; + for (shift = 0; !(mask & 1); shift++) mask >>= 1; + return (color * mask / 255) << shift; +} + +static inline void flush_rgn_data( HRGN rgn, RGNDATA *data ) +{ + HRGN tmp = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data ); + CombineRgn( rgn, rgn, tmp, RGN_OR ); + DeleteObject( tmp ); + data->rdh.nCount = 0; +} + +static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len ) +{ + RECT *rect = (RECT *)data->Buffer + data->rdh.nCount; + + if (len <= 0) return; + rect->left = x; + rect->top = y; + rect->right = x + len; + rect->bottom = y + 1; + data->rdh.nCount++; + if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT)) + flush_rgn_data( rgn, data ); +} + +/*********************************************************************** + * update_surface_region + */ +static void update_surface_region( struct x11drv_window_surface *surface ) +{ +#ifdef HAVE_LIBXSHAPE + char buffer[4096]; + RGNDATA *data = (RGNDATA *)buffer; + BITMAPINFO *info = &surface->info; + UINT *masks = (UINT *)info->bmiColors; + int x, y, start, width; + HRGN rgn; + + if (surface->color_key == CLR_INVALID) + { + XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet ); + return; + } + + data->rdh.dwSize = sizeof(data->rdh); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = 0; + data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh); + + rgn = CreateRectRgn( 0, 0, 0, 0 ); + width = surface->header.rect.right - surface->header.rect.left; + + switch (info->bmiHeader.biBitCount) + { + case 16: + { + WORD *bits = surface->bits.ptr; + int stride = (width + 1) & ~1; + UINT mask = masks[0] | masks[1] | masks[2]; + + for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride) + { + x = 0; + while (x < width) + { + while (x < width && (bits[x] & mask) == surface->color_key) x++; + start = x; + while (x < width && (bits[x] & mask) != surface->color_key) x++; + add_row( rgn, data, surface->header.rect.left + start, y, x - start ); + } + } + break; + } + case 24: + { + BYTE *bits = surface->bits.ptr; + int stride = (width * 3 + 3) & ~3; + + for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride) + { + x = 0; + while (x < width) + { + while (x < width && + (bits[x * 3] == GetBValue(surface->color_key)) && + (bits[x * 3 + 1] == GetGValue(surface->color_key)) && + (bits[x * 3 + 2] == GetRValue(surface->color_key))) + x++; + start = x; + while (x < width && + ((bits[x * 3] != GetBValue(surface->color_key)) || + (bits[x * 3 + 1] != GetGValue(surface->color_key)) || + (bits[x * 3 + 2] != GetRValue(surface->color_key)))) + x++; + add_row( rgn, data, surface->header.rect.left + start, y, x - start ); + } + } + break; + } + case 32: + { + DWORD *bits = surface->bits.ptr; + UINT mask = info->bmiHeader.biCompression == BI_RGB ? 0xffffff : (masks[0] | masks[1] | masks[2]); + + for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width) + { + x = 0; + while (x < width) + { + while (x < width && (bits[x] & mask) == surface->color_key) x++; + start = x; + while (x < width && (bits[x] & mask) != surface->color_key) x++; + add_row( rgn, data, surface->header.rect.left + start, y, x - start ); + } + } + break; + } + default: + assert(0); + } + + if (data->rdh.nCount) flush_rgn_data( rgn, data ); + + if ((data = X11DRV_GetRegionData( rgn, 0 ))) + { + XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, + (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); + HeapFree( GetProcessHeap(), 0, data ); + } + + DeleteObject( rgn ); +#endif +} + +/*********************************************************************** + * set_color_key + */ +static void set_color_key( struct x11drv_window_surface *surface, COLORREF key ) +{ + UINT *masks = (UINT *)surface->info.bmiColors; + + if (key == CLR_INVALID) + surface->color_key = CLR_INVALID; + else if (surface->info.bmiHeader.biBitCount <= 8) + surface->color_key = CLR_INVALID; + else if (key & (1 << 24)) /* PALETTEINDEX */ + surface->color_key = 0; + else if (key >> 16 == 0x10ff) /* DIBINDEX */ + surface->color_key = 0; + else if (surface->info.bmiHeader.biBitCount == 24) + surface->color_key = key; + else if (surface->info.bmiHeader.biCompression == BI_RGB) + surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key); + else + surface->color_key = get_color_component( GetRValue(key), masks[0] ) | + get_color_component( GetGValue(key), masks[1] ) | + get_color_component( GetBValue(key), masks[2] ); +} + /*********************************************************************** * x11drv_surface_lock */ @@ -1611,6 +1782,8 @@ static void x11drv_surface_flush( struct window_surface *window_surface ) surface, coords.width, coords.height, wine_dbgstr_rect( &surface->bounds ), surface->bits.ptr ); + if (surface->color_key != CLR_INVALID) update_surface_region( surface ); + if (surface->image->bits_per_pixel == 4 || surface->image->bits_per_pixel == 8) mapping = X11DRV_PALETTE_PaletteToXPixel; @@ -1662,7 +1835,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 ) +struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect, + COLORREF color_key ) { const XPixmapFormatValues *format = pixmap_formats[vis->depth]; struct x11drv_window_surface *surface; @@ -1688,6 +1862,7 @@ struct window_surface *create_surface( Window window, const XVisualInfo *vis, co surface->header.ref = 1; surface->window = window; surface->is_r8g8b8 = is_r8g8b8( vis ); + set_color_key( surface, color_key ); reset_bounds( &surface->bounds ); if (!(surface->bits.ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, surface->info.bmiHeader.biSizeImage ))) @@ -1709,3 +1884,18 @@ failed: x11drv_surface_destroy( &surface->header ); return NULL; } + +/*********************************************************************** + * set_surface_color_key + */ +void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key ) +{ + struct x11drv_window_surface *surface = get_x11_surface( window_surface ); + COLORREF prev; + + window_surface->funcs->lock( window_surface ); + prev = surface->color_key; + set_color_key( surface, color_key ); + if (surface->color_key != prev) update_surface_region( surface ); + window_surface->funcs->unlock( window_surface ); +} diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 07f9d262550..00c86b9ccd5 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -396,8 +396,6 @@ static void sync_window_opacity( Display *display, Window win, if (flags & LWA_ALPHA) opacity = (0xffffffff / 0xff) * alpha; - if (flags & LWA_COLORKEY) FIXME("LWA_COLORKEY not supported\n"); - if (opacity == 0xffffffff) XDeleteProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY) ); else @@ -1447,7 +1445,10 @@ void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) set_wm_hints( thread_display(), data ); if (offset == GWL_EXSTYLE && (changed & WS_EX_LAYERED)) /* changing WS_EX_LAYERED resets attributes */ + { sync_window_opacity( thread_display(), data->whole_window, 0, 0, 0 ); + if (data->surface) set_surface_color_key( data->surface, CLR_INVALID ); + } } @@ -1971,6 +1972,9 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); RECT surface_rect; XVisualInfo vis; + DWORD flags; + COLORREF key; + BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED; if (!data && !(data = X11DRV_create_win_data( hwnd, window_rect, client_rect ))) return; @@ -1991,7 +1995,7 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag if (swp_flags & SWP_HIDEWINDOW) return; if (data->whole_window == root_window) return; if (has_gl_drawable( hwnd )) return; - if (!client_side_graphics) return; + if (!client_side_graphics && !layered) return; surface_rect = get_surface_rect( visible_rect ); if (data->surface) @@ -2013,7 +2017,10 @@ void CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag vis.red_mask = visual->red_mask; vis.green_mask = visual->green_mask; vis.blue_mask = visual->blue_mask; - *surface = create_surface( data->whole_window, &vis, &surface_rect ); + if (!layered || !GetLayeredWindowAttributes( hwnd, &key, NULL, &flags ) || !(flags & LWA_COLORKEY)) + key = CLR_INVALID; + + *surface = create_surface( data->whole_window, &vis, &surface_rect, key ); } @@ -2239,11 +2246,18 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph { if (data->whole_window) sync_window_opacity( thread_display(), data->whole_window, key, alpha, flags ); + if (data->surface) + set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID ); } else { Window win = X11DRV_get_whole_window( hwnd ); - if (win) sync_window_opacity( gdi_display, win, key, alpha, flags ); + if (win) + { + sync_window_opacity( gdi_display, win, key, alpha, flags ); + if (flags & LWA_COLORKEY) + FIXME( "LWA_COLORKEY not supported on foreign thread window %p\n", hwnd ); + } } } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index c637a67fb1d..72051039df0 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -190,7 +190,8 @@ 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 ) DECLSPEC_HIDDEN; +extern struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect, COLORREF color_key ) DECLSPEC_HIDDEN; +extern void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key ) DECLSPEC_HIDDEN; extern RGNDATA *X11DRV_GetRegionData( HRGN hrgn, HDC hdc_lptodp ) DECLSPEC_HIDDEN; extern BOOL add_extra_clipping_region( X11DRV_PDEVICE *dev, HRGN rgn ) DECLSPEC_HIDDEN; -- 2.11.4.GIT