winex11.drv: Add Xcursor support for 32 bit cursors.
Based on patch by Henri Verbeet.
diff --git a/configure b/configure
index 17705e0..2ba7eac 100755
--- a/configure
+++ b/configure
@@ -7672,9 +7672,11 @@
+
for ac_header in X11/Xlib.h \
X11/XKBlib.h \
X11/Xutil.h \
+ X11/Xcursor/Xcursor.h \
X11/extensions/shape.h \
X11/extensions/XInput.h \
X11/extensions/XShm.h \
@@ -14724,6 +14726,82 @@
fi
+ { echo "$as_me:$LINENO: checking for -lXcursor soname" >&5
+echo $ECHO_N "checking for -lXcursor soname... $ECHO_C" >&6; }
+if test "${ac_cv_lib_soname_Xcursor+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_get_soname_save_LIBS=$LIBS
+LIBS="-lXcursor $X_LIBS -lX11 $X_EXTRA_LIBS $LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XcursorImageLoadCursor ();
+int
+main ()
+{
+return XcursorImageLoadCursor ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ case "$LIBEXT" in
+ dylib) ac_cv_lib_soname_Xcursor=`otool -L conftest$ac_exeext | grep libXcursor\\.[0-9A-Za-z.]*dylib | sed -e "s/^.*\/\(libXcursor\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;;
+ so) ac_cv_lib_soname_Xcursor=`$ac_cv_path_LDD conftest$ac_exeext | grep libXcursor\\.so | sed -e "s/^.*\(libXcursor\.so[^ ]*\).*$/\1/"';2,$d'` ;;
+ esac
+ if test "x$ac_cv_lib_soname_Xcursor" = "x"
+ then
+ ac_cv_lib_soname_Xcursor="libXcursor.$LIBEXT"
+ fi
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_cv_lib_soname_Xcursor="libXcursor.$LIBEXT"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS=$ac_get_soname_save_LIBS
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_lib_soname_Xcursor" >&5
+echo "${ECHO_T}$ac_cv_lib_soname_Xcursor" >&6; }
+if test "${ac_cv_lib_soname_Xcursor+set}" = set; then
+
+cat >>confdefs.h <<_ACEOF
+#define SONAME_LIBXCURSOR "$ac_cv_lib_soname_Xcursor"
+_ACEOF
+
+fi
+
{ echo "$as_me:$LINENO: checking for -lfreetype soname" >&5
echo $ECHO_N "checking for -lfreetype soname... $ECHO_C" >&6; }
if test "${ac_cv_lib_soname_freetype+set}" = set; then
diff --git a/configure.ac b/configure.ac
index 5d8cb52..066a289 100644
--- a/configure.ac
+++ b/configure.ac
@@ -335,6 +335,7 @@
AC_CHECK_HEADERS([X11/Xlib.h \
X11/XKBlib.h \
X11/Xutil.h \
+ X11/Xcursor/Xcursor.h \
X11/extensions/shape.h \
X11/extensions/XInput.h \
X11/extensions/XShm.h \
@@ -1151,6 +1152,7 @@
WINE_GET_SONAME(Xinerama,XineramaQueryScreens,[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(Xrender,XRenderQueryExtension,[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(Xrandr,XRRQueryExtension,[$X_LIBS -lXext -lX11 $X_EXTRA_LIBS])
+ WINE_GET_SONAME(Xcursor,XcursorImageLoadCursor,[$X_LIBS -lX11 $X_EXTRA_LIBS])
WINE_GET_SONAME(freetype,FT_Init_FreeType,[$X_LIBS])
WINE_GET_SONAME(GL,glXQueryExtension,[$X_LIBS $X_EXTRA_LIBS])
WINE_GET_SONAME(hal,libhal_ctx_new)
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
index cf23866..b773f9a 100644
--- a/dlls/winex11.drv/init.c
+++ b/dlls/winex11.drv/init.c
@@ -89,6 +89,9 @@
/* 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 1016c69..e372a0f 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 2007 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,10 +20,24 @@
*/
#include "config.h"
+#include "wine/port.h"
#include <X11/Xlib.h>
#include <stdarg.h>
+#ifdef HAVE_X11_XCURSOR_XCURSOR_H
+# include <X11/Xcursor/Xcursor.h>
+# ifndef SONAME_LIBXCURSOR
+# define SONAME_LIBXCURSOR "libXcursor.so"
+# endif
+static void *xcursor_handle;
+# define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(XcursorImageCreate);
+MAKE_FUNCPTR(XcursorImageDestroy);
+MAKE_FUNCPTR(XcursorImageLoadCursor);
+# undef MAKE_FUNCPTR
+#endif /* HAVE_X11_XCURSOR_XCURSOR_H */
+
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
@@ -32,6 +47,7 @@
#include "win.h"
#include "x11drv.h"
#include "wine/server.h"
+#include "wine/library.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
@@ -75,6 +91,32 @@
BOOL X11DRV_SetCursorPos( INT x, INT y );
+
+/***********************************************************************
+ * X11DRV_Xcursor_Init
+ *
+ * Load the Xcursor library for use.
+ */
+void X11DRV_Xcursor_Init(void)
+{
+#ifdef HAVE_X11_XCURSOR_XCURSOR_H
+ xcursor_handle = wine_dlopen(SONAME_LIBXCURSOR, RTLD_NOW, NULL, 0);
+ if (!xcursor_handle) /* wine_dlopen failed. */
+ {
+ WARN("Xcursor failed to load. Using fallback code.\n");
+ return;
+ }
+#define LOAD_FUNCPTR(f) \
+ p##f = wine_dlsym(xcursor_handle, #f, NULL, 0)
+
+ LOAD_FUNCPTR(XcursorImageCreate);
+ LOAD_FUNCPTR(XcursorImageDestroy);
+ LOAD_FUNCPTR(XcursorImageLoadCursor);
+#undef LOAD_FUNCPTR
+#endif /* HAVE_X11_XCURSOR_XCURSOR_H */
+}
+
+
/***********************************************************************
* get_coords
*
@@ -352,6 +394,165 @@
}
+#ifdef HAVE_X11_XCURSOR_XCURSOR_H
+
+/***********************************************************************
+ * create_cursor_image
+ *
+ * Create an XcursorImage from a CURSORICONINFO
+ */
+static XcursorImage *create_cursor_image( CURSORICONINFO *ptr )
+{
+ int x, xmax;
+ int y, ymax;
+ int and_size, xor_size;
+ unsigned char *and_bits, *and_ptr, *xor_bits, *xor_ptr;
+ int and_width_bytes, xor_width_bytes;
+ XcursorPixel *pixel_ptr;
+ XcursorImage *image;
+
+ ymax = (ptr->nHeight > 32) ? 32 : ptr->nHeight;
+ xmax = (ptr->nWidth > 32) ? 32 : ptr->nWidth;
+
+ and_width_bytes = xmax / 8;
+ xor_width_bytes = and_width_bytes * ptr->bBitsPerPixel;
+
+ and_size = ptr->nWidth * ptr->nHeight / 8;
+ and_ptr = and_bits = (unsigned char *)(ptr + 1);
+
+ xor_size = xor_width_bytes * ptr->nHeight;
+ xor_ptr = xor_bits = and_ptr + and_size;
+
+ image = pXcursorImageCreate( 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 * and_width_bytes);
+ xor_ptr = xor_bits + (y * xor_width_bytes);
+
+ for (x = 0; x < xmax; ++x)
+ {
+ /* Xcursor pixel data is in ARGB format, with A in the high byte */
+ switch (ptr->bBitsPerPixel)
+ {
+ case 32:
+ /* BGRA, 8 bits each */
+ *pixel_ptr = *xor_ptr++;
+ *pixel_ptr |= *xor_ptr++ << 8;
+ *pixel_ptr |= *xor_ptr++ << 16;
+ *pixel_ptr |= *xor_ptr++ << 24;
+ break;
+
+ 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 * 0x1f;
+ *pixel_ptr |= (*xor_ptr & 0xe0) << 3;
+ ++xor_ptr;
+ *pixel_ptr |= (*xor_ptr & 0x07) << 11;
+ *pixel_ptr |= (*xor_ptr & 0xf8) << 13;
+ 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", ptr->bBitsPerPixel);
+ return 0;
+ }
+
+ if (ptr->bBitsPerPixel != 32)
+ {
+ /* 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, CURSORICONINFO *ptr )
+{
+ Cursor cursor;
+ XcursorImage *image;
+
+ if (!ptr) /* Create an empty cursor */
+ {
+ image = pXcursorImageCreate( 1, 1 );
+ image->xhot = 0;
+ image->yhot = 0;
+ *(image->pixels) = 0;
+ cursor = pXcursorImageLoadCursor( display, image );
+ pXcursorImageDestroy( image );
+
+ return cursor;
+ }
+
+ image = create_cursor_image( ptr );
+ if (!image) return 0;
+
+ /* Make sure hotspot is valid */
+ image->xhot = ptr->ptHotSpot.x;
+ image->yhot = ptr->ptHotSpot.y;
+ 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 = 0;
+
+ cursor = pXcursorImageLoadCursor( display, image );
+ pXcursorImageDestroy( image );
+
+ return cursor;
+}
+
+#endif /* HAVE_X11_XCURSOR_XCURSOR_H */
+
+
/***********************************************************************
* create_cursor
*
@@ -363,6 +564,10 @@
XColor fg, bg;
Cursor cursor = None;
+#ifdef HAVE_X11_XCURSOR_XCURSOR_H
+ if (pXcursorImageLoadCursor) return create_xcursor_cursor( display, ptr );
+#endif
+
if (!ptr) /* Create an empty cursor */
{
static const char data[] = { 0 };
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 723a41a..4053c2f 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -228,6 +228,7 @@
/* 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 );
diff --git a/include/config.h.in b/include/config.h.in
index 7ba145e..599ea65 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -924,6 +924,9 @@
/* Define to 1 if you have the <X11/extensions/XShm.h> header file. */
#undef HAVE_X11_EXTENSIONS_XSHM_H
+/* Define to 1 if you have the <X11/Xcursor/Xcursor.h> header file. */
+#undef HAVE_X11_XCURSOR_XCURSOR_H
+
/* Define to 1 if you have the <X11/XKBlib.h> header file. */
#undef HAVE_X11_XKBLIB_H
@@ -1029,6 +1032,9 @@
/* Define to the soname of the libX11 library. */
#undef SONAME_LIBX11
+/* Define to the soname of the libXcursor library. */
+#undef SONAME_LIBXCURSOR
+
/* Define to the soname of the libXext library. */
#undef SONAME_LIBXEXT