diff --git a/configure.ac b/configure.ac index c9bc557..63aee02 100644 --- a/configure.ac +++ b/configure.ac @@ -153,6 +153,22 @@ if test x"$HAVE_XRANDR" = "x1"; then AC_DEFINE(HAVE_XRANDR) fi +# Xcursor +if test -n "$PKG_CONFIG"; then + PKG_CHECK_MODULES(XCURSOR, xcursor, [HAVE_XCURSOR=1], [HAVE_XCURSOR=0]) +fi +if test x"$HAVE_XCURSOR" = "x1"; then + CFLAGS="$CFLAGS $XCURSOR_CFLAGS" + LIBS="$LIBS $XCURSOR_LIBS" + AC_DEFINE(HAVE_XCURSOR) +else + echo + echo "rdesktop requires libXcursor, install the dependency" + echo + exit 1 +fi + + dnl Smartcard support AC_ARG_ENABLE(smartcard, AS_HELP_STRING([--disable-smartcard], [disable support for smartcard])) AS_IF([test "x$enable_smartcard" != "xno"], [ diff --git a/xwin.c b/xwin.c index 2994a64..a4e133a 100644 --- a/xwin.c +++ b/xwin.c @@ -31,6 +31,7 @@ #include #include "rdesktop.h" #include "xproto.h" +#include #ifdef HAVE_XRANDR #include #endif @@ -2906,136 +2907,111 @@ ui_destroy_glyph(RD_HGLYPH glyph) XFreePixmap(g_display, (Pixmap) glyph); } -/* convert next pixel to 32 bpp */ -static int -get_next_xor_pixel(uint8 * xormask, int bpp, int *k) +#define GET_BIT(ptr, bit) (*(ptr + bit / 8) & (1 << (7 - (bit % 8)))) + +static uint32 +get_pixel(uint32 idx, uint8 * andmask, uint8 * xormask, int bpp) { - int rv = 0; - PixelColour pc; - uint8 *s8; - uint16 *s16; + uint32 offs; + uint32 argb; + uint8 alpha; + uint8 *pxor; switch (bpp) { case 1: - s8 = xormask + (*k) / 8; - rv = (*s8) & (0x80 >> ((*k) % 8)); - rv = rv ? 0xffffff : 0; - (*k) += 1; - break; - case 8: - s8 = xormask + *k; - /* should use colour map */ - rv = s8[0]; - rv = rv ? 0xffffff : 0; - (*k) += 1; - break; - case 15: - s16 = (uint16 *) xormask; - SPLITCOLOUR15(s16[*k], pc); - rv = (pc.red << 16) | (pc.green << 8) | pc.blue; - (*k) += 1; - break; - case 16: - s16 = (uint16 *) xormask; - SPLITCOLOUR16(s16[*k], pc); - rv = (pc.red << 16) | (pc.green << 8) | pc.blue; - (*k) += 1; + offs = idx; + argb = GET_BIT(xormask, idx); + alpha = GET_BIT(andmask, idx) ? 0x00 : 0xff; + if (!GET_BIT(andmask, idx) == 0x00 && argb) + { + // If we have an xor bit is high and + // andmask bit is low, we should + // render a black pixle due to we can + // not xor blit in X11. + + // TODO: add outline to make this + // prettier on black backgrounds. + + argb = 0xff000000; + } + else + argb = (alpha << 24) | (argb ? 0xffffff : 0x000000); break; + case 24: - s8 = xormask + *k; - rv = (s8[0] << 16) | (s8[1] << 8) | s8[2]; - (*k) += 3; + offs = idx * 3; + pxor = xormask + offs; + alpha = GET_BIT(andmask, idx) ? 0x00 : 0xff; + argb = (alpha << 24) | (pxor[2] << 16) | (pxor[1] << 8) | pxor[0]; break; + case 32: - s8 = xormask + *k; - rv = (s8[1] << 16) | (s8[2] << 8) | s8[3]; - (*k) += 4; - break; - default: - logger(GUI, Warning, "get_next_xor_pixel(), unhandled bpp=%d", bpp); + offs = idx * 4; + pxor = xormask + offs; + argb = (pxor[3] << 24) | (pxor[2] << 16) | (pxor[1] << 8) | pxor[0]; break; } - return rv; + + return argb; } RD_HCURSOR -ui_create_cursor(unsigned int x, unsigned int y, int width, int height, - uint8 * andmask, uint8 * xormask, int bpp) +ui_create_cursor(unsigned int xhot, unsigned int yhot, int width, + int height, uint8 * andmask, uint8 * xormask, int bpp) { - RD_HGLYPH maskglyph, cursorglyph; - XColor bg, fg; - Cursor xcursor; - uint8 *cursor, *pcursor; - uint8 *mask, *pmask; - uint8 nextbit; - int scanline, offset, delta; - int i, j, k; + Cursor cursor; + XcursorPixel *out; + XcursorImage *cimg; + uint32 x, y, oidx, idx, argb; - k = 0; - scanline = (width + 7) / 8; - offset = scanline * height; + logger(GUI, Debug, "ui_create_cursot(): xhot=%d, yhot=%d, width=%d, height=%d, bpp=%d", + xhot, yhot, width, height, bpp); - cursor = (uint8 *) xmalloc(offset); - memset(cursor, 0, offset); - - mask = (uint8 *) xmalloc(offset); - memset(mask, 0, offset); - if (bpp == 1) + if (bpp != 1 && bpp != 24 && bpp != 32) { - offset = 0; - delta = scanline; + logger(GUI, Warning, "ui_create_xcursor_cursor(): Unhandled cursor bit depth %d", + bpp); + return g_null_cursor; } - else - { - offset = scanline * height - scanline; - delta = -scanline; - } - /* approximate AND and XOR masks with a monochrome X pointer */ - for (i = 0; i < height; i++) - { - pcursor = &cursor[offset]; - pmask = &mask[offset]; - for (j = 0; j < scanline; j++) + cimg = XcursorImageCreate(width, height); + if (!cimg) + { + logger(GUI, Error, "ui_create_xcursor_cursor(): XcursorImageCreate() failed"); + return g_null_cursor; + } + + cimg->xhot = xhot; + cimg->yhot = yhot; + + out = cimg->pixels; + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) { - for (nextbit = 0x80; nextbit != 0; nextbit >>= 1) + oidx = y * width + x; + + // Flip cursor on Y axis if color pointer + if (bpp != 1) { - if (get_next_xor_pixel(xormask, bpp, &k)) - { - *pcursor |= (~(*andmask) & nextbit); - *pmask |= nextbit; - } - else - { - *pcursor |= ((*andmask) & nextbit); - *pmask |= (~(*andmask) & nextbit); - } + oidx = (height - 1 - y) * width + x; } - andmask++; - pcursor++; - pmask++; + idx = y * width + x; + argb = get_pixel(idx, andmask, xormask, bpp); + out[oidx] = argb; } - offset += delta; } - fg.red = fg.blue = fg.green = 0xffff; - bg.red = bg.blue = bg.green = 0x0000; - fg.flags = bg.flags = DoRed | DoBlue | DoGreen; + cursor = XcursorImageLoadCursor(g_display, cimg); + if (!cursor) + { + logger(GUI, Error, "ui_create_cursor(): XcursorImageLoadCursor() failed"); + return g_null_cursor; + } - cursorglyph = ui_create_glyph(width, height, cursor); - maskglyph = ui_create_glyph(width, height, mask); - - xcursor = - XCreatePixmapCursor(g_display, (Pixmap) cursorglyph, - (Pixmap) maskglyph, &fg, &bg, x, y); - - ui_destroy_glyph(maskglyph); - ui_destroy_glyph(cursorglyph); - xfree(mask); - xfree(cursor); - return (RD_HCURSOR) xcursor; + return (RD_HCURSOR) cursor; } void