* lisp.h (struct Lisp_Symbol): Replace field "name" with a lisp
[bpt/emacs.git] / src / w32fns.c
index 1ecc716..91d5b3a 100644 (file)
@@ -277,7 +277,6 @@ Lisp_Object Qfullboth;
 
 extern Lisp_Object Qtop;
 extern Lisp_Object Qdisplay;
-extern Lisp_Object Qtool_bar_lines;
 
 /* State variables for emulating a three button mouse. */
 #define LMOUSE 1
@@ -286,9 +285,9 @@ extern Lisp_Object Qtool_bar_lines;
 
 static int button_state = 0;
 static W32Msg saved_mouse_button_msg;
-static unsigned mouse_button_timer;    /* non-zero when timer is active */
+static unsigned mouse_button_timer = 0;        /* non-zero when timer is active */
 static W32Msg saved_mouse_move_msg;
-static unsigned mouse_move_timer;
+static unsigned mouse_move_timer = 0;
 
 /* Window that is tracking the mouse.  */
 static HWND track_mouse_window;
@@ -297,8 +296,14 @@ FARPROC track_mouse_event_fn;
 /* W95 mousewheel handler */
 unsigned int msh_mousewheel = 0;       
 
+/* Timers */
 #define MOUSE_BUTTON_ID        1
 #define MOUSE_MOVE_ID  2
+#define MENU_FREE_ID 3
+/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
+   is received.  */
+#define MENU_FREE_DELAY 1000
+static unsigned menu_free_timer = 0;
 
 /* The below are defined in frame.c.  */
 
@@ -571,7 +576,7 @@ x_create_bitmap_from_file (f, file)
     }
 
   /* Search bitmap-file-path for the file, if appropriate.  */
-  fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
+  fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
   if (fd < 0)
     return -1;
   emacs_close (fd);
@@ -2281,11 +2286,18 @@ x_set_cursor_color (f, arg, oldval)
        fore_pixel = FRAME_BACKGROUND_PIXEL (f);
     }
 
-  FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
+  f->output_data.w32->cursor_foreground_pixel = fore_pixel;
   f->output_data.w32->cursor_pixel = pixel;
 
   if (FRAME_W32_WINDOW (f) != 0)
     {
+      BLOCK_INPUT;
+      /* Update frame's cursor_gc.  */
+      f->output_data.w32->cursor_gc->foreground = fore_pixel;
+      f->output_data.w32->cursor_gc->background = pixel;
+
+      UNBLOCK_INPUT;
+
       if (FRAME_VISIBLE_P (f))
        {
          x_update_cursor (f, 0);
@@ -4769,6 +4781,18 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
          KillTimer (hwnd, mouse_move_timer);
          mouse_move_timer = 0;
        }
+      else if (wParam == menu_free_timer)
+       {
+         KillTimer (hwnd, menu_free_timer);
+         menu_free_timer = 0;
+         f = x_window_to_frame (dpyinfo, hwnd);
+         if (!f->output_data.w32->menu_command_in_progress)
+           {
+             /* Free memory used by owner-drawn and help-echo strings.  */
+             w32_free_menu_strings (hwnd);
+             f->output_data.w32->menubar_active = 0;
+           }
+       }
       return 0;
   
     case WM_NCACTIVATE:
@@ -4824,12 +4848,11 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
     case WM_EXITMENULOOP:
       f = x_window_to_frame (dpyinfo, hwnd);
 
-      /* Free memory used by owner-drawn and help-echo strings.  */
-      w32_free_menu_strings (hwnd);
-
-      /* Indicate that menubar can be modified again.  */
-      if (f)
-       f->output_data.w32->menubar_active = 0;
+      /* If a menu command is not already in progress, check again
+        after a short delay, since Windows often (always?) sends the
+        WM_EXITMENULOOP before the corresponding WM_COMMAND message.  */
+      if (f && !f->output_data.w32->menu_command_in_progress)
+       menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
       goto dflt;
 
     case WM_MENUSELECT:
@@ -4966,9 +4989,20 @@ w32_wnd_proc (hwnd, msg, wParam, lParam)
          w32_system_caret_hwnd = NULL;
          DestroyCaret ();
        }
+      goto command;
+    case WM_COMMAND:
+      f = x_window_to_frame (dpyinfo, hwnd);
+      if (f && HIWORD (wParam) == 0)
+       {
+         f->output_data.w32->menu_command_in_progress = 1;
+         if (menu_free_timer)
+           {
+             KillTimer (hwnd, menu_free_timer);
+             menu_free_timer = 0;        
+           }
+       }
     case WM_MOVE:
     case WM_SIZE:
-    case WM_COMMAND:
     command:
       wmsg.dwModifiers = w32_get_modifiers ();
       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
@@ -5643,8 +5677,9 @@ This function is an internal primitive--use `make-frame' instead.  */)
   
   x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
                       "menuBar", "MenuBar", RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
+  x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
                        "toolBar", "ToolBar", RES_TYPE_NUMBER);
+
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
   x_default_parameter (f, parms, Qtitle, Qnil,
@@ -6423,7 +6458,8 @@ w32_to_all_x_charsets (fncharset)
       /* Handle startup case of w32-charset-info-alist not
          being set up yet. */
       if (NILP(Vw32_charset_info_alist))
-        return "iso8859-1";
+        return Fcons (build_string ("iso8859-1"), Qnil);
+
       charset_type = Qw32_charset_ansi;
       break;
     case DEFAULT_CHARSET:
@@ -6611,8 +6647,8 @@ w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
   char height_dpi[8];
   char width_pixels[8];
   char *fontname_dash;
-  int display_resy = one_w32_display_info.resy;
-  int display_resx = one_w32_display_info.resx;
+  int display_resy = (int) one_w32_display_info.resy;
+  int display_resx = (int) one_w32_display_info.resx;
   int bufsz;
   struct coding_system coding;
 
@@ -6728,7 +6764,7 @@ x_to_w32_font (lpxstr, lplogfont)
       char name[50], weight[20], slant, pitch, pixels[10], height[10],
         width[10], resy[10], remainder[50];
       char * encoding;
-      int dpi = one_w32_display_info.resy;
+      int dpi = (int) one_w32_display_info.resy;
 
       fields = sscanf (lpxstr,
                       "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
@@ -7091,6 +7127,21 @@ enum_font_cb2 (lplf, lptm, FontType, lpef)
       lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
     return 1;
 
+  if (FontType == RASTER_FONTTYPE)
+    {
+      /* DBCS raster fonts have problems displaying, so skip them.  */
+      int charset = lplf->elfLogFont.lfCharSet;
+      if (charset == SHIFTJIS_CHARSET
+         || charset == HANGEUL_CHARSET
+         || charset == CHINESEBIG5_CHARSET
+         || charset == GB2312_CHARSET
+#ifdef JOHAB_CHARSET
+         || charset == JOHAB_CHARSET
+#endif
+         )
+       return 1;
+    }
+
   {
     char buf[100];
     Lisp_Object width = Qnil;
@@ -7740,8 +7791,10 @@ If omitted or nil, that stands for the selected frame's display.  */)
   else
     cap = GetDeviceCaps (hdc,NUMCOLORS);
 
+  /* We force 24+ bit depths to 24-bit, both to prevent an overflow
+     and because probably is more meaningful on Windows anyway */
   if (cap < 0)
-    cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
+    cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
   
   ReleaseDC (dpyinfo->root_window, hdc);
   
@@ -8111,7 +8164,6 @@ DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
 }
 
 \f
-\f
 /***********************************************************************
                            Image types
  ***********************************************************************/
@@ -8137,8 +8189,8 @@ Lisp_Object Qxbm;
 /* Keywords.  */
 
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
-extern Lisp_Object QCdata;
-Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
+extern Lisp_Object QCdata, QCtype;
+Lisp_Object QCascent, QCmargin, QCrelief;
 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
 
@@ -8468,6 +8520,62 @@ image_spec_value (spec, key, found)
 }
      
 
+DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
+       doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
+PIXELS non-nil means return the size in pixels, otherwise return the
+size in canonical character units.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, pixels, frame)
+     Lisp_Object spec, pixels, frame;
+{
+  Lisp_Object size;
+
+  size = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      int width = img->width + 2 * img->hmargin;
+      int height = img->height + 2 * img->vmargin;
+  
+      if (NILP (pixels))
+       size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
+                     make_float ((double) height / CANON_Y_UNIT (f)));
+      else
+       size = Fcons (make_number (width), make_number (height));
+    }
+  else
+    error ("Invalid image specification");
+
+  return size;
+}
+
+
+DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
+       doc: /* Return t if image SPEC has a mask bitmap.
+FRAME is the frame on which the image will be displayed.  FRAME nil
+or omitted means use the selected frame.  */)
+     (spec, frame)
+     Lisp_Object spec, frame;
+{
+  Lisp_Object mask;
+
+  mask = Qnil;
+  if (valid_image_p (spec))
+    {
+      struct frame *f = check_x_frame (frame);
+      int id = lookup_image (f, spec);
+      struct image *img = IMAGE_FROM_ID (f, id);
+      if (img->mask)
+       mask = Qt;
+    }
+  else
+    error ("Invalid image specification");
+
+  return mask;
+}
 
 \f
 /***********************************************************************
@@ -8570,7 +8678,7 @@ image_ascent (img, face)
        ascent = height / 2;
     }
   else
-    ascent = height * img->ascent / 100.0;
+    ascent = (int) (height * img->ascent / 100.0);
 
   return ascent;
 }
@@ -8579,20 +8687,21 @@ image_ascent (img, face)
 \f
 /* Image background colors.  */
 
-static unsigned long
+/* Find the "best" corner color of a bitmap.  XIMG is assumed to a device
+   context with the bitmap selected.  */
+static COLORREF
 four_corners_best (ximg, width, height)
-     XImage *ximg;
+     HDC ximg;
      unsigned long width, height;
 {
-#if 0 /* TODO: Image support.  */
-  unsigned long corners[4], best;
+  COLORREF corners[4], best;
   int i, best_count;
 
   /* Get the colors at the corners of ximg.  */
-  corners[0] = XGetPixel (ximg, 0, 0);
-  corners[1] = XGetPixel (ximg, width - 1, 0);
-  corners[2] = XGetPixel (ximg, width - 1, height - 1);
-  corners[3] = XGetPixel (ximg, 0, height - 1);
+  corners[0] = GetPixel (ximg, 0, 0);
+  corners[1] = GetPixel (ximg, width - 1, 0);
+  corners[2] = GetPixel (ximg, width - 1, height - 1);
+  corners[3] = GetPixel (ximg, 0, height - 1);
 
   /* Choose the most frequently found color as background.  */
   for (i = best_count = 0; i < 4; ++i)
@@ -8608,9 +8717,6 @@ four_corners_best (ximg, width, height)
     }
 
   return best;
-#else
-  return 0;
-#endif
 }
 
 /* Return the `background' field of IMG.  If IMG doesn't have one yet,
@@ -8708,29 +8814,29 @@ x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
      struct image *img;
      int pixmap_p, mask_p, colors_p;
 {
-#if 0 /* TODO: W32 image support  */
   if (pixmap_p && img->pixmap)
     {
-      XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = None;
+      DeleteObject (img->pixmap);
+      img->pixmap = NULL;
       img->background_valid = 0;
     }
 
   if (mask_p && img->mask)
     {
-      XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
-      img->mask = None;
+      DeleteObject (img->mask);
+      img->mask = NULL;
       img->background_transparent_valid = 0;
     }
       
   if (colors_p && img->ncolors)
     {
+#if 0  /* TODO: color table support.  */
       x_free_colors (f, img->colors, img->ncolors);
+#endif
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
-#endif
 }
 
 /* Free X resources of image IMG which is used on frame F.  */
@@ -8740,18 +8846,18 @@ x_clear_image (f, img)
      struct frame *f;
      struct image *img;
 {
-#if 0 /* TODO: W32 image support  */
-
   if (img->pixmap)
     {
       BLOCK_INPUT;
-      XFreePixmap (NULL, img->pixmap);
+      DeleteObject (img->pixmap);
       img->pixmap = 0;
       UNBLOCK_INPUT;
     }
 
   if (img->ncolors)
     {
+#if 0 /* TODO: color table support  */
+
       int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
       
       /* If display has an immutable color map, freeing colors is not
@@ -8767,12 +8873,12 @@ x_clear_image (f, img)
                       img->ncolors, 0);
          UNBLOCK_INPUT;
        }
+#endif
       
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
-#endif
 }
 
 
@@ -8788,7 +8894,6 @@ x_alloc_image_color (f, img, color_name, dflt)
      Lisp_Object color_name;
      unsigned long dflt;
 {
-#if 0 /* TODO: allocing colors.  */
   XColor color;
   unsigned long result;
 
@@ -8808,8 +8913,6 @@ x_alloc_image_color (f, img, color_name, dflt)
   else
     result = dflt;
   return result;
-#endif
-  return 0;
 }
 
 
@@ -8884,20 +8987,23 @@ clear_image_cache (f, force_p)
     {
       EMACS_TIME t;
       unsigned long old;
-      int i, any_freed_p = 0;
+      int i, nfreed;
 
       EMACS_GET_TIME (t);
       old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
       
-      for (i = 0; i < c->used; ++i)
+      /* Block input so that we won't be interrupted by a SIGIO
+        while being in an inconsistent state.  */
+      BLOCK_INPUT;
+      
+      for (i = nfreed = 0; i < c->used; ++i)
        {
          struct image *img = c->images[i];
          if (img != NULL
-             && (force_p
-                 || (img->timestamp > old)))
+             && (force_p || (img->timestamp < old)))
            {
              free_image (f, img);
-             any_freed_p = 1;
+             ++nfreed;
            }
        }
 
@@ -8905,11 +9011,22 @@ clear_image_cache (f, force_p)
         Emacs was iconified for a longer period of time.  In that
         case, current matrices may still contain references to
         images freed above.  So, clear these matrices.  */
-      if (any_freed_p)
+      if (nfreed)
        {
-         clear_current_matrices (f);
+         Lisp_Object tail, frame;
+         
+         FOR_EACH_FRAME (tail, frame)
+           {
+             struct frame *f = XFRAME (frame);
+             if (FRAME_W32_P (f)
+                 && FRAME_X_IMAGE_CACHE (f) == c)
+               clear_current_matrices (f);
+           }
+
          ++windows_or_buffers_changed;
        }
+
+      UNBLOCK_INPUT;
     }
 }
 
@@ -8985,7 +9102,7 @@ postprocess_image (f, img)
            }
          else if (NILP (mask) && found_p && img->mask)
            {
-             XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+             DeleteObject (img->mask);
              img->mask = NULL;
            }
        }
@@ -9200,8 +9317,6 @@ forall_images_in_image_cache (f, fn)
                            W32 support code
  ***********************************************************************/
 
-#if 0 /* TODO: W32 specific image code.  */
-
 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
                                             XImage **, Pixmap *));
 static void x_destroy_x_image P_ ((XImage *));
@@ -9211,8 +9326,10 @@ static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
    frame F.  Set *XIMG and *PIXMAP to the XImage and Pixmap created.
    Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
-   via xmalloc.  Print error messages via image_error if an error
-   occurs.  Value is non-zero if successful.  */
+   via xmalloc.  DEPTH of zero signifies a 24 bit image, otherwise
+   DEPTH should indicate the bit depth of the image.  Print error
+   messages via image_error if an error occurs.  Value is non-zero if
+   successful.  */
 
 static int
 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
@@ -9221,37 +9338,71 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
      XImage **ximg;
      Pixmap *pixmap;
 {
-#if 0 /* TODO: Image support for W32 */
-  Display *display = FRAME_W32_DISPLAY (f);
-  Screen *screen = FRAME_X_SCREEN (f);
-  Window window = FRAME_W32_WINDOW (f);
+  BITMAPINFOHEADER *header;
+  HDC hdc;
+  int scanline_width_bits;
+  int remainder;
+  int palette_colors = 0;
 
-  xassert (interrupt_input_blocked);
+  if (depth == 0)
+    depth = 24;
+
+  if (depth != 1 && depth != 4 && depth != 8
+      && depth != 16 && depth != 24 && depth != 32)
+    {
+      image_error ("Invalid image bit depth specified", Qnil, Qnil);
+      return 0;
+    }
+
+  scanline_width_bits = width * depth;
+  remainder = scanline_width_bits % 32;
+
+  if (remainder)
+    scanline_width_bits += 32 - remainder;
 
-  if (depth <= 0)
-    depth = one_w32_display_info.n_cbits;
-  *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
-                       depth, ZPixmap, 0, NULL, width, height,
-                       depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
+  /* Bitmaps with a depth less than 16 need a palette.  */
+  /* BITMAPINFO structure already contains the first RGBQUAD.  */
+  if (depth < 16)
+    palette_colors = 1 << depth - 1;
+
+  *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
   if (*ximg == NULL)
     {
-      image_error ("Unable to allocate X image", Qnil, Qnil);
+      image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
       return 0;
     }
 
-  /* Allocate image raster.  */
-  (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
+  header = &((*ximg)->info.bmiHeader);
+  bzero (&((*ximg)->info), sizeof (BITMAPINFO));
+  header->biSize = sizeof (*header);
+  header->biWidth = width;
+  header->biHeight = -height;  /* negative indicates a top-down bitmap.  */
+  header->biPlanes = 1;
+  header->biBitCount = depth;
+  header->biCompression = BI_RGB;
+  header->biClrUsed = palette_colors;
+
+  hdc = get_frame_dc (f);
 
-  /* Allocate a pixmap of the same size.  */
-  *pixmap = XCreatePixmap (display, window, width, height, depth);
-  if (*pixmap == 0)
+  /* Create a DIBSection and raster array for the bitmap,
+     and store its handle in *pixmap.  */
+  *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
+                             &((*ximg)->data), NULL, 0);
+
+  /* Realize display palette and garbage all frames. */
+  release_frame_dc (f, hdc);
+
+  if (*pixmap == NULL)
     {
+      DWORD err = GetLastError();
+      Lisp_Object errcode;
+      /* All system errors are < 10000, so the following is safe.  */
+      XSETINT (errcode, (int) err);
+      image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
       x_destroy_x_image (*ximg);
-      *ximg = NULL;
-      image_error ("Unable to create X pixmap", Qnil, Qnil);
       return 0;
     }
-#endif
+
   return 1;
 }
 
@@ -9265,9 +9416,9 @@ x_destroy_x_image (ximg)
   xassert (interrupt_input_blocked);
   if (ximg)
     {
-      xfree (ximg->data);
+      /* Data will be freed by DestroyObject.  */
       ximg->data = NULL;
-      XDestroyImage (ximg);
+      xfree (ximg);
     }
 }
 
@@ -9281,15 +9432,16 @@ x_put_x_image (f, ximg, pixmap, width, height)
      XImage *ximg;
      Pixmap pixmap;
 {
+
+#if TODO  /* W32 specific image code.  */
   GC gc;
-  
+
   xassert (interrupt_input_blocked);
   gc = XCreateGC (NULL, pixmap, 0, NULL);
   XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
   XFreeGC (NULL, gc);
-}
-
 #endif
+}
 
 \f
 /***********************************************************************
@@ -9317,7 +9469,7 @@ x_find_image_file (file)
   GCPRO2 (file_found, search_path);
 
   /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
-  fd = openp (search_path, file, Qnil, &file_found, 0);
+  fd = openp (search_path, file, Qnil, &file_found, Qnil);
   
   if (fd == -1)
     file_found = Qnil;
@@ -9370,12 +9522,14 @@ slurp_file (file, size)
                              XBM images
  ***********************************************************************/
 
+static int xbm_scan P_ ((char **, char *, char *, int *));
 static int xbm_load P_ ((struct frame *f, struct image *img));
-static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
-                                        Lisp_Object file));
+static int xbm_load_image P_ ((struct frame *f, struct image *img,
+                              char *, char *));
 static int xbm_image_p P_ ((Lisp_Object object));
-static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
-                                         unsigned char **));
+static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
+                                    unsigned char **));
+static int xbm_file_p P_ ((Lisp_Object));
 
 
 /* Indices of image specification fields in xbm_format, below.  */
@@ -9408,13 +9562,14 @@ static struct image_keyword xbm_format[XBM_LAST] =
   {":width",           IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":height",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":data",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":foreground",      IMAGE_STRING_OR_NIL_VALUE,                      0},
-  {":background",      IMAGE_STRING_OR_NIL_VALUE,                      0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":foreground",      IMAGE_STRING_OR_NIL_VALUE,              0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
 
 /* Structure describing the image type XBM.  */
@@ -9457,10 +9612,14 @@ enum xbm_token
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
+   4. A string containing an in-memory XBM file.  WIDTH and HEIGHT
+   may not be specified in this case because they are defined in the
+   XBM file.
+
    Both the file and data forms may contain the additional entries
    `:background COLOR' and `:foreground COLOR'.  If not present,
    foreground and background of the frame on which the image is
-   displayed, is used.  */
+   displayed is used.  */
 
 static int
 xbm_image_p (object)
@@ -9479,6 +9638,12 @@ xbm_image_p (object)
       if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
        return 0;
     }
+  else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
+    {
+      /* In-memory XBM file.  */
+      if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
+       return 0;
+    }
   else
     {
       Lisp_Object data;
@@ -9540,11 +9705,6 @@ xbm_image_p (object)
        return 0;
     }
 
-  /* Baseline must be a value between 0 and 100 (a percentage).  */
-  if (kw[XBM_ASCENT].count
-      && XFASTINT (kw[XBM_ASCENT].value) > 100)
-    return 0;
-  
   return 1;
 }
 
@@ -9566,7 +9726,7 @@ xbm_scan (s, end, sval, ival)
  loop:
 
   /* Skip white space.  */
-  while (*s < end &&(c = *(*s)++, isspace (c)))
+  while (*s < end && (c = *(*s)++, isspace (c)))
     ;
 
   if (*s >= end)
@@ -9643,6 +9803,46 @@ xbm_scan (s, end, sval, ival)
 }
 
 
+/* XBM bits seem to be backward within bytes compared with how
+   Windows does things.  */
+static unsigned char reflect_byte (unsigned char orig)
+{
+  int i;
+  unsigned char reflected = 0x00;
+  for (i = 0; i < 8; i++)
+    {
+      if (orig & (0x01 << i))
+       reflected |= 0x80 >> i;
+    }
+  return reflected;
+}
+
+
+/* Create a Windows bitmap from X bitmap data.  */
+static HBITMAP
+w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
+{
+  int i, j, w1, w2;
+  char *bits, *p;
+  HBITMAP bmp;
+
+  w1 = (width + 7) / 8;         /* nb of 8bits elt in X bitmap */
+  w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
+  bits = (char *) xmalloc (height * w2);
+  bzero (bits, height * w2);
+  for (i = 0; i < height; i++)
+    {
+      p = bits + i*w2;
+      for (j = 0; j < w1; j++)
+        *p++ = reflect_byte(*data++);
+    }
+  bmp = CreateBitmap (width, height, 1, 1, bits);
+  xfree (bits);
+
+  return bmp;
+}
+
+
 /* Replacement for XReadBitmapFileData which isn't available under old
    X versions.  CONTENTS is a pointer to a buffer to parse; END is the
    buffer's end.  Set *WIDTH and *HEIGHT to the width and height of
@@ -9666,7 +9866,7 @@ xbm_read_bitmap_data (contents, end, width, height, data)
   int LA1;
 
 #define match() \
-     LA1 = xbm_scan (contents, end, buffer, &value)
+     LA1 = xbm_scan (&s, end, buffer, &value)
 
 #define expect(TOKEN)          \
      if (LA1 != (TOKEN))       \
@@ -9745,7 +9945,6 @@ xbm_read_bitmap_data (contents, end, width, height, data)
 
   if (v10)
     {
-      
       for (i = 0; i < nbytes; i += 2)
        {
          int val = value;
@@ -9769,7 +9968,7 @@ xbm_read_bitmap_data (contents, end, width, height, data)
          expect (XBM_TK_NUMBER);
          
          *p++ = val;
-         
+
          if (LA1 == ',' || LA1 == '}')
            match ();
          else
@@ -9812,7 +10011,6 @@ xbm_load_image (f, img, contents, end)
   rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
   if (rc)
     {
-      int depth = one_w32_display_info.n_cbits;
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       Lisp_Object value;
@@ -9830,16 +10028,9 @@ xbm_load_image (f, img, contents, end)
          img->background = background;
          img->background_valid = 1;
        }
-      
-#if 0 /* TODO : Port image display to W32 */
       img->pixmap
-       = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
-                                      FRAME_W32_WINDOW (f),
-                                      data,
-                                      img->width, img->height,
-                                      foreground, background,
-                                      depth);
-#endif
+       = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
+
       xfree (data);
 
       if (img->pixmap == 0)
@@ -9929,7 +10120,7 @@ xbm_load (f, img)
       data = image_spec_value (img->spec, QCdata, NULL);
       in_memory_file_p = xbm_file_p (data);
 
-      /* Parse the list specification.  */
+      /* Parse the image specification.  */
       bcopy (xbm_format, fmt, sizeof fmt);
       parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
       xassert (parsed_p);
@@ -9941,6 +10132,7 @@ xbm_load (f, img)
          img->height = XFASTINT (fmt[XBM_HEIGHT].value);
          xassert (img->width > 0 && img->height > 0);
        }
+
       /* Get foreground and background colors, maybe allocate colors.  */
       if (fmt[XBM_FOREGROUND].count
          && STRINGP (fmt[XBM_FOREGROUND].value))
@@ -9977,17 +10169,13 @@ xbm_load (f, img)
            bits = XSTRING (data)->data;
          else
            bits = XBOOL_VECTOR (data)->data;
-#ifdef TODO /* image support.  */
+
          /* Create the pixmap.  */
          depth = one_w32_display_info.n_cbits;
          img->pixmap
-           = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
-                                          FRAME_X_WINDOW (f),
-                                          bits,
-                                          img->width, img->height,
-                                          foreground, background,
-                                          depth);
-#endif
+           = w32_create_pixmap_from_bitmap_data (img->width, img->height,
+                                                 bits);
+
          if (img->pixmap)
            success_p = 1;
          else
@@ -10450,10 +10638,10 @@ colors_in_color_table (n)
 /***********************************************************************
                              Algorithms
  ***********************************************************************/
-#if 0 /* TODO: image support. */
 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
+static void XPutPixel (XImage *, int, int, COLORREF);
 
 /* Non-zero means draw a cross on images having `:conversion
    disabled'.  */
@@ -10500,7 +10688,7 @@ x_to_xcolors (f, img, rgb_p)
   XImage *ximg;
 
   colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
-
+#if 0 /* TODO: implement image colors.  */
   /* Get the X image IMG->pixmap.  */
   ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
                    0, 0, img->width, img->height, ~0, ZPixmap);
@@ -10520,9 +10708,37 @@ x_to_xcolors (f, img, rgb_p)
     }
 
   XDestroyImage (ximg);
+#endif
   return colors;
 }
 
+/* Put a pixel of COLOR at position X, Y in XIMG.  XIMG must have been
+   created with CreateDIBSection, with the pointer to the bit values
+   stored in ximg->data.  */
+
+static void XPutPixel (ximg, x, y, color)
+     XImage * ximg;
+     int x, y;
+     COLORREF color;
+{
+  int width = ximg->info.bmiHeader.biWidth;
+  int height = ximg->info.bmiHeader.biHeight;
+  int rowbytes = width * 3;
+  unsigned char * pixel;
+
+  /* Don't support putting pixels in images with palettes.  */
+  xassert (ximg->info.bmiHeader.biBitCount == 24);
+
+  /* Ensure scanlines are aligned on 4 byte boundaries.  */
+  if (rowbytes % 4)
+    rowbytes += 4 - (rowbytes % 4);
+
+  pixel = ximg->data + y * rowbytes + x * 3;
+  *pixel = 255 - GetRValue (color);
+  *(pixel + 1) = 255 - GetGValue (color);
+  *(pixel + 2) = 255 - GetBValue (color);
+}
+
 
 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
    RGB members are set.  F is the frame on which this all happens.
@@ -10538,9 +10754,9 @@ x_from_xcolors (f, img, colors)
   XImage *oimg;
   Pixmap pixmap;
   XColor *p;
-  
+#if 0   /* TODO: color tables.  */
   init_color_table ();
-  
+#endif
   x_create_x_image_and_pixmap (f, img->width, img->height, 0,
                               &oimg, &pixmap);
   p = colors;
@@ -10548,7 +10764,11 @@ x_from_xcolors (f, img, colors)
     for (x = 0; x < img->width; ++x, ++p)
       {
        unsigned long pixel;
+#if 0  /* TODO: color tables.  */
        pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
+#else
+       pixel = PALETTERGB (p->red, p->green, p->blue);
+#endif
        XPutPixel (oimg, x, y, pixel);
       }
 
@@ -10558,8 +10778,10 @@ x_from_xcolors (f, img, colors)
   x_put_x_image (f, oimg, pixmap, img->width, img->height);
   x_destroy_x_image (oimg);
   img->pixmap = pixmap;
+#if 0  /* TODO: color tables.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
+#endif
 }
 
 
@@ -10710,9 +10932,9 @@ x_disable_image (f, img)
      struct frame *f;
      struct image *img;
 {
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 
-  if (dpyinfo->n_planes >= 2)
+  if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
     {
       /* Color (or grayscale).  Convert to gray, and equalize.  Just
         drawing such images with a stipple can look very odd, so
@@ -10736,8 +10958,9 @@ x_disable_image (f, img)
 
   /* Draw a cross over the disabled image, if we must or if we
      should.  */
-  if (dpyinfo->n_planes < 2 || cross_disabled_images)
+  if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
     {
+#if 0 /* TODO: full image support  */
       Display *dpy = FRAME_X_DISPLAY (f);
       GC gc;
 
@@ -10759,6 +10982,7 @@ x_disable_image (f, img)
                     img->width - 1, 0);
          XFreeGC (dpy, gc);
        }
+#endif
     }
 }
 
@@ -10776,6 +11000,7 @@ x_build_heuristic_mask (f, img, how)
      struct image *img;
      Lisp_Object how;
 {
+#if 0 /* TODO: full image support.  */
   Display *dpy = FRAME_W32_DISPLAY (f);
   XImage *ximg, *mask_img;
   int x, y, rc, use_img_background;
@@ -10839,14 +11064,15 @@ x_build_heuristic_mask (f, img, how)
   XDestroyImage (ximg);
 
   return 1;
+#else
+  return 0;
+#endif
 }
-#endif /* TODO */
 
 \f
 /***********************************************************************
                       PBM (mono, gray, color)
  ***********************************************************************/
-#ifdef HAVE_PBM
 
 static int pbm_image_p P_ ((Lisp_Object object));
 static int pbm_load P_ ((struct frame *f, struct image *img));
@@ -11106,12 +11332,13 @@ pbm_load (f, img)
       || (type != PBM_MONO && max_color_idx < 0))
     goto error;
 
-  if (!x_create_x_image_and_pixmap (f, width, height, 0,
-                                   &ximg, &img->pixmap))
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     goto error;
 
+#if 0  /* TODO: color tables.  */
   /* Initialize the color hash table.  */
   init_color_table ();
+#endif
 
   if (type == PBM_MONO)
     {
@@ -11176,28 +11403,32 @@ pbm_load (f, img)
            
            if (r < 0 || g < 0 || b < 0)
              {
-               xfree (ximg->data);
-               ximg->data = NULL;
-               XDestroyImage (ximg);
+               x_destroy_x_image (ximg);
                image_error ("Invalid pixel value in image `%s'",
                             img->spec, Qnil);
                 goto error;
              }
            
            /* RGB values are now in the range 0..max_color_idx.
-              Scale this to the range 0..0xffff supported by X.  */
-           r = (double) r * 65535 / max_color_idx;
-           g = (double) g * 65535 / max_color_idx;
-           b = (double) b * 65535 / max_color_idx;
-           XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
+              Scale this to the range 0..0xff supported by W32.  */
+           r = (int) ((double) r * 255 / max_color_idx);
+           g = (int) ((double) g * 255 / max_color_idx);
+           b = (int) ((double) b * 255 / max_color_idx);
+           XPutPixel (ximg, x, y,
+#if 0  /* TODO: color tables.  */
+                      lookup_rgb_color (f, r, g, b));
+#else
+           PALETTERGB (r, g, b));
+#endif
          }
     }
-  
+
+#if 0  /* TODO: color tables.  */
   /* Store in IMG->colors the colors allocated for the image, and
      free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
   free_color_table ();
-  
+#endif
   /* Maybe fill in the background field while we have ximg handy.  */
   if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
     IMAGE_BACKGROUND (img, f, ximg);
@@ -11213,7 +11444,6 @@ pbm_load (f, img)
   xfree (contents);
   return 1;
 }
-#endif /* HAVE_PBM */
 
 \f
 /***********************************************************************
@@ -14086,7 +14316,7 @@ specified.  Ensure that file exists if MUSTMATCH is non-nil.  */)
       if (GetOpenFileName (&file_details))
         {
           dostounix_filename (filename);
-          file = build_string (filename);
+          file = DECODE_FILE(build_string (filename));
         }
       else
         file = Qnil;
@@ -14519,14 +14749,16 @@ If the underlying system call fails, value is nil.  */)
 
     if (pfn_GetDiskFreeSpaceEx)
       {
+       /* Unsigned large integers cannot be cast to double, so
+          use signed ones instead.  */
        LARGE_INTEGER availbytes;
        LARGE_INTEGER freebytes;
        LARGE_INTEGER totalbytes;
 
        if (pfn_GetDiskFreeSpaceEx(rootname,
-                                  &availbytes,
-                                  &totalbytes,
-                                  &freebytes))
+                                  (ULARGE_INTEGER *)&availbytes,
+                                  (ULARGE_INTEGER *)&totalbytes,
+                                  (ULARGE_INTEGER *)&freebytes))
          value = list3 (make_float ((double) totalbytes.QuadPart),
                         make_float ((double) freebytes.QuadPart),
                         make_float ((double) availbytes.QuadPart));
@@ -15075,12 +15307,9 @@ versions of Windows) characters.  */);
   set_frame_fontset_func = x_set_font;
   check_window_system_func = check_w32;
 
-#if 0 /* TODO Image support for W32 */
   /* Images.  */
   Qxbm = intern ("xbm");
   staticpro (&Qxbm);
-  QCtype = intern (":type");
-  staticpro (&QCtype);
   QCconversion = intern (":conversion");
   staticpro (&QCconversion);
   QCheuristic_mask = intern (":heuristic-mask");
@@ -15095,6 +15324,7 @@ versions of Windows) characters.  */);
   staticpro (&QCrelief);
   Qpostscript = intern ("postscript");
   staticpro (&Qpostscript);
+#if 0 /* TODO: These need entries at top of file.  */
   QCloader = intern (":loader");
   staticpro (&QCloader);
   QCbounding_box = intern (":bounding-box");
@@ -15103,6 +15333,7 @@ versions of Windows) characters.  */);
   staticpro (&QCpt_width);
   QCpt_height = intern (":pt-height");
   staticpro (&QCpt_height);
+#endif
   QCindex = intern (":index");
   staticpro (&QCindex);
   Qpbm = intern ("pbm");
@@ -15134,12 +15365,13 @@ versions of Windows) characters.  */);
 #endif
 
   defsubr (&Sclear_image_cache);
+  defsubr (&Simage_size);
+  defsubr (&Simage_mask_p);
 
 #if GLYPH_DEBUG
   defsubr (&Simagep);
   defsubr (&Slookup_image);
 #endif
-#endif /* TODO */
 
   hourglass_atimer = NULL;
   hourglass_shown_p = 0;
@@ -15163,10 +15395,11 @@ init_xfns ()
   image_types = NULL;
   Vimage_types = Qnil;
 
-#if 0 /* TODO : Image support for W32 */
+  define_image_type (&pbm_type);
   define_image_type (&xbm_type);
+#if 0 /* TODO : Image support for W32 */
   define_image_type (&gs_type);
-  define_image_type (&pbm_type);
+#endif
   
 #if HAVE_XPM
   define_image_type (&xpm_type);
@@ -15179,7 +15412,7 @@ init_xfns ()
 #if HAVE_TIFF
   define_image_type (&tiff_type);
 #endif
-  
+
 #if HAVE_GIF
   define_image_type (&gif_type);
 #endif
@@ -15187,7 +15420,6 @@ init_xfns ()
 #if HAVE_PNG
   define_image_type (&png_type);
 #endif
-#endif /* TODO */
 }
 
 #undef abort