Index: gdk/gdkdisplay.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdkdisplay.h,v
retrieving revision 1.13
diff -u -r1.13 gdkdisplay.h
--- gdk/gdkdisplay.h	8 Nov 2002 19:41:38 -0000	1.13
+++ gdk/gdkdisplay.h	24 Jun 2003 22:52:33 -0000
@@ -148,6 +148,11 @@
 
 GdkDisplay *gdk_display_open_default_libgtk_only (void);
 
+gboolean gdk_display_supports_cursor_animation (GdkDisplay    *display);
+gboolean gdk_display_supports_cursor_alpha     (GdkDisplay    *display);
+gboolean gdk_display_supports_cursor_color     (GdkDisplay    *display);
+gint     gdk_display_get_default_cursor_size   (GdkDisplay    *display);
+
 G_END_DECLS
 
 #endif				/* __GDK_DISPLAY_H__ */
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 22:52:33 -0000
@@ -2,6 +2,7 @@
 #define __GDK_CURSOR_H__
 
 #include <gdk/gdktypes.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -100,6 +101,14 @@
   guint ref_count;
 };
 
+struct _GdkCursorImage
+{
+  GdkPixbuf *pixbuf;
+  guint x;
+  guint y;
+  guint delay;
+};
+
 /* Cursors
  */
 
@@ -116,6 +125,11 @@
 					  GdkColor	  *bg,
 					  gint		   x,
 					  gint		   y);
+GdkCursor* gdk_cursor_new_from_image	 (GdkDisplay      *display,
+					  GdkCursorImage  *image);
+GdkCursor* gdk_cursor_new_from_images    (GdkDisplay      *display,
+					  GdkCursorImage **images,
+					  gint             n_images);
 GdkDisplay* gdk_cursor_get_display	 (GdkCursor	  *cursor);
 GdkCursor*  gdk_cursor_ref               (GdkCursor       *cursor);
 void        gdk_cursor_unref             (GdkCursor       *cursor);
Index: gdk/gdktypes.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/gdktypes.h,v
retrieving revision 1.63
diff -u -r1.63 gdktypes.h
--- gdk/gdktypes.h	25 Apr 2002 22:29:10 -0000	1.63
+++ gdk/gdktypes.h	24 Jun 2003 22:52:33 -0000
@@ -94,6 +94,7 @@
 typedef struct _GdkColor	      GdkColor;
 typedef struct _GdkColormap	      GdkColormap;
 typedef struct _GdkCursor	      GdkCursor;
+typedef struct _GdkCursorImage	      GdkCursorImage;
 typedef struct _GdkFont		      GdkFont;
 typedef struct _GdkGC                 GdkGC;
 typedef struct _GdkImage              GdkImage;
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 22:52:34 -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,372 @@
 
   return ((GdkCursorPrivate *)cursor)->display;
 }
+
+
+#if HAVE_XCURSOR
+
+static XcursorImage*
+convert_cursor_image (GdkCursorImage *image)
+{
+  guint width, height, rowstride, n_channels;
+  guchar *pixels, *src;
+  XcursorImage *xcimage;
+  XcursorPixel *dest;
+  guchar a;
+  gint i, j;
+
+  width = gdk_pixbuf_get_width (image->pixbuf);
+  height = gdk_pixbuf_get_height (image->pixbuf);
+
+  g_return_val_if_fail (0 <= image->x && image->x < width, NULL);
+  g_return_val_if_fail (0 <= image->y && image->y < height, NULL);
+
+  n_channels = gdk_pixbuf_get_n_channels (image->pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (image->pixbuf);
+  pixels = gdk_pixbuf_get_pixels (image->pixbuf);
+
+  xcimage = XcursorImageCreate (width, height);
+      
+  xcimage->delay = image->delay;
+  xcimage->xhot = image->x;
+  xcimage->yhot = image->y;
+
+  dest = xcimage->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 xcimage;
+}
+
+
+/**
+ * gdk_cursor_new_from_image:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @image: the #GdkCursorImage containing the cursor image and hotspot.
+ *
+ * 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_image (GdkDisplay      *display, 
+			   GdkCursorImage  *image)
+{
+  XcursorImage *xcimage;
+  Cursor xcursor;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (image != NULL && GDK_IS_PIXBUF (image->pixbuf), NULL);
+  g_return_val_if_fail (0 <= image->x && image->x < gdk_pixbuf_get_width (image->pixbuf), NULL);
+  g_return_val_if_fail (0 <= image->y && image->y < gdk_pixbuf_get_height (image->pixbuf), NULL);
+
+  if (display->closed)
+    xcursor = None;
+  else 
+    {
+      xcimage = convert_cursor_image (image);
+      xcursor = XcursorImageLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimage);
+      XcursorImageDestroy (xcimage);
+    }
+
+  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_images:
+ * @display: the #GdkDisplay for which the cursor will be created
+ * @images: the #GdkCursorImages<-- -->s containing the cursor images,
+ *    hotspots for each image, and times in milliseconds to show each
+ *    image.
+ * @n_images: the length of the @images array
+ *
+ * Creates a new animated cursor from an array of #GdkCursorImage. 
+ * 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_images (GdkDisplay      *display,
+			    GdkCursorImage **images,
+			    gint             n_images)
+{
+  XcursorImages *xcimages;
+  Cursor xcursor;
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+  gint i;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (images != NULL || n_images == 0, NULL);
+
+  xcursor = None;
+
+  if (!display->closed && n_images > 0)
+    {
+      xcimages = XcursorImagesCreate (n_images);
+      for (i = 0; i < n_images; i++) 
+	xcimages->images[i] = convert_cursor_image (images[i]);
+      xcimages->nimage = n_images;
+
+      xcursor = XcursorImagesLoadCursor (GDK_DISPLAY_XDISPLAY (display), xcimages);
+
+      for (i = 0; i < n_images; i++)
+	XcursorImageDestroy (xcimages->images[i]);
+      XcursorImagesDestroy (xcimages);
+    }
+
+  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_display_supports_cursor_animation:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if animated cursors are supported on @display.
+ *
+ * Returns: wether animated cursors are supported.
+ *
+ * Since: 2.4
+ */
+gboolean 
+gdk_display_supports_cursor_animation (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorSupportsAnim (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_supports_cursor_alpha:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if cursors can use an 8bit alpha channel 
+ * on @display. Otherwise, cursors are restricted to bilevel 
+ * alpha (i.e. a mask).
+ *
+ * Returns: wether cursors can have alpha channels.
+ *
+ * Since: 2.4
+ */
+gboolean 
+gdk_display_supports_cursor_alpha (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_supports_cursor_color:
+ * @display: a #GdkDisplay
+ *
+ * Returns %TRUE if multicolored cursors are supported
+ * on @display. Otherwise, cursors have only a forground
+ * and a background color.
+ *
+ * Returns: wether cursors can have multiple colors.
+ *
+ * Since: 2.4
+ */
+gboolean 
+gdk_display_supports_cursor_color (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorSupportsARGB (GDK_DISPLAY_XDISPLAY (display));
+}
+
+/**
+ * gdk_display_get_default_cursor_size:
+ * @display: a #GdkDisplay
+ *
+ * Returns the default size to use for cursors on @display.
+ *
+ * Returns: the default cursor size.
+ *
+ * Since: 2.4
+ */
+gint     
+gdk_display_get_default_cursor_size (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return XcursorGetDefaultSize (GDK_DISPLAY_XDISPLAY (display));
+}
+
+#else
+
+GdkCursor *
+gdk_cursor_new_from_image (GdkDisplay     *display, 
+			   GdkCursorImage *image)
+{
+  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 (image != NULL && GDK_IS_PIXBUF (image->pixbuf), NULL);
+
+  width = gdk_pixbuf_get_width (image->pixbuf);
+  height = gdk_pixbuf_get_height (image->pixbuf);
+
+  g_return_val_if_fail (0 <= image->x && image->x < width, NULL);
+  g_return_val_if_fail (0 <= image->y && image->y < height, NULL);
+
+  n_channels = gdk_pixbuf_get_n_channels (image->pixbuf);
+  rowstride = gdk_pixbuf_get_rowstride (image->pixbuf);
+  pixels = gdk_pixbuf_get_pixels (image->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, image->x, image->y);
+   
+  g_object_unref (pixmap);
+  g_object_unref (mask);
+  
+  return cursor;
+}
+
+GdkCursor* 
+gdk_cursor_new_from_images (GdkDisplay         *display,
+			    GdkCursorImage    **images,
+			     gint               n_images)
+{
+  GdkCursorPrivate *private;
+  GdkCursor *cursor;
+
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (images != NULL || n_images == 0, NULL);
+
+  if (n_images > 0)
+   cursor = gdk_cursor_new_from_pixbuf (display, images[0]->pixbuf, images[0]->x, images[0]->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;
+}
+
+gboolean 
+gdk_display_supports_cursor_animation (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return FALSE;
+
+}
+
+gboolean 
+gdk_display_supports_cursor_alpha (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return FALSE;
+}
+
+gboolean 
+gdk_display_supports_cursor_color (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  return FALSE;
+}
+
+gint     
+gdk_display_default_cursor_size (GdkDisplay    *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+  
+  /* no idea, really */
+  return 20; 
+}
+
+#endif
