]> code.delx.au - gnu-emacs/blobdiff - src/xfns.c
Use #if GLYPH_DEBUG instead of #ifdef GLYPH_DEBUG.
[gnu-emacs] / src / xfns.c
index 399da6d6fd9b277aab1821341609e48a92c45c73..6e8931b42d703fe9db7e154f881b09ca7277c4ad 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for the X window system.
 /* Functions for the X window system.
-   Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999
+   Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000
      Free Software Foundation.
 
 This file is part of GNU Emacs.
      Free Software Foundation.
 
 This file is part of GNU Emacs.
@@ -19,14 +19,6 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-/* Image support (XBM, XPM, PBM, JPEG, TIFF, GIF, PNG, GS). tooltips,
-   tool-bars, busy-cursor, file selection dialog added by Gerd
-   Moellmann <gerd@gnu.org>.  */
-
-/* Completely rewritten by Richard Stallman.  */
-
-/* Rewritten for X11 by Joseph Arceneaux */
-
 #include <config.h>
 #include <signal.h>
 #include <stdio.h>
 #include <config.h>
 #include <signal.h>
 #include <stdio.h>
@@ -41,29 +33,23 @@ Boston, MA 02111-1307, USA.  */
 #include "frame.h"
 #include "window.h"
 #include "buffer.h"
 #include "frame.h"
 #include "window.h"
 #include "buffer.h"
+#include "intervals.h"
 #include "dispextern.h"
 #include "keyboard.h"
 #include "blockinput.h"
 #include <epaths.h>
 #include "charset.h"
 #include "dispextern.h"
 #include "keyboard.h"
 #include "blockinput.h"
 #include <epaths.h>
 #include "charset.h"
+#include "coding.h"
 #include "fontset.h"
 #include "systime.h"
 #include "termhooks.h"
 #include "fontset.h"
 #include "systime.h"
 #include "termhooks.h"
+#include "atimer.h"
 
 #ifdef HAVE_X_WINDOWS
 
 
 #ifdef HAVE_X_WINDOWS
 
-#ifndef STDC_HEADERS
-extern void abort ();
-#endif
 #include <ctype.h>
 #include <ctype.h>
-
-/* On some systems, the character-composition stuff is broken in X11R5.  */
-
-#if defined (HAVE_X11R5) && ! defined (HAVE_X11R6)
-#ifdef X11R5_INHIBIT_I18N
-#define X_I18N_INHIBITED
-#endif
-#endif
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #ifndef VMS
 #if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work.  */
 
 #ifndef VMS
 #if 1 /* Used to be #ifdef EMACS_BITMAP_FILES, but this should always work.  */
@@ -138,7 +124,7 @@ extern double atof ();
 
 int gray_bitmap_width = gray_width;
 int gray_bitmap_height = gray_height;
 
 int gray_bitmap_width = gray_width;
 int gray_bitmap_height = gray_height;
-unsigned char *gray_bitmap_bits = gray_bits;
+char *gray_bitmap_bits = gray_bits;
 
 /* The name we're using in resource queries.  Most often "emacs".  */
 
 
 /* The name we're using in resource queries.  Most often "emacs".  */
 
@@ -163,6 +149,11 @@ Lisp_Object Vx_busy_pointer_shape;
 
 Lisp_Object Vx_sensitive_text_pointer_shape;
 
 
 Lisp_Object Vx_sensitive_text_pointer_shape;
 
+/* If non-nil, the pointer shape to indicate that windows can be
+   dragged horizontally.  */
+
+Lisp_Object Vx_window_horizontal_drag_shape;
+
 /* Color of chars displayed in cursor box.  */
 
 Lisp_Object Vx_cursor_fore_pixel;
 /* Color of chars displayed in cursor box.  */
 
 Lisp_Object Vx_cursor_fore_pixel;
@@ -249,9 +240,10 @@ Lisp_Object Qx_frame_parameter;
 Lisp_Object Qx_resource_name;
 Lisp_Object Quser_position;
 Lisp_Object Quser_size;
 Lisp_Object Qx_resource_name;
 Lisp_Object Quser_position;
 Lisp_Object Quser_size;
-Lisp_Object Qdisplay;
+extern Lisp_Object Qdisplay;
 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
-Lisp_Object Qscreen_gamma;
+Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
+Lisp_Object Qcompound_text;
 
 /* The below are defined in frame.c.  */
 
 
 /* The below are defined in frame.c.  */
 
@@ -263,6 +255,11 @@ extern Lisp_Object Vwindow_system_version;
 
 Lisp_Object Qface_set_after_frame_default;
 
 
 Lisp_Object Qface_set_after_frame_default;
 
+#if GLYPH_DEBUG
+int image_cache_refcount, dpyinfo_refcount;
+#endif
+
+
 \f
 /* Error if we are not connected to X.  */
 
 \f
 /* Error if we are not connected to X.  */
 
@@ -308,19 +305,21 @@ static struct x_display_info *
 check_x_display_info (frame)
      Lisp_Object frame;
 {
 check_x_display_info (frame)
      Lisp_Object frame;
 {
+  struct x_display_info *dpyinfo = NULL;
+  
   if (NILP (frame))
     {
       struct frame *sf = XFRAME (selected_frame);
       
       if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
   if (NILP (frame))
     {
       struct frame *sf = XFRAME (selected_frame);
       
       if (FRAME_X_P (sf) && FRAME_LIVE_P (sf))
-       return FRAME_X_DISPLAY_INFO (sf);
+       dpyinfo = FRAME_X_DISPLAY_INFO (sf);
       else if (x_display_list != 0)
       else if (x_display_list != 0)
-       return x_display_list;
+       dpyinfo = x_display_list;
       else
        error ("X windows are not in use or not initialized");
     }
   else if (STRINGP (frame))
       else
        error ("X windows are not in use or not initialized");
     }
   else if (STRINGP (frame))
-    return x_display_info_for_name (frame);
+    dpyinfo = x_display_info_for_name (frame);
   else
     {
       FRAME_PTR f;
   else
     {
       FRAME_PTR f;
@@ -329,8 +328,10 @@ check_x_display_info (frame)
       f = XFRAME (frame);
       if (! FRAME_X_P (f))
        error ("Non-X frame used");
       f = XFRAME (frame);
       if (! FRAME_X_P (f))
        error ("Non-X frame used");
-      return FRAME_X_DISPLAY_INFO (f);
+      dpyinfo = FRAME_X_DISPLAY_INFO (f);
     }
     }
+
+  return dpyinfo;
 }
 
 \f
 }
 
 \f
@@ -353,8 +354,10 @@ x_window_to_frame (dpyinfo, wdesc)
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
+      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
        continue;
+      if (f->output_data.x->busy_window == wdesc)
+       return f;
 #ifdef USE_X_TOOLKIT
       if ((f->output_data.x->edit_widget 
           && XtWindow (f->output_data.x->edit_widget) == wdesc)
 #ifdef USE_X_TOOLKIT
       if ((f->output_data.x->edit_widget 
           && XtWindow (f->output_data.x->edit_widget) == wdesc)
@@ -382,34 +385,40 @@ x_any_window_to_frame (dpyinfo, wdesc)
      int wdesc;
 {
   Lisp_Object tail, frame;
      int wdesc;
 {
   Lisp_Object tail, frame;
-  struct frame *f;
+  struct frame *f, *found;
   struct x_output *x;
 
   struct x_output *x;
 
-  for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+  found = NULL;
+  for (tail = Vframe_list; GC_CONSP (tail) && !found; tail = XCDR (tail))
     {
       frame = XCAR (tail);
       if (!GC_FRAMEP (frame))
         continue;
     {
       frame = XCAR (tail);
       if (!GC_FRAMEP (frame))
         continue;
+      
       f = XFRAME (frame);
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
-       continue;
-      x = f->output_data.x;
-      /* This frame matches if the window is any of its widgets.  */
-      if (x->widget)
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo)
        {
        {
-         if (wdesc == XtWindow (x->widget) 
-             || wdesc == XtWindow (x->column_widget) 
-             || wdesc == XtWindow (x->edit_widget))
-           return f;
-         /* Match if the window is this frame's menubar.  */
-         if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
-           return f;
+         /* This frame matches if the window is any of its widgets.  */
+         x = f->output_data.x;
+         if (x->busy_window == wdesc)
+           found = f;
+         else if (x->widget)
+           {
+             if (wdesc == XtWindow (x->widget) 
+                 || wdesc == XtWindow (x->column_widget) 
+                 || wdesc == XtWindow (x->edit_widget))
+               found = f;
+             /* Match if the window is this frame's menubar.  */
+             else if (lw_window_is_in_menubar (wdesc, x->menubar_widget))
+               found = f;
+           }
+         else if (FRAME_X_WINDOW (f) == wdesc)
+           /* A tooltip frame.  */
+           found = f;
        }
        }
-      else if (FRAME_X_WINDOW (f) == wdesc)
-       /* A tooltip frame.  */
-       return f;
     }
     }
-  return 0;
+  
+  return found;
 }
 
 /* Likewise, but exclude the menu bar widget.  */
 }
 
 /* Likewise, but exclude the menu bar widget.  */
@@ -429,11 +438,13 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc)
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
+      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
       x = f->output_data.x;
       /* This frame matches if the window is any of its widgets.  */
        continue;
       x = f->output_data.x;
       /* This frame matches if the window is any of its widgets.  */
-      if (x->widget)
+      if (x->busy_window == wdesc)
+       return f;
+      else if (x->widget)
        {
          if (wdesc == XtWindow (x->widget) 
              || wdesc == XtWindow (x->column_widget) 
        {
          if (wdesc == XtWindow (x->widget) 
              || wdesc == XtWindow (x->column_widget) 
@@ -464,7 +475,7 @@ x_menubar_window_to_frame (dpyinfo, wdesc)
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
+      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
       x = f->output_data.x;
       /* Match if the window is this frame's menubar.  */
        continue;
       x = f->output_data.x;
       /* Match if the window is this frame's menubar.  */
@@ -493,7 +504,7 @@ x_top_window_to_frame (dpyinfo, wdesc)
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
       if (!GC_FRAMEP (frame))
         continue;
       f = XFRAME (frame);
-      if (f->output_data.nothing == 1 || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
+      if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
       x = f->output_data.x;
 
        continue;
       x = f->output_data.x;
 
@@ -662,9 +673,6 @@ x_create_bitmap_from_file (f, file)
   fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
   if (fd < 0)
     return -1;
   fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
   if (fd < 0)
     return -1;
-  /* XReadBitmapFile won't handle magic file names.  */
-  if (fd == 0)
-    return -1;
   emacs_close (fd);
 
   filename = (char *) XSTRING (found)->data;
   emacs_close (fd);
 
   filename = (char *) XSTRING (found)->data;
@@ -743,7 +751,13 @@ struct x_frame_parm_table
   void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
 };
 
   void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
 };
 
+static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
+static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
+static void x_change_window_heights P_ ((Lisp_Object, int));
+static void x_disable_image P_ ((struct frame *, struct image *));
+static void x_create_im P_ ((struct frame *));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -776,33 +790,43 @@ static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
                                                             char *, char *,
                                                             int));
 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
                                                             char *, char *,
                                                             int));
 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
+                                 Lisp_Object));
+static void init_color_table P_ ((void));
+static void free_color_table P_ ((void));
+static unsigned long *colors_in_color_table P_ ((int *n));
+static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
+static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
+
+
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
 
 static struct x_frame_parm_table x_frame_parms[] =
 {
-  "auto-raise", x_set_autoraise,
-  "auto-lower", x_set_autolower,
-  "background-color", x_set_background_color,
-  "border-color", x_set_border_color,
-  "border-width", x_set_border_width,
-  "cursor-color", x_set_cursor_color,
-  "cursor-type", x_set_cursor_type,
-  "font", x_set_font,
-  "foreground-color", x_set_foreground_color,
-  "icon-name", x_set_icon_name,
-  "icon-type", x_set_icon_type,
-  "internal-border-width", x_set_internal_border_width,
-  "menu-bar-lines", x_set_menu_bar_lines,
-  "mouse-color", x_set_mouse_color,
-  "name", x_explicitly_set_name,
-  "scroll-bar-width", x_set_scroll_bar_width,
-  "title", x_set_title,
-  "unsplittable", x_set_unsplittable,
-  "vertical-scroll-bars", x_set_vertical_scroll_bars,
-  "visibility", x_set_visibility,
-  "tool-bar-lines", x_set_tool_bar_lines,
-  "scroll-bar-foreground", x_set_scroll_bar_foreground,
-  "scroll-bar-background", x_set_scroll_bar_background,
-  "screen-gamma", x_set_screen_gamma
+  "auto-raise",                        x_set_autoraise,
+  "auto-lower",                        x_set_autolower,
+  "background-color",          x_set_background_color,
+  "border-color",              x_set_border_color,
+  "border-width",              x_set_border_width,
+  "cursor-color",              x_set_cursor_color,
+  "cursor-type",               x_set_cursor_type,
+  "font",                      x_set_font,
+  "foreground-color",          x_set_foreground_color,
+  "icon-name",                 x_set_icon_name,
+  "icon-type",                 x_set_icon_type,
+  "internal-border-width",     x_set_internal_border_width,
+  "menu-bar-lines",            x_set_menu_bar_lines,
+  "mouse-color",               x_set_mouse_color,
+  "name",                      x_explicitly_set_name,
+  "scroll-bar-width",          x_set_scroll_bar_width,
+  "title",                     x_set_title,
+  "unsplittable",              x_set_unsplittable,
+  "vertical-scroll-bars",      x_set_vertical_scroll_bars,
+  "visibility",                        x_set_visibility,
+  "tool-bar-lines",            x_set_tool_bar_lines,
+  "scroll-bar-foreground",     x_set_scroll_bar_foreground,
+  "scroll-bar-background",     x_set_scroll_bar_background,
+  "screen-gamma",              x_set_screen_gamma,
+  "line-spacing",              x_set_line_spacing
 };
 
 /* Attach the `x-frame-parameter' properties to
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -819,8 +843,10 @@ init_x_parm_symbols ()
 }
 \f
 /* Change the parameters of frame F as specified by ALIST.
 }
 \f
 /* Change the parameters of frame F as specified by ALIST.
-   If a parameter is not specially recognized, do nothing;
-   otherwise call the `x_set_...' function for that parameter.  */
+   If a parameter is not specially recognized, do nothing special;
+   otherwise call the `x_set_...' function for that parameter.
+   Except for certain geometry properties, always call store_frame_param
+   to store the new value in the parameter alist.  */
 
 void
 x_set_frame_parameters (f, alist)
 
 void
 x_set_frame_parameters (f, alist)
@@ -1102,7 +1128,7 @@ x_real_positions (f, xptr, yptr)
 #endif
   Window tmp_root_window;
   Window *tmp_children;
 #endif
   Window tmp_root_window;
   Window *tmp_children;
-  int tmp_nchildren;
+  unsigned int tmp_nchildren;
 
   while (1)
     {
 
   while (1)
     {
@@ -1228,131 +1254,91 @@ gamma_correct (f, color)
 }
 
 
 }
 
 
-/* Decide if color named COLOR is valid for the display associated with
-   the selected frame; if so, return the rgb values in COLOR_DEF.
-   If ALLOC is nonzero, allocate a new colormap cell.  */
+/* Decide if color named COLOR_NAME is valid for use on frame F.  If
+   so, return the RGB values in COLOR.  If ALLOC_P is non-zero,
+   allocate the color.  Value is zero if COLOR_NAME is invalid, or
+   no color could be allocated.  */
 
 int
 
 int
-defined_color (f, color, color_def, alloc)
-     FRAME_PTR f;
-     char *color;
-     XColor *color_def;
-     int alloc;
+x_defined_color (f, color_name, color, alloc_p)
+     struct frame *f;
+     char *color_name;
+     XColor *color;
+     int alloc_p;
 {
 {
-  register int status;
-  Colormap screen_colormap;
-  Display *display = FRAME_X_DISPLAY (f);
+  int success_p;
+  Display *dpy = FRAME_X_DISPLAY (f);
+  Colormap cmap = FRAME_X_COLORMAP (f);
 
   BLOCK_INPUT;
 
   BLOCK_INPUT;
-  screen_colormap = DefaultColormap (display, XDefaultScreen (display));
-
-  status = XParseColor (display, screen_colormap, color, color_def);
-  if (status && alloc) 
-    {
-      /* Apply gamma correction.  */
-      gamma_correct (f, color_def);
-      
-      status = XAllocColor (display, screen_colormap, color_def);
-      if (!status)
-       {
-         /* If we got to this point, the colormap is full, so we're 
-            going to try and get the next closest color.
-            The algorithm used is a least-squares matching, which is
-            what X uses for closest color matching with StaticColor visuals.  */
-
-         XColor *cells;
-         int no_cells;
-         int nearest;
-         long nearest_delta, trial_delta;
-         int x;
-
-         no_cells = XDisplayCells (display, XDefaultScreen (display));
-         cells = (XColor *) alloca (sizeof (XColor) * no_cells);
-
-         for (x = 0; x < no_cells; x++) 
-           cells[x].pixel = x;
-
-         XQueryColors (display, screen_colormap, cells, no_cells);
-         nearest = 0;
-         /* I'm assuming CSE so I'm not going to condense this. */
-         nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8))
-                           * ((color_def->red >> 8) - (cells[0].red >> 8)))
-                          +
-                          (((color_def->green >> 8) - (cells[0].green >> 8))
-                           * ((color_def->green >> 8) - (cells[0].green >> 8)))
-                          +
-                          (((color_def->blue >> 8) - (cells[0].blue >> 8))
-                           * ((color_def->blue >> 8) - (cells[0].blue >> 8))));
-         for (x = 1; x < no_cells; x++) 
-           {
-             trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8))
-                             * ((color_def->red >> 8) - (cells[x].red >> 8)))
-                            +
-                            (((color_def->green >> 8) - (cells[x].green >> 8))
-                             * ((color_def->green >> 8) - (cells[x].green >> 8)))
-                            +
-                            (((color_def->blue >> 8) - (cells[x].blue >> 8))
-                             * ((color_def->blue >> 8) - (cells[x].blue >> 8))));
-             if (trial_delta < nearest_delta) 
-               {
-                 XColor temp;
-                 temp.red = cells[x].red;
-                 temp.green = cells[x].green;
-                 temp.blue = cells[x].blue;
-                 status = XAllocColor (display, screen_colormap, &temp);
-                 if (status)
-                   {
-                     nearest = x;
-                     nearest_delta = trial_delta;
-                   }
-               }
-           }
-         color_def->red = cells[nearest].red;
-         color_def->green = cells[nearest].green;
-         color_def->blue = cells[nearest].blue;
-         status = XAllocColor (display, screen_colormap, color_def);
-       }
-    }
+  success_p = XParseColor (dpy, cmap, color_name, color);
+  if (success_p && alloc_p)
+    success_p = x_alloc_nearest_color (f, cmap, color);
   UNBLOCK_INPUT;
 
   UNBLOCK_INPUT;
 
-  if (status)
-    return 1;
-  else
-    return 0;
+  return success_p;
 }
 
 }
 
-/* Given a string ARG naming a color, compute a pixel value from it
-   suitable for screen F.
-   If F is not a color screen, return DEF (default) regardless of what
-   ARG says.  */
+
+/* Return the pixel color value for color COLOR_NAME on frame F.  If F
+   is a monochrome frame, return MONO_COLOR regardless of what ARG says.
+   Signal an error if color can't be allocated.  */
 
 int
 
 int
-x_decode_color (f, arg, def)
+x_decode_color (f, color_name, mono_color)
      FRAME_PTR f;
      FRAME_PTR f;
-     Lisp_Object arg;
-     int def;
+     Lisp_Object color_name;
+     int mono_color;
 {
   XColor cdef;
 
 {
   XColor cdef;
 
-  CHECK_STRING (arg, 0);
+  CHECK_STRING (color_name, 0);
 
 
-  if (strcmp (XSTRING (arg)->data, "black") == 0)
+#if 0 /* Don't do this.  It's wrong when we're not using the default
+        colormap, it makes freeing difficult, and it's probably not
+        an important optimization.  */
+  if (strcmp (XSTRING (color_name)->data, "black") == 0)
     return BLACK_PIX_DEFAULT (f);
     return BLACK_PIX_DEFAULT (f);
-  else if (strcmp (XSTRING (arg)->data, "white") == 0)
+  else if (strcmp (XSTRING (color_name)->data, "white") == 0)
     return WHITE_PIX_DEFAULT (f);
     return WHITE_PIX_DEFAULT (f);
+#endif
 
 
+  /* Return MONO_COLOR for monochrome frames.  */
   if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
   if (FRAME_X_DISPLAY_INFO (f)->n_planes == 1)
-    return def;
+    return mono_color;
 
 
-  /* defined_color is responsible for coping with failures
+  /* x_defined_color is responsible for coping with failures
      by looking for a near-miss.  */
      by looking for a near-miss.  */
-  if (defined_color (f, XSTRING (arg)->data, &cdef, 1))
+  if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
     return cdef.pixel;
 
     return cdef.pixel;
 
-  Fsignal (Qerror, Fcons (build_string ("undefined color"),
-                         Fcons (arg, Qnil)));
+  Fsignal (Qerror, Fcons (build_string ("Undefined color"),
+                         Fcons (color_name, Qnil)));
+  return 0;
 }
 }
+
+
 \f
 \f
+/* Change the `line-spacing' frame parameter of frame F.  OLD_VALUE is
+   the previous value of that parameter, NEW_VALUE is the new value.  */
+
+static void
+x_set_line_spacing (f, new_value, old_value)
+     struct frame *f;
+     Lisp_Object new_value, old_value;
+{
+  if (NILP (new_value))
+    f->extra_line_spacing = 0;
+  else if (NATNUMP (new_value))
+    f->extra_line_spacing = XFASTINT (new_value);
+  else
+    Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
+                           Fcons (new_value, Qnil)));
+  if (FRAME_VISIBLE_P (f))
+    redraw_frame (f);
+}
+
+
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
    the previous value of that parameter, NEW_VALUE is the new value.  */
 
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
    the previous value of that parameter, NEW_VALUE is the new value.  */
 
@@ -1367,7 +1353,7 @@ x_set_screen_gamma (f, new_value, old_value)
     /* The value 0.4545 is the normal viewing gamma.  */
     f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
   else
     /* The value 0.4545 is the normal viewing gamma.  */
     f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
   else
-    Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
+    Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
                            Fcons (new_value, Qnil)));
 
   clear_face_cache (0);
                            Fcons (new_value, Qnil)));
 
   clear_face_cache (0);
@@ -1453,7 +1439,7 @@ x_set_mouse_color (f, arg, oldval)
      Lisp_Object arg, oldval;
 {
   Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
      Lisp_Object arg, oldval;
 {
   Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
-  Cursor busy_cursor;
+  Cursor busy_cursor, horizontal_drag_cursor;
   int count;
   unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   unsigned long mask_color = f->output_data.x->background_pixel;
   int count;
   unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   unsigned long mask_color = f->output_data.x->background_pixel;
@@ -1521,6 +1507,17 @@ x_set_mouse_color (f, arg, oldval)
   else
     cross_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_crosshair);
 
   else
     cross_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_crosshair);
 
+  if (!NILP (Vx_window_horizontal_drag_shape))
+    {
+      CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
+      horizontal_drag_cursor
+       = XCreateFontCursor (FRAME_X_DISPLAY (f),
+                            XINT (Vx_window_horizontal_drag_shape));
+    }
+  else
+    horizontal_drag_cursor
+      = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
+
   /* Check and report errors with the above calls.  */
   x_check_errors (FRAME_X_DISPLAY (f), "can't set cursor shape: %s");
   x_uncatch_errors (FRAME_X_DISPLAY (f), count);
   /* Check and report errors with the above calls.  */
   x_check_errors (FRAME_X_DISPLAY (f), "can't set cursor shape: %s");
   x_uncatch_errors (FRAME_X_DISPLAY (f), count);
@@ -1529,15 +1526,10 @@ x_set_mouse_color (f, arg, oldval)
     XColor fore_color, back_color;
 
     fore_color.pixel = f->output_data.x->mouse_pixel;
     XColor fore_color, back_color;
 
     fore_color.pixel = f->output_data.x->mouse_pixel;
+    x_query_color (f, &fore_color);
     back_color.pixel = mask_color;
     back_color.pixel = mask_color;
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
-                &fore_color);
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
-                &back_color);
+    x_query_color (f, &back_color);
+    
     XRecolorCursor (FRAME_X_DISPLAY (f), cursor,
                    &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), nontext_cursor,
     XRecolorCursor (FRAME_X_DISPLAY (f), cursor,
                    &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), nontext_cursor,
@@ -1545,15 +1537,18 @@ x_set_mouse_color (f, arg, oldval)
     XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor,
                    &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor,
     XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor,
                    &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor,
-                    &fore_color, &back_color);
+                   &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor,
                     &fore_color, &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor,
                     &fore_color, &back_color);
+    XRecolorCursor (FRAME_X_DISPLAY (f), horizontal_drag_cursor,
+                    &fore_color, &back_color);
   }
 
   if (FRAME_X_WINDOW (f) != 0)
     XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
 
   }
 
   if (FRAME_X_WINDOW (f) != 0)
     XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
 
-  if (cursor != f->output_data.x->text_cursor && f->output_data.x->text_cursor != 0)
+  if (cursor != f->output_data.x->text_cursor
+      && f->output_data.x->text_cursor != 0)
     XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
   f->output_data.x->text_cursor = cursor;
 
     XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
   f->output_data.x->text_cursor = cursor;
 
@@ -1577,6 +1572,11 @@ x_set_mouse_color (f, arg, oldval)
     XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor);
   f->output_data.x->cross_cursor = cross_cursor;
 
     XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor);
   f->output_data.x->cross_cursor = cross_cursor;
 
+  if (horizontal_drag_cursor != f->output_data.x->horizontal_drag_cursor
+      && f->output_data.x->horizontal_drag_cursor != 0)
+    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->horizontal_drag_cursor);
+  f->output_data.x->horizontal_drag_cursor = horizontal_drag_cursor;
+
   XFlush (FRAME_X_DISPLAY (f));
   UNBLOCK_INPUT;
 
   XFlush (FRAME_X_DISPLAY (f));
   UNBLOCK_INPUT;
 
@@ -1589,26 +1589,49 @@ x_set_cursor_color (f, arg, oldval)
      Lisp_Object arg, oldval;
 {
   unsigned long fore_pixel, pixel;
      Lisp_Object arg, oldval;
 {
   unsigned long fore_pixel, pixel;
+  int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
 
 
-  if (!EQ (Vx_cursor_fore_pixel, Qnil))
-    fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
-                                WHITE_PIX_DEFAULT (f));
+  if (!NILP (Vx_cursor_fore_pixel))
+    {
+      fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
+                                  WHITE_PIX_DEFAULT (f));
+      fore_pixel_allocated_p = 1;
+    }
   else
     fore_pixel = f->output_data.x->background_pixel;
   else
     fore_pixel = f->output_data.x->background_pixel;
+  
   pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+  pixel_allocated_p = 1;
 
   /* Make sure that the cursor color differs from the background color.  */
   if (pixel == f->output_data.x->background_pixel)
     {
 
   /* Make sure that the cursor color differs from the background color.  */
   if (pixel == f->output_data.x->background_pixel)
     {
+      if (pixel_allocated_p)
+       {
+         x_free_colors (f, &pixel, 1);
+         pixel_allocated_p = 0;
+       }
+      
       pixel = f->output_data.x->mouse_pixel;
       if (pixel == fore_pixel)
       pixel = f->output_data.x->mouse_pixel;
       if (pixel == fore_pixel)
-       fore_pixel = f->output_data.x->background_pixel;
+       {
+         if (fore_pixel_allocated_p)
+           {
+             x_free_colors (f, &fore_pixel, 1);
+             fore_pixel_allocated_p = 0;
+           }
+         fore_pixel = f->output_data.x->background_pixel;
+       }
     }
 
   unload_color (f, f->output_data.x->cursor_foreground_pixel);
     }
 
   unload_color (f, f->output_data.x->cursor_foreground_pixel);
+  if (!fore_pixel_allocated_p)
+    fore_pixel = x_copy_color (f, fore_pixel);
   f->output_data.x->cursor_foreground_pixel = fore_pixel;
 
   unload_color (f, f->output_data.x->cursor_pixel);
   f->output_data.x->cursor_foreground_pixel = fore_pixel;
 
   unload_color (f, f->output_data.x->cursor_pixel);
+  if (!pixel_allocated_p)
+    pixel = x_copy_color (f, pixel);
   f->output_data.x->cursor_pixel = pixel;
 
   if (FRAME_X_WINDOW (f) != 0)
   f->output_data.x->cursor_pixel = pixel;
 
   if (FRAME_X_WINDOW (f) != 0)
@@ -1678,27 +1701,51 @@ x_set_border_pixel (f, pix)
     }
 }
 
     }
 }
 
-void
-x_set_cursor_type (f, arg, oldval)
-     FRAME_PTR f;
-     Lisp_Object arg, oldval;
+
+/* Value is the internal representation of the specified cursor type
+   ARG.  If type is BAR_CURSOR, return in *WIDTH the specified width
+   of the bar cursor.  */
+
+enum text_cursor_kinds
+x_specified_cursor_type (arg, width)
+     Lisp_Object arg;
+     int *width;
 {
 {
+  enum text_cursor_kinds type;
+  
   if (EQ (arg, Qbar))
     {
   if (EQ (arg, Qbar))
     {
-      FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
-      f->output_data.x->cursor_width = 2;
+      type = BAR_CURSOR;
+      *width = 2;
     }
     }
-  else if (CONSP (arg) && EQ (XCAR (arg), Qbar)
-          && INTEGERP (XCDR (arg)))
+  else if (CONSP (arg)
+          && EQ (XCAR (arg), Qbar)
+          && INTEGERP (XCDR (arg))
+          && XINT (XCDR (arg)) >= 0)
     {
     {
-      FRAME_DESIRED_CURSOR (f) = BAR_CURSOR;
-      f->output_data.x->cursor_width = XINT (XCDR (arg));
+      type = BAR_CURSOR;
+      *width = XINT (XCDR (arg));
     }
     }
+  else if (NILP (arg))
+    type = NO_CURSOR;
   else
     /* Treat anything unknown as "box cursor".
        It was bad to signal an error; people have trouble fixing
        .Xdefaults with Emacs, when it has something bad in it.  */
   else
     /* Treat anything unknown as "box cursor".
        It was bad to signal an error; people have trouble fixing
        .Xdefaults with Emacs, when it has something bad in it.  */
-    FRAME_DESIRED_CURSOR (f) = FILLED_BOX_CURSOR;
+    type = FILLED_BOX_CURSOR;
+
+  return type;
+}
+
+void
+x_set_cursor_type (f, arg, oldval)
+     FRAME_PTR f;
+     Lisp_Object arg, oldval;
+{
+  int width;
+  
+  FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
+  f->output_data.x->cursor_width = width;
 
   /* Make sure the cursor gets redrawn.  This is overkill, but how
      often do people change cursor types?  */
 
   /* Make sure the cursor gets redrawn.  This is overkill, but how
      often do people change cursor types?  */
@@ -1897,9 +1944,12 @@ x_set_visibility (f, value, oldval)
   else
     Fmake_frame_visible (frame);
 }
   else
     Fmake_frame_visible (frame);
 }
+
 \f
 \f
+/* Change window heights in windows rooted in WINDOW by N lines.  */
+
 static void
 static void
-x_set_menu_bar_lines_1 (window, n)
+x_change_window_heights (window, n)
   Lisp_Object window;
   int n;
 {
   Lisp_Object window;
   int n;
 {
@@ -1908,15 +1958,20 @@ x_set_menu_bar_lines_1 (window, n)
   XSETFASTINT (w->top, XFASTINT (w->top) + n);
   XSETFASTINT (w->height, XFASTINT (w->height) - n);
 
   XSETFASTINT (w->top, XFASTINT (w->top) + n);
   XSETFASTINT (w->height, XFASTINT (w->height) - n);
 
+  if (INTEGERP (w->orig_top))
+    XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
+  if (INTEGERP (w->orig_height))
+    XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
+
   /* Handle just the top child in a vertical split.  */
   if (!NILP (w->vchild))
   /* Handle just the top child in a vertical split.  */
   if (!NILP (w->vchild))
-    x_set_menu_bar_lines_1 (w->vchild, n);
+    x_change_window_heights (w->vchild, n);
 
   /* Adjust all children in a horizontal split.  */
   for (window = w->hchild; !NILP (window); window = w->next)
     {
       w = XWINDOW (window);
 
   /* Adjust all children in a horizontal split.  */
   for (window = w->hchild; !NILP (window); window = w->next)
     {
       w = XWINDOW (window);
-      x_set_menu_bar_lines_1 (window, n);
+      x_change_window_heights (window, n);
     }
 }
 
     }
 }
 
@@ -1964,7 +2019,7 @@ x_set_menu_bar_lines (f, value, oldval)
     }
 #else /* not USE_X_TOOLKIT */
   FRAME_MENU_BAR_LINES (f) = nlines;
     }
 #else /* not USE_X_TOOLKIT */
   FRAME_MENU_BAR_LINES (f) = nlines;
-  x_set_menu_bar_lines_1 (f->root_window, nlines - olines);
+  x_change_window_heights (f->root_window, nlines - olines);
 #endif /* not USE_X_TOOLKIT */
   adjust_glyphs (f);
 }
 #endif /* not USE_X_TOOLKIT */
   adjust_glyphs (f);
 }
@@ -1981,7 +2036,8 @@ x_set_tool_bar_lines (f, value, oldval)
      struct frame *f;
      Lisp_Object value, oldval;
 {
      struct frame *f;
      Lisp_Object value, oldval;
 {
-  int delta, nlines;
+  int delta, nlines, root_height;
+  Lisp_Object root_window;
 
   /* Use VALUE only if an integer >= 0.  */
   if (INTEGERP (value) && XINT (value) >= 0)
 
   /* Use VALUE only if an integer >= 0.  */
   if (INTEGERP (value) && XINT (value) >= 0)
@@ -1993,9 +2049,48 @@ x_set_tool_bar_lines (f, value, oldval)
   ++windows_or_buffers_changed;
 
   delta = nlines - FRAME_TOOL_BAR_LINES (f);
   ++windows_or_buffers_changed;
 
   delta = nlines - FRAME_TOOL_BAR_LINES (f);
+
+  /* Don't resize the tool-bar to more than we have room for.  */
+  root_window = FRAME_ROOT_WINDOW (f);
+  root_height = XINT (XWINDOW (root_window)->height);
+  if (root_height - delta < 1)
+    {
+      delta = root_height - 1;
+      nlines = FRAME_TOOL_BAR_LINES (f) + delta;
+    }
+
   FRAME_TOOL_BAR_LINES (f) = nlines;
   FRAME_TOOL_BAR_LINES (f) = nlines;
-  x_set_menu_bar_lines_1 (FRAME_ROOT_WINDOW (f), delta);
+  x_change_window_heights (root_window, delta);
   adjust_glyphs (f);
   adjust_glyphs (f);
+  
+  /* We also have to make sure that the internal border at the top of
+     the frame, below the menu bar or tool bar, is redrawn when the
+     tool bar disappears.  This is so because the internal border is
+     below the tool bar if one is displayed, but is below the menu bar
+     if there isn't a tool bar.  The tool bar draws into the area
+     below the menu bar.  */
+  if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
+    {
+      updating_frame = f;
+      clear_frame ();
+      clear_current_matrices (f);
+      updating_frame = NULL;
+    }
+
+  /* If the tool bar gets smaller, the internal border below it
+     has to be cleared.  It was formerly part of the display
+     of the larger tool bar, and updating windows won't clear it.  */
+  if (delta < 0)
+    {
+      int height = FRAME_INTERNAL_BORDER_WIDTH (f);
+      int width = PIXEL_WIDTH (f);
+      int y = nlines * CANON_Y_UNIT (f);
+
+      BLOCK_INPUT;
+      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 0, y, width, height, False);
+      UNBLOCK_INPUT;
+    }
 }
 
 
 }
 
 
@@ -2068,6 +2163,60 @@ x_set_scroll_bar_background (f, value, oldval)
     }
 }
 
     }
 }
 
+\f
+/* Encode Lisp string STRING as a text in a format appropriate for
+   XICCC (X Inter Client Communication Conventions).
+
+   If STRING contains only ASCII characters, do no conversion and
+   return the string data of STRING.  Otherwise, encode the text by
+   CODING_SYSTEM, and return a newly allocated memory area which
+   should be freed by `xfree' by a caller.
+
+   Store the byte length of resulting text in *TEXT_BYTES.
+
+   If the text contains only ASCII and Latin-1, store 1 in *STRING_P,
+   which means that the `encoding' of the result can be `STRING'.
+   Otherwise store 0 in *STRINGP, which means that the `encoding' of
+   the result should be `COMPOUND_TEXT'.  */
+
+unsigned char *
+x_encode_text (string, coding_system, text_bytes, stringp)
+     Lisp_Object string, coding_system;
+     int *text_bytes, *stringp;
+{
+  unsigned char *str = XSTRING (string)->data;
+  int chars = XSTRING (string)->size;
+  int bytes = STRING_BYTES (XSTRING (string));
+  int charset_info;
+  int bufsize;
+  unsigned char *buf;
+  struct coding_system coding;
+
+  charset_info = find_charset_in_text (str, chars, bytes, NULL, Qnil);
+  if (charset_info == 0)
+    {
+      /* No multibyte character in OBJ.  We need not encode it.  */
+      *text_bytes = bytes;
+      *stringp = 1;
+      return str;
+    }
+
+  setup_coding_system (coding_system, &coding);
+  coding.src_multibyte = 1;
+  coding.dst_multibyte = 0;
+  coding.mode |= CODING_MODE_LAST_BLOCK;
+  if (coding.type == coding_type_iso2022)
+    coding.flags |= CODING_FLAG_ISO_SAFE;
+  /* We suppress producing escape sequences for composition.  */
+  coding.composing = COMPOSITION_DISABLED;
+  bufsize = encoding_buffer_size (&coding, bytes);
+  buf = (unsigned char *) xmalloc (bufsize);
+  encode_coding (&coding, str, buf, bytes, bufsize);
+  *text_bytes = coding.produced;
+  *stringp = (charset_info == 1 || !EQ (coding_system, Qcompound_text));
+  return buf;
+}
+
 \f
 /* Change the name of frame F to NAME.  If NAME is nil, set F's name to
        x_id_name.
 \f
 /* Change the name of frame F to NAME.  If NAME is nil, set F's name to
        x_id_name.
@@ -2130,19 +2279,31 @@ x_set_name (f, name, explicit)
 #ifdef HAVE_X11R4
       {
        XTextProperty text, icon;
 #ifdef HAVE_X11R4
       {
        XTextProperty text, icon;
-       Lisp_Object icon_name;
-
-       text.value = XSTRING (name)->data;
-       text.encoding = XA_STRING;
+       int bytes, stringp;
+       Lisp_Object coding_system;
+
+       coding_system = Vlocale_coding_system;
+       if (NILP (coding_system))
+         coding_system = Qcompound_text;
+       text.value = x_encode_text (name, coding_system, &bytes, &stringp);
+       text.encoding = (stringp ? XA_STRING
+                        : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
        text.format = 8;
        text.format = 8;
-       text.nitems = STRING_BYTES (XSTRING (name));
+       text.nitems = bytes;
 
 
-       icon_name = (!NILP (f->icon_name) ? f->icon_name : name);
-
-       icon.value = XSTRING (icon_name)->data;
-       icon.encoding = XA_STRING;
-       icon.format = 8;
-       icon.nitems = STRING_BYTES (XSTRING (icon_name));
+       if (NILP (f->icon_name))
+         {
+           icon = text;
+         }
+       else
+         {
+           icon.value = x_encode_text (f->icon_name, coding_system,
+                                       &bytes, &stringp);
+           icon.encoding = (stringp ? XA_STRING
+                            : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
+           icon.format = 8;
+           icon.nitems = bytes;
+         }
 #ifdef USE_X_TOOLKIT
        XSetWMName (FRAME_X_DISPLAY (f),
                    XtWindow (f->output_data.x->widget), &text);
 #ifdef USE_X_TOOLKIT
        XSetWMName (FRAME_X_DISPLAY (f),
                    XtWindow (f->output_data.x->widget), &text);
@@ -2152,6 +2313,11 @@ x_set_name (f, name, explicit)
        XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
        XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
 #endif /* not USE_X_TOOLKIT */
        XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
        XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
 #endif /* not USE_X_TOOLKIT */
+       if (!NILP (f->icon_name)
+           && icon.value != XSTRING (f->icon_name)->data)
+         xfree (icon.value);
+       if (text.value != XSTRING (name)->data)
+         xfree (text.value);
       }
 #else /* not HAVE_X11R4 */
       XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
       }
 #else /* not HAVE_X11R4 */
       XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
@@ -2220,19 +2386,31 @@ x_set_title (f, name, old_name)
 #ifdef HAVE_X11R4
       {
        XTextProperty text, icon;
 #ifdef HAVE_X11R4
       {
        XTextProperty text, icon;
-       Lisp_Object icon_name;
-
-       text.value = XSTRING (name)->data;
-       text.encoding = XA_STRING;
+       int bytes, stringp;
+       Lisp_Object coding_system;
+
+       coding_system = Vlocale_coding_system;
+       if (NILP (coding_system))
+         coding_system = Qcompound_text;
+       text.value = x_encode_text (name, coding_system, &bytes, &stringp);
+       text.encoding = (stringp ? XA_STRING
+                        : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
        text.format = 8;
        text.format = 8;
-       text.nitems = STRING_BYTES (XSTRING (name));
-
-       icon_name = (!NILP (f->icon_name) ? f->icon_name : name);
+       text.nitems = bytes;
 
 
-       icon.value = XSTRING (icon_name)->data;
-       icon.encoding = XA_STRING;
-       icon.format = 8;
-       icon.nitems = STRING_BYTES (XSTRING (icon_name));
+       if (NILP (f->icon_name))
+         {
+           icon = text;
+         }
+       else
+         {
+           icon.value = x_encode_text (f->icon_name, coding_system,
+                                       &bytes, &stringp);
+           icon.encoding = (stringp ? XA_STRING
+                            : FRAME_X_DISPLAY_INFO (f)->Xatom_COMPOUND_TEXT);
+           icon.format = 8;
+           icon.nitems = bytes;
+         }
 #ifdef USE_X_TOOLKIT
        XSetWMName (FRAME_X_DISPLAY (f),
                    XtWindow (f->output_data.x->widget), &text);
 #ifdef USE_X_TOOLKIT
        XSetWMName (FRAME_X_DISPLAY (f),
                    XtWindow (f->output_data.x->widget), &text);
@@ -2242,6 +2420,11 @@ x_set_title (f, name, old_name)
        XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
        XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
 #endif /* not USE_X_TOOLKIT */
        XSetWMName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &text);
        XSetWMIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), &icon);
 #endif /* not USE_X_TOOLKIT */
+       if (!NILP (f->icon_name)
+           && icon.value != XSTRING (f->icon_name)->data)
+         xfree (icon.value);
+       if (text.value != XSTRING (name)->data)
+         xfree (text.value);
       }
 #else /* not HAVE_X11R4 */
       XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
       }
 #else /* not HAVE_X11R4 */
       XSetIconName (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
@@ -2511,8 +2694,6 @@ display_x_get_resource (dpyinfo, attribute, class, component, subclass)
   char *name_key;
   char *class_key;
 
   char *name_key;
   char *class_key;
 
-  check_x ();
-
   CHECK_STRING (attribute, 0);
   CHECK_STRING (class, 0);
 
   CHECK_STRING (attribute, 0);
   CHECK_STRING (class, 0);
 
@@ -3051,106 +3232,414 @@ hack_wm_protocols (f, widget)
   UNBLOCK_INPUT;
 }
 #endif
   UNBLOCK_INPUT;
 }
 #endif
-\f
-#ifdef USE_X_TOOLKIT
 
 
-/* Create and set up the X widget for frame F.  */
 
 
-static void
-x_window (f, window_prompting, minibuffer_only)
-     struct frame *f;
-     long window_prompting;
-     int minibuffer_only;
-{
-  XClassHint class_hints;
-  XSetWindowAttributes attributes;
-  unsigned long attribute_mask;
+\f
+/* Support routines for XIC (X Input Context).  */
 
 
-  Widget shell_widget;
-  Widget pane_widget;
-  Widget frame_widget;
-  Arg al [25];
-  int ac;
+#ifdef HAVE_X_I18N
 
 
-  BLOCK_INPUT;
+static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
+static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
 
 
-  /* Use the resource name as the top-level widget name
-     for looking up resources.  Make a non-Lisp copy
-     for the window manager, so GC relocation won't bother it.
 
 
-     Elsewhere we specify the window name for the window manager.  */
-     
-  {
-    char *str = (char *) XSTRING (Vx_resource_name)->data;
-    f->namebuf = (char *) xmalloc (strlen (str) + 1);
-    strcpy (f->namebuf, str);
-  }
+/* Supported XIM styles, ordered by preferenc.  */
 
 
-  ac = 0;
-  XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
-  XtSetArg (al[ac], XtNinput, 1); ac++;
-  XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
-  XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
-  shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
-                                  applicationShellWidgetClass,
-                                  FRAME_X_DISPLAY (f), al, ac);
+static XIMStyle supported_xim_styles[] =
+{
+  XIMPreeditPosition | XIMStatusArea,
+  XIMPreeditPosition | XIMStatusNothing,
+  XIMPreeditPosition | XIMStatusNone,
+  XIMPreeditNothing | XIMStatusArea,
+  XIMPreeditNothing | XIMStatusNothing,
+  XIMPreeditNothing | XIMStatusNone,
+  XIMPreeditNone | XIMStatusArea,
+  XIMPreeditNone | XIMStatusNothing,
+  XIMPreeditNone | XIMStatusNone,
+  0,
+};
 
 
-  f->output_data.x->widget = shell_widget;
-  /* maybe_set_screen_title_format (shell_widget); */
 
 
-  pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
-                                 (widget_value *) NULL,
-                                 shell_widget, False,
-                                 (lw_callback) NULL,
-                                 (lw_callback) NULL,
-                                 (lw_callback) NULL);
+/* Create an X fontset on frame F with base font name
+   BASE_FONTNAME.. */
 
 
-  f->output_data.x->column_widget = pane_widget;
+static XFontSet
+xic_create_xfontset (f, base_fontname)
+     struct frame *f;
+     char *base_fontname;
+{
+  XFontSet xfs;
+  char **missing_list;
+  int missing_count;
+  char *def_string;
+  
+  xfs = XCreateFontSet (FRAME_X_DISPLAY (f),
+                       base_fontname, &missing_list,
+                       &missing_count, &def_string);
+  if (missing_list)
+    XFreeStringList (missing_list);
+  
+  /* No need to free def_string. */
+  return xfs;
+}
 
 
-  /* mappedWhenManaged to false tells to the paned window to not map/unmap 
-     the emacs screen when changing menubar.  This reduces flickering.  */
 
 
-  ac = 0;
-  XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
-  XtSetArg (al[ac], XtNshowGrip, 0); ac++;
-  XtSetArg (al[ac], XtNallowResize, 1); ac++;
-  XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
-  XtSetArg (al[ac], XtNemacsFrame, f); ac++;
-  frame_widget = XtCreateWidget (f->namebuf,
-                                 emacsFrameClass,
-                                 pane_widget, al, ac);
-  f->output_data.x->edit_widget = frame_widget;
-  XtManageChild (frame_widget); 
+/* Value is the best input style, given user preferences USER (already
+   checked to be supported by Emacs), and styles supported by the
+   input method XIM.  */
 
 
-  /* Do some needed geometry management.  */
-  {
-    int len;
-    char *tem, shell_position[32];
-    Arg al[2];
-    int ac = 0;
-    int extra_borders = 0;
-    int menubar_size 
-      = (f->output_data.x->menubar_widget
-        ? (f->output_data.x->menubar_widget->core.height
-           + f->output_data.x->menubar_widget->core.border_width)
-        : 0);
+static XIMStyle
+best_xim_style (user, xim)
+     XIMStyles *user;
+     XIMStyles *xim;
+{
+  int i, j;
 
 
-#if 0 /* Experimentally, we now get the right results
-        for -geometry -0-0 without this.  24 Aug 96, rms.  */
-    if (FRAME_EXTERNAL_MENU_BAR (f))
-      {
-        Dimension ibw = 0;
-        XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
-        menubar_size += ibw;
-      }
-#endif
+  for (i = 0; i < user->count_styles; ++i)
+    for (j = 0; j < xim->count_styles; ++j)
+      if (user->supported_styles[i] == xim->supported_styles[j])
+       return user->supported_styles[i];
 
 
-    f->output_data.x->menubar_height = menubar_size;
+  /* Return the default style.  */
+  return XIMPreeditNothing | XIMStatusNothing;
+}
 
 
-#ifndef USE_LUCID
-    /* Motif seems to need this amount added to the sizes
+/* Create XIC for frame F. */
+
+void
+create_frame_xic (f)
+     struct frame *f;
+{
+  XIM xim;
+  XIC xic = NULL;
+  XFontSet xfs = NULL;
+  static XIMStyle xic_style;
+
+  if (FRAME_XIC (f))
+    return;
+  
+  xim = FRAME_X_XIM (f);
+  if (xim)
+    {
+      XRectangle s_area;
+      XPoint spot;
+      XVaNestedList preedit_attr;
+      XVaNestedList status_attr;
+      char *base_fontname;
+      int fontset;
+
+      s_area.x = 0; s_area.y = 0; s_area.width = 1; s_area.height = 1;
+      spot.x = 0; spot.y = 1;
+      /* Create X fontset. */
+      fontset = FRAME_FONTSET (f);
+      if (fontset < 0)
+       base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+      else
+       {
+         /* Determine the base fontname from the ASCII font name of
+            FONTSET.  */
+         char *ascii_font = (char *) XSTRING (fontset_ascii (fontset))->data;
+         char *p = ascii_font;
+         int i;
+
+         for (i = 0; *p; p++)
+           if (*p == '-') i++;
+         if (i != 14)
+           /* As the font name doesn't conform to XLFD, we can't
+              modify it to get a suitable base fontname for the
+              frame.  */
+           base_fontname = "-*-*-*-r-normal--14-*-*-*-*-*-*-*";
+         else
+           {
+             int len = strlen (ascii_font) + 1;
+             char *p1 = NULL;
+
+             for (i = 0, p = ascii_font; i < 8; p++)
+               {
+                 if (*p == '-')
+                   {
+                     i++;
+                     if (i == 3)
+                       p1 = p + 1;
+                   }
+               }
+             base_fontname = (char *) alloca (len);
+             bzero (base_fontname, len);
+             strcpy (base_fontname, "-*-*-");
+             bcopy (p1, base_fontname + 5, p - p1);
+             strcat (base_fontname, "*-*-*-*-*-*-*");
+           }
+       }
+      xfs = xic_create_xfontset (f, base_fontname);
+
+      /* Determine XIC style.  */
+      if (xic_style == 0)
+       {
+         XIMStyles supported_list;
+         supported_list.count_styles = (sizeof supported_xim_styles
+                                        / sizeof supported_xim_styles[0]);
+         supported_list.supported_styles = supported_xim_styles;
+         xic_style = best_xim_style (&supported_list,
+                                     FRAME_X_XIM_STYLES (f));
+       }
+
+      preedit_attr = XVaCreateNestedList (0,
+                                         XNFontSet, xfs,
+                                         XNForeground,
+                                         FRAME_FOREGROUND_PIXEL (f),
+                                         XNBackground,
+                                         FRAME_BACKGROUND_PIXEL (f),
+                                         (xic_style & XIMPreeditPosition
+                                          ? XNSpotLocation
+                                          : NULL),
+                                         &spot,
+                                         NULL);
+      status_attr = XVaCreateNestedList (0,
+                                        XNArea,
+                                        &s_area,
+                                        XNFontSet,
+                                        xfs,
+                                        XNForeground,
+                                        FRAME_FOREGROUND_PIXEL (f),
+                                        XNBackground,
+                                        FRAME_BACKGROUND_PIXEL (f),
+                                        NULL);
+
+      xic = XCreateIC (xim,
+                      XNInputStyle, xic_style,
+                      XNClientWindow, FRAME_X_WINDOW(f),
+                      XNFocusWindow, FRAME_X_WINDOW(f),
+                      XNStatusAttributes, status_attr,
+                      XNPreeditAttributes, preedit_attr,
+                      NULL);
+      XFree (preedit_attr);
+      XFree (status_attr);
+    }
+  
+  FRAME_XIC (f) = xic;
+  FRAME_XIC_STYLE (f) = xic_style;
+  FRAME_XIC_FONTSET (f) = xfs;
+}
+
+
+/* Destroy XIC and free XIC fontset of frame F, if any. */
+
+void
+free_frame_xic (f)
+     struct frame *f;
+{
+  if (FRAME_XIC (f) == NULL)
+    return;
+  
+  XDestroyIC (FRAME_XIC (f));
+  if (FRAME_XIC_FONTSET (f))
+    XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+
+  FRAME_XIC (f) = NULL;
+  FRAME_XIC_FONTSET (f) = NULL;
+}
+
+
+/* Place preedit area for XIC of window W's frame to specified
+   pixel position X/Y.  X and Y are relative to window W.  */
+
+void
+xic_set_preeditarea (w, x, y)
+     struct window *w;
+     int x, y;
+{
+  struct frame *f = XFRAME (w->frame);
+  XVaNestedList attr;
+  XPoint spot;
+      
+  spot.x = WINDOW_TO_FRAME_PIXEL_X (w, x);
+  spot.y = WINDOW_TO_FRAME_PIXEL_Y (w, y) + FONT_BASE (FRAME_FONT (f));
+  attr = XVaCreateNestedList (0, XNSpotLocation, &spot, NULL);
+  XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+  XFree (attr);
+}
+
+
+/* Place status area for XIC in bottom right corner of frame F.. */
+
+void
+xic_set_statusarea (f)
+     struct frame *f;
+{
+  XIC xic = FRAME_XIC (f);
+  XVaNestedList attr;
+  XRectangle area;
+  XRectangle *needed;
+
+  /* Negotiate geometry of status area.  If input method has existing
+     status area, use its current size.  */
+  area.x = area.y = area.width = area.height = 0;
+  attr = XVaCreateNestedList (0, XNAreaNeeded, &area, NULL);
+  XSetICValues (xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+  
+  attr = XVaCreateNestedList (0, XNAreaNeeded, &needed, NULL);
+  XGetICValues (xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+
+  if (needed->width == 0) /* Use XNArea instead of XNAreaNeeded */
+    {
+      attr = XVaCreateNestedList (0, XNArea, &needed, NULL);
+      XGetICValues (xic, XNStatusAttributes, attr, NULL);
+      XFree (attr);
+    }
+
+  area.width  = needed->width;
+  area.height = needed->height;
+  area.x = PIXEL_WIDTH (f) - area.width - FRAME_INTERNAL_BORDER_WIDTH (f);
+  area.y = (PIXEL_HEIGHT (f) - area.height
+           - FRAME_MENUBAR_HEIGHT (f) - FRAME_INTERNAL_BORDER_WIDTH (f));
+  XFree (needed);
+
+  attr = XVaCreateNestedList (0, XNArea, &area, NULL);
+  XSetICValues(xic, XNStatusAttributes, attr, NULL);
+  XFree (attr);
+}
+
+
+/* Set X fontset for XIC of frame F, using base font name
+   BASE_FONTNAME.  Called when a new Emacs fontset is chosen.  */
+
+void
+xic_set_xfontset (f, base_fontname)
+     struct frame *f;
+     char *base_fontname;
+{
+  XVaNestedList attr;
+  XFontSet xfs;
+
+  xfs = xic_create_xfontset (f, base_fontname);
+
+  attr = XVaCreateNestedList (0, XNFontSet, xfs, NULL);
+  if (FRAME_XIC_STYLE (f) & XIMPreeditPosition)
+    XSetICValues (FRAME_XIC (f), XNPreeditAttributes, attr, NULL);
+  if (FRAME_XIC_STYLE (f) & XIMStatusArea)
+    XSetICValues (FRAME_XIC (f), XNStatusAttributes, attr, NULL);
+  XFree (attr);
+  
+  if (FRAME_XIC_FONTSET (f))
+    XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f));
+  FRAME_XIC_FONTSET (f) = xfs;
+}
+
+#endif /* HAVE_X_I18N */
+
+
+\f
+#ifdef USE_X_TOOLKIT
+
+/* Create and set up the X widget for frame F.  */
+
+static void
+x_window (f, window_prompting, minibuffer_only)
+     struct frame *f;
+     long window_prompting;
+     int minibuffer_only;
+{
+  XClassHint class_hints;
+  XSetWindowAttributes attributes;
+  unsigned long attribute_mask;
+  Widget shell_widget;
+  Widget pane_widget;
+  Widget frame_widget;
+  Arg al [25];
+  int ac;
+
+  BLOCK_INPUT;
+
+  /* Use the resource name as the top-level widget name
+     for looking up resources.  Make a non-Lisp copy
+     for the window manager, so GC relocation won't bother it.
+
+     Elsewhere we specify the window name for the window manager.  */
+     
+  {
+    char *str = (char *) XSTRING (Vx_resource_name)->data;
+    f->namebuf = (char *) xmalloc (strlen (str) + 1);
+    strcpy (f->namebuf, str);
+  }
+
+  ac = 0;
+  XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
+  XtSetArg (al[ac], XtNinput, 1); ac++;
+  XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
+  XtSetArg (al[ac], XtNborderWidth, f->output_data.x->border_width); ac++;
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
+  shell_widget = XtAppCreateShell (f->namebuf, EMACS_CLASS,
+                                  applicationShellWidgetClass,
+                                  FRAME_X_DISPLAY (f), al, ac);
+
+  f->output_data.x->widget = shell_widget;
+  /* maybe_set_screen_title_format (shell_widget); */
+
+  pane_widget = lw_create_widget ("main", "pane", widget_id_tick++,
+                                 (widget_value *) NULL,
+                                 shell_widget, False,
+                                 (lw_callback) NULL,
+                                 (lw_callback) NULL,
+                                 (lw_callback) NULL,
+                                 (lw_callback) NULL);
+
+  ac = 0;
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
+  XtSetValues (pane_widget, al, ac);
+  f->output_data.x->column_widget = pane_widget;
+
+  /* mappedWhenManaged to false tells to the paned window to not map/unmap 
+     the emacs screen when changing menubar.  This reduces flickering.  */
+
+  ac = 0;
+  XtSetArg (al[ac], XtNmappedWhenManaged, 0); ac++;
+  XtSetArg (al[ac], XtNshowGrip, 0); ac++;
+  XtSetArg (al[ac], XtNallowResize, 1); ac++;
+  XtSetArg (al[ac], XtNresizeToPreferred, 1); ac++;
+  XtSetArg (al[ac], XtNemacsFrame, f); ac++;
+  XtSetArg (al[ac], XtNvisual, FRAME_X_VISUAL (f)); ac++;
+  XtSetArg (al[ac], XtNdepth, FRAME_X_DISPLAY_INFO (f)->n_planes); ac++;
+  XtSetArg (al[ac], XtNcolormap, FRAME_X_COLORMAP (f)); ac++;
+  frame_widget = XtCreateWidget (f->namebuf, emacsFrameClass, pane_widget,
+                                al, ac);
+  f->output_data.x->edit_widget = frame_widget;
+  XtManageChild (frame_widget); 
+
+  /* Do some needed geometry management.  */
+  {
+    int len;
+    char *tem, shell_position[32];
+    Arg al[2];
+    int ac = 0;
+    int extra_borders = 0;
+    int menubar_size 
+      = (f->output_data.x->menubar_widget
+        ? (f->output_data.x->menubar_widget->core.height
+           + f->output_data.x->menubar_widget->core.border_width)
+        : 0);
+
+#if 0 /* Experimentally, we now get the right results
+        for -geometry -0-0 without this.  24 Aug 96, rms.  */
+    if (FRAME_EXTERNAL_MENU_BAR (f))
+      {
+        Dimension ibw = 0;
+        XtVaGetValues (pane_widget, XtNinternalBorderWidth, &ibw, NULL);
+        menubar_size += ibw;
+      }
+#endif
+
+    f->output_data.x->menubar_height = menubar_size;
+
+#ifndef USE_LUCID
+    /* Motif seems to need this amount added to the sizes
        specified for the shell widget.  The Athena/Lucid widgets don't.
        Both conclusions reached experimentally.  -- rms.  */
     XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
        specified for the shell widget.  The Athena/Lucid widgets don't.
        Both conclusions reached experimentally.  -- rms.  */
     XtVaGetValues (f->output_data.x->edit_widget, XtNinternalBorderWidth,
@@ -3208,35 +3697,11 @@ x_window (f, window_prompting, minibuffer_only)
   XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
 
 #ifdef HAVE_X_I18N
   XSetClassHint (FRAME_X_DISPLAY (f), XtWindow (shell_widget), &class_hints);
 
 #ifdef HAVE_X_I18N
-#ifndef X_I18N_INHIBITED
-  { 
-    XIM xim;
-    XIC xic = NULL;
-
-    xim = XOpenIM (FRAME_X_DISPLAY (f), NULL, NULL, NULL);
-
-    if (xim)
-      {
-       xic = XCreateIC (xim,  
-                        XNInputStyle,   XIMPreeditNothing | XIMStatusNothing,
-                        XNClientWindow, FRAME_X_WINDOW(f),
-                        XNFocusWindow,  FRAME_X_WINDOW(f),
-                        NULL);
-
-       if (xic == 0)
-         {
-           XCloseIM (xim);
-           xim = NULL;
-         }
-      }
-    FRAME_XIM (f) = xim;
-    FRAME_XIC (f) = xic;
-  }
-#else /* X_I18N_INHIBITED */
-  FRAME_XIM (f) = 0;
-  FRAME_XIC (f) = 0;
-#endif /* X_I18N_INHIBITED */
-#endif /* HAVE_X_I18N */
+  FRAME_XIC (f) = NULL;
+#ifdef USE_XIM
+  create_frame_xic (f);
+#endif
+#endif
 
   f->output_data.x->wm_hints.input = True;
   f->output_data.x->wm_hints.flags |= InputHint;
 
   f->output_data.x->wm_hints.input = True;
   f->output_data.x->wm_hints.flags |= InputHint;
@@ -3258,8 +3723,19 @@ x_window (f, window_prompting, minibuffer_only)
                   XA_ATOM, 32, PropModeAppend,
                   (unsigned char*) NULL, 0);
 
                   XA_ATOM, 32, PropModeAppend,
                   (unsigned char*) NULL, 0);
 
- /* Make all the standard events reach the Emacs frame.  */
 /* Make all the standard events reach the Emacs frame.  */
   attributes.event_mask = STANDARD_EVENT_SET;
   attributes.event_mask = STANDARD_EVENT_SET;
+
+#ifdef HAVE_X_I18N
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+    }
+#endif /* HAVE_X_I18N */
+  
   attribute_mask = CWEventMask;
   XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
                           attribute_mask, &attributes);
   attribute_mask = CWEventMask;
   XChangeWindowAttributes (XtDisplay (shell_widget), XtWindow (shell_widget),
                           attribute_mask, &attributes);
@@ -3309,11 +3785,9 @@ x_window (f)
   attributes.backing_store = NotUseful;
   attributes.save_under = True;
   attributes.event_mask = STANDARD_EVENT_SET;
   attributes.backing_store = NotUseful;
   attributes.save_under = True;
   attributes.event_mask = STANDARD_EVENT_SET;
-  attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity
-#if 0
-                   | CWBackingStore | CWSaveUnder
-#endif
-                   | CWEventMask);
+  attributes.colormap = FRAME_X_COLORMAP (f);
+  attribute_mask = (CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
+                   | CWColormap);
 
   BLOCK_INPUT;
   FRAME_X_WINDOW (f)
 
   BLOCK_INPUT;
   FRAME_X_WINDOW (f)
@@ -3325,40 +3799,25 @@ x_window (f)
                     f->output_data.x->border_width,
                     CopyFromParent, /* depth */
                     InputOutput, /* class */
                     f->output_data.x->border_width,
                     CopyFromParent, /* depth */
                     InputOutput, /* class */
-                    FRAME_X_DISPLAY_INFO (f)->visual,
+                    FRAME_X_VISUAL (f),
                     attribute_mask, &attributes);
                     attribute_mask, &attributes);
-#ifdef HAVE_X_I18N
-#ifndef X_I18N_INHIBITED
-  { 
-    XIM xim;
-    XIC xic = NULL;
-
-    xim = XOpenIM (FRAME_X_DISPLAY(f), NULL, NULL, NULL);
-
-    if (xim)
-      {
-       xic = XCreateIC (xim,  
-                        XNInputStyle,   XIMPreeditNothing | XIMStatusNothing,
-                        XNClientWindow, FRAME_X_WINDOW(f),
-                        XNFocusWindow,  FRAME_X_WINDOW(f),
-                        NULL);
 
 
-       if (!xic)
-         {
-           XCloseIM (xim);
-           xim = NULL;
-         }
-      }
-
-    FRAME_XIM (f) = xim;
-    FRAME_XIC (f) = xic;
-  }
-#else /* X_I18N_INHIBITED */
-  FRAME_XIM (f) = 0;
-  FRAME_XIC (f) = 0;
-#endif /* X_I18N_INHIBITED */
+#ifdef HAVE_X_I18N
+#ifdef USE_XIM
+  create_frame_xic (f);
+  if (FRAME_XIC (f))
+    {
+      /* XIM server might require some X events. */
+      unsigned long fevent = NoEventMask;
+      XGetICValues(FRAME_XIC (f), XNFilterEvents, &fevent, NULL);
+      attributes.event_mask |= fevent;
+      attribute_mask = CWEventMask;
+      XChangeWindowAttributes (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                              attribute_mask, &attributes);
+    }
+#endif
 #endif /* HAVE_X_I18N */
 #endif /* HAVE_X_I18N */
-
+  
   validate_x_resource_name ();
 
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
   validate_x_resource_name ();
 
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
@@ -3456,7 +3915,7 @@ x_icon (f, parms)
   UNBLOCK_INPUT;
 }
 
   UNBLOCK_INPUT;
 }
 
-/* Make the GC's needed for this window, setting the
+/* Make the GCs needed for this window, setting the
    background, border and mouse colors; also create the
    mouse cursor and the gray border tile.  */
 
    background, border and mouse colors; also create the
    mouse cursor and the gray border tile.  */
 
@@ -3476,7 +3935,7 @@ x_make_gc (f)
 
   BLOCK_INPUT;
 
 
   BLOCK_INPUT;
 
-  /* Create the GC's of this frame.
+  /* Create the GCs of this frame.
      Note that many default values are used.  */
 
   /* Normal video */
      Note that many default values are used.  */
 
   /* Normal video */
@@ -3484,20 +3943,20 @@ x_make_gc (f)
   gc_values.foreground = f->output_data.x->foreground_pixel;
   gc_values.background = f->output_data.x->background_pixel;
   gc_values.line_width = 0;    /* Means 1 using fast algorithm.  */
   gc_values.foreground = f->output_data.x->foreground_pixel;
   gc_values.background = f->output_data.x->background_pixel;
   gc_values.line_width = 0;    /* Means 1 using fast algorithm.  */
-  f->output_data.x->normal_gc = XCreateGC (FRAME_X_DISPLAY (f),
-                                      FRAME_X_WINDOW (f),
-                                      GCLineWidth | GCFont
-                                      | GCForeground | GCBackground,
-                                      &gc_values);
+  f->output_data.x->normal_gc
+    = XCreateGC (FRAME_X_DISPLAY (f),
+                FRAME_X_WINDOW (f),
+                GCLineWidth | GCFont | GCForeground | GCBackground,
+                &gc_values);
 
   /* Reverse video style.  */
   gc_values.foreground = f->output_data.x->background_pixel;
   gc_values.background = f->output_data.x->foreground_pixel;
 
   /* Reverse video style.  */
   gc_values.foreground = f->output_data.x->background_pixel;
   gc_values.background = f->output_data.x->foreground_pixel;
-  f->output_data.x->reverse_gc = XCreateGC (FRAME_X_DISPLAY (f),
-                                       FRAME_X_WINDOW (f),
-                                       GCFont | GCForeground | GCBackground
-                                       | GCLineWidth,
-                                       &gc_values);
+  f->output_data.x->reverse_gc
+    = XCreateGC (FRAME_X_DISPLAY (f),
+                FRAME_X_WINDOW (f),
+                GCFont | GCForeground | GCBackground | GCLineWidth,
+                &gc_values);
 
   /* Cursor has cursor-color background, background-color foreground.  */
   gc_values.foreground = f->output_data.x->background_pixel;
 
   /* Cursor has cursor-color background, background-color foreground.  */
   gc_values.foreground = f->output_data.x->background_pixel;
@@ -3532,6 +3991,74 @@ x_make_gc (f)
   UNBLOCK_INPUT;
 }
 
   UNBLOCK_INPUT;
 }
 
+
+/* Free what was was allocated in x_make_gc.  */
+
+void
+x_free_gcs (f)
+     struct frame *f;
+{
+  Display *dpy = FRAME_X_DISPLAY (f);
+
+  BLOCK_INPUT;
+  
+  if (f->output_data.x->normal_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->normal_gc);
+      f->output_data.x->normal_gc = 0;
+    }
+
+  if (f->output_data.x->reverse_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->reverse_gc);
+      f->output_data.x->reverse_gc = 0;
+    }
+  
+  if (f->output_data.x->cursor_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->cursor_gc);
+      f->output_data.x->cursor_gc = 0;
+    }
+
+  if (f->output_data.x->border_tile)
+    {
+      XFreePixmap (dpy, f->output_data.x->border_tile);
+      f->output_data.x->border_tile = 0;
+    }
+
+  UNBLOCK_INPUT;
+}
+
+
+/* Handler for signals raised during x_create_frame and
+   x_create_top_frame.  FRAME is the frame which is partially
+   constructed.  */
+
+static Lisp_Object
+unwind_create_frame (frame)
+     Lisp_Object frame;
+{
+  struct frame *f = XFRAME (frame);
+
+  /* If frame is ``official'', nothing to do.  */
+  if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
+    {
+#if GLYPH_DEBUG
+      struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+#endif
+      
+      x_free_frame_resources (f);
+
+      /* Check that reference counts are indeed correct.  */
+      xassert (dpyinfo->reference_count == dpyinfo_refcount);
+      xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
+      return Qt;
+    }
+  
+  return Qnil;
+}
+
+
 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
        1, 1, 0,
   "Make a new X window, which is called a \"frame\" in Emacs terms.\n\
 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
        1, 1, 0,
   "Make a new X window, which is called a \"frame\" in Emacs terms.\n\
@@ -3552,7 +4079,7 @@ This function is an internal primitive--use `make-frame' instead.")
   int minibuffer_only = 0;
   long window_prompting = 0;
   int width, height;
   int minibuffer_only = 0;
   long window_prompting = 0;
   int width, height;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
   struct x_display_info *dpyinfo = NULL;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
   struct x_display_info *dpyinfo = NULL;
@@ -3622,6 +4149,7 @@ This function is an internal primitive--use `make-frame' instead.")
   f->output_data.x->fontset = -1;
   f->output_data.x->scroll_bar_foreground_pixel = -1;
   f->output_data.x->scroll_bar_background_pixel = -1;
   f->output_data.x->fontset = -1;
   f->output_data.x->scroll_bar_foreground_pixel = -1;
   f->output_data.x->scroll_bar_background_pixel = -1;
+  record_unwind_protect (unwind_create_frame, frame);
 
   f->icon_name
     = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
 
   f->icon_name
     = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
@@ -3630,10 +4158,37 @@ This function is an internal primitive--use `make-frame' instead.")
     f->icon_name = Qnil;
 
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
     f->icon_name = Qnil;
 
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
+#if GLYPH_DEBUG
+  image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
+  dpyinfo_refcount = dpyinfo->reference_count;
+#endif /* GLYPH_DEBUG */
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
 
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
 
+  /* These colors will be set anyway later, but it's important
+     to get the color reference counts right, so initialize them!  */
+  {
+    Lisp_Object black;
+    struct gcpro gcpro1;
+    
+    black = build_string ("black");
+    GCPRO1 (black);
+    f->output_data.x->foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->background_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->border_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->mouse_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    UNGCPRO;
+  }
+
   /* Specify the parent under which to make this X window.  */
 
   if (!NILP (parent))
   /* Specify the parent under which to make this X window.  */
 
   if (!NILP (parent))
@@ -3662,10 +4217,6 @@ This function is an internal primitive--use `make-frame' instead.")
       specbind (Qx_resource_name, name);
     }
 
       specbind (Qx_resource_name, name);
     }
 
-  /* Create fontsets from `global_fontset_alist' before handling fonts.  */
-  for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
-    fs_register_fontset (f, XCAR (tem));
-
   /* Extract the window parameters from the supplied values
      that are needed to determine window geometry.  */
   {
   /* Extract the window parameters from the supplied values
      that are needed to determine window geometry.  */
   {
@@ -3739,7 +4290,7 @@ This function is an internal primitive--use `make-frame' instead.")
   x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
                       "foreground", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
   x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
                       "foreground", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
-                          "background", "Background", RES_TYPE_STRING);
+                      "background", "Background", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
                       "pointerColor", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
   x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
                       "pointerColor", "Foreground", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
@@ -3748,6 +4299,8 @@ This function is an internal primitive--use `make-frame' instead.")
                       "borderColor", "BorderColor", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qscreen_gamma, Qnil,
                       "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
                       "borderColor", "BorderColor", RES_TYPE_STRING);
   x_default_parameter (f, parms, Qscreen_gamma, Qnil,
                       "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
+  x_default_parameter (f, parms, Qline_spacing, Qnil,
+                      "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
 
   x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
                                        "scrollBarForeground",
 
   x_default_scroll_bar_color_parameter (f, parms, Qscroll_bar_foreground,
                                        "scrollBarForeground",
@@ -3766,11 +4319,8 @@ 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, 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);
                       "toolBar", "ToolBar", RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
-                      "scrollBarWidth", "ScrollBarWidth",
-                      RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate",
                       RES_TYPE_SYMBOL);
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate",
                       RES_TYPE_SYMBOL);
@@ -3832,6 +4382,9 @@ This function is an internal primitive--use `make-frame' instead.")
                       "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
   x_default_parameter (f, parms, Qcursor_type, Qbox,
                       "cursorType", "CursorType", RES_TYPE_SYMBOL);
                       "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
   x_default_parameter (f, parms, Qcursor_type, Qbox,
                       "cursorType", "CursorType", RES_TYPE_SYMBOL);
+  x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
+                      "scrollBarWidth", "ScrollBarWidth",
+                      RES_TYPE_NUMBER);
 
   /* Dimensions, especially f->height, must be done via change_frame_size.
      Change will not be effected unless different from the current
 
   /* Dimensions, especially f->height, must be done via change_frame_size.
      Change will not be effected unless different from the current
@@ -3842,7 +4395,11 @@ This function is an internal primitive--use `make-frame' instead.")
   SET_FRAME_WIDTH (f, 0);
   change_frame_size (f, height, width, 1, 0, 0);
 
   SET_FRAME_WIDTH (f, 0);
   change_frame_size (f, height, width, 1, 0, 0);
 
-  /* Set up faces after all frame parameters are known.  */
+  /* Set up faces after all frame parameters are known.  This call
+     also merges in face attributes specified for new frames.  If we
+     don't do this, the `menu' face for instance won't have the right
+     colors, and the menu bar won't appear in the specified colors for
+     new frames.  */
   call1 (Qface_set_after_frame_default, frame);
 
 #ifdef USE_X_TOOLKIT
   call1 (Qface_set_after_frame_default, frame);
 
 #ifdef USE_X_TOOLKIT
@@ -3893,6 +4450,7 @@ This function is an internal primitive--use `make-frame' instead.")
   return unbind_to (count, frame);
 }
 
   return unbind_to (count, frame);
 }
 
+
 /* FRAME is used only to get a handle on the X display.  We don't pass the
    display info directly because we're called from frame.c, which doesn't
    know about that structure.  */
 /* FRAME is used only to get a handle on the X display.  We don't pass the
    display info directly because we're called from frame.c, which doesn't
    know about that structure.  */
@@ -3910,10 +4468,39 @@ x_get_focus_frame (frame)
   return xfocus;
 }
 
   return xfocus;
 }
 
+
+/* In certain situations, when the window manager follows a
+   click-to-focus policy, there seems to be no way around calling
+   XSetInputFocus to give another frame the input focus .
+
+   In an ideal world, XSetInputFocus should generally be avoided so
+   that applications don't interfere with the window manager's focus
+   policy.  But I think it's okay to use when it's clearly done
+   following a user-command.  */
+
+DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
+  "Set the input focus to FRAME.\n\
+FRAME nil means use the selected frame.")
+  (frame)
+     Lisp_Object frame;
+{
+  struct frame *f = check_x_frame (frame);
+  Display *dpy = FRAME_X_DISPLAY (f);
+  int count;
+
+  BLOCK_INPUT;
+  count = x_catch_errors (dpy);
+  XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 RevertToParent, CurrentTime);
+  x_uncatch_errors (dpy, count);
+  UNBLOCK_INPUT;
+  
+  return Qnil;
+}
+
 \f
 \f
-DEFUN ("x-color-defined-p", Fx_color_defined_p, Sx_color_defined_p, 1, 2, 0,
-       "Return non-nil if color COLOR is supported on frame FRAME.\n\
-If FRAME is omitted or nil, use the selected frame.")
+DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
+  "Internal function called by `color-defined-p', which see.")
   (color, frame)
      Lisp_Object color, frame;
 {
   (color, frame)
      Lisp_Object color, frame;
 {
@@ -3922,18 +4509,14 @@ If FRAME is omitted or nil, use the selected frame.")
 
   CHECK_STRING (color, 1);
 
 
   CHECK_STRING (color, 1);
 
-  if (defined_color (f, XSTRING (color)->data, &foo, 0))
+  if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
     return Qt;
   else
     return Qnil;
 }
 
     return Qt;
   else
     return Qnil;
 }
 
-DEFUN ("x-color-values", Fx_color_values, Sx_color_values, 1, 2, 0,
-  "Return a description of the color named COLOR on frame FRAME.\n\
-The value is a list of integer RGB values--(RED GREEN BLUE).\n\
-These values appear to range from 0 to 65280 or 65535, depending\n\
-on the system; white is (65280 65280 65280) or (65535 65535 65535).\n\
-If FRAME is omitted or nil, use the selected frame.")
+DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
+  "Internal function called by `color-values', which see.")
   (color, frame)
      Lisp_Object color, frame;
 {
   (color, frame)
      Lisp_Object color, frame;
 {
@@ -3942,7 +4525,7 @@ If FRAME is omitted or nil, use the selected frame.")
 
   CHECK_STRING (color, 1);
 
 
   CHECK_STRING (color, 1);
 
-  if (defined_color (f, XSTRING (color)->data, &foo, 0))
+  if (x_defined_color (f, XSTRING (color)->data, &foo, 0))
     {
       Lisp_Object rgb[3];
 
     {
       Lisp_Object rgb[3];
 
@@ -3955,11 +4538,8 @@ If FRAME is omitted or nil, use the selected frame.")
     return Qnil;
 }
 
     return Qnil;
 }
 
-DEFUN ("x-display-color-p", Fx_display_color_p, Sx_display_color_p, 0, 1, 0,
-  "Return t if the X display supports color.\n\
-The optional argument DISPLAY specifies which display to ask about.\n\
-DISPLAY should be either a frame or a display name (a string).\n\
-If omitted or nil, that stands for the selected frame's display.")
+DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
+  "Internal function called by `display-color-p', which see.")
   (display)
      Lisp_Object display;
 {
   (display)
      Lisp_Object display;
 {
@@ -4141,1100 +4721,276 @@ If omitted or nil, that stands for the selected frame's display.")
   struct x_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (HeightMMOfScreen (dpyinfo->screen));
   struct x_display_info *dpyinfo = check_x_display_info (display);
 
   return make_number (HeightMMOfScreen (dpyinfo->screen));
-}
-
-DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
-  "Returns the width in millimeters of the X display DISPLAY.\n\
-The optional argument DISPLAY specifies which display to ask about.\n\
-DISPLAY should be either a frame or a display name (a string).\n\
-If omitted or nil, that stands for the selected frame's display.")
-  (display)
-     Lisp_Object display;
-{
-  struct x_display_info *dpyinfo = check_x_display_info (display);
-
-  return make_number (WidthMMOfScreen (dpyinfo->screen));
-}
-
-DEFUN ("x-display-backing-store", Fx_display_backing_store,
-  Sx_display_backing_store, 0, 1, 0,
-  "Returns an indication of whether X display DISPLAY does backing store.\n\
-The value may be `always', `when-mapped', or `not-useful'.\n\
-The optional argument DISPLAY specifies which display to ask about.\n\
-DISPLAY should be either a frame or a display name (a string).\n\
-If omitted or nil, that stands for the selected frame's display.")
-  (display)
-     Lisp_Object display;
-{
-  struct x_display_info *dpyinfo = check_x_display_info (display);
-
-  switch (DoesBackingStore (dpyinfo->screen))
-    {
-    case Always:
-      return intern ("always");
-
-    case WhenMapped:
-      return intern ("when-mapped");
-
-    case NotUseful:
-      return intern ("not-useful");
-
-    default:
-      error ("Strange value for BackingStore parameter of screen");
-    }
-}
-
-DEFUN ("x-display-visual-class", Fx_display_visual_class,
-  Sx_display_visual_class, 0, 1, 0,
-  "Returns the visual class of the X display DISPLAY.\n\
-The value is one of the symbols `static-gray', `gray-scale',\n\
-`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
-The optional argument DISPLAY specifies which display to ask about.\n\
-DISPLAY should be either a frame or a display name (a string).\n\
-If omitted or nil, that stands for the selected frame's display.")
-       (display)
-     Lisp_Object display;
-{
-  struct x_display_info *dpyinfo = check_x_display_info (display);
-
-  switch (dpyinfo->visual->class)
-    {
-    case StaticGray:  return (intern ("static-gray"));
-    case GrayScale:   return (intern ("gray-scale"));
-    case StaticColor: return (intern ("static-color"));
-    case PseudoColor: return (intern ("pseudo-color"));
-    case TrueColor:   return (intern ("true-color"));
-    case DirectColor: return (intern ("direct-color"));
-    default:
-      error ("Display has an unknown visual class");
-    }
-}
-
-DEFUN ("x-display-save-under", Fx_display_save_under,
-  Sx_display_save_under, 0, 1, 0,
-  "Returns t if the X display DISPLAY supports the save-under feature.\n\
-The optional argument DISPLAY specifies which display to ask about.\n\
-DISPLAY should be either a frame or a display name (a string).\n\
-If omitted or nil, that stands for the selected frame's display.")
-  (display)
-     Lisp_Object display;
-{
-  struct x_display_info *dpyinfo = check_x_display_info (display);
-
-  if (DoesSaveUnders (dpyinfo->screen) == True)
-    return Qt;
-  else
-    return Qnil;
-}
-\f
-int
-x_pixel_width (f)
-     register struct frame *f;
-{
-  return PIXEL_WIDTH (f);
-}
-
-int
-x_pixel_height (f)
-     register struct frame *f;
-{
-  return PIXEL_HEIGHT (f);
-}
-
-int
-x_char_width (f)
-     register struct frame *f;
-{
-  return FONT_WIDTH (f->output_data.x->font);
-}
-
-int
-x_char_height (f)
-     register struct frame *f;
-{
-  return f->output_data.x->line_height;
-}
-
-int
-x_screen_planes (f)
-     register struct frame *f;
-{
-  return FRAME_X_DISPLAY_INFO (f)->n_planes;
-}
-\f
-#if 0  /* These no longer seem like the right way to do things.  */
-
-/* Draw a rectangle on the frame with left top corner including
-   the character specified by LEFT_CHAR and TOP_CHAR.  The rectangle is
-   CHARS by LINES wide and long and is the color of the cursor.  */
-
-void
-x_rectangle (f, gc, left_char, top_char, chars, lines)
-     register struct frame *f;
-     GC gc;
-     register int top_char, left_char, chars, lines;
-{
-  int width;
-  int height;
-  int left = (left_char * FONT_WIDTH (f->output_data.x->font)
-                   + f->output_data.x->internal_border_width);
-  int top = (top_char * f->output_data.x->line_height
-                  + f->output_data.x->internal_border_width);
-
-  if (chars < 0)
-    width = FONT_WIDTH (f->output_data.x->font) / 2;
-  else
-    width = FONT_WIDTH (f->output_data.x->font) * chars;
-  if (lines < 0)
-    height = f->output_data.x->line_height / 2;
-  else
-    height = f->output_data.x->line_height * lines;
-
-  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                 gc, left, top, width, height);
-}
-
-DEFUN ("x-draw-rectangle", Fx_draw_rectangle, Sx_draw_rectangle, 5, 5, 0,
-  "Draw a rectangle on FRAME between coordinates specified by\n\
-numbers X0, Y0, X1, Y1 in the cursor pixel.")
-  (frame, X0, Y0, X1, Y1)
-     register Lisp_Object frame, X0, X1, Y0, Y1;
-{
-  register int x0, y0, x1, y1, top, left, n_chars, n_lines;
-
-  CHECK_LIVE_FRAME (frame, 0);
-  CHECK_NUMBER (X0, 0);
-  CHECK_NUMBER (Y0, 1);
-  CHECK_NUMBER (X1, 2);
-  CHECK_NUMBER (Y1, 3);
-
-  x0 = XINT (X0);
-  x1 = XINT (X1);
-  y0 = XINT (Y0);
-  y1 = XINT (Y1);
-
-  if (y1 > y0)
-    {
-      top = y0;
-      n_lines = y1 - y0 + 1;
-    }
-  else
-    {
-      top = y1;
-      n_lines = y0 - y1 + 1;
-    }
-
-  if (x1 > x0)
-    {
-      left = x0;
-      n_chars = x1 - x0 + 1;
-    }
-  else
-    {
-      left = x1;
-      n_chars = x0 - x1 + 1;
-    }
-
-  BLOCK_INPUT;
-  x_rectangle (XFRAME (frame), XFRAME (frame)->output_data.x->cursor_gc,
-              left, top, n_chars, n_lines);
-  UNBLOCK_INPUT;
-
-  return Qt;
-}
-
-DEFUN ("x-erase-rectangle", Fx_erase_rectangle, Sx_erase_rectangle, 5, 5, 0,
-  "Draw a rectangle drawn on FRAME between coordinates\n\
-X0, Y0, X1, Y1 in the regular background-pixel.")
-  (frame, X0, Y0, X1, Y1)
-  register Lisp_Object frame, X0, Y0, X1, Y1;
-{
-  register int x0, y0, x1, y1, top, left, n_chars, n_lines;
-
-  CHECK_LIVE_FRAME (frame, 0);
-  CHECK_NUMBER (X0, 0);
-  CHECK_NUMBER (Y0, 1);
-  CHECK_NUMBER (X1, 2);
-  CHECK_NUMBER (Y1, 3);
-
-  x0 = XINT (X0);
-  x1 = XINT (X1);
-  y0 = XINT (Y0);
-  y1 = XINT (Y1);
-
-  if (y1 > y0)
-    {
-      top = y0;
-      n_lines = y1 - y0 + 1;
-    }
-  else
-    {
-      top = y1;
-      n_lines = y0 - y1 + 1;
-    }
-
-  if (x1 > x0)
-    {
-      left = x0;
-      n_chars = x1 - x0 + 1;
-    }
-  else
-    {
-      left = x1;
-      n_chars = x0 - x1 + 1;
-    }
-
-  BLOCK_INPUT;
-  x_rectangle (XFRAME (frame), XFRAME (frame)->output_data.x->reverse_gc,
-              left, top, n_chars, n_lines);
-  UNBLOCK_INPUT;
-
-  return Qt;
-}
-
-/* Draw lines around the text region beginning at the character position
-   TOP_X, TOP_Y and ending at BOTTOM_X and BOTTOM_Y.  GC specifies the
-   pixel and line characteristics.  */
-
-#define line_len(line) (FRAME_CURRENT_GLYPHS (f)->used[(line)])
-
-static void
-outline_region (f, gc, top_x, top_y, bottom_x, bottom_y)
-     register struct frame *f;
-     GC gc;
-     int  top_x, top_y, bottom_x, bottom_y;
-{
-  register int ibw = f->output_data.x->internal_border_width;
-  register int font_w = FONT_WIDTH (f->output_data.x->font);
-  register int font_h = f->output_data.x->line_height;
-  int y = top_y;
-  int x = line_len (y);
-  XPoint *pixel_points
-    = (XPoint *) alloca (((bottom_y - top_y + 2) * 4) * sizeof (XPoint));
-  register XPoint *this_point = pixel_points;
-
-  /* Do the horizontal top line/lines */
-  if (top_x == 0)
-    {
-      this_point->x = ibw;
-      this_point->y = ibw + (font_h * top_y);
-      this_point++;
-      if (x == 0)
-       this_point->x = ibw + (font_w / 2); /* Half-size for newline chars.  */
-      else
-       this_point->x = ibw + (font_w * x);
-      this_point->y = (this_point - 1)->y;
-    }
-  else
-    {
-      this_point->x = ibw;
-      this_point->y = ibw + (font_h * (top_y + 1));
-      this_point++;
-      this_point->x = ibw + (font_w * top_x);
-      this_point->y = (this_point - 1)->y;
-      this_point++;
-      this_point->x = (this_point - 1)->x;
-      this_point->y = ibw + (font_h * top_y);
-      this_point++;
-      this_point->x = ibw + (font_w * x);
-      this_point->y = (this_point - 1)->y;
-    }
-
-  /* Now do the right side.  */
-  while (y < bottom_y)
-    {                          /* Right vertical edge */
-      this_point++;
-      this_point->x = (this_point - 1)->x;
-      this_point->y = ibw + (font_h * (y + 1));
-      this_point++;
-
-      y++;                     /* Horizontal connection to next line */
-      x = line_len (y);
-      if (x == 0)
-       this_point->x = ibw + (font_w / 2);
-      else
-       this_point->x = ibw + (font_w * x);
-
-      this_point->y = (this_point - 1)->y;
-    }
-
-  /* Now do the bottom and connect to the top left point.  */
-  this_point->x = ibw + (font_w * (bottom_x + 1));
-
-  this_point++;
-  this_point->x = (this_point - 1)->x;
-  this_point->y = ibw + (font_h * (bottom_y + 1));
-  this_point++;
-  this_point->x = ibw;
-  this_point->y = (this_point - 1)->y;
-  this_point++;
-  this_point->x = pixel_points->x;
-  this_point->y = pixel_points->y;
-
-  XDrawLines (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-             gc, pixel_points,
-             (this_point - pixel_points + 1), CoordModeOrigin);
-}
-
-DEFUN ("x-contour-region", Fx_contour_region, Sx_contour_region, 1, 1, 0,
-  "Highlight the region between point and the character under the mouse\n\
-selected frame.")
-  (event)
-     register Lisp_Object event;
-{
-  register int x0, y0, x1, y1;
-  register struct frame *f = selected_frame;
-  struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-  register int p1, p2;
-
-  CHECK_CONS (event, 0);
-
-  BLOCK_INPUT;
-  x0 = XINT (Fcar (Fcar (event)));
-  y0 = XINT (Fcar (Fcdr (Fcar (event))));
-
-  /* If the mouse is past the end of the line, don't that area.  */
-  /* ReWrite this...  */
-
-  /* Where the cursor is.  */
-  x1 = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x);
-  y1 = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y);
-
-  if (y1 > y0)                 /* point below mouse */
-    outline_region (f, f->output_data.x->cursor_gc,
-                   x0, y0, x1, y1);
-  else if (y1 < y0)            /* point above mouse */
-    outline_region (f, f->output_data.x->cursor_gc,
-                   x1, y1, x0, y0);
-  else                         /* same line: draw horizontal rectangle */
-    {
-      if (x1 > x0)
-       x_rectangle (f, f->output_data.x->cursor_gc,
-                    x0, y0, (x1 - x0 + 1), 1);
-      else if (x1 < x0)
-         x_rectangle (f, f->output_data.x->cursor_gc,
-                      x1, y1, (x0 - x1 + 1), 1);
-    }
-
-  XFlush (FRAME_X_DISPLAY (f));
-  UNBLOCK_INPUT;
-
-  return Qnil;
-}
-
-DEFUN ("x-uncontour-region", Fx_uncontour_region, Sx_uncontour_region, 1, 1, 0,
-  "Erase any highlighting of the region between point and the character\n\
-at X, Y on the selected frame.")
-  (event)
-     register Lisp_Object event;
-{
-  register int x0, y0, x1, y1;
-  register struct frame *f = selected_frame;
-  struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
-
-  BLOCK_INPUT;
-  x0 = XINT (Fcar (Fcar (event)));
-  y0 = XINT (Fcar (Fcdr (Fcar (event))));
-  x1 = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x);
-  y1 = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y);
-
-  if (y1 > y0)                 /* point below mouse */
-    outline_region (f, f->output_data.x->reverse_gc,
-                     x0, y0, x1, y1);
-  else if (y1 < y0)            /* point above mouse */
-    outline_region (f, f->output_data.x->reverse_gc,
-                     x1, y1, x0, y0);
-  else                         /* same line: draw horizontal rectangle */
-    {
-      if (x1 > x0)
-       x_rectangle (f, f->output_data.x->reverse_gc,
-                    x0, y0, (x1 - x0 + 1), 1);
-      else if (x1 < x0)
-       x_rectangle (f, f->output_data.x->reverse_gc,
-                    x1, y1, (x0 - x1 + 1), 1);
-    }
-  UNBLOCK_INPUT;
-
-  return Qnil;
-}
-
-#if 0
-int contour_begin_x, contour_begin_y;
-int contour_end_x, contour_end_y;
-int contour_npoints;
-
-/* Clip the top part of the contour lines down (and including) line Y_POS.
-   If X_POS is in the middle (rather than at the end) of the line, drop
-   down a line at that character.  */
-
-static void
-clip_contour_top (y_pos, x_pos)
-{
-  register XPoint *begin = contour_lines[y_pos].top_left;
-  register XPoint *end;
-  register int npoints;
-  register struct display_line *line = selected_frame->phys_lines[y_pos + 1];
-
-  if (x_pos >= line->len - 1)  /* Draw one, straight horizontal line.  */
-    {
-      end = contour_lines[y_pos].top_right;
-      npoints = (end - begin + 1);
-      XDrawLines (x_current_display, contour_window,
-                 contour_erase_gc, begin_erase, npoints, CoordModeOrigin);
-
-      bcopy (end, begin + 1, contour_last_point - end + 1);
-      contour_last_point -= (npoints - 2);
-      XDrawLines (x_current_display, contour_window,
-                 contour_erase_gc, begin, 2, CoordModeOrigin);
-      XFlush (x_current_display);
-
-      /* Now, update contour_lines structure.  */
-    }
-                               /* ______.         */
-  else                         /*       |________*/
-    {
-      register XPoint *p = begin + 1;
-      end = contour_lines[y_pos].bottom_right;
-      npoints = (end - begin + 1);
-      XDrawLines (x_current_display, contour_window,
-                 contour_erase_gc, begin_erase, npoints, CoordModeOrigin);
-
-      p->y = begin->y;
-      p->x = ibw + (font_w * (x_pos + 1));
-      p++;
-      p->y = begin->y + font_h;
-      p->x = (p - 1)->x;
-      bcopy (end, begin + 3, contour_last_point - end + 1);
-      contour_last_point -= (npoints - 5);
-      XDrawLines (x_current_display, contour_window,
-                 contour_erase_gc, begin, 4, CoordModeOrigin);
-      XFlush (x_current_display);
-
-      /* Now, update contour_lines structure.  */
-    }
-}
-
-/* Erase the top horizontal lines of the contour, and then extend
-   the contour upwards.  */
-
-static void
-extend_contour_top (line)
-{
-}
-
-static void
-clip_contour_bottom (x_pos, y_pos)
-     int x_pos, y_pos;
-{
-}
-
-static void
-extend_contour_bottom (x_pos, y_pos)
-{
-}
-
-DEFUN ("x-select-region", Fx_select_region, Sx_select_region, 1, 1, "e",
-  "")
-  (event)
-     Lisp_Object event;
-{
- register struct frame *f = selected_frame;
- struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
- register int point_x = WINDOW_TO_FRAME_PIXEL_X (w, w->cursor.x);
- register int point_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->cursor.y);
- register int mouse_below_point;
- register Lisp_Object obj;
- register int x_contour_x, x_contour_y;
-
- x_contour_x = x_mouse_x;
- x_contour_y = x_mouse_y;
- if (x_contour_y > point_y || (x_contour_y == point_y
-                              && x_contour_x > point_x))
-   {
-     mouse_below_point = 1;
-     outline_region (f, f->output_data.x->cursor_gc, point_x, point_y,
-                    x_contour_x, x_contour_y);
-   }
- else
-   {
-     mouse_below_point = 0;
-     outline_region (f, f->output_data.x->cursor_gc, x_contour_x, x_contour_y,
-                    point_x, point_y);
-   }
-
- while (1)
-   {
-     obj = read_char (-1, 0, 0, Qnil, 0);
-     if (!CONSP (obj))
-       break;
-
-     if (mouse_below_point)
-       {
-        if (x_mouse_y <= point_y)                /* Flipped.  */
-          {
-            mouse_below_point = 0;
-
-            outline_region (f, f->output_data.x->reverse_gc, point_x, point_y,
-                            x_contour_x, x_contour_y);
-            outline_region (f, f->output_data.x->cursor_gc, x_mouse_x, x_mouse_y,
-                            point_x, point_y);
-          }
-        else if (x_mouse_y < x_contour_y)        /* Bottom clipped.  */
-          {
-            clip_contour_bottom (x_mouse_y);
-          }
-        else if (x_mouse_y > x_contour_y)        /* Bottom extended.  */
-          {
-            extend_bottom_contour (x_mouse_y);
-          }
-
-        x_contour_x = x_mouse_x;
-        x_contour_y = x_mouse_y;
-       }
-     else  /* mouse above or same line as point */
-       {
-        if (x_mouse_y >= point_y)                /* Flipped.  */
-          {
-            mouse_below_point = 1;
-
-            outline_region (f, f->output_data.x->reverse_gc,
-                            x_contour_x, x_contour_y, point_x, point_y);
-            outline_region (f, f->output_data.x->cursor_gc, point_x, point_y,
-                            x_mouse_x, x_mouse_y);
-          }
-        else if (x_mouse_y > x_contour_y)        /* Top clipped.  */
-          {
-            clip_contour_top (x_mouse_y);
-          }
-        else if (x_mouse_y < x_contour_y)        /* Top extended.  */
-          {
-            extend_contour_top (x_mouse_y);
-          }
-       }
-   }
-
- unread_command_event = obj;
- if (mouse_below_point)
-   {
-     contour_begin_x = point_x;
-     contour_begin_y = point_y;
-     contour_end_x = x_contour_x;
-     contour_end_y = x_contour_y;
-   }
- else
-   {
-     contour_begin_x = x_contour_x;
-     contour_begin_y = x_contour_y;
-     contour_end_x = point_x;
-     contour_end_y = point_y;
-   }
-}
-#endif
-
-DEFUN ("x-horizontal-line", Fx_horizontal_line, Sx_horizontal_line, 1, 1, "e",
-  "")
-  (event)
-     Lisp_Object event;
-{
-  register Lisp_Object obj;
-  struct frame *f = selected_frame;
-  register struct window *w = XWINDOW (selected_window);
-  register GC line_gc = f->output_data.x->cursor_gc;
-  register GC erase_gc = f->output_data.x->reverse_gc;
-#if 0
-  char dash_list[] = {6, 4, 6, 4};
-  int dashes = 4;
-  XGCValues gc_values;
-#endif
-  register int previous_y;
-  register int line = (x_mouse_y + 1) * f->output_data.x->line_height
-    + f->output_data.x->internal_border_width;
-  register int left = f->output_data.x->internal_border_width
-    + (WINDOW_LEFT_MARGIN (w)
-       * FONT_WIDTH (f->output_data.x->font));
-  register int right = left + (w->width
-                              * FONT_WIDTH (f->output_data.x->font))
-    - f->output_data.x->internal_border_width;
-
-#if 0
-  BLOCK_INPUT;
-  gc_values.foreground = f->output_data.x->cursor_pixel;
-  gc_values.background = f->output_data.x->background_pixel;
-  gc_values.line_width = 1;
-  gc_values.line_style = LineOnOffDash;
-  gc_values.cap_style = CapRound;
-  gc_values.join_style = JoinRound;
-
-  line_gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                      GCLineStyle | GCJoinStyle | GCCapStyle
-                      | GCLineWidth | GCForeground | GCBackground,
-                      &gc_values);
-  XSetDashes (FRAME_X_DISPLAY (f), line_gc, 0, dash_list, dashes);
-  gc_values.foreground = f->output_data.x->background_pixel;
-  gc_values.background = f->output_data.x->foreground_pixel;
-  erase_gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                      GCLineStyle | GCJoinStyle | GCCapStyle
-                      | GCLineWidth | GCForeground | GCBackground,
-                      &gc_values);
-  XSetDashes (FRAME_X_DISPLAY (f), erase_gc, 0, dash_list, dashes);
-  UNBLOCK_INPUT;
-#endif
-
-  while (1)
-    {
-      BLOCK_INPUT;
-      if (x_mouse_y >= XINT (w->top)
-         && x_mouse_y < XINT (w->top) + XINT (w->height) - 1)
-       {
-         previous_y = x_mouse_y;
-         line = (x_mouse_y + 1) * f->output_data.x->line_height
-           + f->output_data.x->internal_border_width;
-         XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    line_gc, left, line, right, line);
-       }
-      XFlush (FRAME_X_DISPLAY (f));
-      UNBLOCK_INPUT;
-
-      do
-       {
-         obj = read_char (-1, 0, 0, Qnil, 0);
-         if (!CONSP (obj)
-             || (! EQ (Fcar (Fcdr (Fcdr (obj))),
-                       Qvertical_scroll_bar))
-             || x_mouse_grabbed)
-           {
-             BLOCK_INPUT;
-             XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                        erase_gc, left, line, right, line);
-             unread_command_event = obj;
-#if 0
-             XFreeGC (FRAME_X_DISPLAY (f), line_gc);
-             XFreeGC (FRAME_X_DISPLAY (f), erase_gc);
-#endif 
-             UNBLOCK_INPUT;
-             return Qnil;
-           }
-       }
-      while (x_mouse_y == previous_y);
-
-      BLOCK_INPUT;
-      XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                erase_gc, left, line, right, line);
-      UNBLOCK_INPUT;
-    }
-}
-#endif
-\f
-#if 0
-/* These keep track of the rectangle following the pointer.  */
-int mouse_track_top, mouse_track_left, mouse_track_width;
-
-/* Offset in buffer of character under the pointer, or 0.  */
-int mouse_buffer_offset;
-
-DEFUN ("x-track-pointer", Fx_track_pointer, Sx_track_pointer, 0, 0, 0,
-  "Track the pointer.")
-  ()
-{
-  static Cursor current_pointer_shape;
-  FRAME_PTR f = x_mouse_frame;
-
-  BLOCK_INPUT;
-  if (EQ (Vmouse_frame_part, Qtext_part)
-      && (current_pointer_shape != f->output_data.x->nontext_cursor))
-    {
-      unsigned char c;
-      struct buffer *buf;
-
-      current_pointer_shape = f->output_data.x->nontext_cursor;
-      XDefineCursor (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    current_pointer_shape);
-
-      buf = XBUFFER (XWINDOW (Vmouse_window)->buffer);
-      c = *(BUF_CHAR_ADDRESS (buf, mouse_buffer_offset));
-    }
-  else if (EQ (Vmouse_frame_part, Qmodeline_part)
-          && (current_pointer_shape != f->output_data.x->modeline_cursor))
-    {
-      current_pointer_shape = f->output_data.x->modeline_cursor;
-      XDefineCursor (FRAME_X_DISPLAY (f),
-                    FRAME_X_WINDOW (f),
-                    current_pointer_shape);
-    }
-
-  XFlush (FRAME_X_DISPLAY (f));
-  UNBLOCK_INPUT;
-}
-#endif
-
-#if 0
-DEFUN ("x-track-pointer", Fx_track_pointer, Sx_track_pointer, 1, 1, "e",
-  "Draw rectangle around character under mouse pointer, if there is one.")
-  (event)
-     Lisp_Object event;
-{
-  struct window *w = XWINDOW (Vmouse_window);
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-  struct buffer *b = XBUFFER (w->buffer);
-  Lisp_Object obj;
-
-  if (! EQ (Vmouse_window, selected_window))
-      return Qnil;
-
-  if (EQ (event, Qnil))
-    {
-      int x, y;
-
-      x_read_mouse_position (selected_frame, &x, &y);
-    }
-
-  BLOCK_INPUT;
-  mouse_track_width = 0;
-  mouse_track_left = mouse_track_top = -1;
-
-  do
-    {
-      if ((x_mouse_x != mouse_track_left
-          && (x_mouse_x < mouse_track_left
-              || x_mouse_x > (mouse_track_left + mouse_track_width)))
-         || x_mouse_y != mouse_track_top)
-       {
-         int hp = 0;           /* Horizontal position */
-         int len = FRAME_CURRENT_GLYPHS (f)->used[x_mouse_y];
-         int p = FRAME_CURRENT_GLYPHS (f)->bufp[x_mouse_y];
-         int tab_width = XINT (b->tab_width);
-         int ctl_arrow_p = !NILP (b->ctl_arrow);
-         unsigned char c;
-         int mode_line_vpos = XFASTINT (w->height) + XFASTINT (w->top) - 1;
-         int in_mode_line = 0;
-
-         if (! FRAME_CURRENT_GLYPHS (f)->enable[x_mouse_y])
-           break;
-
-         /* Erase previous rectangle.  */
-         if (mouse_track_width)
-           {
-             x_rectangle (f, f->output_data.x->reverse_gc,
-                          mouse_track_left, mouse_track_top,
-                          mouse_track_width, 1);
-
-             if ((mouse_track_left == f->phys_cursor_x
-                  || mouse_track_left == f->phys_cursor_x - 1)
-                 && mouse_track_top == f->phys_cursor_y)
-               {
-                 x_display_cursor (f, 1);
-               }
-           }
-
-         mouse_track_left = x_mouse_x;
-         mouse_track_top = x_mouse_y;
-         mouse_track_width = 0;
-
-         if (mouse_track_left > len) /* Past the end of line.  */
-           goto draw_or_not;
-
-         if (mouse_track_top == mode_line_vpos)
-           {
-             in_mode_line = 1;
-             goto draw_or_not;
-           }
+}
 
 
-         if (tab_width <= 0 || tab_width > 20) tab_width = 8;
-         do
-           {
-             c = FETCH_BYTE (p);
-             if (len == f->width && hp == len - 1 && c != '\n')
-               goto draw_or_not;
+DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
+  "Returns the width in millimeters of the X display DISPLAY.\n\
+The optional argument DISPLAY specifies which display to ask about.\n\
+DISPLAY should be either a frame or a display name (a string).\n\
+If omitted or nil, that stands for the selected frame's display.")
+  (display)
+     Lisp_Object display;
+{
+  struct x_display_info *dpyinfo = check_x_display_info (display);
 
 
-             switch (c)
-               {
-               case '\t':
-                 mouse_track_width = tab_width - (hp % tab_width);
-                 p++;
-                 hp += mouse_track_width;
-                 if (hp > x_mouse_x)
-                   {
-                     mouse_track_left = hp - mouse_track_width;
-                     goto draw_or_not;
-                   }
-                 continue;
+  return make_number (WidthMMOfScreen (dpyinfo->screen));
+}
 
 
-               case '\n':
-                 mouse_track_width = -1;
-                 goto draw_or_not;
+DEFUN ("x-display-backing-store", Fx_display_backing_store,
+  Sx_display_backing_store, 0, 1, 0,
+  "Returns an indication of whether X display DISPLAY does backing store.\n\
+The value may be `always', `when-mapped', or `not-useful'.\n\
+The optional argument DISPLAY specifies which display to ask about.\n\
+DISPLAY should be either a frame or a display name (a string).\n\
+If omitted or nil, that stands for the selected frame's display.")
+  (display)
+     Lisp_Object display;
+{
+  struct x_display_info *dpyinfo = check_x_display_info (display);
+  Lisp_Object result;
 
 
-               default:
-                 if (ctl_arrow_p && (c < 040 || c == 0177))
-                   {
-                     if (p > ZV)
-                       goto draw_or_not;
-
-                     mouse_track_width = 2;
-                     p++;
-                     hp +=2;
-                     if (hp > x_mouse_x)
-                       {
-                         mouse_track_left = hp - mouse_track_width;
-                         goto draw_or_not;
-                       }
-                   }
-                 else
-                   {
-                     mouse_track_width = 1;
-                     p++;
-                     hp++;
-                   }
-                 continue;
-               }
-           }
-         while (hp <= x_mouse_x);
+  switch (DoesBackingStore (dpyinfo->screen))
+    {
+    case Always:
+      result = intern ("always");
+      break;
 
 
-       draw_or_not:
-         if (mouse_track_width) /* Over text; use text pointer shape.  */
-           {
-             XDefineCursor (FRAME_X_DISPLAY (f),
-                            FRAME_X_WINDOW (f),
-                            f->output_data.x->text_cursor);
-             x_rectangle (f, f->output_data.x->cursor_gc,
-                          mouse_track_left, mouse_track_top,
-                          mouse_track_width, 1);
-           }
-         else if (in_mode_line)
-           XDefineCursor (FRAME_X_DISPLAY (f),
-                          FRAME_X_WINDOW (f),
-                          f->output_data.x->modeline_cursor);
-         else
-           XDefineCursor (FRAME_X_DISPLAY (f),
-                          FRAME_X_WINDOW (f),
-                          f->output_data.x->nontext_cursor);
-       }
+    case WhenMapped:
+      result = intern ("when-mapped");
+      break;
 
 
-      XFlush (FRAME_X_DISPLAY (f));
-      UNBLOCK_INPUT;
+    case NotUseful:
+      result = intern ("not-useful");
+      break;
 
 
-      obj = read_char (-1, 0, 0, Qnil, 0);
-      BLOCK_INPUT;
+    default:
+      error ("Strange value for BackingStore parameter of screen");
+      result = Qnil;
     }
     }
-  while (CONSP (obj)              /* Mouse event */
-        && EQ (Fcar (Fcdr (Fcdr (obj))), Qnil)    /* Not scroll bar */
-        && EQ (Vmouse_depressed, Qnil)              /* Only motion events */
-        && EQ (Vmouse_window, selected_window)    /* In this window */
-        && x_mouse_frame);
 
 
-  unread_command_event = obj;
+  return result;
+}
+
+DEFUN ("x-display-visual-class", Fx_display_visual_class,
+  Sx_display_visual_class, 0, 1, 0,
+  "Returns the visual class of the X display DISPLAY.\n\
+The value is one of the symbols `static-gray', `gray-scale',\n\
+`static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
+The optional argument DISPLAY specifies which display to ask about.\n\
+DISPLAY should be either a frame or a display name (a string).\n\
+If omitted or nil, that stands for the selected frame's display.")
+       (display)
+     Lisp_Object display;
+{
+  struct x_display_info *dpyinfo = check_x_display_info (display);
+  Lisp_Object result;
 
 
-  if (mouse_track_width)
+  switch (dpyinfo->visual->class)
     {
     {
-      x_rectangle (f, f->output_data.x->reverse_gc,
-                  mouse_track_left, mouse_track_top,
-                  mouse_track_width, 1);
-      mouse_track_width = 0;
-      if ((mouse_track_left == f->phys_cursor_x
-          || mouse_track_left - 1 == f->phys_cursor_x)
-         && mouse_track_top == f->phys_cursor_y)
-       {
-         x_display_cursor (f, 1);
-       }
+    case StaticGray:
+      result = intern ("static-gray");
+      break;
+    case GrayScale:
+      result = intern ("gray-scale");
+      break;
+    case StaticColor:
+      result = intern ("static-color");
+      break;
+    case PseudoColor:
+      result = intern ("pseudo-color");
+      break;
+    case TrueColor:
+      result = intern ("true-color");
+      break;
+    case DirectColor:
+      result = intern ("direct-color");
+      break;
+    default:
+      error ("Display has an unknown visual class");
+      result = Qnil;
     }
     }
-  XDefineCursor (FRAME_X_DISPLAY (f),
-                FRAME_X_WINDOW (f),
-                f->output_data.x->nontext_cursor);
-  XFlush (FRAME_X_DISPLAY (f));
-  UNBLOCK_INPUT;
+  
+  return result;
+}
 
 
-  return Qnil;
+DEFUN ("x-display-save-under", Fx_display_save_under,
+  Sx_display_save_under, 0, 1, 0,
+  "Returns t if the X display DISPLAY supports the save-under feature.\n\
+The optional argument DISPLAY specifies which display to ask about.\n\
+DISPLAY should be either a frame or a display name (a string).\n\
+If omitted or nil, that stands for the selected frame's display.")
+  (display)
+     Lisp_Object display;
+{
+  struct x_display_info *dpyinfo = check_x_display_info (display);
+
+  if (DoesSaveUnders (dpyinfo->screen) == True)
+    return Qt;
+  else
+    return Qnil;
 }
 }
-#endif
 \f
 \f
-#if 0
-#include "glyphs.h"
-
-/* Draw a pixmap specified by IMAGE_DATA of dimensions WIDTH and HEIGHT
-   on the frame F at position X, Y.  */
+int
+x_pixel_width (f)
+     register struct frame *f;
+{
+  return PIXEL_WIDTH (f);
+}
 
 
-x_draw_pixmap (f, x, y, image_data, width, height)
-     struct frame *f;
-     int x, y, width, height;
-     char *image_data;
+int
+x_pixel_height (f)
+     register struct frame *f;
 {
 {
-  Pixmap image;
+  return PIXEL_HEIGHT (f);
+}
 
 
-  image = XCreateBitmapFromData (FRAME_X_DISPLAY (f),
-                                FRAME_X_WINDOW (f), image_data,
-                                width, height);
-  XCopyPlane (FRAME_X_DISPLAY (f), image, FRAME_X_WINDOW (f),
-             f->output_data.x->normal_gc, 0, 0, width, height, x, y);
+int
+x_char_width (f)
+     register struct frame *f;
+{
+  return FONT_WIDTH (f->output_data.x->font);
 }
 }
-#endif
-\f
-#if 0 /* I'm told these functions are superfluous
-        given the ability to bind function keys.  */
-
-#ifdef HAVE_X11
-DEFUN ("x-rebind-key", Fx_rebind_key, Sx_rebind_key, 3, 3, 0,
-"Rebind X keysym KEYSYM, with MODIFIERS, to generate NEWSTRING.\n\
-KEYSYM is a string which conforms to the X keysym definitions found\n\
-in X11/keysymdef.h, sans the initial XK_. MODIFIERS is nil or a\n\
-list of strings specifying modifier keys such as Control_L, which must\n\
-also be depressed for NEWSTRING to appear.")
-  (x_keysym, modifiers, newstring)
-     register Lisp_Object x_keysym;
-     register Lisp_Object modifiers;
-     register Lisp_Object newstring;
-{
-  char *rawstring;
-  register KeySym keysym;
-  KeySym modifier_list[16];
 
 
-  check_x ();
-  CHECK_STRING (x_keysym, 1);
-  CHECK_STRING (newstring, 3);
+int
+x_char_height (f)
+     register struct frame *f;
+{
+  return f->output_data.x->line_height;
+}
 
 
-  keysym = XStringToKeysym ((char *) XSTRING (x_keysym)->data);
-  if (keysym == NoSymbol)
-    error ("Keysym does not exist");
+int
+x_screen_planes (f)
+     register struct frame *f;
+{
+  return FRAME_X_DISPLAY_INFO (f)->n_planes;
+}
 
 
-  if (NILP (modifiers))
-    XRebindKeysym (x_current_display, keysym, modifier_list, 0,
-                  XSTRING (newstring)->data,
-                  STRING_BYTES (XSTRING (newstring)));
-  else
-    {
-      register Lisp_Object rest, mod;
-      register int i = 0;
 
 
-      for (rest = modifiers; !NILP (rest); rest = Fcdr (rest))
-       {
-         if (i == 16)
-           error ("Can't have more than 16 modifiers");
-
-         mod = Fcar (rest);
-         CHECK_STRING (mod, 3);
-         modifier_list[i] = XStringToKeysym ((char *) XSTRING (mod)->data);
-#ifndef HAVE_X11R5
-         if (modifier_list[i] == NoSymbol
-             || !(IsModifierKey (modifier_list[i]) 
-                   || ((unsigned)(modifier_list[i]) == XK_Mode_switch)
-                   || ((unsigned)(modifier_list[i]) == XK_Num_Lock)))
-#else
-         if (modifier_list[i] == NoSymbol
-             || !IsModifierKey (modifier_list[i]))
-#endif
-           error ("Element is not a modifier keysym");
-         i++;
-       }
+\f
+/************************************************************************
+                             X Displays
+ ************************************************************************/
 
 
-      XRebindKeysym (x_current_display, keysym, modifier_list, i,
-                    XSTRING (newstring)->data,
-                    STRING_BYTES (XSTRING (newstring)));
-    }
+\f
+/* Mapping visual names to visuals.  */
 
 
-  return Qnil;
+static struct visual_class
+{
+  char *name;
+  int class;
 }
 }
-  
-DEFUN ("x-rebind-keys", Fx_rebind_keys, Sx_rebind_keys, 2, 2, 0,
-  "Rebind KEYCODE to list of strings STRINGS.\n\
-STRINGS should be a list of 16 elements, one for each shift combination.\n\
-nil as element means don't change.\n\
-See the documentation of `x-rebind-key' for more information.")
-  (keycode, strings)
-     register Lisp_Object keycode;
-     register Lisp_Object strings;
-{
-  register Lisp_Object item;
-  register unsigned char *rawstring;
-  KeySym rawkey, modifier[1];
-  int strsize;
-  register unsigned i;
+visual_classes[] =
+{
+  {"StaticGray",       StaticGray},
+  {"GrayScale",                GrayScale},
+  {"StaticColor",      StaticColor},
+  {"PseudoColor",      PseudoColor},
+  {"TrueColor",                TrueColor},
+  {"DirectColor",      DirectColor},
+  NULL
+};
+
 
 
-  check_x ();
-  CHECK_NUMBER (keycode, 1);
-  CHECK_CONS (strings, 2);
-  rawkey = (KeySym) ((unsigned) (XINT (keycode))) & 255;
-  for (i = 0; i <= 15; strings = Fcdr (strings), i++)
-    {
-      item = Fcar (strings);
-      if (!NILP (item))
-       {
-         CHECK_STRING (item, 2);
-         strsize = STRING_BYTES (XSTRING (item));
-         rawstring = (unsigned char *) xmalloc (strsize);
-         bcopy (XSTRING (item)->data, rawstring, strsize);
-         modifier[1] = 1 << i;
-         XRebindKeysym (x_current_display, rawkey, modifier, 1,
-                        rawstring, strsize);
-       }
-    }
-  return Qnil;
-}
-#endif /* HAVE_X11 */
-#endif /* 0 */
-\f
 #ifndef HAVE_XSCREENNUMBEROFSCREEN
 #ifndef HAVE_XSCREENNUMBEROFSCREEN
+
+/* Value is the screen number of screen SCR.  This is a substitute for
+   the X function with the same name when that doesn't exist.  */
+
 int
 XScreenNumberOfScreen (scr)
     register Screen *scr;
 {
 int
 XScreenNumberOfScreen (scr)
     register Screen *scr;
 {
-  register Display *dpy;
-  register Screen *dpyscr;
-  register int i;
-
-  dpy = scr->display;
-  dpyscr = dpy->screens;
+  Display *dpy = scr->display;
+  int i;
 
 
-  for (i = 0; i < dpy->nscreens; i++, dpyscr++)
-    if (scr == dpyscr)
-      return i;
+  for (i = 0; i < dpy->nscreens; ++i)
+    if (scr == dpy->screens[i])
+      break;
 
 
-  return -1;
+  return i;
 }
 }
-#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
 
 
-Visual *
-select_visual (dpy, screen, depth)
-     Display *dpy;
-     Screen *screen;
-     unsigned int *depth;
-{
-  Visual *v;
-  XVisualInfo *vinfo, vinfo_template;
-  int n_visuals;
-
-  v = DefaultVisualOfScreen (screen);
+#endif /* not HAVE_XSCREENNUMBEROFSCREEN */
 
 
-#ifdef HAVE_X11R4
-  vinfo_template.visualid = XVisualIDFromVisual (v);
-#else
-  vinfo_template.visualid = v->visualid;
-#endif
 
 
-  vinfo_template.screen = XScreenNumberOfScreen (screen);
+/* Select the visual that should be used on display DPYINFO.  Set
+   members of DPYINFO appropriately.  Called from x_term_init.  */
 
 
-  vinfo = XGetVisualInfo (dpy,
-                         VisualIDMask | VisualScreenMask, &vinfo_template,
-                         &n_visuals);
-  if (n_visuals != 1)
-    fatal ("Can't get proper X visual info");
+void
+select_visual (dpyinfo)
+     struct x_display_info *dpyinfo;
+{
+  Display *dpy = dpyinfo->display;
+  Screen *screen = dpyinfo->screen;
+  Lisp_Object value;
 
 
-  if ((1 << vinfo->depth) == vinfo->colormap_size)
-    *depth = vinfo->depth;
-  else
+  /* See if a visual is specified.  */
+  value = display_x_get_resource (dpyinfo,
+                                 build_string ("visualClass"),
+                                 build_string ("VisualClass"),
+                                 Qnil, Qnil);
+  if (STRINGP (value))
     {
     {
-      int i = 0;
-      int n = vinfo->colormap_size - 1;
-      while (n)
+      /* VALUE should be of the form CLASS-DEPTH, where CLASS is one
+        of `PseudoColor', `TrueColor' etc. and DEPTH is the color
+        depth, a decimal number.  NAME is compared with case ignored.  */
+      char *s = (char *) alloca (STRING_BYTES (XSTRING (value)) + 1);
+      char *dash;
+      int i, class = -1;
+      XVisualInfo vinfo;
+
+      strcpy (s, XSTRING (value)->data);
+      dash = index (s, '-');
+      if (dash)
        {
        {
-         n = n >> 1;
-         i++;
+         dpyinfo->n_planes = atoi (dash + 1);
+         *dash = '\0';
        }
        }
-      *depth = i;
+      else
+       /* We won't find a matching visual with depth 0, so that
+          an error will be printed below.  */
+       dpyinfo->n_planes = 0;
+
+      /* Determine the visual class.  */
+      for (i = 0; visual_classes[i].name; ++i)
+       if (xstricmp (s, visual_classes[i].name) == 0)
+         {
+           class = visual_classes[i].class;
+           break;
+         }
+
+      /* Look up a matching visual for the specified class.  */
+      if (class == -1
+         || !XMatchVisualInfo (dpy, XScreenNumberOfScreen (screen),
+                               dpyinfo->n_planes, class, &vinfo))
+       fatal ("Invalid visual specification `%s'", XSTRING (value)->data);
+      
+      dpyinfo->visual = vinfo.visual;
     }
     }
+  else
+    {
+      int n_visuals;
+      XVisualInfo *vinfo, vinfo_template;
+      
+      dpyinfo->visual = DefaultVisualOfScreen (screen);
+
+#ifdef HAVE_X11R4
+      vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
+#else
+      vinfo_template.visualid = dpyinfo->visual->visualid;
+#endif
+      vinfo_template.screen = XScreenNumberOfScreen (screen);
+      vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
+                             &vinfo_template, &n_visuals);
+      if (n_visuals != 1)
+       fatal ("Can't get proper X visual info");
 
 
-  XFree ((char *) vinfo);
-  return v;
+      dpyinfo->n_planes = vinfo->depth;
+      XFree ((char *) vinfo);
+    }
 }
 
 }
 
+
 /* Return the X display structure for the display named NAME.
    Open a new connection if necessary.  */
 
 /* Return the X display structure for the display named NAME.
    Open a new connection if necessary.  */
 
@@ -5277,6 +5033,7 @@ x_display_info_for_name (name)
   return dpyinfo;
 }
 
   return dpyinfo;
 }
 
+
 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
        1, 3, 0, "Open a connection to an X server.\n\
 DISPLAY is the name of the display to connect to.\n\
 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
        1, 3, 0, "Open a connection to an X server.\n\
 DISPLAY is the name of the display to connect to.\n\
@@ -5345,9 +5102,9 @@ If DISPLAY is nil, that stands for the selected frame's display.")
   for (i = 0; i < dpyinfo->n_fonts; i++)
     if (dpyinfo->font_table[i].name)
       {
   for (i = 0; i < dpyinfo->n_fonts; i++)
     if (dpyinfo->font_table[i].name)
       {
+       if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
+         xfree (dpyinfo->font_table[i].full_name);
        xfree (dpyinfo->font_table[i].name);
        xfree (dpyinfo->font_table[i].name);
-       /* Don't free the full_name string;
-          it is always shared with something else.  */
        XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
       }
 
        XFreeFont (dpyinfo->display, dpyinfo->font_table[i].font);
       }
 
@@ -5423,10 +5180,6 @@ x_sync (f)
 
 static struct image_type *image_types;
 
 
 static struct image_type *image_types;
 
-/* A list of symbols, one for each supported image type.  */
-
-Lisp_Object Vimage_types;
-
 /* The symbol `image' which is the car of the lists used to represent
    images in Lisp.  */
 
 /* The symbol `image' which is the car of the lists used to represent
    images in Lisp.  */
 
@@ -5438,14 +5191,15 @@ Lisp_Object Qxbm;
 
 /* Keywords.  */
 
 
 /* Keywords.  */
 
-Lisp_Object QCtype, QCdata, QCascent, QCmargin, QCrelief;
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
+extern Lisp_Object QCdata;
+Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
-Lisp_Object QCindex, QCuser_data;
+Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
 
 /* Other symbols.  */
 
 
 /* Other symbols.  */
 
-Lisp_Object Qlaplace;
+Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
 
 /* Time in seconds after which images should be removed from the cache
    if not displayed.  */
 
 /* Time in seconds after which images should be removed from the cache
    if not displayed.  */
@@ -5458,8 +5212,9 @@ static void define_image_type P_ ((struct image_type *type));
 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
 static void x_laplace P_ ((struct frame *, struct image *));
 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
 static void x_laplace P_ ((struct frame *, struct image *));
-static int x_build_heuristic_mask P_ ((struct frame *, Lisp_Object,
-                                      struct image *, Lisp_Object));
+static void x_emboss P_ ((struct frame *, struct image *));
+static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
+                                      Lisp_Object));
 
 
 /* Define a new image type from TYPE.  This adds a copy of TYPE to
 
 
 /* Define a new image type from TYPE.  This adds a copy of TYPE to
@@ -5549,6 +5304,7 @@ enum image_value_type
   IMAGE_SYMBOL_VALUE,
   IMAGE_POSITIVE_INTEGER_VALUE,
   IMAGE_NON_NEGATIVE_INTEGER_VALUE,
   IMAGE_SYMBOL_VALUE,
   IMAGE_POSITIVE_INTEGER_VALUE,
   IMAGE_NON_NEGATIVE_INTEGER_VALUE,
+  IMAGE_ASCENT_VALUE,
   IMAGE_INTEGER_VALUE,
   IMAGE_FUNCTION_VALUE,
   IMAGE_NUMBER_VALUE,
   IMAGE_INTEGER_VALUE,
   IMAGE_FUNCTION_VALUE,
   IMAGE_NUMBER_VALUE,
@@ -5576,10 +5332,8 @@ struct image_keyword
 };
 
 
 };
 
 
-static int parse_image_spec P_ ((Lisp_Object spec,
-                                struct image_keyword *keywords,
-                                int nkeywords, Lisp_Object type,
-                                int allow_other_keys_p));
+static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
+                                int, Lisp_Object));
 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
 
 
 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
 
 
@@ -5587,17 +5341,14 @@ static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
    has the format (image KEYWORD VALUE ...).  One of the keyword/
    value pairs must be `:type TYPE'.  KEYWORDS is a vector of
    image_keywords structures of size NKEYWORDS describing other
    has the format (image KEYWORD VALUE ...).  One of the keyword/
    value pairs must be `:type TYPE'.  KEYWORDS is a vector of
    image_keywords structures of size NKEYWORDS describing other
-   allowed keyword/value pairs.  ALLOW_OTHER_KEYS_P non-zero means
-   allow KEYWORD/VALUE pairs other than those described by KEYWORDS
-   without checking them.  Value is non-zero if SPEC is valid.  */
+   allowed keyword/value pairs.  Value is non-zero if SPEC is valid.  */
 
 static int
 
 static int
-parse_image_spec (spec, keywords, nkeywords, type, allow_other_keys_p)
+parse_image_spec (spec, keywords, nkeywords, type)
      Lisp_Object spec;
      struct image_keyword *keywords;
      int nkeywords;
      Lisp_Object type;
      Lisp_Object spec;
      struct image_keyword *keywords;
      int nkeywords;
      Lisp_Object type;
-     int allow_other_keys_p;
 {
   int i;
   Lisp_Object plist;
 {
   int i;
   Lisp_Object plist;
@@ -5622,21 +5373,13 @@ parse_image_spec (spec, keywords, nkeywords, type, allow_other_keys_p)
       value = XCAR (plist);
       plist = XCDR (plist);
 
       value = XCAR (plist);
       plist = XCDR (plist);
 
-      /* Always ignore :user-data DATA.  */
-      if (EQ (key, QCuser_data))
-       continue;
-
       /* Find key in KEYWORDS.  Error if not found.  */
       for (i = 0; i < nkeywords; ++i)
        if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
          break;
 
       if (i == nkeywords)
       /* Find key in KEYWORDS.  Error if not found.  */
       for (i = 0; i < nkeywords; ++i)
        if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
          break;
 
       if (i == nkeywords)
-       {
-         if (!allow_other_keys_p)
-           return 0;
-         continue;
-       }
+       continue;
 
       /* Record that we recognized the keyword.  If a keywords
         was found more than once, it's an error.  */
 
       /* Record that we recognized the keyword.  If a keywords
         was found more than once, it's an error.  */
@@ -5664,6 +5407,15 @@ parse_image_spec (spec, keywords, nkeywords, type, allow_other_keys_p)
            return 0;
          break;
 
            return 0;
          break;
 
+       case IMAGE_ASCENT_VALUE:
+         if (SYMBOLP (value) && EQ (value, Qcenter))
+           break;
+         else if (INTEGERP (value)
+                  && XINT (value) >= 0
+                  && XINT (value) <= 100)
+           break;
+         return 0;
+             
        case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
          if (!INTEGERP (value) || XINT (value) < 0)
            return 0;
        case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
          if (!INTEGERP (value) || XINT (value) < 0)
            return 0;
@@ -5744,6 +5496,63 @@ image_spec_value (spec, key, found)
 }
      
 
 }
      
 
+DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
+  "Return the size of image SPEC as pair (WIDTH . HEIGHT).\n\
+PIXELS non-nil means return the size in pixels, otherwise return the\n\
+size in canonical character units.\n\
+FRAME is the frame on which the image will be displayed.  FRAME nil\n\
+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->margin;
+      int height = img->height + 2 * img->margin;
+  
+      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,
+  "Return t if image SPEC has a mask bitmap.\n\
+FRAME is the frame on which the image will be displayed.  FRAME nil\n\
+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
 /***********************************************************************
 
 \f
 /***********************************************************************
@@ -5821,61 +5630,99 @@ prepare_image_for_display (f, img)
 
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
 
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
-  if (img->pixmap == 0 && !img->load_failed_p)
+  if (img->pixmap == None && !img->load_failed_p)
     img->load_failed_p = img->type->load (f, img) == 0;
 }
      
 
     img->load_failed_p = img->type->load (f, img) == 0;
 }
      
 
+/* Value is the number of pixels for the ascent of image IMG when
+   drawn in face FACE.  */
+
+int
+image_ascent (img, face)
+     struct image *img;
+     struct face *face;
+{
+  int height = img->height + img->margin;
+  int ascent;
+
+  if (img->ascent == CENTERED_IMAGE_ASCENT)
+    {
+      if (face->font)
+       /* This expression is arranged so that if the image can't be
+          exactly centered, it will be moved slightly up.  This is
+          because a typical font is `top-heavy' (due to the presence
+          uppercase letters), so the image placement should err towards
+          being top-heavy too.  It also just generally looks better.  */
+       ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
+      else
+       ascent = height / 2;
+    }
+  else
+    ascent = height * img->ascent / 100.0;
+
+  return ascent;
+}
+
+
 \f
 /***********************************************************************
                  Helper functions for X image types
  ***********************************************************************/
 
 \f
 /***********************************************************************
                  Helper functions for X image types
  ***********************************************************************/
 
+static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
+                                int, int));
 static void x_clear_image P_ ((struct frame *f, struct image *img));
 static unsigned long x_alloc_image_color P_ ((struct frame *f,
                                              struct image *img,
                                              Lisp_Object color_name,
                                              unsigned long dflt));
 
 static void x_clear_image P_ ((struct frame *f, struct image *img));
 static unsigned long x_alloc_image_color P_ ((struct frame *f,
                                              struct image *img,
                                              Lisp_Object color_name,
                                              unsigned long dflt));
 
-/* Free X resources of image IMG which is used on frame F.  */
+
+/* Clear X resources of image IMG on frame F.  PIXMAP_P non-zero means
+   free the pixmap if any.  MASK_P non-zero means clear the mask
+   pixmap if any.  COLORS_P non-zero means free colors allocated for
+   the image, if any.  */
 
 static void
 
 static void
-x_clear_image (f, img)
+x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
      struct frame *f;
      struct image *img;
      struct frame *f;
      struct image *img;
+     int pixmap_p, mask_p, colors_p;
 {
 {
-  if (img->pixmap)
+  if (pixmap_p && img->pixmap)
     {
     {
-      BLOCK_INPUT;
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = 0;
-      UNBLOCK_INPUT;
+      img->pixmap = None;
+    }
+
+  if (mask_p && img->mask)
+    {
+      XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+      img->mask = None;
     }
       
     }
       
-  if (img->ncolors)
+  if (colors_p && img->ncolors)
     {
     {
-      int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
-      
-      /* If display has an immutable color map, freeing colors is not
-        necessary and some servers don't allow it.  So don't do it.  */
-      if (class != StaticColor
-         && class != StaticGray
-         && class != TrueColor)
-       {
-         Colormap cmap;
-         BLOCK_INPUT;
-         cmap = DefaultColormapOfScreen (FRAME_X_DISPLAY_INFO (f)->screen);
-         XFreeColors (FRAME_X_DISPLAY (f), cmap, img->colors,
-                      img->ncolors, 0);
-         UNBLOCK_INPUT;
-       }
-      
+      x_free_colors (f, img->colors, img->ncolors);
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
 }
 
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
 }
 
+/* Free X resources of image IMG which is used on frame F.  */
+
+static void
+x_clear_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  BLOCK_INPUT;
+  x_clear_image_1 (f, img, 1, 1, 1);
+  UNBLOCK_INPUT;
+}
+
 
 /* Allocate color COLOR_NAME for image IMG on frame F.  If color
    cannot be allocated, use DFLT.  Add a newly allocated color to
 
 /* Allocate color COLOR_NAME for image IMG on frame F.  If color
    cannot be allocated, use DFLT.  Add a newly allocated color to
@@ -5894,7 +5741,7 @@ x_alloc_image_color (f, img, color_name, dflt)
 
   xassert (STRINGP (color_name));
 
 
   xassert (STRINGP (color_name));
 
-  if (defined_color (f, XSTRING (color_name)->data, &color, 1))
+  if (x_defined_color (f, XSTRING (color_name)->data, &color, 1))
     {
       /* This isn't called frequently so we get away with simply
         reallocating the color vector to the needed size, here.  */
     {
       /* This isn't called frequently so we get away with simply
         reallocating the color vector to the needed size, here.  */
@@ -5957,8 +5804,8 @@ free_image_cache (f)
       for (i = 0; i < c->used; ++i)
        free_image (f, c->images[i]);
       xfree (c->images);
       for (i = 0; i < c->used; ++i)
        free_image (f, c->images[i]);
       xfree (c->images);
-      xfree (c);
       xfree (c->buckets);
       xfree (c->buckets);
+      xfree (c);
       FRAME_X_IMAGE_CACHE (f) = NULL;
     }
 }
       FRAME_X_IMAGE_CACHE (f) = NULL;
     }
 }
@@ -5982,20 +5829,23 @@ clear_image_cache (f, force_p)
     {
       EMACS_TIME t;
       unsigned long old;
     {
       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);
 
       EMACS_GET_TIME (t);
       old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
+
+      /* Block input so that we won't be interrupted by a SIGIO
+        while being in an inconsistent state.  */
+      BLOCK_INPUT;
       
       
-      for (i = 0; i < c->used; ++i)
+      for (i = nfreed = 0; i < c->used; ++i)
        {
          struct image *img = c->images[i];
          if (img != NULL
        {
          struct image *img = c->images[i];
          if (img != NULL
-             && (force_p
-                 || (img->timestamp > old)))
+             && (force_p || img->timestamp < old))
            {
              free_image (f, img);
            {
              free_image (f, img);
-             any_freed_p = 1;
+             ++nfreed;
            }
        }
 
            }
        }
 
@@ -6003,11 +5853,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.  */
         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_X_P (f)
+                 && FRAME_X_IMAGE_CACHE (f) == c)
+               clear_current_matrices (f);
+           }
+
          ++windows_or_buffers_changed;
        }
          ++windows_or_buffers_changed;
        }
+
+      UNBLOCK_INPUT;
     }
 }
 
     }
 }
 
@@ -6068,10 +5929,10 @@ lookup_image (f, spec)
   /* If not found, create a new image and cache it.  */
   if (img == NULL)
     {
   /* If not found, create a new image and cache it.  */
   if (img == NULL)
     {
+      BLOCK_INPUT;
       img = make_image (spec, hash);
       cache_image (f, img);
       img->load_failed_p = img->type->load (f, img) == 0;
       img = make_image (spec, hash);
       cache_image (f, img);
       img->load_failed_p = img->type->load (f, img) == 0;
-      xassert (!interrupt_input_blocked);
 
       /* If we can't load the image, and we don't have a width and
         height, use some arbitrary width and height so that we can
 
       /* If we can't load the image, and we don't have a width and
         height, use some arbitrary width and height so that we can
@@ -6090,13 +5951,15 @@ lookup_image (f, spec)
       else
        {
          /* Handle image type independent image attributes
       else
        {
          /* Handle image type independent image attributes
-            `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'.  */
-         Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
+            `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'.  */
+         Lisp_Object ascent, margin, relief;
          Lisp_Object file;
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (INTEGERP (ascent))
            img->ascent = XFASTINT (ascent);
          Lisp_Object file;
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (INTEGERP (ascent))
            img->ascent = XFASTINT (ascent);
+         else if (EQ (ascent, Qcenter))
+           img->ascent = CENTERED_IMAGE_ASCENT;
          
          margin = image_spec_value (spec, QCmargin, NULL);
          if (INTEGERP (margin) && XINT (margin) >= 0)
          
          margin = image_spec_value (spec, QCmargin, NULL);
          if (INTEGERP (margin) && XINT (margin) >= 0)
@@ -6109,19 +5972,75 @@ lookup_image (f, spec)
              img->margin += abs (img->relief);
            }
 
              img->margin += abs (img->relief);
            }
 
-         /* Should we apply a Laplace edge-detection algorithm?  */
-         algorithm = image_spec_value (spec, QCalgorithm, NULL);
-         if (img->pixmap && EQ (algorithm, Qlaplace))
-           x_laplace (f, img);
-
-         /* Should we built a mask heuristically?  */
-         heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
-         if (img->pixmap && !img->mask && !NILP (heuristic_mask))
+         /* Manipulation of the image's mask.  */
+         if (img->pixmap)
            {
            {
-             file = image_spec_value (spec, QCfile, NULL);
-             x_build_heuristic_mask (f, file, img, heuristic_mask);
+             /* `:heuristic-mask t'
+                `:mask heuristic'
+                       means build a mask heuristically.
+                `:heuristic-mask (R G B)'
+                `:mask (heuristic (R G B))'
+                       means build a mask from color (R G B) in the
+                       image.
+                `:mask nil'
+                       means remove a mask, if any.  */
+             
+             Lisp_Object mask;
+
+             mask = image_spec_value (spec, QCheuristic_mask, NULL);
+             if (!NILP (mask))
+               x_build_heuristic_mask (f, img, mask);
+             else
+               {
+                 int found_p;
+                   
+                 mask = image_spec_value (spec, QCmask, &found_p);
+                 
+                 if (EQ (mask, Qheuristic))
+                   x_build_heuristic_mask (f, img, Qt);
+                 else if (CONSP (mask)
+                          && EQ (XCAR (mask), Qheuristic))
+                   {
+                     if (CONSP (XCDR (mask)))
+                       x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
+                     else
+                       x_build_heuristic_mask (f, img, XCDR (mask));
+                   }
+                 else if (NILP (mask) && found_p && img->mask)
+                   {
+                     XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+                     img->mask = None;
+                   }
+               }
+           }
+         
+         /* Should we apply an image transformation algorithm?  */
+         if (img->pixmap)
+           {
+             Lisp_Object algorithm;
+
+             algorithm = image_spec_value (spec, QCalgorithm, NULL);
+             if (EQ (algorithm, Qdisabled))
+               x_disable_image (f, img);
+             else if (EQ (algorithm, Qlaplace))
+               x_laplace (f, img);
+             else if (EQ (algorithm, Qemboss))
+               x_emboss (f, img);
+             else if (CONSP (algorithm)
+                      && EQ (XCAR (algorithm), Qedge_detection))
+               {
+                 Lisp_Object tem;
+                 tem = XCDR (algorithm);
+                 if (CONSP (tem))
+                   x_edge_detection (f, img,
+                                     Fplist_get (tem, QCmatrix),
+                                     Fplist_get (tem, QCcolor_adjustment));
+               }
            }
        }
            }
        }
+
+      UNBLOCK_INPUT;
+      xassert (!interrupt_input_blocked);
     }
 
   /* We're using IMG, so set its timestamp to `now'.  */
     }
 
   /* We're using IMG, so set its timestamp to `now'.  */
@@ -6201,9 +6120,8 @@ forall_images_in_image_cache (f, fn)
                            X support code
  ***********************************************************************/
 
                            X support code
  ***********************************************************************/
 
-static int x_create_x_image_and_pixmap P_ ((struct frame *, Lisp_Object,
-                                           int, int, int, XImage **,
-                                           Pixmap *));
+static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
+                                           XImage **, Pixmap *));
 static void x_destroy_x_image P_ ((XImage *));
 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
 
 static void x_destroy_x_image P_ ((XImage *));
 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
 
@@ -6212,13 +6130,11 @@ static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
    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
    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.  FILE is the name of an image file being processed, for
-   error messages.  Value is non-zero if successful.  */
+   occurs.  Value is non-zero if successful.  */
 
 static int
 
 static int
-x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap)
+x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
      struct frame *f;
      struct frame *f;
-     Lisp_Object file;
      int width, height, depth;
      XImage **ximg;
      Pixmap *pixmap;
      int width, height, depth;
      XImage **ximg;
      Pixmap *pixmap;
@@ -6236,7 +6152,7 @@ x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap)
                        depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
   if (*ximg == NULL)
     {
                        depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
   if (*ximg == NULL)
     {
-      image_error ("Unable to allocate X image for %s", file, Qnil);
+      image_error ("Unable to allocate X image", Qnil, Qnil);
       return 0;
     }
 
       return 0;
     }
 
@@ -6245,11 +6161,11 @@ x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap)
 
   /* Allocate a pixmap of the same size.  */
   *pixmap = XCreatePixmap (display, window, width, height, depth);
 
   /* Allocate a pixmap of the same size.  */
   *pixmap = XCreatePixmap (display, window, width, height, depth);
-  if (*pixmap == 0)
+  if (*pixmap == None)
     {
       x_destroy_x_image (*ximg);
       *ximg = NULL;
     {
       x_destroy_x_image (*ximg);
       *ximg = NULL;
-      image_error ("Unable to create pixmap for `%s'", file, Qnil);
+      image_error ("Unable to create X pixmap", Qnil, Qnil);
       return 0;
     }
 
       return 0;
     }
 
@@ -6293,10 +6209,12 @@ x_put_x_image (f, ximg, pixmap, width, height)
 
 \f
 /***********************************************************************
 
 \f
 /***********************************************************************
-                             Searching files
+                             File Handling
  ***********************************************************************/
 
 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
  ***********************************************************************/
 
 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
+static char *slurp_file P_ ((char *, int *));
+
 
 /* Find image file FILE.  Look in data-directory, then
    x-bitmap-file-path.  Value is the full name of the file found, or
 
 /* Find image file FILE.  Look in data-directory, then
    x-bitmap-file-path.  Value is the full name of the file found, or
@@ -6317,7 +6235,7 @@ x_find_image_file (file)
   /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
   fd = openp (search_path, file, "", &file_found, 0);
   
   /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
   fd = openp (search_path, file, "", &file_found, 0);
   
-  if (fd < 0)
+  if (fd == -1)
     file_found = Qnil;
   else
     close (fd);
     file_found = Qnil;
   else
     close (fd);
@@ -6327,17 +6245,55 @@ x_find_image_file (file)
 }
 
 
 }
 
 
+/* Read FILE into memory.  Value is a pointer to a buffer allocated
+   with xmalloc holding FILE's contents.  Value is null if an error
+   occurred.  *SIZE is set to the size of the file.  */
+
+static char *
+slurp_file (file, size)
+     char *file;
+     int *size;
+{
+  FILE *fp = NULL;
+  char *buf = NULL;
+  struct stat st;
+
+  if (stat (file, &st) == 0
+      && (fp = fopen (file, "r")) != NULL
+      && (buf = (char *) xmalloc (st.st_size),
+         fread (buf, 1, st.st_size, fp) == st.st_size))
+    {
+      *size = st.st_size;
+      fclose (fp);
+    }
+  else
+    {
+      if (fp)
+       fclose (fp);
+      if (buf)
+       {
+         xfree (buf);
+         buf = NULL;
+       }
+    }
+  
+  return buf;
+}
+
+
 \f
 /***********************************************************************
                              XBM images
  ***********************************************************************/
 
 \f
 /***********************************************************************
                              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 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_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.  */
 
 
 /* Indices of image specification fields in xbm_format, below.  */
@@ -6356,6 +6312,7 @@ enum xbm_keyword_index
   XBM_RELIEF,
   XBM_ALGORITHM,
   XBM_HEURISTIC_MASK,
   XBM_RELIEF,
   XBM_ALGORITHM,
   XBM_HEURISTIC_MASK,
+  XBM_MASK,
   XBM_LAST
 };
 
   XBM_LAST
 };
 
@@ -6371,11 +6328,12 @@ static struct image_keyword xbm_format[XBM_LAST] =
   {":data",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":foreground",      IMAGE_STRING_VALUE,                     0},
   {":background",      IMAGE_STRING_VALUE,                     0},
   {":data",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":foreground",      IMAGE_STRING_VALUE,                     0},
   {":background",      IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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.  */
 };
 
 /* Structure describing the image type XBM.  */
@@ -6418,10 +6376,14 @@ enum xbm_token
    3. a vector of strings or bool-vectors, one for each line of the
    bitmap.
 
    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
    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)
 
 static int
 xbm_image_p (object)
@@ -6430,7 +6392,7 @@ xbm_image_p (object)
   struct image_keyword kw[XBM_LAST];
   
   bcopy (xbm_format, kw, sizeof kw);
   struct image_keyword kw[XBM_LAST];
   
   bcopy (xbm_format, kw, sizeof kw);
-  if (!parse_image_spec (object, kw, XBM_LAST, Qxbm, 0))
+  if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
     return 0;
 
   xassert (EQ (kw[XBM_TYPE].value, Qxbm));
     return 0;
 
   xassert (EQ (kw[XBM_TYPE].value, Qxbm));
@@ -6440,6 +6402,12 @@ xbm_image_p (object)
       if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
        return 0;
     }
       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;
   else
     {
       Lisp_Object data;
@@ -6501,11 +6469,6 @@ xbm_image_p (object)
        return 0;
     }
 
        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;
 }
 
   return 1;
 }
 
@@ -6517,30 +6480,33 @@ xbm_image_p (object)
    scanning a number, store its value in *IVAL.  */
 
 static int
    scanning a number, store its value in *IVAL.  */
 
 static int
-xbm_scan (fp, sval, ival)
-     FILE *fp;
+xbm_scan (s, end, sval, ival)
+     char **s, *end;
      char *sval;
      int *ival;
 {
   int c;
      char *sval;
      int *ival;
 {
   int c;
+
+ loop:
   
   /* Skip white space.  */
   
   /* Skip white space.  */
-  while ((c = fgetc (fp)) != EOF && isspace (c))
+  while (*s < end && (c = *(*s)++, isspace (c)))
     ;
 
     ;
 
-  if (c == EOF)
+  if (*s >= end)
     c = 0;
   else if (isdigit (c))
     {
       int value = 0, digit;
       
     c = 0;
   else if (isdigit (c))
     {
       int value = 0, digit;
       
-      if (c == '0')
+      if (c == '0' && *s < end)
        {
        {
-         c = fgetc (fp);
+         c = *(*s)++;
          if (c == 'x' || c == 'X')
            {
          if (c == 'x' || c == 'X')
            {
-             while ((c = fgetc (fp)) != EOF)
+             while (*s < end)
                {
                {
+                 c = *(*s)++;
                  if (isdigit (c))
                    digit = c - '0';
                  else if (c >= 'a' && c <= 'f')
                  if (isdigit (c))
                    digit = c - '0';
                  else if (c >= 'a' && c <= 'f')
@@ -6555,53 +6521,66 @@ xbm_scan (fp, sval, ival)
          else if (isdigit (c))
            {
              value = c - '0';
          else if (isdigit (c))
            {
              value = c - '0';
-             while ((c = fgetc (fp)) != EOF
-                    && isdigit (c))
+             while (*s < end
+                    && (c = *(*s)++, isdigit (c)))
                value = 8 * value + c - '0';
            }
        }
       else
        {
          value = c - '0';
                value = 8 * value + c - '0';
            }
        }
       else
        {
          value = c - '0';
-         while ((c = fgetc (fp)) != EOF
-                && isdigit (c))
+         while (*s < end
+                && (c = *(*s)++, isdigit (c)))
            value = 10 * value + c - '0';
        }
 
            value = 10 * value + c - '0';
        }
 
-      if (c != EOF)
-       ungetc (c, fp);
+      if (*s < end)
+       *s = *s - 1;
       *ival = value;
       c = XBM_TK_NUMBER;
     }
   else if (isalpha (c) || c == '_')
     {
       *sval++ = c;
       *ival = value;
       c = XBM_TK_NUMBER;
     }
   else if (isalpha (c) || c == '_')
     {
       *sval++ = c;
-      while ((c = fgetc (fp)) != EOF
-            && (isalnum (c) || c == '_'))
+      while (*s < end
+            && (c = *(*s)++, (isalnum (c) || c == '_')))
        *sval++ = c;
       *sval = 0;
        *sval++ = c;
       *sval = 0;
-      if (c != EOF)
-       ungetc (c, fp);
+      if (*s < end)
+       *s = *s - 1;
       c = XBM_TK_IDENT;
     }
       c = XBM_TK_IDENT;
     }
+  else if (c == '/' && **s == '*')
+    {
+      /* C-style comment.  */
+      ++*s;
+      while (**s && (**s != '*' || *(*s + 1) != '/'))
+       ++*s;
+      if (**s)
+       {
+         *s += 2;
+         goto loop;
+       }
+    }
 
   return c;
 }
 
 
 /* Replacement for XReadBitmapFileData which isn't available under old
 
   return c;
 }
 
 
 /* Replacement for XReadBitmapFileData which isn't available under old
-   X versions.  FILE is the name of the bitmap file to read.  Set
-   *WIDTH and *HEIGHT to the width and height of the image.  Return in
-   *DATA the bitmap data allocated with xmalloc.  Value is non-zero if
-   successful.  */
+   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
+   the image.  Return in *DATA the bitmap data allocated with xmalloc.
+   Value is non-zero if successful.  DATA null means just test if
+   CONTENTS looks like an in-memory XBM file.  */
 
 static int
 
 static int
-xbm_read_bitmap_file_data (file, width, height, data)
-     char *file;
+xbm_read_bitmap_data (contents, end, width, height, data)
+     char *contents, *end;
      int *width, *height;
      unsigned char **data;
 {
      int *width, *height;
      unsigned char **data;
 {
-  FILE *fp;
+  char *s = contents;
   char buffer[BUFSIZ];
   int padding_p = 0;
   int v10 = 0;
   char buffer[BUFSIZ];
   int padding_p = 0;
   int v10 = 0;
@@ -6611,7 +6590,7 @@ xbm_read_bitmap_file_data (file, width, height, data)
   int LA1;
 
 #define match() \
   int LA1;
 
 #define match() \
-     LA1 = xbm_scan (fp, buffer, &value)
+     LA1 = xbm_scan (&s, end, buffer, &value)
 
 #define expect(TOKEN)          \
      if (LA1 != (TOKEN))       \
 
 #define expect(TOKEN)          \
      if (LA1 != (TOKEN))       \
@@ -6625,13 +6604,10 @@ xbm_read_bitmap_file_data (file, width, height, data)
      else                                                      \
        goto failure
 
      else                                                      \
        goto failure
 
-  fp = fopen (file, "r");
-  if (fp == NULL)
-    return 0;
-
   *width = *height = -1;
   *width = *height = -1;
-  *data = NULL;
-  LA1 = xbm_scan (fp, buffer, &value);
+  if (data)
+    *data = NULL;
+  LA1 = xbm_scan (&s, end, buffer, &value);
 
   /* Parse defines for width, height and hot-spots.  */
   while (LA1 == '#')
 
   /* Parse defines for width, height and hot-spots.  */
   while (LA1 == '#')
@@ -6654,6 +6630,8 @@ xbm_read_bitmap_file_data (file, width, height, data)
 
   if (*width < 0 || *height < 0)
     goto failure;
 
   if (*width < 0 || *height < 0)
     goto failure;
+  else if (data == NULL)
+    goto success;
 
   /* Parse bits.  Must start with `static'.  */
   expect_ident ("static");
 
   /* Parse bits.  Must start with `static'.  */
   expect_ident ("static");
@@ -6691,7 +6669,6 @@ xbm_read_bitmap_file_data (file, width, height, data)
 
   if (v10)
     {
 
   if (v10)
     {
-      
       for (i = 0; i < nbytes; i += 2)
        {
          int val = value;
       for (i = 0; i < nbytes; i += 2)
        {
          int val = value;
@@ -6723,13 +6700,12 @@ xbm_read_bitmap_file_data (file, width, height, data)
        }
     }
 
        }
     }
 
-  fclose (fp);
+ success:
   return 1;
 
  failure:
   
   return 1;
 
  failure:
   
-  fclose (fp);
-  if (*data)
+  if (data && *data)
     {
       xfree (*data);
       *data = NULL;
     {
       xfree (*data);
       *data = NULL;
@@ -6742,35 +6718,21 @@ xbm_read_bitmap_file_data (file, width, height, data)
 }
 
 
 }
 
 
-/* Load XBM image IMG which will be displayed on frame F from file
-   SPECIFIED_FILE.  Value is non-zero if successful.  */
+/* Load XBM image IMG which will be displayed on frame F from buffer
+   CONTENTS.  END is the end of the buffer.  Value is non-zero if
+   successful.  */
 
 static int
 
 static int
-xbm_load_image_from_file (f, img, specified_file)
+xbm_load_image (f, img, contents, end)
      struct frame *f;
      struct image *img;
      struct frame *f;
      struct image *img;
-     Lisp_Object specified_file;
+     char *contents, *end;
 {
   int rc;
   unsigned char *data;
   int success_p = 0;
 {
   int rc;
   unsigned char *data;
   int success_p = 0;
-  Lisp_Object file;
-  struct gcpro gcpro1;
   
   
-  xassert (STRINGP (specified_file));
-  file = Qnil;
-  GCPRO1 (file);
-
-  file = x_find_image_file (specified_file);
-  if (!STRINGP (file))
-    {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
-         
-  rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
-                                 &img->height, &data);
+  rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
   if (rc)
     {
       int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
   if (rc)
     {
       int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
@@ -6789,7 +6751,6 @@ xbm_load_image_from_file (f, img, specified_file)
       if (!NILP (value))
        background = x_alloc_image_color (f, img, value, background);
 
       if (!NILP (value))
        background = x_alloc_image_color (f, img, value, background);
 
-      BLOCK_INPUT;
       img->pixmap
        = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
                                       FRAME_X_WINDOW (f),
       img->pixmap
        = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
                                       FRAME_X_WINDOW (f),
@@ -6799,24 +6760,36 @@ xbm_load_image_from_file (f, img, specified_file)
                                       depth);
       xfree (data);
 
                                       depth);
       xfree (data);
 
-      if (img->pixmap == 0)
+      if (img->pixmap == None)
        {
          x_clear_image (f, img);
        {
          x_clear_image (f, img);
-         image_error ("Unable to create X pixmap for `%s'", file, Qnil);
+         image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
        }
       else
        success_p = 1;
        }
       else
        success_p = 1;
-      
-      UNBLOCK_INPUT;
     }
   else
     }
   else
-    image_error ("Error loading XBM image %s", img->spec, Qnil);
+    image_error ("Error loading XBM image `%s'", img->spec, Qnil);
 
 
-  UNGCPRO;
   return success_p;
 }
 
 
   return success_p;
 }
 
 
+/* Value is non-zero if DATA looks like an in-memory XBM file.  */
+
+static int
+xbm_file_p (data)
+     Lisp_Object data;
+{
+  int w, h;
+  return (STRINGP (data)
+         && xbm_read_bitmap_data (XSTRING (data)->data,
+                                  (XSTRING (data)->data
+                                   + STRING_BYTES (XSTRING (data))),
+                                  &w, &h, NULL));
+}
+
+    
 /* Fill image IMG which is used on frame F with pixmap data.  Value is
    non-zero if successful.  */
 
 /* Fill image IMG which is used on frame F with pixmap data.  Value is
    non-zero if successful.  */
 
@@ -6833,31 +6806,60 @@ xbm_load (f, img)
   /* If IMG->spec specifies a file name, create a non-file spec from it.  */
   file_name = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (file_name))
   /* If IMG->spec specifies a file name, create a non-file spec from it.  */
   file_name = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (file_name))
-    success_p = xbm_load_image_from_file (f, img, file_name);
+    {
+      Lisp_Object file;
+      char *contents;
+      int size;
+      struct gcpro gcpro1;
+      
+      file = x_find_image_file (file_name);
+      GCPRO1 (file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", file_name, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      contents = slurp_file (XSTRING (file)->data, &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading XBM image `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      success_p = xbm_load_image (f, img, contents, contents + size);
+      UNGCPRO;
+    }
   else
     {
       struct image_keyword fmt[XBM_LAST];
       Lisp_Object data;
   else
     {
       struct image_keyword fmt[XBM_LAST];
       Lisp_Object data;
+      unsigned char *bitmap_data;
       int depth;
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       char *bits;
       int depth;
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       char *bits;
-      int parsed_p;
+      int parsed_p, height, width;
+      int in_memory_file_p = 0;
+
+      /* See if data looks like an in-memory XBM file.  */
+      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);
       bcopy (xbm_format, fmt, sizeof fmt);
-      parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm, 0);
+      parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
       xassert (parsed_p);
 
       /* Get specified width, and height.  */
       xassert (parsed_p);
 
       /* Get specified width, and height.  */
-      img->width = XFASTINT (fmt[XBM_WIDTH].value);
-      img->height = XFASTINT (fmt[XBM_HEIGHT].value);
-      xassert (img->width > 0 && img->height > 0);
-
-      BLOCK_INPUT;
-      
-      if (fmt[XBM_ASCENT].count)
-       img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
+      if (!in_memory_file_p)
+       {
+         img->width = XFASTINT (fmt[XBM_WIDTH].value);
+         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)
 
       /* Get foreground and background colors, maybe allocate colors.  */
       if (fmt[XBM_FOREGROUND].count)
@@ -6867,112 +6869,319 @@ xbm_load (f, img)
        background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
                                          background);
 
        background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
                                          background);
 
-      /* Set bits to the bitmap image data.  */
-      data = fmt[XBM_DATA].value;
-      if (VECTORP (data))
+      if (in_memory_file_p)
+       success_p = xbm_load_image (f, img, XSTRING (data)->data,
+                                   (XSTRING (data)->data
+                                    + STRING_BYTES (XSTRING (data))));
+      else
        {
        {
-         int i;
-         char *p;
-         int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
+         if (VECTORP (data))
+           {
+             int i;
+             char *p;
+             int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
          
          
-         p = bits = (char *) alloca (nbytes * img->height);
-         for (i = 0; i < img->height; ++i, p += nbytes)
+             p = bits = (char *) alloca (nbytes * img->height);
+             for (i = 0; i < img->height; ++i, p += nbytes)
+               {
+                 Lisp_Object line = XVECTOR (data)->contents[i];
+                 if (STRINGP (line))
+                   bcopy (XSTRING (line)->data, p, nbytes);
+                 else
+                   bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+               }
+           }
+         else if (STRINGP (data))
+           bits = XSTRING (data)->data;
+         else
+           bits = XBOOL_VECTOR (data)->data;
+
+         /* Create the pixmap.  */
+         depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+         img->pixmap
+           = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
+                                          FRAME_X_WINDOW (f),
+                                          bits,
+                                          img->width, img->height,
+                                          foreground, background,
+                                          depth);
+         if (img->pixmap)
+           success_p = 1;
+         else
            {
            {
-             Lisp_Object line = XVECTOR (data)->contents[i];
-             if (STRINGP (line))
-               bcopy (XSTRING (line)->data, p, nbytes);
-             else
-               bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
+             image_error ("Unable to create pixmap for XBM image `%s'",
+                          img->spec, Qnil);
+             x_clear_image (f, img);
            }
        }
            }
        }
-      else if (STRINGP (data))
-       bits = XSTRING (data)->data;
-      else
-       bits = XBOOL_VECTOR (data)->data;
+    }
 
 
-      /* Create the pixmap.  */
-      depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
-      img->pixmap
-       = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
-                                      FRAME_X_WINDOW (f),
-                                      bits,
-                                      img->width, img->height,
-                                      foreground, background,
-                                      depth);
-      if (img->pixmap)
-       success_p = 1;
-      else
-       {
-         image_error ("Unable to create pixmap for XBM image", Qnil, Qnil);
-         x_clear_image (f, img);
-       }
+  return success_p;
+}
+  
 
 
-      UNBLOCK_INPUT;
+\f
+/***********************************************************************
+                             XPM images
+ ***********************************************************************/
+
+#if HAVE_XPM 
+
+static int xpm_image_p P_ ((Lisp_Object object));
+static int xpm_load P_ ((struct frame *f, struct image *img));
+static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
+
+#include "X11/xpm.h"
+
+/* The symbol `xpm' identifying XPM-format images.  */
+
+Lisp_Object Qxpm;
+
+/* Indices of image specification fields in xpm_format, below.  */
+
+enum xpm_keyword_index
+{
+  XPM_TYPE,
+  XPM_FILE,
+  XPM_DATA,
+  XPM_ASCENT,
+  XPM_MARGIN,
+  XPM_RELIEF,
+  XPM_ALGORITHM,
+  XPM_HEURISTIC_MASK,
+  XPM_MASK,
+  XPM_COLOR_SYMBOLS,
+  XPM_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+   of valid XPM image specifications.  */
+
+static struct image_keyword xpm_format[XPM_LAST] =
+{
+  {":type",            IMAGE_SYMBOL_VALUE,                     1},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":relief",          IMAGE_INTEGER_VALUE,                    0},
+  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":color-symbols",   IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+};
+
+/* Structure describing the image type XBM.  */
+
+static struct image_type xpm_type =
+{
+  &Qxpm,
+  xpm_image_p,
+  xpm_load,
+  x_clear_image,
+  NULL
+};
+
+
+/* Define ALLOC_XPM_COLORS if we can use Emacs' own color allocation
+   functions for allocating image colors.  Our own functions handle
+   color allocation failures more gracefully than the ones on the XPM
+   lib.  */
+
+#if defined XpmAllocColor && defined XpmFreeColors && defined XpmColorClosure
+#define ALLOC_XPM_COLORS
+#endif
+
+#ifdef ALLOC_XPM_COLORS
+
+static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
+static void xpm_free_color_cache P_ ((void));
+static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
+static int xpm_color_bucket P_ ((char *));
+static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
+                                                    XColor *, int));
+
+/* An entry in a hash table used to cache color definitions of named
+   colors.  This cache is necessary to speed up XPM image loading in
+   case we do color allocations ourselves.  Without it, we would need
+   a call to XParseColor per pixel in the image.  */
+
+struct xpm_cached_color
+{
+  /* Next in collision chain.  */
+  struct xpm_cached_color *next;
+
+  /* Color definition (RGB and pixel color).  */
+  XColor color;
+
+  /* Color name.  */
+  char name[1];
+};
+
+/* The hash table used for the color cache, and its bucket vector
+   size.  */
+
+#define XPM_COLOR_CACHE_BUCKETS        1001
+struct xpm_cached_color **xpm_color_cache;
+
+/* Initialize the color cache.  */
+
+static void
+xpm_init_color_cache (f, attrs)
+     struct frame *f;
+     XpmAttributes *attrs;
+{
+  size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
+  xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
+  memset (xpm_color_cache, 0, nbytes);
+  init_color_table ();
+
+  if (attrs->valuemask & XpmColorSymbols)
+    {
+      int i;
+      XColor color;
+      
+      for (i = 0; i < attrs->numsymbols; ++i)
+       if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+                        attrs->colorsymbols[i].value, &color))
+         {
+           color.pixel = lookup_rgb_color (f, color.red, color.green,
+                                           color.blue);
+           xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
+         }
     }
     }
+}
+
+
+/* Free the color cache.  */
+
+static void
+xpm_free_color_cache ()
+{
+  struct xpm_cached_color *p, *next;
+  int i;
+
+  for (i = 0; i < XPM_COLOR_CACHE_BUCKETS; ++i)
+    for (p = xpm_color_cache[i]; p; p = next)
+      {
+       next = p->next;
+       xfree (p);
+      }
+
+  xfree (xpm_color_cache);
+  xpm_color_cache = NULL;
+  free_color_table ();
+}
+
+
+/* Return the bucket index for color named COLOR_NAME in the color
+   cache.  */
 
 
-  return success_p;
-}
+static int
+xpm_color_bucket (color_name)
+     char *color_name;
+{
+  unsigned h = 0;
+  char *s;
   
   
+  for (s = color_name; *s; ++s)
+    h = (h << 2) ^ *s;
+  return h %= XPM_COLOR_CACHE_BUCKETS;
+}
 
 
-\f
-/***********************************************************************
-                             XPM images
- ***********************************************************************/
 
 
-#if HAVE_XPM 
+/* On frame F, cache values COLOR for color with name COLOR_NAME.
+   BUCKET, if >= 0, is a precomputed bucket index.  Value is the cache
+   entry added.  */
 
 
-static int xpm_image_p P_ ((Lisp_Object object));
-static int xpm_load P_ ((struct frame *f, struct image *img));
-static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
+static struct xpm_cached_color *
+xpm_cache_color (f, color_name, color, bucket)
+     struct frame *f;
+     char *color_name;
+     XColor *color;
+     int bucket;
+{
+  size_t nbytes;
+  struct xpm_cached_color *p;
+  
+  if (bucket < 0)
+    bucket = xpm_color_bucket (color_name);
+      
+  nbytes = sizeof *p + strlen (color_name);
+  p = (struct xpm_cached_color *) xmalloc (nbytes);
+  strcpy (p->name, color_name);
+  p->color = *color;
+  p->next = xpm_color_cache[bucket];
+  xpm_color_cache[bucket] = p;
+  return p;
+}
 
 
-#include "X11/xpm.h"
 
 
-/* The symbol `xpm' identifying XPM-format images.  */
+/* Look up color COLOR_NAME for frame F in the color cache.  If found,
+   return the cached definition in *COLOR.  Otherwise, make a new
+   entry in the cache and allocate the color.  Value is zero if color
+   allocation failed.  */
 
 
-Lisp_Object Qxpm;
+static int
+xpm_lookup_color (f, color_name, color)
+     struct frame *f;
+     char *color_name;
+     XColor *color;
+{
+  struct xpm_cached_color *p;
+  int h = xpm_color_bucket (color_name);
 
 
-/* Indices of image specification fields in xpm_format, below.  */
+  for (p = xpm_color_cache[h]; p; p = p->next)
+    if (strcmp (p->name, color_name) == 0)
+      break;
 
 
-enum xpm_keyword_index
-{
-  XPM_TYPE,
-  XPM_FILE,
-  XPM_DATA,
-  XPM_ASCENT,
-  XPM_MARGIN,
-  XPM_RELIEF,
-  XPM_ALGORITHM,
-  XPM_HEURISTIC_MASK,
-  XPM_COLOR_SYMBOLS,
-  XPM_LAST
-};
+  if (p != NULL)
+    *color = p->color;
+  else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+                       color_name, color))
+    {
+      color->pixel = lookup_rgb_color (f, color->red, color->green,
+                                      color->blue);
+      p = xpm_cache_color (f, color_name, color, h);
+    }
+  
+  return p != NULL;
+}
 
 
-/* Vector of image_keyword structures describing the format
-   of valid XPM image specifications.  */
 
 
-static struct image_keyword xpm_format[XPM_LAST] =
+/* Callback for allocating color COLOR_NAME.  Called from the XPM lib.
+   CLOSURE is a pointer to the frame on which we allocate the
+   color.  Return in *COLOR the allocated color.  Value is non-zero
+   if successful.  */
+
+static int
+xpm_alloc_color (dpy, cmap, color_name, color, closure)
+     Display *dpy;
+     Colormap cmap;
+     char *color_name;
+     XColor *color;
+     void *closure;
 {
 {
-  {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     0},
-  {":data",            IMAGE_STRING_VALUE,                     0},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
-  {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":color-symbols",   IMAGE_DONT_CHECK_VALUE_TYPE,            0}
-};
+  return xpm_lookup_color ((struct frame *) closure, color_name, color);
+}
 
 
-/* Structure describing the image type XBM.  */
 
 
-static struct image_type xpm_type =
+/* Callback for freeing NPIXELS colors contained in PIXELS.  CLOSURE
+   is a pointer to the frame on which we allocate the color.  Value is
+   non-zero if successful.  */
+
+static int
+xpm_free_colors (dpy, cmap, pixels, npixels, closure)
+     Display *dpy;
+     Colormap cmap;
+     Pixel *pixels;
+     int npixels;
+     void *closure;
 {
 {
-  &Qxpm,
-  xpm_image_p,
-  xpm_load,
-  x_clear_image,
-  NULL
-};
+  return 1;
+}
+
+#endif /* ALLOC_XPM_COLORS */
 
 
 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
 
 
 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
@@ -7005,15 +7214,13 @@ xpm_image_p (object)
 {
   struct image_keyword fmt[XPM_LAST];
   bcopy (xpm_format, fmt, sizeof fmt);
 {
   struct image_keyword fmt[XPM_LAST];
   bcopy (xpm_format, fmt, sizeof fmt);
-  return (parse_image_spec (object, fmt, XPM_LAST, Qxpm, 0)
+  return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
          /* Either `:file' or `:data' must be present.  */
          && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
          /* Either no `:color-symbols' or it's a list of conses
             whose car and cdr are strings.  */
          && (fmt[XPM_COLOR_SYMBOLS].count == 0
          /* Either `:file' or `:data' must be present.  */
          && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
          /* Either no `:color-symbols' or it's a list of conses
             whose car and cdr are strings.  */
          && (fmt[XPM_COLOR_SYMBOLS].count == 0
-             || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
-         && (fmt[XPM_ASCENT].count == 0
-             || XFASTINT (fmt[XPM_ASCENT].value) < 100));
+             || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value)));
 }
 
 
 }
 
 
@@ -7032,16 +7239,29 @@ xpm_load (f, img)
   /* Configure the XPM lib.  Use the visual of frame F.  Allocate
      close colors.  Return colors allocated.  */
   bzero (&attrs, sizeof attrs);
   /* Configure the XPM lib.  Use the visual of frame F.  Allocate
      close colors.  Return colors allocated.  */
   bzero (&attrs, sizeof attrs);
-  attrs.visual = FRAME_X_DISPLAY_INFO (f)->visual;
+  attrs.visual = FRAME_X_VISUAL (f);
+  attrs.colormap = FRAME_X_COLORMAP (f);
   attrs.valuemask |= XpmVisual;
   attrs.valuemask |= XpmVisual;
+  attrs.valuemask |= XpmColormap;
+
+#ifdef ALLOC_XPM_COLORS
+  /* Allocate colors with our own functions which handle
+     failing color allocation more gracefully.  */
+  attrs.color_closure = f;
+  attrs.alloc_color = xpm_alloc_color;
+  attrs.free_colors = xpm_free_colors;
+  attrs.valuemask |= XpmAllocColor | XpmFreeColors | XpmColorClosure;
+#else /* not ALLOC_XPM_COLORS */
+  /* Let the XPM lib allocate colors.  */
   attrs.valuemask |= XpmReturnAllocPixels;
 #ifdef XpmAllocCloseColors
   attrs.alloc_close_colors = 1;
   attrs.valuemask |= XpmAllocCloseColors;
   attrs.valuemask |= XpmReturnAllocPixels;
 #ifdef XpmAllocCloseColors
   attrs.alloc_close_colors = 1;
   attrs.valuemask |= XpmAllocCloseColors;
-#else
+#else /* not XpmAllocCloseColors */
   attrs.closeness = 600;
   attrs.valuemask |= XpmCloseness;
   attrs.closeness = 600;
   attrs.valuemask |= XpmCloseness;
-#endif
+#endif /* not XpmAllocCloseColors */
+#endif /* ALLOC_XPM_COLORS */
 
   /* If image specification contains symbolic color definitions, add
      these to `attrs'.  */
 
   /* If image specification contains symbolic color definitions, add
      these to `attrs'.  */
@@ -7081,15 +7301,17 @@ xpm_load (f, img)
 
   /* Create a pixmap for the image, either from a file, or from a
      string buffer containing data in the same format as an XPM file.  */
 
   /* Create a pixmap for the image, either from a file, or from a
      string buffer containing data in the same format as an XPM file.  */
-  BLOCK_INPUT;
+#ifdef ALLOC_XPM_COLORS
+  xpm_init_color_cache (f, &attrs);
+#endif
+  
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (specified_file))
     {
       Lisp_Object file = x_find_image_file (specified_file);
       if (!STRINGP (file))
        {
   specified_file = image_spec_value (img->spec, QCfile, NULL);
   if (STRINGP (specified_file))
     {
       Lisp_Object file = x_find_image_file (specified_file);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file %s", specified_file, Qnil);
-         UNBLOCK_INPUT;
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
          return 0;
        }
       
          return 0;
        }
       
@@ -7105,25 +7327,30 @@ xpm_load (f, img)
                                      &img->pixmap, &img->mask,
                                      &attrs);
     }
                                      &img->pixmap, &img->mask,
                                      &attrs);
     }
-  UNBLOCK_INPUT;
 
   if (rc == XpmSuccess)
     {
 
   if (rc == XpmSuccess)
     {
-      /* Remember allocated colors.  */
+#ifdef ALLOC_XPM_COLORS
+      img->colors = colors_in_color_table (&img->ncolors);
+#else /* not ALLOC_XPM_COLORS */
       img->ncolors = attrs.nalloc_pixels;
       img->colors = (unsigned long *) xmalloc (img->ncolors
                                               * sizeof *img->colors);
       for (i = 0; i < attrs.nalloc_pixels; ++i)
       img->ncolors = attrs.nalloc_pixels;
       img->colors = (unsigned long *) xmalloc (img->ncolors
                                               * sizeof *img->colors);
       for (i = 0; i < attrs.nalloc_pixels; ++i)
-       img->colors[i] = attrs.alloc_pixels[i];
+       {
+         img->colors[i] = attrs.alloc_pixels[i];
+#ifdef DEBUG_X_COLORS
+         register_color (img->colors[i]);
+#endif
+       }
+#endif /* not ALLOC_XPM_COLORS */
 
       img->width = attrs.width;
       img->height = attrs.height;
       xassert (img->width > 0 && img->height > 0);
 
       /* The call to XpmFreeAttributes below frees attrs.alloc_pixels.  */
 
       img->width = attrs.width;
       img->height = attrs.height;
       xassert (img->width > 0 && img->height > 0);
 
       /* The call to XpmFreeAttributes below frees attrs.alloc_pixels.  */
-      BLOCK_INPUT;
       XpmFreeAttributes (&attrs);
       XpmFreeAttributes (&attrs);
-      UNBLOCK_INPUT;
     }
   else
     {
     }
   else
     {
@@ -7151,6 +7378,9 @@ xpm_load (f, img)
        }
     }
 
        }
     }
 
+#ifdef ALLOC_XPM_COLORS
+  xpm_free_color_cache ();
+#endif
   return rc == XpmSuccess;
 }
 
   return rc == XpmSuccess;
 }
 
@@ -7188,15 +7418,6 @@ struct ct_color **ct_table;
 
 int ct_colors_allocated;
 
 
 int ct_colors_allocated;
 
-/* Function prototypes.  */
-
-static void init_color_table P_ ((void));
-static void free_color_table P_ ((void));
-static unsigned long *colors_in_color_table P_ ((int *n));
-static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
-static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
-
-
 /* Initialize the color table.  */
 
 static void
 /* Initialize the color table.  */
 
 static void
@@ -7257,10 +7478,8 @@ lookup_rgb_color (f, r, g, b)
       color.green = g;
       color.blue = b;
       
       color.green = g;
       color.blue = b;
       
-      BLOCK_INPUT;
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       rc = x_alloc_nearest_color (f, cmap, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
-      UNBLOCK_INPUT;
 
       if (rc)
        {
 
       if (rc)
        {
@@ -7303,13 +7522,10 @@ lookup_pixel_color (f, pixel)
       Colormap cmap;
       int rc;
 
       Colormap cmap;
       int rc;
 
-      BLOCK_INPUT;
-      
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       color.pixel = pixel;
       color.pixel = pixel;
-      XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
+      x_query_color (f, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
-      UNBLOCK_INPUT;
 
       if (rc)
        {
 
       if (rc)
        {
@@ -7371,135 +7587,314 @@ static void x_laplace_write_row P_ ((struct frame *, long *,
                                     int, XImage *, int));
 static void x_laplace_read_row P_ ((struct frame *, Colormap,
                                    XColor *, int, XImage *, int));
                                     int, XImage *, int));
 static void x_laplace_read_row P_ ((struct frame *, Colormap,
                                    XColor *, int, XImage *, int));
+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));
+
+/* Non-zero means draw a cross on images having `:algorithm
+   disabled'.  */
+
+int cross_disabled_images;
+
+/* Edge detection matrices for different edge-detection
+   strategies.  */
+
+static int emboss_matrix[9] = {
+   /* x - 1    x       x + 1  */
+        2,     -1,       0,            /* y - 1 */
+       -1,      0,        1,           /* y     */
+        0,      1,       -2            /* y + 1 */
+};
+
+static int laplace_matrix[9] = {
+   /* x - 1    x       x + 1  */
+        1,      0,       0,            /* y - 1 */
+        0,      0,        0,           /* y     */
+        0,      0,       -1            /* y + 1 */
+};
+
+/* Value is the intensity of the color whose red/green/blue values
+   are R, G, and B.  */
+
+#define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
+
+
+/* On frame F, return an array of XColor structures describing image
+   IMG->pixmap.  Each XColor structure has its pixel color set.  RGB_P
+   non-zero means also fill the red/green/blue members of the XColor
+   structures.  Value is a pointer to the array of XColors structures,
+   allocated with xmalloc; it must be freed by the caller.  */
+
+static XColor *
+x_to_xcolors (f, img, rgb_p)
+     struct frame *f;
+     struct image *img;
+     int rgb_p;
+{
+  int x, y;
+  XColor *colors, *p;
+  XImage *ximg;
+
+  colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
+
+  /* Get the X image IMG->pixmap.  */
+  ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
+                   0, 0, img->width, img->height, ~0, ZPixmap);
+
+  /* Fill the `pixel' members of the XColor array.  I wished there
+     were an easy and portable way to circumvent XGetPixel.  */
+  p = colors;
+  for (y = 0; y < img->height; ++y)
+    {
+      XColor *row = p;
+      
+      for (x = 0; x < img->width; ++x, ++p)
+       p->pixel = XGetPixel (ximg, x, y);
+
+      if (rgb_p)
+       x_query_colors (f, row, img->width);
+    }
+
+  XDestroyImage (ximg);
+  return colors;
+}
 
 
 
 
-/* Fill COLORS with RGB colors from row Y of image XIMG.  F is the
-   frame we operate on, CMAP is the color-map in effect, and WIDTH is
-   the width of one row in the image.  */
+/* Create IMG->pixmap from an array COLORS of XColor structures, whose
+   RGB members are set.  F is the frame on which this all happens.
+   COLORS will be freed; an existing IMG->pixmap will be freed, too.  */
 
 static void
 
 static void
-x_laplace_read_row (f, cmap, colors, width, ximg, y)
+x_from_xcolors (f, img, colors)
      struct frame *f;
      struct frame *f;
-     Colormap cmap;
+     struct image *img;
      XColor *colors;
      XColor *colors;
-     int width;
-     XImage *ximg;
-     int y;
 {
 {
-  int x;
+  int x, y;
+  XImage *oimg;
+  Pixmap pixmap;
+  XColor *p;
+  
+  init_color_table ();
+  
+  x_create_x_image_and_pixmap (f, img->width, img->height, 0,
+                              &oimg, &pixmap);
+  p = colors;
+  for (y = 0; y < img->height; ++y)
+    for (x = 0; x < img->width; ++x, ++p)
+      {
+       unsigned long pixel;
+       pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
+       XPutPixel (oimg, x, y, pixel);
+      }
 
 
-  for (x = 0; x < width; ++x)
-    colors[x].pixel = XGetPixel (ximg, x, y);
+  xfree (colors);
+  x_clear_image_1 (f, img, 1, 0, 1);
 
 
-  XQueryColors (FRAME_X_DISPLAY (f), cmap, colors, width);
+  x_put_x_image (f, oimg, pixmap, img->width, img->height);
+  x_destroy_x_image (oimg);
+  img->pixmap = pixmap;
+  img->colors = colors_in_color_table (&img->ncolors);
+  free_color_table ();
 }
 
 
 }
 
 
-/* Write row Y of image XIMG.  PIXELS is an array of WIDTH longs
-   containing the pixel colors to write.  F is the frame we are
-   working on.  */
+/* On frame F, perform edge-detection on image IMG.
+
+   MATRIX is a nine-element array specifying the transformation
+   matrix.  See emboss_matrix for an example.
+   
+   COLOR_ADJUST is a color adjustment added to each pixel of the
+   outgoing image.  */
 
 static void
 
 static void
-x_laplace_write_row (f, pixels, width, ximg, y)
+x_detect_edges (f, img, matrix, color_adjust)
      struct frame *f;
      struct frame *f;
-     long *pixels;
-     int width;
-     XImage *ximg;
-     int y;
+     struct image *img;
+     int matrix[9], color_adjust;
 {
 {
-  int x;
+  XColor *colors = x_to_xcolors (f, img, 1);
+  XColor *new, *p;
+  int x, y, i, sum;
+
+  for (i = sum = 0; i < 9; ++i)
+    sum += abs (matrix[i]);
+
+#define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
+
+  new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
+
+  for (y = 0; y < img->height; ++y)
+    {
+      p = COLOR (new, 0, y);
+      p->red = p->green = p->blue = 0xffff/2;
+      p = COLOR (new, img->width - 1, y);
+      p->red = p->green = p->blue = 0xffff/2;
+    }
   
   
-  for (x = 0; x < width; ++x)
-    XPutPixel (ximg, x, y, pixels[x]);
+  for (x = 1; x < img->width - 1; ++x)
+    {
+      p = COLOR (new, x, 0);
+      p->red = p->green = p->blue = 0xffff/2;
+      p = COLOR (new, x, img->height - 1);
+      p->red = p->green = p->blue = 0xffff/2;
+    }
+
+  for (y = 1; y < img->height - 1; ++y)
+    {
+      p = COLOR (new, 1, y);
+      
+      for (x = 1; x < img->width - 1; ++x, ++p)
+       {
+         int r, g, b, y1, x1;
+
+         r = g = b = i = 0;
+         for (y1 = y - 1; y1 < y + 2; ++y1)
+           for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
+             if (matrix[i])
+               {
+                 XColor *t = COLOR (colors, x1, y1);
+                 r += matrix[i] * t->red;
+                 g += matrix[i] * t->green;
+                 b += matrix[i] * t->blue;
+               }
+
+         r = (r / sum + color_adjust) & 0xffff;
+         g = (g / sum + color_adjust) & 0xffff;
+         b = (b / sum + color_adjust) & 0xffff;
+         p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
+       }
+    }
+
+  xfree (colors);
+  x_from_xcolors (f, img, new);
+
+#undef COLOR
 }
 
 
 }
 
 
-/* Transform image IMG which is used on frame F with a Laplace
-   edge-detection algorithm.  The result is an image that can be used
-   to draw disabled buttons, for example.  */
+/* Perform the pre-defined `emboss' edge-detection on image IMG
+   on frame F.  */
 
 static void
 
 static void
-x_laplace (f, img)
+x_emboss (f, img)
      struct frame *f;
      struct image *img;
 {
      struct frame *f;
      struct image *img;
 {
-  Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
-  XImage *ximg, *oimg;
-  XColor *in[3];
-  long *out;
-  Pixmap pixmap;
-  int x, y, i;
-  long pixel;
-  int in_y, out_y, rc;
-  int mv2 = 45000;
+  x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
+}
 
 
-  BLOCK_INPUT;
 
 
-  /* Get the X image IMG->pixmap.  */
-  ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
-                   0, 0, img->width, img->height, ~0, ZPixmap);
+/* Perform the pre-defined `laplace' edge-detection on image IMG
+   on frame F.  */
+
+static void
+x_laplace (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  x_detect_edges (f, img, laplace_matrix, 45000);
+}
 
 
-  /* Allocate 3 input rows, and one output row of colors.  */
-  for (i = 0; i < 3; ++i)
-    in[i] = (XColor *) alloca (img->width * sizeof (XColor));
-  out = (long *) alloca (img->width * sizeof (long));
 
 
-  /* Create an X image for output.  */
-  rc = x_create_x_image_and_pixmap (f, Qnil, img->width, img->height, 0,
-                                   &oimg, &pixmap);
+/* Perform edge-detection on image IMG on frame F, with specified
+   transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
 
 
-  /* Fill first two rows.  */
-  x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
-  x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
-  in_y = 2;
+   MATRIX must be either
 
 
-  /* Write first row, all zeros.  */
-  init_color_table ();
-  pixel = lookup_rgb_color (f, 0, 0, 0);
-  for (x = 0; x < img->width; ++x)
-    out[x] = pixel;
-  x_laplace_write_row (f, out, img->width, oimg, 0);
-  out_y = 1;
+   - a list of at least 9 numbers in row-major form
+   - a vector of at least 9 numbers
+
+   COLOR_ADJUST nil means use a default; otherwise it must be a
+   number.  */
 
 
-  for (y = 2; y < img->height; ++y)
+static void
+x_edge_detection (f, img, matrix, color_adjust)
+     struct frame *f;
+     struct image *img;
+     Lisp_Object matrix, color_adjust;
+{
+  int i = 0;
+  int trans[9];
+  
+  if (CONSP (matrix))
+    {
+      for (i = 0;
+          i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
+          ++i, matrix = XCDR (matrix))
+       trans[i] = XFLOATINT (XCAR (matrix));
+    }
+  else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
     {
     {
-      int rowa = y % 3;
-      int rowb = (y + 2) % 3;
+      for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
+       trans[i] = XFLOATINT (AREF (matrix, i));
+    }
+
+  if (NILP (color_adjust))
+    color_adjust = make_number (0xffff / 2);
+
+  if (i == 9 && NUMBERP (color_adjust))
+    x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
+}
+
+
+/* Transform image IMG on frame F so that it looks disabled.  */
+
+static void
+x_disable_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 
 
-      x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
+  if (dpyinfo->n_planes >= 2)
+    {
+      /* Color (or grayscale).  Convert to gray, and equalize.  Just
+        drawing such images with a stipple can look very odd, so
+        we're using this method instead.  */
+      XColor *colors = x_to_xcolors (f, img, 1);
+      XColor *p, *end;
+      const int h = 15000;
+      const int l = 30000;
 
 
-      for (x = 0; x < img->width - 2; ++x)
+      for (p = colors, end = colors + img->width * img->height;
+          p < end;
+          ++p)
        {
        {
-         int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
-         int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
-         int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
-         
-         out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
-                                        b & 0xffff);
+         int i = COLOR_INTENSITY (p->red, p->green, p->blue);
+         int i2 = (0xffff - h - l) * i / 0xffff + l;
+         p->red = p->green = p->blue = i2;
        }
 
        }
 
-      x_laplace_write_row (f, out, img->width, oimg, out_y++);
+      x_from_xcolors (f, img, colors);
     }
 
     }
 
-  /* Write last line, all zeros.  */
-  for (x = 0; x < img->width; ++x)
-    out[x] = pixel;
-  x_laplace_write_row (f, out, img->width, oimg, out_y);
-
-  /* Free the input image, and free resources of IMG.  */
-  XDestroyImage (ximg);
-  x_clear_image (f, img);
-  
-  /* Put the output image into pixmap, and destroy it.  */
-  x_put_x_image (f, oimg, pixmap, img->width, img->height);
-  x_destroy_x_image (oimg);
+  /* Draw a cross over the disabled image, if we must or if we
+     should.  */
+  if (dpyinfo->n_planes < 2 || cross_disabled_images)
+    {
+      Display *dpy = FRAME_X_DISPLAY (f);
+      GC gc;
 
 
-  /* Remember new pixmap and colors in IMG.  */
-  img->pixmap = pixmap;
-  img->colors = colors_in_color_table (&img->ncolors);
-  free_color_table ();
+      gc = XCreateGC (dpy, img->pixmap, 0, NULL);
+      XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
+      XDrawLine (dpy, img->pixmap, gc, 0, 0,
+                img->width - 1, img->height - 1);
+      XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
+                img->width - 1, 0);
+      XFreeGC (dpy, gc);
 
 
-  UNBLOCK_INPUT;
+      if (img->mask)
+       {
+         gc = XCreateGC (dpy, img->mask, 0, NULL);
+         XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
+         XDrawLine (dpy, img->mask, gc, 0, 0,
+                    img->width - 1, img->height - 1);
+         XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
+                    img->width - 1, 0);
+         XFreeGC (dpy, gc);
+       }
+    }
 }
 
 
 }
 
 
@@ -7511,27 +7906,27 @@ x_laplace (f, img)
    heuristically.  Value is non-zero if successful. */
 
 static int
    heuristically.  Value is non-zero if successful. */
 
 static int
-x_build_heuristic_mask (f, file, img, how)
+x_build_heuristic_mask (f, img, how)
      struct frame *f;
      struct frame *f;
-     Lisp_Object file;
      struct image *img;
      Lisp_Object how;
 {
   Display *dpy = FRAME_X_DISPLAY (f);
   XImage *ximg, *mask_img;
   int x, y, rc, look_at_corners_p;
      struct image *img;
      Lisp_Object how;
 {
   Display *dpy = FRAME_X_DISPLAY (f);
   XImage *ximg, *mask_img;
   int x, y, rc, look_at_corners_p;
-  unsigned long bg;
+  unsigned long bg = 0;
+
+  if (img->mask)
+    {
+      XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+      img->mask = None;
+    }
 
 
-  BLOCK_INPUT;
-  
   /* Create an image and pixmap serving as mask.  */
   /* Create an image and pixmap serving as mask.  */
-  rc = x_create_x_image_and_pixmap (f, file, img->width, img->height, 1,
+  rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
                                    &mask_img, &img->mask);
   if (!rc)
                                    &mask_img, &img->mask);
   if (!rc)
-    {
-      UNBLOCK_INPUT;
-      return 0;
-    }
+    return 0;
 
   /* Get the X image of IMG->pixmap.  */
   ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
 
   /* Get the X image of IMG->pixmap.  */
   ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
@@ -7562,7 +7957,7 @@ x_build_heuristic_mask (f, file, img, how)
 
          sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
          
 
          sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
          
-         cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+         cmap = FRAME_X_COLORMAP (f);
          if (XLookupColor (dpy, cmap, color_name, &exact, &color))
            {
              bg = color.pixel;
          if (XLookupColor (dpy, cmap, color_name, &exact, &color))
            {
              bg = color.pixel;
@@ -7607,7 +8002,6 @@ x_build_heuristic_mask (f, file, img, how)
   x_destroy_x_image (mask_img);
   XDestroyImage (ximg);
   
   x_destroy_x_image (mask_img);
   XDestroyImage (ximg);
   
-  UNBLOCK_INPUT;
   return 1;
 }
 
   return 1;
 }
 
@@ -7619,7 +8013,7 @@ x_build_heuristic_mask (f, file, img, how)
 
 static int pbm_image_p P_ ((Lisp_Object object));
 static int pbm_load P_ ((struct frame *f, struct image *img));
 
 static int pbm_image_p P_ ((Lisp_Object object));
 static int pbm_load P_ ((struct frame *f, struct image *img));
-static int pbm_scan_number P_ ((FILE *fp));
+static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
 
 /* The symbol `pbm' identifying images of this type.  */
 
 
 /* The symbol `pbm' identifying images of this type.  */
 
@@ -7631,11 +8025,15 @@ enum pbm_keyword_index
 {
   PBM_TYPE,
   PBM_FILE,
 {
   PBM_TYPE,
   PBM_FILE,
+  PBM_DATA,
   PBM_ASCENT,
   PBM_MARGIN,
   PBM_RELIEF,
   PBM_ALGORITHM,
   PBM_HEURISTIC_MASK,
   PBM_ASCENT,
   PBM_MARGIN,
   PBM_RELIEF,
   PBM_ALGORITHM,
   PBM_HEURISTIC_MASK,
+  PBM_MASK,
+  PBM_FOREGROUND,
+  PBM_BACKGROUND,
   PBM_LAST
 };
 
   PBM_LAST
 };
 
@@ -7645,12 +8043,16 @@ enum pbm_keyword_index
 static struct image_keyword pbm_format[PBM_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
 static struct image_keyword pbm_format[PBM_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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},
+  {":foreground",      IMAGE_STRING_VALUE,                     0},
+  {":background",      IMAGE_STRING_VALUE,                     0}
 };
 
 /* Structure describing the image type `pbm'.  */
 };
 
 /* Structure describing the image type `pbm'.  */
@@ -7675,40 +8077,41 @@ pbm_image_p (object)
   
   bcopy (pbm_format, fmt, sizeof fmt);
   
   
   bcopy (pbm_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm, 0)
-      || (fmt[PBM_ASCENT].count 
-         && XFASTINT (fmt[PBM_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm))
     return 0;
     return 0;
-  return 1;
+
+  /* Must specify either :data or :file.  */
+  return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
 }
 
 
 }
 
 
-/* Scan a decimal number from PBM input file FP and return it.  Value
-   is -1 at end of file or if an error occurs.  */
+/* Scan a decimal number from *S and return it.  Advance *S while
+   reading the number.  END is the end of the string.  Value is -1 at
+   end of input.  */
 
 static int
 
 static int
-pbm_scan_number (fp)
-     FILE *fp;
+pbm_scan_number (s, end)
+     unsigned char **s, *end;
 {
 {
-  int c, val = -1;
+  int c = 0, val = -1;
 
 
-  while (!feof (fp))
+  while (*s < end)
     {
       /* Skip white-space.  */
     {
       /* Skip white-space.  */
-      while ((c = fgetc (fp)) != EOF && isspace (c))
+      while (*s < end && (c = *(*s)++, isspace (c)))
        ;
 
       if (c == '#')
        {
          /* Skip comment to end of line.  */
        ;
 
       if (c == '#')
        {
          /* Skip comment to end of line.  */
-         while ((c = fgetc (fp)) != EOF && c != '\n')
+         while (*s < end && (c = *(*s)++, c != '\n'))
            ;
        }
       else if (isdigit (c))
        {
          /* Read decimal number.  */
          val = c - '0';
            ;
        }
       else if (isdigit (c))
        {
          /* Read decimal number.  */
          val = c - '0';
-         while ((c = fgetc (fp)) != EOF && isdigit (c))
+         while (*s < end && (c = *(*s)++, isdigit (c)))
            val = 10 * val + c - '0';
          break;
        }
            val = 10 * val + c - '0';
          break;
        }
@@ -7727,50 +8130,60 @@ pbm_load (f, img)
      struct frame *f;
      struct image *img;
 {
      struct frame *f;
      struct image *img;
 {
-  FILE *fp;
-  char magic[2];
   int raw_p, x, y;
   int width, height, max_color_idx = 0;
   XImage *ximg;
   Lisp_Object file, specified_file;
   enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
   struct gcpro gcpro1;
   int raw_p, x, y;
   int width, height, max_color_idx = 0;
   XImage *ximg;
   Lisp_Object file, specified_file;
   enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
   struct gcpro gcpro1;
+  unsigned char *contents = NULL;
+  unsigned char *end, *p;
+  int size;
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  file = Qnil;
   GCPRO1 (file);
   GCPRO1 (file);
-  if (!STRINGP (file))
+
+  if (STRINGP (specified_file))
     {
     {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
+      file = x_find_image_file (specified_file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
 
 
-  fp = fopen (XSTRING (file)->data, "r");
-  if (fp == NULL)
-    {
-      UNGCPRO;
-      return 0;
-    }
+      contents = slurp_file (XSTRING (file)->data, &size);
+      if (contents == NULL)
+       {
+         image_error ("Error reading `%s'", file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
 
 
-  /* Read first two characters.  */
-  if (fread (magic, sizeof *magic, 2, fp) != 2)
+      p = contents;
+      end = contents + size;
+    }
+  else
     {
     {
-      fclose (fp);
-      image_error ("Not a PBM image file: %s", file, Qnil);
-      UNGCPRO;
-      return 0;
+      Lisp_Object data;
+      data = image_spec_value (img->spec, QCdata, NULL);
+      p = XSTRING (data)->data;
+      end = p + STRING_BYTES (XSTRING (data));
     }
 
     }
 
-  if (*magic != 'P')
+  /* Check magic number.  */
+  if (end - p < 2 || *p++ != 'P')
     {
     {
-      fclose (fp);
-      image_error ("Not a PBM image file: %s", file, Qnil);
+      image_error ("Not a PBM image: `%s'", img->spec, Qnil);
+    error:
+      xfree (contents);
       UNGCPRO;
       return 0;
     }
 
       UNGCPRO;
       return 0;
     }
 
-  switch (magic[1])
+  switch (*p++)
     {
     case '1':
       raw_p = 0, type = PBM_MONO;
     {
     case '1':
       raw_p = 0, type = PBM_MONO;
@@ -7797,41 +8210,30 @@ pbm_load (f, img)
       break;
 
     default:
       break;
 
     default:
-      fclose (fp);
-      image_error ("Not a PBM image file: %s", file, Qnil);
-      UNGCPRO;
-      return 0;
+      image_error ("Not a PBM image: `%s'", img->spec, Qnil);
+      goto error;
     }
 
   /* Read width, height, maximum color-component.  Characters
      starting with `#' up to the end of a line are ignored.  */
     }
 
   /* Read width, height, maximum color-component.  Characters
      starting with `#' up to the end of a line are ignored.  */
-  width = pbm_scan_number (fp);
-  height = pbm_scan_number (fp);
+  width = pbm_scan_number (&p, end);
+  height = pbm_scan_number (&p, end);
 
   if (type != PBM_MONO)
     {
 
   if (type != PBM_MONO)
     {
-      max_color_idx = pbm_scan_number (fp);
+      max_color_idx = pbm_scan_number (&p, end);
       if (raw_p && max_color_idx > 255)
        max_color_idx = 255;
     }
   
       if (raw_p && max_color_idx > 255)
        max_color_idx = 255;
     }
   
-  if (width < 0 || height < 0
+  if (width < 0
+      || height < 0
       || (type != PBM_MONO && max_color_idx < 0))
       || (type != PBM_MONO && max_color_idx < 0))
-    {
-      fclose (fp);
-      UNGCPRO;
-      return 0;
-    }
+    goto error;
 
 
-  BLOCK_INPUT;
-  if (!x_create_x_image_and_pixmap (f, file, width, height, 0,
+  if (!x_create_x_image_and_pixmap (f, width, height, 0,
                                    &ximg, &img->pixmap))
                                    &ximg, &img->pixmap))
-    {
-      fclose (fp);
-      UNBLOCK_INPUT;
-      UNGCPRO;
-      return 0;
-    }
+    goto error;
   
   /* Initialize the color hash table.  */
   init_color_table ();
   
   /* Initialize the color hash table.  */
   init_color_table ();
@@ -7839,6 +8241,19 @@ pbm_load (f, img)
   if (type == PBM_MONO)
     {
       int c = 0, g;
   if (type == PBM_MONO)
     {
       int c = 0, g;
+      struct image_keyword fmt[PBM_LAST];
+      unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
+      unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
+
+      /* Parse the image specification.  */
+      bcopy (pbm_format, fmt, sizeof fmt);
+      parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
+      
+      /* Get foreground and background colors, maybe allocate colors.  */
+      if (fmt[PBM_FOREGROUND].count)
+       fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
+      if (fmt[PBM_BACKGROUND].count)
+       bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
       
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
       
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
@@ -7846,16 +8261,14 @@ pbm_load (f, img)
            if (raw_p)
              {
                if ((x & 7) == 0)
            if (raw_p)
              {
                if ((x & 7) == 0)
-                 c = fgetc (fp);
+                 c = *p++;
                g = c & 0x80;
                c <<= 1;
              }
            else
                g = c & 0x80;
                c <<= 1;
              }
            else
-             g = pbm_scan_number (fp);
+             g = pbm_scan_number (&p, end);
 
 
-           XPutPixel (ximg, x, y, (g
-                                   ? FRAME_FOREGROUND_PIXEL (f)
-                                   : FRAME_BACKGROUND_PIXEL (f)));
+           XPutPixel (ximg, x, y, g ? fg : bg);
          }
     }
   else
          }
     }
   else
@@ -7866,31 +8279,28 @@ pbm_load (f, img)
            int r, g, b;
            
            if (type == PBM_GRAY)
            int r, g, b;
            
            if (type == PBM_GRAY)
-             r = g = b = raw_p ? fgetc (fp) : pbm_scan_number (fp);
+             r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
            else if (raw_p)
              {
            else if (raw_p)
              {
-               r = fgetc (fp);
-               g = fgetc (fp);
-               b = fgetc (fp);
+               r = *p++;
+               g = *p++;
+               b = *p++;
              }
            else
              {
              }
            else
              {
-               r = pbm_scan_number (fp);
-               g = pbm_scan_number (fp);
-               b = pbm_scan_number (fp);
+               r = pbm_scan_number (&p, end);
+               g = pbm_scan_number (&p, end);
+               b = pbm_scan_number (&p, end);
              }
            
            if (r < 0 || g < 0 || b < 0)
              {
              }
            
            if (r < 0 || g < 0 || b < 0)
              {
-               fclose (fp);
                xfree (ximg->data);
                ximg->data = NULL;
                XDestroyImage (ximg);
                xfree (ximg->data);
                ximg->data = NULL;
                XDestroyImage (ximg);
-               UNBLOCK_INPUT;
-               image_error ("Invalid pixel value in file `%s'",
-                            file, Qnil);
-               UNGCPRO;
-               return 0;
+               image_error ("Invalid pixel value in image `%s'",
+                            img->spec, Qnil);
+               goto error;
              }
            
            /* RGB values are now in the range 0..max_color_idx.
              }
            
            /* RGB values are now in the range 0..max_color_idx.
@@ -7902,8 +8312,6 @@ pbm_load (f, img)
          }
     }
   
          }
     }
   
-  fclose (fp);
-
   /* Store in IMG->colors the colors allocated for the image, and
      free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
   /* Store in IMG->colors the colors allocated for the image, and
      free the color table.  */
   img->colors = colors_in_color_table (&img->ncolors);
@@ -7912,12 +8320,12 @@ pbm_load (f, img)
   /* Put the image into a pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   /* Put the image into a pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
-  UNBLOCK_INPUT;
       
   img->width = width;
   img->height = height;
 
   UNGCPRO;
       
   img->width = width;
   img->height = height;
 
   UNGCPRO;
+  xfree (contents);
   return 1;
 }
 
   return 1;
 }
 
@@ -7945,12 +8353,14 @@ Lisp_Object Qpng;
 enum png_keyword_index
 {
   PNG_TYPE,
 enum png_keyword_index
 {
   PNG_TYPE,
+  PNG_DATA,
   PNG_FILE,
   PNG_ASCENT,
   PNG_MARGIN,
   PNG_RELIEF,
   PNG_ALGORITHM,
   PNG_HEURISTIC_MASK,
   PNG_FILE,
   PNG_ASCENT,
   PNG_MARGIN,
   PNG_RELIEF,
   PNG_ALGORITHM,
   PNG_HEURISTIC_MASK,
+  PNG_MASK,
   PNG_LAST
 };
 
   PNG_LAST
 };
 
@@ -7960,12 +8370,14 @@ enum png_keyword_index
 static struct image_keyword png_format[PNG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
 static struct image_keyword png_format[PNG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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 `png'.  */
 };
 
 /* Structure describing the image type `png'.  */
@@ -7989,11 +8401,11 @@ png_image_p (object)
   struct image_keyword fmt[PNG_LAST];
   bcopy (png_format, fmt, sizeof fmt);
   
   struct image_keyword fmt[PNG_LAST];
   bcopy (png_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng, 1)
-      || (fmt[PNG_ASCENT].count 
-         && XFASTINT (fmt[PNG_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng))
     return 0;
     return 0;
-  return 1;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
 }
 
 
 }
 
 
@@ -8020,6 +8432,35 @@ my_png_warning (png_ptr, msg)
   image_error ("PNG warning: %s", build_string (msg), Qnil);
 }
 
   image_error ("PNG warning: %s", build_string (msg), Qnil);
 }
 
+/* Memory source for PNG decoding.  */
+
+struct png_memory_storage
+{
+  unsigned char *bytes;                /* The data       */
+  size_t len;                  /* How big is it? */
+  int index;                   /* Where are we?  */
+};
+
+
+/* Function set as reader function when reading PNG image from memory.
+   PNG_PTR is a pointer to the PNG control structure.  Copy LENGTH
+   bytes from the input to DATA.  */
+
+static void
+png_read_from_memory (png_ptr, data, length)
+     png_structp png_ptr;
+     png_bytep data;
+     png_size_t length;
+{
+  struct png_memory_storage *tbr
+    = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
+
+  if (length > tbr->len - tbr->index)
+    png_error (png_ptr, "Read error");
+  
+  bcopy (tbr->bytes + tbr->index, data, length);
+  tbr->index = tbr->index + length;
+}
 
 /* Load PNG image IMG for use on frame F.  Value is non-zero if
    successful.  */
 
 /* Load PNG image IMG for use on frame F.  Value is non-zero if
    successful.  */
@@ -8030,15 +8471,16 @@ png_load (f, img)
      struct image *img;
 {
   Lisp_Object file, specified_file;
      struct image *img;
 {
   Lisp_Object file, specified_file;
+  Lisp_Object specified_data;
   int x, y, i;
   XImage *ximg, *mask_img = NULL;
   struct gcpro gcpro1;
   png_struct *png_ptr = NULL;
   png_info *info_ptr = NULL, *end_info = NULL;
   int x, y, i;
   XImage *ximg, *mask_img = NULL;
   struct gcpro gcpro1;
   png_struct *png_ptr = NULL;
   png_info *info_ptr = NULL, *end_info = NULL;
-  FILE *fp;
+  FILE *volatile fp = NULL;
   png_byte sig[8];
   png_byte sig[8];
-  png_byte *pixels = NULL;
-  png_byte **rows = NULL;
+  png_byte * volatile pixels = NULL;
+  png_byte ** volatile rows = NULL;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   png_byte channels;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   png_byte channels;
@@ -8047,36 +8489,62 @@ png_load (f, img)
   char *gamma_str;
   double screen_gamma, image_gamma;
   int intent;
   char *gamma_str;
   double screen_gamma, image_gamma;
   int intent;
+  struct png_memory_storage tbr;  /* Data to be read */
 
   /* Find out what file to load.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
   /* Find out what file to load.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   GCPRO1 (file);
   GCPRO1 (file);
-  if (!STRINGP (file))
-    {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
 
 
-  /* Open the image file.  */
-  fp = fopen (XSTRING (file)->data, "rb");
-  if (!fp)
+  if (NILP (specified_data))
     {
     {
-      image_error ("Cannot open image file %s", file, Qnil);
-      UNGCPRO;
-      fclose (fp);
-      return 0;
-    }
+      file = x_find_image_file (specified_file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      /* Open the image file.  */
+      fp = fopen (XSTRING (file)->data, "rb");
+      if (!fp)
+       {
+         image_error ("Cannot open image file `%s'", file, Qnil);
+         UNGCPRO;
+         fclose (fp);
+         return 0;
+       }
 
 
-  /* Check PNG signature.  */
-  if (fread (sig, 1, sizeof sig, fp) != sizeof sig
-      || !png_check_sig (sig, sizeof sig))
+      /* Check PNG signature.  */
+      if (fread (sig, 1, sizeof sig, fp) != sizeof sig
+         || !png_check_sig (sig, sizeof sig))
+       {
+         image_error ("Not a PNG file: `%s'", file, Qnil);
+         UNGCPRO;
+         fclose (fp);
+         return 0;
+       }
+    }
+  else
     {
     {
-      image_error ("Not a PNG file: %s", file, Qnil);
-      UNGCPRO;
-      fclose (fp);
-      return 0;
+      /* Read from memory.  */
+      tbr.bytes = XSTRING (specified_data)->data;
+      tbr.len = STRING_BYTES (XSTRING (specified_data));
+      tbr.index = 0;
+
+      /* Check PNG signature.  */
+      if (tbr.len < sizeof sig
+         || !png_check_sig (tbr.bytes, sizeof sig))
+       {
+         image_error ("Not a PNG image: `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+
+      /* Need to skip past the signature.  */
+      tbr.bytes += sizeof (sig);
     }
 
   /* Initialize read and info structs for PNG lib.  */
     }
 
   /* Initialize read and info structs for PNG lib.  */
@@ -8084,7 +8552,7 @@ png_load (f, img)
                                    my_png_error, my_png_warning);
   if (!png_ptr)
     {
                                    my_png_error, my_png_warning);
   if (!png_ptr)
     {
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
       UNGCPRO;
       return 0;
     }
@@ -8093,7 +8561,7 @@ png_load (f, img)
   if (!info_ptr)
     {
       png_destroy_read_struct (&png_ptr, NULL, NULL);
   if (!info_ptr)
     {
       png_destroy_read_struct (&png_ptr, NULL, NULL);
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
       UNGCPRO;
       return 0;
     }
@@ -8102,7 +8570,7 @@ png_load (f, img)
   if (!end_info)
     {
       png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
   if (!end_info)
     {
       png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
       UNGCPRO;
       return 0;
     }
@@ -8116,14 +8584,17 @@ png_load (f, img)
         png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
       xfree (pixels);
       xfree (rows);
         png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
       xfree (pixels);
       xfree (rows);
-      if (fp)
-       fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
 
   /* Read image info.  */
       UNGCPRO;
       return 0;
     }
 
   /* Read image info.  */
-  png_init_io (png_ptr, fp);
+  if (!NILP (specified_data))
+    png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
+  else
+    png_init_io (png_ptr, fp);
+
   png_set_sig_bytes (png_ptr, sizeof sig);
   png_read_info (png_ptr, info_ptr);
   png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
   png_set_sig_bytes (png_ptr, sizeof sig);
   png_read_info (png_ptr, info_ptr);
   png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
@@ -8193,11 +8664,9 @@ png_load (f, img)
          Colormap cmap;
          png_color_16 frame_background;
 
          Colormap cmap;
          png_color_16 frame_background;
 
-         BLOCK_INPUT;
-         cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+         cmap = FRAME_X_COLORMAP (f);
          color.pixel = FRAME_BACKGROUND_PIXEL (f);
          color.pixel = FRAME_BACKGROUND_PIXEL (f);
-         XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
-         UNBLOCK_INPUT;
+         x_query_color (f, &color);
 
          bzero (&frame_background, sizeof frame_background);
          frame_background.red = color.red;
 
          bzero (&frame_background, sizeof frame_background);
          frame_background.red = color.red;
@@ -8232,30 +8701,27 @@ png_load (f, img)
   /* Read the entire image.  */
   png_read_image (png_ptr, rows);
   png_read_end (png_ptr, info_ptr);
   /* Read the entire image.  */
   png_read_image (png_ptr, rows);
   png_read_end (png_ptr, info_ptr);
-  fclose (fp);
-  fp = NULL;
+  if (fp)
+    {
+      fclose (fp);
+      fp = NULL;
+    }
   
   
-  BLOCK_INPUT;
-
   /* Create the X image and pixmap.  */
   /* Create the X image and pixmap.  */
-  if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
                                    &img->pixmap))
                                    &img->pixmap))
-    {
-      UNBLOCK_INPUT;
-      goto error;
-    }
+    goto error;
   
   /* Create an image and pixmap serving as mask if the PNG image
      contains an alpha channel.  */
   if (channels == 4
       && !transparent_p
   
   /* Create an image and pixmap serving as mask if the PNG image
      contains an alpha channel.  */
   if (channels == 4
       && !transparent_p
-      && !x_create_x_image_and_pixmap (f, file, width, height, 1,
+      && !x_create_x_image_and_pixmap (f, width, height, 1,
                                       &mask_img, &img->mask))
     {
       x_destroy_x_image (ximg);
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
                                       &mask_img, &img->mask))
     {
       x_destroy_x_image (ximg);
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = 0;
-      UNBLOCK_INPUT;
+      img->pixmap = None;
       goto error;
     }
 
       goto error;
     }
 
@@ -8323,7 +8789,6 @@ png_load (f, img)
       x_destroy_x_image (mask_img);
     }
 
       x_destroy_x_image (mask_img);
     }
 
-  UNBLOCK_INPUT;
   UNGCPRO;
   return 1;
 }
   UNGCPRO;
   return 1;
 }
@@ -8365,12 +8830,14 @@ Lisp_Object Qjpeg;
 enum jpeg_keyword_index
 {
   JPEG_TYPE,
 enum jpeg_keyword_index
 {
   JPEG_TYPE,
+  JPEG_DATA,
   JPEG_FILE,
   JPEG_ASCENT,
   JPEG_MARGIN,
   JPEG_RELIEF,
   JPEG_ALGORITHM,
   JPEG_HEURISTIC_MASK,
   JPEG_FILE,
   JPEG_ASCENT,
   JPEG_MARGIN,
   JPEG_RELIEF,
   JPEG_ALGORITHM,
   JPEG_HEURISTIC_MASK,
+  JPEG_MASK,
   JPEG_LAST
 };
 
   JPEG_LAST
 };
 
@@ -8380,12 +8847,14 @@ enum jpeg_keyword_index
 static struct image_keyword jpeg_format[JPEG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
 static struct image_keyword jpeg_format[JPEG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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 `jpeg'.  */
 };
 
 /* Structure describing the image type `jpeg'.  */
@@ -8410,19 +8879,21 @@ jpeg_image_p (object)
   
   bcopy (jpeg_format, fmt, sizeof fmt);
   
   
   bcopy (jpeg_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg, 0)
-      || (fmt[JPEG_ASCENT].count 
-         && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg))
     return 0;
     return 0;
-  return 1;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
 }
 
 }
 
+
 struct my_jpeg_error_mgr
 {
   struct jpeg_error_mgr pub;
   jmp_buf setjmp_buffer;
 };
 
 struct my_jpeg_error_mgr
 {
   struct jpeg_error_mgr pub;
   jmp_buf setjmp_buffer;
 };
 
+
 static void
 my_error_exit (cinfo)
      j_common_ptr cinfo;
 static void
 my_error_exit (cinfo)
      j_common_ptr cinfo;
@@ -8431,6 +8902,103 @@ my_error_exit (cinfo)
   longjmp (mgr->setjmp_buffer, 1);
 }
 
   longjmp (mgr->setjmp_buffer, 1);
 }
 
+
+/* Init source method for JPEG data source manager.  Called by
+   jpeg_read_header() before any data is actually read.  See
+   libjpeg.doc from the JPEG lib distribution.  */
+
+static void
+our_init_source (cinfo)
+     j_decompress_ptr cinfo;
+{
+}
+
+
+/* Fill input buffer method for JPEG data source manager.  Called
+   whenever more data is needed.  We read the whole image in one step,
+   so this only adds a fake end of input marker at the end.  */
+
+static boolean
+our_fill_input_buffer (cinfo)
+     j_decompress_ptr cinfo;
+{
+  /* Insert a fake EOI marker.  */
+  struct jpeg_source_mgr *src = cinfo->src;
+  static JOCTET buffer[2];
+
+  buffer[0] = (JOCTET) 0xFF;
+  buffer[1] = (JOCTET) JPEG_EOI;
+
+  src->next_input_byte = buffer;
+  src->bytes_in_buffer = 2;
+  return TRUE;
+}
+
+
+/* Method to skip over NUM_BYTES bytes in the image data.  CINFO->src
+   is the JPEG data source manager.  */
+
+static void
+our_skip_input_data (cinfo, num_bytes)
+     j_decompress_ptr cinfo;
+     long num_bytes;
+{
+  struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
+
+  if (src)
+    {
+      if (num_bytes > src->bytes_in_buffer)
+       ERREXIT (cinfo, JERR_INPUT_EOF);
+      
+      src->bytes_in_buffer -= num_bytes;
+      src->next_input_byte += num_bytes;
+    }
+}
+
+
+/* Method to terminate data source.  Called by
+   jpeg_finish_decompress() after all data has been processed.  */
+
+static void
+our_term_source (cinfo)
+     j_decompress_ptr cinfo;
+{
+}
+
+
+/* Set up the JPEG lib for reading an image from DATA which contains
+   LEN bytes.  CINFO is the decompression info structure created for
+   reading the image.  */
+
+static void
+jpeg_memory_src (cinfo, data, len)
+     j_decompress_ptr cinfo;
+     JOCTET *data;
+     unsigned int len;
+{
+  struct jpeg_source_mgr *src;
+
+  if (cinfo->src == NULL)
+    {
+      /* First time for this JPEG object?  */
+      cinfo->src = (struct jpeg_source_mgr *)
+       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+                                   sizeof (struct jpeg_source_mgr));
+      src = (struct jpeg_source_mgr *) cinfo->src;
+      src->next_input_byte = data;
+    }
+  
+  src = (struct jpeg_source_mgr *) cinfo->src;
+  src->init_source = our_init_source;
+  src->fill_input_buffer = our_fill_input_buffer;
+  src->skip_input_data = our_skip_input_data;
+  src->resync_to_restart = jpeg_resync_to_restart; /* Use default method.  */
+  src->term_source = our_term_source;
+  src->bytes_in_buffer = len;
+  src->next_input_byte = data;
+}
+
+
 /* Load image IMG for use on frame F.  Patterned after example.c
    from the JPEG lib.  */
 
 /* Load image IMG for use on frame F.  Patterned after example.c
    from the JPEG lib.  */
 
@@ -8442,7 +9010,8 @@ jpeg_load (f, img)
   struct jpeg_decompress_struct cinfo;
   struct my_jpeg_error_mgr mgr;
   Lisp_Object file, specified_file;
   struct jpeg_decompress_struct cinfo;
   struct my_jpeg_error_mgr mgr;
   Lisp_Object file, specified_file;
-  FILE *fp;
+  Lisp_Object specified_data;
+  FILE * volatile fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
   XImage *ximg = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
   XImage *ximg = NULL;
@@ -8453,28 +9022,33 @@ jpeg_load (f, img)
 
   /* Open the JPEG file.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
   /* Open the JPEG file.  */
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   GCPRO1 (file);
   GCPRO1 (file);
-  if (!STRINGP (file))
+
+  if (NILP (specified_data))
     {
     {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
+      file = x_find_image_file (specified_file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
   
   
-  fp = fopen (XSTRING (file)->data, "r");
-  if (fp == NULL)
-    {
-      image_error ("Cannot open `%s'", file, Qnil);
-      UNGCPRO;
-      return 0;
+      fp = fopen (XSTRING (file)->data, "r");
+      if (fp == NULL)
+       {
+         image_error ("Cannot open `%s'", file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
     }
 
     }
 
-  /* Customize libjpeg's error handling to call my_error_exit
-     when an error is detected.  This function will perform
-     a longjmp.  */
-  mgr.pub.error_exit = my_error_exit;
+  /* Customize libjpeg's error handling to call my_error_exit when an
+     error is detected.  This function will perform a longjmp.  */
   cinfo.err = jpeg_std_error (&mgr.pub);
   cinfo.err = jpeg_std_error (&mgr.pub);
+  mgr.pub.error_exit = my_error_exit;
   
   if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
     {
   
   if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
     {
@@ -8483,49 +9057,47 @@ jpeg_load (f, img)
          /* Called from my_error_exit.  Display a JPEG error.  */
          char buffer[JMSG_LENGTH_MAX];
          cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
          /* Called from my_error_exit.  Display a JPEG error.  */
          char buffer[JMSG_LENGTH_MAX];
          cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
-         image_error ("Error reading JPEG file `%s': %s", file,
+         image_error ("Error reading JPEG image `%s': %s", img->spec,
                       build_string (buffer));
        }
          
       /* Close the input file and destroy the JPEG object.  */
                       build_string (buffer));
        }
          
       /* Close the input file and destroy the JPEG object.  */
-      fclose (fp);
+      if (fp)
+       fclose ((FILE *) fp);
       jpeg_destroy_decompress (&cinfo);
 
       jpeg_destroy_decompress (&cinfo);
 
-      BLOCK_INPUT;
-      
       /* If we already have an XImage, free that.  */
       x_destroy_x_image (ximg);
 
       /* Free pixmap and colors.  */
       x_clear_image (f, img);
       
       /* If we already have an XImage, free that.  */
       x_destroy_x_image (ximg);
 
       /* Free pixmap and colors.  */
       x_clear_image (f, img);
       
-      UNBLOCK_INPUT;
       UNGCPRO;
       return 0;
     }
 
   /* Create the JPEG decompression object.  Let it read from fp.
       UNGCPRO;
       return 0;
     }
 
   /* Create the JPEG decompression object.  Let it read from fp.
-     Read the JPEG image header.  */
+        Read the JPEG image header.  */
   jpeg_create_decompress (&cinfo);
   jpeg_create_decompress (&cinfo);
-  jpeg_stdio_src (&cinfo, fp);
+
+  if (NILP (specified_data))
+    jpeg_stdio_src (&cinfo, (FILE *) fp);
+  else
+    jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
+                    STRING_BYTES (XSTRING (specified_data)));
+
   jpeg_read_header (&cinfo, TRUE);
 
   /* Customize decompression so that color quantization will be used.
   jpeg_read_header (&cinfo, TRUE);
 
   /* Customize decompression so that color quantization will be used.
-     Start decompression.  */
+        Start decompression.  */
   cinfo.quantize_colors = TRUE;
   jpeg_start_decompress (&cinfo);
   width = img->width = cinfo.output_width;
   height = img->height = cinfo.output_height;
 
   cinfo.quantize_colors = TRUE;
   jpeg_start_decompress (&cinfo);
   width = img->width = cinfo.output_width;
   height = img->height = cinfo.output_height;
 
-  BLOCK_INPUT;
-
   /* Create X image and pixmap.  */
   /* Create X image and pixmap.  */
-  if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
-                                   &img->pixmap))
-    {
-      UNBLOCK_INPUT;
-      longjmp (mgr.setjmp_buffer, 2);
-    }
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
+    longjmp (mgr.setjmp_buffer, 2);
 
   /* Allocate colors.  When color quantization is used,
      cinfo.actual_number_of_colors has been set with the number of
 
   /* Allocate colors.  When color quantization is used,
      cinfo.actual_number_of_colors has been set with the number of
@@ -8579,12 +9151,12 @@ jpeg_load (f, img)
   /* Clean up.  */
   jpeg_finish_decompress (&cinfo);
   jpeg_destroy_decompress (&cinfo);
   /* Clean up.  */
   jpeg_finish_decompress (&cinfo);
   jpeg_destroy_decompress (&cinfo);
-  fclose (fp);
+  if (fp)
+    fclose ((FILE *) fp);
   
   /* Put the image into the pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   
   /* Put the image into the pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
-  UNBLOCK_INPUT;
   UNGCPRO;
   return 1;
 }
   UNGCPRO;
   return 1;
 }
@@ -8613,12 +9185,14 @@ Lisp_Object Qtiff;
 enum tiff_keyword_index
 {
   TIFF_TYPE,
 enum tiff_keyword_index
 {
   TIFF_TYPE,
+  TIFF_DATA,
   TIFF_FILE,
   TIFF_ASCENT,
   TIFF_MARGIN,
   TIFF_RELIEF,
   TIFF_ALGORITHM,
   TIFF_HEURISTIC_MASK,
   TIFF_FILE,
   TIFF_ASCENT,
   TIFF_MARGIN,
   TIFF_RELIEF,
   TIFF_ALGORITHM,
   TIFF_HEURISTIC_MASK,
+  TIFF_MASK,
   TIFF_LAST
 };
 
   TIFF_LAST
 };
 
@@ -8628,12 +9202,14 @@ enum tiff_keyword_index
 static struct image_keyword tiff_format[TIFF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
 static struct image_keyword tiff_format[TIFF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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 `tiff'.  */
 };
 
 /* Structure describing the image type `tiff'.  */
@@ -8657,11 +9233,128 @@ tiff_image_p (object)
   struct image_keyword fmt[TIFF_LAST];
   bcopy (tiff_format, fmt, sizeof fmt);
   
   struct image_keyword fmt[TIFF_LAST];
   bcopy (tiff_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff, 1)
-      || (fmt[TIFF_ASCENT].count 
-         && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff))
     return 0;
     return 0;
-  return 1;
+  
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
+}
+
+
+/* Reading from a memory buffer for TIFF images Based on the PNG
+   memory source, but we have to provide a lot of extra functions.
+   Blah.
+
+   We really only need to implement read and seek, but I am not
+   convinced that the TIFF library is smart enough not to destroy
+   itself if we only hand it the function pointers we need to
+   override.  */
+
+typedef struct
+{
+  unsigned char *bytes;
+  size_t len;
+  int index;
+}
+tiff_memory_source;
+
+
+static size_t
+tiff_read_from_memory (data, buf, size)
+     thandle_t data;
+     tdata_t buf;
+     tsize_t size;
+{
+  tiff_memory_source *src = (tiff_memory_source *) data;
+
+  if (size > src->len - src->index)
+    return (size_t) -1;
+  bcopy (src->bytes + src->index, buf, size);
+  src->index += size;
+  return size;
+}
+
+
+static size_t
+tiff_write_from_memory (data, buf, size)
+     thandle_t data;
+     tdata_t buf;
+     tsize_t size;
+{
+  return (size_t) -1;
+}
+
+
+static toff_t
+tiff_seek_in_memory (data, off, whence)
+     thandle_t data;
+     toff_t off;
+     int whence;
+{
+  tiff_memory_source *src = (tiff_memory_source *) data;
+  int idx;
+
+  switch (whence)
+    {
+    case SEEK_SET:             /* Go from beginning of source.  */
+      idx = off;
+      break;
+      
+    case SEEK_END:             /* Go from end of source.  */
+      idx = src->len + off;
+      break;
+      
+    case SEEK_CUR:             /* Go from current position.  */
+      idx = src->index + off;
+      break;
+      
+    default:                   /* Invalid `whence'.   */
+      return -1;
+    }
+  
+  if (idx > src->len || idx < 0)
+    return -1;
+  
+  src->index = idx;
+  return src->index;
+}
+
+
+static int
+tiff_close_memory (data)
+     thandle_t data;
+{
+  /* NOOP */
+  return 0;
+}
+
+
+static int
+tiff_mmap_memory (data, pbase, psize)
+     thandle_t data;
+     tdata_t *pbase;
+     toff_t *psize;
+{
+  /* It is already _IN_ memory. */
+  return 0;
+}
+
+
+static void
+tiff_unmap_memory (data, base, size)
+     thandle_t data;
+     tdata_t base;
+     toff_t size;
+{
+  /* We don't need to do this. */
+}
+
+
+static toff_t
+tiff_size_of_memory (data)
+     thandle_t data;
+{
+  return ((tiff_memory_source *) data)->len;
 }
 
 
 }
 
 
@@ -8674,30 +9367,62 @@ tiff_load (f, img)
      struct image *img;
 {
   Lisp_Object file, specified_file;
      struct image *img;
 {
   Lisp_Object file, specified_file;
+  Lisp_Object specified_data;
   TIFF *tiff;
   int width, height, x, y;
   uint32 *buf;
   int rc;
   XImage *ximg;
   struct gcpro gcpro1;
   TIFF *tiff;
   int width, height, x, y;
   uint32 *buf;
   int rc;
   XImage *ximg;
   struct gcpro gcpro1;
+  tiff_memory_source memsrc;
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   GCPRO1 (file);
   GCPRO1 (file);
-  if (!STRINGP (file))
+
+  if (NILP (specified_data))
     {
     {
-      image_error ("Cannot find image file %s", file, Qnil);
-      UNGCPRO;
-      return 0;
+      /* Read from a file */
+      file = x_find_image_file (specified_file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+         
+      /* Try to open the image file.  */
+      tiff = TIFFOpen (XSTRING (file)->data, "r");
+      if (tiff == NULL)
+       {
+         image_error ("Cannot open `%s'", file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
     }
     }
-  
-  /* Try to open the image file.  */
-  tiff = TIFFOpen (XSTRING (file)->data, "r");
-  if (tiff == NULL)
+  else
     {
     {
-      image_error ("Cannot open `%s'", file, Qnil);
-      UNGCPRO;
-      return 0;
+      /* Memory source! */
+      memsrc.bytes = XSTRING (specified_data)->data;
+      memsrc.len = STRING_BYTES (XSTRING (specified_data));
+      memsrc.index = 0;
+
+      tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
+                            (TIFFReadWriteProc) tiff_read_from_memory,
+                            (TIFFReadWriteProc) tiff_write_from_memory,
+                            tiff_seek_in_memory,
+                            tiff_close_memory,
+                            tiff_size_of_memory,
+                            tiff_mmap_memory,
+                            tiff_unmap_memory);
+
+      if (!tiff)
+       {
+         image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
     }
 
   /* Get width and height of the image, and allocate a raster buffer
     }
 
   /* Get width and height of the image, and allocate a raster buffer
@@ -8710,19 +9435,15 @@ tiff_load (f, img)
   TIFFClose (tiff);
   if (!rc)
     {
   TIFFClose (tiff);
   if (!rc)
     {
-      image_error ("Error reading `%s'", file, Qnil);
+      image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
       xfree (buf);
       UNGCPRO;
       return 0;
     }
 
       xfree (buf);
       UNGCPRO;
       return 0;
     }
 
-  BLOCK_INPUT;
-
   /* Create the X image and pixmap.  */
   /* Create the X image and pixmap.  */
-  if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg, 
-                                   &img->pixmap))
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     {
     {
-      UNBLOCK_INPUT;
       xfree (buf);
       UNGCPRO;
       return 0;
       xfree (buf);
       UNGCPRO;
       return 0;
@@ -8754,7 +9475,6 @@ tiff_load (f, img)
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   xfree (buf);
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   xfree (buf);
-  UNBLOCK_INPUT;
       
   img->width = width;
   img->height = height;
       
   img->width = width;
   img->height = height;
@@ -8787,12 +9507,14 @@ Lisp_Object Qgif;
 enum gif_keyword_index
 {
   GIF_TYPE,
 enum gif_keyword_index
 {
   GIF_TYPE,
+  GIF_DATA,
   GIF_FILE,
   GIF_ASCENT,
   GIF_MARGIN,
   GIF_RELIEF,
   GIF_ALGORITHM,
   GIF_HEURISTIC_MASK,
   GIF_FILE,
   GIF_ASCENT,
   GIF_MARGIN,
   GIF_RELIEF,
   GIF_ALGORITHM,
   GIF_HEURISTIC_MASK,
+  GIF_MASK,
   GIF_IMAGE,
   GIF_LAST
 };
   GIF_IMAGE,
   GIF_LAST
 };
@@ -8803,12 +9525,14 @@ enum gif_keyword_index
 static struct image_keyword gif_format[GIF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
 static struct image_keyword gif_format[GIF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":image",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0}
 };
 
   {":image",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0}
 };
 
@@ -8833,11 +9557,45 @@ gif_image_p (object)
   struct image_keyword fmt[GIF_LAST];
   bcopy (gif_format, fmt, sizeof fmt);
   
   struct image_keyword fmt[GIF_LAST];
   bcopy (gif_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif, 1)
-      || (fmt[GIF_ASCENT].count 
-         && XFASTINT (fmt[GIF_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif))
     return 0;
     return 0;
-  return 1;
+  
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
+}
+
+
+/* Reading a GIF image from memory
+   Based on the PNG memory stuff to a certain extent. */
+
+typedef struct
+{
+  unsigned char *bytes;
+  size_t len;
+  int index;
+}
+gif_memory_source;
+
+
+/* Make the current memory source available to gif_read_from_memory.
+   It's done this way because not all versions of libungif support
+   a UserData field in the GifFileType structure.  */
+static gif_memory_source *current_gif_memory_src;
+
+static int
+gif_read_from_memory (file, buf, len)
+     GifFileType *file;
+     GifByteType *buf;
+     int len;
+{
+  gif_memory_source *src = current_gif_memory_src;
+
+  if (len > src->len - src->index)
+    return -1;
+
+  bcopy (src->bytes + src->index, buf, len);
+  src->index += len;
+  return len;
 }
 
 
 }
 
 
@@ -8850,6 +9608,7 @@ gif_load (f, img)
      struct image *img;
 {
   Lisp_Object file, specified_file;
      struct image *img;
 {
   Lisp_Object file, specified_file;
+  Lisp_Object specified_data;
   int rc, width, height, x, y, i;
   XImage *ximg;
   ColorMapObject *gif_color_map;
   int rc, width, height, x, y, i;
   XImage *ximg;
   ColorMapObject *gif_color_map;
@@ -8858,31 +9617,55 @@ gif_load (f, img)
   struct gcpro gcpro1;
   Lisp_Object image;
   int ino, image_left, image_top, image_width, image_height;
   struct gcpro gcpro1;
   Lisp_Object image;
   int ino, image_left, image_top, image_width, image_height;
+  gif_memory_source memsrc;
+  unsigned char *raster;
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   GCPRO1 (file);
   GCPRO1 (file);
-  if (!STRINGP (file))
+
+  if (NILP (specified_data))
     {
     {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
-      UNGCPRO;
-      return 0;
-    }
+      file = x_find_image_file (specified_file);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
   
   
-  /* Open the GIF file.  */
-  gif = DGifOpenFileName (XSTRING (file)->data);
-  if (gif == NULL)
+      /* Open the GIF file.  */
+      gif = DGifOpenFileName (XSTRING (file)->data);
+      if (gif == NULL)
+       {
+         image_error ("Cannot open `%s'", file, Qnil);
+         UNGCPRO;
+         return 0;
+       }
+    }
+  else
     {
     {
-      image_error ("Cannot open `%s'", file, Qnil);
-      UNGCPRO;
-      return 0;
+      /* Read from memory! */
+      current_gif_memory_src = &memsrc;
+      memsrc.bytes = XSTRING (specified_data)->data;
+      memsrc.len = STRING_BYTES (XSTRING (specified_data));
+      memsrc.index = 0;
+
+      gif = DGifOpen(&memsrc, gif_read_from_memory);
+      if (!gif)
+       {
+         image_error ("Cannot open memory source `%s'", img->spec, Qnil);
+         UNGCPRO;
+         return 0;
+       }
     }
 
   /* Read entire contents.  */
   rc = DGifSlurp (gif);
   if (rc == GIF_ERROR)
     {
     }
 
   /* Read entire contents.  */
   rc = DGifSlurp (gif);
   if (rc == GIF_ERROR)
     {
-      image_error ("Error reading `%s'", file, Qnil);
+      image_error ("Error reading `%s'", img->spec, Qnil);
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
@@ -8892,7 +9675,8 @@ gif_load (f, img)
   ino = INTEGERP (image) ? XFASTINT (image) : 0;
   if (ino >= gif->ImageCount)
     {
   ino = INTEGERP (image) ? XFASTINT (image) : 0;
   if (ino >= gif->ImageCount)
     {
-      image_error ("Invalid image number `%s'", image, Qnil);
+      image_error ("Invalid image number `%s' in image `%s'",
+                  image, img->spec);
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
@@ -8901,13 +9685,9 @@ gif_load (f, img)
   width = img->width = gif->SWidth;
   height = img->height = gif->SHeight;
 
   width = img->width = gif->SWidth;
   height = img->height = gif->SHeight;
 
-  BLOCK_INPUT;
-
   /* Create the X image and pixmap.  */
   /* Create the X image and pixmap.  */
-  if (!x_create_x_image_and_pixmap (f, file, width, height, 0, &ximg,
-                                   &img->pixmap))
+  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
     {
     {
-      UNBLOCK_INPUT;
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
@@ -8957,7 +9737,11 @@ gif_load (f, img)
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
 
        XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
     }
 
-  /* Read the GIF image into the X image.  */
+  /* Read the GIF image into the X image.  We use a local variable
+     `raster' here because RasterBits below is a char *, and invites
+     problems with bytes >= 0x80.  */
+  raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
+  
   if (gif->SavedImages[ino].ImageDesc.Interlace)
     {
       static int interlace_start[] = {0, 4, 2, 1};
   if (gif->SavedImages[ino].ImageDesc.Interlace)
     {
       static int interlace_start[] = {0, 4, 2, 1};
@@ -8978,8 +9762,7 @@ gif_load (f, img)
          
          for (x = 0; x < image_width; x++)
            {
          
          for (x = 0; x < image_width; x++)
            {
-             unsigned int i
-               = gif->SavedImages[ino].RasterBits[(y * image_width) + x];
+             int i = raster[(y * image_width) + x];
              XPutPixel (ximg, x + image_left, row + image_top,
                         pixel_colors[i]);
            }
              XPutPixel (ximg, x + image_left, row + image_top,
                         pixel_colors[i]);
            }
@@ -8992,7 +9775,7 @@ gif_load (f, img)
       for (y = 0; y < image_height; ++y)
        for (x = 0; x < image_width; ++x)
          {
       for (y = 0; y < image_height; ++y)
        for (x = 0; x < image_width; ++x)
          {
-           unsigned i = gif->SavedImages[ino].RasterBits[y * image_width + x];
+           int i = raster[y * image_width + x];
            XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
          }
     }
            XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
          }
     }
@@ -9002,7 +9785,6 @@ gif_load (f, img)
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
   /* Put the image into the pixmap, then free the X image and its buffer.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
   x_destroy_x_image (ximg);
-  UNBLOCK_INPUT;
       
   UNGCPRO;
   return 1;
       
   UNGCPRO;
   return 1;
@@ -9043,6 +9825,7 @@ enum gs_keyword_index
   GS_RELIEF,
   GS_ALGORITHM,
   GS_HEURISTIC_MASK,
   GS_RELIEF,
   GS_ALGORITHM,
   GS_HEURISTIC_MASK,
+  GS_MASK,
   GS_LAST
 };
 
   GS_LAST
 };
 
@@ -9057,11 +9840,12 @@ static struct image_keyword gs_format[GS_LAST] =
   {":file",            IMAGE_STRING_VALUE,                     1},
   {":loader",          IMAGE_FUNCTION_VALUE,                   0},
   {":bounding-box",    IMAGE_DONT_CHECK_VALUE_TYPE,            1},
   {":file",            IMAGE_STRING_VALUE,                     1},
   {":loader",          IMAGE_FUNCTION_VALUE,                   0},
   {":bounding-box",    IMAGE_DONT_CHECK_VALUE_TYPE,            1},
-  {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
   {":algorithm",       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 `ghostscript'.  */
 };
 
 /* Structure describing the image type `ghostscript'.  */
@@ -9102,9 +9886,7 @@ gs_image_p (object)
   
   bcopy (gs_format, fmt, sizeof fmt);
   
   
   bcopy (gs_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript, 1)
-      || (fmt[GS_ASCENT].count 
-         && XFASTINT (fmt[GS_ASCENT].value) > 100))
+  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript))
     return 0;
 
   /* Bounding box must be a list or vector containing 4 integers.  */
     return 0;
 
   /* Bounding box must be a list or vector containing 4 integers.  */
@@ -9159,17 +9941,14 @@ gs_load (f, img)
   img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
 
   /* Create the pixmap.  */
   img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
 
   /* Create the pixmap.  */
-  BLOCK_INPUT;
-  xassert (img->pixmap == 0);
+  xassert (img->pixmap == None);
   img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                               img->width, img->height,
                               DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
   img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                               img->width, img->height,
                               DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
-  UNBLOCK_INPUT;
 
   if (!img->pixmap)
     {
 
   if (!img->pixmap)
     {
-      image_error ("Unable to create pixmap for `%s'",
-                  image_spec_value (img->spec, QCfile, NULL), Qnil);
+      image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
       return 0;
     }
     
       return 0;
     }
     
@@ -9233,7 +10012,7 @@ x_kill_gs_process (pixmap, f)
   /* On displays with a mutable colormap, figure out the colors
      allocated for the image by looking at the pixels of an XImage for
      img->pixmap.  */
   /* On displays with a mutable colormap, figure out the colors
      allocated for the image by looking at the pixels of an XImage for
      img->pixmap.  */
-  class = FRAME_X_DISPLAY_INFO (f)->visual->class;
+  class = FRAME_X_VISUAL (f)->class;
   if (class != StaticColor && class != StaticGray && class != TrueColor)
     {
       XImage *ximg;
   if (class != StaticColor && class != StaticGray && class != TrueColor)
     {
       XImage *ximg;
@@ -9272,16 +10051,12 @@ x_kill_gs_process (pixmap, f)
             allocated colors on behalf of us.  So, to get the
             reference counts right, free them once.  */
          if (img->ncolors)
             allocated colors on behalf of us.  So, to get the
             reference counts right, free them once.  */
          if (img->ncolors)
-           {
-             Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
-             XFreeColors (FRAME_X_DISPLAY (f), cmap,
-                          img->colors, img->ncolors, 0);
-           }
+           x_free_colors (f, img->colors, img->ncolors);
 #endif
        }
       else
        image_error ("Cannot get X image of `%s'; colors will not be freed",
 #endif
        }
       else
        image_error ("Cannot get X image of `%s'; colors will not be freed",
-                    image_spec_value (img->spec, QCfile, NULL), Qnil);
+                    img->spec, Qnil);
       
       UNBLOCK_INPUT;
     }
       
       UNBLOCK_INPUT;
     }
@@ -9398,106 +10173,172 @@ value.")
                                Busy cursor
  ***********************************************************************/
 
                                Busy cursor
  ***********************************************************************/
 
-/* The implementation partly follows a patch from
-   F.Pierresteguy@frcl.bull.fr dated 1994.  */
+/* If non-null, an asynchronous timer that, when it expires, displays
+   a busy cursor on all frames.  */
 
 
-/* Setting inhibit_busy_cursor to 2 inhibits busy-cursor display until
-   the next X event is read and we enter XTread_socket again.  Setting
-   it to 1 inhibits busy-cursor display for direct commands.  */
+static struct atimer *busy_cursor_atimer;
 
 
-int inhibit_busy_cursor;
+/* Non-zero means a busy cursor is currently shown.  */
 
 
-/* Incremented with each call to x-display-busy-cursor.
-   Decremented in x-undisplay-busy-cursor.  */
+static int busy_cursor_shown_p;
 
 
-static int busy_count;
+/* Number of seconds to wait before displaying a busy cursor.  */
 
 
+static Lisp_Object Vbusy_cursor_delay;
 
 
-DEFUN ("x-show-busy-cursor", Fx_show_busy_cursor,
-       Sx_show_busy_cursor, 0, 0, 0,
-  "Show a busy cursor, if not already shown.\n\
-Each call to this function must be matched by a call to\n\
-x-undisplay-busy-cursor to make the busy pointer disappear again.")
-  ()
-{
-  ++busy_count;
-  if (busy_count == 1)
-    {
-      Lisp_Object rest, frame;
+/* Default number of seconds to wait before displaying a busy
+   cursor.  */
 
 
-      FOR_EACH_FRAME (rest, frame)
-       if (FRAME_X_P (XFRAME (frame)))
-         {
-           struct frame *f = XFRAME (frame);
-           
-           BLOCK_INPUT;
-           f->output_data.x->busy_p = 1;
-           
-           if (!f->output_data.x->busy_window)
-             {
-               unsigned long mask = CWCursor;
-               XSetWindowAttributes attrs;
-
-               attrs.cursor = f->output_data.x->busy_cursor;
-               f->output_data.x->busy_window
-                 = XCreateWindow (FRAME_X_DISPLAY (f),
-                                  FRAME_OUTER_WINDOW (f),
-                                  0, 0, 32000, 32000, 0, 0,
-                                  InputOnly, CopyFromParent,
-                                  mask, &attrs);
-             }
+#define DEFAULT_BUSY_CURSOR_DELAY 1
 
 
-           XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-           UNBLOCK_INPUT;
-         }
-    }
+/* Function prototypes.  */
 
 
-  return Qnil;
+static void show_busy_cursor P_ ((struct atimer *));
+static void hide_busy_cursor P_ ((void));
+
+
+/* Cancel a currently active busy-cursor timer, and start a new one.  */
+
+void
+start_busy_cursor ()
+{
+  EMACS_TIME delay;
+  int secs, usecs = 0;
+  
+  cancel_busy_cursor ();
+
+  if (INTEGERP (Vbusy_cursor_delay)
+      && XINT (Vbusy_cursor_delay) > 0)
+    secs = XFASTINT (Vbusy_cursor_delay);
+  else if (FLOATP (Vbusy_cursor_delay)
+          && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
+    {
+      Lisp_Object tem;
+      tem = Ftruncate (Vbusy_cursor_delay, Qnil);
+      secs = XFASTINT (tem);
+      usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
+    }
+  else
+    secs = DEFAULT_BUSY_CURSOR_DELAY;
+  
+  EMACS_SET_SECS_USECS (delay, secs, usecs);
+  busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
+                                    show_busy_cursor, NULL);
 }
 
 
 }
 
 
-DEFUN ("x-hide-busy-cursor", Fx_hide_busy_cursor,
-       Sx_hide_busy_cursor, 0, 1, 0,
-  "Hide a busy-cursor.\n\
-A busy-cursor will actually be undisplayed when a matching\n\
-`x-undisplay-busy-cursor' is called for each `x-display-busy-cursor'\n\
-issued.  FORCE non-nil means undisplay the busy-cursor forcibly,\n\
-not counting calls.")
-  (force)
-     Lisp_Object force;
+/* Cancel the busy cursor timer if active, hide a busy cursor if
+   shown.  */
+
+void
+cancel_busy_cursor ()
 {
 {
-  Lisp_Object rest, frame;
+  if (busy_cursor_atimer)
+    {
+      cancel_atimer (busy_cursor_atimer);
+      busy_cursor_atimer = NULL;
+    }
+  
+  if (busy_cursor_shown_p)
+    hide_busy_cursor ();
+}
 
 
-  if (busy_count == 0)
-    return Qnil;
 
 
-  if (!NILP (force) && busy_count != 0)
-    busy_count = 1;
+/* Timer function of busy_cursor_atimer.  TIMER is equal to
+   busy_cursor_atimer.
 
 
-  --busy_count;
-  if (busy_count != 0)
-    return Qnil;
+   Display a busy cursor on all frames by mapping the frames'
+   busy_window.  Set the busy_p flag in the frames' output_data.x
+   structure to indicate that a busy cursor is shown on the
+   frames.  */
+
+static void
+show_busy_cursor (timer)
+     struct atimer *timer;
+{
+  /* The timer implementation will cancel this timer automatically
+     after this function has run.  Set busy_cursor_atimer to null
+     so that we know the timer doesn't have to be canceled.  */
+  busy_cursor_atimer = NULL;
 
 
-  FOR_EACH_FRAME (rest, frame)
+  if (!busy_cursor_shown_p)
     {
     {
-      struct frame *f = XFRAME (frame);
-      
-      if (FRAME_X_P (f)
-         /* Watch out for newly created frames.  */
-         && f->output_data.x->busy_window)
+      Lisp_Object rest, frame;
+  
+      BLOCK_INPUT;
+  
+      FOR_EACH_FRAME (rest, frame)
        {
        {
+         struct frame *f = XFRAME (frame);
          
          
-         BLOCK_INPUT;
-         XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-         /* Sync here because XTread_socket looks at the busy_p flag
-            that is reset to zero below.  */
-         XSync (FRAME_X_DISPLAY (f), False);
-         UNBLOCK_INPUT;
-         f->output_data.x->busy_p = 0;
+         if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
+           {
+             Display *dpy = FRAME_X_DISPLAY (f);
+             
+#ifdef USE_X_TOOLKIT
+             if (f->output_data.x->widget)
+#else
+             if (FRAME_OUTER_WINDOW (f))
+#endif
+               {
+                 f->output_data.x->busy_p = 1;
+       
+                 if (!f->output_data.x->busy_window)
+                   {
+                     unsigned long mask = CWCursor;
+                     XSetWindowAttributes attrs;
+           
+                     attrs.cursor = f->output_data.x->busy_cursor;
+           
+                     f->output_data.x->busy_window
+                       = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
+                                        0, 0, 32000, 32000, 0, 0,
+                                        InputOnly,
+                                        CopyFromParent,
+                                        mask, &attrs);
+                   }
+       
+                 XMapRaised (dpy, f->output_data.x->busy_window);
+                 XFlush (dpy);
+               }
+           }
        }
        }
+
+      busy_cursor_shown_p = 1;
+      UNBLOCK_INPUT;
     }
     }
+}
 
 
-  return Qnil;
+
+/* Hide the busy cursor on all frames, if it is currently shown.  */
+
+static void
+hide_busy_cursor ()
+{
+  if (busy_cursor_shown_p)
+    {
+      Lisp_Object rest, frame;
+
+      BLOCK_INPUT;
+      FOR_EACH_FRAME (rest, frame)
+       {
+         struct frame *f = XFRAME (frame);
+      
+         if (FRAME_X_P (f)
+             /* Watch out for newly created frames.  */
+             && f->output_data.x->busy_window)
+           {
+             XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
+             /* Sync here because XTread_socket looks at the busy_p flag
+                that is reset to zero below.  */
+             XSync (FRAME_X_DISPLAY (f), False);
+             f->output_data.x->busy_p = 0;
+           }
+       }
+
+      busy_cursor_shown_p = 0;
+      UNBLOCK_INPUT;
+    }
 }
 
 
 }
 
 
@@ -9509,9 +10350,9 @@ not counting calls.")
 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
                                           Lisp_Object));
      
 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
                                           Lisp_Object));
      
-/* The frame of a currently visible tooltip, or null.  */
+/* The frame of a currently visible tooltip.  */
 
 
-struct frame *tip_frame;
+Lisp_Object tip_frame;
 
 /* If non-nil, a timer started that hides the last tooltip when it
    fires.  */
 
 /* If non-nil, a timer started that hides the last tooltip when it
    fires.  */
@@ -9519,8 +10360,31 @@ struct frame *tip_frame;
 Lisp_Object tip_timer;
 Window tip_window;
 
 Lisp_Object tip_timer;
 Window tip_window;
 
+
+static Lisp_Object
+unwind_create_tip_frame (frame)
+     Lisp_Object frame;
+{
+  Lisp_Object deleted;
+
+  deleted = unwind_create_frame (frame);
+  if (EQ (deleted, Qt))
+    {
+      tip_window = None;
+      tip_frame = Qnil;
+    }
+  
+  return deleted;
+}
+
+
 /* Create a frame for a tooltip on the display described by DPYINFO.
 /* Create a frame for a tooltip on the display described by DPYINFO.
-   PARMS is a list of frame parameters.  Value is the frame.  */
+   PARMS is a list of frame parameters.  Value is the frame.
+
+   Note that functions called here, esp. x_default_parameter can
+   signal errors, for instance when a specified color name is
+   undefined.  We have to make sure that we're in a consistent state
+   when this happens.  */
 
 static Lisp_Object
 x_create_tip_frame (dpyinfo, parms)
 
 static Lisp_Object
 x_create_tip_frame (dpyinfo, parms)
@@ -9532,7 +10396,7 @@ x_create_tip_frame (dpyinfo, parms)
   Lisp_Object name;
   long window_prompting = 0;
   int width, height;
   Lisp_Object name;
   long window_prompting = 0;
   int width, height;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
 
   struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
 
@@ -9558,23 +10422,57 @@ x_create_tip_frame (dpyinfo, parms)
 
   frame = Qnil;
   GCPRO3 (parms, name, frame);
 
   frame = Qnil;
   GCPRO3 (parms, name, frame);
-  tip_frame = f = make_frame (1);
+  f = make_frame (1);
   XSETFRAME (frame, f);
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
   XSETFRAME (frame, f);
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
+  record_unwind_protect (unwind_create_tip_frame, frame);
 
 
+  /* By setting the output method, we're essentially saying that
+     the frame is live, as per FRAME_LIVE_P.  If we get a signal
+     from this point on, x_destroy_window might screw up reference
+     counts etc.  */
   f->output_method = output_x_window;
   f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
   bzero (f->output_data.x, sizeof (struct x_output));
   f->output_data.x->icon_bitmap = -1;
   f->output_data.x->fontset = -1;
   f->output_method = output_x_window;
   f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
   bzero (f->output_data.x, sizeof (struct x_output));
   f->output_data.x->icon_bitmap = -1;
   f->output_data.x->fontset = -1;
+  f->output_data.x->scroll_bar_foreground_pixel = -1;
+  f->output_data.x->scroll_bar_background_pixel = -1;
   f->icon_name = Qnil;
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
   f->icon_name = Qnil;
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
+#if GLYPH_DEBUG
+  image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
+  dpyinfo_refcount = dpyinfo->reference_count;
+#endif /* GLYPH_DEBUG */
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
   f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
   f->output_data.x->explicit_parent = 0;
 
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
   f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
   f->output_data.x->explicit_parent = 0;
 
+  /* These colors will be set anyway later, but it's important
+     to get the color reference counts right, so initialize them!  */
+  {
+    Lisp_Object black;
+    struct gcpro gcpro1;
+    
+    black = build_string ("black");
+    GCPRO1 (black);
+    f->output_data.x->foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->background_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->cursor_foreground_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->border_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    f->output_data.x->mouse_pixel
+      = x_decode_color (f, black, BLACK_PIX_DEFAULT (f));
+    UNGCPRO;
+  }
+
   /* Set the name; the functions to which we pass f expect the name to
      be set.  */
   if (EQ (name, Qunbound) || NILP (name))
   /* Set the name; the functions to which we pass f expect the name to
      be set.  */
   if (EQ (name, Qunbound) || NILP (name))
@@ -9590,12 +10488,8 @@ x_create_tip_frame (dpyinfo, parms)
       specbind (Qx_resource_name, name);
     }
 
       specbind (Qx_resource_name, name);
     }
 
-  /* Create fontsets from `global_fontset_alist' before handling fonts.  */
-  for (tem = Vglobal_fontset_alist; CONSP (tem); tem = XCDR (tem))
-    fs_register_fontset (f, XCAR (tem));
-
-  /* Extract the window parameters from the supplied values
-     that are needed to determine window geometry.  */
+  /* Extract the window parameters from the supplied values that are
+     needed to determine window geometry.  */
   {
     Lisp_Object font;
 
   {
     Lisp_Object font;
 
@@ -9699,9 +10593,12 @@ x_create_tip_frame (dpyinfo, parms)
     unsigned long mask;
     
     BLOCK_INPUT;
     unsigned long mask;
     
     BLOCK_INPUT;
-    mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
-    /* Window managers looks at the override-redirect flag to
-       determine whether or net to give windows a decoration (Xlib
+    mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
+    if (DoesSaveUnders (dpyinfo->screen))
+      mask |= CWSaveUnder;
+    
+    /* Window managers look at the override-redirect flag to determine
+       whether or net to give windows a decoration (Xlib spec, chapter
        3.2.8).  */
     attrs.override_redirect = True;
     attrs.save_under = True;
        3.2.8).  */
     attrs.override_redirect = True;
     attrs.save_under = True;
@@ -9747,43 +10644,55 @@ x_create_tip_frame (dpyinfo, parms)
      below.  And the frame needs to be on Vframe_list or making it
      visible won't work.  */
   Vframe_list = Fcons (frame, Vframe_list);
      below.  And the frame needs to be on Vframe_list or making it
      visible won't work.  */
   Vframe_list = Fcons (frame, Vframe_list);
+  tip_frame = frame;
 
   /* Now that the frame is official, it counts as a reference to
      its display.  */
   FRAME_X_DISPLAY_INFO (f)->reference_count++;
 
 
   /* Now that the frame is official, it counts as a reference to
      its display.  */
   FRAME_X_DISPLAY_INFO (f)->reference_count++;
 
+  /* Discard the unwind_protect.  */
   return unbind_to (count, frame);
 }
 
 
   return unbind_to (count, frame);
 }
 
 
-DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
+DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   "Show STRING in a \"tooltip\" window on frame FRAME.\n\
   "Show STRING in a \"tooltip\" window on frame FRAME.\n\
-A tooltip window is a small X window displaying STRING at\n\
-the current mouse position.\n\
+A tooltip window is a small X window displaying a string.\n\
+\n\
 FRAME nil or omitted means use the selected frame.\n\
 FRAME nil or omitted means use the selected frame.\n\
+\n\
 PARMS is an optional list of frame parameters which can be\n\
 used to change the tooltip's appearance.\n\
 PARMS is an optional list of frame parameters which can be\n\
 used to change the tooltip's appearance.\n\
+\n\
 Automatically hide the tooltip after TIMEOUT seconds.\n\
 Automatically hide the tooltip after TIMEOUT seconds.\n\
-TIMEOUT nil means use the default timeout of 5 seconds.")
-  (string, frame, parms, timeout)
-     Lisp_Object string, frame, parms, timeout;
+TIMEOUT nil means use the default timeout of 5 seconds.\n\
+\n\
+If the list of frame parameters PARAMS contains a `left' parameters,\n\
+the tooltip is displayed at that x-position.  Otherwise it is\n\
+displayed at the mouse position, with offset DX added (default is 5 if\n\
+DX isn't specified).  Likewise for the y-position; if a `top' frame\n\
+parameter is specified, it determines the y-position of the tooltip\n\
+window, otherwise it is displayed at the mouse position, with offset\n\
+DY added (default is -10).")
+  (string, frame, parms, timeout, dx, dy)
+     Lisp_Object string, frame, parms, timeout, dx, dy;
 {
   struct frame *f;
   struct window *w;
   Window root, child;
 {
   struct frame *f;
   struct window *w;
   Window root, child;
-  Lisp_Object buffer;
+  Lisp_Object buffer, top, left;
   struct buffer *old_buffer;
   struct text_pos pos;
   int i, width, height;
   int root_x, root_y, win_x, win_y;
   unsigned pmask;
   struct buffer *old_buffer;
   struct text_pos pos;
   int i, width, height;
   int root_x, root_y, win_x, win_y;
   unsigned pmask;
-  struct gcpro gcpro1, gcpro2, gcpro3;
+  struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   int count = specpdl_ptr - specpdl;
   
   specbind (Qinhibit_redisplay, Qt);
 
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   int count = specpdl_ptr - specpdl;
   
   specbind (Qinhibit_redisplay, Qt);
 
-  GCPRO3 (string, parms, frame);
+  GCPRO4 (string, parms, frame, timeout);
 
   CHECK_STRING (string, 0);
   f = check_x_frame (frame);
 
   CHECK_STRING (string, 0);
   f = check_x_frame (frame);
@@ -9791,6 +10700,16 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
     timeout = make_number (5);
   else
     CHECK_NATNUM (timeout, 2);
     timeout = make_number (5);
   else
     CHECK_NATNUM (timeout, 2);
+  
+  if (NILP (dx))
+    dx = make_number (5);
+  else
+    CHECK_NUMBER (dx, 5);
+  
+  if (NILP (dy))
+    dy = make_number (-10);
+  else
+    CHECK_NUMBER (dy, 6);
 
   /* Hide a previous tip, if any.  */
   Fx_hide_tip ();
 
   /* Hide a previous tip, if any.  */
   Fx_hide_tip ();
@@ -9811,15 +10730,15 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   /* Create a frame for the tooltip, and record it in the global
      variable tip_frame.  */
   frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
   /* Create a frame for the tooltip, and record it in the global
      variable tip_frame.  */
   frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
-  tip_frame = f = XFRAME (frame);
+  f = XFRAME (frame);
 
   /* Set up the frame's root window.  Currently we use a size of 80
      columns x 40 lines.  If someone wants to show a larger tip, he
      will loose.  I don't think this is a realistic case.  */
   w = XWINDOW (FRAME_ROOT_WINDOW (f));
   w->left = w->top = make_number (0);
 
   /* Set up the frame's root window.  Currently we use a size of 80
      columns x 40 lines.  If someone wants to show a larger tip, he
      will loose.  I don't think this is a realistic case.  */
   w = XWINDOW (FRAME_ROOT_WINDOW (f));
   w->left = w->top = make_number (0);
-  w->width = 80;
-  w->height = 40;
+  w->width = make_number (80);
+  w->height = make_number (40);
   adjust_glyphs (f);
   w->pseudo_window_p = 1;
 
   adjust_glyphs (f);
   w->pseudo_window_p = 1;
 
@@ -9829,7 +10748,7 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   old_buffer = current_buffer;
   set_buffer_internal_1 (XBUFFER (buffer));
   Ferase_buffer ();
   old_buffer = current_buffer;
   set_buffer_internal_1 (XBUFFER (buffer));
   Ferase_buffer ();
-  Finsert (make_number (1), &string);
+  Finsert (1, &string);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
@@ -9850,7 +10769,7 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
       /* Let the row go over the full width of the frame.  */
       row->full_width_p = 1;
 
       /* Let the row go over the full width of the frame.  */
       row->full_width_p = 1;
 
-      /* There's a glyph at the end of rows that is use to place
+      /* There's a glyph at the end of rows that is used to place
         the cursor there.  Don't include the width of this glyph.  */
       if (row->used[TEXT_AREA])
        {
         the cursor there.  Don't include the width of this glyph.  */
       if (row->used[TEXT_AREA])
        {
@@ -9869,13 +10788,28 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
   width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
 
   height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
   width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
 
+  /* User-specified position?  */
+  left = Fcdr (Fassq (Qleft, parms));
+  top  = Fcdr (Fassq (Qtop, parms));
+  
   /* Move the tooltip window where the mouse pointer is.  Resize and
      show it.  */
   BLOCK_INPUT;
   XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
                 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
   /* Move the tooltip window where the mouse pointer is.  Resize and
      show it.  */
   BLOCK_INPUT;
   XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
                 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
+  UNBLOCK_INPUT;
+
+  root_x += XINT (dx);
+  root_y += XINT (dy);
+  
+  if (INTEGERP (left))
+    root_x = XINT (left);
+  if (INTEGERP (top))
+    root_y = XINT (top);
+  
+  BLOCK_INPUT;
   XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
   XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    root_x + 5, root_y - height - 5, width, height);
+                    root_x, root_y - height, width, height);
   XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
   UNBLOCK_INPUT;
 
   XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
   UNBLOCK_INPUT;
 
@@ -9890,7 +10824,8 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   /* Let the tip disappear after timeout seconds.  */
   tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
                     intern ("x-hide-tip"));
   /* Let the tip disappear after timeout seconds.  */
   tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
                     intern ("x-hide-tip"));
-  
+
+  UNGCPRO;
   return unbind_to (count, Qnil);
 }
 
   return unbind_to (count, Qnil);
 }
 
@@ -9900,28 +10835,53 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
 Value is t is tooltip was open, nil otherwise.")
   ()
 {
 Value is t is tooltip was open, nil otherwise.")
   ()
 {
-  int count = specpdl_ptr - specpdl;
-  int deleted_p = 0;
+  int count;
+  Lisp_Object deleted, frame, timer;
+  struct gcpro gcpro1, gcpro2;
+
+  /* Return quickly if nothing to do.  */
+  if (NILP (tip_timer) && NILP (tip_frame))
+    return Qnil;
   
   
+  frame = tip_frame;
+  timer = tip_timer;
+  GCPRO2 (frame, timer);
+  tip_frame = tip_timer = deleted = Qnil;
+  
+  count = BINDING_STACK_SIZE ();
   specbind (Qinhibit_redisplay, Qt);
   specbind (Qinhibit_redisplay, Qt);
+  specbind (Qinhibit_quit, Qt);
   
   
-  if (!NILP (tip_timer))
-    {
-      call1 (intern ("cancel-timer"), tip_timer);
-      tip_timer = Qnil;
-    }
+  if (!NILP (timer))
+    call1 (intern ("cancel-timer"), timer);
 
 
-  if (tip_frame)
+  if (FRAMEP (frame))
     {
     {
-      Lisp_Object frame;
-      
-      XSETFRAME (frame, tip_frame);
-      Fdelete_frame (frame, Qt);
-      tip_frame = NULL;
-      deleted_p = 1;
+      Fdelete_frame (frame, Qnil);
+      deleted = Qt;
+
+#ifdef USE_LUCID
+      /* Bloodcurdling hack alert: The Lucid menu bar widget's
+        redisplay procedure is not called when a tip frame over menu
+        items is unmapped.  Redisplay the menu manually...  */
+      {
+       struct frame *f = SELECTED_FRAME ();
+       Widget w = f->output_data.x->menubar_widget;
+       extern void xlwmenu_redisplay P_ ((Widget));
+       
+       if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
+           && w != None)
+         {
+           BLOCK_INPUT;
+           xlwmenu_redisplay (w);
+           UNBLOCK_INPUT;
+         }
+      }
+#endif /* USE_LUCID */
     }
 
     }
 
-  return unbind_to (count, deleted_p ? Qt : Qnil);
+  UNGCPRO;
+  return unbind_to (count, deleted);
 }
 
 
 }
 
 
@@ -10048,6 +11008,15 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
       XmListSetPos (list, item_pos);
     }
 
       XmListSetPos (list, item_pos);
     }
 
+#ifdef HAVE_MOTIF_2_1
+
+  /* Process events until the user presses Cancel or OK.  */
+  result = 0;
+  while (result == 0 || XtAppPending (Xt_app_con))
+    XtAppProcessEvent (Xt_app_con, XtIMAll);
+
+#else /* not HAVE_MOTIF_2_1 */
+  
   /* Process all events until the user presses Cancel or OK.  */
   for (result = 0; result == 0;)
     {
   /* Process all events until the user presses Cancel or OK.  */
   for (result = 0; result == 0;)
     {
@@ -10063,20 +11032,22 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
       parent = widget;
       while (parent && parent != dialog)
        parent = XtParent (parent);
       parent = widget;
       while (parent && parent != dialog)
        parent = XtParent (parent);
-      
+
       if (parent == dialog
          || (event.type == Expose
              && !process_expose_from_menu (event)))
        XtDispatchEvent (&event);
     }
 
       if (parent == dialog
          || (event.type == Expose
              && !process_expose_from_menu (event)))
        XtDispatchEvent (&event);
     }
 
+#endif /* not HAVE_MOTIF_2_1 */
+
   /* Get the result.  */
   if (result == XmCR_OK)
     {
       XmString text;
       String data;
       
   /* Get the result.  */
   if (result == XmCR_OK)
     {
       XmString text;
       String data;
       
-      XtVaGetValues (dialog, XmNtextString, &text, 0);
+      XtVaGetValues (dialog, XmNtextString, &text, NULL);
       XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
       XmStringFree (text);
       file = build_string (data);
       XmStringGetLtoR (text, XmFONTLIST_DEFAULT_TAG, &data);
       XmStringFree (text);
       file = build_string (data);
@@ -10100,37 +11071,68 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
 
 #endif /* USE_MOTIF */
 
 
 #endif /* USE_MOTIF */
 
+
 \f
 /***********************************************************************
 \f
 /***********************************************************************
-                               Tests
+                              Keyboard
  ***********************************************************************/
 
  ***********************************************************************/
 
-#if GLYPH_DEBUG
+#ifdef HAVE_XKBGETKEYBOARD
+#include <X11/XKBlib.h>
+#include <X11/keysym.h>
+#endif
 
 
-DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
-  "Value is non-nil if SPEC is a valid image specification.")
-  (spec)
-     Lisp_Object spec;
+DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
+       Sx_backspace_delete_keys_p, 0, 1, 0,
+  "Check if both Backspace and Delete keys are on the keyboard of FRAME.\n\
+FRAME nil means use the selected frame.\n\
+Value is t if we know that both keys are present, and are mapped to the\n\
+usual X keysyms.")
+  (frame)
+     Lisp_Object frame;
 {
 {
-  return valid_image_p (spec) ? Qt : Qnil;
-}
+#ifdef HAVE_XKBGETKEYBOARD
+  XkbDescPtr kb;
+  struct frame *f = check_x_frame (frame);
+  Display *dpy = FRAME_X_DISPLAY (f);
+  Lisp_Object have_keys;
 
 
+  have_keys = Qnil;
 
 
-DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
-  (spec)
-     Lisp_Object spec;
-{
-  int id = -1;
-  
-  if (valid_image_p (spec))
-    id = lookup_image (SELECTED_FRAME (), spec);
+  BLOCK_INPUT;
+  kb = XkbGetKeyboard (dpy, XkbAllComponentsMask, XkbUseCoreKbd);
+  if (kb)
+    {
+      int delete_keycode = 0, backspace_keycode = 0, i;
+      
+      for (i = kb->min_key_code;
+          (i < kb->max_key_code
+           && (delete_keycode == 0 || backspace_keycode == 0));
+          ++i)
+       {
+         /* The XKB symbolic key names can be seen most easily
+            in the PS file generated by `xkbprint -label name $DISPLAY'.  */
+         if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
+           delete_keycode = i;
+         else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
+           backspace_keycode = i;
+       }
 
 
-  debug_print (spec);
-  return make_number (id);
+      XkbFreeKeyboard (kb, XkbAllComponentsMask, True);
+  
+      if (delete_keycode
+         && backspace_keycode
+         && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
+         && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
+       have_keys = Qt;
+    }
+  UNBLOCK_INPUT;
+  return have_keys;
+#else /* not HAVE_XKBGETKEYBOARD */
+  return Qnil;
+#endif /* not HAVE_XKBGETKEYBOARD */
 }
 
 }
 
-#endif /* GLYPH_DEBUG != 0 */
-
 
 \f
 /***********************************************************************
 
 \f
 /***********************************************************************
@@ -10206,19 +11208,40 @@ syms_of_xfns ()
   staticpro (&Quser_position);
   Quser_size = intern ("user-size");
   staticpro (&Quser_size);
   staticpro (&Quser_position);
   Quser_size = intern ("user-size");
   staticpro (&Quser_size);
-  Qdisplay = intern ("display");
-  staticpro (&Qdisplay);
   Qscroll_bar_foreground = intern ("scroll-bar-foreground");
   staticpro (&Qscroll_bar_foreground);
   Qscroll_bar_background = intern ("scroll-bar-background");
   staticpro (&Qscroll_bar_background);
   Qscreen_gamma = intern ("screen-gamma");
   staticpro (&Qscreen_gamma);
   Qscroll_bar_foreground = intern ("scroll-bar-foreground");
   staticpro (&Qscroll_bar_foreground);
   Qscroll_bar_background = intern ("scroll-bar-background");
   staticpro (&Qscroll_bar_background);
   Qscreen_gamma = intern ("screen-gamma");
   staticpro (&Qscreen_gamma);
+  Qline_spacing = intern ("line-spacing");
+  staticpro (&Qline_spacing);
+  Qcenter = intern ("center");
+  staticpro (&Qcenter);
+  Qcompound_text = intern ("compound-text");
+  staticpro (&Qcompound_text);
   /* This is the end of symbol initialization.  */
 
   /* This is the end of symbol initialization.  */
 
+  /* Text property `display' should be nonsticky by default.  */
+  Vtext_property_default_nonsticky
+    = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
+
+
   Qlaplace = intern ("laplace");
   staticpro (&Qlaplace);
   Qlaplace = intern ("laplace");
   staticpro (&Qlaplace);
-  
+  Qemboss = intern ("emboss");
+  staticpro (&Qemboss);
+  Qedge_detection = intern ("edge-detection");
+  staticpro (&Qedge_detection);
+  Qheuristic = intern ("heuristic");
+  staticpro (&Qheuristic);
+  QCmatrix = intern (":matrix");
+  staticpro (&QCmatrix);
+  QCcolor_adjustment = intern (":color-adjustment");
+  staticpro (&QCcolor_adjustment);
+  QCmask = intern (":mask");
+  staticpro (&QCmask);
   Qface_set_after_frame_default = intern ("face-set-after-frame-default");
   staticpro (&Qface_set_after_frame_default);
 
   Qface_set_after_frame_default = intern ("face-set-after-frame-default");
   staticpro (&Qface_set_after_frame_default);
 
@@ -10229,6 +11252,12 @@ syms_of_xfns ()
 
   init_x_parm_symbols ();
 
 
   init_x_parm_symbols ();
 
+  DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
+    "Non-nil means always draw a cross over disabled images.\n\
+Disabled images are those having an `:algorithm disabled' property.\n\
+A cross is always drawn on black & white displays.");
+  cross_disabled_images = 0;
+
   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
     "List of directories to search for bitmap files for X.");
   Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
   DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
     "List of directories to search for bitmap files for X.");
   Vx_bitmap_file_path = decode_env_path ((char *) 0, PATH_BITMAPS);
@@ -10280,6 +11309,11 @@ or when you set the mouse color.");
     "Non-zero means Emacs displays a busy cursor on window systems.");
   display_busy_cursor_p = 1;
   
     "Non-zero means Emacs displays a busy cursor on window systems.");
   display_busy_cursor_p = 1;
   
+  DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
+     "*Seconds to wait before displaying a busy-cursor.\n\
+Value must be an integer or float.");
+  Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
+
 #if 0 /* This doesn't really do anything.  */
   DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
              "The shape of the pointer when over the mode line.\n\
 #if 0 /* This doesn't really do anything.  */
   DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
              "The shape of the pointer when over the mode line.\n\
@@ -10295,6 +11329,13 @@ This variable takes effect when you create a new frame\n\
 or when you set the mouse color.");
   Vx_sensitive_text_pointer_shape = Qnil;
 
 or when you set the mouse color.");
   Vx_sensitive_text_pointer_shape = Qnil;
 
+  DEFVAR_LISP ("x-window-horizontal-drag-cursor",
+             &Vx_window_horizontal_drag_shape,
+  "Pointer shape to use for indicating a window can be dragged horizontally.\n\
+This variable takes effect when you create a new frame\n\
+or when you set the mouse color.");
+  Vx_window_horizontal_drag_shape = Qnil;
+
   DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
               "A string indicating the foreground color of the cursor box.");
   Vx_cursor_fore_pixel = Qnil;
   DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
               "A string indicating the foreground color of the cursor box.");
   Vx_cursor_fore_pixel = Qnil;
@@ -10324,11 +11365,6 @@ from the image cache.  Value must be an integer or nil with nil\n\
 meaning don't clear the cache.");
   Vimage_cache_eviction_delay = make_number (30 * 60);
 
 meaning don't clear the cache.");
   Vimage_cache_eviction_delay = make_number (30 * 60);
 
-  DEFVAR_LISP ("image-types", &Vimage_types,
-     "List of supported image types.\n\
-Each element of the list is a symbol for a supported image type.");
-  Vimage_types = Qnil;
-
 #ifdef USE_X_TOOLKIT
   Fprovide (intern ("x-toolkit"));
 #endif
 #ifdef USE_X_TOOLKIT
   Fprovide (intern ("x-toolkit"));
 #endif
@@ -10343,16 +11379,10 @@ Each element of the list is a symbol for a supported image type.");
   defsubr (&Sx_delete_window_property);
   defsubr (&Sx_window_property);
 
   defsubr (&Sx_delete_window_property);
   defsubr (&Sx_window_property);
 
-#if 0
-  defsubr (&Sx_draw_rectangle);
-  defsubr (&Sx_erase_rectangle);
-  defsubr (&Sx_contour_region);
-  defsubr (&Sx_uncontour_region);
-#endif
-  defsubr (&Sx_display_color_p);
+  defsubr (&Sxw_display_color_p);
   defsubr (&Sx_display_grayscale_p);
   defsubr (&Sx_display_grayscale_p);
-  defsubr (&Sx_color_defined_p);
-  defsubr (&Sx_color_values);
+  defsubr (&Sxw_color_defined_p);
+  defsubr (&Sxw_color_values);
   defsubr (&Sx_server_max_request_size);
   defsubr (&Sx_server_vendor);
   defsubr (&Sx_server_version);
   defsubr (&Sx_server_max_request_size);
   defsubr (&Sx_server_vendor);
   defsubr (&Sx_server_version);
@@ -10366,23 +11396,15 @@ Each element of the list is a symbol for a supported image type.");
   defsubr (&Sx_display_visual_class);
   defsubr (&Sx_display_backing_store);
   defsubr (&Sx_display_save_under);
   defsubr (&Sx_display_visual_class);
   defsubr (&Sx_display_backing_store);
   defsubr (&Sx_display_save_under);
-#if 0
-  defsubr (&Sx_rebind_key);
-  defsubr (&Sx_rebind_keys);
-  defsubr (&Sx_track_pointer);
-  defsubr (&Sx_grab_pointer);
-  defsubr (&Sx_ungrab_pointer);
-#endif
   defsubr (&Sx_parse_geometry);
   defsubr (&Sx_create_frame);
   defsubr (&Sx_parse_geometry);
   defsubr (&Sx_create_frame);
-#if 0
-  defsubr (&Sx_horizontal_line);
-#endif
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);
   defsubr (&Sx_synchronize);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);
   defsubr (&Sx_synchronize);
-
+  defsubr (&Sx_focus_frame);
+  defsubr (&Sx_backspace_delete_keys_p);
+  
   /* Setting callback functions for fontset handler.  */
   get_font_info_func = x_get_font_info;
 
   /* Setting callback functions for fontset handler.  */
   get_font_info_func = x_get_font_info;
 
@@ -10408,8 +11430,6 @@ Each element of the list is a symbol for a supported image type.");
   staticpro (&QCheuristic_mask);
   QCcolor_symbols = intern (":color-symbols");
   staticpro (&QCcolor_symbols);
   staticpro (&QCheuristic_mask);
   QCcolor_symbols = intern (":color-symbols");
   staticpro (&QCcolor_symbols);
-  QCdata = intern (":data");
-  staticpro (&QCdata);
   QCascent = intern (":ascent");
   staticpro (&QCascent);
   QCmargin = intern (":margin");
   QCascent = intern (":ascent");
   staticpro (&QCascent);
   QCmargin = intern (":margin");
@@ -10428,8 +11448,6 @@ Each element of the list is a symbol for a supported image type.");
   staticpro (&QCpt_height);
   QCindex = intern (":index");
   staticpro (&QCindex);
   staticpro (&QCpt_height);
   QCindex = intern (":index");
   staticpro (&QCindex);
-  QCuser_data = intern (":user-data");
-  staticpro (&QCuser_data);
   Qpbm = intern ("pbm");
   staticpro (&Qpbm);
 
   Qpbm = intern ("pbm");
   staticpro (&Qpbm);
 
@@ -10459,22 +11477,18 @@ Each element of the list is a symbol for a supported image type.");
 #endif
 
   defsubr (&Sclear_image_cache);
 #endif
 
   defsubr (&Sclear_image_cache);
+  defsubr (&Simage_size);
+  defsubr (&Simage_mask_p);
 
 
-#if GLYPH_DEBUG
-  defsubr (&Simagep);
-  defsubr (&Slookup_image);
-#endif
-
-  /* Busy-cursor.  */
-  defsubr (&Sx_show_busy_cursor);
-  defsubr (&Sx_hide_busy_cursor);
-  busy_count = 0;
-  inhibit_busy_cursor = 0;
+  busy_cursor_atimer = NULL;
+  busy_cursor_shown_p = 0;
 
   defsubr (&Sx_show_tip);
   defsubr (&Sx_hide_tip);
 
   defsubr (&Sx_show_tip);
   defsubr (&Sx_hide_tip);
-  staticpro (&tip_timer);
   tip_timer = Qnil;
   tip_timer = Qnil;
+  staticpro (&tip_timer);
+  tip_frame = Qnil;
+  staticpro (&tip_frame);
 
 #ifdef USE_MOTIF
   defsubr (&Sx_file_dialog);
 
 #ifdef USE_MOTIF
   defsubr (&Sx_file_dialog);