Commit edea44f0 authored by Alexandre Julliard's avatar Alexandre Julliard

winex11: Add support for the LWA_COLORKEY layered window attribute.

parent 425f0a25
......@@ -26,12 +26,19 @@
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xresource.h>
#include <X11/Xutil.h>
#ifdef HAVE_LIBXSHAPE
#include <X11/extensions/shape.h>
#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 );
}
......@@ -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 );
}
}
}
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment