diff --git a/configure b/configure index 17705e03f8c..2ba7eac984c 100755 --- a/configure +++ b/configure @@ -7672,9 +7672,11 @@ then + 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 \ @@ -14722,6 +14724,82 @@ cat >>confdefs.h <<_ACEOF #define SONAME_LIBXRANDR "$ac_cv_lib_soname_Xrandr" _ACEOF +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 diff --git a/configure.ac b/configure.ac index 5d8cb526419..066a2890142 100644 --- a/configure.ac +++ b/configure.ac @@ -335,6 +335,7 @@ then 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 @@ then 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 cf23866debe..b773f9a02f6 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 1016c697127..e372a0f5eda 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 #include +#ifdef HAVE_X11_XCURSOR_XCURSOR_H +# include +# 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 @@ static RECT cursor_clip; /* Cursor clipping rect */ 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 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, } +#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 @@ static Cursor create_cursor( Display *display, CURSORICONINFO *ptr ) 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 723a41a65f0..4053c2f6fcd 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -228,6 +228,7 @@ extern BOOL X11DRV_SwapBuffers(X11DRV_PDEVICE *physDev); /* 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 7ba145edd11..599ea65c7c6 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -924,6 +924,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_X11_EXTENSIONS_XSHM_H +/* Define to 1 if you have the header file. */ +#undef HAVE_X11_XCURSOR_XCURSOR_H + /* Define to 1 if you have the 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