changeset 2959:4eb2a8c07cb3

[xemacs-hg @ 2005-09-27 05:48:22 by ben] Implement color pixmap cursors glyphs.c, glyphs-eimage.c, glyphs-x.c, glyphs-gtk.c, glyphs-msw.c, console-impl.h: Allow all kinds of color images (GIF, JPEG, ...) to be mouse pointers. new -> new_, 'foo -> `foo'.
author ben
date Tue, 27 Sep 2005 05:48:27 +0000
parents 9e04ad6a1ac6
children 9151417c3852
files src/ChangeLog src/console-impl.h src/glyphs-eimage.c src/glyphs-gtk.c src/glyphs-msw.c src/glyphs-x.c src/glyphs.c
diffstat 7 files changed, 372 insertions(+), 251 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/ChangeLog	Tue Sep 27 05:48:27 2005 +0000
@@ -1,3 +1,36 @@
+2005-09-27  Ben Wing  <ben@xemacs.org>
+
+	* glyphs.c:
+	* glyphs.c (find_instantiator_differences):
+	* glyphs.c (Fvalid_image_instance_type_p):
+	* glyphs.c (Fimage_instance_type):
+	* glyphs.c (Fcolorize_image_instance):
+	* glyphs.c (Fglyph_type):
+	* glyphs.c (glyph_image_instance):
+	* glyphs.c (image_instantiator_format_create):
+	* glyphs-eimage.c:
+	* glyphs-eimage.c (jpeg_instantiate):
+	* glyphs-eimage.c (gif_instantiate):
+	* glyphs-eimage.c (png_instantiate):
+	* glyphs-eimage.c (tiff_instantiate):
+	* glyphs-x.c:
+	* glyphs-x.c (image_instance_convert_to_pointer):
+	* glyphs-x.c (init_image_instance_from_x_image):
+	* glyphs-x.c (x_init_image_instance_from_eimage):
+	* glyphs-x.c (x_xpm_instantiate):
+	* glyphs-x.c (x_colorize_image_instance):
+	* glyphs-gtk.c:
+	* glyphs-gtk.c (image_instance_convert_to_pointer):
+	* glyphs-gtk.c (init_image_instance_from_gdk_image):
+	* glyphs-gtk.c (gtk_init_image_instance_from_eimage):
+	* glyphs-gtk.c (gtk_xpm_instantiate):
+	* glyphs-msw.c:
+	* glyphs-msw.c (mswindows_init_image_instance_from_eimage):
+	* console-impl.h:
+	* console-impl.h (struct console_methods):
+	Allow all kinds of color images (GIF, JPEG, ...) to be mouse pointers.
+	new -> new_, 'foo -> `foo'.
+
 2005-09-27  Ben Wing  <ben@xemacs.org>
 
 	* Makefile.in.in (cppflags):
--- a/src/console-impl.h	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/console-impl.h	Tue Sep 27 05:48:27 2005 +0000
@@ -1,5 +1,5 @@
 /* Define console object for XEmacs.
-   Copyright (C) 1996, 2002, 2003 Ben Wing
+   Copyright (C) 1996, 2002, 2003, 2005 Ben Wing
 
 This file is part of XEmacs.
 
@@ -252,6 +252,8 @@
 						  unsigned char *eimage,
 						  int dest_mask,
 						  Lisp_Object instantiator,
+						  Lisp_Object pointer_fg,
+						  Lisp_Object pointer_bg,
 						  Lisp_Object domain);
   Lisp_Object (*locate_pixmap_file_method) (Lisp_Object file_method);
   int (*colorize_image_instance_method) (Lisp_Object image_instance,
--- a/src/glyphs-eimage.c	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/glyphs-eimage.c	Tue Sep 27 05:48:27 2005 +0000
@@ -2,7 +2,7 @@
    Copyright (C) 1993, 1994, 1998 Free Software Foundation, Inc.
    Copyright (C) 1995 Board of Trustees, University of Illinois.
    Copyright (C) 1995 Tinker Systems
-   Copyright (C) 1995, 1996, 2001, 2002, 2004 Ben Wing
+   Copyright (C) 1995, 1996, 2001, 2002, 2004, 2005 Ben Wing
    Copyright (C) 1995 Sun Microsystems
 
 This file is part of XEmacs.
@@ -24,22 +24,16 @@
 
 /* Synched up with: Not in FSF. */
 
-/* Original author: Jamie Zawinski for 19.8
-   font-truename stuff added by Jamie Zawinski for 19.10
-   subwindow support added by Chuck Thompson
-   additional XPM support added by Chuck Thompson
-   initial X-Face support added by Stig
-   rewritten/restructured by Ben Wing for 19.12/19.13
+/* Originally part of glyphs.c.
+
    GIF/JPEG support added by Ben Wing for 19.14
    PNG support added by Bill Perry for 19.14
    Improved GIF/JPEG support added by Bill Perry for 19.14
    Cleanup/simplification of error handling by Ben Wing for 19.14
-   Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
    GIF support changed to external Gifreader lib by Jareth Hein for 21.0
    Many changes for color work and optimizations by Jareth Hein for 21.0
    Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
    TIFF code by Jareth Hein for 21.0
-   Generalization for ms-windows by Andy Piper for 21.0
    TODO:
    Convert images.el to C and stick it in here?
  */
@@ -325,8 +319,7 @@
    source code and from gif_instantiate() */
 static void
 jpeg_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
-		  Lisp_Object UNUSED (pointer_fg),
-		  Lisp_Object UNUSED (pointer_bg),
+		  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
 		  int dest_mask, Lisp_Object domain)
 {
   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
@@ -500,7 +493,7 @@
 		 init_image_instance_from_eimage,
 		 (ii, cinfo.output_width, cinfo.output_height, 1,
 		  unwind.eimage, dest_mask,
-		  instantiator, domain));
+		  instantiator, pointer_fg, pointer_bg, domain));
 
   /* Step 7: Finish decompression */
 
@@ -614,8 +607,7 @@
 
 static void
 gif_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
-		 Lisp_Object UNUSED (pointer_fg),
-		 Lisp_Object UNUSED (pointer_bg),
+		 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
 		 int dest_mask, Lisp_Object domain)
 {
   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
@@ -729,8 +721,9 @@
     /* now instantiate */
     MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain),
 		   init_image_instance_from_eimage,
-		   (ii, width, height, unwind.giffile->ImageCount, unwind.eimage, dest_mask,
-		    instantiator, domain));
+		   (ii, width, height, unwind.giffile->ImageCount,
+		    unwind.eimage, dest_mask, instantiator, pointer_fg,
+		    pointer_bg, domain));
   }
 
   /* We read the gif successfully. If we have more than one slice then
@@ -864,8 +857,7 @@
 
 static void
 png_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
-		 Lisp_Object UNUSED (pointer_fg),
-		 Lisp_Object UNUSED (pointer_bg),
+		 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
 		 int dest_mask, Lisp_Object domain)
 {
   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
@@ -1046,7 +1038,7 @@
   MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain),
 		 init_image_instance_from_eimage,
 		 (ii, width, height, 1, unwind.eimage, dest_mask,
-		  instantiator, domain));
+		  instantiator, pointer_fg, pointer_bg, domain));
 
   /* This will clean up everything else. */
   unbind_to (speccount);
@@ -1242,8 +1234,7 @@
 
 static void
 tiff_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
-		  Lisp_Object UNUSED (pointer_fg),
-		  Lisp_Object UNUSED (pointer_bg),
+		  Lisp_Object pointer_fg, Lisp_Object pointer_bg,
 		  int dest_mask, Lisp_Object domain)
 {
   Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
@@ -1336,7 +1327,7 @@
   MAYBE_DEVMETH (DOMAIN_XDEVICE (ii->domain),
 		 init_image_instance_from_eimage,
 		 (ii, width, height, 1, unwind.eimage, dest_mask,
-		  instantiator, domain));
+		  instantiator, pointer_fg, pointer_bg, domain));
 
   unbind_to (speccount);
 }
--- a/src/glyphs-gtk.c	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/glyphs-gtk.c	Tue Sep 27 05:48:27 2005 +0000
@@ -2,7 +2,7 @@
    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Board of Trustees, University of Illinois.
    Copyright (C) 1995 Tinker Systems
-   Copyright (C) 1995, 1996, 2001, 2002, 2004 Ben Wing
+   Copyright (C) 1995, 1996, 2001, 2002, 2004, 2005 Ben Wing
    Copyright (C) 1995 Sun Microsystems
 
 This file is part of XEmacs.
@@ -677,6 +677,51 @@
 /*                        color pixmap functions                        */
 /************************************************************************/
 
+/* Create a pointer from a color pixmap. */
+
+static void
+image_instance_convert_to_pointer (Lisp_Image_Instance *ii,
+				   Lisp_Object instantiator,
+				   Lisp_Object pointer_fg,
+				   Lisp_Object pointer_bg)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  GdkPixmap *pixmap = IMAGE_INSTANCE_X_PIXMAP (ii);
+  GdkPixmap *mask = (GdkPixmap *) IMAGE_INSTANCE_PIXMAP_MASK (ii);
+  GdkColor fg, bg;
+  int xhot = 0, yhot = 0;
+  int w, h;
+
+  if (INTP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)))
+    xhot = XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii));
+  if (INTP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)))
+    yhot = XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii));
+  w = IMAGE_INSTANCE_PIXMAP_WIDTH (ii);
+  h = IMAGE_INSTANCE_PIXMAP_HEIGHT (ii);
+
+  check_pointer_sizes (w, h, instantiator);
+
+  /* If the loaded pixmap has colors allocated (meaning it came from an
+     XPM file), then use those as the default colors for the cursor we
+     create.  Otherwise, default to pointer_fg and pointer_bg.
+  */
+  if (DEVICE_GTK_DEPTH (XDEVICE (device)) > 1)
+    {
+      warn_when_safe (Qunimplemented, Qnotice,
+		      "GTK does not support XPM cursors...\n");
+      IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (GDK_COFFEE_MUG);
+    }
+  else
+    {
+      generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
+			     &fg, &bg);
+      IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
+      IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
+      IMAGE_INSTANCE_GTK_CURSOR (ii) =
+	gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, xhot, yhot);
+    }
+}
+
 /* Initialize an image instance from an XImage.
 
    DEST_MASK specifies the mask of allowed image types.
@@ -705,21 +750,29 @@
 				    unsigned long *pixels,
 				    int npixels,
 				    int slices,
-				    Lisp_Object instantiator)
+				    Lisp_Object instantiator,
+				    Lisp_Object pointer_fg,
+				    Lisp_Object pointer_bg)
 {
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
   GdkGC *gc;
   GdkWindow *d;
   GdkPixmap *pixmap;
+  enum image_instance_type type;
 
   if (!DEVICE_GTK_P (XDEVICE (device)))
     gui_error ("Not a Gtk device", device);
 
   d = GET_GTK_WIDGET_WINDOW (DEVICE_GTK_APP_SHELL (XDEVICE (device)));
 
-  if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
+  if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
+    type = IMAGE_COLOR_PIXMAP;
+  else if (dest_mask & IMAGE_POINTER_MASK)
+    type = IMAGE_POINTER;
+  else
     incompatible_image_types (instantiator, dest_mask,
-			      IMAGE_COLOR_PIXMAP_MASK);
+			      IMAGE_COLOR_PIXMAP_MASK
+			      | IMAGE_POINTER_MASK);
 
   pixmap = gdk_pixmap_new (d, gdk_image->width, gdk_image->height, gdk_image->depth);
   if (!pixmap)
@@ -750,6 +803,10 @@
   IMAGE_INSTANCE_GTK_COLORMAP (ii) = cmap;
   IMAGE_INSTANCE_GTK_PIXELS (ii) = pixels;
   IMAGE_INSTANCE_GTK_NPIXELS (ii) = npixels;
+
+  if (type == IMAGE_POINTER)
+    image_instance_convert_to_pointer (ii, instantiator, pointer_fg,
+				       pointer_bg);
 }
 
 #if 0
@@ -831,6 +888,8 @@
 				     unsigned char *eimage, 
 				     int dest_mask,
 				     Lisp_Object instantiator,
+				     Lisp_Object pointer_fg,
+				     Lisp_Object pointer_bg,
 				     Lisp_Object UNUSED (domain))
 {
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
@@ -856,7 +915,8 @@
 	/* Now create the pixmap and set up the image instance */
 	init_image_instance_from_gdk_image (ii, gdk_image, dest_mask,
 					    cmap, pixtbl, npixels, slices,
-					    instantiator);
+					    instantiator, pointer_fg,
+					    pointer_bg);
       else
 	image_instance_add_gdk_image (ii, gdk_image, slice, instantiator);
 
@@ -1269,38 +1329,13 @@
       break;
 
     case IMAGE_POINTER:
-      {
-	GdkColor fg, bg;
-	unsigned int xhot, yhot;
-
-	/* #### Gtk does not give us access to the hotspots of a pixmap */
-	xhot = yhot = 1;
-	IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = make_int (xhot);
-	IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = make_int (yhot);
-
-	check_pointer_sizes (w, h, instantiator);
-
-	/* If the loaded pixmap has colors allocated (meaning it came from an
-	   XPM file), then use those as the default colors for the cursor we
-	   create.  Otherwise, default to pointer_fg and pointer_bg.
-	*/
-	if (depth > 1)
-	  {
-	    warn_when_safe (Qunimplemented, Qnotice,
-			    "GTK does not support XPM cursors...\n");
-	    IMAGE_INSTANCE_GTK_CURSOR (ii) = gdk_cursor_new (GDK_COFFEE_MUG);
-	  }
-	else
-	  {
-	    generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
-				   &fg, &bg);
-	    IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
-	    IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
-	    IMAGE_INSTANCE_GTK_CURSOR (ii) =
-	      gdk_cursor_new_from_pixmap (pixmap, mask, &fg, &bg, xhot, yhot);
-	  }
-      }
-
+      if (xpmattrs.valuemask & XpmHotspot)
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = make_int (xpmattrs.x_hotspot);
+      if (xpmattrs.valuemask & XpmHotspot)
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = make_int (xpmattrs.y_hotspot);
+      
+      image_instance_convert_to_pointer (ii, instantiator, pointer_fg,
+					 pointer_bg);
       break;
 
     default:
--- a/src/glyphs-msw.c	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/glyphs-msw.c	Tue Sep 27 05:48:27 2005 +0000
@@ -1,6 +1,6 @@
 /* mswindows-specific glyph objects.
    Copyright (C) 1998, 1999, 2000 Andy Piper.
-   Copyright (C) 2001, 2002, 2003, 2004 Ben Wing.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005 Ben Wing.
 
 This file is part of XEmacs.
 
@@ -436,6 +436,8 @@
 					   Binbyte *eimage,
 					   int dest_mask,
 					   Lisp_Object instantiator,
+					   Lisp_Object UNUSED (pointer_fg),
+					   Lisp_Object UNUSED (pointer_bg),
 					   Lisp_Object domain)
 {
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
--- a/src/glyphs-x.c	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/glyphs-x.c	Tue Sep 27 05:48:27 2005 +0000
@@ -2,7 +2,7 @@
    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
    Copyright (C) 1995 Board of Trustees, University of Illinois.
    Copyright (C) 1995 Tinker Systems
-   Copyright (C) 1995, 1996, 2001, 2002, 2003, 2004 Ben Wing
+   Copyright (C) 1995, 1996, 2001, 2002, 2003, 2004, 2005 Ben Wing
    Copyright (C) 1995 Sun Microsystems
    Copyright (C) 1999, 2000, 2002 Andy Piper
 
@@ -724,6 +724,159 @@
 /*                        color pixmap functions                        */
 /************************************************************************/
 
+/* Create a pointer from a color pixmap. */
+
+static void
+image_instance_convert_to_pointer (Lisp_Image_Instance *ii,
+				   Lisp_Object instantiator,
+				   Lisp_Object pointer_fg,
+				   Lisp_Object pointer_bg)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  Display *dpy = DEVICE_X_DISPLAY (XDEVICE (device));
+  Screen *xs = DefaultScreenOfDisplay (dpy);
+  int npixels = IMAGE_INSTANCE_X_NPIXELS (ii);
+  unsigned long *pixels = IMAGE_INSTANCE_X_PIXELS (ii);
+  Pixmap pixmap = IMAGE_INSTANCE_X_PIXMAP (ii);
+  Pixmap mask = (Pixmap) IMAGE_INSTANCE_PIXMAP_MASK (ii);
+  Colormap cmap;
+  XColor fg, bg;
+  int i;
+  int xhot = 0, yhot = 0;
+  int w, h;
+
+  if (INTP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii)))
+    xhot = XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii));
+  if (INTP (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii)))
+    yhot = XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii));
+  w = IMAGE_INSTANCE_PIXMAP_WIDTH (ii);
+  h = IMAGE_INSTANCE_PIXMAP_HEIGHT (ii);
+
+#if 1
+  /* Although I haven't found it documented yet, it appears that pointers are
+     always colored via the default window colormap... Sigh. */
+  cmap = DefaultColormap (dpy, DefaultScreen (dpy));
+  IMAGE_INSTANCE_X_COLORMAP (ii) = cmap;
+#else
+  cmap = IMAGE_INSTANCE_X_COLORMAP (ii);
+#endif
+
+  check_pointer_sizes (xs, w, h, instantiator);
+
+  /* If the loaded pixmap has colors allocated (meaning it came from an
+     XPM file), then use those as the default colors for the cursor we
+     create.  Otherwise, default to pointer_fg and pointer_bg.
+  */
+  if (npixels >= 2)
+    {
+      /* With an XBM file, it's obvious which bit is foreground
+	 and which is background, or rather, it's implicit: in
+	 an XBM file, a 1 bit is foreground, and a 0 bit is
+	 background.
+
+	 XCreatePixmapCursor() assumes this property of the
+	 pixmap it is called with as well; the `foreground'
+	 color argument is used for the 1 bits.
+
+	 With an XPM file, it's tricker, since the elements of
+	 the pixmap don't represent FG and BG, but are actual
+	 pixel values.  So we need to figure out which of those
+	 pixels is the foreground color and which is the
+	 background.  We do it by comparing RGB and assuming
+	 that the darker color is the foreground.  This works
+	 with the result of xbmtopbm|ppmtoxpm, at least.
+
+	 It might be nice if there was some way to tag the
+	 colors in the XPM file with whether they are the
+	 foreground - perhaps with logical color names somehow?
+
+	 Once we have decided which color is the foreground, we
+	 need to ensure that that color corresponds to a `1' bit
+	 in the Pixmap.  The XPM library wrote into the (1-bit)
+	 pixmap with XPutPixel, which will ignore all but the
+	 least significant bit.
+
+	 This means that a 1 bit in the image corresponds to
+	 `fg' only if `fg.pixel' is odd.
+
+	 (This also means that the image will be all the same
+	 color if both `fg' and `bg' are odd or even, but we can
+	 safely assume that that won't happen if the XPM file is
+	 sensible I think.)
+
+	 The desired result is that the image use `1' to
+	 represent the foreground color, and `0' to represent
+	 the background color.  So, we may need to invert the
+	 image to accomplish this; we invert if fg is
+	 odd. (Remember that WhitePixel and BlackPixel are not
+	 necessarily 1 and 0 respectively, though I think it
+	 might be safe to assume that one of them is always 1
+	 and the other is always 0.  We also pretty much need to
+	 assume that one is even and the other is odd.)
+      */
+
+      fg.pixel = pixels[0];	/* pick a pixel at random. */
+      bg.pixel = fg.pixel;
+      for (i = 1; i < npixels; i++) /* Look for an "other" pixel value.*/
+	{
+	  bg.pixel = pixels[i];
+	  if (fg.pixel != bg.pixel)
+	    break;
+	}
+
+      /* If (fg.pixel == bg.pixel) then probably something has
+	 gone wrong, but I don't think signalling an error would
+	 be appropriate. */
+
+      XQueryColor (dpy, cmap, &fg);
+      XQueryColor (dpy, cmap, &bg);
+
+      /* If the foreground is lighter than the background, swap them.
+	 (This occurs semi-randomly, depending on the ordering of the
+	 color list in the XPM file.)
+      */
+      {
+	unsigned short fg_total = ((fg.red / 3) + (fg.green / 3)
+				   + (fg.blue / 3));
+	unsigned short bg_total = ((bg.red / 3) + (bg.green / 3)
+				   + (bg.blue / 3));
+	if (fg_total > bg_total)
+	  {
+	    XColor swap;
+	    swap = fg;
+	    fg = bg;
+	    bg = swap;
+	  }
+      }
+
+      /* If the fg pixel corresponds to a `0' in the bitmap, invert it.
+	 (This occurs (only?) on servers with Black=0, White=1.)
+      */
+      if ((fg.pixel & 1) == 0)
+	{
+	  XGCValues gcv;
+	  GC gc;
+	  gcv.function = GXxor;
+	  gcv.foreground = 1;
+	  gc = XCreateGC (dpy, pixmap, (GCFunction | GCForeground),
+			  &gcv);
+	  XFillRectangle (dpy, pixmap, gc, 0, 0, w, h);
+	  XFreeGC (dpy, gc);
+	}
+    }
+  else
+    {
+      generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
+			     &fg, &bg);
+      IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
+      IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
+    }
+
+  IMAGE_INSTANCE_X_CURSOR (ii) =
+    XCreatePixmapCursor
+    (dpy, pixmap, mask, &fg, &bg, xhot, yhot);
+}
+
 /* Initialize an image instance from an XImage.
 
    DEST_MASK specifies the mask of allowed image types.
@@ -740,9 +893,7 @@
 
    If this fails, signal an error.  INSTANTIATOR is only used
    in the error message.
-
-   #### This should be able to handle conversion into `pointer'.
-   Use the same code as for `xpm'. */
+*/
 
 static void
 init_image_instance_from_x_image (Lisp_Image_Instance *ii,
@@ -752,23 +903,31 @@
 				  unsigned long *pixels,
 				  int npixels,
 				  int slices,
-				  Lisp_Object instantiator)
+				  Lisp_Object instantiator,
+				  Lisp_Object pointer_fg,
+				  Lisp_Object pointer_bg)
 {
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
   Display *dpy;
   GC gc;
   Drawable d;
   Pixmap pixmap;
+  enum image_instance_type type;
 
   if (!DEVICE_X_P (XDEVICE (device)))
     gui_error ("Not an X device", device);
 
   dpy = DEVICE_X_DISPLAY (XDEVICE (device));
-  d = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (device)));
-
-  if (!(dest_mask & IMAGE_COLOR_PIXMAP_MASK))
+  d = XtWindow (DEVICE_XT_APP_SHELL (XDEVICE (device)));
+
+  if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
+    type = IMAGE_COLOR_PIXMAP;
+  else if (dest_mask & IMAGE_POINTER_MASK)
+    type = IMAGE_POINTER;
+  else
     incompatible_image_types (instantiator, dest_mask,
-			      IMAGE_COLOR_PIXMAP_MASK);
+			      IMAGE_COLOR_PIXMAP_MASK
+			      | IMAGE_POINTER_MASK);
 
   pixmap = XCreatePixmap (dpy, d, ximage->width,
 			  ximage->height, ximage->depth);
@@ -802,6 +961,10 @@
   IMAGE_INSTANCE_X_COLORMAP (ii) = cmap;
   IMAGE_INSTANCE_X_PIXELS (ii) = pixels;
   IMAGE_INSTANCE_X_NPIXELS (ii) = npixels;
+
+  if (type == IMAGE_POINTER)
+    image_instance_convert_to_pointer (ii, instantiator, pointer_fg,
+				       pointer_bg);
 }
 
 static void
@@ -846,6 +1009,8 @@
 				   Binbyte *eimage,
 				   int dest_mask,
 				   Lisp_Object instantiator,
+				   Lisp_Object pointer_fg,
+				   Lisp_Object pointer_bg,
 				   Lisp_Object UNUSED (domain))
 {
   Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
@@ -864,14 +1029,16 @@
 	{
 	  if (pixtbl)
 	    xfree (pixtbl, unsigned long *);
-	  signal_image_error("EImage to XImage conversion failed", instantiator);
+	  signal_image_error ("EImage to XImage conversion failed",
+			      instantiator);
 	}
 
       /* Now create the pixmap and set up the image instance */
       if (slice == 0)
 	init_image_instance_from_x_image (ii, ximage, dest_mask,
 					  cmap, pixtbl, npixels, slices,
-					  instantiator);
+					  instantiator, pointer_fg,
+					  pointer_bg);
       else
 	image_instance_add_x_image (ii, ximage, slice, instantiator);
 
@@ -1236,20 +1403,20 @@
      always colored via the default window colormap... Sigh. */
   if (type == IMAGE_POINTER)
     {
-      cmap = DefaultColormap(dpy, DefaultScreen(dpy));
+      cmap = DefaultColormap (dpy, DefaultScreen (dpy));
       depth = DefaultDepthOfScreen (xs);
       visual = DefaultVisualOfScreen (xs);
     }
   else
     {
-      cmap = DEVICE_X_COLORMAP (XDEVICE(device));
-      depth = DEVICE_X_DEPTH (XDEVICE(device));
-      visual = DEVICE_X_VISUAL (XDEVICE(device));
+      cmap = DEVICE_X_COLORMAP (XDEVICE (device));
+      depth = DEVICE_X_DEPTH (XDEVICE (device));
+      visual = DEVICE_X_VISUAL (XDEVICE (device));
     }
 #else
-  cmap = DEVICE_X_COLORMAP (XDEVICE(device));
-  depth = DEVICE_X_DEPTH (XDEVICE(device));
-  visual = DEVICE_X_VISUAL (XDEVICE(device));
+  cmap = DEVICE_X_COLORMAP (XDEVICE (device));
+  depth = DEVICE_X_DEPTH (XDEVICE (device));
+  visual = DEVICE_X_VISUAL (XDEVICE (device));
 #endif
 
   x_initialize_pixmap_image_instance (ii, 1, type);
@@ -1382,145 +1549,17 @@
       break;
 
     case IMAGE_COLOR_PIXMAP:
-      {
-	IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth;
-      }
+      IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = depth;
       break;
 
     case IMAGE_POINTER:
-      {
-	int npixels = xpmattrs.npixels;
-	Pixel *pixels = xpmattrs.pixels;
-	XColor fg, bg;
-	int i;
-	int xhot = 0, yhot = 0;
-
-	if (xpmattrs.valuemask & XpmHotspot)
-	  {
-	    xhot = xpmattrs.x_hotspot;
-	    IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = make_int (xpmattrs.x_hotspot);
-	  }
-	if (xpmattrs.valuemask & XpmHotspot)
-	  {
-	    yhot = xpmattrs.y_hotspot;
-	    IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = make_int (xpmattrs.y_hotspot);
-	  }
-	check_pointer_sizes (xs, w, h, instantiator);
-
-	/* If the loaded pixmap has colors allocated (meaning it came from an
-	   XPM file), then use those as the default colors for the cursor we
-	   create.  Otherwise, default to pointer_fg and pointer_bg.
-	   */
-	if (npixels >= 2)
-	  {
-	    /* With an XBM file, it's obvious which bit is foreground
-	       and which is background, or rather, it's implicit: in
-	       an XBM file, a 1 bit is foreground, and a 0 bit is
-	       background.
-
-	       XCreatePixmapCursor() assumes this property of the
-	       pixmap it is called with as well; the `foreground'
-	       color argument is used for the 1 bits.
-
-	       With an XPM file, it's tricker, since the elements of
-	       the pixmap don't represent FG and BG, but are actual
-	       pixel values.  So we need to figure out which of those
-	       pixels is the foreground color and which is the
-	       background.  We do it by comparing RGB and assuming
-	       that the darker color is the foreground.  This works
-	       with the result of xbmtopbm|ppmtoxpm, at least.
-
-	       It might be nice if there was some way to tag the
-	       colors in the XPM file with whether they are the
-	       foreground - perhaps with logical color names somehow?
-
-	       Once we have decided which color is the foreground, we
-	       need to ensure that that color corresponds to a `1' bit
-	       in the Pixmap.  The XPM library wrote into the (1-bit)
-	       pixmap with XPutPixel, which will ignore all but the
-	       least significant bit.
-
-	       This means that a 1 bit in the image corresponds to
-	       `fg' only if `fg.pixel' is odd.
-
-	       (This also means that the image will be all the same
-	       color if both `fg' and `bg' are odd or even, but we can
-	       safely assume that that won't happen if the XPM file is
-	       sensible I think.)
-
-	       The desired result is that the image use `1' to
-	       represent the foreground color, and `0' to represent
-	       the background color.  So, we may need to invert the
-	       image to accomplish this; we invert if fg is
-	       odd. (Remember that WhitePixel and BlackPixel are not
-	       necessarily 1 and 0 respectively, though I think it
-	       might be safe to assume that one of them is always 1
-	       and the other is always 0.  We also pretty much need to
-	       assume that one is even and the other is odd.)
-	       */
-
-	    fg.pixel = pixels[0];	/* pick a pixel at random. */
-	    bg.pixel = fg.pixel;
-	    for (i = 1; i < npixels; i++) /* Look for an "other" pixel value.*/
-	      {
-		bg.pixel = pixels[i];
-		if (fg.pixel != bg.pixel)
-		  break;
-	      }
-
-	    /* If (fg.pixel == bg.pixel) then probably something has
-	       gone wrong, but I don't think signalling an error would
-	       be appropriate. */
-
-	    XQueryColor (dpy, cmap, &fg);
-	    XQueryColor (dpy, cmap, &bg);
-
-	    /* If the foreground is lighter than the background, swap them.
-	       (This occurs semi-randomly, depending on the ordering of the
-	       color list in the XPM file.)
-	       */
-	    {
-	      unsigned short fg_total = ((fg.red / 3) + (fg.green / 3)
-					 + (fg.blue / 3));
-	      unsigned short bg_total = ((bg.red / 3) + (bg.green / 3)
-					 + (bg.blue / 3));
-	      if (fg_total > bg_total)
-		{
-		  XColor swap;
-		  swap = fg;
-		  fg = bg;
-		  bg = swap;
-		}
-	    }
-
-	    /* If the fg pixel corresponds to a `0' in the bitmap, invert it.
-	       (This occurs (only?) on servers with Black=0, White=1.)
-	       */
-	    if ((fg.pixel & 1) == 0)
-	      {
-		XGCValues gcv;
-		GC gc;
-		gcv.function = GXxor;
-		gcv.foreground = 1;
-		gc = XCreateGC (dpy, pixmap, (GCFunction | GCForeground),
-				&gcv);
-		XFillRectangle (dpy, pixmap, gc, 0, 0, w, h);
-		XFreeGC (dpy, gc);
-	      }
-	  }
-	else
-	  {
-	    generate_cursor_fg_bg (device, &pointer_fg, &pointer_bg,
-				   &fg, &bg);
-	    IMAGE_INSTANCE_PIXMAP_FG (ii) = pointer_fg;
-	    IMAGE_INSTANCE_PIXMAP_BG (ii) = pointer_bg;
-	  }
-
-	IMAGE_INSTANCE_X_CURSOR (ii) =
-	  XCreatePixmapCursor
-	    (dpy, pixmap, mask, &fg, &bg, xhot, yhot);
-      }
-
+      if (xpmattrs.valuemask & XpmHotspot)
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = make_int (xpmattrs.x_hotspot);
+      if (xpmattrs.valuemask & XpmHotspot)
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = make_int (xpmattrs.y_hotspot);
+      
+      image_instance_convert_to_pointer (ii, instantiator, pointer_fg,
+					 pointer_bg);
       break;
 
     default:
@@ -1986,7 +2025,7 @@
     Display *dpy = DEVICE_X_DISPLAY (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
     Drawable draw = XtWindow(DEVICE_XT_APP_SHELL (XDEVICE (IMAGE_INSTANCE_DEVICE (p))));
     Dimension d = DEVICE_X_DEPTH (XDEVICE (IMAGE_INSTANCE_DEVICE (p)));
-    Pixmap new = XCreatePixmap (dpy, draw,
+    Pixmap new_ = XCreatePixmap (dpy, draw,
 				IMAGE_INSTANCE_PIXMAP_WIDTH (p),
 				IMAGE_INSTANCE_PIXMAP_HEIGHT (p), d);
     XColor color;
@@ -1996,13 +2035,13 @@
     gcv.foreground = color.pixel;
     color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (background));
     gcv.background = color.pixel;
-    gc = XCreateGC (dpy, new, GCBackground|GCForeground, &gcv);
-    XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), new, gc, 0, 0,
+    gc = XCreateGC (dpy, new_, GCBackground|GCForeground, &gcv);
+    XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), new_, gc, 0, 0,
 		IMAGE_INSTANCE_PIXMAP_WIDTH (p),
 		IMAGE_INSTANCE_PIXMAP_HEIGHT (p),
 		0, 0, 1);
     XFreeGC (dpy, gc);
-    IMAGE_INSTANCE_X_PIXMAP (p) = new;
+    IMAGE_INSTANCE_X_PIXMAP (p) = new_;
     IMAGE_INSTANCE_PIXMAP_DEPTH (p) = d;
     IMAGE_INSTANCE_PIXMAP_FG (p) = foreground;
     IMAGE_INSTANCE_PIXMAP_BG (p) = background;
--- a/src/glyphs.c	Tue Sep 27 05:35:26 2005 +0000
+++ b/src/glyphs.c	Tue Sep 27 05:48:27 2005 +0000
@@ -1,7 +1,7 @@
 /* Generic glyph/image implementation + display tables
    Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
    Copyright (C) 1995 Tinker Systems
-   Copyright (C) 1995, 1996, 2000, 2001, 2002, 2004 Ben Wing
+   Copyright (C) 1995, 1996, 2000, 2001, 2002, 2004, 2005 Ben Wing
    Copyright (C) 1995 Sun Microsystems
    Copyright (C) 1998, 1999, 2000 Andy Piper
 
@@ -24,8 +24,24 @@
 
 /* Synched up with: Not in FSF. */
 
-/* Written by Ben Wing and Chuck Thompson. Heavily modified /
-   rewritten by Andy Piper. */
+/* This file mostly written by Ben Wing, with some code by Chuck Thompson.
+   Heavily modified / rewritten by Andy Piper.
+
+   Earliest glyph support, Jamie Zawinski for 19.8?
+   subwindow support added by Chuck Thompson
+   additional XPM support added by Chuck Thompson
+   initial X-Face support added by Stig
+   Majorly rewritten/restructured by Ben Wing, including creation of
+   glyph and image-instance objects, for 19.12/19.13
+   GIF/JPEG/etc. support originally in this file -- see glyph-eimage.c
+   Pointer/icon overhaul, more restructuring by Ben Wing for 19.14
+   Many changes for color work and optimizations by Jareth Hein for 21.0
+   Switch of GIF/JPEG/PNG to new EImage intermediate code by Jareth Hein for 21.0
+   TIFF code by Jareth Hein for 21.0
+   Generalization for ms-windows by Andy Piper for 21.0
+   TODO:
+   Convert images.el to C and stick it in here?
+ */
 
 #include <config.h>
 #include "lisp.h"
@@ -232,12 +248,12 @@
 If LOCALE is non-nil then the format is checked in that locale.
 If LOCALE is nil the current console is used.
 
-Valid formats are some subset of 'nothing, 'string, 'formatted-string,
-'xpm, 'xbm, 'xface, 'gif, 'jpeg, 'png, 'tiff, 'cursor-font, 'font,
-'autodetect, 'subwindow, 'inherit, 'mswindows-resource, 'bmp,
-'native-layout, 'layout, 'label, 'tab-control, 'tree-view,
-'progress-gauge, 'scrollbar, 'combo-box, 'edit-field, 'button,
-'widget, 'pointer, and 'text, depending on how XEmacs was compiled.
+Valid formats are some subset of `nothing', `string', `formatted-string',
+`xpm', `xbm', `xface', `gif', `jpeg', `png', `tiff', `cursor-font', `font',
+`autodetect', `subwindow', `inherit', `mswindows-resource', `bmp',
+`native-layout', `layout', `label', `tab-control', `tree-view',
+`progress-gauge', `scrollbar', `combo-box', `edit-field', `button',
+`widget', `pointer', and `text', depending on how XEmacs was compiled.
 */
        (image_instantiator_format, locale))
 {
@@ -437,12 +453,12 @@
 }
 
 static Lisp_Object
-find_instantiator_differences (Lisp_Object new, Lisp_Object old)
+find_instantiator_differences (Lisp_Object new_, Lisp_Object old)
 {
   Lisp_Object alist = Qnil;
-  Lisp_Object *elt = XVECTOR_DATA (new);
+  Lisp_Object *elt = XVECTOR_DATA (new_);
   Lisp_Object *old_elt = XVECTOR_DATA (old);
-  int len = XVECTOR_LENGTH (new);
+  int len = XVECTOR_LENGTH (new_);
   struct gcpro gcpro1;
 
   /* If the vector length has changed then consider everything
@@ -450,7 +466,7 @@
      disappeared or been added, but this code is only used as an
      optimization anyway so lets not bother. */
   if (len != XVECTOR_LENGTH (old))
-    return new;
+    return new_;
 
   GCPRO1 (alist);
 
@@ -1450,8 +1466,9 @@
 
 DEFUN ("valid-image-instance-type-p", Fvalid_image_instance_type_p, 1, 1, 0, /*
 Given an IMAGE-INSTANCE-TYPE, return non-nil if it is valid.
-Valid types are some subset of 'nothing, 'text, 'mono-pixmap, 'color-pixmap,
-'pointer, 'subwindow, and 'widget, depending on how XEmacs was compiled.
+Valid types are some subset of `nothing', `text', `mono-pixmap',
+`color-pixmap', `pointer', `subwindow', and `widget', depending on how
+XEmacs was compiled.
 */
        (image_instance_type))
 {
@@ -1550,27 +1567,27 @@
 DEST-TYPES should be a list of allowed image instance types that can
 be generated.  The recognized image instance types are
 
-'nothing
+`nothing'
   Nothing is displayed.
-'text
+`text'
   Displayed as text.  The foreground and background colors and the
   font of the text are specified independent of the pixmap.  Typically
   these attributes will come from the face of the surrounding text,
   unless a face is specified for the glyph in which the image appears.
-'mono-pixmap
+`mono-pixmap'
   Displayed as a mono pixmap (a pixmap with only two colors where the
   foreground and background can be specified independent of the pixmap;
   typically the pixmap assumes the foreground and background colors of
   the text around it, unless a face is specified for the glyph in which
   the image appears).
-'color-pixmap
+`color-pixmap'
   Displayed as a color pixmap.
-'pointer
+`pointer'
   Used as the mouse pointer for a window.
-'subwindow
+`subwindow'
   A child window that is treated as an image.  This allows (e.g.)
   another program to be responsible for drawing into the window.
-'widget
+`widget'
   A child window that contains a window-system widget, e.g. a push
   button, text field, or slider.
 
@@ -1648,8 +1665,8 @@
 
 DEFUN ("image-instance-type", Fimage_instance_type, 1, 1, 0, /*
 Return the type of the given image instance.
-The return value will be one of 'nothing, 'text, 'mono-pixmap,
-'color-pixmap, 'pointer, 'subwindow, or 'widget.
+The return value will be one of `nothing', `text', `mono-pixmap',
+`color-pixmap', `pointer', `subwindow', or `widget'.
 */
        (image_instance))
 {
@@ -1964,7 +1981,7 @@
 */
        (image_instance, foreground, background))
 {
-  Lisp_Object new;
+  Lisp_Object new_;
   Lisp_Object device;
 
   CHECK_IMAGE_INSTANCE (image_instance);
@@ -1978,20 +1995,20 @@
 
   /* #### There should be a copy_image_instance(), which calls a
      device-specific method to copy the window-system subobject. */
-  new = allocate_image_instance (XIMAGE_INSTANCE_DOMAIN (image_instance),
+  new_ = allocate_image_instance (XIMAGE_INSTANCE_DOMAIN (image_instance),
 				 Qnil, Qnil);
 #ifdef MC_ALLOC
-  copy_lrecord (XIMAGE_INSTANCE (new), XIMAGE_INSTANCE (image_instance));
+  copy_lrecord (XIMAGE_INSTANCE (new_), XIMAGE_INSTANCE (image_instance));
 #else /* not MC_ALLOC */
-  copy_lcrecord (XIMAGE_INSTANCE (new), XIMAGE_INSTANCE (image_instance));
+  copy_lcrecord (XIMAGE_INSTANCE (new_), XIMAGE_INSTANCE (image_instance));
 #endif /* not MC_ALLOC */
   /* note that if this method returns non-zero, this method MUST
      copy any window-system resources, so that when one image instance is
      freed, the other one is not hosed. */
-  if (!DEVMETH (XDEVICE (device), colorize_image_instance, (new, foreground,
+  if (!DEVMETH (XDEVICE (device), colorize_image_instance, (new_, foreground,
 							    background)))
     return image_instance;
-  return new;
+  return new_;
 }
 
 
@@ -3942,7 +3959,7 @@
 
 DEFUN ("glyph-type", Fglyph_type, 1, 1, 0, /*
 Return the type of the given glyph.
-The return value will be one of 'buffer, 'pointer, or 'icon.
+The return value will be one of `buffer', `pointer', or `icon'.
 */
        (glyph))
 {
@@ -3962,7 +3979,7 @@
 {
   Lisp_Object specifier = GLYPH_IMAGE (XGLYPH (glyph));
 
-  /* This can never return Qunbound.  All glyphs have 'nothing as
+  /* This can never return Qunbound.  All glyphs have `nothing' as
      a fallback. */
   Lisp_Object image_instance = specifier_instance (specifier, Qunbound,
 						   domain, errb, no_quit, 0,
@@ -5401,6 +5418,8 @@
 
   IIFORMAT_VALID_KEYWORD (xface, Q_data, check_valid_string);
   IIFORMAT_VALID_KEYWORD (xface, Q_file, check_valid_string);
+  IIFORMAT_VALID_KEYWORD (xface, Q_mask_data, check_valid_xbm_inline);
+  IIFORMAT_VALID_KEYWORD (xface, Q_mask_file, check_valid_string);
   IIFORMAT_VALID_KEYWORD (xface, Q_hotspot_x, check_valid_int);
   IIFORMAT_VALID_KEYWORD (xface, Q_hotspot_y, check_valid_int);
   IIFORMAT_VALID_KEYWORD (xface, Q_foreground, check_valid_string);