[5/10] x11drv: Add Xcursor support, prefer it when available.
H. Verbeet
hverbeet at gmail.com
Sat Aug 5 16:39:41 CDT 2006
This adds Xcursor support to winex11.drv. Xcursor allows animated and
multicolor cursors to be used.
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index fa74bee..f27418e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1228,6 +1228,7 @@ dnl **** Get the soname for libraries th
if test "$LIBEXT" = "so" -o "$LIBEXT" = "dylib"
then
WINE_GET_SONAME(X11,XCreateWindow,[$X_LIBS $X_EXTRA_LIBS])
+ WINE_GET_SONAME(Xcursor,XcursorImageLoadCursor,[$X_LIBS -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(Xext,XextCreateExtension,[$X_LIBS -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(Xi,XOpenDevice,[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(Xrender,XRenderQueryExtension,[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
index 4e5248e..c2abdb1 100644
--- a/dlls/winex11.drv/Makefile.in
+++ b/dlls/winex11.drv/Makefile.in
@@ -39,6 +39,7 @@ C_SRCS = \
xdnd.c \
xfont.c \
xim.c \
+ xcursor.c \
xrandr.c \
xrender.c \
xvidmode.c
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
index b3ee171..7e409e3 100644
--- a/dlls/winex11.drv/init.c
+++ b/dlls/winex11.drv/init.c
@@ -89,6 +89,9 @@ static void device_init(void)
/* Initialize XRender */
X11DRV_XRender_Init();
+ /* Init Xcursor */
+ X11DRV_Xcursor_init();
+
palette_size = X11DRV_PALETTE_Init();
X11DRV_BITMAP_Init();
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index f9c3e54..5d3681a 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -2,6 +2,7 @@
* X11 mouse driver
*
* Copyright 1998 Ulrich Weigand
+ * Copyright (C) 2006 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -352,6 +353,153 @@ void X11DRV_send_mouse_input( HWND hwnd,
/***********************************************************************
+ * create_cursor_image
+ *
+ * Create an XcursorImage from a cursor_frame_t
+ */
+static XcursorImage *create_cursor_image( cursor_frame_t *frame )
+{
+ int x, xmax;
+ int y, ymax;
+ int and_size, xor_size;
+ unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr;
+ XcursorPixel *pixel_ptr;
+ XcursorImage *image;
+
+ and_size = frame->and_width_bytes * frame->height;
+ and_ptr = and_bits = frame->bits;
+
+ xor_size = frame->xor_width_bytes * frame->height;
+ xor_ptr = xor_bits = frame->bits + and_size;
+
+ ymax = (frame->height > 32) ? 32 : frame->height;
+ xmax = (frame->width > 32) ? 32 : frame->width;
+
+ image = xcursor_ops.XcursorImageCreate( xmax, ymax );
+ pixel_ptr = image->pixels;
+
+ /* On windows, to calculate the color for a pixel, first an AND is done
+ * with the background and the "and" bitmap, then an XOR with the "xor"
+ * bitmap. This means that when the data in the "and" bitmap is 0, the
+ * pixel will get the color as specified in the "xor" bitmap.
+ * However, if the data in the "and" bitmap is 1, the result will be the
+ * background XOR'ed with the value in the "xor" bitmap. In case the "xor"
+ * data is completely black (0x000000) the pixel will become transparent,
+ * in case it's white (0xffffff) the pixel will become the inverse of the
+ * background color.
+ *
+ * Since we can't support inverting colors, we map the grayscale value of
+ * the "xor" data to the alpha channel, and xor the the color with either
+ * black or white.
+ */
+ for (y = 0; y < ymax; ++y)
+ {
+ and_ptr = and_bits + (y * frame->and_width_bytes);
+ xor_ptr = xor_bits + (y * frame->xor_width_bytes);
+
+ for (x = 0; x < xmax; ++x)
+ {
+ /* Xcursor pixel data is in ARGB format, with A in the high byte */
+ switch (frame->bpp)
+ {
+ case 24:
+ /* BGR, 8 bits each */
+ *pixel_ptr = *xor_ptr++;
+ *pixel_ptr |= *xor_ptr++ << 8;
+ *pixel_ptr |= *xor_ptr++ << 16;
+ break;
+
+ case 16:
+ /* BGR, 5 red, 6 green, 5 blue */
+ *pixel_ptr = (*xor_ptr & 0xf8) | ((*xor_ptr & 0x07) << 13);
+ ++xor_ptr;
+ *pixel_ptr |= ((*xor_ptr & 0xe0) << 5) | ((*xor_ptr & 0x1f) << 19);
+ break;
+
+ case 1:
+ if (*xor_ptr & (1 << (7 - (x & 7)))) *pixel_ptr = 0xffffff;
+ else *pixel_ptr = 0;
+ if ((x & 7) == 7) ++xor_ptr;
+ break;
+
+ default:
+ FIXME("Currently no support for cursors with %d bits per pixel\n", frame->bpp);
+ return 0;
+ }
+ /* Alpha channel */
+ if (~*and_ptr & (1 << (7 - (x & 7)))) *pixel_ptr |= 0xff << 24;
+ else if (*pixel_ptr)
+ {
+ int alpha = (*pixel_ptr & 0xff) * 0.30f
+ + ((*pixel_ptr & 0xff00) >> 8) * 0.55f
+ + ((*pixel_ptr & 0xff0000) >> 16) * 0.15f;
+ *pixel_ptr ^= ((x + y) % 2) ? 0xffffff : 0x000000;
+ *pixel_ptr |= alpha << 24;
+ }
+
+ if ((x & 7) == 7) ++and_ptr;
+ ++pixel_ptr;
+ }
+ }
+
+ return image;
+}
+
+
+/***********************************************************************
+ * create_xcursor_cursor
+ *
+ * Use Xcursor to create an X cursor from a Windows one.
+ */
+static Cursor create_xcursor_cursor( Display *display, const cursor_t *cursor_object )
+{
+ unsigned int i;
+ Cursor cursor;
+ XcursorImage *image;
+ XcursorImages *images;
+
+ if (!cursor_object) /* Create an empty cursor */
+ {
+ image = xcursor_ops.XcursorImageCreate( 1, 1 );
+ image->xhot = 0;
+ image->yhot = 0;
+ *(image->pixels) = 0;
+ cursor = xcursor_ops.XcursorImageLoadCursor( display, image );
+ xcursor_ops.XcursorImageDestroy( image );
+
+ return cursor;
+ }
+
+ images = xcursor_ops.XcursorImagesCreate( cursor_object->num_frames );
+ for (i = 0; i < cursor_object->num_frames; ++i)
+ {
+ cursor_frame_t *frame = &cursor_object->frames[i];
+ image = create_cursor_image( frame );
+ if (!image) return 0;
+
+ /* Make sure hotspot is valid */
+ image->xhot = frame->xhot;
+ image->yhot = frame->yhot;
+ if (image->xhot < 0 || image->xhot >= image->width ||
+ image->yhot < 0 || image->yhot >= image->height)
+ {
+ image->xhot = image->width / 2;
+ image->yhot = image->height / 2;
+ }
+
+ image->delay = cursor_object->delay;
+
+ images->images[images->nimage++] = image;
+ }
+
+ cursor = xcursor_ops.XcursorImagesLoadCursor( display, images );
+ xcursor_ops.XcursorImagesDestroy( images );
+
+ return cursor;
+}
+
+
+/***********************************************************************
* create_cursor
*
* Create an X cursor from a Windows one.
@@ -654,7 +802,15 @@ void X11DRV_SetCursor( const cursor_t *c
/* If in desktop mode, set the cursor on the desktop window */
wine_tsx11_lock();
- cursor = create_cursor( gdi_display, cursor_object );
+ if (xcursor_ops.XcursorImageLoadCursor)
+ {
+ cursor = create_xcursor_cursor( gdi_display, cursor_object );
+ }
+ else
+ {
+ cursor = create_cursor( gdi_display, cursor_object );
+ }
+
if (cursor)
{
XDefineCursor( gdi_display, root_window, cursor );
@@ -669,7 +825,15 @@ void X11DRV_SetCursor( const cursor_t *c
struct x11drv_thread_data *data = x11drv_thread_data();
wine_tsx11_lock();
- cursor = create_cursor( data->display, cursor_object );
+ if (xcursor_ops.XcursorImageLoadCursor)
+ {
+ cursor = create_xcursor_cursor( data->display, cursor_object );
+ }
+ else
+ {
+ cursor = create_cursor( data->display, cursor_object );
+ }
+
if (cursor)
{
if (data->cursor) XFreeCursor( data->display, data->cursor );
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index e5027c4..0d610c1 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -229,6 +229,7 @@ extern BOOL X11DRV_SwapBuffers(X11DRV_PD
/* X11 driver internal functions */
+extern void X11DRV_Xcursor_init(void);
extern void X11DRV_BITMAP_Init(void);
extern void X11DRV_FONT_Init( int log_pixels_x, int log_pixels_y );
@@ -429,6 +430,39 @@ extern void X11DRV_DIB_CopyDIBSection(X1
struct _DCICMD;
extern INT X11DRV_DCICommand(INT cbInput, const struct _DCICMD *lpCmd, LPVOID lpOutData);
+/* Xcursor */
+typedef unsigned int XcursorUInt;
+typedef XcursorUInt XcursorPixel;
+typedef XcursorUInt XcursorDim;
+
+typedef struct {
+ XcursorUInt version;
+ XcursorDim size;
+ XcursorDim width;
+ XcursorDim height;
+ XcursorDim xhot;
+ XcursorDim yhot;
+ XcursorUInt delay;
+ XcursorPixel *pixels;
+} XcursorImage;
+
+typedef struct {
+ int nimage;
+ XcursorImage **images;
+ char *name;
+} XcursorImages;
+
+typedef struct {
+ XcursorImage *(*XcursorImageCreate)(int, int);
+ XcursorImages *(*XcursorImagesCreate)(int);
+ void (*XcursorImageDestroy)(XcursorImage *);
+ void (*XcursorImagesDestroy)(XcursorImages *);
+ Cursor (*XcursorImageLoadCursor)(Display *, XcursorImage *);
+ Cursor (*XcursorImagesLoadCursor)(Display *, XcursorImages *);
+} xcursor_functions;
+
+extern xcursor_functions xcursor_ops;
+
/**************************************************************************
* X11 GDI driver
*/
diff --git a/dlls/winex11.drv/xcursor.c b/dlls/winex11.drv/xcursor.c
new file mode 100644
index 0000000..bfcf8c7
--- /dev/null
+++ b/dlls/winex11.drv/xcursor.c
@@ -0,0 +1,53 @@
+/*
+ * Xcursor function pointers
+ *
+ * Copyright (C) 2006 Henri Verbeet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "config.h"
+#include "wine/port.h"
+#include "wine/debug.h"
+#include "wine/library.h"
+#include "x11drv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(xcursor);
+
+#ifndef SONAME_LIBXCURSOR
+#define SONAME_LIBXCURSOR "libXcursor.so"
+#endif
+
+xcursor_functions xcursor_ops;
+
+static void error( void )
+{
+ memset( &xcursor_ops, 0, sizeof(xcursor_ops) );
+}
+
+void X11DRV_Xcursor_init( void )
+{
+ void *xcursor_handle = wine_dlopen( SONAME_LIBXCURSOR, RTLD_NOW, NULL, 0 );
+
+#define LOAD_FUNCPTR(f) \
+ if(!(xcursor_ops.f = wine_dlsym( xcursor_handle, #f, NULL, 0)) ) \
+ { error(); return; }
+ LOAD_FUNCPTR(XcursorImageCreate)
+ LOAD_FUNCPTR(XcursorImagesCreate)
+ LOAD_FUNCPTR(XcursorImageDestroy)
+ LOAD_FUNCPTR(XcursorImagesDestroy)
+ LOAD_FUNCPTR(XcursorImageLoadCursor)
+ LOAD_FUNCPTR(XcursorImagesLoadCursor)
+#undef LOAD_FUNCPTR
+}
More information about the wine-patches
mailing list