(x_set_menu_bar_lines_1): Adjust window's orig_top and
[bpt/emacs.git] / src / xfns.c
index 4afa9d2..dafee87 100644 (file)
@@ -19,16 +19,8 @@ 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.  */
 
-/* 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 <signal.h>
 #include <config.h>
+#include <signal.h>
 #include <stdio.h>
 #include <math.h>
 
@@ -41,6 +33,7 @@ Boston, MA 02111-1307, USA.  */
 #include "frame.h"
 #include "window.h"
 #include "buffer.h"
+#include "intervals.h"
 #include "dispextern.h"
 #include "keyboard.h"
 #include "blockinput.h"
@@ -49,15 +42,13 @@ Boston, MA 02111-1307, USA.  */
 #include "fontset.h"
 #include "systime.h"
 #include "termhooks.h"
+#include "atimer.h"
 
 #ifdef HAVE_X_WINDOWS
 
-#ifdef STDC_HEADERS
-#include <stdlib.h>
-#else
-extern void abort ();
-#endif
 #include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 /* On some systems, the character-composition stuff is broken in X11R5.  */
 
@@ -251,7 +242,7 @@ Lisp_Object Qx_frame_parameter;
 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 Qscreen_gamma;
 
@@ -355,8 +346,10 @@ x_window_to_frame (dpyinfo, wdesc)
       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;
+      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)
@@ -384,34 +377,40 @@ x_any_window_to_frame (dpyinfo, wdesc)
      int wdesc;
 {
   Lisp_Object tail, frame;
-  struct frame *f;
+  struct frame *f, *found;
   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;
+      
       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.  */
@@ -431,11 +430,13 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc)
       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.  */
-      if (x->widget)
+      if (x->busy_window == wdesc)
+       return f;
+      else if (x->widget)
        {
          if (wdesc == XtWindow (x->widget) 
              || wdesc == XtWindow (x->column_widget) 
@@ -466,7 +467,7 @@ x_menubar_window_to_frame (dpyinfo, wdesc)
       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.  */
@@ -495,7 +496,7 @@ x_top_window_to_frame (dpyinfo, wdesc)
       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;
 
@@ -667,7 +668,7 @@ x_create_bitmap_from_file (f, file)
   /* XReadBitmapFile won't handle magic file names.  */
   if (fd == 0)
     return -1;
-  close (fd);
+  emacs_close (fd);
 
   filename = (char *) XSTRING (found)->data;
 
@@ -745,6 +746,7 @@ struct x_frame_parm_table
   void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
 };
 
+static void x_create_im P_ ((struct frame *));
 void x_set_foreground_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));
@@ -1235,7 +1237,7 @@ gamma_correct (f, color)
    If ALLOC is nonzero, allocate a new colormap cell.  */
 
 int
-defined_color (f, color, color_def, alloc)
+x_defined_color (f, color, color_def, alloc)
      FRAME_PTR f;
      char *color;
      XColor *color_def;
@@ -1246,7 +1248,7 @@ defined_color (f, color, color_def, alloc)
   Display *display = FRAME_X_DISPLAY (f);
 
   BLOCK_INPUT;
-  screen_colormap = DefaultColormap (display, XDefaultScreen (display));
+  screen_colormap = FRAME_X_COLORMAP (f);
 
   status = XParseColor (display, screen_colormap, color, color_def);
   if (status && alloc) 
@@ -1323,37 +1325,44 @@ defined_color (f, color, color_def, alloc)
     return 0;
 }
 
-/* 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
-x_decode_color (f, arg, def)
+x_decode_color (f, color_name, mono_color)
      FRAME_PTR f;
-     Lisp_Object arg;
-     int def;
+     Lisp_Object color_name;
+     int mono_color;
 {
   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);
-  else if (strcmp (XSTRING (arg)->data, "white") == 0)
+  else if (strcmp (XSTRING (color_name)->data, "white") == 0)
     return WHITE_PIX_DEFAULT (f);
+#endif
 
+  /* Return MONO_COLOR for monochrome frames.  */
   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.  */
-  if (defined_color (f, XSTRING (arg)->data, &cdef, 1))
+  if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
     return cdef.pixel;
 
   Fsignal (Qerror, Fcons (build_string ("undefined color"),
-                         Fcons (arg, Qnil)));
+                         Fcons (color_name, Qnil)));
 }
+
+
 \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.  */
@@ -1532,13 +1541,9 @@ x_set_mouse_color (f, arg, oldval)
 
     fore_color.pixel = f->output_data.x->mouse_pixel;
     back_color.pixel = mask_color;
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
+    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                 &fore_color);
-    XQueryColor (FRAME_X_DISPLAY (f),
-                DefaultColormap (FRAME_X_DISPLAY (f),
-                                 DefaultScreen (FRAME_X_DISPLAY (f))),
+    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                 &back_color);
     XRecolorCursor (FRAME_X_DISPLAY (f), cursor,
                    &fore_color, &back_color);
@@ -1910,6 +1915,11 @@ x_set_menu_bar_lines_1 (window, 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))
     x_set_menu_bar_lines_1 (w->vchild, n);
@@ -2513,8 +2523,6 @@ display_x_get_resource (dpyinfo, attribute, class, component, subclass)
   char *name_key;
   char *class_key;
 
-  check_x ();
-
   CHECK_STRING (attribute, 0);
   CHECK_STRING (class, 0);
 
@@ -3053,6 +3061,293 @@ hack_wm_protocols (f, widget)
   UNBLOCK_INPUT;
 }
 #endif
+
+
+\f
+/* Support routines for XIC (X Input Context).  */
+
+#ifdef HAVE_X_I18N
+
+static XFontSet xic_create_xfontset P_ ((struct frame *, char *));
+static XIMStyle best_xim_style P_ ((XIMStyles *, XIMStyles *));
+
+
+/* Supported XIM styles, ordered by preferenc.  */
+
+static XIMStyle supported_xim_styles[] =
+{
+  XIMPreeditPosition | XIMStatusArea,
+  XIMPreeditPosition | XIMStatusNothing,
+  XIMPreeditPosition | XIMStatusNone,
+  XIMPreeditNothing | XIMStatusArea,
+  XIMPreeditNothing | XIMStatusNothing,
+  XIMPreeditNothing | XIMStatusNone,
+  XIMPreeditNone | XIMStatusArea,
+  XIMPreeditNone | XIMStatusNothing,
+  XIMPreeditNone | XIMStatusNone,
+  0,
+};
+
+
+/* Create an X fontset on frame F with base font name
+   BASE_FONTNAME.. */
+
+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;
+}
+
+
+/* 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.  */
+
+static XIMStyle
+best_xim_style (user, xim)
+     XIMStyles *user;
+     XIMStyles *xim;
+{
+  int i, j;
+
+  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];
+
+  /* Return the default style.  */
+  return XIMPreeditNothing | XIMStatusNothing;
+}
+
+/* Create XIC for frame F. */
+
+void
+create_frame_xic (f)
+     struct frame *f;
+{
+#ifndef X_I18N_INHIBITED
+  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
+       {
+         struct fontset_info *fontsetp;
+         int len = 0;
+         int i;
+         
+         fontsetp = FRAME_FONTSET_DATA (f)->fontset_table[fontset];
+         for (i = 0; i <= MAX_CHARSET; i++)
+           if (fontsetp->fontname[i])
+             len += strlen (fontsetp->fontname[i]) + 1;
+         base_fontname = alloca (len);
+         strcpy (base_fontname, fontsetp->fontname[CHARSET_ASCII]);
+         for (i = MIN_CHARSET_OFFICIAL_DIMENSION1; i <= MAX_CHARSET; i++)
+           if (fontsetp->fontname[i])
+             {
+               strcat (base_fontname, ",");
+               strcat (base_fontname, fontsetp->fontname[i]);
+             }
+       }
+      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;
+#else /* X_I18N_INHIBITED */
+  FRAME_XIC (f) = NULL;
+  FRAME_XIC_STYLE (f) = 0;
+  FRAME_XIC_FONTSET (f) = NULL;
+#endif /* X_I18N_INHIBITED */
+}
+
+
+/* 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
 
@@ -3067,7 +3362,6 @@ x_window (f, window_prompting, minibuffer_only)
   XClassHint class_hints;
   XSetWindowAttributes attributes;
   unsigned long attribute_mask;
-
   Widget shell_widget;
   Widget pane_widget;
   Widget frame_widget;
@@ -3093,6 +3387,9 @@ x_window (f, window_prompting, minibuffer_only)
   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);
@@ -3105,8 +3402,14 @@ x_window (f, window_prompting, minibuffer_only)
                                  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 
@@ -3118,9 +3421,11 @@ x_window (f, window_prompting, minibuffer_only)
   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);
+  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;
  
@@ -3210,35 +3515,9 @@ x_window (f, window_prompting, minibuffer_only)
   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;
+  create_frame_xic (f);
+#endif
 
   f->output_data.x->wm_hints.input = True;
   f->output_data.x->wm_hints.flags |= InputHint;
@@ -3260,8 +3539,19 @@ x_window (f, window_prompting, minibuffer_only)
                   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;
+
+#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);
@@ -3311,11 +3601,9 @@ x_window (f)
   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)
@@ -3329,38 +3617,21 @@ x_window (f)
                     InputOutput, /* class */
                     FRAME_X_DISPLAY_INFO (f)->visual,
                     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
+  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 /* HAVE_X_I18N */
-
+  
   validate_x_resource_name ();
 
   class_hints.res_name = (char *) XSTRING (Vx_resource_name)->data;
@@ -3636,6 +3907,29 @@ This function is an internal primitive--use `make-frame' instead.")
   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))
@@ -3741,7 +4035,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"),
-                          "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"),
@@ -3770,9 +4064,6 @@ This function is an internal primitive--use `make-frame' instead.")
                       "menuBar", "MenuBar", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
                       "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);
@@ -3834,6 +4125,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);
+  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
@@ -3913,9 +4207,8 @@ x_get_focus_frame (frame)
 }
 
 \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;
 {
@@ -3924,18 +4217,14 @@ If FRAME is omitted or nil, use the selected frame.")
 
   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;
 }
 
-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;
 {
@@ -3944,7 +4233,7 @@ If FRAME is omitted or nil, use the selected frame.")
 
   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];
 
@@ -3957,11 +4246,8 @@ If FRAME is omitted or nil, use the selected frame.")
     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;
 {
@@ -5172,71 +5458,145 @@ See the documentation of `x-rebind-key' for more information.")
 }
 #endif /* HAVE_X11 */
 #endif /* 0 */
+
+\f
+/************************************************************************
+                             X Displays
+ ************************************************************************/
+
 \f
+/* Mapping visual names to visuals.  */
+
+static struct visual_class
+{
+  char *name;
+  int class;
+}
+visual_classes[] =
+{
+  {"StaticGray",       StaticGray},
+  {"GrayScale",                GrayScale},
+  {"StaticColor",      StaticColor},
+  {"PseudoColor",      PseudoColor},
+  {"TrueColor",                TrueColor},
+  {"DirectColor",      DirectColor},
+  NULL
+};
+
+
 #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;
 {
-  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);
+/* Select the visual that should be used on display DPYINFO.  Set
+   members of DPYINFO appropriately.  Called from x_term_init.  */
 
-#ifdef HAVE_X11R4
-  vinfo_template.visualid = XVisualIDFromVisual (v);
-#else
-  vinfo_template.visualid = v->visualid;
-#endif
+void
+select_visual (dpyinfo)
+     struct x_display_info *dpyinfo;
+{
+  Display *dpy = dpyinfo->display;
+  Screen *screen = dpyinfo->screen;
+  Lisp_Object value;
 
-  vinfo_template.screen = XScreenNumberOfScreen (screen);
+  /* See if a visual is specified.  */
+  value = display_x_get_resource (dpyinfo,
+                                 build_string ("visualClass"),
+                                 build_string ("VisualClass"),
+                                 Qnil, Qnil);
+  if (STRINGP (value))
+    {
+      /* 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)
+       {
+         dpyinfo->n_planes = atoi (dash + 1);
+         *dash = '\0';
+       }
+      else
+       /* We won't find a matching visual with depth 0, so that
+          an error will be printed below.  */
+       dpyinfo->n_planes = 0;
 
-  vinfo = XGetVisualInfo (dpy,
-                         VisualIDMask | VisualScreenMask, &vinfo_template,
-                         &n_visuals);
-  if (n_visuals != 1)
-    fatal ("Can't get proper X visual info");
+      /* 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;
+         }
 
-  if ((1 << vinfo->depth) == vinfo->colormap_size)
-    *depth = vinfo->depth;
+      /* 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 i = 0;
-      int n = vinfo->colormap_size - 1;
-      while (n)
+      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");
+
+      if ((1 << vinfo->depth) == vinfo->colormap_size)
+       dpyinfo->n_planes = vinfo->depth;
+      else
        {
-         n = n >> 1;
-         i++;
+         int i = 0;
+         int n = vinfo->colormap_size - 1;
+         while (n)
+           {
+             n = n >> 1;
+             i++;
+           }
+         dpyinfo->n_planes = i;
        }
-      *depth = i;
-    }
 
-  XFree ((char *) vinfo);
-  return v;
+      XFree ((char *) vinfo);
+    }
 }
 
+
 /* Return the X display structure for the display named NAME.
    Open a new connection if necessary.  */
 
@@ -5279,6 +5639,7 @@ x_display_info_for_name (name)
   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\
@@ -5440,8 +5801,9 @@ Lisp_Object Qxbm;
 
 /* Keywords.  */
 
-Lisp_Object QCtype, QCdata, QCascent, QCmargin, QCrelief;
 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 QCindex;
 
@@ -5460,8 +5822,8 @@ 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 int x_build_heuristic_mask P_ ((struct frame *, Lisp_Object,
-                                      struct image *, Lisp_Object));
+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
@@ -5578,10 +5940,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 *));
 
 
@@ -5589,17 +5949,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
-   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
-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;
-     int allow_other_keys_p;
 {
   int i;
   Lisp_Object plist;
@@ -5630,11 +5987,7 @@ parse_image_spec (spec, keywords, nkeywords, type, allow_other_keys_p)
          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.  */
@@ -5852,21 +6205,9 @@ x_clear_image (f, img)
       
   if (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;
-       }
+      BLOCK_INPUT;
+      x_free_colors (f, img->colors, img->ncolors);
+      UNBLOCK_INPUT;
       
       xfree (img->colors);
       img->colors = NULL;
@@ -5892,7 +6233,7 @@ x_alloc_image_color (f, img, color_name, dflt)
 
   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.  */
@@ -6115,10 +6456,7 @@ lookup_image (f, spec)
          /* Should we built a mask heuristically?  */
          heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
          if (img->pixmap && !img->mask && !NILP (heuristic_mask))
-           {
-             file = image_spec_value (spec, QCfile, NULL);
-             x_build_heuristic_mask (f, file, img, heuristic_mask);
-           }
+           x_build_heuristic_mask (f, img, heuristic_mask);
        }
     }
 
@@ -6199,9 +6537,8 @@ forall_images_in_image_cache (f, fn)
                            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));
 
@@ -6210,13 +6547,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
-   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
-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;
-     Lisp_Object file;
      int width, height, depth;
      XImage **ximg;
      Pixmap *pixmap;
@@ -6234,7 +6569,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)
     {
-      image_error ("Unable to allocate X image for %s", file, Qnil);
+      image_error ("Unable to allocate X image", Qnil, Qnil);
       return 0;
     }
 
@@ -6247,7 +6582,7 @@ x_create_x_image_and_pixmap (f, file, width, height, depth, ximg, pixmap)
     {
       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;
     }
 
@@ -6428,7 +6763,7 @@ xbm_image_p (object)
   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));
@@ -6762,7 +7097,7 @@ xbm_load_image_from_file (f, img, specified_file)
   file = x_find_image_file (specified_file);
   if (!STRINGP (file))
     {
-      image_error ("Cannot find image file %s", specified_file, Qnil);
+      image_error ("Cannot find image file `%s'", specified_file, Qnil);
       UNGCPRO;
       return 0;
     }
@@ -6808,7 +7143,7 @@ xbm_load_image_from_file (f, img, specified_file)
       UNBLOCK_INPUT;
     }
   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;
@@ -6844,7 +7179,7 @@ xbm_load (f, img)
 
       /* Parse the list specification.  */
       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.  */
@@ -6901,7 +7236,8 @@ xbm_load (f, img)
        success_p = 1;
       else
        {
-         image_error ("Unable to create pixmap for XBM image", Qnil, Qnil);
+         image_error ("Unable to create pixmap for XBM image `%s'",
+                      img->spec, Qnil);
          x_clear_image (f, img);
        }
 
@@ -7003,7 +7339,7 @@ xpm_image_p (object)
 {
   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
@@ -7030,8 +7366,10 @@ xpm_load (f, img)
   /* 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 |= XpmColormap;
   attrs.valuemask |= XpmReturnAllocPixels;
 #ifdef XpmAllocCloseColors
   attrs.alloc_close_colors = 1;
@@ -7086,7 +7424,7 @@ xpm_load (f, img)
       Lisp_Object file = x_find_image_file (specified_file);
       if (!STRINGP (file))
        {
-         image_error ("Cannot find image file %s", specified_file, Qnil);
+         image_error ("Cannot find image file `%s'", specified_file, Qnil);
          UNBLOCK_INPUT;
          return 0;
        }
@@ -7256,7 +7594,7 @@ lookup_rgb_color (f, r, g, b)
       color.blue = b;
       
       BLOCK_INPUT;
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       rc = x_alloc_nearest_color (f, cmap, &color);
       UNBLOCK_INPUT;
 
@@ -7303,7 +7641,7 @@ lookup_pixel_color (f, pixel)
 
       BLOCK_INPUT;
       
-      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+      cmap = FRAME_X_COLORMAP (f);
       color.pixel = pixel;
       XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
@@ -7421,7 +7759,7 @@ x_laplace (f, img)
      struct frame *f;
      struct image *img;
 {
-  Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+  Colormap cmap = FRAME_X_COLORMAP (f);
   XImage *ximg, *oimg;
   XColor *in[3];
   long *out;
@@ -7443,7 +7781,7 @@ x_laplace (f, img)
   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,
+  rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
                                    &oimg, &pixmap);
 
   /* Fill first two rows.  */
@@ -7509,9 +7847,8 @@ x_laplace (f, img)
    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;
-     Lisp_Object file;
      struct image *img;
      Lisp_Object how;
 {
@@ -7523,7 +7860,7 @@ x_build_heuristic_mask (f, file, img, how)
   BLOCK_INPUT;
   
   /* 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)
     {
@@ -7560,7 +7897,7 @@ x_build_heuristic_mask (f, file, img, how)
 
          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;
@@ -7617,7 +7954,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_scan_number P_ ((FILE *fp));
+static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
 
 /* The symbol `pbm' identifying images of this type.  */
 
@@ -7629,6 +7966,7 @@ enum pbm_keyword_index
 {
   PBM_TYPE,
   PBM_FILE,
+  PBM_DATA,
   PBM_ASCENT,
   PBM_MARGIN,
   PBM_RELIEF,
@@ -7643,7 +7981,8 @@ enum pbm_keyword_index
 static struct image_keyword pbm_format[PBM_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_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},
@@ -7673,40 +8012,43 @@ pbm_image_p (object)
   
   bcopy (pbm_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm, 0)
+  if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
       || (fmt[PBM_ASCENT].count 
          && XFASTINT (fmt[PBM_ASCENT].value) > 100))
     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
-pbm_scan_number (fp)
-     FILE *fp;
+pbm_scan_number (s, end)
+     unsigned char **s, *end;
 {
   int c, val = -1;
 
-  while (!feof (fp))
+  while (*s < end)
     {
       /* 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.  */
-         while ((c = fgetc (fp)) != EOF && c != '\n')
+         while (*s < end && (c = *(*s)++, c != '\n'))
            ;
        }
       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;
        }
@@ -7718,6 +8060,42 @@ pbm_scan_number (fp)
 }
 
 
+/* Read FILE into memory.  Value is a pointer to a buffer allocated
+   with xmalloc holding FILE's contents.  Value is null if an error
+   occured.  *SIZE is set to the size of the file.  */
+
+static char *
+pbm_read_file (file, size)
+     Lisp_Object file;
+     int *size;
+{
+  FILE *fp = NULL;
+  char *buf = NULL;
+  struct stat st;
+
+  if (stat (XSTRING (file)->data, &st) == 0
+      && (fp = fopen (XSTRING (file)->data, "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;
+}
+
+
 /* Load PBM image IMG for use on frame F.  */
 
 static int 
@@ -7725,50 +8103,60 @@ pbm_load (f, 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;
+  unsigned char *contents = NULL;
+  unsigned char *end, *p;
+  int size;
 
   specified_file = image_spec_value (img->spec, QCfile, NULL);
-  file = x_find_image_file (specified_file);
+  file = Qnil;
   GCPRO1 (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)
+  if (STRINGP (specified_file))
     {
-      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;
+       }
+
+      contents = pbm_read_file (file, &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;
     }
 
-  switch (magic[1])
+  switch (*p++)
     {
     case '1':
       raw_p = 0, type = PBM_MONO;
@@ -7795,40 +8183,33 @@ pbm_load (f, img)
       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.  */
-  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)
     {
-      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 (width < 0 || height < 0
+  if (width < 0
+      || height < 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))
     {
-      fclose (fp);
       UNBLOCK_INPUT;
-      UNGCPRO;
-      return 0;
+      goto error;
     }
   
   /* Initialize the color hash table.  */
@@ -7844,12 +8225,12 @@ pbm_load (f, img)
            if (raw_p)
              {
                if ((x & 7) == 0)
-                 c = fgetc (fp);
+                 c = *p++;
                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)
@@ -7864,31 +8245,29 @@ pbm_load (f, img)
            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)
              {
-               r = fgetc (fp);
-               g = fgetc (fp);
-               b = fgetc (fp);
+               r = *p++;
+               g = *p++;
+               b = *p++;
              }
            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)
              {
-               fclose (fp);
                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.
@@ -7900,8 +8279,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);
@@ -7916,6 +8293,7 @@ pbm_load (f, img)
   img->height = height;
 
   UNGCPRO;
+  xfree (contents);
   return 1;
 }
 
@@ -7943,6 +8321,7 @@ Lisp_Object Qpng;
 enum png_keyword_index
 {
   PNG_TYPE,
+  PNG_DATA,
   PNG_FILE,
   PNG_ASCENT,
   PNG_MARGIN,
@@ -7958,7 +8337,8 @@ enum png_keyword_index
 static struct image_keyword png_format[PNG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
@@ -7966,7 +8346,7 @@ static struct image_keyword png_format[PNG_LAST] =
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
 
-/* Structure describing the image type `gif'.  */
+/* Structure describing the image type `png'.  */
 
 static struct image_type png_type =
 {
@@ -7987,11 +8367,13 @@ png_image_p (object)
   struct image_keyword fmt[PNG_LAST];
   bcopy (png_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng, 1)
+  if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
       || (fmt[PNG_ASCENT].count 
          && XFASTINT (fmt[PNG_ASCENT].value) > 100))
     return 0;
-  return 1;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
 }
 
 
@@ -8018,6 +8400,35 @@ my_png_warning (png_ptr, msg)
   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.  */
@@ -8028,12 +8439,13 @@ png_load (f, img)
      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;
-  FILE *fp;
+  FILE *fp = NULL;
   png_byte sig[8];
   png_byte *pixels = NULL;
   png_byte **rows = NULL;
@@ -8045,36 +8457,62 @@ png_load (f, img)
   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);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   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;
+       }
 
-  /* Check PNG signature.  */
-  if (fread (sig, 1, sizeof sig, fp) != sizeof sig
-      || !png_check_sig (sig, sizeof sig))
+      /* 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))
+       {
+         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.  */
@@ -8082,7 +8520,7 @@ png_load (f, img)
                                    my_png_error, my_png_warning);
   if (!png_ptr)
     {
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
@@ -8091,7 +8529,7 @@ png_load (f, img)
   if (!info_ptr)
     {
       png_destroy_read_struct (&png_ptr, NULL, NULL);
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
@@ -8100,7 +8538,7 @@ png_load (f, img)
   if (!end_info)
     {
       png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
-      fclose (fp);
+      if (fp) fclose (fp);
       UNGCPRO;
       return 0;
     }
@@ -8114,14 +8552,17 @@ png_load (f, img)
         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.  */
-  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,
@@ -8157,10 +8598,13 @@ png_load (f, img)
 
   /* Tell the PNG lib to handle gamma correction for us.  */
 
+#if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
   if (png_get_sRGB (png_ptr, info_ptr, &intent))
     /* There is a special chunk in the image specifying the gamma.  */
     png_set_sRGB (png_ptr, info_ptr, intent);
-  else if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
+  else
+#endif
+  if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
     /* Image contains gamma information.  */
     png_set_gamma (png_ptr, screen_gamma, image_gamma);
   else
@@ -8189,7 +8633,7 @@ png_load (f, img)
          png_color_16 frame_background;
 
          BLOCK_INPUT;
-         cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+         cmap = FRAME_X_COLORMAP (f);
          color.pixel = FRAME_BACKGROUND_PIXEL (f);
          XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
          UNBLOCK_INPUT;
@@ -8227,13 +8671,16 @@ png_load (f, img)
   /* 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.  */
-  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))
     {
       UNBLOCK_INPUT;
@@ -8244,7 +8691,7 @@ png_load (f, img)
      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);
@@ -8360,6 +8807,7 @@ Lisp_Object Qjpeg;
 enum jpeg_keyword_index
 {
   JPEG_TYPE,
+  JPEG_DATA,
   JPEG_FILE,
   JPEG_ASCENT,
   JPEG_MARGIN,
@@ -8375,7 +8823,8 @@ enum jpeg_keyword_index
 static struct image_keyword jpeg_format[JPEG_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
@@ -8405,13 +8854,16 @@ jpeg_image_p (object)
   
   bcopy (jpeg_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg, 0)
+  if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
       || (fmt[JPEG_ASCENT].count 
          && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
     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;
@@ -8426,6 +8878,102 @@ my_error_exit (cinfo)
   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.  */
 
@@ -8437,7 +8985,8 @@ jpeg_load (f, img)
   struct jpeg_decompress_struct cinfo;
   struct my_jpeg_error_mgr mgr;
   Lisp_Object file, specified_file;
-  FILE *fp;
+  Lisp_Object specified_data;
+  FILE *fp = NULL;
   JSAMPARRAY buffer;
   int row_stride, x, y;
   XImage *ximg = NULL;
@@ -8448,26 +8997,31 @@ jpeg_load (f, img)
 
   /* 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);
-  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.  */
+  /* 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;
   cinfo.err = jpeg_std_error (&mgr.pub);
   
@@ -8478,12 +9032,13 @@ 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);
-         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.  */
-      fclose (fp);
+      if (fp)
+       fclose (fp);
       jpeg_destroy_decompress (&cinfo);
 
       BLOCK_INPUT;
@@ -8500,13 +9055,19 @@ jpeg_load (f, img)
     }
 
   /* 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_stdio_src (&cinfo, fp);
+
+  if (NILP (specified_data))
+    jpeg_stdio_src (&cinfo, 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.
-     Start decompression.  */
+        Start decompression.  */
   cinfo.quantize_colors = TRUE;
   jpeg_start_decompress (&cinfo);
   width = img->width = cinfo.output_width;
@@ -8515,8 +9076,7 @@ jpeg_load (f, img)
   BLOCK_INPUT;
 
   /* Create 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;
       longjmp (mgr.setjmp_buffer, 2);
@@ -8574,7 +9134,8 @@ jpeg_load (f, img)
   /* Clean up.  */
   jpeg_finish_decompress (&cinfo);
   jpeg_destroy_decompress (&cinfo);
-  fclose (fp);
+  if (fp)
+    fclose (fp);
   
   /* Put the image into the pixmap.  */
   x_put_x_image (f, ximg, img->pixmap, width, height);
@@ -8608,6 +9169,7 @@ Lisp_Object Qtiff;
 enum tiff_keyword_index
 {
   TIFF_TYPE,
+  TIFF_DATA,
   TIFF_FILE,
   TIFF_ASCENT,
   TIFF_MARGIN,
@@ -8623,7 +9185,8 @@ enum tiff_keyword_index
 static struct image_keyword tiff_format[TIFF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
@@ -8652,13 +9215,124 @@ tiff_image_p (object)
   struct image_keyword fmt[TIFF_LAST];
   bcopy (tiff_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff, 1)
+  if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
       || (fmt[TIFF_ASCENT].count 
          && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
     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;
+}
 
 /* Load TIFF image IMG for use on frame F.  Value is non-zero if
    successful.  */
@@ -8669,30 +9343,62 @@ tiff_load (f, img)
      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_memory_source memsrc;
 
   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);
-  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
@@ -8705,7 +9411,7 @@ tiff_load (f, img)
   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;
@@ -8714,8 +9420,7 @@ tiff_load (f, img)
   BLOCK_INPUT;
 
   /* 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);
@@ -8782,6 +9487,7 @@ Lisp_Object Qgif;
 enum gif_keyword_index
 {
   GIF_TYPE,
+  GIF_DATA,
   GIF_FILE,
   GIF_ASCENT,
   GIF_MARGIN,
@@ -8798,7 +9504,8 @@ enum gif_keyword_index
 static struct image_keyword gif_format[GIF_LAST] =
 {
   {":type",            IMAGE_SYMBOL_VALUE,                     1},
-  {":file",            IMAGE_STRING_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0},
   {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
@@ -8818,7 +9525,6 @@ static struct image_type gif_type =
   NULL
 };
 
-
 /* Return non-zero if OBJECT is a valid GIF image specification.  */
 
 static int
@@ -8828,11 +9534,45 @@ gif_image_p (object)
   struct image_keyword fmt[GIF_LAST];
   bcopy (gif_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif, 1)
+  if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
       || (fmt[GIF_ASCENT].count 
          && XFASTINT (fmt[GIF_ASCENT].value) > 100))
     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;
 }
 
 
@@ -8845,6 +9585,7 @@ gif_load (f, img)
      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;
@@ -8853,31 +9594,55 @@ gif_load (f, img)
   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);
-  file = x_find_image_file (specified_file);
+  specified_data = image_spec_value (img->spec, QCdata, NULL);
+  file = Qnil;
   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)
     {
-      image_error ("Error reading `%s'", file, Qnil);
+      image_error ("Error reading `%s'", img->spec, Qnil);
       DGifCloseFile (gif);
       UNGCPRO;
       return 0;
@@ -8887,7 +9652,8 @@ gif_load (f, img)
   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;
@@ -8899,8 +9665,7 @@ gif_load (f, img)
   BLOCK_INPUT;
 
   /* 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);
@@ -8952,23 +9717,37 @@ gif_load (f, img)
        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};
       static int interlace_increment[] = {8, 8, 4, 2};
       int pass, inc;
+      int row = interlace_start[0];
 
-      for (pass = 0; pass < 4; ++pass)
+      pass = 0;
+
+      for (y = 0; y < image_height; y++)
        {
-         inc = interlace_increment[pass];
-         for (y = interlace_start[pass]; y < image_height; y += inc)
-           for (x = 0; x < image_width; ++x)
-             {
-               unsigned i = gif->SavedImages[ino].RasterBits[y * image_width + x];
-               XPutPixel (ximg, x + image_left, y + image_top, 
-                          pixel_colors[i]);
-             }
+         if (row >= image_height)
+           {
+             row = interlace_start[++pass];
+             while (row >= image_height)
+               row = interlace_start[++pass];
+           }
+         
+         for (x = 0; x < image_width; x++)
+           {
+             int i = raster[(y * image_width) + x];
+             XPutPixel (ximg, x + image_left, row + image_top,
+                        pixel_colors[i]);
+           }
+         
+         row += interlace_increment[pass];
        }
     }
   else
@@ -8976,7 +9755,7 @@ gif_load (f, img)
       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]);
          }
     }
@@ -9086,7 +9865,7 @@ gs_image_p (object)
   
   bcopy (gs_format, fmt, sizeof fmt);
   
-  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript, 1)
+  if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
       || (fmt[GS_ASCENT].count 
          && XFASTINT (fmt[GS_ASCENT].value) > 100))
     return 0;
@@ -9152,8 +9931,7 @@ gs_load (f, img)
 
   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;
     }
     
@@ -9256,16 +10034,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)
-           {
-             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",
-                    image_spec_value (img->spec, QCfile, NULL), Qnil);
+                    img->spec, Qnil);
       
       UNBLOCK_INPUT;
     }
@@ -9382,106 +10156,162 @@ value.")
                                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.")
-  ()
+/* Default number of seconds to wait before displaying a busy
+   cursor.  */
+
+#define DEFAULT_BUSY_CURSOR_DELAY 1
+
+/* Function prototypes.  */
+
+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 ()
 {
-  ++busy_count;
-  if (busy_count == 1)
+  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 rest, frame;
+      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);
+}
+
+
+/* Cancel the busy cursor timer if active, hide a busy cursor if
+   shown.  */
+
+void
+cancel_busy_cursor ()
+{
+  if (busy_cursor_atimer)
+    {
+      cancel_atimer (busy_cursor_atimer);
+      busy_cursor_atimer = NULL;
+    }
+  
+  if (busy_cursor_shown_p)
+    hide_busy_cursor ();
+}
+
 
+/* Timer function of busy_cursor_atimer.  TIMER is equal to
+   busy_cursor_atimer.
+
+   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;
+
+  if (!busy_cursor_shown_p)
+    {
+      Lisp_Object rest, frame;
+  
+      BLOCK_INPUT;
+  
       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,
+                                  InputOnly,
+                                  CopyFromParent,
                                   mask, &attrs);
              }
-
+       
            XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-           UNBLOCK_INPUT;
+           XFlush (FRAME_X_DISPLAY (f));
          }
-    }
 
-  return Qnil;
+      busy_cursor_shown_p = 1;
+      UNBLOCK_INPUT;
+    }
 }
 
 
-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;
-{
-  Lisp_Object rest, frame;
-
-  if (busy_count == 0)
-    return Qnil;
-
-  if (!NILP (force) && busy_count != 0)
-    busy_count = 1;
-
-  --busy_count;
-  if (busy_count != 0)
-    return Qnil;
+/* Hide the busy cursor on all frames, if it is currently shown.  */
 
-  FOR_EACH_FRAME (rest, frame)
+static void
+hide_busy_cursor ()
+{
+  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)
        {
-         
-         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;
+         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;
+           }
        }
-    }
 
-  return Qnil;
+      busy_cursor_shown_p = 0;
+      UNBLOCK_INPUT;
+    }
 }
 
 
@@ -9684,8 +10514,8 @@ x_create_tip_frame (dpyinfo, parms)
     
     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
+    /* 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;
@@ -9750,7 +10580,7 @@ used to change the tooltip's appearance.\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;
+     Lisp_Object string, frame, parms, timeout;
 {
   struct frame *f;
   struct window *w;
@@ -9761,13 +10591,13 @@ TIMEOUT nil means use the default timeout of 5 seconds.")
   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);
 
-  GCPRO3 (string, parms, frame);
+  GCPRO4 (string, parms, frame, timeout);
 
   CHECK_STRING (string, 0);
   f = check_x_frame (frame);
@@ -9874,7 +10704,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"));
-  
+
+  UNGCPRO;
   return unbind_to (count, Qnil);
 }
 
@@ -10190,8 +11021,6 @@ syms_of_xfns ()
   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");
@@ -10200,6 +11029,11 @@ syms_of_xfns ()
   staticpro (&Qscreen_gamma);
   /* 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);
   
@@ -10264,6 +11098,11 @@ or when you set the mouse color.");
     "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\
@@ -10333,10 +11172,10 @@ Each element of the list is a symbol for a supported image type.");
   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_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);
@@ -10392,8 +11231,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);
-  QCdata = intern (":data");
-  staticpro (&QCdata);
   QCascent = intern (":ascent");
   staticpro (&QCascent);
   QCmargin = intern (":margin");
@@ -10447,11 +11284,8 @@ Each element of the list is a symbol for a supported image type.");
   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);