diff src/glyphs-msw.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children a5df635868b2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/glyphs-msw.c	Mon Aug 13 11:28:15 2007 +0200
@@ -0,0 +1,3012 @@
+/* mswindows-specific glyph objects.
+   Copyright (C) 1998, 1999 Andy Piper.
+   
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with: Not in FSF. */
+
+/* written by Andy Piper <andy@xemacs.org> plagerising bits from
+   glyphs-x.c */
+
+#include <config.h>
+#include "lisp.h"
+#include "lstream.h"
+
+#define OEMRESOURCE /* Define OCR_ and friend constants */
+#include "console-msw.h"
+#include "glyphs-msw.h"
+#include "objects-msw.h"
+
+#include "window.h"
+#include "elhash.h"
+#include "buffer.h"
+#include "frame.h"
+#include "insdel.h"
+#include "opaque.h"
+#include "sysfile.h"
+#include "faces.h"
+#include "imgproc.h"
+
+#ifdef FILE_CODING
+#include "file-coding.h"
+#endif
+#include <stdio.h>
+#include <ctype.h>
+#ifdef HAVE_XFACE
+#include <setjmp.h>
+#endif
+
+#define WIDGET_GLYPH_SLOT 0
+
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (nothing);
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (string);
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (formatted_string);
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (inherit);
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (layout);
+#ifdef HAVE_JPEG
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (jpeg);
+#endif
+#ifdef HAVE_TIFF
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (tiff);
+#endif  
+#ifdef HAVE_PNG
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (png);
+#endif  
+#ifdef HAVE_GIF
+DECLARE_IMAGE_INSTANTIATOR_FORMAT (gif);
+#endif  
+#ifdef HAVE_XPM
+DEFINE_DEVICE_IIFORMAT (mswindows, xpm);
+#endif
+DEFINE_DEVICE_IIFORMAT (mswindows, xbm);
+#ifdef HAVE_XFACE
+DEFINE_DEVICE_IIFORMAT (mswindows, xface);
+#endif
+DEFINE_DEVICE_IIFORMAT (mswindows, button);
+DEFINE_DEVICE_IIFORMAT (mswindows, edit_field);
+DEFINE_DEVICE_IIFORMAT (mswindows, subwindow);
+DEFINE_DEVICE_IIFORMAT (mswindows, widget);
+DEFINE_DEVICE_IIFORMAT (mswindows, label);
+DEFINE_DEVICE_IIFORMAT (mswindows, scrollbar);
+DEFINE_DEVICE_IIFORMAT (mswindows, combo_box);
+DEFINE_DEVICE_IIFORMAT (mswindows, progress_gauge);
+DEFINE_DEVICE_IIFORMAT (mswindows, tree_view);
+DEFINE_DEVICE_IIFORMAT (mswindows, tab_control);
+
+DEFINE_IMAGE_INSTANTIATOR_FORMAT (bmp);
+Lisp_Object Qbmp;
+Lisp_Object Vmswindows_bitmap_file_path;
+static	COLORREF transparent_color = RGB (1,1,1);
+
+DEFINE_IMAGE_INSTANTIATOR_FORMAT (mswindows_resource);
+Lisp_Object Q_resource_type, Q_resource_id;
+Lisp_Object Qmswindows_resource;
+
+static void
+mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
+					     int slices,
+					     enum image_instance_type type);
+static void
+mswindows_initialize_image_instance_mask (struct Lisp_Image_Instance* image, 
+					  struct frame* f);
+
+COLORREF mswindows_string_to_color (CONST char *name);
+
+#define BPLINE(width) ((int)(~3UL & (unsigned long)((width) +3)))
+
+/************************************************************************/
+/* convert from a series of RGB triples to a BITMAPINFO formated for the*/
+/* proper display 							*/
+/************************************************************************/
+static BITMAPINFO* convert_EImage_to_DIBitmap (Lisp_Object device,
+					       int width, int height,
+					       unsigned char *pic,
+					       int *bit_count,
+					       unsigned char** bmp_data)
+{
+  struct device *d = XDEVICE (device);
+  int i,j;
+  RGBQUAD* colortbl;
+  int		ncolors;
+  BITMAPINFO*	bmp_info;
+  unsigned char *ip, *dp;
+
+  if (DEVICE_MSWINDOWS_BITSPIXEL (d) > 0)
+    {
+      int bpline = BPLINE(width * 3);
+      /* FIXME: we can do this because 24bpp implies no color table, once
+       * we start palettizing this is no longer true. The X versions of
+       * this function quantises to 256 colors or bit masks down to a
+       * long. Windows can actually handle rgb triples in the raw so I
+       * don't see much point trying to optimize down to the best
+       * structure - unless it has memory / color allocation implications
+       * .... */
+      bmp_info=xnew_and_zero (BITMAPINFO);
+      
+      if (!bmp_info)
+	{
+	  return NULL;
+	}
+
+      bmp_info->bmiHeader.biBitCount=24; /* just RGB triples for now */
+      bmp_info->bmiHeader.biCompression=BI_RGB; /* just RGB triples for now */
+      bmp_info->bmiHeader.biSizeImage=width*height*3; 
+
+      /* bitmap data needs to be in blue, green, red triples - in that
+	 order, eimage is in RGB format so we need to convert */
+      *bmp_data = xnew_array_and_zero (unsigned char, bpline * height);
+      *bit_count = bpline * height;
+
+      if (!bmp_data)
+	{
+	  xfree (bmp_info);
+	  return NULL;
+	}
+
+      ip = pic;
+      for (i = height-1; i >= 0; i--) {
+	dp = (*bmp_data) + (i * bpline);
+	for (j = 0; j < width; j++) {
+	  dp[2] =*ip++;
+	  dp[1] =*ip++;
+	  *dp   =*ip++;
+	  dp += 3;
+	}
+      }
+    }
+  else				/* scale to 256 colors */
+    {
+      int rd,gr,bl;
+      quant_table *qtable;
+      int bpline = BPLINE (width * 3);
+      /* Quantize the image and get a histogram while we're at it.
+	 Do this first to save memory */
+      qtable = build_EImage_quantable(pic, width, height, 256);
+      if (qtable == NULL) return NULL;
+
+      /* use our quantize table to allocate the colors */
+      ncolors = qtable->num_active_colors;
+      bmp_info=(BITMAPINFO*)xmalloc_and_zero (sizeof(BITMAPINFOHEADER) + 
+					     sizeof(RGBQUAD) * ncolors);
+      if (!bmp_info)
+	{
+	  xfree (qtable);
+	  return NULL;
+	}
+
+      colortbl=(RGBQUAD*)(((unsigned char*)bmp_info)+sizeof(BITMAPINFOHEADER));
+
+      bmp_info->bmiHeader.biBitCount=8; 
+      bmp_info->bmiHeader.biCompression=BI_RGB; 
+      bmp_info->bmiHeader.biSizeImage=bpline*height;
+      bmp_info->bmiHeader.biClrUsed=ncolors; 
+      bmp_info->bmiHeader.biClrImportant=ncolors; 
+      
+      *bmp_data = (unsigned char *) xmalloc_and_zero (bpline * height);
+      *bit_count = bpline * height;
+
+      if (!*bmp_data)
+	{
+	  xfree (qtable);
+	  xfree (bmp_info);
+	  return NULL;
+	}
+      
+      /* build up an RGBQUAD colortable */
+      for (i = 0; i < qtable->num_active_colors; i++) {
+	colortbl[i].rgbRed = (BYTE) qtable->rm[i];
+	colortbl[i].rgbGreen = (BYTE) qtable->gm[i];
+	colortbl[i].rgbBlue = (BYTE) qtable->bm[i];
+	colortbl[i].rgbReserved = 0;
+      }
+
+      /* now build up the data. picture has to be upside-down and
+         back-to-front for msw bitmaps */
+      ip = pic;
+      for (i = height-1; i >= 0; i--) {
+	dp = (*bmp_data) + (i * bpline);
+	for (j = 0; j < width; j++) {
+	  rd = *ip++;
+	  gr = *ip++;
+	  bl = *ip++;
+	  *dp++ = QUANT_GET_COLOR (qtable,rd,gr,bl);
+	}
+      }
+      xfree (qtable);
+    } 
+  /* fix up the standard stuff */
+  bmp_info->bmiHeader.biWidth=width;
+  bmp_info->bmiHeader.biHeight=height;
+  bmp_info->bmiHeader.biPlanes=1;
+  bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+  bmp_info->bmiHeader.biXPelsPerMeter=0; /* unless you know better */
+  bmp_info->bmiHeader.biYPelsPerMeter=0; 
+
+  return bmp_info;
+}
+
+/* Given a pixmap filename, look through all of the "standard" places
+   where the file might be located.  Return a full pathname if found;
+   otherwise, return Qnil. */
+
+static Lisp_Object
+mswindows_locate_pixmap_file (Lisp_Object name)
+{
+  /* This function can GC if IN_REDISPLAY is false */
+  Lisp_Object found;
+
+  /* Check non-absolute pathnames with a directory component relative to
+     the search path; that's the way Xt does it. */
+  if (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 0)) ||
+      (XSTRING_BYTE (name, 0) == '.' &&
+       (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 1)) ||
+	(XSTRING_BYTE (name, 1) == '.' &&
+	 (IS_DIRECTORY_SEP(XSTRING_BYTE (name, 2)))))))
+    {
+      if (!NILP (Ffile_readable_p (name)))
+	return name;
+      else
+	return Qnil;
+    }
+
+  if (locate_file (Vmswindows_bitmap_file_path, name, Qnil, &found, R_OK) < 0)
+    {
+      Lisp_Object temp = list1 (Vdata_directory);
+      struct gcpro gcpro1;
+
+      GCPRO1 (temp);
+      locate_file (temp, name, Qnil, &found, R_OK);
+      UNGCPRO;
+    }
+    
+  return found;
+}
+
+
+/* Initialize an image instance from a bitmap
+
+   DEST_MASK specifies the mask of allowed image types.
+
+   If this fails, signal an error.  INSTANTIATOR is only used
+   in the error message. */
+
+static void
+init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
+				   BITMAPINFO *bmp_info,
+				   int dest_mask,
+				   void *bmp_data,
+				   int bmp_bits,
+				   int slices,
+				   Lisp_Object instantiator, 
+				   int x_hot, int y_hot,
+				   int create_mask)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  struct device *d = XDEVICE (device);
+  struct frame *f;
+  void* bmp_buf=0;
+  int type = 0;
+  HBITMAP bitmap;
+  HDC hdc;
+
+  if (!DEVICE_MSWINDOWS_P (d))
+    signal_simple_error ("Not an mswindows device", device);
+
+  if (NILP (DEVICE_SELECTED_FRAME (d)))
+    signal_simple_error ("No selected frame on mswindows device", device);
+
+  f = XFRAME (DEVICE_SELECTED_FRAME (d));
+  
+  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_POINTER_MASK);
+  hdc = FRAME_MSWINDOWS_CDC (f);
+
+  bitmap=CreateDIBSection (hdc,  
+			  bmp_info,
+			  DIB_RGB_COLORS,
+			  &bmp_buf, 
+			  0,0);
+
+  if (!bitmap || !bmp_buf)
+    signal_simple_error ("Unable to create bitmap", instantiator);
+
+  /* copy in the actual bitmap */
+  memcpy (bmp_buf, bmp_data, bmp_bits);
+
+  mswindows_initialize_dibitmap_image_instance (ii, slices, type);
+
+  IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
+    find_keyword_in_vector (instantiator, Q_file);
+
+  /* Fixup a set of bitmaps. */
+  IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = bitmap;
+
+  IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = NULL;
+  IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = bmp_info->bmiHeader.biWidth;
+  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = bmp_info->bmiHeader.biHeight;
+  IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = bmp_info->bmiHeader.biBitCount;
+  XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), x_hot);
+  XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), y_hot);
+
+  if (create_mask)
+    {
+      mswindows_initialize_image_instance_mask (ii, f);
+    }
+  
+  if (type == IMAGE_POINTER)
+    {
+      mswindows_initialize_image_instance_icon(ii, TRUE);
+    }
+}
+
+static void
+image_instance_add_dibitmap (struct Lisp_Image_Instance *ii,
+			     BITMAPINFO *bmp_info,
+			     void *bmp_data,
+			     int bmp_bits,
+			     int slice,
+			     Lisp_Object instantiator)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  struct device *d = XDEVICE (device);
+  struct frame *f = XFRAME (DEVICE_SELECTED_FRAME (d));
+  void* bmp_buf=0;
+  HDC hdc = FRAME_MSWINDOWS_CDC (f);
+  HBITMAP bitmap = CreateDIBSection (hdc,  
+				     bmp_info,
+				     DIB_RGB_COLORS,
+				     &bmp_buf, 
+				     0,0);
+  
+  if (!bitmap || !bmp_buf)
+    signal_simple_error ("Unable to create bitmap", instantiator);
+
+  /* copy in the actual bitmap */
+  memcpy (bmp_buf, bmp_data, bmp_bits);
+  IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE (ii, slice) = bitmap;
+}
+
+static void
+mswindows_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii,
+					   int width, int height,
+					   int slices,
+					   unsigned char *eimage, 
+					   int dest_mask,
+					   Lisp_Object instantiator,
+					   Lisp_Object domain)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  BITMAPINFO*		bmp_info;
+  unsigned char*	bmp_data;
+  int			bmp_bits;
+  COLORREF		bkcolor;
+  int slice;
+  
+  if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
+    signal_simple_error ("Not an mswindows device", device);
+
+  /* this is a hack but MaskBlt and TransparentBlt are not supported
+     on most windows variants */
+  bkcolor = COLOR_INSTANCE_MSWINDOWS_COLOR 
+    (XCOLOR_INSTANCE (FACE_BACKGROUND (Vdefault_face, domain)));
+
+  for (slice = 0; slice < slices; slice++)
+    {
+      /* build a bitmap from the eimage */
+      if (!(bmp_info=convert_EImage_to_DIBitmap (device, width, height, 
+						 eimage + (width * height * 3 * slice),
+						 &bmp_bits, &bmp_data)))
+	{
+	  signal_simple_error ("EImage to DIBitmap conversion failed",
+			       instantiator);
+	}
+
+      /* Now create the pixmap and set up the image instance */
+      if (slice == 0)
+	init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
+					   bmp_data, bmp_bits, slices, instantiator,
+					   0, 0, 0);
+      else
+	image_instance_add_dibitmap (ii, bmp_info, bmp_data, bmp_bits, slice,
+				     instantiator);
+      
+      xfree (bmp_info);
+      xfree (bmp_data);
+    }
+}
+
+static void set_mono_pixel ( unsigned char* bits, 
+			     int bpline, int height, 
+			     int x, int y, int white ) 
+{ 
+  int index;
+  unsigned char    bitnum;  
+  /* Find the byte on which this scanline begins */
+  index = (height - y - 1) * bpline; 
+  /* Find the byte containing this pixel */
+  index += (x >> 3); 
+  /* Which bit is it? */
+  bitnum = (unsigned char)( 7 - (x % 8) );  
+  if( white )         /* Turn it on */
+    bits[index] |= (1<<bitnum);
+  else         /* Turn it off */
+    bits[index] &= ~(1<<bitnum); 
+} 
+
+static void
+mswindows_initialize_image_instance_mask (struct Lisp_Image_Instance* image, 
+					  struct frame* f)
+{
+  HBITMAP mask;
+  HGDIOBJ old = NULL;
+  HDC hcdc = FRAME_MSWINDOWS_CDC (f);
+  unsigned char* dibits;
+  BITMAPINFO* bmp_info = 
+    xmalloc_and_zero (sizeof(BITMAPINFO) + sizeof(RGBQUAD));
+  int i, j;
+  int height = IMAGE_INSTANCE_PIXMAP_HEIGHT (image);
+  
+  void* and_bits; 
+  int maskbpline = BPLINE (((IMAGE_INSTANCE_PIXMAP_WIDTH (image)+7)/8));
+  int bpline = BPLINE (IMAGE_INSTANCE_PIXMAP_WIDTH (image) * 3); 
+
+  if (!bmp_info)
+    return;
+
+  bmp_info->bmiHeader.biWidth=IMAGE_INSTANCE_PIXMAP_WIDTH (image);
+  bmp_info->bmiHeader.biHeight = height;
+  bmp_info->bmiHeader.biPlanes=1;
+  bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+  bmp_info->bmiHeader.biBitCount=1; 
+  bmp_info->bmiHeader.biCompression=BI_RGB; 
+  bmp_info->bmiHeader.biClrUsed = 2; 
+  bmp_info->bmiHeader.biClrImportant = 2; 
+  bmp_info->bmiHeader.biSizeImage = height * maskbpline; 
+  bmp_info->bmiColors[0].rgbRed = 0;
+  bmp_info->bmiColors[0].rgbGreen = 0;
+  bmp_info->bmiColors[0].rgbBlue = 0;
+  bmp_info->bmiColors[0].rgbReserved = 0;
+  bmp_info->bmiColors[1].rgbRed = 255;
+  bmp_info->bmiColors[1].rgbGreen = 255;
+  bmp_info->bmiColors[1].rgbBlue = 255;
+  bmp_info->bmiColors[0].rgbReserved = 0;
+    
+  if (!(mask = CreateDIBSection (hcdc,  
+				 bmp_info,
+				 DIB_RGB_COLORS,
+				 &and_bits, 
+				 0,0)))
+    {
+      xfree (bmp_info);
+      return;
+    }
+
+  old = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_BITMAP (image));
+  /* build up an in-memory set of bits to mess with */
+  xzero (*bmp_info);
+
+  bmp_info->bmiHeader.biWidth=IMAGE_INSTANCE_PIXMAP_WIDTH (image);
+  bmp_info->bmiHeader.biHeight = -height;
+  bmp_info->bmiHeader.biPlanes=1;
+  bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+  bmp_info->bmiHeader.biBitCount=24; 
+  bmp_info->bmiHeader.biCompression=BI_RGB; 
+  bmp_info->bmiHeader.biClrUsed = 0; 
+  bmp_info->bmiHeader.biClrImportant = 0; 
+  bmp_info->bmiHeader.biSizeImage = height * bpline;
+
+  dibits = xmalloc_and_zero (bpline * height);
+  if (GetDIBits (hcdc,
+		 IMAGE_INSTANCE_MSWINDOWS_BITMAP (image),
+		 0,
+		 height,
+		 dibits,
+		 bmp_info,
+		 DIB_RGB_COLORS) <= 0)
+    {
+      xfree (bmp_info);
+      return;
+    }
+
+  /* now set the colored bits in the mask and transparent ones to
+     black in the original */
+  for(i=0; i<IMAGE_INSTANCE_PIXMAP_WIDTH (image); i++)     
+    { 
+      for(j=0; j<height; j++)         
+	{ 
+	  unsigned char* idx = &dibits[j * bpline + i * 3];
+
+	  if( RGB (idx[2], idx[1], idx[0]) == transparent_color )
+	    { 
+	      idx[0] = idx[1] = idx[2] = 0;
+	      set_mono_pixel( and_bits, maskbpline, height, i, j, TRUE );
+	    }
+	  else             
+	    { 
+	      set_mono_pixel( and_bits, maskbpline, height, i, j, FALSE );
+            }
+	}
+    }
+
+  SetDIBits (hcdc,
+	     IMAGE_INSTANCE_MSWINDOWS_BITMAP (image),
+	     0,
+	     height,
+	     dibits,
+	     bmp_info,
+	     DIB_RGB_COLORS);
+
+  xfree (bmp_info);
+  xfree (dibits);
+  
+  SelectObject(hcdc, old);
+
+  IMAGE_INSTANCE_MSWINDOWS_MASK (image) = mask;
+}
+
+void
+mswindows_initialize_image_instance_icon (struct Lisp_Image_Instance* image,
+					  int cursor)
+{
+  ICONINFO x_icon;
+
+  /* we rely on windows to do any resizing necessary */
+  x_icon.fIcon=cursor ? FALSE : TRUE;
+  x_icon.xHotspot=XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (image));
+  x_icon.yHotspot=XINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (image));
+  x_icon.hbmMask=IMAGE_INSTANCE_MSWINDOWS_MASK (image);
+  x_icon.hbmColor=IMAGE_INSTANCE_MSWINDOWS_BITMAP (image);
+  
+  IMAGE_INSTANCE_MSWINDOWS_ICON (image)=
+    CreateIconIndirect (&x_icon);
+}
+
+HBITMAP
+mswindows_create_resized_bitmap (struct Lisp_Image_Instance* ii,
+				 struct frame* f,
+				 int newx, int newy)
+{
+  HBITMAP newbmp;
+  HGDIOBJ old1, old2;
+  HDC hcdc = FRAME_MSWINDOWS_CDC (f);
+  HDC hdcDst = CreateCompatibleDC (hcdc);  
+  
+  old1 = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii)); 
+  
+  newbmp = CreateCompatibleBitmap (hcdc, newx, newy);
+
+  old2 = SelectObject (hdcDst, newbmp);
+  
+  if (!StretchBlt (hdcDst, 0, 0, newx, newy,
+		   hcdc, 0, 0, 
+		   IMAGE_INSTANCE_PIXMAP_WIDTH (ii), 
+		   IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
+		   SRCCOPY))
+    {
+      DeleteObject (newbmp);
+      DeleteDC (hdcDst);
+      return 0;
+    }
+
+  SelectObject (hdcDst, old2);
+  SelectObject (hcdc, old1);
+  DeleteDC (hdcDst);
+
+  return newbmp;
+}
+
+HBITMAP
+mswindows_create_resized_mask (struct Lisp_Image_Instance* ii,
+			       struct frame* f,
+			       int newx, int newy)
+{
+  if (IMAGE_INSTANCE_MSWINDOWS_MASK (ii))
+    {
+      HBITMAP newmask;
+      HGDIOBJ old1, old2;
+      HDC hcdc = FRAME_MSWINDOWS_CDC (f);
+      HDC hdcDst = CreateCompatibleDC (hcdc);  
+  
+      old1 = SelectObject (hcdc, IMAGE_INSTANCE_MSWINDOWS_MASK (ii)); 
+      newmask = CreateCompatibleBitmap(hcdc, newx, newy);
+      old2 = SelectObject (hdcDst, newmask);
+
+      if (!StretchBlt(hdcDst, 0, 0, newx, newy,
+		      hcdc, 0, 0, 
+		      IMAGE_INSTANCE_PIXMAP_WIDTH (ii), 
+		      IMAGE_INSTANCE_PIXMAP_HEIGHT (ii), 
+		      SRCCOPY))
+	{
+	  DeleteObject (newmask);
+	  DeleteDC (hdcDst);
+	  return NULL;
+	}
+      
+      SelectObject (hdcDst, old2);
+      SelectObject (hcdc, old1);
+
+      DeleteDC (hdcDst);
+
+      return newmask;
+    }
+
+  return NULL;
+}
+
+int
+mswindows_resize_dibitmap_instance (struct Lisp_Image_Instance* ii,
+				    struct frame* f,
+				    int newx, int newy)
+{
+  HBITMAP newbmp = mswindows_create_resized_bitmap (ii, f, newx, newy);
+  HBITMAP newmask = mswindows_create_resized_mask (ii, f, newx, newy);
+
+  if (!newbmp)
+    return FALSE;
+  
+  if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii))
+    DeleteObject (IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii));
+  if (IMAGE_INSTANCE_MSWINDOWS_MASK (ii))
+    DeleteObject (IMAGE_INSTANCE_MSWINDOWS_MASK (ii));
+
+  IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = newbmp;
+  IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = newmask;
+  IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = newx;
+  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = newy;
+
+  return TRUE;
+}
+
+/**********************************************************************
+ *                               XPM                                  *
+ **********************************************************************/
+
+#ifdef HAVE_XPM
+
+struct color_symbol
+{
+  char*		name;
+  COLORREF	color;
+};
+
+static struct color_symbol*
+extract_xpm_color_names (Lisp_Object device,
+			 Lisp_Object domain,
+			 Lisp_Object color_symbol_alist,
+			 int* nsymbols)
+{
+  /* This function can GC */
+  Lisp_Object rest;
+  Lisp_Object results = Qnil;
+  int i, j;
+  struct color_symbol *colortbl;
+  struct gcpro gcpro1, gcpro2;
+
+  GCPRO2 (results, device);
+
+  /* We built up results to be (("name" . #<color>) ...) so that if an
+     error happens we don't lose any malloc()ed data, or more importantly,
+     leave any pixels allocated in the server. */
+  i = 0;
+  LIST_LOOP (rest, color_symbol_alist)
+    {
+      Lisp_Object cons = XCAR (rest);
+      Lisp_Object name = XCAR (cons);
+      Lisp_Object value = XCDR (cons);
+      if (NILP (value))
+	continue;
+      if (STRINGP (value))
+	value =
+	  Fmake_color_instance
+	  (value, device, encode_error_behavior_flag (ERROR_ME_NOT));
+      else
+        {
+          assert (COLOR_SPECIFIERP (value));
+          value = Fspecifier_instance (value, domain, Qnil, Qnil);
+        }
+      if (NILP (value))
+        continue;
+      results = noseeum_cons (noseeum_cons (name, value), results);
+      i++;
+    }
+  UNGCPRO;			/* no more evaluation */
+
+  *nsymbols=i;
+  if (i == 0) return 0;
+
+  colortbl = xnew_array_and_zero (struct color_symbol, i);
+
+  for (j=0; j<i; j++)
+    {
+      Lisp_Object cons = XCAR (results);
+      colortbl[j].color = 
+	COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (XCDR (cons)));
+
+      GET_C_STRING_OS_DATA_ALLOCA (XCAR (cons), colortbl[j].name);
+      colortbl[j].name = xstrdup (colortbl[j].name); /* mustn't lose this when we return */
+      free_cons (XCONS (cons));
+      cons = results;
+      results = XCDR (results);
+      free_cons (XCONS (cons));
+    }
+  return colortbl;
+}
+
+static int xpm_to_eimage (Lisp_Object image, CONST Extbyte *buffer,
+			  unsigned char** data,
+			  int* width, int* height,
+			  int* x_hot, int* y_hot,
+			  int* transp,
+			  struct color_symbol* color_symbols,
+			  int nsymbols)
+{
+  XpmImage xpmimage;
+  XpmInfo xpminfo;
+  int result, i, j, transp_idx, maskbpline;
+  unsigned char* dptr;
+  unsigned int* sptr;
+  COLORREF color; /* the american spelling virus hits again .. */
+  COLORREF* colortbl; 
+
+  xzero (xpmimage);
+  xzero (xpminfo);
+  xpminfo.valuemask=XpmHotspot;
+  *transp=FALSE;
+
+  result = XpmCreateXpmImageFromBuffer ((char*)buffer,
+				       &xpmimage,
+				       &xpminfo);
+  switch (result)
+    {
+    case XpmSuccess:
+      break;
+    case XpmFileInvalid:
+      {
+	signal_simple_error ("Invalid XPM data", image);
+      }
+    case XpmNoMemory:
+      {
+	signal_double_file_error ("Parsing pixmap data",
+				  "out of memory", image);
+      }
+    default:
+      {
+	signal_double_file_error_2 ("Parsing pixmap data",
+				    "unknown error code",
+				    make_int (result), image);
+      }
+    }
+  
+  *width = xpmimage.width;
+  *height = xpmimage.height;
+  maskbpline = BPLINE (((~7UL & (unsigned long)(*width + 7)) / 8));
+  
+  *data = xnew_array_and_zero (unsigned char, *width * *height * 3);
+
+  if (!*data)
+    {
+      XpmFreeXpmImage (&xpmimage);
+      XpmFreeXpmInfo (&xpminfo);
+      return 0;
+    }
+
+  /* build a color table to speed things up */
+  colortbl = xnew_array_and_zero (COLORREF, xpmimage.ncolors);
+  if (!colortbl)
+    {
+      xfree (*data);
+      XpmFreeXpmImage (&xpmimage);
+      XpmFreeXpmInfo (&xpminfo);
+      return 0;
+    }
+
+  for (i=0; i<xpmimage.ncolors; i++)
+    {
+      /* goto alert!!!! */
+      /* pick up symbolic colors in preference */
+      if (xpmimage.colorTable[i].symbolic)
+	{
+	  if (!strcasecmp (xpmimage.colorTable[i].symbolic,"BgColor")
+	      ||
+	      !strcasecmp (xpmimage.colorTable[i].symbolic,"None"))
+	    {
+	      *transp=TRUE;
+	      colortbl[i]=transparent_color; 
+	      transp_idx=i;
+	      goto label_found_color;
+	    }
+	  else if (color_symbols)
+	    {
+	      for (j = 0; j<nsymbols; j++)
+		{
+		  if (!strcmp (xpmimage.colorTable[i].symbolic,
+			       color_symbols[j].name ))
+		    {
+		      colortbl[i]=color_symbols[j].color;
+		      goto label_found_color;
+		    }
+		}
+	    }
+	  else if (xpmimage.colorTable[i].c_color == 0)
+	    {
+	      goto label_no_color;
+	    }
+	}
+      /* pick up transparencies */
+      if (!strcasecmp (xpmimage.colorTable[i].c_color,"None"))
+	{
+	  *transp=TRUE;
+	  colortbl[i]=transparent_color; 
+	  transp_idx=i;
+	  goto label_found_color;
+	}
+      /* finally pick up a normal color spec */
+      if (xpmimage.colorTable[i].c_color)
+	{
+	  colortbl[i]=
+	    mswindows_string_to_color (xpmimage.colorTable[i].c_color);
+	  goto label_found_color;
+	}
+      
+    label_no_color:
+      xfree (*data);
+      xfree (colortbl);
+      XpmFreeXpmImage (&xpmimage);
+      XpmFreeXpmInfo (&xpminfo);
+      return 0;
+      
+    label_found_color:;
+    }
+
+  /* convert the image */
+  sptr=xpmimage.data;
+  dptr=*data;
+  for (i = 0; i< *width * *height; i++)
+    {
+      color = colortbl[*sptr++];
+
+      /* split out the 0x02bbggrr colorref into an rgb triple */
+      *dptr++=GetRValue (color); /* red */
+      *dptr++=GetGValue (color); /* green */
+      *dptr++=GetBValue (color); /* blue */
+    }
+
+  *x_hot=xpminfo.x_hotspot;
+  *y_hot=xpminfo.y_hotspot;
+
+  XpmFreeXpmImage (&xpmimage);
+  XpmFreeXpmInfo (&xpminfo);
+  xfree (colortbl);
+  return TRUE;
+}
+
+static void
+mswindows_xpm_instantiate (Lisp_Object image_instance,
+			   Lisp_Object instantiator,
+			   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			   int dest_mask, Lisp_Object domain)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  CONST Extbyte		*bytes;
+  Extcount 		len;
+  unsigned char		*eimage;
+  int			width, height, x_hot, y_hot;
+  BITMAPINFO*		bmp_info;
+  unsigned char*	bmp_data;
+  int			bmp_bits;
+  int 			nsymbols=0, transp;
+  struct color_symbol*	color_symbols=NULL;
+  
+  Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
+  Lisp_Object color_symbol_alist = find_keyword_in_vector (instantiator,
+							   Q_color_symbols);
+
+  if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
+    signal_simple_error ("Not an mswindows device", device);
+
+  assert (!NILP (data));
+
+  GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
+
+  /* in case we have color symbols */
+  color_symbols = extract_xpm_color_names (device, domain,
+					   color_symbol_alist, &nsymbols);
+
+  /* convert to an eimage to make processing easier */
+  if (!xpm_to_eimage (image_instance, bytes, &eimage, &width, &height,
+		      &x_hot, &y_hot, &transp, color_symbols, nsymbols))
+    {
+      signal_simple_error ("XPM to EImage conversion failed", 
+			   image_instance);
+    }
+  
+  if (color_symbols)
+    {
+      while (nsymbols--)
+	{
+	  xfree (color_symbols[nsymbols].name);
+	}
+      xfree(color_symbols);
+    }
+  
+  /* build a bitmap from the eimage */
+  if (!(bmp_info=convert_EImage_to_DIBitmap (device, width, height, eimage,
+					     &bmp_bits, &bmp_data)))
+    {
+      signal_simple_error ("XPM to EImage conversion failed",
+			   image_instance);
+    }
+  xfree (eimage);
+
+  /* Now create the pixmap and set up the image instance */
+  init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
+				     bmp_data, bmp_bits, 1, instantiator,
+				     x_hot, y_hot, transp);
+
+  xfree (bmp_info);
+  xfree (bmp_data);
+}
+#endif /* HAVE_XPM */
+
+/**********************************************************************
+ *                               BMP                                  *
+ **********************************************************************/
+
+static void
+bmp_validate (Lisp_Object instantiator)
+{
+  file_or_data_must_be_present (instantiator);
+}
+
+static Lisp_Object
+bmp_normalize (Lisp_Object inst, Lisp_Object console_type)
+{
+  return simple_image_type_normalize (inst, console_type, Qbmp);
+}
+
+static int
+bmp_possible_dest_types (void)
+{
+  return IMAGE_COLOR_PIXMAP_MASK;
+}
+
+static void
+bmp_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+		 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+		 int dest_mask, Lisp_Object domain)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  CONST Extbyte		*bytes;
+  Extcount 		len;
+  BITMAPFILEHEADER*	bmp_file_header;
+  BITMAPINFO*		bmp_info;
+  void*			bmp_data;
+  int			bmp_bits;
+  Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
+
+  if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
+    signal_simple_error ("Not an mswindows device", device);
+
+  assert (!NILP (data));
+
+  GET_STRING_BINARY_DATA_ALLOCA (data, bytes, len);
+  
+  /* Then slurp the image into memory, decoding along the way.
+     The result is the image in a simple one-byte-per-pixel
+     format. */
+  
+  bmp_file_header=(BITMAPFILEHEADER*)bytes;
+  bmp_info = (BITMAPINFO*)(bytes + sizeof(BITMAPFILEHEADER));
+  bmp_data = (Extbyte*)bytes + bmp_file_header->bfOffBits;
+  bmp_bits = bmp_file_header->bfSize - bmp_file_header->bfOffBits;
+
+  /* Now create the pixmap and set up the image instance */
+  init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
+				     bmp_data, bmp_bits, 1, instantiator,
+				     0, 0, 0);
+}
+
+
+/**********************************************************************
+ *                             RESOURCES                              *
+ **********************************************************************/
+
+static void
+mswindows_resource_validate (Lisp_Object instantiator)
+{
+  if ((NILP (find_keyword_in_vector (instantiator, Q_file)) 
+       &&
+       NILP (find_keyword_in_vector (instantiator, Q_resource_id))) 
+      ||
+      NILP (find_keyword_in_vector (instantiator, Q_resource_type)))
+    signal_simple_error ("Must supply :file, :resource-id and :resource-type",
+			 instantiator);
+}
+
+static Lisp_Object
+mswindows_resource_normalize (Lisp_Object inst, Lisp_Object console_type)
+{
+  /* This function can call lisp */
+  Lisp_Object file = Qnil;
+  struct gcpro gcpro1, gcpro2;
+  Lisp_Object alist = Qnil;
+
+  GCPRO2 (file, alist);
+
+  file = potential_pixmap_file_instantiator (inst, Q_file, Q_data, 
+					     console_type);
+
+  if (CONSP (file)) /* failure locating filename */
+    signal_double_file_error ("Opening pixmap file",
+			      "no such file or directory",
+			      Fcar (file));
+
+  if (NILP (file)) /* no conversion necessary */
+    RETURN_UNGCPRO (inst);
+
+  alist = tagged_vector_to_alist (inst);
+
+  {
+    alist = remassq_no_quit (Q_file, alist);
+    alist = Fcons (Fcons (Q_file, file), alist);
+  }
+
+  {
+    Lisp_Object result = alist_to_tagged_vector (Qmswindows_resource, alist);
+    free_alist (alist);
+    RETURN_UNGCPRO (result);
+  }
+}
+
+static int
+mswindows_resource_possible_dest_types (void)
+{
+  return IMAGE_POINTER_MASK | IMAGE_COLOR_PIXMAP_MASK;
+}
+
+typedef struct 
+{
+  char *name;
+  int	resource_id;
+} resource_t;
+
+#ifndef OCR_ICOCUR
+#define OCR_ICOCUR          32647
+#define OIC_SAMPLE          32512
+#define OIC_HAND            32513
+#define OIC_QUES            32514
+#define OIC_BANG            32515
+#define OIC_NOTE            32516
+#define OIC_WINLOGO         32517
+#define LR_SHARED           0x8000
+#endif
+
+static CONST resource_t bitmap_table[] = 
+{
+  /* bitmaps */
+  { "close", OBM_CLOSE },
+  { "uparrow", OBM_UPARROW },
+  { "dnarrow", OBM_DNARROW },
+  { "rgarrow", OBM_RGARROW },
+  { "lfarrow", OBM_LFARROW },
+  { "reduce", OBM_REDUCE },
+  { "zoom", OBM_ZOOM },
+  { "restore", OBM_RESTORE },
+  { "reduced", OBM_REDUCED },
+  { "zoomd", OBM_ZOOMD },
+  { "restored", OBM_RESTORED },
+  { "uparrowd", OBM_UPARROWD },
+  { "dnarrowd", OBM_DNARROWD },
+  { "rgarrowd", OBM_RGARROWD },
+  { "lfarrowd", OBM_LFARROWD },
+  { "mnarrow", OBM_MNARROW },
+  { "combo", OBM_COMBO },
+  { "uparrowi", OBM_UPARROWI },
+  { "dnarrowi", OBM_DNARROWI },
+  { "rgarrowi", OBM_RGARROWI },
+  { "lfarrowi", OBM_LFARROWI },
+  { "size", OBM_SIZE },
+  { "btsize", OBM_BTSIZE },
+  { "check", OBM_CHECK },
+  { "checkboxes", OBM_CHECKBOXES },
+  { "btncorners" , OBM_BTNCORNERS },
+  {0}
+};
+
+static CONST resource_t cursor_table[] = 
+{
+  /* cursors */
+  { "normal", OCR_NORMAL },
+  { "ibeam", OCR_IBEAM },
+  { "wait", OCR_WAIT },
+  { "cross", OCR_CROSS },
+  { "up", OCR_UP },
+  /* { "icon", OCR_ICON }, */
+  { "sizenwse", OCR_SIZENWSE },
+  { "sizenesw", OCR_SIZENESW },
+  { "sizewe", OCR_SIZEWE },
+  { "sizens", OCR_SIZENS },
+  { "sizeall", OCR_SIZEALL },
+  /* { "icour", OCR_ICOCUR }, */
+  { "no", OCR_NO },
+  { 0 }
+};
+
+static CONST resource_t icon_table[] = 
+{
+  /* icons */
+  { "sample", OIC_SAMPLE },
+  { "hand", OIC_HAND },
+  { "ques", OIC_QUES },
+  { "bang", OIC_BANG },
+  { "note", OIC_NOTE },
+  { "winlogo", OIC_WINLOGO },
+  {0}
+};
+
+static int resource_name_to_resource (Lisp_Object name, int type)
+{
+  CONST resource_t* res = (type == IMAGE_CURSOR ? cursor_table 
+			   : type == IMAGE_ICON ? icon_table 
+			   : bitmap_table);
+
+  if (INTP (name))
+    {
+      return XINT (name);
+    }
+  else if (!STRINGP (name))
+    {
+      signal_simple_error ("invalid resource identifier", name);
+    }
+  
+  do {
+    Extbyte* nm=0;
+    GET_C_STRING_OS_DATA_ALLOCA (name, nm);
+      if (!strcasecmp ((char*)res->name, nm))
+      return res->resource_id;
+  } while ((++res)->name);
+  return 0;
+}
+
+static int
+resource_symbol_to_type (Lisp_Object data)
+{
+  if (EQ (data, Qcursor))
+    return IMAGE_CURSOR;
+  else if (EQ (data, Qicon))
+    return IMAGE_ICON;
+  else if (EQ (data, Qbitmap))
+    return IMAGE_BITMAP;
+  else
+    return 0;
+}
+
+static void
+mswindows_resource_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+		    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+		    int dest_mask, Lisp_Object domain)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  unsigned int type = 0;
+  HANDLE himage = NULL;
+  LPCTSTR resid=0;
+  HINSTANCE hinst = NULL;
+  ICONINFO iconinfo;
+  int iitype=0;
+  char* fname=0;
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+
+  Lisp_Object file = find_keyword_in_vector (instantiator, Q_file);
+  Lisp_Object resource_type = find_keyword_in_vector (instantiator, 
+						      Q_resource_type);
+  Lisp_Object resource_id = find_keyword_in_vector (instantiator, 
+						    Q_resource_id);
+
+  xzero (iconinfo);
+
+  if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
+    signal_simple_error ("Not an mswindows device", device);
+
+  type = resource_symbol_to_type (resource_type);
+
+  if (dest_mask & IMAGE_POINTER_MASK && type == IMAGE_CURSOR)
+    iitype = IMAGE_POINTER;
+  else if (dest_mask & IMAGE_COLOR_PIXMAP_MASK)
+    iitype = IMAGE_COLOR_PIXMAP;
+  else 
+    incompatible_image_types (instantiator, dest_mask,
+			      IMAGE_COLOR_PIXMAP_MASK | IMAGE_POINTER_MASK);
+
+  /* mess with the keyword info we were provided with */
+  if (!NILP (file))
+    {
+      Extbyte* f=0;
+      GET_C_STRING_FILENAME_DATA_ALLOCA (file, f);
+#ifdef __CYGWIN32__
+      CYGWIN_WIN32_PATH (f, fname);
+#else
+      fname = f;
+#endif
+      
+      if (NILP (resource_id))
+	resid = (LPCTSTR)fname;
+      else
+	{
+	  hinst = LoadLibraryEx (fname, NULL,
+				 LOAD_LIBRARY_AS_DATAFILE);
+	  resid = MAKEINTRESOURCE (resource_name_to_resource (resource_id,
+							   type));
+	  
+	  if (!resid)
+	    GET_C_STRING_OS_DATA_ALLOCA (resource_id, resid);
+	}
+    }
+  else if (!(resid = MAKEINTRESOURCE (resource_name_to_resource (resource_id,
+							       type))))
+    signal_simple_error ("Invalid resource identifier", resource_id);
+  
+  /* load the image */
+  if (!(himage = LoadImage (hinst, resid, type, 0, 0,
+			    LR_CREATEDIBSECTION | LR_DEFAULTSIZE | 
+			    LR_SHARED |      
+			    (!NILP (file) ? LR_LOADFROMFILE : 0))))
+    {
+      signal_simple_error ("Cannot load image", instantiator);
+    }
+
+  if (hinst)
+    FreeLibrary (hinst);
+
+  mswindows_initialize_dibitmap_image_instance (ii, 1, iitype);
+
+  IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = file;
+  IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = 
+    GetSystemMetrics (type == IMAGE_CURSOR ? SM_CXCURSOR : SM_CXICON);
+  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = 
+    GetSystemMetrics (type == IMAGE_CURSOR ? SM_CYCURSOR : SM_CYICON);
+  IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1;
+
+  /* hey, we've got an icon type thing so we can reverse engineer the
+     bitmap and mask */
+  if (type != IMAGE_BITMAP)
+    {
+      GetIconInfo (himage, &iconinfo);
+      IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = iconinfo.hbmColor;
+      IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = iconinfo.hbmMask;
+      XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), iconinfo.xHotspot);
+      XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), iconinfo.yHotspot);
+      IMAGE_INSTANCE_MSWINDOWS_ICON (ii) = himage;
+    }
+  else
+    {
+      IMAGE_INSTANCE_MSWINDOWS_ICON (ii) = NULL;
+      IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = himage;
+      IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = NULL;
+      XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 0);
+      XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 0);
+    }
+}
+
+static void
+check_valid_resource_symbol (Lisp_Object data)
+{
+  CHECK_SYMBOL (data);
+  if (!resource_symbol_to_type (data))
+    signal_simple_error ("invalid resource type", data);
+}
+
+static void
+check_valid_resource_id (Lisp_Object data)
+{
+  if (!resource_name_to_resource (data, IMAGE_CURSOR)
+      &&
+      !resource_name_to_resource (data, IMAGE_ICON)
+      &&
+      !resource_name_to_resource (data, IMAGE_BITMAP))
+    signal_simple_error ("invalid resource identifier", data);
+}
+
+void
+check_valid_string_or_int (Lisp_Object data)
+{
+  if (!INTP (data))
+    CHECK_STRING (data);
+  else
+    CHECK_INT (data);
+}
+
+/**********************************************************************
+ *                             XBM                                    *
+ **********************************************************************/
+#ifndef HAVE_X_WINDOWS
+/* $XConsortium: RdBitF.c,v 1.10 94/04/17 20:16:13 kaleb Exp $ */
+
+/*
+
+Copyright (c) 1988  X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from the X Consortium.
+
+*/
+
+/*
+ * This file contains miscellaneous utility routines and is not part of the
+ * Xlib standard.
+ *
+ * Public entry points:
+ *
+ *     XmuReadBitmapData		read data from FILE descriptor
+ *     XmuReadBitmapDataFromFile	read X10 or X11 format bitmap files
+ *					and return data
+ *
+ * Note that this file and ../X/XRdBitF.c look very similar....  Keep them
+ * that way (but don't use common source code so that people can have one 
+ * without the other).
+ */
+
+
+/*
+ * Based on an optimized version provided by Jim Becker, August 5, 1988.
+ */
+#ifndef BitmapSuccess
+#define BitmapSuccess           0
+#define BitmapOpenFailed        1
+#define BitmapFileInvalid       2
+#define BitmapNoMemory          3
+#endif
+#define MAX_SIZE 255
+
+/* shared data for the image read/parse logic */
+static short hexTable[256];		/* conversion value */
+static int initialized = FALSE;	/* easier to fill in at run time */
+
+/*
+ *	Table index for the hex values. Initialized once, first time.
+ *	Used for translation value or delimiter significance lookup.
+ */
+static void initHexTable()
+{
+    /*
+     * We build the table at run time for several reasons:
+     *
+     *     1.  portable to non-ASCII machines.
+     *     2.  still reentrant since we set the init flag after setting table.
+     *     3.  easier to extend.
+     *     4.  less prone to bugs.
+     */
+    hexTable['0'] = 0;	hexTable['1'] = 1;
+    hexTable['2'] = 2;	hexTable['3'] = 3;
+    hexTable['4'] = 4;	hexTable['5'] = 5;
+    hexTable['6'] = 6;	hexTable['7'] = 7;
+    hexTable['8'] = 8;	hexTable['9'] = 9;
+    hexTable['A'] = 10;	hexTable['B'] = 11;
+    hexTable['C'] = 12;	hexTable['D'] = 13;
+    hexTable['E'] = 14;	hexTable['F'] = 15;
+    hexTable['a'] = 10;	hexTable['b'] = 11;
+    hexTable['c'] = 12;	hexTable['d'] = 13;
+    hexTable['e'] = 14;	hexTable['f'] = 15;
+
+    /* delimiters of significance are flagged w/ negative value */
+    hexTable[' '] = -1;	hexTable[','] = -1;
+    hexTable['}'] = -1;	hexTable['\n'] = -1;
+    hexTable['\t'] = -1;
+	
+    initialized = TRUE;
+}
+
+/*
+ *	read next hex value in the input stream, return -1 if EOF
+ */
+static int NextInt ( FILE *fstream )
+{
+    int	ch;
+    int	value = 0;
+    int gotone = 0;
+    int done = 0;
+    
+    /* loop, accumulate hex value until find delimiter  */
+    /* skip any initial delimiters found in read stream */
+
+    while (!done) {
+	ch = getc(fstream);
+	if (ch == EOF) {
+	    value	= -1;
+	    done++;
+	} else {
+	    /* trim high bits, check type and accumulate */
+	    ch &= 0xff;
+	    if (isascii(ch) && isxdigit(ch)) {
+		value = (value << 4) + hexTable[ch];
+		gotone++;
+	    } else if ((hexTable[ch]) < 0 && gotone)
+	      done++;
+	}
+    }
+    return value;
+}
+
+
+/*
+ * The data returned by the following routine is always in left-most byte
+ * first and left-most bit first.  If it doesn't return BitmapSuccess then
+ * its arguments won't have been touched.  This routine should look as much
+ * like the Xlib routine XReadBitmapfile as possible.
+ */
+int read_bitmap_data (fstream, width, height, datap, x_hot, y_hot)
+    FILE *fstream;			/* handle on file  */
+    unsigned int *width, *height;	/* RETURNED */
+    unsigned char **datap;		/* RETURNED */
+    int *x_hot, *y_hot;			/* RETURNED */
+{
+    unsigned char *data = NULL;		/* working variable */
+    char line[MAX_SIZE];		/* input line from file */
+    int size;				/* number of bytes of data */
+    char name_and_type[MAX_SIZE];	/* an input line */
+    char *type;				/* for parsing */
+    int value;				/* from an input line */
+    int version10p;			/* boolean, old format */
+    int padding;			/* to handle alignment */
+    int bytes_per_line;			/* per scanline of data */
+    unsigned int ww = 0;		/* width */
+    unsigned int hh = 0;		/* height */
+    int hx = -1;			/* x hotspot */
+    int hy = -1;			/* y hotspot */
+
+#define Xmalloc(size) malloc(size)
+
+    /* first time initialization */
+    if (initialized == FALSE) initHexTable();
+
+    /* error cleanup and return macro	*/
+#define	RETURN(code) { if (data) free (data); return code; }
+
+    while (fgets(line, MAX_SIZE, fstream)) {
+	if (strlen(line) == MAX_SIZE-1) {
+	    RETURN (BitmapFileInvalid);
+	}
+	if (sscanf(line,"#define %s %d",name_and_type,&value) == 2) {
+	    if (!(type = strrchr(name_and_type, '_')))
+	      type = name_and_type;
+	    else
+	      type++;
+
+	    if (!strcmp("width", type))
+	      ww = (unsigned int) value;
+	    if (!strcmp("height", type))
+	      hh = (unsigned int) value;
+	    if (!strcmp("hot", type)) {
+		if (type-- == name_and_type || type-- == name_and_type)
+		  continue;
+		if (!strcmp("x_hot", type))
+		  hx = value;
+		if (!strcmp("y_hot", type))
+		  hy = value;
+	    }
+	    continue;
+	}
+    
+	if (sscanf(line, "static short %s = {", name_and_type) == 1)
+	  version10p = 1;
+	else if (sscanf(line,"static unsigned char %s = {",name_and_type) == 1)
+	  version10p = 0;
+	else if (sscanf(line, "static char %s = {", name_and_type) == 1)
+	  version10p = 0;
+	else
+	  continue;
+
+	if (!(type = strrchr(name_and_type, '_')))
+	  type = name_and_type;
+	else
+	  type++;
+
+	if (strcmp("bits[]", type))
+	  continue;
+    
+	if (!ww || !hh)
+	  RETURN (BitmapFileInvalid);
+
+	if ((ww % 16) && ((ww % 16) < 9) && version10p)
+	  padding = 1;
+	else
+	  padding = 0;
+
+	bytes_per_line = (ww+7)/8 + padding;
+
+	size = bytes_per_line * hh;
+	data = (unsigned char *) Xmalloc ((unsigned int) size);
+	if (!data) 
+	  RETURN (BitmapNoMemory);
+
+	if (version10p) {
+	    unsigned char *ptr;
+	    int bytes;
+
+	    for (bytes=0, ptr=data; bytes<size; (bytes += 2)) {
+		if ((value = NextInt(fstream)) < 0)
+		  RETURN (BitmapFileInvalid);
+		*(ptr++) = value;
+		if (!padding || ((bytes+2) % bytes_per_line))
+		  *(ptr++) = value >> 8;
+	    }
+	} else {
+	    unsigned char *ptr;
+	    int bytes;
+
+	    for (bytes=0, ptr=data; bytes<size; bytes++, ptr++) {
+		if ((value = NextInt(fstream)) < 0) 
+		  RETURN (BitmapFileInvalid);
+		*ptr=value;
+	    }
+	}
+	break;
+    }					/* end while */
+
+    if (data == NULL) {
+	RETURN (BitmapFileInvalid);
+    }
+
+    *datap = data;
+    data = NULL;
+    *width = ww;
+    *height = hh;
+    if (x_hot) *x_hot = hx;
+    if (y_hot) *y_hot = hy;
+
+    RETURN (BitmapSuccess);
+}
+
+
+int read_bitmap_data_from_file (CONST char *filename, unsigned int *width, 
+				unsigned int *height, unsigned char **datap,
+				int *x_hot, int *y_hot)
+{
+    FILE *fstream;
+    int status;
+
+    if ((fstream = fopen (filename, "r")) == NULL) {
+	return BitmapOpenFailed;
+    }
+    status = read_bitmap_data (fstream, width, height, datap, x_hot, y_hot);
+    fclose (fstream);
+    return status;
+}
+#endif /* HAVE_X_WINDOWS */
+
+/* this table flips four bits around. */
+static int flip_table[] =
+{
+  0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
+};
+
+/* the bitmap data comes in the following format: Widths are padded to
+   a multiple of 8.  Scan lines are stored in increasing byte order
+   from left to right, little-endian within a byte.  0 = white, 1 =
+   black.  It must be converted to the following format: Widths are
+   padded to a multiple of 16.  Scan lines are stored in increasing
+   byte order from left to right, big-endian within a byte.  0 =
+   black, 1 = white.  */
+HBITMAP
+xbm_create_bitmap_from_data (HDC hdc, char *data,
+			     unsigned int width, unsigned int height,
+			     int mask, COLORREF fg, COLORREF bg)
+{
+  int old_width = (width + 7)/8;
+  int new_width = BPLINE (2*((width + 15)/16));
+  unsigned char *offset;
+  void *bmp_buf = 0;
+  unsigned char *new_data, *new_offset;
+  int i, j;
+  BITMAPINFO* bmp_info = 
+    xmalloc_and_zero (sizeof(BITMAPINFO) + sizeof(RGBQUAD));
+  HBITMAP bitmap;
+
+  if (!bmp_info)
+    return NULL;
+  
+  new_data = (unsigned char *) xmalloc_and_zero (height * new_width);
+      
+  if (!new_data)
+    {
+      xfree (bmp_info);
+      return NULL;
+    }
+  
+  for (i=0; i<height; i++)
+    {
+      offset = data + i*old_width;
+      new_offset = new_data + i*new_width;
+
+      for (j=0; j<old_width; j++)
+	{
+	  int byte = offset[j];
+	  new_offset[j] = ~ (unsigned char)
+	    ((flip_table[byte & 0xf] << 4) + flip_table[byte >> 4]);
+	}
+    }
+
+  /* if we want a mask invert the bits */
+  if (!mask)
+    {
+      new_offset = &new_data[height * new_width];
+      while (new_offset-- != new_data)
+	{
+	  *new_offset ^= 0xff;
+	}
+    }
+
+  bmp_info->bmiHeader.biWidth=width;
+  bmp_info->bmiHeader.biHeight=-(LONG)height;
+  bmp_info->bmiHeader.biPlanes=1;
+  bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
+  bmp_info->bmiHeader.biBitCount=1; 
+  bmp_info->bmiHeader.biCompression=BI_RGB;
+  bmp_info->bmiHeader.biClrUsed = 2; 
+  bmp_info->bmiHeader.biClrImportant = 2; 
+  bmp_info->bmiHeader.biSizeImage = height * new_width; 
+  bmp_info->bmiColors[0].rgbRed = GetRValue (fg);
+  bmp_info->bmiColors[0].rgbGreen = GetGValue (fg);
+  bmp_info->bmiColors[0].rgbBlue = GetBValue (fg);
+  bmp_info->bmiColors[0].rgbReserved = 0;
+  bmp_info->bmiColors[1].rgbRed = GetRValue (bg);
+  bmp_info->bmiColors[1].rgbGreen = GetGValue (bg);
+  bmp_info->bmiColors[1].rgbBlue = GetBValue (bg);
+  bmp_info->bmiColors[1].rgbReserved = 0;
+  
+  bitmap = CreateDIBSection (hdc,  
+			     bmp_info,
+			     DIB_RGB_COLORS,
+			     &bmp_buf, 
+			     0,0);
+
+  xfree (bmp_info);
+  
+  if (!bitmap || !bmp_buf)
+    {
+      xfree (new_data);
+      return NULL;
+    }
+  
+  /* copy in the actual bitmap */
+  memcpy (bmp_buf, new_data, height * new_width);
+  xfree (new_data);
+
+  return bitmap;
+}
+
+/* Given inline data for a mono pixmap, initialize the given
+   image instance accordingly. */
+
+static void
+init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii,
+				     int width, int height,
+				     /* Note that data is in ext-format! */
+				     CONST char *bits,
+				     Lisp_Object instantiator,
+				     Lisp_Object pointer_fg,
+				     Lisp_Object pointer_bg,
+				     int dest_mask,
+				     HBITMAP mask,
+				     Lisp_Object mask_filename)
+{
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  struct frame* f = XFRAME (DEVICE_SELECTED_FRAME (XDEVICE (device)));
+  Lisp_Object foreground = find_keyword_in_vector (instantiator, Q_foreground);
+  Lisp_Object background = find_keyword_in_vector (instantiator, Q_background);
+  enum image_instance_type type;
+  COLORREF black = PALETTERGB (0,0,0);
+  COLORREF white = PALETTERGB (255,255,255);
+
+  HDC hdc = FRAME_MSWINDOWS_CDC (f);
+
+  if (!DEVICE_MSWINDOWS_P (XDEVICE (device)))
+    signal_simple_error ("Not an MS-Windows device", device);
+
+  if ((dest_mask & IMAGE_MONO_PIXMAP_MASK) &&
+      (dest_mask & IMAGE_COLOR_PIXMAP_MASK))
+    {
+      if (!NILP (foreground) || !NILP (background))
+	type = IMAGE_COLOR_PIXMAP;
+      else
+	type = IMAGE_MONO_PIXMAP;
+    }
+  else if (dest_mask & IMAGE_MONO_PIXMAP_MASK)
+    type = IMAGE_MONO_PIXMAP;
+  else 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_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
+			      | IMAGE_POINTER_MASK);
+
+  mswindows_initialize_dibitmap_image_instance (ii, 1, type);
+  
+  IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
+    find_keyword_in_vector (instantiator, Q_file);
+  IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = width;
+  IMAGE_INSTANCE_PIXMAP_HEIGHT (ii) = height;
+  IMAGE_INSTANCE_PIXMAP_DEPTH (ii) = 1;
+  XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 0);
+  XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 0);
+  IMAGE_INSTANCE_MSWINDOWS_MASK (ii) = mask ? mask :
+    xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
+				 TRUE, black, white);
+
+  switch (type)
+    {
+    case IMAGE_MONO_PIXMAP:
+      IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
+	xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
+				     FALSE, black, black);
+      break;
+
+    case IMAGE_COLOR_PIXMAP:
+      {
+	COLORREF fg = black;
+	COLORREF bg = white;
+
+	if (!NILP (foreground) && !COLOR_INSTANCEP (foreground))
+	  foreground =
+	    Fmake_color_instance (foreground, device,
+				  encode_error_behavior_flag (ERROR_ME));
+
+	if (COLOR_INSTANCEP (foreground))
+	  fg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (foreground));
+
+	if (!NILP (background) && !COLOR_INSTANCEP (background))
+	  background =
+	    Fmake_color_instance (background, device,
+				  encode_error_behavior_flag (ERROR_ME));
+
+	if (COLOR_INSTANCEP (background))
+	  bg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (background));
+
+	IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
+	IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
+
+	IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
+	  xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
+				       FALSE, fg, black);
+      }
+      break;
+
+    case IMAGE_POINTER:
+      {
+	COLORREF fg = black;
+	COLORREF bg = white;
+
+	if (NILP (foreground))
+	  foreground = pointer_fg;
+	if (NILP (background))
+	  background = pointer_bg;
+
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = 
+	  find_keyword_in_vector (instantiator, Q_hotspot_x);
+	IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = 
+	  find_keyword_in_vector (instantiator, Q_hotspot_y);
+	IMAGE_INSTANCE_PIXMAP_FG (ii) = foreground;
+	IMAGE_INSTANCE_PIXMAP_BG (ii) = background;
+	if (COLOR_INSTANCEP (foreground))
+	  fg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (foreground));
+	if (COLOR_INSTANCEP (background))
+	  bg = COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (background));
+
+	IMAGE_INSTANCE_MSWINDOWS_BITMAP (ii) = 
+	  xbm_create_bitmap_from_data (hdc, (Extbyte *) bits, width, height, 
+				       TRUE, fg, black);
+	mswindows_initialize_image_instance_icon (ii, TRUE);
+      }
+      break;
+
+    default:
+      abort ();
+    }
+}
+
+static void
+xbm_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
+		   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+		   int dest_mask, int width, int height,
+		   /* Note that data is in ext-format! */
+		   CONST char *bits)
+{
+  Lisp_Object mask_data = find_keyword_in_vector (instantiator, Q_mask_data);
+  Lisp_Object mask_file = find_keyword_in_vector (instantiator, Q_mask_file);
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  struct frame* f = XFRAME (DEVICE_SELECTED_FRAME 
+			    (XDEVICE (IMAGE_INSTANCE_DEVICE (ii))));
+  HDC hdc = FRAME_MSWINDOWS_CDC (f);
+  HBITMAP mask = 0;
+  CONST char *gcc_may_you_rot_in_hell;
+
+  if (!NILP (mask_data))
+    {
+      GET_C_STRING_BINARY_DATA_ALLOCA (XCAR (XCDR (XCDR (mask_data))),
+				       gcc_may_you_rot_in_hell);
+      mask =
+	xbm_create_bitmap_from_data ( hdc,
+				      (unsigned char *)
+				      gcc_may_you_rot_in_hell,
+				      XINT (XCAR (mask_data)),
+				      XINT (XCAR (XCDR (mask_data))), FALSE,
+				      PALETTERGB (0,0,0),
+				      PALETTERGB (255,255,255));
+    }
+
+  init_image_instance_from_xbm_inline (ii, width, height, bits,
+				       instantiator, pointer_fg, pointer_bg,
+				       dest_mask, mask, mask_file);
+}
+
+/* Instantiate method for XBM's. */
+
+static void
+mswindows_xbm_instantiate (Lisp_Object image_instance, 
+			   Lisp_Object instantiator,
+			   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			   int dest_mask, Lisp_Object domain)
+{
+  Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
+  CONST char *gcc_go_home;
+
+  assert (!NILP (data));
+
+  GET_C_STRING_BINARY_DATA_ALLOCA (XCAR (XCDR (XCDR (data))),
+				   gcc_go_home);
+
+  xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
+		     pointer_bg, dest_mask, XINT (XCAR (data)),
+		     XINT (XCAR (XCDR (data))), gcc_go_home);
+}
+
+#ifdef HAVE_XFACE
+/**********************************************************************
+ *                             X-Face                                 *
+ **********************************************************************/
+#if defined(EXTERN)
+/* This is about to get redefined! */
+#undef EXTERN
+#endif
+/* We have to define SYSV32 so that compface.h includes string.h
+   instead of strings.h. */
+#define SYSV32
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <compface.h>
+#ifdef __cplusplus
+}
+#endif
+/* JMP_BUF cannot be used here because if it doesn't get defined
+   to jmp_buf we end up with a conflicting type error with the
+   definition in compface.h */
+extern jmp_buf comp_env;
+#undef SYSV32
+
+static void
+mswindows_xface_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			     int dest_mask, Lisp_Object domain)
+{
+  Lisp_Object data = find_keyword_in_vector (instantiator, Q_data);
+  int i, stattis;
+  char *p, *bits, *bp;
+  CONST char * volatile emsg = 0;
+  CONST char * volatile dstring;
+
+  assert (!NILP (data));
+
+  GET_C_STRING_BINARY_DATA_ALLOCA (data, dstring);
+
+  if ((p = strchr (dstring, ':')))
+    {
+      dstring = p + 1;
+    }
+
+  /* Must use setjmp not SETJMP because we used jmp_buf above not JMP_BUF */
+  if (!(stattis = setjmp (comp_env)))
+    {
+      UnCompAll ((char *) dstring);
+      UnGenFace ();
+    }
+
+  switch (stattis)
+    {
+    case -2:
+      emsg = "uncompface: internal error";
+      break;
+    case -1:
+      emsg = "uncompface: insufficient or invalid data";
+      break;
+    case 1:
+      emsg = "uncompface: excess data ignored";
+      break;
+    }
+
+  if (emsg)
+    signal_simple_error_2 (emsg, data, Qimage);
+
+  bp = bits = (char *) alloca (PIXELS / 8);
+
+  /* the compface library exports char F[], which uses a single byte per
+     pixel to represent a 48x48 bitmap.  Yuck. */
+  for (i = 0, p = F; i < (PIXELS / 8); ++i)
+    {
+      int n, b;
+      /* reverse the bit order of each byte... */
+      for (b = n = 0; b < 8; ++b)
+	{
+	  n |= ((*p++) << b);
+	}
+      *bp++ = (char) n;
+    }
+
+  xbm_instantiate_1 (image_instance, instantiator, pointer_fg,
+		     pointer_bg, dest_mask, 48, 48, bits);
+}
+#endif /* HAVE_XFACE */
+
+
+/************************************************************************/
+/*                      image instance methods                          */
+/************************************************************************/
+
+static void
+mswindows_print_image_instance (struct Lisp_Image_Instance *p,
+				Lisp_Object printcharfun,
+				int escapeflag)
+{
+  char buf[100];
+
+  switch (IMAGE_INSTANCE_TYPE (p))
+    {
+    case IMAGE_MONO_PIXMAP:
+    case IMAGE_COLOR_PIXMAP:
+    case IMAGE_POINTER:
+      sprintf (buf, " (0x%lx", 
+	       (unsigned long) IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
+      write_c_string (buf, printcharfun);
+      if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
+	{
+	  sprintf (buf, "/0x%lx", 
+		   (unsigned long) IMAGE_INSTANCE_MSWINDOWS_MASK (p));
+	  write_c_string (buf, printcharfun);
+	}
+      write_c_string (")", printcharfun);
+      break;
+
+    default:
+      break;
+    }
+}
+
+#ifdef DEBUG_WIDGETS
+extern int debug_widget_instances;
+#endif
+
+static void
+mswindows_finalize_image_instance (struct Lisp_Image_Instance *p)
+{
+  if (DEVICE_LIVE_P (XDEVICE (p->device)))
+    {
+      if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET
+	  || 
+	  IMAGE_INSTANCE_TYPE (p) == IMAGE_SUBWINDOW)
+	{
+#ifdef DEBUG_WIDGETS
+	  debug_widget_instances--;
+	  stderr_out ("widget destroyed, %d left\n", debug_widget_instances);
+#endif
+	  if (IMAGE_INSTANCE_SUBWINDOW_ID (p))
+	    {
+	      DestroyWindow (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p));
+	      DestroyWindow (IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (p));
+	      IMAGE_INSTANCE_SUBWINDOW_ID (p) = 0;
+	    }
+	}
+      else if (p->data)
+	{
+	  int i;
+	  if (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p))
+	    disable_glyph_animated_timeout (IMAGE_INSTANCE_PIXMAP_TIMEOUT (p));
+
+	  if (IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICES (p))
+	    {
+	      for (i = 0; i < IMAGE_INSTANCE_PIXMAP_MAXSLICE (p); i++)
+		{
+		  if (IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE (p, i))
+		    DeleteObject (IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE (p, i));
+		  IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICE (p, i) = 0;
+		}
+	      xfree (IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICES (p));
+	      IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICES (p) = 0;
+	    }
+	  if (IMAGE_INSTANCE_MSWINDOWS_MASK (p))
+	    DeleteObject (IMAGE_INSTANCE_MSWINDOWS_MASK (p));
+	  IMAGE_INSTANCE_MSWINDOWS_MASK (p) = 0;
+	  if (IMAGE_INSTANCE_MSWINDOWS_ICON (p))
+	    DestroyIcon (IMAGE_INSTANCE_MSWINDOWS_ICON (p));
+	  IMAGE_INSTANCE_MSWINDOWS_ICON (p) = 0;
+	}
+    }
+
+  if (p->data)
+    {
+      xfree (p->data);
+      p->data = 0;
+    }
+}
+
+/************************************************************************/
+/*                      subwindow and widget support                      */
+/************************************************************************/
+
+/* unmap the image if it is a widget. This is used by redisplay via
+   redisplay_unmap_subwindows */
+static void
+mswindows_unmap_subwindow (struct Lisp_Image_Instance *p)
+{
+  if (IMAGE_INSTANCE_SUBWINDOW_ID (p))
+    {
+      SetWindowPos (IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (p), 
+		    NULL, 
+		    0, 0, 0, 0,
+		    SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE
+		    | SWP_NOSENDCHANGING);
+    }
+}
+
+/* map the subwindow. This is used by redisplay via
+   redisplay_output_subwindow */
+static void
+mswindows_map_subwindow (struct Lisp_Image_Instance *p, int x, int y,
+			 struct display_glyph_area* dga)
+{
+  /* move the window before mapping it ... */
+  SetWindowPos (IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (p),
+		NULL, 
+		x, y, dga->width, dga->height,
+		SWP_NOZORDER 
+		| SWP_NOCOPYBITS | SWP_NOSENDCHANGING);
+  /* ... adjust the child ... */
+  SetWindowPos (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p),
+		NULL, 
+		-dga->xoffset, -dga->yoffset, 0, 0,
+		SWP_NOZORDER | SWP_NOSIZE
+		| SWP_NOCOPYBITS | SWP_NOSENDCHANGING);
+  /* ... now map it - we are not allowed to move it at the same time. */
+  SetWindowPos (IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (p), 
+		NULL, 
+		0, 0, 0, 0,
+		SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE
+		| SWP_SHOWWINDOW | SWP_NOCOPYBITS 
+		| SWP_NOSENDCHANGING);
+}
+
+/* resize the subwindow instance */
+static void 
+mswindows_resize_subwindow (struct Lisp_Image_Instance* ii, int w, int h)
+{
+  /* Set the size of the control .... */
+  SetWindowPos (WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii), 
+		NULL, 
+		0, 0, w, h,
+		SWP_NOZORDER | SWP_NOMOVE
+		| SWP_NOCOPYBITS | SWP_NOSENDCHANGING);
+}
+
+/* when you click on a widget you may activate another widget this
+   needs to be checked and all appropriate widgets updated */
+static void
+mswindows_update_subwindow (struct Lisp_Image_Instance *p)
+{
+  if (IMAGE_INSTANCE_TYPE (p) == IMAGE_WIDGET)
+    {
+      /* buttons checked or otherwise */
+      if ( EQ (IMAGE_INSTANCE_WIDGET_TYPE (p), Qbutton))
+	{
+	  if (gui_item_selected_p (IMAGE_INSTANCE_WIDGET_ITEM (p)))
+	    SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p), 
+			 BM_SETCHECK, (WPARAM)BST_CHECKED, 0); 
+	  else
+	    SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p),
+			 BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
+	}
+
+      /* set the widget font from the widget face */
+      SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (p),
+		   WM_SETFONT, 
+		   (WPARAM)FONT_INSTANCE_MSWINDOWS_HFONT 
+		   (XFONT_INSTANCE (widget_face_font_info
+				    (IMAGE_INSTANCE_SUBWINDOW_FRAME (p), 
+				     IMAGE_INSTANCE_WIDGET_FACE (p),
+				     0, 0))), 
+		   MAKELPARAM (TRUE, 0));
+    }
+}
+
+/* register widgets into our hastable so that we can cope with the
+   callbacks. The hashtable is weak so deregistration is handled
+   automatically */
+static int
+mswindows_register_gui_item (Lisp_Object gui, Lisp_Object domain)
+{
+  Lisp_Object frame = FW_FRAME (domain);
+  struct frame* f = XFRAME (frame);
+  int id = gui_item_id_hash (FRAME_MSWINDOWS_WIDGET_HASH_TABLE (f),
+			     gui,
+			     WIDGET_GLYPH_SLOT);
+  Fputhash (make_int (id),
+	    XGUI_ITEM (gui)->callback,
+	    FRAME_MSWINDOWS_WIDGET_HASH_TABLE (f));
+  return id;
+}
+
+static int
+mswindows_register_widget_instance (Lisp_Object instance, Lisp_Object domain)
+{
+  return mswindows_register_gui_item (XIMAGE_INSTANCE_WIDGET_ITEM (instance),
+				      domain);
+}
+
+static void
+mswindows_subwindow_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+				 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+				 int dest_mask, Lisp_Object domain)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii);
+  struct device* d = XDEVICE (device);
+  Lisp_Object frame = FW_FRAME (domain);
+  HWND wnd;
+
+  if (!DEVICE_MSWINDOWS_P (d))
+    signal_simple_error ("Not an mswindows device", device);
+
+  /* have to set the type this late in case there is no device
+     instantiation for a widget */
+  IMAGE_INSTANCE_TYPE (ii) = IMAGE_SUBWINDOW;
+  /* Allocate space for the clip window */
+  ii->data = xnew_and_zero (struct mswindows_subwindow_data);
+
+  if ((IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii)
+       = CreateWindowEx(
+			0,		/* EX flags */
+			XEMACS_CONTROL_CLASS,
+			0,		/* text */
+			WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD,
+			0,         /* starting x position */
+			0,         /* starting y position */
+			IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+			IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+			/* parent window */
+			FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+			NULL,       /* No menu */
+			NULL, /* must be null for this class */
+			NULL)) == NULL)
+    signal_simple_error ("window creation failed with code", 
+			 make_int (GetLastError()));
+
+  wnd = CreateWindow( "STATIC",  
+		      "",
+		      WS_CHILD,  
+		      0,         /* starting x position */
+		      0,         /* starting y position */
+		      IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+		      IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+		      IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii),
+		      0,
+		      (HINSTANCE) 
+		      GetWindowLong (FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+				     GWL_HINSTANCE), 
+		      NULL);
+
+  SetWindowLong (wnd, GWL_USERDATA, (LONG)LISP_TO_VOID(image_instance));
+  IMAGE_INSTANCE_SUBWINDOW_ID (ii) = wnd;
+}
+
+static int
+mswindows_image_instance_equal (struct Lisp_Image_Instance *p1,
+				struct Lisp_Image_Instance *p2, int depth)
+{
+  switch (IMAGE_INSTANCE_TYPE (p1))
+    {
+    case IMAGE_MONO_PIXMAP:
+    case IMAGE_COLOR_PIXMAP:
+    case IMAGE_POINTER:
+      if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p1) 
+	  != IMAGE_INSTANCE_MSWINDOWS_BITMAP (p2))
+	return 0;
+      break;
+    
+    default:
+      break;
+    }
+
+  return 1;
+}
+
+static unsigned long
+mswindows_image_instance_hash (struct Lisp_Image_Instance *p, int depth)
+{
+  switch (IMAGE_INSTANCE_TYPE (p))
+    {
+    case IMAGE_MONO_PIXMAP:
+    case IMAGE_COLOR_PIXMAP:
+    case IMAGE_POINTER:
+      return (unsigned long) IMAGE_INSTANCE_MSWINDOWS_BITMAP (p);
+    
+    default:
+      return 0;
+    }
+}
+
+/* Set all the slots in an image instance structure to reasonable
+   default values.  This is used somewhere within an instantiate
+   method.  It is assumed that the device slot within the image
+   instance is already set -- this is the case when instantiate
+   methods are called. */
+
+static void
+mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
+					      int slices,
+					      enum image_instance_type type)
+{
+  ii->data = xnew_and_zero (struct mswindows_image_instance_data);
+  IMAGE_INSTANCE_TYPE (ii) = type;
+  IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_MASK_FILENAME (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_FG (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_BG (ii) = Qnil;
+  IMAGE_INSTANCE_PIXMAP_MAXSLICE (ii) = slices;
+  IMAGE_INSTANCE_MSWINDOWS_BITMAP_SLICES (ii) = 
+    xnew_array_and_zero (HBITMAP, slices);
+}
+
+
+#ifdef HAVE_WIDGETS
+
+/************************************************************************/
+/*                            widgets                            */
+/************************************************************************/
+static void
+mswindows_widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			      int dest_mask, Lisp_Object domain,
+			      CONST char* class, int flags, int exflags)
+{
+  /* this function can call lisp */
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  Lisp_Object device = IMAGE_INSTANCE_DEVICE (ii), style;
+  struct device* d = XDEVICE (device);
+  Lisp_Object frame = FW_FRAME (domain);
+  Extbyte* nm=0;
+  HWND wnd;
+  int id = 0xffff;
+  Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
+  struct Lisp_Gui_Item* pgui = XGUI_ITEM (gui);
+
+  if (!DEVICE_MSWINDOWS_P (d))
+    signal_simple_error ("Not an mswindows device", device);
+
+  if (!gui_item_active_p (gui))
+    flags |= WS_DISABLED;
+
+  style = pgui->style;
+
+  if (!NILP (pgui->callback))
+    {
+      id = mswindows_register_widget_instance (image_instance, domain);
+    }
+  /* have to set the type this late in case there is no device
+     instantiation for a widget */
+  IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
+  if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
+    GET_C_STRING_OS_DATA_ALLOCA (IMAGE_INSTANCE_WIDGET_TEXT (ii), nm);
+
+  /* allocate space for the clip window and then allocate the clip window */
+  ii->data = xnew_and_zero (struct mswindows_subwindow_data);
+
+  if ((IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii)
+       = CreateWindowEx(
+			0,		/* EX flags */
+			XEMACS_CONTROL_CLASS,
+			0,		/* text */
+			WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_CHILD,
+			0,         /* starting x position */
+			0,         /* starting y position */
+			IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+			IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+			/* parent window */
+			FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+			(HMENU)id,       /* No menu */
+			NULL, /* must be null for this class */
+			NULL)) == NULL)
+    signal_simple_error ("window creation failed with code", 
+			 make_int (GetLastError()));
+
+  if ((wnd = CreateWindowEx( 
+			    exflags /* | WS_EX_NOPARENTNOTIFY*/,
+			    class,  
+			    nm,
+			    flags | WS_CHILD | WS_VISIBLE,
+			    0,         /* starting x position */
+			    0,         /* starting y position */
+			    IMAGE_INSTANCE_WIDGET_WIDTH (ii),
+			    IMAGE_INSTANCE_WIDGET_HEIGHT (ii),
+			    /* parent window */
+			    IMAGE_INSTANCE_MSWINDOWS_CLIPWINDOW (ii),
+			    (HMENU)id,       /* No menu */
+			    (HINSTANCE) 
+			    GetWindowLong 
+			    (FRAME_MSWINDOWS_HANDLE (XFRAME (frame)),
+			     GWL_HINSTANCE), 
+			    NULL)) == NULL)
+    signal_simple_error ("window creation failed with code", 
+			 make_int (GetLastError()));
+
+  IMAGE_INSTANCE_SUBWINDOW_ID (ii) = wnd;
+  SetWindowLong (wnd, GWL_USERDATA, (LONG)LISP_TO_VOID(image_instance));
+  /* set the widget font from the widget face */
+  SendMessage (wnd, WM_SETFONT, 
+	       (WPARAM)FONT_INSTANCE_MSWINDOWS_HFONT 
+	       (XFONT_INSTANCE (widget_face_font_info 
+				(domain, 
+				 IMAGE_INSTANCE_WIDGET_FACE (ii),
+				 0, 0))), 
+	       MAKELPARAM (TRUE, 0));
+}
+
+/* Instantiate a button widget. Unfortunately instantiated widgets are
+   particular to a frame since they need to have a parent. It's not
+   like images where you just select the image into the context you
+   want to display it in and BitBlt it. So images instances can have a
+   many-to-one relationship with things you see, whereas widgets can
+   only be one-to-one (i.e. per frame) */
+static void
+mswindows_button_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			      Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			      int dest_mask, Lisp_Object domain)
+{
+  /* this function can call lisp */
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  HWND wnd;
+  int flags = BS_NOTIFY;
+  Lisp_Object style;
+  Lisp_Object gui = IMAGE_INSTANCE_WIDGET_ITEM (ii);
+  struct Lisp_Gui_Item* pgui = XGUI_ITEM (gui);
+  Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
+
+  if (!gui_item_active_p (gui))
+    flags |= WS_DISABLED;
+
+  if (!NILP (glyph))
+    {
+      if (!IMAGE_INSTANCEP (glyph))
+	glyph = glyph_image_instance (glyph, domain, ERROR_ME, 1);
+
+      if (IMAGE_INSTANCEP (glyph))
+	flags |= XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ? 
+	  BS_BITMAP : BS_ICON;
+    }
+
+  style = pgui->style;
+
+  if (EQ (style, Qradio))
+    {
+      flags |= BS_RADIOBUTTON;
+    }
+  else if (EQ (style, Qtoggle))
+    {
+      flags |= BS_AUTOCHECKBOX;
+    }
+  else
+    flags |= BS_DEFPUSHBUTTON;
+
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, "BUTTON", flags, 
+				WS_EX_CONTROLPARENT);
+
+  wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* set the checked state */
+  if (gui_item_selected_p (gui))
+    SendMessage (wnd, BM_SETCHECK, (WPARAM)BST_CHECKED, 0); 
+  else
+    SendMessage (wnd, BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0);
+  /* add the image if one was given */
+  if (!NILP (glyph) && IMAGE_INSTANCEP (glyph))
+    {
+      SendMessage (wnd, BM_SETIMAGE, 
+		   (WPARAM) (XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ? 
+			     IMAGE_BITMAP : IMAGE_ICON),
+		   (LPARAM) (XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) ?
+			     XIMAGE_INSTANCE_MSWINDOWS_BITMAP (glyph) :
+			     XIMAGE_INSTANCE_MSWINDOWS_ICON (glyph)));
+    }
+}
+
+/* instantiate an edit control */
+static void
+mswindows_edit_field_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			    int dest_mask, Lisp_Object domain)
+{
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, "EDIT", 
+				ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP
+				| WS_BORDER,
+				WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT);
+}
+
+/* instantiate a progress gauge */
+static void
+mswindows_progress_gauge_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+				Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+				int dest_mask, Lisp_Object domain)
+{
+  HWND wnd;
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, PROGRESS_CLASS, 
+				WS_TABSTOP | WS_BORDER | PBS_SMOOTH,
+				WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT);
+  wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* set the colors */
+#ifdef PBS_SETBKCOLOR
+  SendMessage (wnd, PBS_SETBKCOLOR, 0, 
+	       (LPARAM) (COLOR_INSTANCE_MSWINDOWS_COLOR 
+			 (XCOLOR_INSTANCE 
+			  (FACE_BACKGROUND 
+			   (XIMAGE_INSTANCE_WIDGET_FACE (ii),
+			    XIMAGE_INSTANCE_SUBWINDOW_FRAME (ii))))));
+#endif
+#ifdef PBS_SETBARCOLOR
+  SendMessage (wnd, PBS_SETBARCOLOR, 0, 
+	       (L:PARAM) (COLOR_INSTANCE_MSWINDOWS_COLOR 
+			  (XCOLOR_INSTANCE 
+			   (FACE_FOREGROUND 
+			    (XIMAGE_INSTANCE_WIDGET_FACE (ii),
+			     XIMAGE_INSTANCE_SUBWINDOW_FRAME (ii))))));
+#endif
+}
+
+/* instantiate a tree view widget */
+static HTREEITEM add_tree_item (Lisp_Object image_instance,
+				HWND wnd, HTREEITEM parent, Lisp_Object item,
+				int children, Lisp_Object domain)
+{
+  TV_INSERTSTRUCT tvitem;
+  HTREEITEM ret;
+
+  tvitem.hParent = parent;
+  tvitem.hInsertAfter = TVI_LAST;
+  tvitem.item.mask = TVIF_TEXT | TVIF_CHILDREN;
+  tvitem.item.cChildren = children;
+      
+  if (GUI_ITEMP (item))
+    {
+      tvitem.item.lParam = mswindows_register_gui_item (item, domain);
+      tvitem.item.mask |= TVIF_PARAM;
+      GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (item)->name, 
+				   tvitem.item.pszText);
+    }
+  else
+    GET_C_STRING_OS_DATA_ALLOCA (item, tvitem.item.pszText);
+
+  tvitem.item.cchTextMax = strlen (tvitem.item.pszText);
+
+  if ((ret = (HTREEITEM)SendMessage (wnd, TVM_INSERTITEM, 
+				     0, (LPARAM)&tvitem)) == 0)
+    signal_simple_error ("error adding tree view entry", item);
+
+  return ret;
+}
+
+static void add_tree_item_list (Lisp_Object image_instance,
+				HWND wnd, HTREEITEM parent, Lisp_Object list,
+				Lisp_Object domain)
+{
+  Lisp_Object rest;
+
+  /* get the first item */
+  parent = add_tree_item (image_instance, wnd, parent, XCAR (list), TRUE, domain);
+  /* recursively add items to the tree view */
+  LIST_LOOP (rest, XCDR (list))
+    {
+      if (LISTP (XCAR (rest)))
+	add_tree_item_list (image_instance, wnd, parent, XCAR (rest), domain);
+      else
+	add_tree_item (image_instance, wnd, parent, XCAR (rest), FALSE, domain);
+    }
+}
+
+static void
+mswindows_tree_view_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			    int dest_mask, Lisp_Object domain)
+{
+  Lisp_Object rest;
+  HWND wnd;
+  HTREEITEM parent;
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, WC_TREEVIEW, 
+				WS_TABSTOP | WS_BORDER | PBS_SMOOTH
+				| TVS_HASLINES | TVS_HASBUTTONS,
+				WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT);
+
+  wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+ 
+  /* define a root */
+  parent = add_tree_item (image_instance, wnd, NULL, 
+			  XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)), 
+			  TRUE, domain);
+ 
+  /* recursively add items to the tree view */
+  /* add items to the tab */
+  LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+    {
+      if (LISTP (XCAR (rest)))
+	add_tree_item_list (image_instance, wnd, parent, XCAR (rest), domain);
+      else
+	add_tree_item (image_instance, wnd, parent, XCAR (rest), FALSE, domain);
+    }
+}
+
+/* instantiate a tab control */
+static TC_ITEM* add_tab_item (Lisp_Object image_instance,
+			     HWND wnd, Lisp_Object item,
+			     Lisp_Object domain, int index)
+{
+  TC_ITEM tvitem, *ret;
+
+  tvitem.mask = TCIF_TEXT;
+      
+  if (GUI_ITEMP (item))
+    {
+      tvitem.lParam = mswindows_register_gui_item (item, domain);
+      tvitem.mask |= TCIF_PARAM;
+      GET_C_STRING_OS_DATA_ALLOCA (XGUI_ITEM (item)->name, 
+				   tvitem.pszText);
+    }
+  else
+    {
+      CHECK_STRING (item);
+      GET_C_STRING_OS_DATA_ALLOCA (item, tvitem.pszText);
+    }
+
+  tvitem.cchTextMax = strlen (tvitem.pszText);
+
+  if ((ret = (TC_ITEM*)SendMessage (wnd, TCM_INSERTITEM, 
+				    index, (LPARAM)&tvitem)) < 0)
+    signal_simple_error ("error adding tab entry", item);
+
+  return ret;
+}
+
+static void
+mswindows_tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			   Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			   int dest_mask, Lisp_Object domain)
+{
+  Lisp_Object rest;
+  HWND wnd;
+  int index = 0;
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, WC_TABCONTROL, 
+				/* borders don't suit tabs so well */
+				WS_TABSTOP,
+				WS_EX_CONTROLPARENT);
+
+  wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* add items to the tab */
+  LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+    {
+      add_tab_item (image_instance, wnd, XCAR (rest), domain, index);
+      index++;
+    }
+}
+
+/* set the properties of a tab control */
+static Lisp_Object
+mswindows_tab_control_set_property (Lisp_Object image_instance, Lisp_Object prop,
+				    Lisp_Object val)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
+  if (EQ (prop, Q_items))
+    {
+      HWND wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+      int index = 0;
+      Lisp_Object rest;
+      check_valid_item_list_1 (val);
+
+      /* delete the pre-existing items */
+      SendMessage (wnd, TCM_DELETEALLITEMS, 0, 0);
+  
+      IMAGE_INSTANCE_WIDGET_ITEMS (ii) = 
+	Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)), 
+	       parse_gui_item_tree_children (val));
+
+      /* add items to the tab */
+      LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))
+	{
+	  add_tab_item (image_instance, wnd, XCAR (rest), 
+			IMAGE_INSTANCE_SUBWINDOW_FRAME (ii), index);
+	  index++;
+	}
+
+      return Qt;
+    }
+  return Qunbound;
+}
+
+/* instantiate a static control possible for putting other things in */
+static void
+mswindows_label_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			     int dest_mask, Lisp_Object domain)
+{
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, "STATIC", 
+				0, WS_EX_STATICEDGE);
+}
+
+/* instantiate a scrollbar control */
+static void
+mswindows_scrollbar_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+				 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+				 int dest_mask, Lisp_Object domain)
+{
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, "SCROLLBAR", 
+				0,
+				WS_EX_CLIENTEDGE );
+}
+
+/* instantiate a combo control */
+static void
+mswindows_combo_box_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
+			     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
+			     int dest_mask, Lisp_Object domain)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  HANDLE wnd;
+  Lisp_Object rest;
+  Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties),
+				 Q_items, Qnil);
+  int len;
+  GET_LIST_LENGTH (data, len);
+
+  /* Maybe ought to generalise this more but it may be very windows
+     specific. In windows the window height of a combo box is the
+     height when the combo box is open. Thus we need to set the height
+     before creating the window and then reset it to a single line
+     after the window is created so that redisplay does the right
+     thing. */
+  widget_instantiate_1 (image_instance, instantiator, pointer_fg,
+			pointer_bg, dest_mask, domain, len + 1, 0, 0);
+
+  mswindows_widget_instantiate (image_instance, instantiator, pointer_fg,
+				pointer_bg, dest_mask, domain, "COMBOBOX", 
+				WS_BORDER | WS_TABSTOP | CBS_DROPDOWN
+				| CBS_AUTOHSCROLL  
+				| CBS_HASSTRINGS | WS_VSCROLL,
+				WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT);
+  /* reset the height */
+  widget_text_to_pixel_conversion (domain, 
+				   IMAGE_INSTANCE_WIDGET_FACE (ii), 1, 0, 
+				   &IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii), 0);
+  wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* add items to the combo box */
+  SendMessage (wnd, CB_RESETCONTENT, 0, 0);
+  LIST_LOOP (rest, Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), Q_items, Qnil))
+    {
+      Extbyte* lparam;
+      GET_C_STRING_OS_DATA_ALLOCA (XCAR (rest), lparam);
+      if (SendMessage (wnd, CB_ADDSTRING, 0, (LPARAM)lparam) == CB_ERR)
+	signal_simple_error ("error adding combo entries", instantiator);
+    }
+}
+
+/* get properties of a control */
+static Lisp_Object
+mswindows_widget_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  HANDLE wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* get the text from a control */
+  if (EQ (prop, Q_text))
+    {
+      Extcount len = SendMessage (wnd, WM_GETTEXTLENGTH, 0, 0);
+      Extbyte* buf =alloca (len+1);
+      
+      SendMessage (wnd, WM_GETTEXT, (WPARAM)len+1, (LPARAM) buf);
+      return build_ext_string (buf, FORMAT_OS);
+    }
+  return Qunbound;
+}
+
+/* get properties of a button */
+static Lisp_Object
+mswindows_button_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  HANDLE wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* check the state of a button */
+  if (EQ (prop, Q_selected))
+    {
+      if (SendMessage (wnd, BM_GETSTATE, 0, 0) & BST_CHECKED)
+	return Qt;
+      else
+	return Qnil;
+    }
+  return Qunbound;
+}
+
+/* get properties of a combo box */
+static Lisp_Object
+mswindows_combo_box_property (Lisp_Object image_instance, Lisp_Object prop)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+  HANDLE wnd = WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii);
+  /* get the text from a control */
+  if (EQ (prop, Q_text))
+    {
+      long item = SendMessage (wnd, CB_GETCURSEL, 0, 0);
+      Extcount len = SendMessage (wnd, CB_GETLBTEXTLEN, (WPARAM)item, 0);
+      Extbyte* buf = alloca (len+1);
+      SendMessage (wnd, CB_GETLBTEXT, (WPARAM)item, (LPARAM)buf);
+      return build_ext_string (buf, FORMAT_OS);
+    }
+  return Qunbound;
+}
+
+/* set the properties of a control */
+static Lisp_Object
+mswindows_widget_set_property (Lisp_Object image_instance, Lisp_Object prop,
+			       Lisp_Object val)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
+  if (EQ (prop, Q_text))
+    {
+      Extbyte* lparam=0;
+      CHECK_STRING (val);
+      GET_C_STRING_OS_DATA_ALLOCA (val, lparam);
+      SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii),
+		   WM_SETTEXT, 0, (LPARAM)lparam);
+      return Qt;
+    }
+  return Qunbound;
+}
+
+/* set the properties of a progres guage */
+static Lisp_Object
+mswindows_progress_gauge_set_property (Lisp_Object image_instance, Lisp_Object prop,
+				 Lisp_Object val)
+{
+  struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
+
+  if (EQ (prop, Q_percent))
+    {
+      CHECK_INT (val);
+      SendMessage (WIDGET_INSTANCE_MSWINDOWS_HANDLE (ii),
+		   PBM_SETPOS, (WPARAM)XINT (val), 0);
+      return Qt;
+    }
+  return Qunbound;
+}
+
+LRESULT WINAPI
+mswindows_control_wnd_proc (HWND hwnd, UINT message,
+			    WPARAM wParam, LPARAM lParam)
+{
+  switch (message)
+    {
+    case WM_NOTIFY:
+    case WM_COMMAND:
+    case WM_CTLCOLORBTN:
+    case WM_CTLCOLORLISTBOX:
+    case WM_CTLCOLOREDIT:
+    case WM_CTLCOLORSTATIC:
+    case WM_CTLCOLORSCROLLBAR:
+
+      return mswindows_wnd_proc (GetParent (hwnd), message, wParam, lParam);
+    default:
+      return DefWindowProc (hwnd, message, wParam, lParam);
+    }
+}
+
+#endif /* HAVE_WIDGETS */
+
+
+/************************************************************************/
+/*                            initialization                            */
+/************************************************************************/
+
+void
+syms_of_glyphs_mswindows (void)
+{
+  defkeyword (&Q_resource_id, ":resource-id");
+  defkeyword (&Q_resource_type, ":resource-type");
+}
+
+void
+console_type_create_glyphs_mswindows (void)
+{
+  /* image methods */
+
+  CONSOLE_HAS_METHOD (mswindows, print_image_instance);
+  CONSOLE_HAS_METHOD (mswindows, finalize_image_instance);
+  CONSOLE_HAS_METHOD (mswindows, unmap_subwindow);
+  CONSOLE_HAS_METHOD (mswindows, map_subwindow);
+  CONSOLE_HAS_METHOD (mswindows, update_subwindow);
+  CONSOLE_HAS_METHOD (mswindows, image_instance_equal);
+  CONSOLE_HAS_METHOD (mswindows, image_instance_hash);
+  CONSOLE_HAS_METHOD (mswindows, init_image_instance_from_eimage);
+  CONSOLE_HAS_METHOD (mswindows, locate_pixmap_file);
+  CONSOLE_HAS_METHOD (mswindows, resize_subwindow);
+}
+
+void
+image_instantiator_format_create_glyphs_mswindows (void)
+{
+  IIFORMAT_VALID_CONSOLE (mswindows, nothing);
+  IIFORMAT_VALID_CONSOLE (mswindows, string);
+  IIFORMAT_VALID_CONSOLE (mswindows, layout);
+  IIFORMAT_VALID_CONSOLE (mswindows, formatted_string);
+  IIFORMAT_VALID_CONSOLE (mswindows, inherit);
+  /* image-instantiator types */
+#ifdef HAVE_XPM
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, xpm);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, xpm, instantiate);
+#endif
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, xbm);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, xbm, instantiate);
+#ifdef HAVE_XFACE
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, xface);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, xface, instantiate);
+#endif
+#ifdef HAVE_JPEG
+  IIFORMAT_VALID_CONSOLE (mswindows, jpeg);
+#endif
+#ifdef HAVE_TIFF
+  IIFORMAT_VALID_CONSOLE (mswindows, tiff);
+#endif  
+#ifdef HAVE_PNG
+  IIFORMAT_VALID_CONSOLE (mswindows, png);
+#endif  
+#ifdef HAVE_GIF
+  IIFORMAT_VALID_CONSOLE (mswindows, gif);
+#endif  
+#ifdef HAVE_WIDGETS
+  /* button widget */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, button);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, button, property);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, button, instantiate);
+
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, edit_field);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, edit_field, instantiate);
+  
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, subwindow);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, subwindow, instantiate);
+
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, widget);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, widget, property);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, widget, set_property);
+
+  /* label */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, label);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, label, instantiate);
+
+  /* combo box */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, combo_box);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, combo_box, property);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, combo_box, instantiate);
+
+  /* scrollbar */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, scrollbar);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, scrollbar, instantiate);
+
+  /* progress gauge */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, progress_gauge);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, progress_gauge, set_property);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, progress_gauge, instantiate);
+
+  /* tree view widget */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, tree_view);
+  /*  IIFORMAT_HAS_DEVMETHOD (mswindows, progress, set_property);*/
+  IIFORMAT_HAS_DEVMETHOD (mswindows, tree_view, instantiate);
+
+  /* tab control widget */
+  INITIALIZE_DEVICE_IIFORMAT (mswindows, tab_control);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, tab_control, instantiate);
+  IIFORMAT_HAS_DEVMETHOD (mswindows, tab_control, set_property);
+#endif
+  /* windows bitmap format */
+  INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (bmp, "bmp");
+  IIFORMAT_HAS_METHOD (bmp, validate);
+  IIFORMAT_HAS_METHOD (bmp, normalize);
+  IIFORMAT_HAS_METHOD (bmp, possible_dest_types);
+  IIFORMAT_HAS_METHOD (bmp, instantiate);
+
+  IIFORMAT_VALID_KEYWORD (bmp, Q_data, check_valid_string);
+  IIFORMAT_VALID_KEYWORD (bmp, Q_file, check_valid_string);
+  IIFORMAT_VALID_CONSOLE (mswindows, bmp);
+
+  /* mswindows resources */
+  INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (mswindows_resource,
+					"mswindows-resource");
+
+  IIFORMAT_HAS_METHOD (mswindows_resource, validate);
+  IIFORMAT_HAS_METHOD (mswindows_resource, normalize);
+  IIFORMAT_HAS_METHOD (mswindows_resource, possible_dest_types);
+  IIFORMAT_HAS_METHOD (mswindows_resource, instantiate);
+
+  IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_resource_type, 
+			  check_valid_resource_symbol);
+  IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_resource_id, check_valid_resource_id);
+  IIFORMAT_VALID_KEYWORD (mswindows_resource, Q_file, check_valid_string);
+  IIFORMAT_VALID_CONSOLE (mswindows, mswindows_resource);
+}
+
+void
+vars_of_glyphs_mswindows (void)
+{
+  DEFVAR_LISP ("mswindows-bitmap-file-path", &Vmswindows_bitmap_file_path /*
+A list of the directories in which mswindows bitmap files may be found.
+This is used by the `make-image-instance' function.
+*/ );
+  Vmswindows_bitmap_file_path = Qnil;
+}
+
+void
+complex_vars_of_glyphs_mswindows (void)
+{
+}