XEmacs 21.2.20 "Yoko".
[chise/xemacs-chise.git.1] / src / glyphs-msw.c
index 7366c8e..d3c11b6 100644 (file)
@@ -1,5 +1,5 @@
-/* mswindows-specific Lisp objects.
-   Copyright (C) 1998 Andy Piper.
+/* mswindows-specific glyph objects.
+   Copyright (C) 1998, 1999 Andy Piper.
    
 This file is part of XEmacs.
 
@@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA.  */
 
 /* Synched up with: Not in FSF. */
 
-/* written by Andy Piper <andyp@parallax.co.uk> plagerising buts from
+/* written by Andy Piper <andy@xemacs.org> plagerising bits from
    glyphs-x.c */
 
 #include <config.h>
@@ -32,6 +32,8 @@ Boston, MA 02111-1307, USA.  */
 #include "glyphs-msw.h"
 #include "objects-msw.h"
 
+#include "window.h"
+#include "elhash.h"
 #include "buffer.h"
 #include "frame.h"
 #include "insdel.h"
@@ -45,7 +47,46 @@ Boston, MA 02111-1307, USA.  */
 #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;
@@ -58,7 +99,8 @@ Lisp_Object Qmswindows_resource;
 
 static void
 mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
-                                           enum image_instance_type type);
+                                            int slices,
+                                            enum image_instance_type type);
 static void
 mswindows_initialize_image_instance_mask (struct Lisp_Image_Instance* image, 
                                          struct frame* f);
@@ -87,9 +129,9 @@ static BITMAPINFO* convert_EImage_to_DIBitmap (Lisp_Object device,
   if (DEVICE_MSWINDOWS_BITSPIXEL (d) > 0)
     {
       int bpline = BPLINE(width * 3);
-      /* FIXME: we can do this because 24bpp implies no colour table, once
-       * we start paletizing this is no longer true. The X versions of
-       * this function quantises to 256 colours or bit masks down to a
+      /* 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
@@ -222,13 +264,13 @@ mswindows_locate_pixmap_file (Lisp_Object name)
        return Qnil;
     }
 
-  if (locate_file (Vmswindows_bitmap_file_path, name, "", &found, R_OK) < 0)
+  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, "", &found, R_OK);
+      locate_file (temp, name, Qnil, &found, R_OK);
       UNGCPRO;
     }
     
@@ -249,6 +291,7 @@ init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
                                   int dest_mask,
                                   void *bmp_data,
                                   int bmp_bits,
+                                  int slices,
                                   Lisp_Object instantiator, 
                                   int x_hot, int y_hot,
                                   int create_mask)
@@ -257,7 +300,7 @@ init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
   struct device *d = XDEVICE (device);
   struct frame *f;
   void* bmp_buf=0;
-  int type;
+  int type = 0;
   HBITMAP bitmap;
   HDC hdc;
 
@@ -290,12 +333,14 @@ init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
   /* copy in the actual bitmap */
   memcpy (bmp_buf, bmp_data, bmp_bits);
 
-  mswindows_initialize_dibitmap_image_instance (ii, type);
+  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;
@@ -315,8 +360,36 @@ init_image_instance_from_dibitmap (struct Lisp_Image_Instance *ii,
 }
 
 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,
@@ -327,6 +400,7 @@ mswindows_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii,
   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);
@@ -336,21 +410,29 @@ mswindows_init_image_instance_from_eimage (struct Lisp_Image_Instance *ii,
   bkcolor = COLOR_INSTANCE_MSWINDOWS_COLOR 
     (XCOLOR_INSTANCE (FACE_BACKGROUND (Vdefault_face, domain)));
 
-  /* build a bitmap from the eimage */
-  if (!(bmp_info=convert_EImage_to_DIBitmap (device, width, height, eimage,
-                                            &bmp_bits, &bmp_data)))
+  for (slice = 0; slice < slices; slice++)
     {
-      signal_simple_error ("EImage to DIBitmap conversion failed",
-                          instantiator);
-    }
-
-  /* Now create the pixmap and set up the image instance */
-  init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
-                                    bmp_data, bmp_bits, instantiator,
-                                    0, 0, 0);
+      /* 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);
+       }
 
-  xfree (bmp_info);
-  xfree (bmp_data);
+      /* 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, 
@@ -660,7 +742,8 @@ extract_xpm_color_names (Lisp_Object device,
       colortbl[j].color = 
        COLOR_INSTANCE_MSWINDOWS_COLOR (XCOLOR_INSTANCE (XCDR (cons)));
 
-      colortbl[j].name = (char *) XSTRING_DATA (XCAR (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);
@@ -699,7 +782,7 @@ static int xpm_to_eimage (Lisp_Object image, CONST Extbyte *buffer,
       break;
     case XpmFileInvalid:
       {
-       signal_simple_error ("invalid XPM data", image);
+       signal_simple_error ("Invalid XPM data", image);
       }
     case XpmNoMemory:
       {
@@ -859,7 +942,13 @@ mswindows_xpm_instantiate (Lisp_Object image_instance,
     }
   
   if (color_symbols)
-    xfree(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,
@@ -872,7 +961,7 @@ mswindows_xpm_instantiate (Lisp_Object image_instance,
 
   /* Now create the pixmap and set up the image instance */
   init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
-                                    bmp_data, bmp_bits, instantiator,
+                                    bmp_data, bmp_bits, 1, instantiator,
                                     x_hot, y_hot, transp);
 
   xfree (bmp_info);
@@ -935,7 +1024,7 @@ bmp_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
 
   /* Now create the pixmap and set up the image instance */
   init_image_instance_from_dibitmap (ii, bmp_info, dest_mask,
-                                    bmp_data, bmp_bits, instantiator,
+                                    bmp_data, bmp_bits, 1, instantiator,
                                     0, 0, 0);
 }
 
@@ -1093,7 +1182,9 @@ static int resource_name_to_resource (Lisp_Object name, int type)
     }
   
   do {
-    if (!strcasecmp ((char*)res->name, XSTRING_DATA (name)))
+    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;
@@ -1151,11 +1242,12 @@ mswindows_resource_instantiate (Lisp_Object image_instance, Lisp_Object instanti
   /* 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 (XSTRING_DATA (file), fname);
+      CYGWIN_WIN32_PATH (f, fname);
 #else
-      /* #### FIXME someone who knows ... */
-      fname = XSTRING_DATA (file);
+      fname = f;
 #endif
       
       if (NILP (resource_id))
@@ -1168,12 +1260,12 @@ mswindows_resource_instantiate (Lisp_Object image_instance, Lisp_Object instanti
                                                           type));
          
          if (!resid)
-           resid = XSTRING_DATA (resource_id);
+           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);
+    signal_simple_error ("Invalid resource identifier", resource_id);
   
   /* load the image */
   if (!(himage = LoadImage (hinst, resid, type, 0, 0,
@@ -1181,13 +1273,13 @@ mswindows_resource_instantiate (Lisp_Object image_instance, Lisp_Object instanti
                            LR_SHARED |      
                            (!NILP (file) ? LR_LOADFROMFILE : 0))))
     {
-      signal_simple_error ("cannot load image", instantiator);
+      signal_simple_error ("Cannot load image", instantiator);
     }
 
   if (hinst)
     FreeLibrary (hinst);
 
-  mswindows_initialize_dibitmap_image_instance (ii, iitype);
+  mswindows_initialize_dibitmap_image_instance (ii, 1, iitype);
 
   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) = file;
   IMAGE_INSTANCE_PIXMAP_WIDTH (ii) = 
@@ -1295,7 +1387,7 @@ in this Software without prior written authorization from the X Consortium.
 
 
 /*
- * Based on an optimized version provided by Jim Becker, Auguest 5, 1988.
+ * Based on an optimized version provided by Jim Becker, August 5, 1988.
  */
 #ifndef BitmapSuccess
 #define BitmapSuccess           0
@@ -1540,7 +1632,7 @@ xbm_create_bitmap_from_data (HDC hdc, char *data,
                             int mask, COLORREF fg, COLORREF bg)
 {
   int old_width = (width + 7)/8;
-  int new_width = 2*((width + 15)/16);
+  int new_width = BPLINE (2*((width + 15)/16));
   unsigned char *offset;
   void *bmp_buf = 0;
   unsigned char *new_data, *new_offset;
@@ -1552,7 +1644,7 @@ xbm_create_bitmap_from_data (HDC hdc, char *data,
   if (!bmp_info)
     return NULL;
   
-  new_data = (unsigned char *) xmalloc (height * new_width);
+  new_data = (unsigned char *) xmalloc_and_zero (height * new_width);
       
   if (!new_data)
     {
@@ -1565,8 +1657,6 @@ xbm_create_bitmap_from_data (HDC hdc, char *data,
       offset = data + i*old_width;
       new_offset = new_data + i*new_width;
 
-      new_offset[new_width - 1] = 0; /* there may be an extra byte
-                                        that needs to be padded */
       for (j=0; j<old_width; j++)
        {
          int byte = offset[j];
@@ -1586,7 +1676,7 @@ xbm_create_bitmap_from_data (HDC hdc, char *data,
     }
 
   bmp_info->bmiHeader.biWidth=width;
-  bmp_info->bmiHeader.biHeight=-height;
+  bmp_info->bmiHeader.biHeight=-(LONG)height;
   bmp_info->bmiHeader.biPlanes=1;
   bmp_info->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
   bmp_info->bmiHeader.biBitCount=1; 
@@ -1671,7 +1761,7 @@ init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii,
                              IMAGE_MONO_PIXMAP_MASK | IMAGE_COLOR_PIXMAP_MASK
                              | IMAGE_POINTER_MASK);
 
-  mswindows_initialize_dibitmap_image_instance (ii, type);
+  mswindows_initialize_dibitmap_image_instance (ii, 1, type);
   
   IMAGE_INSTANCE_PIXMAP_FILENAME (ii) =
     find_keyword_in_vector (instantiator, Q_file);
@@ -1732,10 +1822,10 @@ init_image_instance_from_xbm_inline (struct Lisp_Image_Instance *ii,
        if (NILP (background))
          background = pointer_bg;
 
-       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_X (ii), 
-                find_keyword_in_vector (instantiator, Q_hotspot_x));
-       XSETINT (IMAGE_INSTANCE_PIXMAP_HOTSPOT_Y (ii), 
-                find_keyword_in_vector (instantiator, Q_hotspot_y));
+       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))
@@ -1811,6 +1901,93 @@ mswindows_xbm_instantiate (Lisp_Object image_instance,
                     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 */
+
 \f
 /************************************************************************/
 /*                      image instance methods                          */
@@ -1839,32 +2016,235 @@ mswindows_print_image_instance (struct Lisp_Image_Instance *p,
        }
       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 (!p->data)
-    return;
-
   if (DEVICE_LIVE_P (XDEVICE (p->device)))
     {
-      if (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p))
-       DeleteObject (IMAGE_INSTANCE_MSWINDOWS_BITMAP (p));
-      IMAGE_INSTANCE_MSWINDOWS_BITMAP (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 (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;
+       }
     }
 
-  xfree (p->data);
-  p->data = 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
@@ -1880,6 +2260,7 @@ mswindows_image_instance_equal (struct Lisp_Image_Instance *p1,
          != IMAGE_INSTANCE_MSWINDOWS_BITMAP (p2))
        return 0;
       break;
+    
     default:
       break;
     }
@@ -1896,6 +2277,7 @@ mswindows_image_instance_hash (struct Lisp_Image_Instance *p, int depth)
     case IMAGE_COLOR_PIXMAP:
     case IMAGE_POINTER:
       return (unsigned long) IMAGE_INSTANCE_MSWINDOWS_BITMAP (p);
+    
     default:
       return 0;
     }
@@ -1909,7 +2291,8 @@ mswindows_image_instance_hash (struct Lisp_Image_Instance *p, int depth)
 
 static void
 mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
-                                           enum image_instance_type type)
+                                             int slices,
+                                             enum image_instance_type type)
 {
   ii->data = xnew_and_zero (struct mswindows_image_instance_data);
   IMAGE_INSTANCE_TYPE (ii) = type;
@@ -1919,8 +2302,569 @@ mswindows_initialize_dibitmap_image_instance (struct Lisp_Image_Instance *ii,
   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);
+}
+
+\f
+#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 */
+
 \f
 /************************************************************************/
 /*                            initialization                            */
@@ -1940,23 +2884,93 @@ console_type_create_glyphs_mswindows (void)
 
   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);
-#ifdef HAVE_XPM
-  CONSOLE_HAS_METHOD (mswindows, xpm_instantiate);
-#endif
-  CONSOLE_HAS_METHOD (mswindows, xbm_instantiate);
+  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);
@@ -1964,7 +2978,9 @@ image_instantiator_format_create_glyphs_mswindows (void)
 
   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");
 
@@ -1977,13 +2993,12 @@ image_instantiator_format_create_glyphs_mswindows (void)
                          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)
 {
-  Fprovide (Qbmp);
-  Fprovide (Qmswindows_resource);
   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.