Index: configure.in
===================================================================
RCS file: /cvs/gnome/gtk+/configure.in,v
retrieving revision 1.333
diff -u -r1.333 configure.in
--- configure.in	17 Jun 2003 00:37:23 -0000	1.333
+++ configure.in	24 Jun 2003 21:28:23 -0000
@@ -1230,6 +1230,15 @@
 	  :, [#include <X11/Xlib.h>])], : ,
        $X_LIBS -lXrandr -lXrender -lX11 $X_EXTRA_LIBS)
 
+  # Checks for Xcursor library
+  have_xcursor=false
+  PKG_CHECK_MODULES(XCURSOR, xcursor, have_xcursor=true, :)
+
+  if $have_xcursor ; then
+    AC_DEFINE(HAVE_XCURSOR, 1, Have the Xcursor library)
+    GDK_EXTRA_LIBS="$XCURSOR_LIBS $GDK_EXTRA_LIBS";
+  fi
+    
   # Xshm checks
 
   if test "x$enable_shm" = "xyes"; then
Index: gdk/gdkcursor.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkcursor.h,v
retrieving revision 1.8
diff -u -r1.8 gdkcursor.h
--- gdk/gdkcursor.h	18 Jun 2002 20:59:32 -0000	1.8
+++ gdk/gdkcursor.h	24 Jun 2003 21:28:23 -0000
@@ -2,6 +2,7 @@
 #define __GDK_CURSOR_H__
 
 #include <gdk/gdktypes.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -114,6 +115,16 @@
 					  GdkPixmap	  *mask,
 					  GdkColor	  *fg,
 					  GdkColor	  *bg,
+					  gint		   x,
+					  gint		   y);
+GdkCursor* gdk_cursor_new_from_pixbuf	 (GdkDisplay      *display,
+					  GdkPixbuf	  *pixbuf,
+					  gint		   x,
+					  gint		   y);
+GdkCursor* gdk_cursor_new_from_pixbufs   (GdkDisplay      *display,
+					  GdkPixbuf      **pixbufs,
+					  gint             n_pixbufs,
+					  gint            *delays,
 					  gint		   x,
 					  gint		   y);
 GdkDisplay* gdk_cursor_get_display	 (GdkCursor	  *cursor);
Index: gdk/x11/gdkcursor-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkcursor-x11.c,v
retrieving revision 1.27
diff -u -r1.27 gdkcursor-x11.c
--- gdk/x11/gdkcursor-x11.c	28 Nov 2002 00:33:05 -0000	1.27
+++ gdk/x11/gdkcursor-x11.c	24 Jun 2003 21:28:23 -0000
@@ -24,14 +24,20 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include "config.h"
 #include <X11/Xlib.h>
 #include <X11/cursorfont.h>
+#ifdef HAVE_XCURSOR
+#include <X11/Xcursor/Xcursor.h>
+#endif
 
 #include "gdkprivate-x11.h"
 #include "gdkcursor.h"
 #include "gdkpixmap-x11.h"
 #include "gdkx.h"
 #include <gdk/gdkpixmap.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
 
 /**
  * gdk_cursor_new_for_display:
@@ -294,3 +300,278 @@
 
   return ((GdkCursorPrivate *)cursor)->display;
 }
+
+
+#if HAVE_XCURSOR
+
+static XcursorImage*
+cursor_image_new_from_pixbuf (GdkPixbuf *pixbuf, 
+			      gint       delay, 
+			      gint       x,
+			      gint       y)
+{
+  guint width, height, rowstride, n_channels;
+  guchar *pixels, *src;
+  XcursorImage *image;
+  XcursorPixel *dest;
+  guchar a;
+  gint i, j;
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  g_return_val_if_fail (0 <= x && x < width, NULL);
+  g_return_val_if_fail (0 <= y && y < height, NULL);
+
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  image = XcursorImageCreate (width, height);
+      
+  image->delay = delay;
+  image->xhot = x;
+  image->yhot = y;
+
+  dest = image->pixels;
+
+  for (j = 0; j < height; j++) 
+    {
+      src = pixels + j * rowstride;
+      for (i = 0; i < width; i++) 
+	{
+	  if (n_channels == 3) 
+	    a = 0xff;
+	  else
+	    a = src[3];
+	  
+	  *dest =  (a << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
+	  src += n_channels;
+	  dest++;
+	}
+    }
+
+  return image;
+}
+
+
+/**
+ * gdk_cursor_new_from_pixbuf:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @pixbuf: the #GdkPixbuf containing the cursor image.
+ * @x: the horizontal offset of the 'hotspot' of the cursor. 
+ * @y: the vertical offset of the 'hotspot' of the cursor.
+ *
+ * Creates a new cursor from a pixbuf. 
+ *
+ * Not all GDK backends support RGBA cursors. If they are not 
+ * supported, a monochrome approximation will be displayed.
+ *
+ * On the X backend, support for RGBA cursors requires a
+ * sufficently new version of the X Render extension. 
+ *
+ * Returns: a new #GdkCursor.
+ * 
+ * Since: 2.4
+ */
+GdkCursor *
+gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
+			    GdkPixbuf  *pixbuf,
+			    gint        x,
+			    gint        y)
+{
+  XcursorImage *image;
+  Cursor xcursor;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+  g_return_val_if_fail (0 <= x && x < gdk_pixbuf_get_width (pixbuf), NULL);
+  g_return_val_if_fail (0 <= y && y < gdk_pixbuf_get_height (pixbuf), NULL);
+
+  if (display->closed)
+    xcursor = None;
+  else 
+    {
+      image = cursor_image_new_from_pixbuf (pixbuf, 0, x, y);
+      xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), image);
+      XcursorImageDestroy (image);
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  
+  return cursor;
+}
+
+/**
+ * gdk_cursor_new_from_pixbufs:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @pixbufs: the #GdkPixbuf<-- -->s containing the cursor image. 
+ * @n_pixbufs: the length of the @pixbufs and @delays arrays
+ * @delays: times in milliseconds to show each image
+ * @x: the horizontal offset of the 'hotspot' of the cursor. 
+ * @y: the vertical offset of the 'hotspot' of the cursor.
+ *
+ * Creates a new animated cursor from an array of pixbufs. If
+ * the array doesn't contain any images, an invisible cursor
+ * is created.
+ *
+ * Not all GDK backends support animated cursors. If animated 
+ * cursors are not supported, the first image will be used. 
+ *
+ * On the X backend, support for animated cursors requires a
+ * sufficently new version of the X Render extension. 
+ *
+ * Returns: a new #GdkCursor.
+ * 
+ * Since: 2.4
+ */
+GdkCursor* 
+gdk_cursor_new_from_pixbufs (GdkDisplay  *display,
+			     GdkPixbuf  **pixbufs,
+			     gint         n_pixbufs,
+			     gint        *delays,
+			     gint	     x,
+			     gint	     y)
+{
+  XcursorImages *images;
+  Cursor xcursor;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  gint i;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (pixbufs != NULL || n_pixbufs == 0, NULL);
+
+  xcursor = None;
+
+  if (!display->closed && n_pixbufs > 0)
+    {
+      images = XcursorImagesCreate (n_pixbufs);
+      for (i = 0; i < n_pixbufs; i++) 
+	images->images[i] = cursor_image_new_from_pixbuf (pixbufs[i], delays[i], x, y);
+      images->nimage = n_pixbufs;
+
+      xcursor = XcursorImagesLoadCursor (GDK_DISPLAY_XDISPLAY (display), images);
+
+      for (i = 0; i < n_pixbufs; i++)
+	XcursorImageDestroy (images->images[i]);
+      XcursorImagesDestroy (images);
+    }
+
+  private = g_new (GdkCursorPrivate, 1);
+  private->display = display;
+  private->xcursor = xcursor;
+  cursor = (GdkCursor *) private;
+  cursor->type = GDK_CURSOR_IS_PIXMAP;
+  cursor->ref_count = 1;
+  
+  return cursor;
+}
+
+#else
+
+GdkCursor *
+gdk_cursor_new_from_pixbuf (GdkDisplay *display, 
+			    GdkPixbuf  *pixbuf,
+			    gint        x,
+			    gint        y)
+{
+  GdkCursor *cursor;
+  GdkPixmap *pixmap, *mask;
+  guint width, height, n_channels, rowstride, i, j;
+  guint8 *data, *mask_data, *pixels;
+  GdkColor fg = { 0, 0, 0, 0 };
+  GdkColor bg = { 0, 0xffff, 0xffff, 0xffff };
+  GdkScreen *screen;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+  width = gdk_pixbuf_get_width (pixbuf);
+  height = gdk_pixbuf_get_height (pixbuf);
+
+  g_return_val_if_fail (0 <= x && (guint)x < width, NULL);
+  g_return_val_if_fail (0 <= y && (guint)y < height, NULL);
+
+  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+  pixels = gdk_pixbuf_get_pixels (pixbuf);
+
+  data = g_new0 (guint8, (width + 7) / 8 * height);
+  mask_data = g_new0 (guint8, (width + 7) / 8 * height);
+
+  for (j = 0; j < height; j++)
+    {
+      guint8 *src = pixels + j * rowstride;
+      guint8 *d = data + (width + 7) / 8 * j;
+      guint8 *md = mask_data + (width + 7) / 8 * j;
+	
+      for (i = 0; i < width; i++)
+	{
+	  if (src[1] < 0x80)
+	    *d |= 1 << (i % 8);
+	  
+	  if (n_channels == 3 || src[3] >= 0x80)
+	    *md |= 1 << (i % 8);
+	  
+	  src += n_channels;
+	  if (i % 8 == 0)
+	    {
+	      d++; 
+	      md++;
+	    }
+	}
+    }
+      
+  screen = gdk_display_get_default_screen (display);
+  pixmap = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen), 
+					data, width, height);
+ 
+  mask = gdk_bitmap_create_from_data (gdk_screen_get_root_window (screen),
+				      mask_data, width, height);
+   
+  cursor = gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, x, y);
+   
+  g_object_unref (pixmap);
+  g_object_unref (mask);
+  
+  return cursor;
+}
+
+GdkCursor* 
+gdk_cursor_new_from_pixbufs (GdkDisplay         *display,
+			     GdkPixbuf         **pixbufs,
+			     gint                n_pixbufs,
+			     gint               *delays,
+			     gint		    x,
+			     gint		    y)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (pixbufs != NULL || n_pixbufs == 0, NULL);
+
+  if (n_pixbufs > 0)
+   cursor = gdk_cursor_new_from_pixbuf (display, pixbufs[0], x, y);
+  else 
+    {
+      private = g_new (GdkCursorPrivate, 1);
+      private->display = display;
+      private->xcursor = None;
+      cursor = (GdkCursor *) private;
+      cursor->type = GDK_CURSOR_IS_PIXMAP;
+      cursor->ref_count = 1;
+    }
+
+  return cursor;
+}
+
+#endif
