*** empty log message ***
[bpt/emacs.git] / src / xfns.c
index 9a17196..cc778d8 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for the X window system.
-   Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000
+   Copyright (C) 1989, 92, 93, 94, 95, 96, 1997, 1998, 1999, 2000, 2001
      Free Software Foundation.
 
 This file is part of GNU Emacs.
@@ -107,6 +107,14 @@ extern XFontStruct *xlwmenu_default_font;
 extern void free_frame_menubar ();
 extern double atof ();
 
+#ifdef USE_MOTIF
+
+/* LessTif/Motif version info.  */
+
+static Lisp_Object Vmotif_version_string;
+
+#endif /* USE_MOTIF */
+
 #endif /* USE_X_TOOLKIT */
 
 #define min(a,b) ((a) < (b) ? (a) : (b))
@@ -124,7 +132,7 @@ extern double atof ();
 
 int gray_bitmap_width = gray_width;
 int gray_bitmap_height = gray_height;
-unsigned char *gray_bitmap_bits = gray_bits;
+char *gray_bitmap_bits = gray_bits;
 
 /* The name we're using in resource queries.  Most often "emacs".  */
 
@@ -135,20 +143,25 @@ Lisp_Object Vx_resource_name;
 
 Lisp_Object Vx_resource_class;
 
-/* Non-zero means we're allowed to display a busy cursor.  */
+/* Non-zero means we're allowed to display an hourglass cursor.  */
 
-int display_busy_cursor_p;
+int display_hourglass_p;
 
 /* The background and shape of the mouse pointer, and shape when not
    over text or in the modeline.  */
 
 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
-Lisp_Object Vx_busy_pointer_shape;
+Lisp_Object Vx_hourglass_pointer_shape;
 
 /* The shape when over mouse-sensitive text.  */
 
 Lisp_Object Vx_sensitive_text_pointer_shape;
 
+/* If non-nil, the pointer shape to indicate that windows can be
+   dragged horizontally.  */
+
+Lisp_Object Vx_window_horizontal_drag_shape;
+
 /* Color of chars displayed in cursor box.  */
 
 Lisp_Object Vx_cursor_fore_pixel;
@@ -169,41 +182,6 @@ Lisp_Object Vx_bitmap_file_path;
 
 Lisp_Object Vx_pixel_size_width_font_regexp;
 
-/* Evaluate this expression to rebuild the section of syms_of_xfns
-   that initializes and staticpros the symbols declared below.  Note
-   that Emacs 18 has a bug that keeps C-x C-e from being able to
-   evaluate this expression.
-
-(progn
-  ;; Accumulate a list of the symbols we want to initialize from the
-  ;; declarations at the top of the file.
-  (goto-char (point-min))
-  (search-forward "/\*&&& symbols declared here &&&*\/\n")
-  (let (symbol-list)
-    (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
-      (setq symbol-list
-           (cons (buffer-substring (match-beginning 1) (match-end 1))
-                 symbol-list))
-      (forward-line 1))
-    (setq symbol-list (nreverse symbol-list))
-    ;; Delete the section of syms_of_... where we initialize the symbols.
-    (search-forward "\n  /\*&&& init symbols here &&&*\/\n")
-    (let ((start (point)))
-      (while (looking-at "^  Q")
-       (forward-line 2))
-      (kill-region start (point)))
-    ;; Write a new symbol initialization section.
-    (while symbol-list
-      (insert (format "  %s = intern (\"" (car symbol-list)))
-      (let ((start (point)))
-       (insert (substring (car symbol-list) 1))
-       (subst-char-in-region start (point) ?_ ?-))
-      (insert (format "\");\n  staticpro (&%s);\n" (car symbol-list)))
-      (setq symbol-list (cdr symbol-list)))))
-
-  */        
-
-/*&&& symbols declared here &&&*/
 Lisp_Object Qauto_raise;
 Lisp_Object Qauto_lower;
 Lisp_Object Qbar;
@@ -238,7 +216,8 @@ Lisp_Object Quser_size;
 extern Lisp_Object Qdisplay;
 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
 Lisp_Object Qscreen_gamma, Qline_spacing, Qcenter;
-Lisp_Object Qcompound_text;
+Lisp_Object Qcompound_text, Qcancel_timer;
+Lisp_Object Qwait_for_wm;
 
 /* The below are defined in frame.c.  */
 
@@ -250,6 +229,11 @@ extern Lisp_Object Vwindow_system_version;
 
 Lisp_Object Qface_set_after_frame_default;
 
+#if GLYPH_DEBUG
+int image_cache_refcount, dpyinfo_refcount;
+#endif
+
+
 \f
 /* Error if we are not connected to X.  */
 
@@ -346,7 +330,7 @@ x_window_to_frame (dpyinfo, wdesc)
       f = XFRAME (frame);
       if (!FRAME_X_P (f) || FRAME_X_DISPLAY_INFO (f) != dpyinfo)
        continue;
-      if (f->output_data.x->busy_window == wdesc)
+      if (f->output_data.x->hourglass_window == wdesc)
        return f;
 #ifdef USE_X_TOOLKIT
       if ((f->output_data.x->edit_widget 
@@ -390,7 +374,7 @@ x_any_window_to_frame (dpyinfo, wdesc)
        {
          /* This frame matches if the window is any of its widgets.  */
          x = f->output_data.x;
-         if (x->busy_window == wdesc)
+         if (x->hourglass_window == wdesc)
            found = f;
          else if (x->widget)
            {
@@ -432,7 +416,7 @@ x_non_menubar_window_to_frame (dpyinfo, wdesc)
        continue;
       x = f->output_data.x;
       /* This frame matches if the window is any of its widgets.  */
-      if (x->busy_window == wdesc)
+      if (x->hourglass_window == wdesc)
        return f;
       else if (x->widget)
        {
@@ -663,9 +647,6 @@ x_create_bitmap_from_file (f, file)
   fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
   if (fd < 0)
     return -1;
-  /* XReadBitmapFile won't handle magic file names.  */
-  if (fd == 0)
-    return -1;
   emacs_close (fd);
 
   filename = (char *) XSTRING (found)->data;
@@ -744,10 +725,13 @@ struct x_frame_parm_table
   void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
 };
 
+static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
+static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
+static void x_change_window_heights P_ ((Lisp_Object, int));
 static void x_disable_image P_ ((struct frame *, struct image *));
-static void x_create_im P_ ((struct frame *));
 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
+static void x_set_wait_for_wm P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
@@ -816,7 +800,8 @@ static struct x_frame_parm_table x_frame_parms[] =
   "scroll-bar-foreground",     x_set_scroll_bar_foreground,
   "scroll-bar-background",     x_set_scroll_bar_background,
   "screen-gamma",              x_set_screen_gamma,
-  "line-spacing",              x_set_line_spacing
+  "line-spacing",              x_set_line_spacing,
+  "wait-for-wm",               x_set_wait_for_wm
 };
 
 /* Attach the `x-frame-parameter' properties to
@@ -1302,8 +1287,9 @@ x_decode_color (f, color_name, mono_color)
   if (x_defined_color (f, XSTRING (color_name)->data, &cdef, 1))
     return cdef.pixel;
 
-  return Fsignal (Qerror, Fcons (build_string ("Undefined color"),
-                                Fcons (color_name, Qnil)));
+  Fsignal (Qerror, Fcons (build_string ("Undefined color"),
+                         Fcons (color_name, Qnil)));
+  return 0;
 }
 
 
@@ -1328,8 +1314,22 @@ x_set_line_spacing (f, new_value, old_value)
 }
 
 
+/* Change the `wait-for-wm' frame parameter of frame F.  OLD_VALUE is
+   the previous value of that parameter, NEW_VALUE is the new value.
+   See also the comment of wait_for_wm in struct x_output.  */
+
+static void
+x_set_wait_for_wm (f, new_value, old_value)
+     struct frame *f;
+     Lisp_Object new_value, old_value;
+{
+  f->output_data.x->wait_for_wm = !NILP (new_value);
+}
+
+
 /* Change the `screen-gamma' frame parameter of frame F.  OLD_VALUE is
-   the previous value of that parameter, NEW_VALUE is the new value.  */
+   the previous value of that parameter, NEW_VALUE is the new
+   value.  */
 
 static void
 x_set_screen_gamma (f, new_value, old_value)
@@ -1362,24 +1362,37 @@ x_set_foreground_color (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
-  unsigned long pixel
-    = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+  struct x_output *x = f->output_data.x;
+  unsigned long fg, old_fg;
 
-  unload_color (f, f->output_data.x->foreground_pixel);
-  f->output_data.x->foreground_pixel = pixel;
+  fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
+  old_fg = x->foreground_pixel;
+  x->foreground_pixel = fg;
 
   if (FRAME_X_WINDOW (f) != 0)
     {
+      Display *dpy = FRAME_X_DISPLAY (f);
+      
       BLOCK_INPUT;
-      XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
-                     f->output_data.x->foreground_pixel);
-      XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
-                     f->output_data.x->foreground_pixel);
+      XSetForeground (dpy, x->normal_gc, fg);
+      XSetBackground (dpy, x->reverse_gc, fg);
+
+      if (x->cursor_pixel == old_fg)
+       {
+         unload_color (f, x->cursor_pixel);
+         x->cursor_pixel = x_copy_color (f, fg);
+         XSetBackground (dpy, x->cursor_gc, x->cursor_pixel);
+       }
+      
       UNBLOCK_INPUT;
+      
       update_face_from_frame_parameter (f, Qforeground_color, arg);
+      
       if (FRAME_VISIBLE_P (f))
         redraw_frame (f);
     }
+      
+  unload_color (f, old_fg);
 }
 
 void
@@ -1387,34 +1400,38 @@ x_set_background_color (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
-  unsigned long pixel
-    = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
+  struct x_output *x = f->output_data.x;
+  unsigned long bg;
 
-  unload_color (f, f->output_data.x->background_pixel);
-  f->output_data.x->background_pixel = pixel;
+  bg = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
+  unload_color (f, x->background_pixel);
+  x->background_pixel = bg;
 
   if (FRAME_X_WINDOW (f) != 0)
     {
+      Display *dpy = FRAME_X_DISPLAY (f);
+      
       BLOCK_INPUT;
-      /* The main frame area.  */
-      XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc,
-                     f->output_data.x->background_pixel);
-      XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->reverse_gc,
-                     f->output_data.x->background_pixel);
-      XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
-                     f->output_data.x->background_pixel);
-      XSetWindowBackground (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                           f->output_data.x->background_pixel);
+      XSetBackground (dpy, x->normal_gc, bg);
+      XSetForeground (dpy, x->reverse_gc, bg);
+      XSetWindowBackground (dpy, FRAME_X_WINDOW (f), bg);
+      XSetForeground (dpy, x->cursor_gc, bg);
+
+#ifndef USE_TOOLKIT_SCROLL_BARS /* Turns out to be annoying with
+                                  toolkit scroll bars.  */
       {
        Lisp_Object bar;
-       for (bar = FRAME_SCROLL_BARS (f); !NILP (bar);
+       for (bar = FRAME_SCROLL_BARS (f);
+            !NILP (bar);
             bar = XSCROLL_BAR (bar)->next)
-         XSetWindowBackground (FRAME_X_DISPLAY (f),
-                               SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
-                               f->output_data.x->background_pixel);
+         {
+           Window window = SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar));
+           XSetWindowBackground (dpy, window, bg);
+         }
       }
-      UNBLOCK_INPUT;
+#endif /* USE_TOOLKIT_SCROLL_BARS */
 
+      UNBLOCK_INPUT;
       update_face_from_frame_parameter (f, Qbackground_color, arg);
 
       if (FRAME_VISIBLE_P (f))
@@ -1427,128 +1444,141 @@ x_set_mouse_color (f, arg, oldval)
      struct frame *f;
      Lisp_Object arg, oldval;
 {
+  struct x_output *x = f->output_data.x;
+  Display *dpy = FRAME_X_DISPLAY (f);
   Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
-  Cursor busy_cursor;
+  Cursor hourglass_cursor, horizontal_drag_cursor;
   int count;
   unsigned long pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
-  unsigned long mask_color = f->output_data.x->background_pixel;
+  unsigned long mask_color = x->background_pixel;
 
   /* Don't let pointers be invisible.  */
-  if (mask_color == pixel
-      && mask_color == f->output_data.x->background_pixel)
-    pixel = f->output_data.x->foreground_pixel;
+  if (mask_color == pixel)
+    {
+      x_free_colors (f, &pixel, 1);
+      pixel = x_copy_color (f, x->foreground_pixel);
+    }
 
-  unload_color (f, f->output_data.x->mouse_pixel);
-  f->output_data.x->mouse_pixel = pixel;
+  unload_color (f, x->mouse_pixel);
+  x->mouse_pixel = pixel;
 
   BLOCK_INPUT;
 
   /* It's not okay to crash if the user selects a screwy cursor.  */
-  count = x_catch_errors (FRAME_X_DISPLAY (f));
+  count = x_catch_errors (dpy);
 
-  if (!EQ (Qnil, Vx_pointer_shape))
+  if (!NILP (Vx_pointer_shape))
     {
       CHECK_NUMBER (Vx_pointer_shape, 0);
-      cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XINT (Vx_pointer_shape));
+      cursor = XCreateFontCursor (dpy, XINT (Vx_pointer_shape));
     }
   else
-    cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_xterm);
-  x_check_errors (FRAME_X_DISPLAY (f), "bad text pointer cursor: %s");
+    cursor = XCreateFontCursor (dpy, XC_xterm);
+  x_check_errors (dpy, "bad text pointer cursor: %s");
 
-  if (!EQ (Qnil, Vx_nontext_pointer_shape))
+  if (!NILP (Vx_nontext_pointer_shape))
     {
       CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
-      nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f),
-                                         XINT (Vx_nontext_pointer_shape));
+      nontext_cursor
+       = XCreateFontCursor (dpy, XINT (Vx_nontext_pointer_shape));
     }
   else
-    nontext_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_left_ptr);
-  x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s");
+    nontext_cursor = XCreateFontCursor (dpy, XC_left_ptr);
+  x_check_errors (dpy, "bad nontext pointer cursor: %s");
 
-  if (!EQ (Qnil, Vx_busy_pointer_shape))
+  if (!NILP (Vx_hourglass_pointer_shape))
     {
-      CHECK_NUMBER (Vx_busy_pointer_shape, 0);
-      busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f),
-                                      XINT (Vx_busy_pointer_shape));
+      CHECK_NUMBER (Vx_hourglass_pointer_shape, 0);
+      hourglass_cursor
+       = XCreateFontCursor (dpy, XINT (Vx_hourglass_pointer_shape));
     }
   else
-    busy_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_watch);
-  x_check_errors (FRAME_X_DISPLAY (f), "bad busy pointer cursor: %s");
+    hourglass_cursor = XCreateFontCursor (dpy, XC_watch);
+  x_check_errors (dpy, "bad hourglass pointer cursor: %s");
   
-  x_check_errors (FRAME_X_DISPLAY (f), "bad nontext pointer cursor: %s");
-  if (!EQ (Qnil, Vx_mode_pointer_shape))
+  x_check_errors (dpy, "bad nontext pointer cursor: %s");
+  if (!NILP (Vx_mode_pointer_shape))
     {
       CHECK_NUMBER (Vx_mode_pointer_shape, 0);
-      mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f),
-                                      XINT (Vx_mode_pointer_shape));
+      mode_cursor = XCreateFontCursor (dpy, XINT (Vx_mode_pointer_shape));
     }
   else
-    mode_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_xterm);
-  x_check_errors (FRAME_X_DISPLAY (f), "bad modeline pointer cursor: %s");
+    mode_cursor = XCreateFontCursor (dpy, XC_xterm);
+  x_check_errors (dpy, "bad modeline pointer cursor: %s");
 
-  if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
+  if (!NILP (Vx_sensitive_text_pointer_shape))
     {
       CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
       cross_cursor
-       = XCreateFontCursor (FRAME_X_DISPLAY (f),
-                            XINT (Vx_sensitive_text_pointer_shape));
+       = XCreateFontCursor (dpy, XINT (Vx_sensitive_text_pointer_shape));
+    }
+  else
+    cross_cursor = XCreateFontCursor (dpy, XC_crosshair);
+
+  if (!NILP (Vx_window_horizontal_drag_shape))
+    {
+      CHECK_NUMBER (Vx_window_horizontal_drag_shape, 0);
+      horizontal_drag_cursor
+       = XCreateFontCursor (dpy, XINT (Vx_window_horizontal_drag_shape));
     }
   else
-    cross_cursor = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_crosshair);
+    horizontal_drag_cursor
+      = XCreateFontCursor (dpy, XC_sb_h_double_arrow);
 
   /* Check and report errors with the above calls.  */
-  x_check_errors (FRAME_X_DISPLAY (f), "can't set cursor shape: %s");
-  x_uncatch_errors (FRAME_X_DISPLAY (f), count);
+  x_check_errors (dpy, "can't set cursor shape: %s");
+  x_uncatch_errors (dpy, count);
 
   {
     XColor fore_color, back_color;
 
-    fore_color.pixel = f->output_data.x->mouse_pixel;
+    fore_color.pixel = x->mouse_pixel;
+    x_query_color (f, &fore_color);
     back_color.pixel = mask_color;
-    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
-                &fore_color);
-    XQueryColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
-                &back_color);
-    XRecolorCursor (FRAME_X_DISPLAY (f), cursor,
-                   &fore_color, &back_color);
-    XRecolorCursor (FRAME_X_DISPLAY (f), nontext_cursor,
-                   &fore_color, &back_color);
-    XRecolorCursor (FRAME_X_DISPLAY (f), mode_cursor,
-                   &fore_color, &back_color);
-    XRecolorCursor (FRAME_X_DISPLAY (f), cross_cursor,
-                    &fore_color, &back_color);
-    XRecolorCursor (FRAME_X_DISPLAY (f), busy_cursor,
-                    &fore_color, &back_color);
+    x_query_color (f, &back_color);
+    
+    XRecolorCursor (dpy, cursor, &fore_color, &back_color);
+    XRecolorCursor (dpy, nontext_cursor, &fore_color, &back_color);
+    XRecolorCursor (dpy, mode_cursor, &fore_color, &back_color);
+    XRecolorCursor (dpy, cross_cursor, &fore_color, &back_color);
+    XRecolorCursor (dpy, hourglass_cursor, &fore_color, &back_color);
+    XRecolorCursor (dpy, horizontal_drag_cursor, &fore_color, &back_color);
   }
 
   if (FRAME_X_WINDOW (f) != 0)
-    XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
-
-  if (cursor != f->output_data.x->text_cursor && f->output_data.x->text_cursor != 0)
-    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->text_cursor);
-  f->output_data.x->text_cursor = cursor;
-
-  if (nontext_cursor != f->output_data.x->nontext_cursor
-      && f->output_data.x->nontext_cursor != 0)
-    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->nontext_cursor);
-  f->output_data.x->nontext_cursor = nontext_cursor;
-
-  if (busy_cursor != f->output_data.x->busy_cursor
-      && f->output_data.x->busy_cursor != 0)
-    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->busy_cursor);
-  f->output_data.x->busy_cursor = busy_cursor;
-
-  if (mode_cursor != f->output_data.x->modeline_cursor
-      && f->output_data.x->modeline_cursor != 0)
-    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->modeline_cursor);
-  f->output_data.x->modeline_cursor = mode_cursor;
+    XDefineCursor (dpy, FRAME_X_WINDOW (f), cursor);
+
+  if (cursor != x->text_cursor
+      && x->text_cursor != 0)
+    XFreeCursor (dpy, x->text_cursor);
+  x->text_cursor = cursor;
+
+  if (nontext_cursor != x->nontext_cursor
+      && x->nontext_cursor != 0)
+    XFreeCursor (dpy, x->nontext_cursor);
+  x->nontext_cursor = nontext_cursor;
+
+  if (hourglass_cursor != x->hourglass_cursor
+      && x->hourglass_cursor != 0)
+    XFreeCursor (dpy, x->hourglass_cursor);
+  x->hourglass_cursor = hourglass_cursor;
+
+  if (mode_cursor != x->modeline_cursor
+      && x->modeline_cursor != 0)
+    XFreeCursor (dpy, f->output_data.x->modeline_cursor);
+  x->modeline_cursor = mode_cursor;
   
-  if (cross_cursor != f->output_data.x->cross_cursor
-      && f->output_data.x->cross_cursor != 0)
-    XFreeCursor (FRAME_X_DISPLAY (f), f->output_data.x->cross_cursor);
-  f->output_data.x->cross_cursor = cross_cursor;
+  if (cross_cursor != x->cross_cursor
+      && x->cross_cursor != 0)
+    XFreeCursor (dpy, x->cross_cursor);
+  x->cross_cursor = cross_cursor;
 
-  XFlush (FRAME_X_DISPLAY (f));
+  if (horizontal_drag_cursor != x->horizontal_drag_cursor
+      && x->horizontal_drag_cursor != 0)
+    XFreeCursor (dpy, x->horizontal_drag_cursor);
+  x->horizontal_drag_cursor = horizontal_drag_cursor;
+
+  XFlush (dpy);
   UNBLOCK_INPUT;
 
   update_face_from_frame_parameter (f, Qmouse_color, arg);
@@ -1561,6 +1591,7 @@ x_set_cursor_color (f, arg, oldval)
 {
   unsigned long fore_pixel, pixel;
   int fore_pixel_allocated_p = 0, pixel_allocated_p = 0;
+  struct x_output *x = f->output_data.x;
 
   if (!NILP (Vx_cursor_fore_pixel))
     {
@@ -1569,13 +1600,13 @@ x_set_cursor_color (f, arg, oldval)
       fore_pixel_allocated_p = 1;
     }
   else
-    fore_pixel = f->output_data.x->background_pixel;
+    fore_pixel = x->background_pixel;
   
   pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
   pixel_allocated_p = 1;
 
   /* Make sure that the cursor color differs from the background color.  */
-  if (pixel == f->output_data.x->background_pixel)
+  if (pixel == x->background_pixel)
     {
       if (pixel_allocated_p)
        {
@@ -1583,7 +1614,7 @@ x_set_cursor_color (f, arg, oldval)
          pixel_allocated_p = 0;
        }
       
-      pixel = f->output_data.x->mouse_pixel;
+      pixel = x->mouse_pixel;
       if (pixel == fore_pixel)
        {
          if (fore_pixel_allocated_p)
@@ -1591,27 +1622,25 @@ x_set_cursor_color (f, arg, oldval)
              x_free_colors (f, &fore_pixel, 1);
              fore_pixel_allocated_p = 0;
            }
-         fore_pixel = f->output_data.x->background_pixel;
+         fore_pixel = x->background_pixel;
        }
     }
 
-  unload_color (f, f->output_data.x->cursor_foreground_pixel);
+  unload_color (f, x->cursor_foreground_pixel);
   if (!fore_pixel_allocated_p)
     fore_pixel = x_copy_color (f, fore_pixel);
-  f->output_data.x->cursor_foreground_pixel = fore_pixel;
+  x->cursor_foreground_pixel = fore_pixel;
 
-  unload_color (f, f->output_data.x->cursor_pixel);
+  unload_color (f, x->cursor_pixel);
   if (!pixel_allocated_p)
     pixel = x_copy_color (f, pixel);
-  f->output_data.x->cursor_pixel = pixel;
+  x->cursor_pixel = pixel;
 
   if (FRAME_X_WINDOW (f) != 0)
     {
       BLOCK_INPUT;
-      XSetBackground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
-                     f->output_data.x->cursor_pixel);
-      XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->cursor_gc,
-                     fore_pixel);
+      XSetBackground (FRAME_X_DISPLAY (f), x->cursor_gc, x->cursor_pixel);
+      XSetForeground (FRAME_X_DISPLAY (f), x->cursor_gc, fore_pixel);
       UNBLOCK_INPUT;
 
       if (FRAME_VISIBLE_P (f))
@@ -1819,6 +1848,7 @@ x_set_font (f, arg, oldval)
   Lisp_Object result;
   Lisp_Object fontset_name;
   Lisp_Object frame;
+  int old_fontset = f->output_data.x->fontset;
 
   CHECK_STRING (arg, 1);
 
@@ -1836,6 +1866,16 @@ x_set_font (f, arg, oldval)
     error ("The characters of the given font have varying widths");
   else if (STRINGP (result))
     {
+      if (STRINGP (fontset_name))
+       {
+         /* Fontset names are built from ASCII font names, so the
+            names may be equal despite there was a change.  */
+         if (old_fontset == f->output_data.x->fontset)
+           return;
+       }
+      else if (!NILP (Fequal (result, oldval)))
+       return;
+      
       store_frame_param (f, Qfont, result);
       recompute_basic_faces (f);
     }
@@ -1915,9 +1955,12 @@ x_set_visibility (f, value, oldval)
   else
     Fmake_frame_visible (frame);
 }
+
 \f
+/* Change window heights in windows rooted in WINDOW by N lines.  */
+
 static void
-x_set_menu_bar_lines_1 (window, n)
+x_change_window_heights (window, n)
   Lisp_Object window;
   int n;
 {
@@ -1933,13 +1976,13 @@ x_set_menu_bar_lines_1 (window, n)
 
   /* Handle just the top child in a vertical split.  */
   if (!NILP (w->vchild))
-    x_set_menu_bar_lines_1 (w->vchild, n);
+    x_change_window_heights (w->vchild, n);
 
   /* Adjust all children in a horizontal split.  */
   for (window = w->hchild; !NILP (window); window = w->next)
     {
       w = XWINDOW (window);
-      x_set_menu_bar_lines_1 (window, n);
+      x_change_window_heights (window, n);
     }
 }
 
@@ -1987,7 +2030,7 @@ x_set_menu_bar_lines (f, value, oldval)
     }
 #else /* not USE_X_TOOLKIT */
   FRAME_MENU_BAR_LINES (f) = nlines;
-  x_set_menu_bar_lines_1 (f->root_window, nlines - olines);
+  x_change_window_heights (f->root_window, nlines - olines);
 #endif /* not USE_X_TOOLKIT */
   adjust_glyphs (f);
 }
@@ -2004,7 +2047,12 @@ x_set_tool_bar_lines (f, value, oldval)
      struct frame *f;
      Lisp_Object value, oldval;
 {
-  int delta, nlines;
+  int delta, nlines, root_height;
+  Lisp_Object root_window;
+
+  /* Treat tool bars like menu bars.  */
+  if (FRAME_MINIBUF_ONLY_P (f))
+    return;
 
   /* Use VALUE only if an integer >= 0.  */
   if (INTEGERP (value) && XINT (value) >= 0)
@@ -2016,9 +2064,51 @@ x_set_tool_bar_lines (f, value, oldval)
   ++windows_or_buffers_changed;
 
   delta = nlines - FRAME_TOOL_BAR_LINES (f);
+
+  /* Don't resize the tool-bar to more than we have room for.  */
+  root_window = FRAME_ROOT_WINDOW (f);
+  root_height = XINT (XWINDOW (root_window)->height);
+  if (root_height - delta < 1)
+    {
+      delta = root_height - 1;
+      nlines = FRAME_TOOL_BAR_LINES (f) + delta;
+    }
+
   FRAME_TOOL_BAR_LINES (f) = nlines;
-  x_set_menu_bar_lines_1 (FRAME_ROOT_WINDOW (f), delta);
+  x_change_window_heights (root_window, delta);
   adjust_glyphs (f);
+  
+  /* We also have to make sure that the internal border at the top of
+     the frame, below the menu bar or tool bar, is redrawn when the
+     tool bar disappears.  This is so because the internal border is
+     below the tool bar if one is displayed, but is below the menu bar
+     if there isn't a tool bar.  The tool bar draws into the area
+     below the menu bar.  */
+  if (FRAME_X_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
+    {
+      updating_frame = f;
+      clear_frame ();
+      clear_current_matrices (f);
+      updating_frame = NULL;
+    }
+
+  /* If the tool bar gets smaller, the internal border below it
+     has to be cleared.  It was formerly part of the display
+     of the larger tool bar, and updating windows won't clear it.  */
+  if (delta < 0)
+    {
+      int height = FRAME_INTERNAL_BORDER_WIDTH (f);
+      int width = PIXEL_WIDTH (f);
+      int y = nlines * CANON_Y_UNIT (f);
+
+      BLOCK_INPUT;
+      x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                   0, y, width, height, False);
+      UNBLOCK_INPUT;
+
+      if (WINDOWP (f->tool_bar_window))
+       clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
+    }
 }
 
 
@@ -2135,6 +2225,8 @@ x_encode_text (string, coding_system, text_bytes, stringp)
   coding.mode |= CODING_MODE_LAST_BLOCK;
   if (coding.type == coding_type_iso2022)
     coding.flags |= CODING_FLAG_ISO_SAFE;
+  /* We suppress producing escape sequences for composition.  */
+  coding.composing = COMPOSITION_DISABLED;
   bufsize = encoding_buffer_size (&coding, bytes);
   buf = (unsigned char *) xmalloc (bufsize);
   encode_coding (&coding, str, buf, bytes, bufsize);
@@ -3232,6 +3324,8 @@ best_xim_style (user, xim)
 
 /* Create XIC for frame F. */
 
+static XIMStyle xic_style;
+
 void
 create_frame_xic (f)
      struct frame *f;
@@ -3239,7 +3333,6 @@ create_frame_xic (f)
   XIM xim;
   XIC xic = NULL;
   XFontSet xfs = NULL;
-  static XIMStyle xic_style;
 
   if (FRAME_XIC (f))
     return;
@@ -3869,20 +3962,20 @@ x_make_gc (f)
   gc_values.foreground = f->output_data.x->foreground_pixel;
   gc_values.background = f->output_data.x->background_pixel;
   gc_values.line_width = 0;    /* Means 1 using fast algorithm.  */
-  f->output_data.x->normal_gc = XCreateGC (FRAME_X_DISPLAY (f),
-                                      FRAME_X_WINDOW (f),
-                                      GCLineWidth | GCFont
-                                      | GCForeground | GCBackground,
-                                      &gc_values);
+  f->output_data.x->normal_gc
+    = XCreateGC (FRAME_X_DISPLAY (f),
+                FRAME_X_WINDOW (f),
+                GCLineWidth | GCFont | GCForeground | GCBackground,
+                &gc_values);
 
   /* Reverse video style.  */
   gc_values.foreground = f->output_data.x->background_pixel;
   gc_values.background = f->output_data.x->foreground_pixel;
-  f->output_data.x->reverse_gc = XCreateGC (FRAME_X_DISPLAY (f),
-                                       FRAME_X_WINDOW (f),
-                                       GCFont | GCForeground | GCBackground
-                                       | GCLineWidth,
-                                       &gc_values);
+  f->output_data.x->reverse_gc
+    = XCreateGC (FRAME_X_DISPLAY (f),
+                FRAME_X_WINDOW (f),
+                GCFont | GCForeground | GCBackground | GCLineWidth,
+                &gc_values);
 
   /* Cursor has cursor-color background, background-color foreground.  */
   gc_values.foreground = f->output_data.x->background_pixel;
@@ -3911,12 +4004,79 @@ x_make_gc (f)
        gray_bits, gray_width, gray_height,
        f->output_data.x->foreground_pixel,
        f->output_data.x->background_pixel,
-       DefaultDepth (FRAME_X_DISPLAY (f),
-                     XScreenNumberOfScreen (FRAME_X_SCREEN (f)))));
+       DefaultDepth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f))));
+
+  UNBLOCK_INPUT;
+}
+
+
+/* Free what was was allocated in x_make_gc.  */
+
+void
+x_free_gcs (f)
+     struct frame *f;
+{
+  Display *dpy = FRAME_X_DISPLAY (f);
+
+  BLOCK_INPUT;
+  
+  if (f->output_data.x->normal_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->normal_gc);
+      f->output_data.x->normal_gc = 0;
+    }
+
+  if (f->output_data.x->reverse_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->reverse_gc);
+      f->output_data.x->reverse_gc = 0;
+    }
+  
+  if (f->output_data.x->cursor_gc)
+    {
+      XFreeGC (dpy, f->output_data.x->cursor_gc);
+      f->output_data.x->cursor_gc = 0;
+    }
+
+  if (f->output_data.x->border_tile)
+    {
+      XFreePixmap (dpy, f->output_data.x->border_tile);
+      f->output_data.x->border_tile = 0;
+    }
 
   UNBLOCK_INPUT;
 }
 
+
+/* Handler for signals raised during x_create_frame and
+   x_create_top_frame.  FRAME is the frame which is partially
+   constructed.  */
+
+static Lisp_Object
+unwind_create_frame (frame)
+     Lisp_Object frame;
+{
+  struct frame *f = XFRAME (frame);
+
+  /* If frame is ``official'', nothing to do.  */
+  if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
+    {
+#if GLYPH_DEBUG
+      struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+#endif
+      
+      x_free_frame_resources (f);
+
+      /* Check that reference counts are indeed correct.  */
+      xassert (dpyinfo->reference_count == dpyinfo_refcount);
+      xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
+      return Qt;
+    }
+  
+  return Qnil;
+}
+
+
 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
        1, 1, 0,
   "Make a new X window, which is called a \"frame\" in Emacs terms.\n\
@@ -3937,7 +4097,7 @@ This function is an internal primitive--use `make-frame' instead.")
   int minibuffer_only = 0;
   long window_prompting = 0;
   int width, height;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   Lisp_Object display;
   struct x_display_info *dpyinfo = NULL;
@@ -4007,6 +4167,7 @@ This function is an internal primitive--use `make-frame' instead.")
   f->output_data.x->fontset = -1;
   f->output_data.x->scroll_bar_foreground_pixel = -1;
   f->output_data.x->scroll_bar_background_pixel = -1;
+  record_unwind_protect (unwind_create_frame, frame);
 
   f->icon_name
     = x_get_arg (dpyinfo, parms, Qicon_name, "iconName", "Title",
@@ -4015,6 +4176,10 @@ This function is an internal primitive--use `make-frame' instead.")
     f->icon_name = Qnil;
 
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
+#if GLYPH_DEBUG
+  image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
+  dpyinfo_refcount = dpyinfo->reference_count;
+#endif /* GLYPH_DEBUG */
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
@@ -4024,6 +4189,16 @@ This function is an internal primitive--use `make-frame' instead.")
   {
     Lisp_Object black;
     struct gcpro gcpro1;
+
+    /* Function x_decode_color can signal an error.  Make
+       sure to initialize color slots so that we won't try
+       to free colors we haven't allocated.  */
+    f->output_data.x->foreground_pixel = -1;
+    f->output_data.x->background_pixel = -1;
+    f->output_data.x->cursor_pixel = -1;
+    f->output_data.x->cursor_foreground_pixel = -1;
+    f->output_data.x->border_pixel = -1;
+    f->output_data.x->mouse_pixel = -1;
     
     black = build_string ("black");
     GCPRO1 (black);
@@ -4172,15 +4347,47 @@ This function is an internal primitive--use `make-frame' instead.")
   
   x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
                       "menuBar", "MenuBar", RES_TYPE_NUMBER);
-  x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
+  x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
                       "toolBar", "ToolBar", RES_TYPE_NUMBER);
   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
                       "bufferPredicate", "BufferPredicate",
                       RES_TYPE_SYMBOL);
   x_default_parameter (f, parms, Qtitle, Qnil,
                       "title", "Title", RES_TYPE_STRING);
+  x_default_parameter (f, parms, Qwait_for_wm, Qt,
+                      "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN);
 
   f->output_data.x->parent_desc = FRAME_X_DISPLAY_INFO (f)->root_window;
+
+  /* Add the tool-bar height to the initial frame height so that the
+     user gets a text display area of the size he specified with -g or
+     via .Xdefaults.  Later changes of the tool-bar height don't
+     change the frame size.  This is done so that users can create
+     tall Emacs frames without having to guess how tall the tool-bar
+     will get.  */
+  if (FRAME_TOOL_BAR_LINES (f))
+    {
+      int margin, relief, bar_height;
+      
+      relief = (tool_bar_button_relief > 0
+               ? tool_bar_button_relief
+               : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
+
+      if (INTEGERP (Vtool_bar_button_margin)
+         && XINT (Vtool_bar_button_margin) > 0)
+       margin = XFASTINT (Vtool_bar_button_margin);
+      else if (CONSP (Vtool_bar_button_margin)
+              && INTEGERP (XCDR (Vtool_bar_button_margin))
+              && XINT (XCDR (Vtool_bar_button_margin)) > 0)
+       margin = XFASTINT (XCDR (Vtool_bar_button_margin));
+      else
+       margin = 0;
+         
+      bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
+      f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
+    }
+
+  /* Compute the size of the X window.  */
   window_prompting = x_figure_window_size (f, parms);
 
   if (window_prompting & XNegative)
@@ -4203,14 +4410,7 @@ This function is an internal primitive--use `make-frame' instead.")
   tem = x_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
   f->no_split = minibuffer_only || EQ (tem, Qt);
 
-  /* Create the X widget or window.  Add the tool-bar height to the
-     initial frame height so that the user gets a text display area of
-     the size he specified with -g or via .Xdefaults.  Later changes
-     of the tool-bar height don't change the frame size.  This is done
-     so that users can create tall Emacs frames without having to
-     guess how tall the tool-bar will get.  */
-  f->height += FRAME_TOOL_BAR_LINES (f);
-
+  /* Create the X widget or window.  */
 #ifdef USE_X_TOOLKIT
   x_window (f, window_prompting, minibuffer_only);
 #else
@@ -4244,11 +4444,16 @@ This function is an internal primitive--use `make-frame' instead.")
      f->height.  */
   width = f->width;
   height = f->height;
+  
   f->height = 0;
   SET_FRAME_WIDTH (f, 0);
   change_frame_size (f, height, width, 1, 0, 0);
 
-  /* Set up faces after all frame parameters are known.  */
+  /* Set up faces after all frame parameters are known.  This call
+     also merges in face attributes specified for new frames.  If we
+     don't do this, the `menu' face for instance won't have the right
+     colors, and the menu bar won't appear in the specified colors for
+     new frames.  */
   call1 (Qface_set_after_frame_default, frame);
 
 #ifdef USE_X_TOOLKIT
@@ -4296,9 +4501,15 @@ This function is an internal primitive--use `make-frame' instead.")
     }
 
   UNGCPRO;
+
+  /* Make sure windows on this frame appear in calls to next-window
+     and similar functions.  */
+  Vwindow_list = Qnil;
+  
   return unbind_to (count, frame);
 }
 
+
 /* FRAME is used only to get a handle on the X display.  We don't pass the
    display info directly because we're called from frame.c, which doesn't
    know about that structure.  */
@@ -4869,7 +5080,7 @@ x_display_info_for_name (name)
 
   validate_x_resource_name ();
 
-  dpyinfo = x_term_init (name, (unsigned char *)0,
+  dpyinfo = x_term_init (name, (char *)0,
                         (char *) XSTRING (Vx_resource_name)->data);
 
   if (dpyinfo == 0)
@@ -5042,7 +5253,7 @@ Lisp_Object Qxbm;
 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 QCconversion, QCcolor_symbols, QCheuristic_mask;
 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
 
 /* Other symbols.  */
@@ -5114,11 +5325,22 @@ valid_image_p (object)
   
   if (CONSP (object) && EQ (XCAR (object), Qimage))
     {
-      Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
-      struct image_type *type = lookup_image_type (symbol);
-      
-      if (type)
-       valid_p = type->valid_p (object);
+      Lisp_Object tem;
+
+      for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
+       if (EQ (XCAR (tem), QCtype))
+         {
+           tem = XCDR (tem);
+           if (CONSP (tem) && SYMBOLP (XCAR (tem)))
+             {
+               struct image_type *type;
+               type = lookup_image_type (XCAR (tem));
+               if (type)
+                 valid_p = type->valid_p (object);
+             }
+           
+           break;
+         }
     }
 
   return valid_p;
@@ -5149,8 +5371,10 @@ enum image_value_type
 {
   IMAGE_DONT_CHECK_VALUE_TYPE,
   IMAGE_STRING_VALUE,
+  IMAGE_STRING_OR_NIL_VALUE,
   IMAGE_SYMBOL_VALUE,
   IMAGE_POSITIVE_INTEGER_VALUE,
+  IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
   IMAGE_NON_NEGATIVE_INTEGER_VALUE,
   IMAGE_ASCENT_VALUE,
   IMAGE_INTEGER_VALUE,
@@ -5245,6 +5469,11 @@ parse_image_spec (spec, keywords, nkeywords, type)
            return 0;
          break;
 
+       case IMAGE_STRING_OR_NIL_VALUE:
+         if (!STRINGP (value) && !NILP (value))
+           return 0;
+         break;
+
        case IMAGE_SYMBOL_VALUE:
          if (!SYMBOLP (value))
            return 0;
@@ -5255,6 +5484,15 @@ parse_image_spec (spec, keywords, nkeywords, type)
            return 0;
          break;
 
+       case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
+         if (INTEGERP (value) && XINT (value) >= 0)
+           break;
+         if (CONSP (value)
+             && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
+             && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
+           break;
+         return 0;
+
        case IMAGE_ASCENT_VALUE:
          if (SYMBOLP (value) && EQ (value, Qcenter))
            break;
@@ -5361,8 +5599,8 @@ or omitted means use the selected frame.")
       struct frame *f = check_x_frame (frame);
       int id = lookup_image (f, spec);
       struct image *img = IMAGE_FROM_ID (f, id);
-      int width = img->width + 2 * img->margin;
-      int height = img->height + 2 * img->margin;
+      int width = img->width + 2 * img->hmargin;
+      int height = img->height + 2 * img->vmargin;
   
       if (NILP (pixels))
        size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
@@ -5478,7 +5716,7 @@ prepare_image_for_display (f, img)
 
   /* If IMG doesn't have a pixmap yet, load it now, using the image
      type dependent loader function.  */
-  if (img->pixmap == 0 && !img->load_failed_p)
+  if (img->pixmap == None && !img->load_failed_p)
     img->load_failed_p = img->type->load (f, img) == 0;
 }
      
@@ -5491,13 +5729,18 @@ image_ascent (img, face)
      struct image *img;
      struct face *face;
 {
-  int height = img->height + img->margin;
+  int height = img->height + img->vmargin;
   int ascent;
 
   if (img->ascent == CENTERED_IMAGE_ASCENT)
     {
       if (face->font)
-       ascent = height / 2 - (face->font->descent - face->font->ascent) / 2;
+       /* This expression is arranged so that if the image can't be
+          exactly centered, it will be moved slightly up.  This is
+          because a typical font is `top-heavy' (due to the presence
+          uppercase letters), so the image placement should err towards
+          being top-heavy too.  It also just generally looks better.  */
+       ascent = (height + face->font->ascent - face->font->descent + 1) / 2;
       else
        ascent = height / 2;
     }
@@ -5513,39 +5756,59 @@ image_ascent (img, face)
                  Helper functions for X image types
  ***********************************************************************/
 
+static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
+                                int, int));
 static void x_clear_image P_ ((struct frame *f, struct image *img));
 static unsigned long x_alloc_image_color P_ ((struct frame *f,
                                              struct image *img,
                                              Lisp_Object color_name,
                                              unsigned long dflt));
 
-/* Free X resources of image IMG which is used on frame F.  */
+
+/* Clear X resources of image IMG on frame F.  PIXMAP_P non-zero means
+   free the pixmap if any.  MASK_P non-zero means clear the mask
+   pixmap if any.  COLORS_P non-zero means free colors allocated for
+   the image, if any.  */
 
 static void
-x_clear_image (f, img)
+x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
      struct frame *f;
      struct image *img;
+     int pixmap_p, mask_p, colors_p;
 {
-  if (img->pixmap)
+  if (pixmap_p && img->pixmap)
     {
-      BLOCK_INPUT;
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = 0;
-      UNBLOCK_INPUT;
+      img->pixmap = None;
+    }
+
+  if (mask_p && img->mask)
+    {
+      XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+      img->mask = None;
     }
       
-  if (img->ncolors)
+  if (colors_p && img->ncolors)
     {
-      BLOCK_INPUT;
       x_free_colors (f, img->colors, img->ncolors);
-      UNBLOCK_INPUT;
-      
       xfree (img->colors);
       img->colors = NULL;
       img->ncolors = 0;
     }
 }
 
+/* Free X resources of image IMG which is used on frame F.  */
+
+static void
+x_clear_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  BLOCK_INPUT;
+  x_clear_image_1 (f, img, 1, 1, 1);
+  UNBLOCK_INPUT;
+}
+
 
 /* Allocate color COLOR_NAME for image IMG on frame F.  If color
    cannot be allocated, use DFLT.  Add a newly allocated color to
@@ -5588,6 +5851,7 @@ x_alloc_image_color (f, img, color_name, dflt)
  ***********************************************************************/
 
 static void cache_image P_ ((struct frame *f, struct image *img));
+static void postprocess_image P_ ((struct frame *, struct image *));
 
 
 /* Return a new, initialized image cache that is allocated from the
@@ -5652,20 +5916,23 @@ clear_image_cache (f, force_p)
     {
       EMACS_TIME t;
       unsigned long old;
-      int i, any_freed_p = 0;
+      int i, nfreed;
 
       EMACS_GET_TIME (t);
       old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
+
+      /* Block input so that we won't be interrupted by a SIGIO
+        while being in an inconsistent state.  */
+      BLOCK_INPUT;
       
-      for (i = 0; i < c->used; ++i)
+      for (i = nfreed = 0; i < c->used; ++i)
        {
          struct image *img = c->images[i];
          if (img != NULL
-             && (force_p
-                 || (img->timestamp > old)))
+             && (force_p || img->timestamp < old))
            {
              free_image (f, img);
-             any_freed_p = 1;
+             ++nfreed;
            }
        }
 
@@ -5673,11 +5940,22 @@ clear_image_cache (f, force_p)
         Emacs was iconified for a longer period of time.  In that
         case, current matrices may still contain references to
         images freed above.  So, clear these matrices.  */
-      if (any_freed_p)
+      if (nfreed)
        {
-         clear_current_matrices (f);
+         Lisp_Object tail, frame;
+         
+         FOR_EACH_FRAME (tail, frame)
+           {
+             struct frame *f = XFRAME (frame);
+             if (FRAME_X_P (f)
+                 && FRAME_X_IMAGE_CACHE (f) == c)
+               clear_current_matrices (f);
+           }
+
          ++windows_or_buffers_changed;
        }
+
+      UNBLOCK_INPUT;
     }
 }
 
@@ -5705,6 +5983,81 @@ FRAME t means clear the image caches of all frames.")
 }
 
 
+/* Compute masks and transform image IMG on frame F, as specified
+   by the image's specification,  */
+
+static void
+postprocess_image (f, img)
+     struct frame *f;
+     struct image *img;
+{
+  /* Manipulation of the image's mask.  */
+  if (img->pixmap)
+    {
+      Lisp_Object conversion, spec;
+      Lisp_Object mask;
+
+      spec = img->spec;
+      
+      /* `:heuristic-mask t'
+        `:mask heuristic'
+        means build a mask heuristically.
+        `:heuristic-mask (R G B)'
+        `:mask (heuristic (R G B))'
+        means build a mask from color (R G B) in the
+        image.
+        `:mask nil'
+        means remove a mask, if any.  */
+             
+      mask = image_spec_value (spec, QCheuristic_mask, NULL);
+      if (!NILP (mask))
+       x_build_heuristic_mask (f, img, mask);
+      else
+       {
+         int found_p;
+                   
+         mask = image_spec_value (spec, QCmask, &found_p);
+                 
+         if (EQ (mask, Qheuristic))
+           x_build_heuristic_mask (f, img, Qt);
+         else if (CONSP (mask)
+                  && EQ (XCAR (mask), Qheuristic))
+           {
+             if (CONSP (XCDR (mask)))
+               x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
+             else
+               x_build_heuristic_mask (f, img, XCDR (mask));
+           }
+         else if (NILP (mask) && found_p && img->mask)
+           {
+             XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
+             img->mask = None;
+           }
+       }
+         
+      /* Should we apply an image transformation algorithm?  */
+      conversion = image_spec_value (spec, QCconversion, NULL);
+      if (EQ (conversion, Qdisabled))
+       x_disable_image (f, img);
+      else if (EQ (conversion, Qlaplace))
+       x_laplace (f, img);
+      else if (EQ (conversion, Qemboss))
+       x_emboss (f, img);
+      else if (CONSP (conversion)
+              && EQ (XCAR (conversion), Qedge_detection))
+       {
+         Lisp_Object tem;
+         tem = XCDR (conversion);
+         if (CONSP (tem))
+           x_edge_detection (f, img,
+                             Fplist_get (tem, QCmatrix),
+                             Fplist_get (tem, QCcolor_adjustment));
+       }
+    }
+}
+
+
 /* Return the id of image with Lisp specification SPEC on frame F.
    SPEC must be a valid Lisp image specification (see valid_image_p).  */
 
@@ -5738,6 +6091,8 @@ lookup_image (f, spec)
   /* If not found, create a new image and cache it.  */
   if (img == NULL)
     {
+      extern Lisp_Object Qpostscript;
+      
       BLOCK_INPUT;
       img = make_image (spec, hash);
       cache_image (f, img);
@@ -5762,7 +6117,6 @@ lookup_image (f, spec)
          /* Handle image type independent image attributes
             `:ascent ASCENT', `:margin MARGIN', `:relief RELIEF'.  */
          Lisp_Object ascent, margin, relief;
-         Lisp_Object file;
 
          ascent = image_spec_value (spec, QCascent, NULL);
          if (INTEGERP (ascent))
@@ -5772,83 +6126,30 @@ lookup_image (f, spec)
          
          margin = image_spec_value (spec, QCmargin, NULL);
          if (INTEGERP (margin) && XINT (margin) >= 0)
-           img->margin = XFASTINT (margin);
+           img->vmargin = img->hmargin = XFASTINT (margin);
+         else if (CONSP (margin) && INTEGERP (XCAR (margin))
+                  && INTEGERP (XCDR (margin)))
+           {
+             if (XINT (XCAR (margin)) > 0)
+               img->hmargin = XFASTINT (XCAR (margin));
+             if (XINT (XCDR (margin)) > 0)
+               img->vmargin = XFASTINT (XCDR (margin));
+           }
          
          relief = image_spec_value (spec, QCrelief, NULL);
          if (INTEGERP (relief))
            {
              img->relief = XINT (relief);
-             img->margin += abs (img->relief);
-           }
-
-         /* Manipulation of the image's mask.  */
-         if (img->pixmap)
-           {
-             /* `:heuristic-mask t'
-                `:mask heuristic'
-                       means build a mask heuristically.
-                `:heuristic-mask (R G B)'
-                `:mask (heuristic (R G B))'
-                       means build a mask from color (R G B) in the
-                       image.
-                `:mask nil'
-                       means remove a mask, if any.  */
-             
-             Lisp_Object mask;
-
-             mask = image_spec_value (spec, QCheuristic_mask, NULL);
-             if (!NILP (mask))
-               x_build_heuristic_mask (f, img, mask);
-             else
-               {
-                 int found_p;
-                   
-                 mask = image_spec_value (spec, QCmask, &found_p);
-                 
-                 if (EQ (mask, Qheuristic))
-                   x_build_heuristic_mask (f, img, Qt);
-                 else if (CONSP (mask)
-                          && EQ (XCAR (mask), Qheuristic))
-                   {
-                     if (CONSP (XCDR (mask)))
-                       x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
-                     else
-                       x_build_heuristic_mask (f, img, XCDR (mask));
-                   }
-                 else if (NILP (mask) && found_p && img->mask)
-                   {
-                     XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
-                     img->mask = 0;
-                   }
-               }
-           }
-         
-         /* Should we apply an image transformation algorithm?  */
-         if (img->pixmap)
-           {
-             Lisp_Object algorithm;
-
-             algorithm = image_spec_value (spec, QCalgorithm, NULL);
-             if (EQ (algorithm, Qdisabled))
-               x_disable_image (f, img);
-             else if (EQ (algorithm, Qlaplace))
-               x_laplace (f, img);
-             else if (EQ (algorithm, Qemboss))
-               x_emboss (f, img);
-             else if (CONSP (algorithm)
-                      && EQ (XCAR (algorithm), Qedge_detection))
-               {
-                 Lisp_Object tem;
-                 tem = XCDR (algorithm);
-                 if (CONSP (tem))
-                   x_edge_detection (f, img,
-                                     Fplist_get (tem, QCmatrix),
-                                     Fplist_get (tem, QCcolor_adjustment));
-               }
+             img->hmargin += abs (img->relief);
+             img->vmargin += abs (img->relief);
            }
 
+         /* Do image transformations and compute masks, unless we
+            don't have the image yet.  */
+         if (!EQ (*img->type->type, Qpostscript))
+           postprocess_image (f, img);
        }
-      
+
       UNBLOCK_INPUT;
       xassert (!interrupt_input_blocked);
     }
@@ -5971,7 +6272,7 @@ x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
 
   /* Allocate a pixmap of the same size.  */
   *pixmap = XCreatePixmap (display, window, width, height, depth);
-  if (*pixmap == 0)
+  if (*pixmap == None)
     {
       x_destroy_x_image (*ximg);
       *ximg = NULL;
@@ -6045,7 +6346,7 @@ x_find_image_file (file)
   /* Try to find FILE in data-directory, then x-bitmap-file-path.  */
   fd = openp (search_path, file, "", &file_found, 0);
   
-  if (fd < 0)
+  if (fd == -1)
     file_found = Qnil;
   else
     close (fd);
@@ -6136,12 +6437,12 @@ static struct image_keyword xbm_format[XBM_LAST] =
   {":width",           IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":height",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
   {":data",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":foreground",      IMAGE_STRING_VALUE,                     0},
-  {":background",      IMAGE_STRING_VALUE,                     0},
+  {":foreground",      IMAGE_STRING_OR_NIL_VALUE,              0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
@@ -6296,6 +6597,8 @@ xbm_scan (s, end, sval, ival)
      int *ival;
 {
   int c;
+
+ loop:
   
   /* Skip white space.  */
   while (*s < end && (c = *(*s)++, isspace (c)))
@@ -6358,6 +6661,18 @@ xbm_scan (s, end, sval, ival)
        *s = *s - 1;
       c = XBM_TK_IDENT;
     }
+  else if (c == '/' && **s == '*')
+    {
+      /* C-style comment.  */
+      ++*s;
+      while (**s && (**s != '*' || *(*s + 1) != '/'))
+       ++*s;
+      if (**s)
+       {
+         *s += 2;
+         goto loop;
+       }
+    }
 
   return c;
 }
@@ -6556,7 +6871,7 @@ xbm_load_image (f, img, contents, end)
                                       depth);
       xfree (data);
 
-      if (img->pixmap == 0)
+      if (img->pixmap == None)
        {
          x_clear_image (f, img);
          image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
@@ -6632,12 +6947,11 @@ xbm_load (f, img)
     {
       struct image_keyword fmt[XBM_LAST];
       Lisp_Object data;
-      unsigned char *bitmap_data;
       int depth;
       unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
       unsigned long background = FRAME_BACKGROUND_PIXEL (f);
       char *bits;
-      int parsed_p, height, width;
+      int parsed_p;
       int in_memory_file_p = 0;
 
       /* See if data looks like an in-memory XBM file.  */
@@ -6658,10 +6972,12 @@ xbm_load (f, img)
        }
 
       /* Get foreground and background colors, maybe allocate colors.  */
-      if (fmt[XBM_FOREGROUND].count)
+      if (fmt[XBM_FOREGROUND].count
+         && STRINGP (fmt[XBM_FOREGROUND].value))
        foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
                                          foreground);
-      if (fmt[XBM_BACKGROUND].count)
+      if (fmt[XBM_BACKGROUND].count
+         && STRINGP (fmt[XBM_BACKGROUND].value))
        background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
                                          background);
 
@@ -6759,9 +7075,9 @@ static struct image_keyword xpm_format[XPM_LAST] =
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":color-symbols",   IMAGE_DONT_CHECK_VALUE_TYPE,            0}
@@ -6790,9 +7106,12 @@ static struct image_type xpm_type =
 
 #ifdef ALLOC_XPM_COLORS
 
-static void xpm_init_color_cache P_ ((void));
+static void xpm_init_color_cache P_ ((struct frame *, XpmAttributes *));
 static void xpm_free_color_cache P_ ((void));
 static int xpm_lookup_color P_ ((struct frame *, char *, XColor *));
+static int xpm_color_bucket P_ ((char *));
+static struct xpm_cached_color *xpm_cache_color P_ ((struct frame *, char *,
+                                                    XColor *, int));
 
 /* An entry in a hash table used to cache color definitions of named
    colors.  This cache is necessary to speed up XPM image loading in
@@ -6817,16 +7136,32 @@ struct xpm_cached_color
 #define XPM_COLOR_CACHE_BUCKETS        1001
 struct xpm_cached_color **xpm_color_cache;
 
-
 /* Initialize the color cache.  */
 
 static void
-xpm_init_color_cache ()
+xpm_init_color_cache (f, attrs)
+     struct frame *f;
+     XpmAttributes *attrs;
 {
   size_t nbytes = XPM_COLOR_CACHE_BUCKETS * sizeof *xpm_color_cache;
   xpm_color_cache = (struct xpm_cached_color **) xmalloc (nbytes);
   memset (xpm_color_cache, 0, nbytes);
   init_color_table ();
+
+  if (attrs->valuemask & XpmColorSymbols)
+    {
+      int i;
+      XColor color;
+      
+      for (i = 0; i < attrs->numsymbols; ++i)
+       if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+                        attrs->colorsymbols[i].value, &color))
+         {
+           color.pixel = lookup_rgb_color (f, color.red, color.green,
+                                           color.blue);
+           xpm_cache_color (f, attrs->colorsymbols[i].name, &color, -1);
+         }
+    }
 }
 
 
@@ -6851,8 +7186,51 @@ xpm_free_color_cache ()
 }
 
 
-/* Look up color COLOR_NAME for frame F in the color cache.  If found,
-   return the cached definition in *COLOR.  Otherwise, make a new
+/* Return the bucket index for color named COLOR_NAME in the color
+   cache.  */
+
+static int
+xpm_color_bucket (color_name)
+     char *color_name;
+{
+  unsigned h = 0;
+  char *s;
+  
+  for (s = color_name; *s; ++s)
+    h = (h << 2) ^ *s;
+  return h %= XPM_COLOR_CACHE_BUCKETS;
+}
+
+
+/* On frame F, cache values COLOR for color with name COLOR_NAME.
+   BUCKET, if >= 0, is a precomputed bucket index.  Value is the cache
+   entry added.  */
+
+static struct xpm_cached_color *
+xpm_cache_color (f, color_name, color, bucket)
+     struct frame *f;
+     char *color_name;
+     XColor *color;
+     int bucket;
+{
+  size_t nbytes;
+  struct xpm_cached_color *p;
+  
+  if (bucket < 0)
+    bucket = xpm_color_bucket (color_name);
+      
+  nbytes = sizeof *p + strlen (color_name);
+  p = (struct xpm_cached_color *) xmalloc (nbytes);
+  strcpy (p->name, color_name);
+  p->color = *color;
+  p->next = xpm_color_cache[bucket];
+  xpm_color_cache[bucket] = p;
+  return p;
+}
+
+
+/* Look up color COLOR_NAME for frame F in the color cache.  If found,
+   return the cached definition in *COLOR.  Otherwise, make a new
    entry in the cache and allocate the color.  Value is zero if color
    allocation failed.  */
 
@@ -6862,13 +7240,8 @@ xpm_lookup_color (f, color_name, color)
      char *color_name;
      XColor *color;
 {
-  unsigned h = 0;
-  const char *s;
   struct xpm_cached_color *p;
-
-  for (s = color_name; *s; ++s)
-    h = (h << 2) ^ *s;
-  h %= XPM_COLOR_CACHE_BUCKETS;
+  int h = xpm_color_bucket (color_name);
 
   for (p = xpm_color_cache[h]; p; p = p->next)
     if (strcmp (p->name, color_name) == 0)
@@ -6879,17 +7252,11 @@ xpm_lookup_color (f, color_name, color)
   else if (XParseColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
                        color_name, color))
     {
-      size_t nbytes;
       color->pixel = lookup_rgb_color (f, color->red, color->green,
                                       color->blue);
-      nbytes = sizeof *p + strlen (color_name);
-      p = (struct xpm_cached_color *) xmalloc (nbytes);
-      strcpy (p->name, color_name);
-      p->color = *color;
-      p->next = xpm_color_cache[h];
-      xpm_color_cache[h] = p;
+      p = xpm_cache_color (f, color_name, color, h);
     }
-
+  
   return p != NULL;
 }
 
@@ -6977,7 +7344,7 @@ xpm_load (f, img)
      struct frame *f;
      struct image *img;
 {
-  int rc, i;
+  int rc;
   XpmAttributes attrs;
   Lisp_Object specified_file, color_symbols;
 
@@ -7047,7 +7414,7 @@ xpm_load (f, img)
   /* Create a pixmap for the image, either from a file, or from a
      string buffer containing data in the same format as an XPM file.  */
 #ifdef ALLOC_XPM_COLORS
-  xpm_init_color_cache ();
+  xpm_init_color_cache (f, &attrs);
 #endif
   
   specified_file = image_spec_value (img->spec, QCfile, NULL);
@@ -7078,6 +7445,8 @@ xpm_load (f, img)
 #ifdef ALLOC_XPM_COLORS
       img->colors = colors_in_color_table (&img->ncolors);
 #else /* not ALLOC_XPM_COLORS */
+      int i;
+
       img->ncolors = attrs.nalloc_pixels;
       img->colors = (unsigned long *) xmalloc (img->ncolors
                                               * sizeof *img->colors);
@@ -7269,7 +7638,7 @@ lookup_pixel_color (f, pixel)
 
       cmap = FRAME_X_COLORMAP (f);
       color.pixel = pixel;
-      XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
+      x_query_color (f, &color);
       rc = x_alloc_nearest_color (f, cmap, &color);
 
       if (rc)
@@ -7336,7 +7705,7 @@ static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
 
-/* Non-zero means draw a cross on images having `:algorithm
+/* Non-zero means draw a cross on images having `:conversion
    disabled'.  */
 
 int cross_disabled_images;
@@ -7397,8 +7766,7 @@ x_to_xcolors (f, img, rgb_p)
        p->pixel = XGetPixel (ximg, x, y);
 
       if (rgb_p)
-       XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
-                     row, img->width);
+       x_query_colors (f, row, img->width);
     }
 
   XDestroyImage (ximg);
@@ -7435,7 +7803,7 @@ x_from_xcolors (f, img, colors)
       }
 
   xfree (colors);
-  x_clear_image (f, img);
+  x_clear_image_1 (f, img, 1, 0, 1);
 
   x_put_x_image (f, oimg, pixmap, img->width, img->height);
   x_destroy_x_image (oimg);
@@ -7592,7 +7960,7 @@ x_disable_image (f, img)
      struct image *img;
 {
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
-  
+
   if (dpyinfo->n_planes >= 2)
     {
       /* Color (or grayscale).  Convert to gray, and equalize.  Just
@@ -7665,9 +8033,9 @@ x_build_heuristic_mask (f, img, how)
   if (img->mask)
     {
       XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
-      img->mask = 0;
+      img->mask = None;
     }
-  
+
   /* Create an image and pixmap serving as mask.  */
   rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
                                    &mask_img, &img->mask);
@@ -7778,6 +8146,8 @@ enum pbm_keyword_index
   PBM_ALGORITHM,
   PBM_HEURISTIC_MASK,
   PBM_MASK,
+  PBM_FOREGROUND,
+  PBM_BACKGROUND,
   PBM_LAST
 };
 
@@ -7790,11 +8160,13 @@ static struct image_keyword pbm_format[PBM_LAST] =
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
-  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
+  {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":foreground",      IMAGE_STRING_OR_NIL_VALUE,              0},
+  {":background",      IMAGE_STRING_OR_NIL_VALUE,              0}
 };
 
 /* Structure describing the image type `pbm'.  */
@@ -7983,6 +8355,21 @@ pbm_load (f, img)
   if (type == PBM_MONO)
     {
       int c = 0, g;
+      struct image_keyword fmt[PBM_LAST];
+      unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
+      unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
+
+      /* Parse the image specification.  */
+      bcopy (pbm_format, fmt, sizeof fmt);
+      parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
+      
+      /* Get foreground and background colors, maybe allocate colors.  */
+      if (fmt[PBM_FOREGROUND].count
+         && STRINGP (fmt[PBM_FOREGROUND].value))
+       fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
+      if (fmt[PBM_BACKGROUND].count
+         && STRINGP (fmt[PBM_BACKGROUND].value))
+       bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
       
       for (y = 0; y < height; ++y)
        for (x = 0; x < width; ++x)
@@ -7997,9 +8384,7 @@ pbm_load (f, img)
            else
              g = pbm_scan_number (&p, end);
 
-           XPutPixel (ximg, x, y, (g
-                                   ? FRAME_FOREGROUND_PIXEL (f)
-                                   : FRAME_BACKGROUND_PIXEL (f)));
+           XPutPixel (ximg, x, y, g ? fg : bg);
          }
     }
   else
@@ -8104,9 +8489,9 @@ static struct image_keyword png_format[PNG_LAST] =
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
@@ -8397,7 +8782,7 @@ png_load (f, img)
 
          cmap = FRAME_X_COLORMAP (f);
          color.pixel = FRAME_BACKGROUND_PIXEL (f);
-         XQueryColor (FRAME_X_DISPLAY (f), cmap, &color);
+         x_query_color (f, &color);
 
          bzero (&frame_background, sizeof frame_background);
          frame_background.red = color.red;
@@ -8452,7 +8837,7 @@ png_load (f, img)
     {
       x_destroy_x_image (ximg);
       XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
-      img->pixmap = 0;
+      img->pixmap = None;
       goto error;
     }
 
@@ -8581,9 +8966,9 @@ static struct image_keyword jpeg_format[JPEG_LAST] =
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversions",     IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
@@ -8936,9 +9321,9 @@ static struct image_keyword tiff_format[TIFF_LAST] =
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversions",     IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
@@ -9259,9 +9644,9 @@ static struct image_keyword gif_format[GIF_LAST] =
   {":data",            IMAGE_STRING_VALUE,                     0},
   {":file",            IMAGE_STRING_VALUE,                     0},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":image",           IMAGE_NON_NEGATIVE_INTEGER_VALUE,       0}
@@ -9477,7 +9862,7 @@ gif_load (f, img)
     {
       static int interlace_start[] = {0, 4, 2, 1};
       static int interlace_increment[] = {8, 8, 4, 2};
-      int pass, inc;
+      int pass;
       int row = interlace_start[0];
 
       pass = 0;
@@ -9572,9 +9957,9 @@ static struct image_keyword gs_format[GS_LAST] =
   {":loader",          IMAGE_FUNCTION_VALUE,                   0},
   {":bounding-box",    IMAGE_DONT_CHECK_VALUE_TYPE,            1},
   {":ascent",          IMAGE_ASCENT_VALUE,                     0},
-  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE,           0},
+  {":margin",          IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,   0},
   {":relief",          IMAGE_INTEGER_VALUE,                    0},
-  {":algorithm",       IMAGE_DONT_CHECK_VALUE_TYPE,            0},
+  {":conversion",      IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":heuristic-mask",  IMAGE_DONT_CHECK_VALUE_TYPE,            0},
   {":mask",            IMAGE_DONT_CHECK_VALUE_TYPE,            0}
 };
@@ -9672,7 +10057,7 @@ gs_load (f, img)
   img->height = in_height * FRAME_X_DISPLAY_INFO (f)->resy;
 
   /* Create the pixmap.  */
-  xassert (img->pixmap == 0);
+  xassert (img->pixmap == None);
   img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                               img->width, img->height,
                               DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
@@ -9732,9 +10117,13 @@ x_kill_gs_process (pixmap, f)
     if (c->images[i]->pixmap == pixmap)
       break;
 
+  /* Should someone in between have cleared the image cache, for
+     instance, give up.  */
+  if (i == c->used)
+    return;
+  
   /* Kill the GS process.  We should have found PIXMAP in the image
      cache and its image should contain a process object.  */
-  xassert (i < c->used);
   img = c->images[i];
   xassert (PROCESSP (img->data.lisp_val));
   Fkill_process (img->data.lisp_val, Qnil);
@@ -9791,6 +10180,12 @@ x_kill_gs_process (pixmap, f)
       
       UNBLOCK_INPUT;
     }
+
+  /* Now that we have the pixmap, compute mask and transform the
+     image if requested.  */
+  BLOCK_INPUT;
+  postprocess_image (f, img);
+  UNBLOCK_INPUT;
 }
 
 
@@ -9888,7 +10283,7 @@ value.")
                               &actual_type, &actual_format, 
                               &actual_size, &bytes_remaining, 
                               (unsigned char **) &tmp_data);
-      if (rc == Success)
+      if (rc == Success && tmp_data)
        prop_value = make_string (tmp_data, size);
 
       XFree (tmp_data);
@@ -9905,138 +10300,149 @@ value.")
  ***********************************************************************/
 
 /* If non-null, an asynchronous timer that, when it expires, displays
-   a busy cursor on all frames.  */
+   an hourglass cursor on all frames.  */
 
-static struct atimer *busy_cursor_atimer;
+static struct atimer *hourglass_atimer;
 
-/* Non-zero means a busy cursor is currently shown.  */
+/* Non-zero means an hourglass cursor is currently shown.  */
 
-static int busy_cursor_shown_p;
+static int hourglass_shown_p;
 
-/* Number of seconds to wait before displaying a busy cursor.  */
+/* Number of seconds to wait before displaying an hourglass cursor.  */
 
-static Lisp_Object Vbusy_cursor_delay;
+static Lisp_Object Vhourglass_delay;
 
-/* Default number of seconds to wait before displaying a busy
+/* Default number of seconds to wait before displaying an hourglass
    cursor.  */
 
-#define DEFAULT_BUSY_CURSOR_DELAY 1
+#define DEFAULT_HOURGLASS_DELAY 1
 
 /* Function prototypes.  */
 
-static void show_busy_cursor P_ ((struct atimer *));
-static void hide_busy_cursor P_ ((void));
+static void show_hourglass P_ ((struct atimer *));
+static void hide_hourglass P_ ((void));
 
 
-/* Cancel a currently active busy-cursor timer, and start a new one.  */
+/* Cancel a currently active hourglass timer, and start a new one.  */
 
 void
-start_busy_cursor ()
+start_hourglass ()
 {
   EMACS_TIME delay;
   int secs, usecs = 0;
   
-  cancel_busy_cursor ();
+  cancel_hourglass ();
 
-  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)
+  if (INTEGERP (Vhourglass_delay)
+      && XINT (Vhourglass_delay) > 0)
+    secs = XFASTINT (Vhourglass_delay);
+  else if (FLOATP (Vhourglass_delay)
+          && XFLOAT_DATA (Vhourglass_delay) > 0)
     {
       Lisp_Object tem;
-      tem = Ftruncate (Vbusy_cursor_delay, Qnil);
+      tem = Ftruncate (Vhourglass_delay, Qnil);
       secs = XFASTINT (tem);
-      usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
+      usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
     }
   else
-    secs = DEFAULT_BUSY_CURSOR_DELAY;
+    secs = DEFAULT_HOURGLASS_DELAY;
   
   EMACS_SET_SECS_USECS (delay, secs, usecs);
-  busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
-                                    show_busy_cursor, NULL);
+  hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
+                                    show_hourglass, NULL);
 }
 
 
-/* Cancel the busy cursor timer if active, hide a busy cursor if
+/* Cancel the hourglass cursor timer if active, hide a busy cursor if
    shown.  */
 
 void
-cancel_busy_cursor ()
+cancel_hourglass ()
 {
-  if (busy_cursor_atimer)
+  if (hourglass_atimer)
     {
-      cancel_atimer (busy_cursor_atimer);
-      busy_cursor_atimer = NULL;
+      cancel_atimer (hourglass_atimer);
+      hourglass_atimer = NULL;
     }
   
-  if (busy_cursor_shown_p)
-    hide_busy_cursor ();
+  if (hourglass_shown_p)
+    hide_hourglass ();
 }
 
 
-/* Timer function of busy_cursor_atimer.  TIMER is equal to
-   busy_cursor_atimer.
+/* Timer function of hourglass_atimer.  TIMER is equal to
+   hourglass_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.  */
+   Display an hourglass pointer on all frames by mapping the frames'
+   hourglass_window.  Set the hourglass_p flag in the frames'
+   output_data.x structure to indicate that an hourglass cursor is
+   shown on the frames.  */
 
 static void
-show_busy_cursor (timer)
+show_hourglass (timer)
      struct atimer *timer;
 {
   /* The timer implementation will cancel this timer automatically
-     after this function has run.  Set busy_cursor_atimer to null
+     after this function has run.  Set hourglass_atimer to null
      so that we know the timer doesn't have to be canceled.  */
-  busy_cursor_atimer = NULL;
+  hourglass_atimer = NULL;
 
-  if (!busy_cursor_shown_p)
+  if (!hourglass_shown_p)
     {
       Lisp_Object rest, frame;
   
       BLOCK_INPUT;
   
       FOR_EACH_FRAME (rest, frame)
-       if (FRAME_X_P (XFRAME (frame)))
-         {
-           struct frame *f = XFRAME (frame);
-       
-           f->output_data.x->busy_p = 1;
+       {
+         struct frame *f = XFRAME (frame);
+         
+         if (FRAME_LIVE_P (f) && FRAME_X_P (f) && FRAME_X_DISPLAY (f))
+           {
+             Display *dpy = FRAME_X_DISPLAY (f);
+             
+#ifdef USE_X_TOOLKIT
+             if (f->output_data.x->widget)
+#else
+             if (FRAME_OUTER_WINDOW (f))
+#endif
+               {
+                 f->output_data.x->hourglass_p = 1;
        
-           if (!f->output_data.x->busy_window)
-             {
-               unsigned long mask = CWCursor;
-               XSetWindowAttributes attrs;
+                 if (!f->output_data.x->hourglass_window)
+                   {
+                     unsigned long mask = CWCursor;
+                     XSetWindowAttributes attrs;
            
-               attrs.cursor = f->output_data.x->busy_cursor;
+                     attrs.cursor = f->output_data.x->hourglass_cursor;
            
-               f->output_data.x->busy_window
-                 = XCreateWindow (FRAME_X_DISPLAY (f),
-                                  FRAME_OUTER_WINDOW (f),
-                                  0, 0, 32000, 32000, 0, 0,
-                                  InputOnly,
-                                  CopyFromParent,
-                                  mask, &attrs);
-             }
+                     f->output_data.x->hourglass_window
+                       = XCreateWindow (dpy, FRAME_OUTER_WINDOW (f),
+                                        0, 0, 32000, 32000, 0, 0,
+                                        InputOnly,
+                                        CopyFromParent,
+                                        mask, &attrs);
+                   }
        
-           XMapRaised (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
-           XFlush (FRAME_X_DISPLAY (f));
-         }
+                 XMapRaised (dpy, f->output_data.x->hourglass_window);
+                 XFlush (dpy);
+               }
+           }
+       }
 
-      busy_cursor_shown_p = 1;
+      hourglass_shown_p = 1;
       UNBLOCK_INPUT;
     }
 }
 
 
-/* Hide the busy cursor on all frames, if it is currently shown.  */
+/* Hide the hourglass pointer on all frames, if it is currently
+   shown.  */
 
 static void
-hide_busy_cursor ()
+hide_hourglass ()
 {
-  if (busy_cursor_shown_p)
+  if (hourglass_shown_p)
     {
       Lisp_Object rest, frame;
 
@@ -10047,17 +10453,18 @@ hide_busy_cursor ()
       
          if (FRAME_X_P (f)
              /* Watch out for newly created frames.  */
-             && f->output_data.x->busy_window)
+             && f->output_data.x->hourglass_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.  */
+             XUnmapWindow (FRAME_X_DISPLAY (f),
+                           f->output_data.x->hourglass_window);
+             /* Sync here because XTread_socket looks at the
+                hourglass_p flag that is reset to zero below.  */
              XSync (FRAME_X_DISPLAY (f), False);
-             f->output_data.x->busy_p = 0;
+             f->output_data.x->hourglass_p = 0;
            }
        }
 
-      busy_cursor_shown_p = 0;
+      hourglass_shown_p = 0;
       UNBLOCK_INPUT;
     }
 }
@@ -10069,11 +10476,13 @@ hide_busy_cursor ()
  ***********************************************************************/
 
 static Lisp_Object x_create_tip_frame P_ ((struct x_display_info *,
-                                          Lisp_Object));
+                                          Lisp_Object, Lisp_Object));
+static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
+                               Lisp_Object, int, int, int *, int *));
      
-/* The frame of a currently visible tooltip, or null.  */
+/* The frame of a currently visible tooltip.  */
 
-struct frame *tip_frame;
+Lisp_Object tip_frame;
 
 /* If non-nil, a timer started that hides the last tooltip when it
    fires.  */
@@ -10081,22 +10490,58 @@ struct frame *tip_frame;
 Lisp_Object tip_timer;
 Window tip_window;
 
+/* If non-nil, a vector of 3 elements containing the last args
+   with which x-show-tip was called.  See there.  */
+
+Lisp_Object last_show_tip_args;
+
+/* Maximum size for tooltips; a cons (COLUMNS . ROWS).  */
+
+Lisp_Object Vx_max_tooltip_size;
+
+
+static Lisp_Object
+unwind_create_tip_frame (frame)
+     Lisp_Object frame;
+{
+  Lisp_Object deleted;
+
+  deleted = unwind_create_frame (frame);
+  if (EQ (deleted, Qt))
+    {
+      tip_window = None;
+      tip_frame = Qnil;
+    }
+  
+  return deleted;
+}
+
+
 /* Create a frame for a tooltip on the display described by DPYINFO.
-   PARMS is a list of frame parameters.  Value is the frame.  */
+   PARMS is a list of frame parameters.  TEXT is the string to
+   display in the tip frame.  Value is the frame.
+
+   Note that functions called here, esp. x_default_parameter can
+   signal errors, for instance when a specified color name is
+   undefined.  We have to make sure that we're in a consistent state
+   when this happens.  */
 
 static Lisp_Object
-x_create_tip_frame (dpyinfo, parms)
+x_create_tip_frame (dpyinfo, parms, text)
      struct x_display_info *dpyinfo;
-     Lisp_Object parms;
+     Lisp_Object parms, text;
 {
   struct frame *f;
   Lisp_Object frame, tem;
   Lisp_Object name;
   long window_prompting = 0;
   int width, height;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
   struct gcpro gcpro1, gcpro2, gcpro3;
   struct kboard *kb;
+  int face_change_count_before = face_change_count;
+  Lisp_Object buffer;
+  struct buffer *old_buffer;
 
   check_x ();
 
@@ -10120,10 +10565,25 @@ x_create_tip_frame (dpyinfo, parms)
 
   frame = Qnil;
   GCPRO3 (parms, name, frame);
-  tip_frame = f = make_frame (1);
+  f = make_frame (1);
   XSETFRAME (frame, f);
+
+  buffer = Fget_buffer_create (build_string (" *tip*"));
+  Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
+  old_buffer = current_buffer;
+  set_buffer_internal_1 (XBUFFER (buffer));
+  current_buffer->truncate_lines = Qnil;
+  Ferase_buffer ();
+  Finsert (1, &text);
+  set_buffer_internal_1 (old_buffer);
+  
   FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
+  record_unwind_protect (unwind_create_tip_frame, frame);
 
+  /* By setting the output method, we're essentially saying that
+     the frame is live, as per FRAME_LIVE_P.  If we get a signal
+     from this point on, x_destroy_window might screw up reference
+     counts etc.  */
   f->output_method = output_x_window;
   f->output_data.x = (struct x_output *) xmalloc (sizeof (struct x_output));
   bzero (f->output_data.x, sizeof (struct x_output));
@@ -10133,6 +10593,10 @@ x_create_tip_frame (dpyinfo, parms)
   f->output_data.x->scroll_bar_background_pixel = -1;
   f->icon_name = Qnil;
   FRAME_X_DISPLAY_INFO (f) = dpyinfo;
+#if GLYPH_DEBUG
+  image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
+  dpyinfo_refcount = dpyinfo->reference_count;
+#endif /* GLYPH_DEBUG */
 #ifdef MULTI_KBOARD
   FRAME_KBOARD (f) = kb;
 #endif
@@ -10177,8 +10641,8 @@ x_create_tip_frame (dpyinfo, parms)
       specbind (Qx_resource_name, name);
     }
 
-  /* Extract the window parameters from the supplied values
-     that are needed to determine window geometry.  */
+  /* Extract the window parameters from the supplied values that are
+     needed to determine window geometry.  */
   {
     Lisp_Object font;
 
@@ -10282,7 +10746,10 @@ x_create_tip_frame (dpyinfo, parms)
     unsigned long mask;
     
     BLOCK_INPUT;
-    mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
+    mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
+    if (DoesSaveUnders (dpyinfo->screen))
+      mask |= CWSaveUnder;
+    
     /* Window managers look at the override-redirect flag to determine
        whether or net to give windows a decoration (Xlib spec, chapter
        3.2.8).  */
@@ -10322,6 +10789,26 @@ x_create_tip_frame (dpyinfo, parms)
   SET_FRAME_WIDTH (f, 0);
   change_frame_size (f, height, width, 1, 0, 0);
 
+  /* Set up faces after all frame parameters are known.  This call
+     also merges in face attributes specified for new frames.
+
+     Frame parameters may be changed if .Xdefaults contains
+     specifications for the default font.  For example, if there is an
+     `Emacs.default.attributeBackground: pink', the `background-color'
+     attribute of the frame get's set, which let's the internal border
+     of the tooltip frame appear in pink.  Prevent this.  */
+  {
+    Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
+
+    /* Set tip_frame here, so that */
+    tip_frame = frame;
+    call1 (Qface_set_after_frame_default, frame);
+    
+    if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
+      Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
+                                             Qnil));
+  }
+  
   f->no_split = 1;
 
   UNGCPRO;
@@ -10335,10 +10822,69 @@ x_create_tip_frame (dpyinfo, parms)
      its display.  */
   FRAME_X_DISPLAY_INFO (f)->reference_count++;
 
+  /* Setting attributes of faces of the tooltip frame from resources
+     and similar will increment face_change_count, which leads to the
+     clearing of all current matrices.  Since this isn't necessary
+     here, avoid it by resetting face_change_count to the value it
+     had before we created the tip frame.  */
+  face_change_count = face_change_count_before;
+
+  /* Discard the unwind_protect.  */
   return unbind_to (count, frame);
 }
 
 
+/* Compute where to display tip frame F.  PARMS is the list of frame
+   parameters for F.  DX and DY are specified offsets from the current
+   location of the mouse.  WIDTH and HEIGHT are the width and height
+   of the tooltip.  Return coordinates relative to the root window of
+   the display in *ROOT_X, and *ROOT_Y.  */
+
+static void
+compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
+     struct frame *f;
+     Lisp_Object parms, dx, dy;
+     int width, height;
+     int *root_x, *root_y;
+{
+  Lisp_Object left, top;
+  int win_x, win_y;
+  Window root, child;
+  unsigned pmask;
+  
+  /* User-specified position?  */
+  left = Fcdr (Fassq (Qleft, parms));
+  top  = Fcdr (Fassq (Qtop, parms));
+  
+  /* Move the tooltip window where the mouse pointer is.  Resize and
+     show it.  */
+  if (!INTEGERP (left) && !INTEGERP (top))
+    {
+      BLOCK_INPUT;
+      XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
+                    &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
+      UNBLOCK_INPUT;
+    }
+
+  if (INTEGERP (top))
+    *root_y = XINT (top);
+  else if (*root_y + XINT (dy) - height < 0)
+    *root_y -= XINT (dy);
+  else
+    {
+      *root_y -= height;
+      *root_y += XINT (dy);
+    }
+
+  if (INTEGERP (left))
+    *root_x = XINT (left);
+  else if (*root_x + XINT (dx) + width > FRAME_X_DISPLAY_INFO (f)->width)
+    *root_x -= width + XINT (dx);
+  else
+    *root_x += XINT (dx);
+}
+
+
 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
   "Show STRING in a \"tooltip\" window on frame FRAME.\n\
 A tooltip window is a small X window displaying a string.\n\
@@ -10357,22 +10903,23 @@ displayed at the mouse position, with offset DX added (default is 5 if\n\
 DX isn't specified).  Likewise for the y-position; if a `top' frame\n\
 parameter is specified, it determines the y-position of the tooltip\n\
 window, otherwise it is displayed at the mouse position, with offset\n\
-DY added (default is -5).")
+DY added (default is -10).\n\
+\n\
+A tooltip's maximum size is specified by `x-max-tooltip-size'.\n\
+Text larger than the specified size is clipped.")
   (string, frame, parms, timeout, dx, dy)
      Lisp_Object string, frame, parms, timeout, dx, dy;
 {
   struct frame *f;
   struct window *w;
-  Window root, child;
-  Lisp_Object buffer, top, left;
+  Lisp_Object buffer, top, left, max_width, max_height;
+  int root_x, root_y;
   struct buffer *old_buffer;
   struct text_pos pos;
   int i, width, height;
-  int root_x, root_y, win_x, win_y;
-  unsigned pmask;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
-  int count = specpdl_ptr - specpdl;
+  int count = BINDING_STACK_SIZE ();
   
   specbind (Qinhibit_redisplay, Qt);
 
@@ -10391,13 +10938,50 @@ DY added (default is -5).")
     CHECK_NUMBER (dx, 5);
   
   if (NILP (dy))
-    dy = make_number (-5);
+    dy = make_number (-10);
   else
     CHECK_NUMBER (dy, 6);
 
+  if (NILP (last_show_tip_args))
+    last_show_tip_args = Fmake_vector (make_number (3), Qnil);
+
+  if (!NILP (tip_frame))
+    {
+      Lisp_Object last_string = AREF (last_show_tip_args, 0);
+      Lisp_Object last_frame = AREF (last_show_tip_args, 1);
+      Lisp_Object last_parms = AREF (last_show_tip_args, 2);
+
+      if (EQ (frame, last_frame)
+         && !NILP (Fequal (last_string, string))
+         && !NILP (Fequal (last_parms, parms)))
+       {
+         struct frame *f = XFRAME (tip_frame);
+         
+         /* Only DX and DY have changed.  */
+         if (!NILP (tip_timer))
+           {
+             Lisp_Object timer = tip_timer;
+             tip_timer = Qnil;
+             call1 (Qcancel_timer, timer);
+           }
+
+         BLOCK_INPUT;
+         compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
+                         PIXEL_HEIGHT (f), &root_x, &root_y);
+         XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                      root_x, root_y);
+         UNBLOCK_INPUT;
+         goto start_timer;
+       }
+    }
+
   /* Hide a previous tip, if any.  */
   Fx_hide_tip ();
 
+  ASET (last_show_tip_args, 0, string);
+  ASET (last_show_tip_args, 1, frame);
+  ASET (last_show_tip_args, 2, parms);
+
   /* Add default values to frame parameters.  */
   if (NILP (Fassq (Qname, parms)))
     parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
@@ -10413,26 +10997,36 @@ DY added (default is -5).")
 
   /* Create a frame for the tooltip, and record it in the global
      variable tip_frame.  */
-  frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms);
-  tip_frame = f = XFRAME (frame);
+  frame = x_create_tip_frame (FRAME_X_DISPLAY_INFO (f), parms, string);
+  f = XFRAME (frame);
 
-  /* Set up the frame's root window.  Currently we use a size of 80
-     columns x 40 lines.  If someone wants to show a larger tip, he
-     will loose.  I don't think this is a realistic case.  */
+  /* Set up the frame's root window.  */
   w = XWINDOW (FRAME_ROOT_WINDOW (f));
   w->left = w->top = make_number (0);
-  w->width = make_number (80);
-  w->height = make_number (40);
+  
+  if (CONSP (Vx_max_tooltip_size)
+      && INTEGERP (XCAR (Vx_max_tooltip_size))
+      && XINT (XCAR (Vx_max_tooltip_size)) > 0
+      && INTEGERP (XCDR (Vx_max_tooltip_size))
+      && XINT (XCDR (Vx_max_tooltip_size)) > 0)
+    {
+      w->width = XCAR (Vx_max_tooltip_size);
+      w->height = XCDR (Vx_max_tooltip_size);
+    }
+  else
+    {
+      w->width = make_number (80);
+      w->height = make_number (40);
+    }
+  
+  f->window_width = XINT (w->width);
   adjust_glyphs (f);
   w->pseudo_window_p = 1;
 
   /* Display the tooltip text in a temporary buffer.  */
-  buffer = Fget_buffer_create (build_string (" *tip*"));
-  Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
   old_buffer = current_buffer;
-  set_buffer_internal_1 (XBUFFER (buffer));
-  Ferase_buffer ();
-  Finsert (1, &string);
+  set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
+  current_buffer->truncate_lines = Qnil;
   clear_glyph_matrix (w->desired_matrix);
   clear_glyph_matrix (w->current_matrix);
   SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
@@ -10472,31 +11066,16 @@ DY added (default is -5).")
   height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
   width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
 
-  /* User-specified position?  */
-  left = Fcdr (Fassq (Qleft, parms));
-  top  = Fcdr (Fassq (Qtop, parms));
-  
   /* Move the tooltip window where the mouse pointer is.  Resize and
      show it.  */
-  BLOCK_INPUT;
-  XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
-                &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
-  UNBLOCK_INPUT;
+  compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
 
-  root_x += XINT (dx);
-  root_y += XINT (dy);
-  
-  if (INTEGERP (left))
-    root_x = XINT (left);
-  if (INTEGERP (top))
-    root_y = XINT (top);
-  
   BLOCK_INPUT;
   XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    root_x, root_y - height, width, height);
+                    root_x, root_y, width, height);
   XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
   UNBLOCK_INPUT;
-
+  
   /* Draw into the window.  */
   w->must_be_updated_p = 1;
   update_single_window (w, 1);
@@ -10505,6 +11084,7 @@ DY added (default is -5).")
   set_buffer_internal_1 (old_buffer);
   windows_or_buffers_changed = old_windows_or_buffers_changed;
 
+ start_timer:
   /* Let the tip disappear after timeout seconds.  */
   tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
                     intern ("x-hide-tip"));
@@ -10519,28 +11099,53 @@ DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
 Value is t is tooltip was open, nil otherwise.")
   ()
 {
-  int count = specpdl_ptr - specpdl;
-  int deleted_p = 0;
+  int count;
+  Lisp_Object deleted, frame, timer;
+  struct gcpro gcpro1, gcpro2;
+
+  /* Return quickly if nothing to do.  */
+  if (NILP (tip_timer) && NILP (tip_frame))
+    return Qnil;
   
+  frame = tip_frame;
+  timer = tip_timer;
+  GCPRO2 (frame, timer);
+  tip_frame = tip_timer = deleted = Qnil;
+  
+  count = BINDING_STACK_SIZE ();
   specbind (Qinhibit_redisplay, Qt);
+  specbind (Qinhibit_quit, Qt);
   
-  if (!NILP (tip_timer))
-    {
-      call1 (intern ("cancel-timer"), tip_timer);
-      tip_timer = Qnil;
-    }
+  if (!NILP (timer))
+    call1 (Qcancel_timer, timer);
 
-  if (tip_frame)
+  if (FRAMEP (frame))
     {
-      Lisp_Object frame;
-      
-      XSETFRAME (frame, tip_frame);
-      Fdelete_frame (frame, Qt);
-      tip_frame = NULL;
-      deleted_p = 1;
+      Fdelete_frame (frame, Qnil);
+      deleted = Qt;
+
+#ifdef USE_LUCID
+      /* Bloodcurdling hack alert: The Lucid menu bar widget's
+        redisplay procedure is not called when a tip frame over menu
+        items is unmapped.  Redisplay the menu manually...  */
+      {
+       struct frame *f = SELECTED_FRAME ();
+       Widget w = f->output_data.x->menubar_widget;
+       extern void xlwmenu_redisplay P_ ((Widget));
+       
+       if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen)
+           && w != NULL)
+         {
+           BLOCK_INPUT;
+           xlwmenu_redisplay (w);
+           UNBLOCK_INPUT;
+         }
+      }
+#endif /* USE_LUCID */
     }
 
-  return unbind_to (count, deleted_p ? Qt : Qnil);
+  UNGCPRO;
+  return unbind_to (count, deleted);
 }
 
 
@@ -10564,6 +11169,21 @@ file_dialog_cb (widget, client_data, call_data)
 }
 
 
+/* Callback for unmapping a file selection dialog.  This is used to
+   capture the case where a dialog is closed via a window manager's
+   closer button, for example. Using a XmNdestroyCallback didn't work
+   in this case.  */
+
+static void
+file_dialog_unmap_cb (widget, client_data, call_data)
+     Widget widget;
+     XtPointer call_data, client_data;
+{
+  int *result = (int *) client_data;
+  *result = XmCR_CANCEL;
+}
+
+
 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
   "Read file name, prompting with PROMPT in directory DIR.\n\
 Use a file selection dialog.\n\
@@ -10616,6 +11236,8 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
                 (XtPointer) &result);
   XtAddCallback (dialog, XmNcancelCallback, file_dialog_cb,
                 (XtPointer) &result);
+  XtAddCallback (dialog, XmNunmapCallback, file_dialog_unmap_cb,
+                (XtPointer) &result);
 
   /* Disable the help button since we can't display help.  */
   help = XmFileSelectionBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
@@ -10667,38 +11289,18 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
       XmListSetPos (list, item_pos);
     }
 
-#ifdef HAVE_MOTIF_2_1
-
-  /* Process events until the user presses Cancel or OK.  */
+  /* Process events until the user presses Cancel or OK.  Block
+     and unblock input here so that we get a chance of processing
+     expose events.  */
+  UNBLOCK_INPUT;
   result = 0;
-  while (result == 0 || XtAppPending (Xt_app_con))
-    XtAppProcessEvent (Xt_app_con, XtIMAll);
-
-#else /* not HAVE_MOTIF_2_1 */
-  
-  /* Process all events until the user presses Cancel or OK.  */
-  for (result = 0; result == 0;)
+  while (result == 0)
     {
-      XEvent event;
-      Widget widget, parent;
-      
-      XtAppNextEvent (Xt_app_con, &event);
-
-      /* See if the receiver of the event is one of the widgets of
-        the file selection dialog.  If so, dispatch it.  If not,
-        discard it.  */
-      widget = XtWindowToWidget (event.xany.display, event.xany.window);
-      parent = widget;
-      while (parent && parent != dialog)
-       parent = XtParent (parent);
-
-      if (parent == dialog
-         || (event.type == Expose
-             && !process_expose_from_menu (event)))
-       XtDispatchEvent (&event);
+      BLOCK_INPUT;
+      XtAppProcessEvent (Xt_app_con, XtIMAll);
+      UNBLOCK_INPUT;
     }
-
-#endif /* not HAVE_MOTIF_2_1 */
+  BLOCK_INPUT;
 
   /* Get the result.  */
   if (result == XmCR_OK)
@@ -10732,6 +11334,93 @@ selection dialog's entry field, if MUSTMATCH is non-nil.")
 
 
 \f
+/***********************************************************************
+                              Keyboard
+ ***********************************************************************/
+
+#ifdef HAVE_XKBGETKEYBOARD
+#include <X11/XKBlib.h>
+#include <X11/keysym.h>
+#endif
+
+DEFUN ("x-backspace-delete-keys-p", Fx_backspace_delete_keys_p,
+       Sx_backspace_delete_keys_p, 0, 1, 0,
+  "Check if both Backspace and Delete keys are on the keyboard of FRAME.\n\
+FRAME nil means use the selected frame.\n\
+Value is t if we know that both keys are present, and are mapped to the\n\
+usual X keysyms.")
+  (frame)
+     Lisp_Object frame;
+{
+#ifdef HAVE_XKBGETKEYBOARD
+  XkbDescPtr kb;
+  struct frame *f = check_x_frame (frame);
+  Display *dpy = FRAME_X_DISPLAY (f);
+  Lisp_Object have_keys;
+  int major, minor, op, event, error;
+
+  BLOCK_INPUT;
+
+  /* Check library version in case we're dynamically linked.  */
+  major = XkbMajorVersion;
+  minor = XkbMinorVersion;
+  if (!XkbLibraryVersion (&major, &minor))
+    {
+      UNBLOCK_INPUT;
+      return Qnil;
+    }
+
+  /* Check that the server supports XKB.  */
+  major = XkbMajorVersion;
+  minor = XkbMinorVersion;
+  if (!XkbQueryExtension (dpy, &op, &event, &error, &major, &minor))
+    {
+      UNBLOCK_INPUT;
+      return Qnil;
+    }
+  
+  have_keys = Qnil;
+  kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
+  if (kb)
+    {
+      int delete_keycode = 0, backspace_keycode = 0, i;
+
+      if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
+       {
+         for (i = kb->min_key_code;
+              (i < kb->max_key_code
+               && (delete_keycode == 0 || backspace_keycode == 0));
+              ++i)
+           {
+             /* The XKB symbolic key names can be seen most easily in
+                the PS file generated by `xkbprint -label name
+                $DISPLAY'.  */
+             if (bcmp ("DELE", kb->names->keys[i].name, 4) == 0)
+               delete_keycode = i;
+             else if (bcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
+               backspace_keycode = i;
+           }
+
+         XkbFreeNames (kb, 0, True);
+       }
+
+      XkbFreeClientMap (kb, 0, True);
+  
+      if (delete_keycode
+         && backspace_keycode
+         && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
+         && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
+       have_keys = Qt;
+    }
+  UNBLOCK_INPUT;
+  return have_keys;
+#else /* not HAVE_XKBGETKEYBOARD */
+  return Qnil;
+#endif /* not HAVE_XKBGETKEYBOARD */
+}
+
+
+\f
 /***********************************************************************
                            Initialization
  ***********************************************************************/
@@ -10817,6 +11506,10 @@ syms_of_xfns ()
   staticpro (&Qcenter);
   Qcompound_text = intern ("compound-text");
   staticpro (&Qcompound_text);
+  Qcancel_timer = intern ("cancel-timer");
+  staticpro (&Qcancel_timer);
+  Qwait_for_wm = intern ("wait-for-wm");
+  staticpro (&Qwait_for_wm);
   /* This is the end of symbol initialization.  */
 
   /* Text property `display' should be nonsticky by default.  */
@@ -10851,7 +11544,7 @@ syms_of_xfns ()
 
   DEFVAR_BOOL ("cross-disabled-images", &cross_disabled_images,
     "Non-nil means always draw a cross over disabled images.\n\
-Disabled images are those having an `:algorithm disabled' property.\n\
+Disabled images are those having an `:conversion disabled' property.\n\
 A cross is always drawn on black & white displays.");
   cross_disabled_images = 0;
 
@@ -10896,20 +11589,20 @@ or when you set the mouse color.");
 #endif
   Vx_nontext_pointer_shape = Qnil;
 
-  DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
+  DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
     "The shape of the pointer when Emacs is busy.\n\
 This variable takes effect when you create a new frame\n\
 or when you set the mouse color.");
-  Vx_busy_pointer_shape = Qnil;
+  Vx_hourglass_pointer_shape = Qnil;
 
-  DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
-    "Non-zero means Emacs displays a busy cursor on window systems.");
-  display_busy_cursor_p = 1;
+  DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
+    "Non-zero means Emacs displays an hourglass pointer on window systems.");
+  display_hourglass_p = 1;
   
-  DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
-     "*Seconds to wait before displaying a busy-cursor.\n\
+  DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
+     "*Seconds to wait before displaying an hourglass pointer.\n\
 Value must be an integer or float.");
-  Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
+  Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
 
 #if 0 /* This doesn't really do anything.  */
   DEFVAR_LISP ("x-mode-pointer-shape", &Vx_mode_pointer_shape,
@@ -10926,10 +11619,22 @@ This variable takes effect when you create a new frame\n\
 or when you set the mouse color.");
   Vx_sensitive_text_pointer_shape = Qnil;
 
+  DEFVAR_LISP ("x-window-horizontal-drag-cursor",
+             &Vx_window_horizontal_drag_shape,
+  "Pointer shape to use for indicating a window can be dragged horizontally.\n\
+This variable takes effect when you create a new frame\n\
+or when you set the mouse color.");
+  Vx_window_horizontal_drag_shape = Qnil;
+
   DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
               "A string indicating the foreground color of the cursor box.");
   Vx_cursor_fore_pixel = Qnil;
 
+  DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
+   "Maximum size for tooltips.  Value is a pair (COLUMNS . ROWS).\n\
+Text larger than this is clipped.");
+  Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
+  
   DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
               "Non-nil if no X window manager is in use.\n\
 Emacs doesn't try to figure this out; this is always nil\n\
@@ -10957,10 +11662,15 @@ meaning don't clear the cache.");
 
 #ifdef USE_X_TOOLKIT
   Fprovide (intern ("x-toolkit"));
-#endif
+  
 #ifdef USE_MOTIF
   Fprovide (intern ("motif"));
-#endif
+
+  DEFVAR_LISP ("motif-version-string", &Vmotif_version_string,
+     "Version info for LessTif/Motif.");
+  Vmotif_version_string = build_string (XmVERSION_STRING);
+#endif /* USE_MOTIF */
+#endif /* USE_X_TOOLKIT */
 
   defsubr (&Sx_get_resource);
 
@@ -10993,7 +11703,8 @@ meaning don't clear the cache.");
   defsubr (&Sx_display_list);
   defsubr (&Sx_synchronize);
   defsubr (&Sx_focus_frame);
-
+  defsubr (&Sx_backspace_delete_keys_p);
+  
   /* Setting callback functions for fontset handler.  */
   get_font_info_func = x_get_font_info;
 
@@ -11013,8 +11724,8 @@ meaning don't clear the cache.");
   staticpro (&Qxbm);
   QCtype = intern (":type");
   staticpro (&QCtype);
-  QCalgorithm = intern (":algorithm");
-  staticpro (&QCalgorithm);
+  QCconversion = intern (":conversion");
+  staticpro (&QCconversion);
   QCheuristic_mask = intern (":heuristic-mask");
   staticpro (&QCheuristic_mask);
   QCcolor_symbols = intern (":color-symbols");
@@ -11069,13 +11780,18 @@ meaning don't clear the cache.");
   defsubr (&Simage_size);
   defsubr (&Simage_mask_p);
 
-  busy_cursor_atimer = NULL;
-  busy_cursor_shown_p = 0;
+  hourglass_atimer = NULL;
+  hourglass_shown_p = 0;
 
   defsubr (&Sx_show_tip);
   defsubr (&Sx_hide_tip);
-  staticpro (&tip_timer);
   tip_timer = Qnil;
+  staticpro (&tip_timer);
+  tip_frame = Qnil;
+  staticpro (&tip_frame);
+
+  last_show_tip_args = Qnil;
+  staticpro (&last_show_tip_args);
 
 #ifdef USE_MOTIF
   defsubr (&Sx_file_dialog);