Use XCAR and XCDR instead of explicit member references.
[bpt/emacs.git] / src / xterm.c
index 43e4430..db2b355 100644 (file)
@@ -1,5 +1,6 @@
 /* X Communication module for terminals which understand the X protocol.
-   Copyright (C) 1989, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1989, 93, 94, 95, 96, 1997, 1998, 1999
+   Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,6 +19,7 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
+/* New display code by Gerd Moellmann <gerd@gnu.org>.  */
 /* Xt features made by Fred Pierresteguy.  */
 
 /* On 4.3 these lose if they come after xterm.h.  */
@@ -28,16 +30,19 @@ Boston, MA 02111-1307, USA.  */
 #include <config.h>
 
 #include <stdio.h>
-
-/* Need syssignal.h for various externs and definitions that may be required
-   by some configurations for calls to signal later in this source file.  */
-#include "syssignal.h"
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
 
 #ifdef HAVE_X_WINDOWS
 
 #include "lisp.h"
 #include "blockinput.h"
 
+/* Need syssignal.h for various externs and definitions that may be required
+   by some configurations for calls to signal later in this source file.  */
+#include "syssignal.h"
+
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
 #include "xterm.h"
@@ -70,8 +75,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "charset.h"
 #include "ccl.h"
-#include "fontset.h"
 #include "frame.h"
+#include "fontset.h"
 #include "dispextern.h"
 #include "termhooks.h"
 #include "termopts.h"
@@ -86,18 +91,46 @@ Boston, MA 02111-1307, USA.  */
 #include "window.h"
 #include "keyboard.h"
 #include "intervals.h"
+#include "process.h"
 
 #ifdef USE_X_TOOLKIT
 #include <X11/Shell.h>
 #endif
 
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #ifdef USE_X_TOOLKIT
+
 extern void free_frame_menubar ();
 extern FRAME_PTR x_menubar_window_to_frame ();
+
 #if (XtSpecificationRelease >= 5) && !defined(NO_EDITRES)
 #define HACK_EDITRES
 extern void _XEditResCheckMessages ();
 #endif /* not NO_EDITRES */
+
+/* Include toolkit specific headers for the scroll bar widget.  */
+
+#ifdef USE_TOOLKIT_SCROLL_BARS
+#if defined USE_MOTIF
+#include <Xm/Xm.h>             /* for LESSTIF_VERSION */
+#include <Xm/ScrollBar.h>
+#include <Xm/ScrollBarP.h>
+#elif defined HAVE_XAW3D
+#include <X11/Xaw3d/Simple.h>
+#include <X11/Xaw3d/ThreeD.h>
+#include <X11/Xaw3d/Scrollbar.h>
+#define ARROW_SCROLLBAR
+#include <X11/Xaw3d/ScrollbarP.h>
+#endif /* HAVE_XAW3D */
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
 #endif /* USE_X_TOOLKIT */
 
 #ifndef USE_X_TOOLKIT
@@ -125,60 +158,151 @@ extern void _XEditResCheckMessages ();
 #endif
 
 #ifndef min
-#define min(a,b) ((a)<(b) ? (a) : (b))
+#define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
 #ifndef max
-#define max(a,b) ((a)>(b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define abs(x) ((x) < 0 ? -(x) : (x))
+
+#define BETWEEN(X, LOWER, UPPER)  ((X) >= (LOWER) && (X) < (UPPER))
+
+\f
+/* Bitmaps for truncated lines.  */
+
+enum bitmap_type
+{
+  NO_BITMAP,
+  LEFT_TRUNCATION_BITMAP,
+  RIGHT_TRUNCATION_BITMAP,
+  OVERLAY_ARROW_BITMAP,
+  CONTINUED_LINE_BITMAP,
+  CONTINUATION_LINE_BITMAP,
+  ZV_LINE_BITMAP
+};
+
+/* Bitmap drawn to indicate lines not displaying text if
+   `indicate-empty-lines' is non-nil.  */
+
+#define zv_width 8
+#define zv_height 8
+static unsigned char zv_bits[] = {
+   0x00, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00};
+
+/* An arrow like this: `<-'.  */
+
+#define left_width 8
+#define left_height 8
+static unsigned char left_bits[] = {
+   0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
+
+/* Right truncation arrow bitmap `->'.  */
+
+#define right_width 8
+#define right_height 8
+static unsigned char right_bits[] = {
+   0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
+
+/* Marker for continued lines.  */
+
+#define continued_width 8
+#define continued_height 8
+static unsigned char continued_bits[] = {
+   0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
+
+/* Marker for continuation lines.  */
+
+#define continuation_width 8
+#define continuation_height 8
+static unsigned char continuation_bits[] = {
+   0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
+
+/* Overlay arrow bitmap.  */
+
+#if 0
+/* A bomb.  */
+#define ov_width 8
+#define ov_height 8
+static unsigned char ov_bits[] = {
+   0x30, 0x08, 0x3c, 0x7e, 0x7a, 0x7a, 0x62, 0x3c};
+#else
+/* A triangular arrow.  */
+#define ov_width 8
+#define ov_height 8
+static unsigned char ov_bits[] = {
+   0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
+
 #endif
+
+extern Lisp_Object Qhelp_echo;
+
 \f
-/* This is a chain of structures for all the X displays currently in use.  */
+/* Non-zero means Emacs uses toolkit scroll bars.  */
+
+int x_toolkit_scroll_bars_p;
+
+/* If a string, XTread_socket generates an event to display that string.
+   (The display is done in read_char.)  */
+   
+static Lisp_Object help_echo;
+
+/* Temporary variable for XTread_socket.  */
+
+static Lisp_Object previous_help_echo;
+
+/* Non-zero means that a HELP_EVENT has been generated since Emacs
+   start.  */
+
+static int any_help_event_p;
+
+/* Non-zero means draw block and hollow cursor as wide as the glyph
+   under it.  For example, if a block cursor is over a tab, it will be
+   drawn as wide as that tab on the display.  */
+
+int x_stretch_cursor_p;
+
+/* This is a chain of structures for all the X displays currently in
+   use.  */
+
 struct x_display_info *x_display_list;
 
-/* This is a list of cons cells, each of the form (NAME . FONT-LIST-CACHE),
-   one for each element of x_display_list and in the same order.
-   NAME is the name of the frame.
-   FONT-LIST-CACHE records previous values returned by x-list-fonts.  */
+/* This is a list of cons cells, each of the form (NAME
+   . FONT-LIST-CACHE), one for each element of x_display_list and in
+   the same order.  NAME is the name of the frame.  FONT-LIST-CACHE
+   records previous values returned by x-list-fonts.  */
+
 Lisp_Object x_display_name_list;
 
 /* Frame being updated by update_frame.  This is declared in term.c.
-   This is set by update_begin and looked at by all the
-   XT functions.  It is zero while not inside an update.
-   In that case, the XT functions assume that `selected_frame'
-   is the frame to apply to.  */
+   This is set by update_begin and looked at by all the XT functions.
+   It is zero while not inside an update.  In that case, the XT
+   functions assume that `selected_frame' is the frame to apply to.  */
+
 extern struct frame *updating_frame;
 
-extern waiting_for_input;
+extern int waiting_for_input;
+
+/* This is a frame waiting to be auto-raised, within XTread_socket.  */
 
-/* This is a frame waiting to be autoraised, within XTread_socket.  */
 struct frame *pending_autoraise_frame;
 
 #ifdef USE_X_TOOLKIT
 /* The application context for Xt use.  */
 XtAppContext Xt_app_con;
+static String Xt_default_resources[] = {0};
+#endif /* USE_X_TOOLKIT */
 
-static String Xt_default_resources[] =
-{
-  0
-};
-#endif
-
-/* During an update, maximum vpos for ins/del line operations to affect.  */
-
-static int flexlines;
-
-/* During an update, nonzero if chars output now should be highlighted.  */
-
-static int highlight;
+/* Nominal cursor position -- where to draw output.  
+   HPOS and VPOS are window relative glyph matrix coordinates.
+   X and Y are window relative pixel coordinates.  */
 
-/* Nominal cursor position -- where to draw output.
-   During an update, these are different from the cursor-box position.  */
+struct cursor_pos output_cursor;
 
-static int curs_x;
-static int curs_y;
 
 /* Mouse movement.
 
-   Formerly, we used PointerMotionHintMask (in STANDARD_EVENT_MASK)
+   Formerly, we used PointerMotionHintMask (in standard_event_mask)
    so that we would have to call XQueryPointer after each MotionNotify
    event to ask for another such event.  However, this made mouse tracking
    slow, and there was a bug that made it eventually stop.
@@ -197,30 +321,35 @@ static int curs_y;
    is off.  */
 
 /* Where the mouse was last time we reported a mouse event.  */
-static FRAME_PTR last_mouse_frame;
-static XRectangle last_mouse_glyph;
 
+FRAME_PTR last_mouse_frame;
+static XRectangle last_mouse_glyph;
 static Lisp_Object last_mouse_press_frame;
 
 /* The scroll bar in which the last X motion event occurred.
 
-   If the last X motion event occurred in a scroll bar, we set this
-   so XTmouse_position can know whether to report a scroll bar motion or
+   If the last X motion event occurred in a scroll bar, we set this so
+   XTmouse_position can know whether to report a scroll bar motion or
    an ordinary motion.
 
-   If the last X motion event didn't occur in a scroll bar, we set this
-   to Qnil, to tell XTmouse_position to return an ordinary motion event.  */
+   If the last X motion event didn't occur in a scroll bar, we set
+   this to Qnil, to tell XTmouse_position to return an ordinary motion
+   event.  */
+
 static Lisp_Object last_mouse_scroll_bar;
 
 /* This is a hack.  We would really prefer that XTmouse_position would
    return the time associated with the position it returns, but there
-   doesn't seem to be any way to wrest the timestamp from the server
+   doesn't seem to be any way to wrest the time-stamp from the server
    along with the position query.  So, we just keep track of the time
    of the last movement we received, and return that in hopes that
    it's somewhat accurate.  */
+
 static Time last_mouse_movement_time;
 
-/* Incremented by XTread_socket whenever it really tries to read events.  */
+/* Incremented by XTread_socket whenever it really tries to read
+   events.  */
+
 #ifdef __STDC__
 static int volatile input_signal_count;
 #else
@@ -228,15 +357,17 @@ static int input_signal_count;
 #endif
 
 /* Used locally within XTread_socket.  */
+
 static int x_noop_count;
 
 /* Initial values of argv and argc.  */
+
 extern char **initial_argv;
 extern int initial_argc;
 
 extern Lisp_Object Vcommand_line_args, Vsystem_name;
 
-/* Tells if a window manager is present or not. */
+/* Tells if a window manager is present or not.  */
 
 extern Lisp_Object Vx_no_window_manager;
 
@@ -245,35 +376,141 @@ extern Lisp_Object Qface, Qmouse_face;
 extern int errno;
 
 /* A mask of extra modifier bits to put into every keyboard char.  */
+
 extern int extra_keyboard_modifiers;
 
 static Lisp_Object Qvendor_specific_keysyms;
 
 extern XrmDatabase x_load_resources ();
-
 extern Lisp_Object x_icon_type ();
 
-void x_delete_display ();
 
-static void redraw_previous_char ();
-static void redraw_following_char ();
-static unsigned int x_x_to_emacs_modifiers ();
+/* Enumeration for overriding/changing the face to use for drawing
+   glyphs in x_draw_glyphs.  */
+
+enum draw_glyphs_face
+{
+  DRAW_NORMAL_TEXT,
+  DRAW_INVERSE_VIDEO,
+  DRAW_CURSOR,
+  DRAW_MOUSE_FACE,
+  DRAW_IMAGE_RAISED,
+  DRAW_IMAGE_SUNKEN
+};
+
+static void x_update_window_end P_ ((struct window *, int));
+static void frame_to_window_pixel_xy P_ ((struct window *, int *, int *));
+void x_delete_display P_ ((struct x_display_info *));
+static unsigned int x_x_to_emacs_modifiers P_ ((struct x_display_info *,
+                                               unsigned));
+static int fast_find_position P_ ((struct window *, int, int *, int *,
+                                  int *, int *));
+static void set_output_cursor P_ ((struct cursor_pos *));
+static struct glyph *x_y_to_hpos_vpos P_ ((struct window *, int, int,
+                                          int *, int *, int *));
+static void note_mode_line_highlight P_ ((struct window *, int, int));
+static void x_check_font P_ ((struct frame *, XFontStruct *));
+static void note_mouse_highlight P_ ((struct frame *, int, int));
+static void note_tool_bar_highlight P_ ((struct frame *f, int, int));
+static void x_handle_tool_bar_click P_ ((struct frame *, XButtonEvent *));
+static void show_mouse_face P_ ((struct x_display_info *,
+                                enum draw_glyphs_face));
+static int x_io_error_quitter P_ ((Display *));
+int x_catch_errors P_ ((Display *));
+void x_uncatch_errors P_ ((Display *, int));
+void x_lower_frame P_ ((struct frame *));
+void x_scroll_bar_clear P_ ((struct frame *));
+int x_had_errors_p P_ ((Display *));
+void x_wm_set_size_hint P_ ((struct frame *, long, int));
+void x_raise_frame P_ ((struct frame *));
+void x_set_window_size P_ ((struct frame *, int, int, int));
+void x_wm_set_window_state P_ ((struct frame *, int));
+void x_wm_set_icon_pixmap P_ ((struct frame *, int));
+void x_initialize P_ ((void));
+static void x_font_min_bounds P_ ((XFontStruct *, int *, int *));
+static int x_compute_min_glyph_bounds P_ ((struct frame *));
+static void x_draw_phys_cursor_glyph P_ ((struct window *,
+                                         struct glyph_row *,
+                                         enum draw_glyphs_face));
+static void x_update_end P_ ((struct frame *));
+static void XTframe_up_to_date P_ ((struct frame *));
+static void XTreassert_line_highlight P_ ((int, int));
+static void x_change_line_highlight P_ ((int, int, int, int));
+static void XTset_terminal_modes P_ ((void));
+static void XTreset_terminal_modes P_ ((void));
+static void XTcursor_to P_ ((int, int, int, int));
+static void x_write_glyphs P_ ((struct glyph *, int));
+static void x_clear_end_of_line P_ ((int));
+static void x_clear_frame P_ ((void));
+static void x_clear_cursor P_ ((struct window *));
+static void frame_highlight P_ ((struct frame *));
+static void frame_unhighlight P_ ((struct frame *));
+static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
+static void XTframe_rehighlight P_ ((struct frame *));
+static void x_frame_rehighlight P_ ((struct x_display_info *));
+static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
+static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *));
+static int x_intersect_rectangles P_ ((XRectangle *, XRectangle *,
+                                      XRectangle *));
+static void expose_frame P_ ((struct frame *, int, int, int, int));
+static void expose_window_tree P_ ((struct window *, XRectangle *));
+static void expose_window P_ ((struct window *, XRectangle *));
+static void expose_area P_ ((struct window *, struct glyph_row *,
+                            XRectangle *, enum glyph_row_area));
+static void expose_line P_ ((struct window *, struct glyph_row *,
+                            XRectangle *));
+static void x_update_cursor_in_window_tree P_ ((struct window *, int));
+static void x_update_window_cursor P_ ((struct window *, int));
+static void x_erase_phys_cursor P_ ((struct window *));
+void x_display_and_set_cursor P_ ((struct window *, int, int, int, int, int));
+static void x_draw_bitmap P_ ((struct window *, struct glyph_row *, 
+                              enum bitmap_type));
+
+static void x_clip_to_row P_ ((struct window *, struct glyph_row *,
+                              GC, int));
+static int x_phys_cursor_in_rect_p P_ ((struct window *, XRectangle *));
+static void x_draw_row_bitmaps P_ ((struct window *, struct glyph_row *));
+static void note_overwritten_text_cursor P_ ((struct window *, int, int));
+static void x_flush P_ ((struct frame *f));
+     
+
+/* Flush display of frame F, or of all frames if F is null.  */
+
+static void
+x_flush (f)
+     struct frame *f;
+{
+  BLOCK_INPUT;
+  if (f == NULL)
+    {
+      Lisp_Object rest, frame;
+      FOR_EACH_FRAME (rest, frame)
+       x_flush (XFRAME (frame));
+    }
+  else if (FRAME_X_P (f))
+    XFlush (FRAME_X_DISPLAY (f));
+  UNBLOCK_INPUT;
+}
+
 
-static int fast_find_position ();
-static void note_mouse_highlight ();
-static void clear_mouse_face ();
-static void show_mouse_face ();
-static void do_line_dance ();
+/* Remove calls to XFlush by defining XFlush to an empty replacement.
+   Calls to XFlush should be unnecessary because the X output buffer
+   is flushed automatically as needed by calls to XPending,
+   XNextEvent, or XWindowEvent according to the XFlush man page.
+   XTread_socket calls XPending.  Removing XFlush improves
+   performance.  */
+
+#define XFlush(DISPLAY)        (void) 0 
 
-static int XTcursor_to ();
-static int XTclear_end_of_line ();
-static int x_io_error_quitter ();
-int x_catch_errors ();
-void x_uncatch_errors ();
 \f
+/***********************************************************************
+                             Debugging
+ ***********************************************************************/
+
 #if 0
-/* This is a function useful for recording debugging information
-   about the sequence of occurrences in this file.  */
+
+/* This is a function useful for recording debugging information about
+   the sequence of occurrences in this file.  */
 
 struct record 
 {
@@ -298,6 +535,8 @@ record_event (locus, type)
 }
 
 #endif /* 0 */
+
+
 \f
 /* Return the struct x_display_info corresponding to DPY.  */
 
@@ -313,189 +552,560 @@ x_display_info_for_display (dpy)
 
   return 0;
 }
-\f
-/* Starting and ending updates.
 
-   These hooks are called by update_frame at the beginning and end
-   of a frame update.  We record in `updating_frame' the identity
-   of the frame being updated, so that the XT... functions do not
-   need to take a frame as argument.  Most of the XT... functions
-   should never be called except during an update, the only exceptions
-   being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight.  */
 
-static
-XTupdate_begin (f)
+\f
+/***********************************************************************
+                   Starting and ending an update
+ ***********************************************************************/
+                                                                       
+/* Start an update of frame F.  This function is installed as a hook
+   for update_begin, i.e. it is called when update_begin is called.
+   This function is called prior to calls to x_update_window_begin for
+   each window being updated.  Currently, there is nothing to do here
+   because all interesting stuff is done on a window basis.  */
+
+static void
+x_update_begin (f)
      struct frame *f;
 {
-  int mask;
+  /* Nothing to do.  */
+}
 
-  if (f == 0)
-    abort ();
 
-  flexlines = f->height;
-  highlight = 0;
+/* Start update of window W.  Set the global variable updated_window
+   to the window being updated and set output_cursor to the cursor
+   position of W.  */
 
-  BLOCK_INPUT;
+static void
+x_update_window_begin (w)
+     struct window *w;
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  struct x_display_info *display_info = FRAME_X_DISPLAY_INFO (f);
+  
+  updated_window = w;
+  set_output_cursor (&w->cursor);
 
-  curs_x = FRAME_CURSOR_X (f);
-  curs_y = FRAME_CURSOR_Y (f);
+  BLOCK_INPUT;
 
-  if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
+  if (f == display_info->mouse_face_mouse_frame)
     {
       /* Don't do highlighting for mouse motion during the update.  */
-      FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 1;
+      display_info->mouse_face_defer = 1;
 
-      /* If the frame needs to be redrawn,
-        simply forget about any prior mouse highlighting.  */
+      /* If F needs to be redrawn, simply forget about any prior mouse
+        highlighting.  */
       if (FRAME_GARBAGED_P (f))
-       FRAME_X_DISPLAY_INFO (f)->mouse_face_window = Qnil;
-
-      if (!NILP (FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
+       display_info->mouse_face_window = Qnil;
+
+      /* Can we tell that this update does not affect the window
+        where the mouse highlight is?  If so, no need to turn off.
+        Likewise, don't do anything if the frame is garbaged;
+        in that case, the frame's current matrix that we would use
+        is all wrong, and we will redisplay that line anyway.  */
+      if (!NILP (display_info->mouse_face_window)
+         && w == XWINDOW (display_info->mouse_face_window))
        {
-         int firstline, lastline, i;
-         struct window *w = XWINDOW (FRAME_X_DISPLAY_INFO (f)->mouse_face_window);
+         int i;
 
-         /* Find the first, and the last+1, lines affected by redisplay.  */
-         for (firstline = 0; firstline < f->height; firstline++)
-           if (FRAME_DESIRED_GLYPHS (f)->enable[firstline])
+         for (i = 0; i < w->desired_matrix->nrows; ++i)
+           if (MATRIX_ROW_ENABLED_P (w->desired_matrix, i))
              break;
 
-         lastline = f->height;
-         for (i = f->height - 1; i >= 0; i--)
-           {
-             if (FRAME_DESIRED_GLYPHS (f)->enable[i])
-               break;
-             else
-               lastline = i;
-           }
-
-         /* Can we tell that this update does not affect the window
-            where the mouse highlight is?  If so, no need to turn off.
-            Likewise, don't do anything if the frame is garbaged;
-            in that case, the FRAME_CURRENT_GLYPHS that we would use
-            are all wrong, and we will redisplay that line anyway.  */
-         if (! (firstline > (XFASTINT (w->top) + window_internal_height (w))
-                || lastline < XFASTINT (w->top)))
-           clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
+         if (i < w->desired_matrix->nrows)
+           clear_mouse_face (display_info);
        }
     }
 
   UNBLOCK_INPUT;
 }
 
-static
-XTupdate_end (f)
-     struct frame *f;
+
+/* Draw a vertical window border to the right of window W if W doesn't
+   have vertical scroll bars.  */
+
+static void
+x_draw_vertical_border (w)
+     struct window *w;
 {
-  int mask;
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  
+  /* Redraw borders between horizontally adjacent windows.  Don't
+     do it for frames with vertical scroll bars because either the
+     right scroll bar of a window, or the left scroll bar of its
+     neighbor will suffice as a border.  */
+  if (!WINDOW_RIGHTMOST_P (w)
+      && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+    {
+      int x0, x1, y0, y1;
+
+      window_box_edges (w, -1, &x0, &y0, &x1, &y1);
+      x1 += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f);
+      y1 -= 1;
+      
+      XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 
+                f->output_data.x->normal_gc, x1, y0, x1, y1);
+    }
+}
+   
+   
+/* End update of window W (which is equal to updated_window).  Draw
+   vertical borders between horizontally adjacent windows, and display
+   W's cursor if CURSOR_ON_P is non-zero.  W may be a menu bar
+   pseudo-window in case we don't have X toolkit support.  Such
+   windows don't have a cursor, so don't display it here.  */
 
-  BLOCK_INPUT;
+static void
+x_update_window_end (w, cursor_on_p)
+     struct window *w;
+     int cursor_on_p;
+{
+  if (!w->pseudo_window_p)
+    {
+      BLOCK_INPUT;
+      if (cursor_on_p)
+       x_display_and_set_cursor (w, 1, output_cursor.hpos,
+                                 output_cursor.vpos,
+                                 output_cursor.x, output_cursor.y);
+      x_draw_vertical_border (w);
+      UNBLOCK_INPUT;
+    }
+  
+  updated_window = NULL;
+}
 
-  do_line_dance ();
-  x_display_cursor (f, 1, curs_x, curs_y);
 
+/* End update of frame F.  This function is installed as a hook in
+   update_end.  */
+
+static void
+x_update_end (f)
+     struct frame *f;
+{
+  /* Mouse highlight may be displayed again.  */
   FRAME_X_DISPLAY_INFO (f)->mouse_face_defer = 0;
-#if 0
-  /* This fails in the case of having updated only the echo area
-     if we have switched buffers.  In that case, FRAME_CURRENT_GLYPHS
-     has no relation to the current contents, and its charstarts
-     have no relation to the contents of the window-buffer.
-  I don't know a clean way to check
-     for that case.  window_end_valid isn't set up yet.  */
-  if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
-    note_mouse_highlight (f, FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
-                         FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
-#endif
 
+  BLOCK_INPUT;
   XFlush (FRAME_X_DISPLAY (f));
   UNBLOCK_INPUT;
 }
 
-/* This is called after a redisplay on frame F.  */
 
-static
+/* This function is called from various places in xdisp.c whenever a
+   complete update has been performed.  The global variable
+   updated_window is not available here.  */
+
+static void
 XTframe_up_to_date (f)
-     FRAME_PTR f;
+     struct frame *f;
 {
-  BLOCK_INPUT;
-  if (FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc
-      || f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame)
+  if (FRAME_X_P (f))
     {
-      note_mouse_highlight (FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame,
-                           FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x,
-                           FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y);
-      FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
+      struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+      if (dpyinfo->mouse_face_deferred_gc
+         || f == dpyinfo->mouse_face_mouse_frame)
+       {
+         BLOCK_INPUT;
+         if (dpyinfo->mouse_face_mouse_frame)
+           note_mouse_highlight (dpyinfo->mouse_face_mouse_frame,
+                                 dpyinfo->mouse_face_mouse_x,
+                                 dpyinfo->mouse_face_mouse_y);
+         dpyinfo->mouse_face_deferred_gc = 0;
+         UNBLOCK_INPUT;
+       }
     }
-  UNBLOCK_INPUT;
 }
+
+
+/* Draw truncation mark bitmaps, continuation mark bitmaps, overlay
+   arrow bitmaps, or clear the areas where they would be displayed
+   before DESIRED_ROW is made current.  The window being updated is
+   found in updated_window.  This function It is called from
+   update_window_line only if it is known that there are differences
+   between bitmaps to be drawn between current row and DESIRED_ROW.  */
+
+static void
+x_after_update_window_line (desired_row)
+     struct glyph_row *desired_row;
+{
+  struct window *w = updated_window;
+  
+  xassert (w);
+  
+  if (!desired_row->mode_line_p && !w->pseudo_window_p)
+    {
+      BLOCK_INPUT;
+      x_draw_row_bitmaps (w, desired_row);
+
+      /* When a window has disappeared, make sure that no rest of
+        full-width rows stays visible in the internal border.  */
+      if (windows_or_buffers_changed)
+       {
+         struct frame *f = XFRAME (w->frame);
+         int width = FRAME_INTERNAL_BORDER_WIDTH (f);
+         int height = desired_row->visible_height;
+         int x = (window_box_right (w, -1)
+                  + FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f));
+         int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
+
+         XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     x, y, width, height, False);
+       }
+      
+      UNBLOCK_INPUT;
+    }
+}
+
+
+/* Draw the bitmap WHICH in one of the areas to the left or right of
+   window W.  ROW is the glyph row for which to display the bitmap; it
+   determines the vertical position at which the bitmap has to be
+   drawn.  */
+
+static void
+x_draw_bitmap (w, row, which)
+     struct window *w;
+     struct glyph_row *row;
+     enum bitmap_type which;
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  Display *display = FRAME_X_DISPLAY (f);
+  Window window = FRAME_X_WINDOW (f);
+  int x, y, wd, h, dy;
+  unsigned char *bits;
+  Pixmap pixmap;
+  GC gc = f->output_data.x->normal_gc;
+  struct face *face;
+  int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+
+  /* Must clip because of partially visible lines.  */
+  x_clip_to_row (w, row, gc, 1);
+
+  switch (which)
+    {
+    case LEFT_TRUNCATION_BITMAP:
+      wd = left_width;
+      h = left_height;
+      bits = left_bits;
+      x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
+          - wd
+          - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
+      break;
+      
+    case OVERLAY_ARROW_BITMAP:
+      wd = left_width;
+      h = left_height;
+      bits = ov_bits;
+      x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
+          - wd
+          - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
+      break;
+      
+    case RIGHT_TRUNCATION_BITMAP:
+      wd = right_width;
+      h = right_height;
+      bits = right_bits;
+      x = window_box_right (w, -1);
+      x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
+      break;
+
+    case CONTINUED_LINE_BITMAP:
+      wd = right_width;
+      h = right_height;
+      bits = continued_bits;
+      x = window_box_right (w, -1);
+      x += (FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f) - wd) / 2;
+      break;
+      
+    case CONTINUATION_LINE_BITMAP:
+      wd = continuation_width;
+      h = continuation_height;
+      bits = continuation_bits;
+      x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
+          - wd
+          - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
+      break;
+
+    case ZV_LINE_BITMAP:
+      wd = zv_width;
+      h = zv_height;
+      bits = zv_bits;
+      x = (WINDOW_TO_FRAME_PIXEL_X (w, 0)
+          - wd
+          - (FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - wd) / 2);
+      break;
+
+    default:
+      abort ();
+    }
+
+  /* Convert to frame coordinates.  Set dy to the offset in the row to
+     start drawing the bitmap.  */
+  y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+  dy = (row->height - h) / 2;
+
+  /* Draw the bitmap.  I believe these small pixmaps can be cached
+     by the server.  */
+  face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
+  pixmap = XCreatePixmapFromBitmapData (display, window, bits, wd, h,
+                                       face->foreground,
+                                       face->background, depth);
+  XCopyArea (display, pixmap, window, gc, 0, 0, wd, h, x, y + dy);
+  XFreePixmap (display, pixmap);
+  XSetClipMask (display, gc, None);
+}
+
+
+/* Draw flags bitmaps for glyph row ROW on window W.  Call this
+   function with input blocked.  */
+
+static void
+x_draw_row_bitmaps (w, row)
+     struct window *w;
+     struct glyph_row *row;
+{
+  struct frame *f = XFRAME (w->frame);
+  enum bitmap_type bitmap;
+  struct face *face;
+  int header_line_height = -1;
+
+  xassert (interrupt_input_blocked);
+
+  /* If row is completely invisible, because of vscrolling, we
+     don't have to draw anything.  */
+  if (row->visible_height <= 0)
+    return;
+
+  face = FACE_FROM_ID (f, BITMAP_AREA_FACE_ID);
+  PREPARE_FACE_FOR_DISPLAY (f, face);
+
+  /* Decide which bitmap to draw at the left side.  */
+  if (row->overlay_arrow_p)
+    bitmap = OVERLAY_ARROW_BITMAP;
+  else if (row->truncated_on_left_p)
+    bitmap = LEFT_TRUNCATION_BITMAP;
+  else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
+    bitmap = CONTINUATION_LINE_BITMAP;
+  else if (row->indicate_empty_line_p)
+    bitmap = ZV_LINE_BITMAP;
+  else
+    bitmap = NO_BITMAP;
+
+  /* Clear flags area if no bitmap to draw or if bitmap doesn't fill
+     the flags area.  */
+  if (bitmap == NO_BITMAP
+      || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
+      || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
+    {
+      /* If W has a vertical border to its left, don't draw over it.  */
+      int border = ((XFASTINT (w->left) > 0
+                    && !FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+                   ? 1 : 0);
+      int left = window_box_left (w, -1);
+
+      if (header_line_height < 0)
+       header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+      
+      /* In case the same realized face is used for bitmap areas and
+        for something displayed in the text (e.g. face `region' on
+        mono-displays, the fill style may have been changed to
+        FillSolid in x_draw_glyph_string_background.  */
+      if (face->stipple)
+       XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
+      else
+       XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
+      
+      XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     face->gc,
+                     (left
+                      - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
+                      + border),
+                     WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+                                                      row->y)),
+                     FRAME_X_LEFT_FLAGS_AREA_WIDTH (f) - border,
+                     row->visible_height);
+      if (!face->stipple)
+       XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
+    }
+
+  /* Draw the left bitmap.  */
+  if (bitmap != NO_BITMAP)
+    x_draw_bitmap (w, row, bitmap);
+
+  /* Decide which bitmap to draw at the right side.  */
+  if (row->truncated_on_right_p)
+    bitmap = RIGHT_TRUNCATION_BITMAP;
+  else if (row->continued_p)
+    bitmap = CONTINUED_LINE_BITMAP;
+  else
+    bitmap = NO_BITMAP;
+
+  /* Clear flags area if no bitmap to draw of if bitmap doesn't fill
+     the flags area.  */
+  if (bitmap == NO_BITMAP
+      || FRAME_FLAGS_BITMAP_WIDTH (f) < FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f)
+      || row->height > FRAME_FLAGS_BITMAP_HEIGHT (f))
+    {
+      int right = window_box_right (w, -1);
+
+      if (header_line_height < 0)
+       header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+
+      /* In case the same realized face is used for bitmap areas and
+        for something displayed in the text (e.g. face `region' on
+        mono-displays, the fill style may have been changed to
+        FillSolid in x_draw_glyph_string_background.  */
+      if (face->stipple)
+       XSetFillStyle (FRAME_X_DISPLAY (f), face->gc, FillOpaqueStippled);
+      else
+       XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->background);
+      XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     face->gc,
+                     right,
+                     WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+                                                      row->y)),
+                     FRAME_X_RIGHT_FLAGS_AREA_WIDTH (f),
+                     row->visible_height);
+      if (!face->stipple)
+       XSetForeground (FRAME_X_DISPLAY (f), face->gc, face->foreground);
+    }
+
+  /* Draw the right bitmap.  */
+  if (bitmap != NO_BITMAP)
+    x_draw_bitmap (w, row, bitmap);
+}
+
 \f
-/* External interface to control of standout mode.
-   Call this when about to modify line at position VPOS
  and not change whether it is highlighted.  */
+/***********************************************************************
+                         Line Highlighting
***********************************************************************/
 
+/* External interface to control of standout mode.  Not used for X
+   frames.  Aborts when called.  */
+
+static void
 XTreassert_line_highlight (new, vpos)
      int new, vpos;
 {
-  highlight = new;
+  abort ();
 }
 
-/* Call this when about to modify line at position VPOS
-   and change whether it is highlighted.  */
 
-static
-XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
-     int new_highlight, vpos, first_unused_hpos;
+/* Call this when about to modify line at position VPOS and change
+   whether it is highlighted.  Not used for X frames.  Aborts when
+   called.  */
+
+static void
+x_change_line_highlight (new_highlight, vpos, y, first_unused_hpos)
+     int new_highlight, vpos, y, first_unused_hpos;
 {
-  highlight = new_highlight;
-  XTcursor_to (vpos, 0);
-  XTclear_end_of_line (FRAME_WINDOW_WIDTH (updating_frame));
+  abort ();
 }
 
-/* This is used when starting Emacs and when restarting after suspend.
-   When starting Emacs, no X window is mapped.  And nothing must be done
-   to Emacs's own window if it is suspended (though that rarely happens).  */
 
-static
+/* This is called when starting Emacs and when restarting after
+   suspend.  When starting Emacs, no X window is mapped.  And nothing
+   must be done to Emacs's own window if it is suspended (though that
+   rarely happens).  */
+
+static void
 XTset_terminal_modes ()
 {
 }
 
-/* This is called when exiting or suspending Emacs.
-   Exiting will make the X-windows go away, and suspending
-   requires no action.  */
+/* This is called when exiting or suspending Emacs.  Exiting will make
+   the X-windows go away, and suspending requires no action.  */
 
-static
+static void
 XTreset_terminal_modes ()
 {
-/*  XTclear_frame ();  */
 }
+
+
 \f
-/* Set the nominal cursor position of the frame.
-   This is where display update commands will take effect.
  This does not affect the place where the cursor-box is displayed.  */
+/***********************************************************************
+                           Output Cursor
***********************************************************************/
 
-static int
-XTcursor_to (row, col)
-     register int row, col;
+/* Set the global variable output_cursor to CURSOR.  All cursor
+   positions are relative to updated_window.  */
+
+static void
+set_output_cursor (cursor)
+    struct cursor_pos *cursor;
+{
+  output_cursor.hpos = cursor->hpos;
+  output_cursor.vpos = cursor->vpos;
+  output_cursor.x = cursor->x;
+  output_cursor.y = cursor->y;
+}
+
+
+/* Set a nominal cursor position.
+
+   HPOS and VPOS are column/row positions in a window glyph matrix.  X
+   and Y are window text area relative pixel positions.
+   
+   If this is done during an update, updated_window will contain the
+   window that is being updated and the position is the future output
+   cursor position for that window.  If updated_window is null, use
+   selected_window and display the cursor at the given position.  */
+
+static void
+XTcursor_to (vpos, hpos, y, x)
+     int vpos, hpos, y, x;
 {
-  int mask;
-  int orow = row;
+  struct window *w;
+
+  /* If updated_window is not set, work on selected_window.  */
+  if (updated_window)
+    w = updated_window;
+  else
+    w = XWINDOW (selected_window);
 
-  curs_x = col;
-  curs_y = row;
+  /* Set the output cursor.  */
+  output_cursor.hpos = hpos;
+  output_cursor.vpos = vpos;
+  output_cursor.x = x;
+  output_cursor.y = y;
 
-  if (updating_frame == 0)
+  /* If not called as part of an update, really display the cursor.
+     This will also set the cursor position of W.  */
+  if (updated_window == NULL)
     {
       BLOCK_INPUT;
-      x_display_cursor (selected_frame, 1, curs_x, curs_y);
+      x_display_cursor (w, 1, hpos, vpos, x, y);
       XFlush (FRAME_X_DISPLAY (selected_frame));
       UNBLOCK_INPUT;
     }
 }
-\f
 
-/* Return a pointer to per char metric information in FONT of a
-   character pointed by B (*XChar2b).  */
+
+\f
+/***********************************************************************
+                          Display Iterator
+ ***********************************************************************/
+
+/* Function prototypes of this page.  */
+
+static struct face *x_get_glyph_face_and_encoding P_ ((struct frame *,
+                                                      struct glyph *,
+                                                      XChar2b *));
+static struct face *x_get_char_face_and_encoding P_ ((struct frame *, int,
+                                                     int, XChar2b *, int));
+static XCharStruct *x_per_char_metric P_ ((XFontStruct *, XChar2b *));
+static void x_encode_char P_ ((int, XChar2b *, struct font_info *));
+static void x_append_glyph P_ ((struct it *));
+static void x_append_stretch_glyph P_ ((struct it *it, Lisp_Object,
+                                       int, int, double));
+static void x_produce_glyphs P_ ((struct it *));
+static void x_produce_special_glyphs P_ ((struct it *, enum display_element_type));
+static void x_produce_image_glyph P_ ((struct it *it));
+     
+
+/* Return a pointer to per-char metric information in FONT of a
+   character pointed by B which is a pointer to an XChar2b.  */
 
 #define PER_CHAR_METRIC(font, b)                                          \
   ((font)->per_char                                                       \
@@ -506,937 +1116,3686 @@ XTcursor_to (row, col)
         : 0))                                                             \
    : &((font)->max_bounds))
 
-/* Display a sequence of N glyphs found at GP.
-   WINDOW is the x-window to output to.  LEFT and TOP are starting coords.
-   HL is 1 if this text is highlighted, 2 if the cursor is on it,
-   3 if should appear in its mouse-face.
-   JUST_FOREGROUND if 1 means draw only the foreground;
-   don't alter the background.
 
-   CMPCHARP if non NULL is a pointer to the struct cmpchar_info, which
-   means drawing glyphs on the same column.  This is set to non NULL
-   only when recursively called within dumpglyphs to draw a composite
-   character specified by CMPCHAR.
+/* Get metrics of character CHAR2B in FONT.  Value is always non-null.
+   If CHAR2B is not contained in FONT, the font's default character
+   metric is returned.  */
 
-   FONT is the default font to use (for glyphs whose font-code is 0).
-
-   Since the display generation code is responsible for calling
-   compute_char_face and compute_glyph_face on everything it puts in
-   the display structure, we can assume that the face code on each
-   glyph is a valid index into FRAME_COMPUTED_FACES (f), and the one
-   to which we can actually apply intern_face.
-   Call this function with input blocked.
-
-   Return overall pixel width of the drawn glyphs.  */
-
-#if 1
-/* This is the multi-face code.  */
+static INLINE XCharStruct *
+x_per_char_metric (font, char2b)
+     XFontStruct *font;
+     XChar2b *char2b;
+{
+  /* The result metric information.  */
+  XCharStruct *pcm = NULL;
 
-static int
-dumpglyphs (f, left, top, gp, n, hl, just_foreground, cmpcharp)
-     struct frame *f;
-     int left, top;
-     register GLYPH *gp; /* Points to first GLYPH. */
-     register int n;  /* Number of glyphs to display. */
-     int hl;
-     int just_foreground;
-     struct cmpchar_info *cmpcharp;
-{
-  /* Holds characters to be displayed. */
-  XChar2b *buf = (XChar2b *) alloca (FRAME_WINDOW_WIDTH (f) * sizeof (*buf));
-  register XChar2b *cp;                /* Steps through buf[]. */
-  register int tlen = GLYPH_TABLE_LENGTH;
-  register Lisp_Object *tbase = GLYPH_TABLE_BASE;
-  Window window = FRAME_X_WINDOW (f);
-  int orig_left = left;
-  int gidx = 0;
-  int i;
+  xassert (font && char2b);
 
-  while (n > 0)
-    {
-      /* Get the face-code of the next GLYPH.  */
-      int cf, len;
-      GLYPH g = *gp;
-      int ch, first_ch, charset;
-      /* HIGHEST and LOWEST are used while drawing a composite
-         character.  The meanings are described later.  */
-      int highest, lowest;
-
-      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
-      cf = (cmpcharp ? cmpcharp->face_work : FAST_GLYPH_FACE (g));
-      ch = FAST_GLYPH_CHAR (g);
-      if (gidx == 0) first_ch = ch;
-      charset = CHAR_CHARSET (ch);
-      if (charset == CHARSET_COMPOSITION)
+  if (font->per_char != NULL)
+    {
+      if (font->min_byte1 == 0 && font->max_byte1 == 0)
        {
-         /* We must draw components of the composite character on the
-             same column.  */
-         cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (ch)];
-
-         /* Set the face in the slot for work.  */
-         cmpcharp->face_work = cf;
-
-         /* We don't need the return value ... */
-         dumpglyphs (f, left, top, cmpcharp->glyph, cmpcharp->glyph_len,
-                     hl, just_foreground, cmpcharp);
-         /* ... because the width of just drawn text can be
-             calculated as follows.  */
-         left += FONT_WIDTH (f->output_data.x->font) * cmpcharp->width;
-
-         ++gp, --n;
-         while (gp && (*gp & GLYPH_MASK_PADDING)) ++gp, --n;
-         cmpcharp = NULL;
-         continue;
+         /* min_char_or_byte2 specifies the linear character index
+            corresponding to the first element of the per_char array,
+            max_char_or_byte2 is the index of the last character.  A
+            character with non-zero CHAR2B->byte1 is not in the font.
+            A character with byte2 less than min_char_or_byte2 or
+            greater max_char_or_byte2 is not in the font.  */
+         if (char2b->byte1 == 0
+             && char2b->byte2 >= font->min_char_or_byte2
+             && char2b->byte2 <= font->max_char_or_byte2)
+           pcm = font->per_char + char2b->byte2 - font->min_char_or_byte2;
        }
-
-      /* Find the run of consecutive glyphs which can be drawn with
-        the same GC (i.e. the same charset and the same face-code).
-        Extract their character codes into BUF.
-        If CMPCHARP is not NULL, face-code is not checked because we
-        use only the face specified in `cmpcharp->face_work'.  */
-      cp = buf;
-      while (n > 0)
+      else
        {
-         int this_charset, c1, c2;
-
-         g = *gp;
-         GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
-         ch = FAST_GLYPH_CHAR (g);
-         SPLIT_CHAR (ch, this_charset, c1, c2);
-         if (this_charset != charset
-             || (cmpcharp == NULL && FAST_GLYPH_FACE (g) != cf))
-           break;
-
-         if (c2 > 0)
-           cp->byte1 = c1, cp->byte2 = c2;
-         else
-           cp->byte1 = 0, cp->byte2 = c1;
-         ++cp;
-         ++gp, --n;
-         while (gp && (*gp & GLYPH_MASK_PADDING))
-           ++gp, --n;
+         /* If either min_byte1 or max_byte1 are nonzero, both
+            min_char_or_byte2 and max_char_or_byte2 are less than
+            256, and the 2-byte character index values corresponding
+            to the per_char array element N (counting from 0) are:
+
+            byte1 = N/D + min_byte1
+            byte2 = N\D + min_char_or_byte2
+
+            where:
+
+            D = max_char_or_byte2 - min_char_or_byte2 + 1
+            / = integer division
+            \ = integer modulus  */
+         if (char2b->byte1 >= font->min_byte1
+             && char2b->byte1 <= font->max_byte1
+             && char2b->byte2 >= font->min_char_or_byte2
+             && char2b->byte2 <= font->max_char_or_byte2)
+           {
+             pcm = (font->per_char
+                    + ((font->max_char_or_byte2 - font->min_char_or_byte2 + 1)
+                       * (char2b->byte1 - font->min_byte1))
+                    + (char2b->byte2 - font->min_char_or_byte2));
+           }
        }
+    }
+  else
+    {
+      /* If the per_char pointer is null, all glyphs between the first
+        and last character indexes inclusive have the same
+        information, as given by both min_bounds and max_bounds.  */
+      if (char2b->byte2 >= font->min_char_or_byte2
+         && char2b->byte2 <= font->max_char_or_byte2)
+       pcm = &font->max_bounds;
+    }
 
-      /* LEN gets the length of the run.  */
-      len = cp - buf;
-      /* Now output this run of chars, with the font and pixel values
-        determined by the face code CF.  */
-      {
-       struct face *face = FRAME_DEFAULT_FACE (f);
-       XFontStruct *font = NULL;
-       GC gc;
-       int stippled = 0;
-       int line_height = f->output_data.x->line_height;
-       /* Pixel width of each glyph in this run.  */
-       int glyph_width
-         = (FONT_WIDTH (f->output_data.x->font)
-            * (cmpcharp ? cmpcharp->width : CHARSET_WIDTH (charset)));
-       /* Overall pixel width of this run.  */
-       int run_width
-         = (FONT_WIDTH (f->output_data.x->font)
-            * (cmpcharp ? cmpcharp->width : len * CHARSET_WIDTH (charset)));
-       /* A flag to tell if we have already filled background.  We
-          fill background in advance in the following cases:
-          1) A face has stipple.
-          2) A height of font is shorter than LINE_HEIGHT.
-          3) Drawing a composite character.
-          4) Font has non-zero _MULE_BASELINE_OFFSET property.
-          After filling background, we draw glyphs by XDrawString16.  */
-       int background_filled;
-       /* Baseline position of a character, offset from TOP.  */
-       int baseline;
-       /* The property value of `_MULE_RELATIVE_COMPOSE' and
-           `_MULE_DEFAULT_ASCENT'.  */
-       int relative_compose = 0, default_ascent = 0;
-       /* 1 if we find no font or a font of inappropriate size.  */
-       int require_clipping;
-
-       /* HL = 3 means use a mouse face previously chosen.  */
-       if (hl == 3)
-         cf = FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id;
-
-       /* First look at the face of the text itself.  */
-       if (cf != 0)
-         {
-           /* It's possible for the display table to specify
-              a face code that is out of range.  Use 0 in that case.  */
-           if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
-               || FRAME_COMPUTED_FACES (f) [cf] == 0)
-             cf = 0;
-
-           if (cf == 1)
-             face = FRAME_MODE_LINE_FACE (f);
-           else
-             face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
-           if (FACE_STIPPLE (face))
-             stippled = 1;
-         }
 
-       /* Then comes the distinction between modeline and normal text.  */
-       else if (hl == 0)
-         ;
-       else if (hl == 1)
-         {
-           face = FRAME_MODE_LINE_FACE (f);
-           if (FACE_STIPPLE (face))
-             stippled = 1;
-         }
+  if (pcm == NULL || pcm->width == 0)
+    {
+      /* Character not contained in the font.  FONT->default_char
+        gives the character that will be printed.  FONT->default_char
+        is a 16-bit character code with byte1 in the most significant
+        byte and byte2 in the least significant byte.  */
+      XChar2b default_char;
+      default_char.byte1 = (font->default_char >> BITS_PER_CHAR) & 0xff;
+      default_char.byte2 = font->default_char & 0xff;
+
+      /* Avoid an endless recursion if FONT->default_char itself
+        hasn't per char metrics.  handa@etl.go.jp reports that some
+        fonts have this problem.  */
+      if (default_char.byte1 != char2b->byte1
+         || default_char.byte2 != char2b->byte2)
+       pcm = x_per_char_metric (font, &default_char);
+      else
+       pcm = &font->max_bounds;
+    }
+  
+  return pcm;
+}
+
+
+/* Encode CHAR2B using encoding information from FONT_INFO.  CHAR2B is
+   the two-byte form of C.  Encoding is returned in *CHAR2B.  */
+
+static INLINE void
+x_encode_char (c, char2b, font_info)
+     int c;
+     XChar2b *char2b;
+     struct font_info *font_info;
+{
+  int charset = CHAR_CHARSET (c);
+  XFontStruct *font = font_info->font;
+
+  /* FONT_INFO may define a scheme by which to encode byte1 and byte2.
+     This may be either a program in a special encoder language or a
+     fixed encoding.  */
+  if (font_info->font_encoder)
+    {
+      /* It's a program.  */
+      struct ccl_program *ccl = font_info->font_encoder;
+
+      if (CHARSET_DIMENSION (charset) == 1)
+       {
+         ccl->reg[0] = charset;
+         ccl->reg[1] = char2b->byte2;
+       }
+      else
+       {
+         ccl->reg[0] = charset;
+         ccl->reg[1] = char2b->byte1;
+         ccl->reg[2] = char2b->byte2;
+       }
+      
+      ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
+      
+      /* We assume that MSBs are appropriately set/reset by CCL
+        program.  */
+      if (font->max_byte1 == 0)        /* 1-byte font */
+       char2b->byte2 = ccl->reg[1];
+      else
+       char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
+    }
+  else if (font_info->encoding[charset])
+    {
+      /* Fixed encoding scheme.  See fontset.h for the meaning of the
+        encoding numbers.  */
+      int enc = font_info->encoding[charset];
+      
+      if ((enc == 1 || enc == 2)
+         && CHARSET_DIMENSION (charset) == 2)
+       char2b->byte1 |= 0x80;
+      
+      if (enc == 1 || enc == 3)
+       char2b->byte2 |= 0x80;
+    }
+}
+
+
+/* Get face and two-byte form of character C in face FACE_ID on frame
+   F.  The encoding of C is returned in *CHAR2B.  MULTIBYTE_P non-zero
+   means we want to display multibyte text.  Value is a pointer to a
+   realized face that is ready for display.  */
+
+static INLINE struct face *
+x_get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p)
+     struct frame *f;
+     int c, face_id;
+     XChar2b *char2b;
+     int multibyte_p;
+{
+  struct face *face = FACE_FROM_ID (f, face_id);
+
+  if (!multibyte_p)
+    {
+      /* Unibyte case.  We don't have to encode, but we have to make
+        sure to use a face suitable for unibyte.  */
+      char2b->byte1 = 0;
+      char2b->byte2 = c;
+      
+      if (!FACE_SUITABLE_FOR_CHARSET_P (face, -1))
+       {
+         face_id = FACE_FOR_CHARSET (f, face_id, -1);
+         face = FACE_FROM_ID (f, face_id);
+       }
+    }
+  else if (c < 128 && face_id < BASIC_FACE_ID_SENTINEL)
+    {
+      /* Case of ASCII in a face known to fit ASCII.  */
+      char2b->byte1 = 0;
+      char2b->byte2 = c;
+    }
+  else
+    {
+      int c1, c2, charset;
+      
+      /* Split characters into bytes.  If c2 is -1 afterwards, C is
+        really a one-byte character so that byte1 is zero.  */
+      SPLIT_CHAR (c, charset, c1, c2);
+      if (c2 > 0)
+       char2b->byte1 = c1, char2b->byte2 = c2;
+      else
+       char2b->byte1 = 0, char2b->byte2 = c1;
+
+      /* Get the face for displaying C.  If `face' is not suitable for
+        charset, get the one that fits.  (This can happen for the
+        translations of composite characters where the glyph
+        specifies a face for ASCII, but translations have a different
+        charset.)  */
+      if (!FACE_SUITABLE_FOR_CHARSET_P (face, charset))
+       {
+         face_id = FACE_FOR_CHARSET (f, face_id, charset);
+         face = FACE_FROM_ID (f, face_id);
+       }
+  
+      /* Maybe encode the character in *CHAR2B.  */
+      if (charset != CHARSET_ASCII)
+       {
+         struct font_info *font_info
+           = FONT_INFO_FROM_ID (f, face->font_info_id);
+         if (font_info)
+           {
+             x_encode_char (c, char2b, font_info);
+             if (charset == charset_latin_iso8859_1)
+               {
+                 xassert (((XFontStruct *) font_info->font)->max_char_or_byte2
+                          >= 0x80);
+                 char2b->byte2 |= 0x80;
+               }
+           }
+       }
+    }
+
+  /* Make sure X resources of the face are allocated.  */
+  xassert (face != NULL);
+  PREPARE_FACE_FOR_DISPLAY (f, face);
+  
+  return face;
+}
+
+
+/* Get face and two-byte form of character glyph GLYPH on frame F.
+   The encoding of GLYPH->u.ch.code is returned in *CHAR2B.  Value is
+   a pointer to a realized face that is ready for display.  */
+
+static INLINE struct face *
+x_get_glyph_face_and_encoding (f, glyph, char2b)
+     struct frame *f;
+     struct glyph *glyph;
+     XChar2b *char2b;
+{
+  struct face *face;
+
+  xassert (glyph->type == CHAR_GLYPH);
+  face = FACE_FROM_ID (f, glyph->u.ch.face_id);
+
+  if (!glyph->multibyte_p)
+    {
+      /* Unibyte case.  We don't have to encode, but we have to make
+        sure to use a face suitable for unibyte.  */
+      char2b->byte1 = 0;
+      char2b->byte2 = glyph->u.ch.code;
+    }
+  else if (glyph->u.ch.code < 128
+          && glyph->u.ch.face_id < BASIC_FACE_ID_SENTINEL)
+    {
+      /* Case of ASCII in a face known to fit ASCII.  */
+      char2b->byte1 = 0;
+      char2b->byte2 = glyph->u.ch.code;
+    }
+  else
+    {
+      int c1, c2, charset;
+      
+      /* Split characters into bytes.  If c2 is -1 afterwards, C is
+        really a one-byte character so that byte1 is zero.  */
+      SPLIT_CHAR (glyph->u.ch.code, charset, c1, c2);
+      if (c2 > 0)
+       char2b->byte1 = c1, char2b->byte2 = c2;
+      else
+       char2b->byte1 = 0, char2b->byte2 = c1;
+
+      /* Maybe encode the character in *CHAR2B.  */
+      if (charset != CHARSET_ASCII)
+       {
+         struct font_info *font_info
+           = FONT_INFO_FROM_ID (f, face->font_info_id);
+         if (font_info)
+           {
+             x_encode_char (glyph->u.ch.code, char2b, font_info);
+             if (charset == charset_latin_iso8859_1)
+               char2b->byte2 |= 0x80;
+           }
+       }
+    }
+
+  /* Make sure X resources of the face are allocated.  */
+  xassert (face != NULL);
+  PREPARE_FACE_FOR_DISPLAY (f, face);
+  return face;
+}
+
+
+/* Store one glyph for IT->char_to_display in IT->glyph_row.  
+   Called from x_produce_glyphs when IT->glyph_row is non-null.  */
+
+static INLINE void
+x_append_glyph (it)
+     struct it *it;
+{
+  struct glyph *glyph;
+  enum glyph_row_area area = it->area;
+  
+  xassert (it->glyph_row);
+  xassert (it->char_to_display != '\n' && it->char_to_display != '\t');
+  
+  glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+  if (glyph < it->glyph_row->glyphs[area + 1])
+    {
+      /* Play it safe.  If sub-structures of the glyph are not all the
+        same size, it otherwise be that some bits stay set.  This
+        would prevent a comparison with GLYPH_EQUAL_P.  */
+      glyph->u.val = 0;
+      
+      glyph->type = CHAR_GLYPH;
+      glyph->pixel_width = it->pixel_width;
+      glyph->u.ch.code = it->char_to_display;
+      glyph->u.ch.face_id = it->face_id;
+      glyph->charpos = CHARPOS (it->position);
+      glyph->object = it->object;
+      glyph->left_box_line_p = it->start_of_box_run_p;
+      glyph->right_box_line_p = it->end_of_box_run_p;
+      glyph->voffset = it->voffset;
+      glyph->multibyte_p = it->multibyte_p;
+      glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
+                                     || it->phys_descent > it->descent);
+      ++it->glyph_row->used[area];
+    }
+}
+
+
+/* Change IT->ascent and IT->height according to the setting of
+   IT->voffset.  */
+
+static INLINE void
+take_vertical_position_into_account (it)
+     struct it *it;
+{
+  if (it->voffset)
+    {
+      if (it->voffset < 0)
+       /* Increase the ascent so that we can display the text higher
+          in the line.  */
+       it->ascent += abs (it->voffset);
+      else
+       /* Increase the descent so that we can display the text lower
+          in the line.  */
+       it->descent += it->voffset;
+    }
+}
+
+
+/* Produce glyphs/get display metrics for the image IT is loaded with.
+   See the description of struct display_iterator in dispextern.h for
+   an overview of struct display_iterator.  */
+
+static void
+x_produce_image_glyph (it)
+     struct it *it;
+{
+  struct image *img;
+  struct face *face;
+
+  xassert (it->what == IT_IMAGE);
+
+  face = FACE_FROM_ID (it->f, it->face_id);
+  img = IMAGE_FROM_ID (it->f, it->image_id);
+  xassert (img);
+
+  /* Make sure X resources of the face and image are loaded.  */
+  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+  prepare_image_for_display (it->f, img);
+
+  it->ascent = it->phys_ascent = IMAGE_ASCENT (img);
+  it->descent = it->phys_descent = img->height + 2 * img->margin - it->ascent;
+  it->pixel_width = img->width + 2 * img->margin;
+
+  it->nglyphs = 1;
+  
+  if (face->box != FACE_NO_BOX)
+    {
+      it->ascent += face->box_line_width;
+      it->descent += face->box_line_width;
+      
+      if (it->start_of_box_run_p)
+       it->pixel_width += face->box_line_width;
+      if (it->end_of_box_run_p)
+       it->pixel_width += face->box_line_width;
+    }
+
+  take_vertical_position_into_account (it);
+  
+  if (it->glyph_row)
+    {
+      struct glyph *glyph;
+      enum glyph_row_area area = it->area;
+      
+      glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+      if (glyph < it->glyph_row->glyphs[area + 1])
+       {
+         glyph->type = IMAGE_GLYPH;
+         glyph->u.img.id = img->id;
+         glyph->u.img.face_id = it->face_id;
+         glyph->pixel_width = it->pixel_width;
+         glyph->charpos = CHARPOS (it->position);
+         glyph->object = it->object;
+         glyph->left_box_line_p = it->start_of_box_run_p;
+         glyph->right_box_line_p = it->end_of_box_run_p;
+         glyph->voffset = it->voffset;
+         glyph->multibyte_p = it->multibyte_p;
+         ++it->glyph_row->used[area];
+       }
+    }
+}
+
+
+/* Append a stretch glyph to IT->glyph_row.  OBJECT is the source
+   of the glyph, WIDTH and HEIGHT are the width and height of the 
+   stretch.  ASCENT is the percentage/100 of HEIGHT to use for the 
+   ascent of the glyph (0 <= ASCENT <= 1).  */
+  
+static void
+x_append_stretch_glyph (it, object, width, height, ascent)
+     struct it *it;
+     Lisp_Object object;
+     int width, height;
+     double ascent;
+{
+  struct glyph *glyph;
+  enum glyph_row_area area = it->area;
+
+  xassert (ascent >= 0 && ascent <= 1);
+  
+  glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+  if (glyph < it->glyph_row->glyphs[area + 1])
+    {
+      glyph->type = STRETCH_GLYPH;
+      glyph->u.stretch.ascent = height * ascent;
+      glyph->u.stretch.height = height;
+      glyph->u.stretch.face_id = it->face_id;
+      glyph->pixel_width = width;
+      glyph->charpos = CHARPOS (it->position);
+      glyph->object = object;
+      glyph->left_box_line_p = it->start_of_box_run_p;
+      glyph->right_box_line_p = it->end_of_box_run_p;
+      glyph->voffset = it->voffset;
+      glyph->multibyte_p = it->multibyte_p;
+      ++it->glyph_row->used[area];
+    }
+}
+
+
+/* Produce a stretch glyph for iterator IT.  IT->object is the value
+   of the glyph property displayed.  The value must be a list
+   `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
+   being recognized:
+
+   1. `:width WIDTH' specifies that the space should be WIDTH *
+   canonical char width wide.  WIDTH may be an integer or floating 
+   point number.
+
+   2. `:relative-width FACTOR' specifies that the width of the stretch
+   should be computed from the width of the first character having the
+   `glyph' property, and should be FACTOR times that width.
+
+   3. `:align-to HPOS' specifies that the space should be wide enough
+   to reach HPOS, a value in canonical character units.
+
+   Exactly one of the above pairs must be present.  
+
+   4. `:height HEIGHT' specifies that the height of the stretch produced
+   should be HEIGHT, measured in canonical character units.
+
+   5. `:relative-height FACTOR' specifies that the height of the the
+   stretch should be FACTOR times the height of the characters having
+   the glyph property.
+
+   Either none or exactly one of 4 or 5 must be present.
+
+   6. `:ascent ASCENT'  specifies that ASCENT percent of the height
+   of the stretch should be used for the ascent of the stretch.
+   ASCENT must be in the range 0 <= ASCENT <= 100.  */
+
+#define NUMVAL(X)                              \
+     ((INTEGERP (X) || FLOATP (X))             \
+      ? XFLOATINT (X)                          \
+      : - 1)
+
+
+static void
+x_produce_stretch_glyph (it)
+     struct it *it;
+{
+  /* (space :width WIDTH :height HEIGHT.  */
+  extern Lisp_Object QCwidth, QCheight, QCascent, Qspace;
+  extern Lisp_Object QCrelative_width, QCrelative_height;
+  extern Lisp_Object QCalign_to;
+  Lisp_Object prop, plist;
+  double width = 0, height = 0, ascent = 0;
+  struct face *face = FACE_FROM_ID (it->f, it->face_id);
+  XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
+
+  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+  
+  /* List should start with `space'.  */
+  xassert (CONSP (it->object) && EQ (XCAR (it->object), Qspace));
+  plist = XCDR (it->object);
+
+  /* Compute the width of the stretch.  */
+  if (prop = Fplist_get (plist, QCwidth),
+      NUMVAL (prop) > 0)
+    /* Absolute width `:width WIDTH' specified and valid.  */
+    width = NUMVAL (prop) * CANON_X_UNIT (it->f);
+  else if (prop = Fplist_get (plist, QCrelative_width),
+          NUMVAL (prop) > 0)
+    {
+      /* Relative width `:relative-width FACTOR' specified and valid.
+        Compute the width of the characters having the `glyph'
+        property.  */
+      struct it it2;
+      unsigned char *p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
+      
+      it2 = *it;
+      if (it->multibyte_p)
+       {
+         int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
+                       - IT_BYTEPOS (*it));
+         it2.c = STRING_CHAR_AND_LENGTH (p, maxlen, it2.len);
+       }
+      else
+       it2.c = *p, it2.len = 1;
+
+      it2.glyph_row = NULL;
+      it2.what = IT_CHARACTER;
+      x_produce_glyphs (&it2);
+      width = NUMVAL (prop) * it2.pixel_width;
+    }
+  else if (prop = Fplist_get (plist, QCalign_to),
+          NUMVAL (prop) > 0)
+    width = NUMVAL (prop) * CANON_X_UNIT (it->f) - it->current_x;
+  else
+    /* Nothing specified -> width defaults to canonical char width.  */
+    width = CANON_X_UNIT (it->f);
+  
+  /* Compute height.  */
+  if (prop = Fplist_get (plist, QCheight),
+      NUMVAL (prop) > 0)
+    height = NUMVAL (prop) * CANON_Y_UNIT (it->f);
+  else if (prop = Fplist_get (plist, QCrelative_height),
+          NUMVAL (prop) > 0)
+    height = FONT_HEIGHT (font) * NUMVAL (prop);
+  else
+    height = FONT_HEIGHT (font);
+
+  /* Compute percentage of height used for ascent.  If 
+     `:ascent ASCENT' is present and valid, use that.  Otherwise,
+     derive the ascent from the font in use.  */
+  if (prop = Fplist_get (plist, QCascent),
+      NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
+    ascent = NUMVAL (prop) / 100.0;
+  else
+    ascent = (double) font->ascent / FONT_HEIGHT (font);
+
+  if (width <= 0)
+    width = 1;
+  if (height <= 0)
+    height = 1;
+
+  if (it->glyph_row)
+    {
+      Lisp_Object object = it->stack[it->sp - 1].string;
+      if (!STRINGP (object))
+       object = it->w->buffer;
+      x_append_stretch_glyph (it, object, width, height, ascent);
+    }
+
+  it->pixel_width = width;
+  it->ascent = it->phys_ascent = height * ascent;
+  it->descent = it->phys_descent = height - it->ascent;
+  it->nglyphs = 1;
+
+  if (face->box != FACE_NO_BOX)
+    {
+      it->ascent += face->box_line_width;
+      it->descent += face->box_line_width;
+      
+      if (it->start_of_box_run_p)
+       it->pixel_width += face->box_line_width;
+      if (it->end_of_box_run_p)
+       it->pixel_width += face->box_line_width;
+    }
+  
+  take_vertical_position_into_account (it);
+}
+
+
+/* Produce glyphs/get display metrics for the display element IT is
+   loaded with.  See the description of struct display_iterator in
+   dispextern.h for an overview of struct display_iterator.  */
+
+static void
+x_produce_glyphs (it)
+     struct it *it;
+{
+  if (it->what == IT_CHARACTER)
+    {
+      XChar2b char2b;
+      XFontStruct *font;
+      struct face *face;
+      XCharStruct *pcm;
+      struct it ci;
+      int font_not_found_p;
+      int c;
+
+      /* Maybe translate single-byte characters to multibyte.  */
+      it->char_to_display = it->c;
+      if (unibyte_display_via_language_environment
+         && SINGLE_BYTE_CHAR_P (it->c)
+         && (it->c >= 0240
+             || (it->c >= 0200
+                 && !NILP (Vnonascii_translation_table))))
+       {
+         it->char_to_display = unibyte_char_to_multibyte (it->c);
+         it->charset = CHAR_CHARSET (it->char_to_display);
+       }
+      
+      /* Get face and font to use.  Encode IT->char_to_display.  */
+      face = x_get_char_face_and_encoding (it->f, it->char_to_display,
+                                          it->face_id, &char2b,
+                                          it->multibyte_p);
+      font = face->font;
+
+      /* When no suitable font found, use the default font.  */
+      font_not_found_p = font == NULL;
+      if (font_not_found_p)
+       font = FRAME_FONT (it->f);
+
+      if (it->char_to_display >= ' '
+         && (!it->multibyte_p || it->char_to_display < 128))
+       {
+         /* Either unibyte or ASCII.  */
+         int stretched_p;
+
+         it->nglyphs = 1;
+
+         pcm = x_per_char_metric (font, &char2b);
+         it->ascent = font->ascent;
+         it->descent = font->descent;
+         it->phys_ascent = pcm->ascent;
+         it->phys_descent = pcm->descent;
+         it->pixel_width = pcm->width;
+
+         /* If this is a space inside a region of text with
+            `space-width' property, change its width.  */
+         stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
+         if (stretched_p)
+           it->pixel_width *= XFLOATINT (it->space_width);
+
+         /* If face has a box, add the box thickness to the character
+            height.  If character has a box line to the left and/or
+            right, add the box line width to the character's width.  */
+         if (face->box != FACE_NO_BOX)
+           {
+             int thick = face->box_line_width;
+             
+             it->ascent += thick;
+             it->descent += thick;
+             
+             if (it->start_of_box_run_p)
+               it->pixel_width += thick;
+             if (it->end_of_box_run_p)
+               it->pixel_width += thick;
+           }
+
+         /* If face has an overline, add the height of the overline
+            (1 pixel) and a 1 pixel margin to the character height.  */
+         if (face->overline_p)
+           it->ascent += 2;
+
+         take_vertical_position_into_account (it);
+  
+         /* If we have to actually produce glyphs, do it.  */
+         if (it->glyph_row)
+           {
+             if (stretched_p)
+               {
+                 /* Translate a space with a `space-width' property
+                    into a stretch glyph.  */
+                 double ascent = (double) font->ascent / FONT_HEIGHT (font);
+                 x_append_stretch_glyph (it, it->object, it->pixel_width, 
+                                         it->ascent + it->descent, ascent);
+               }
+             else
+               x_append_glyph (it);
+
+             /* If characters with lbearing or rbearing are displayed
+                in this line, record that fact in a flag of the
+                glyph row.  This is used to optimize X output code.  */
+             if (pcm->lbearing < 0
+                 || pcm->rbearing > pcm->width)
+               it->glyph_row->contains_overlapping_glyphs_p = 1;
+           }
+       }
+      else if (it->char_to_display == '\n')
+       {
+         /* A newline has no width but we need the height of the line.  */
+         it->pixel_width = 0;
+         it->nglyphs = 0;
+         it->ascent = it->phys_ascent = font->ascent;
+         it->descent = it->phys_descent = font->descent;
+      
+         if (face->box != FACE_NO_BOX)
+           {
+             int thick = face->box_line_width;
+             it->ascent += thick;
+             it->descent += thick;
+           }
+       }
+      else if (it->char_to_display == '\t')
+       {
+         int tab_width = it->tab_width * CANON_X_UNIT (it->f);
+         int x = (it->current_x
+                  - it->prompt_width
+                  + it->continuation_lines_width);
+         int next_tab_x = ((1 + x + tab_width - 1) / tab_width) * tab_width;
+      
+         it->pixel_width = next_tab_x - x;
+         it->nglyphs = 1;
+         it->ascent = it->phys_ascent = font->ascent;
+         it->descent = it->phys_descent = font->descent;
+         
+         if (it->glyph_row)
+           {
+             double ascent = (double) it->ascent / (it->ascent + it->descent);
+             x_append_stretch_glyph (it, it->object, it->pixel_width, 
+                                     it->ascent + it->descent, ascent);
+           }
+       }
+      else 
+       {
+         /* A multi-byte character.  Assume that the display width of the
+            character is the width of the character multiplied by the
+            width of the font.  There has to be better support for
+            variable sizes in cmpchar_info to do anything better than
+            that.
+
+            Note: composite characters are represented as one glyph in
+            the glyph matrix.  There are no padding glyphs.  */
+         if (it->charset == CHARSET_COMPOSITION)
+           {
+             struct cmpchar_info *cmpcharp;
+             int idx;
+
+             idx = COMPOSITE_CHAR_ID (it->char_to_display);
+             cmpcharp = cmpchar_table[idx];
+             it->pixel_width = font->max_bounds.width * cmpcharp->width;
+         
+             /* There are no padding glyphs, so there is only one glyph
+                to produce for the composite char.  Important is that
+                pixel_width, ascent and descent are the values of what is
+                drawn by draw_glyphs.  */
+             it->nglyphs = 1;
+
+             /* These settings may not be correct.  We must have more
+                information in cmpcharp to do the correct setting.  */
+             it->ascent = font->ascent;
+             it->descent = font->descent;
+             it->phys_ascent = font->max_bounds.ascent;
+             it->phys_descent = font->max_bounds.descent;
+           }
+         else
+           {
+             /* If we found a font, this font should give us the right
+                metrics.  If we didn't find a font, use the frame's
+                default font and calculate the width of the character
+                from the charset width; this is what old redisplay code
+                did.  */
+             pcm = x_per_char_metric (font, &char2b);
+             it->pixel_width = pcm->width;
+             if (font_not_found_p)
+               it->pixel_width *= CHARSET_WIDTH (it->charset);
+             it->nglyphs = 1;
+             it->ascent = font->ascent;
+             it->descent = font->descent;
+             it->phys_ascent = pcm->ascent;
+             it->phys_descent = pcm->descent;
+             if (it->glyph_row
+                 && (pcm->lbearing < 0
+                     || pcm->rbearing > pcm->width))
+               it->glyph_row->contains_overlapping_glyphs_p = 1;
+           }
+       
+         if (face->box != FACE_NO_BOX)
+           {
+             int thick = face->box_line_width;
+             it->ascent += thick;
+             it->descent += thick;
+         
+             if (it->start_of_box_run_p)
+               it->pixel_width += thick;
+             if (it->end_of_box_run_p)
+               it->pixel_width += thick;
+           }
+  
+         /* If face has an overline, add the height of the overline
+            (1 pixel) and a 1 pixel margin to the character height.  */
+         if (face->overline_p)
+           it->ascent += 2;
+
+         take_vertical_position_into_account (it);
+  
+         if (it->glyph_row)
+           x_append_glyph (it);
+       }
+    }
+  else if (it->what == IT_IMAGE)
+    x_produce_image_glyph (it);
+  else if (it->what == IT_STRETCH)
+    x_produce_stretch_glyph (it);
+
+  /* Accumulate dimensions.  */
+  xassert (it->ascent >= 0 && it->descent > 0);
+  if (it->area == TEXT_AREA)
+    it->current_x += it->pixel_width;
+  
+  it->max_ascent = max (it->max_ascent, it->ascent);
+  it->max_descent = max (it->max_descent, it->descent);
+  it->max_phys_ascent = max (it->max_phys_ascent, it->phys_ascent);
+  it->max_phys_descent = max (it->max_phys_descent, it->phys_descent);
+}
+
+
+/* Estimate the pixel height of the mode or top line on frame F.
+   FACE_ID specifies what line's height to estimate.  */
+
+int
+x_estimate_mode_line_height (f, face_id)
+     struct frame *f;
+     enum face_id face_id;
+{
+  int height = 1;
+
+  /* This function is called so early when Emacs starts that the face
+     cache and mode line face are not yet initialized.  */
+  if (FRAME_FACE_CACHE (f))
+      {
+       struct face *face = FACE_FROM_ID (f, face_id);
+       if (face)
+         height = FONT_HEIGHT (face->font) + 2 * face->box_line_width;
+      }
+  
+  return height;
+}
+
+\f
+/***********************************************************************
+                           Glyph display
+ ***********************************************************************/
+
+/* A sequence of glyphs to be drawn in the same face.
+
+   This data structure is not really completely X specific, so it
+   could possibly, at least partially, be useful for other systems.  It
+   is currently not part of the external redisplay interface because
+   it's not clear what other systems will need.  */
+
+struct glyph_string
+{
+  /* X-origin of the string.  */
+  int x;
+
+  /* Y-origin and y-position of the base line of this string.  */
+  int y, ybase;
+
+  /* The width of the string, not including a face extension.  */
+  int width;
+
+  /* The width of the string, including a face extension.  */
+  int background_width;
+
+  /* The height of this string.  This is the height of the line this
+     string is drawn in, and can be different from the height of the
+     font the string is drawn in.  */
+  int height;
+
+  /* Number of pixels this string overwrites in front of its x-origin.
+     This number is zero if the string has an lbearing >= 0; it is
+     -lbearing, if the string has an lbearing < 0.  */
+  int left_overhang;
+
+  /* Number of pixels this string overwrites past its right-most
+     nominal x-position, i.e. x + width.  Zero if the string's
+     rbearing is <= its nominal width, rbearing - width otherwise.  */
+  int right_overhang;
+
+  /* The frame on which the glyph string is drawn.  */
+  struct frame *f;
+
+  /* The window on which the glyph string is drawn.  */
+  struct window *w;
+
+  /* X display and window for convenience.  */
+  Display *display;
+  Window window;
+
+  /* The glyph row for which this string was built.  It determines the
+     y-origin and height of the string.  */
+  struct glyph_row *row;
+
+  /* The area within row.  */
+  enum glyph_row_area area;
+
+  /* Characters to be drawn, and number of characters.  */
+  XChar2b *char2b;
+  int nchars;
+
+  /* Character set of this glyph string.  */
+  int charset;
+
+  /* A face-override for drawing cursors, mouse face and similar.  */
+  enum draw_glyphs_face hl;
+
+  /* Face in which this string is to be drawn.  */
+  struct face *face;
+
+  /* Font in which this string is to be drawn.  */
+  XFontStruct *font;
+
+  /* Font info for this string.  */
+  struct font_info *font_info;
+
+  /* Non-null means this string describes (part of) a composite
+     character.  All characters from char2b are drawn at the same
+     x-origin in that case.  */
+  struct cmpchar_info *cmpcharp;
+
+  /* Index of this glyph string's first character in the glyph
+     definition of cmpcharp.  If this is zero, this glyph string
+     describes the first character of a composite character.  */
+  int gidx;
+
+  /* 1 means this glyph strings face has to be drawn to the right end
+     of the window's drawing area.  */
+  unsigned extends_to_end_of_line_p : 1;
+
+  /* 1 means the background of this string has been drawn.  */
+  unsigned background_filled_p : 1;
+
+  /* 1 means glyph string must be drawn with 16-bit functions.  */
+  unsigned two_byte_p : 1;
+
+  /* 1 means that the original font determined for drawing this glyph
+     string could not be loaded.  The member `font' has been set to
+     the frame's default font in this case.  */
+  unsigned font_not_found_p : 1;
+
+  /* 1 means that the face in which this glyph string is drawn has a
+     stipple pattern.  */
+  unsigned stippled_p : 1;
+
+  /* 1 means only the foreground of this glyph string must be drawn,
+     and we should use the physical height of the line this glyph
+     string appears in as clip rect.  */
+  unsigned for_overlaps_p : 1;
+
+  /* The GC to use for drawing this glyph string.  */
+  GC gc;
+
+  /* A pointer to the first glyph in the string.  This glyph
+     corresponds to char2b[0].  Needed to draw rectangles if
+     font_not_found_p is 1.  */
+  struct glyph *first_glyph;
+
+  /* Image, if any.  */
+  struct image *img;
+
+  struct glyph_string *next, *prev;
+};
+
+
+#if GLYPH_DEBUG
+
+static void
+x_dump_glyph_string (s)
+     struct glyph_string *s;
+{
+  fprintf (stderr, "glyph string\n");
+  fprintf (stderr, "  x, y, w, h = %d, %d, %d, %d\n",
+          s->x, s->y, s->width, s->height);
+  fprintf (stderr, "  ybase = %d\n", s->ybase);
+  fprintf (stderr, "  hl = %d\n", s->hl);
+  fprintf (stderr, "  left overhang = %d, right = %d\n",
+          s->left_overhang, s->right_overhang);
+  fprintf (stderr, "  nchars = %d\n", s->nchars);
+  fprintf (stderr, "  extends to end of line = %d\n",
+          s->extends_to_end_of_line_p);
+  fprintf (stderr, "  font height = %d\n", FONT_HEIGHT (s->font));
+  fprintf (stderr, "  bg width = %d\n", s->background_width);
+}
+
+#endif /* GLYPH_DEBUG */
+
+
+
+static void x_append_glyph_string_lists P_ ((struct glyph_string **,
+                                            struct glyph_string **,
+                                            struct glyph_string *,
+                                            struct glyph_string *));
+static void x_prepend_glyph_string_lists P_ ((struct glyph_string **,
+                                             struct glyph_string **,
+                                             struct glyph_string *,
+                                             struct glyph_string *));
+static void x_append_glyph_string P_ ((struct glyph_string **,
+                                      struct glyph_string **,
+                                      struct glyph_string *));
+static int x_left_overwritten P_ ((struct glyph_string *));
+static int x_left_overwriting P_ ((struct glyph_string *));
+static int x_right_overwritten P_ ((struct glyph_string *));
+static int x_right_overwriting P_ ((struct glyph_string *));
+static int x_fill_glyph_string P_ ((struct glyph_string *, int, int, int,
+                                   int));
+static void x_init_glyph_string P_ ((struct glyph_string *,
+                                       XChar2b *, struct window *,
+                                       struct glyph_row *,
+                                       enum glyph_row_area, int, 
+                                       enum draw_glyphs_face));
+static int x_draw_glyphs P_ ((struct window *, int , struct glyph_row *,
+                             enum glyph_row_area, int, int,
+                             enum draw_glyphs_face, int *, int *, int));
+static void x_set_glyph_string_clipping P_ ((struct glyph_string *));
+static void x_set_glyph_string_gc P_ ((struct glyph_string *));
+static void x_draw_glyph_string_background P_ ((struct glyph_string *,
+                                               int));
+static void x_draw_glyph_string_foreground P_ ((struct glyph_string *));
+static void x_draw_glyph_string_underline P_ ((struct glyph_string *));
+static void x_draw_glyph_string_box P_ ((struct glyph_string *));
+static void x_draw_glyph_string  P_ ((struct glyph_string *));
+static void x_compute_glyph_string_overhangs P_ ((struct glyph_string *));
+static void x_set_cursor_gc P_ ((struct glyph_string *));
+static void x_set_mode_line_face_gc P_ ((struct glyph_string *));
+static void x_set_mouse_face_gc P_ ((struct glyph_string *));
+static void x_get_glyph_overhangs P_ ((struct glyph *, struct frame *,
+                                      int *, int *));
+static void x_compute_overhangs_and_x P_ ((struct glyph_string *, int, int));
+static int x_alloc_lighter_color P_ ((struct frame *, Display *, Colormap,
+                                     unsigned long *, float, int));
+static void x_setup_relief_color P_ ((struct frame *, struct relief *,
+                                     float, int, unsigned long));
+static void x_setup_relief_colors P_ ((struct glyph_string *));
+static void x_draw_image_glyph_string P_ ((struct glyph_string *));
+static void x_draw_image_relief P_ ((struct glyph_string *));
+static void x_draw_image_foreground P_ ((struct glyph_string *));
+static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap));
+static void x_fill_image_glyph_string P_ ((struct glyph_string *));
+static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
+                                          int, int, int));
+static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
+                                   int, int, int, int, XRectangle *));
+static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
+                                int, int, int, XRectangle *));
+static void x_fix_overlapping_area P_ ((struct window *, struct glyph_row *,
+                                       enum glyph_row_area));
+
+
+/* Append the list of glyph strings with head H and tail T to the list
+   with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the result.  */
+
+static INLINE void
+x_append_glyph_string_lists (head, tail, h, t)
+     struct glyph_string **head, **tail;
+     struct glyph_string *h, *t;
+{
+  if (h)
+    {
+      if (*head)
+       (*tail)->next = h;
+      else
+       *head = h;
+      h->prev = *tail;
+      *tail = t;
+    }
+}
+
+
+/* Prepend the list of glyph strings with head H and tail T to the
+   list with head *HEAD and tail *TAIL.  Set *HEAD and *TAIL to the
+   result.  */
+
+static INLINE void
+x_prepend_glyph_string_lists (head, tail, h, t)
+     struct glyph_string **head, **tail;
+     struct glyph_string *h, *t;
+{
+  if (h)
+    {
+      if (*head)
+       (*head)->prev = t;
+      else
+       *tail = t;
+      t->next = *head;
+      *head = h;
+    }
+}
+
+
+/* Append glyph string S to the list with head *HEAD and tail *TAIL.
+   Set *HEAD and *TAIL to the resulting list.  */
+
+static INLINE void
+x_append_glyph_string (head, tail, s)
+     struct glyph_string **head, **tail;
+     struct glyph_string *s;
+{
+  s->next = s->prev = NULL;
+  x_append_glyph_string_lists (head, tail, s, s);
+}
+
+
+/* Set S->gc to a suitable GC for drawing glyph string S in cursor
+   face.  */
+
+static void
+x_set_cursor_gc (s)
+     struct glyph_string *s;
+{
+  if (s->font == FRAME_FONT (s->f)
+      && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
+      && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
+      && !s->cmpcharp)
+    s->gc = s->f->output_data.x->cursor_gc;
+  else
+    {
+      /* Cursor on non-default face: must merge.  */
+      XGCValues xgcv;
+      unsigned long mask;
+
+      xgcv.background = s->f->output_data.x->cursor_pixel;
+      xgcv.foreground = s->face->background;
+
+      /* If the glyph would be invisible, try a different foreground.  */
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->face->foreground;
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->f->output_data.x->cursor_foreground_pixel;
+      if (xgcv.foreground == xgcv.background)
+       xgcv.foreground = s->face->foreground;
+
+      /* Make sure the cursor is distinct from text in this face.  */
+      if (xgcv.background == s->face->background
+         && xgcv.foreground == s->face->foreground)
+       {
+         xgcv.background = s->face->foreground;
+         xgcv.foreground = s->face->background;
+       }
+
+      IF_DEBUG (x_check_font (s->f, s->font));
+      xgcv.font = s->font->fid;
+      xgcv.graphics_exposures = False;
+      mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+
+      if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+       XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+                  mask, &xgcv);
+      else
+       FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+         = XCreateGC (s->display, s->window, mask, &xgcv);
+
+      s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+    }
+}
+
+
+/* Set up S->gc of glyph string S for drawing text in mouse face.  */
+   
+static void
+x_set_mouse_face_gc (s)
+     struct glyph_string *s;
+{     
+  int face_id;
+
+  /* What face has to be used for the mouse face?  */
+  face_id = FRAME_X_DISPLAY_INFO (s->f)->mouse_face_face_id;
+  face_id = FACE_FOR_CHARSET (s->f, face_id, s->charset);
+  s->face = FACE_FROM_ID (s->f, face_id);
+  PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
+
+  /* If font in this face is same as S->font, use it.  */
+  if (s->font == s->face->font)
+    s->gc = s->face->gc;
+  else
+    {
+      /* Otherwise construct scratch_cursor_gc with values from FACE
+        but font FONT.  */
+      XGCValues xgcv;
+      unsigned long mask;
+      
+      xgcv.background = s->face->background;
+      xgcv.foreground = s->face->foreground;
+      IF_DEBUG (x_check_font (s->f, s->font));
+      xgcv.font = s->font->fid;
+      xgcv.graphics_exposures = False;
+      mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+      
+      if (FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc)
+       XChangeGC (s->display, FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc,
+                  mask, &xgcv);
+      else
+       FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc
+         = XCreateGC (s->display, s->window, mask, &xgcv);
+      
+      s->gc = FRAME_X_DISPLAY_INFO (s->f)->scratch_cursor_gc;
+    }
+
+  xassert (s->gc != 0);
+}
+
+
+/* Set S->gc of glyph string S to a GC suitable for drawing a mode line.
+   Faces to use in the mode line have already been computed when the
+   matrix was built, so there isn't much to do, here.  */
+
+static INLINE void
+x_set_mode_line_face_gc (s)
+     struct glyph_string *s;
+{     
+  s->gc = s->face->gc;
+  xassert (s->gc != 0);
+}
+
+
+/* Set S->gc of glyph string S for drawing that glyph string.  Set
+   S->stippled_p to a non-zero value if the face of S has a stipple
+   pattern.  */
+
+static INLINE void
+x_set_glyph_string_gc (s)
+     struct glyph_string *s;
+{
+  if (s->hl == DRAW_NORMAL_TEXT)
+    {
+      s->gc = s->face->gc;
+      s->stippled_p = s->face->stipple != 0;
+    }
+  else if (s->hl == DRAW_INVERSE_VIDEO)
+    {
+      x_set_mode_line_face_gc (s);
+      s->stippled_p = s->face->stipple != 0;
+    }
+  else if (s->hl == DRAW_CURSOR)
+    {
+      x_set_cursor_gc (s);
+      s->stippled_p = 0;
+    }
+  else if (s->hl == DRAW_MOUSE_FACE)
+    {
+      x_set_mouse_face_gc (s);
+      s->stippled_p = s->face->stipple != 0;
+    }
+  else if (s->hl == DRAW_IMAGE_RAISED
+          || s->hl == DRAW_IMAGE_SUNKEN)
+    {
+      s->gc = s->face->gc;
+      s->stippled_p = s->face->stipple != 0;
+    }
+  else
+    {
+      s->gc = s->face->gc;
+      s->stippled_p = s->face->stipple != 0;
+    }
+
+  /* GC must have been set.  */
+  xassert (s->gc != 0);
+}
+
+
+/* Return in *R the clipping rectangle for glyph string S.  */
+
+static void
+x_get_glyph_string_clip_rect (s, r)
+     struct glyph_string *s;
+     XRectangle *r;
+{
+  if (s->row->full_width_p)
+    {
+      /* Draw full-width.  X coordinates are relative to S->w->left.  */
+      int canon_x = CANON_X_UNIT (s->f);
+      
+      r->x = WINDOW_LEFT_MARGIN (s->w) * canon_x;
+      r->width = XFASTINT (s->w->width) * canon_x;
+
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (s->f))
+       {
+         int width = FRAME_SCROLL_BAR_WIDTH (s->f) * canon_x;
+         if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (s->f))
+           r->x -= width;
+       }
+      
+      r->x += FRAME_INTERNAL_BORDER_WIDTH (s->f);
+      
+      /* Unless displaying a mode or menu bar line, which are always
+        fully visible, clip to the visible part of the row.  */
+      if (s->w->pseudo_window_p)
+       r->height = s->row->visible_height;
+      else
+       r->height = s->height;
+    }
+  else
+    {
+      /* This is a text line that may be partially visible.  */
+      r->x = WINDOW_AREA_TO_FRAME_PIXEL_X (s->w, s->area, 0);
+      r->width = window_box_width (s->w, s->area);
+      r->height = s->row->visible_height;
+    }
+
+  /* Don't use S->y for clipping because it doesn't take partially
+     visible lines into account.  For example, it can be negative for
+     partially visible lines at the top of a window.  */
+  if (!s->row->full_width_p
+      && MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (s->w, s->row))
+    r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+  else
+    r->y = max (0, s->row->y);
+
+  /* If drawing a tool-bar window, draw it over the internal border
+     at the top of the window.  */
+  if (s->w == XWINDOW (s->f->tool_bar_window))
+    r->y -= s->f->output_data.x->internal_border_width;
+
+  /* If S draws overlapping rows, it's sufficient to use the top and
+     bottom of the window for clipping because this glyph string
+     intentionally draws over other lines.  */
+  if (s->for_overlaps_p)
+    {
+      r->y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (s->w);
+      r->height = window_text_bottom_y (s->w) - r->y;
+    }
+      
+  r->y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r->y);
+}
+
+
+/* Set clipping for output of glyph string S.  S may be part of a mode
+   line or menu if we don't have X toolkit support.  */
+
+static INLINE void
+x_set_glyph_string_clipping (s)
+     struct glyph_string *s;
+{
+  XRectangle r;
+  x_get_glyph_string_clip_rect (s, &r);
+  XSetClipRectangles (s->display, s->gc, 0, 0, &r, 1, Unsorted);
+}
+
+
+/* Compute left and right overhang of glyph string S.  If S is a glyph
+   string for a composite character, assume overhangs don't exist.  */
+
+static INLINE void
+x_compute_glyph_string_overhangs (s)
+     struct glyph_string *s;
+{
+  if (s->cmpcharp == NULL
+      && s->first_glyph->type == CHAR_GLYPH)
+    {
+      XCharStruct cs;
+      int direction, font_ascent, font_descent;
+      XTextExtents16 (s->font, s->char2b, s->nchars, &direction,
+                     &font_ascent, &font_descent, &cs);
+      s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
+      s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
+    }
+}
+
+
+/* Compute overhangs and x-positions for glyph string S and its
+   predecessors, or successors.  X is the starting x-position for S.
+   BACKWARD_P non-zero means process predecessors.  */
+   
+static void
+x_compute_overhangs_and_x (s, x, backward_p)
+     struct glyph_string *s;
+     int x;
+     int backward_p;
+{
+  if (backward_p)
+    {
+      while (s)
+       {
+         x_compute_glyph_string_overhangs (s);
+         x -= s->width;
+         s->x = x;
+         s = s->prev;
+       }
+    }
+  else
+    {
+      while (s)
+       {
+         x_compute_glyph_string_overhangs (s);
+         s->x = x;
+         x += s->width;
+         s = s->next;
+       }
+    }
+}
+
+
+/* Set *LEFT and *RIGHT to the left and right overhang of GLYPH on
+   frame F.  Overhangs of glyphs other than type CHAR_GLYPH or of
+   character glyphs for composite characters are assumed to be zero.  */
+
+static void
+x_get_glyph_overhangs (glyph, f, left, right)
+     struct glyph *glyph;
+     struct frame *f;
+     int *left, *right;
+{
+  int c;
+  
+  *left = *right = 0;
+  
+  if (glyph->type == CHAR_GLYPH
+      && (c = glyph->u.ch.code,
+         CHAR_CHARSET (c) != CHARSET_COMPOSITION))
+    {
+      XFontStruct *font;
+      struct face *face;
+      struct font_info *font_info;
+      XChar2b char2b;
+      
+      face = x_get_glyph_face_and_encoding (f, glyph, &char2b);
+      font = face->font;
+      font_info = FONT_INFO_FROM_ID (f, face->font_info_id);
+      if (font)
+       {
+         XCharStruct *pcm = x_per_char_metric (font, &char2b);
+         
+         if (pcm->rbearing > pcm->width)
+           *right = pcm->rbearing - pcm->width;
+         if (pcm->lbearing < 0)
+           *left = -pcm->lbearing;
+       }
+    }
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+   is overwritten by S because of S's left overhang.  Value is -1
+   if no glyphs are overwritten.  */
+
+static int
+x_left_overwritten (s)
+     struct glyph_string *s;
+{
+  int k;
+    
+  if (s->left_overhang)
+    {
+      int x = 0, i;
+      struct glyph *glyphs = s->row->glyphs[s->area];
+      int first = s->first_glyph - glyphs;
+
+      for (i = first - 1; i >= 0 && x > -s->left_overhang; --i)
+       x -= glyphs[i].pixel_width;
+
+      k = i + 1;
+    }
+  else
+    k = -1;
+
+  return k;
+}
+
+
+/* Return the index of the first glyph preceding glyph string S that
+   is overwriting S because of its right overhang.  Value is -1 if no
+   glyph in front of S overwrites S.  */
+
+static int
+x_left_overwriting (s)
+     struct glyph_string *s;
+{
+  int i, k, x;
+  struct glyph *glyphs = s->row->glyphs[s->area];
+  int first = s->first_glyph - glyphs;
+
+  k = -1;
+  x = 0;
+  for (i = first - 1; i >= 0; --i)
+    {
+      int left, right;
+      x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+      if (x + right > 0)
+       k = i;
+      x -= glyphs[i].pixel_width;
+    }
+
+  return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that is
+   not overwritten by S because of S's right overhang.  Value is -1 if
+   no such glyph is found.  */
+
+static int
+x_right_overwritten (s)
+     struct glyph_string *s;
+{
+  int k = -1;
+
+  if (s->right_overhang)
+    {
+      int x = 0, i;
+      struct glyph *glyphs = s->row->glyphs[s->area];
+      int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+      int end = s->row->used[s->area];
+      
+      for (i = first; i < end && s->right_overhang > x; ++i)
+       x += glyphs[i].pixel_width;
+
+      k = i;
+    }
+
+  return k;
+}
+
+
+/* Return the index of the last glyph following glyph string S that
+   overwrites S because of its left overhang.  Value is negative
+   if no such glyph is found.  */
+
+static int
+x_right_overwriting (s)
+     struct glyph_string *s;
+{
+  int i, k, x;
+  int end = s->row->used[s->area];
+  struct glyph *glyphs = s->row->glyphs[s->area];
+  int first = (s->first_glyph - glyphs) + (s->cmpcharp ? 1 : s->nchars);
+
+  k = -1;
+  x = 0;
+  for (i = first; i < end; ++i)
+    {
+      int left, right;
+      x_get_glyph_overhangs (glyphs + i, s->f, &left, &right);
+      if (x - left < 0)
+       k = i;
+      x += glyphs[i].pixel_width;
+    }
+
+  return k;
+}
+
+
+/* Fill rectangle X, Y, W, H with background color of glyph string S.  */
+
+static INLINE void
+x_clear_glyph_string_rect (s, x, y, w, h)
+     struct glyph_string *s;
+     int x, y, w, h;
+{
+  XGCValues xgcv;
+  XGetGCValues (s->display, s->gc, GCForeground | GCBackground, &xgcv);
+  XSetForeground (s->display, s->gc, xgcv.background);
+  XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+  XSetForeground (s->display, s->gc, xgcv.foreground);
+}
+
+
+/* Draw the background of glyph_string S.  If S->background_filled_p
+   is non-zero don't draw it.  FORCE_P non-zero means draw the
+   background even if it wouldn't be drawn normally.  This is used
+   when a string preceding S draws into the background of S.  */
+
+static void
+x_draw_glyph_string_background (s, force_p)
+     struct glyph_string *s;
+     int force_p;
+{
+  /* Nothing to do if background has already been drawn or if it
+     shouldn't be drawn in the first place.  */
+  if (!s->background_filled_p)
+    {
+      if (s->cmpcharp
+         && s->gidx > 0
+         && !s->font_not_found_p
+         && !s->extends_to_end_of_line_p)
+       {
+         /* Don't draw background for glyphs of a composite
+            characters, except for the first one.  */
+         s->background_filled_p = 1;
+       }
+      else if (s->stippled_p)
+       {
+         /* Fill background with a stipple pattern.  */
+         XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+         XFillRectangle (s->display, s->window, s->gc, s->x,
+                         s->y + s->face->box_line_width,
+                         s->background_width,
+                         s->height - 2 * s->face->box_line_width);
+         XSetFillStyle (s->display, s->gc, FillSolid);
+         s->background_filled_p = 1;
+       }
+      else if (FONT_HEIGHT (s->font) < s->height - 2 * s->face->box_line_width
+              || s->font_not_found_p
+              || s->extends_to_end_of_line_p
+              || s->cmpcharp
+              || force_p)
+       {
+         x_clear_glyph_string_rect (s, s->x, s->y + s->face->box_line_width,
+                                    s->background_width,
+                                    s->height - 2 * s->face->box_line_width);
+         s->background_filled_p = 1;
+       }
+    }
+}
+
+
+/* Draw the foreground of glyph string S.  */
+
+static void
+x_draw_glyph_string_foreground (s)
+     struct glyph_string *s;
+{
+  int i, x;
+
+  /* If first glyph of S has a left box line, start drawing the text
+     of S to the right of that box line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + s->face->box_line_width;
+  else
+    x = s->x;
+
+  if (s->cmpcharp == NULL)
+    {
+      /* Not a composite character.  Draw characters of S as
+        rectangles if S's font could not be loaded.  */
+      if (s->font_not_found_p)
+       {
+         for (i = 0; i < s->nchars; ++i)
+           {
+             struct glyph *g = s->first_glyph + i;
+             XDrawRectangle (s->display, s->window,
+                             s->gc, x, s->y, g->pixel_width - 1,
+                             s->height - 1);
+             x += g->pixel_width;
+           }
+       }
+      else
+       {
+         char *char1b = (char *) s->char2b;
+
+         /* If we can use 8-bit functions, condense S->char2b.  */
+         if (!s->two_byte_p)
+           for (i = 0; i < s->nchars; ++i)
+             char1b[i] = s->char2b[i].byte2;
+
+         /* Draw text with XDrawString if background has already been
+            filled.  Otherwise, use XDrawImageString.  (Note that
+            XDrawImageString is usually faster than XDrawString.)
+            Always use XDrawImageString when drawing the cursor so
+            that there is no chance that characters under a box
+            cursor are invisible.  */
+         if (s->for_overlaps_p
+             || (s->background_filled_p && s->hl != DRAW_CURSOR))
+           {
+             /* Draw characters with 16-bit or 8-bit functions.  */
+             if (s->two_byte_p)
+               XDrawString16 (s->display, s->window, s->gc, x, s->ybase, 
+                              s->char2b, s->nchars);
+             else
+               XDrawString (s->display, s->window, s->gc, x, s->ybase, 
+                            char1b, s->nchars);
+           }
+         else
+           {
+             if (s->two_byte_p)
+               XDrawImageString16 (s->display, s->window, s->gc,
+                                   x, s->ybase, s->char2b, s->nchars);
+             else
+               XDrawImageString (s->display, s->window, s->gc,
+                                 x, s->ybase, char1b, s->nchars);
+           }
+       }
+    }
+  else
+    {
+      /* S is a glyph string for a composite character. S->gidx is the
+        index of the first character drawn in the vector
+        S->cmpcharp->glyph.  S->gidx == 0 means we are drawing the
+        very first component character of a composite char.  */
+
+      /* Draw a single rectangle for the composite character if S's
+        font could not be loaded.  */
+      if (s->font_not_found_p && s->gidx == 0)
+       XDrawRectangle (s->display, s->window, s->gc, x, s->y,
+                       s->width - 1, s->height - 1);
+      else
+       {
+         XCharStruct *pcm;
+         int relative_compose, default_ascent, i;
+         int highest = 0, lowest = 0;
+
+         /* The value of font_info my be null if we couldn't find it
+            in x_get_char_face_and_encoding.  */
+         if (s->cmpcharp->cmp_rule == NULL && s->font_info)
+           {
+             relative_compose = s->font_info->relative_compose;
+             default_ascent = s->font_info->default_ascent;
+           }
+         else
+           relative_compose = default_ascent = 0;
+
+         if ((s->cmpcharp->cmp_rule || relative_compose)
+             && s->gidx == 0)
+           {
+             /* This is the first character.  Initialize variables.
+                Highest is the highest position of glyphs ever
+                written, lowest the lowest position.  */
+             int x_offset = 0;
+             int first_ch = s->first_glyph->u.ch.code;
+
+             if (default_ascent
+                 && CHAR_TABLE_P (Vuse_default_ascent)
+                 && !NILP (Faref (Vuse_default_ascent, first_ch)))
+               {
+                 highest = default_ascent;
+                 lowest = 0;
+               }
+             else
+               {
+                 pcm = PER_CHAR_METRIC (s->font, s->char2b);
+                 highest = pcm->ascent + 1;
+                 lowest = - pcm->descent;
+               }
+
+             if (s->cmpcharp->cmp_rule)
+               x_offset = (s->cmpcharp->col_offset[0]
+                           * FONT_WIDTH (s->f->output_data.x->font));
+
+             /* Draw the first character at the normal position.  */
+             XDrawString16 (s->display, s->window, s->gc,
+                            x + x_offset,
+                            s->ybase, s->char2b, 1);
+             i = 1;
+             ++s->gidx;
+           }
+         else
+           i = 0;
+
+         for (; i < s->nchars; i++, ++s->gidx)
+           {
+             int x_offset = 0, y_offset = 0;
+
+             if (relative_compose)
+               {
+                 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
+                 if (NILP (Vignore_relative_composition)
+                     || NILP (Faref (Vignore_relative_composition,
+                                     make_number (s->cmpcharp->glyph[s->gidx]))))
+                   {
+                     if (- pcm->descent >= relative_compose)
+                       {
+                         /* Draw above the current glyphs.  */
+                         y_offset = highest + pcm->descent;
+                         highest += pcm->ascent + pcm->descent;
+                       }
+                     else if (pcm->ascent <= 0)
+                       {
+                         /* Draw beneath the current glyphs.  */
+                         y_offset = lowest - pcm->ascent;
+                         lowest -= pcm->ascent + pcm->descent;
+                       }
+                   }
+                 else
+                   {
+                     /* Draw the glyph at normal position.  If
+                        it sticks out of HIGHEST or LOWEST,
+                        update them appropriately.  */
+                     if (pcm->ascent > highest)
+                       highest = pcm->ascent;
+                     else if (- pcm->descent < lowest)
+                       lowest = - pcm->descent;
+                   }
+               }
+             else if (s->cmpcharp->cmp_rule)
+               {
+                 int gref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) / 9;
+                 int nref = (s->cmpcharp->cmp_rule[s->gidx] - 0xA0) % 9;
+                 int bottom, top;
+
+                 /* Re-encode GREF and NREF so that they specify
+                    only Y-axis information:
+                    0:top, 1:base, 2:bottom, 3:center  */
+                 gref = gref / 3 + (gref == 4) * 2;
+                 nref = nref / 3 + (nref == 4) * 2;
+
+                 pcm = PER_CHAR_METRIC (s->font, s->char2b + i);
+                 bottom = ((gref == 0 ? highest : gref == 1 ? 0
+                            : gref == 2 ? lowest
+                            : (highest + lowest) / 2)
+                           - (nref == 0 ? pcm->ascent + pcm->descent
+                              : nref == 1 ? pcm->descent : nref == 2 ? 0
+                              : (pcm->ascent + pcm->descent) / 2));
+                 top = bottom + (pcm->ascent + pcm->descent);
+                 if (top > highest)
+                   highest = top;
+                 if (bottom < lowest)
+                   lowest = bottom;
+                 y_offset = bottom + pcm->descent;
+                 x_offset = (s->cmpcharp->col_offset[s->gidx]
+                             * FONT_WIDTH (FRAME_FONT (s->f)));
+               }
+
+             XDrawString16 (s->display, s->window, s->gc,
+                            x + x_offset, s->ybase - y_offset,
+                            s->char2b + i, 1);
+           }
+       }
+    }
+}
+
+
+#ifdef USE_X_TOOLKIT
+
+/* Allocate the color COLOR->pixel on the screen and display of
+   widget WIDGET in colormap CMAP.  If an exact match cannot be
+   allocated, try the nearest color available.  Value is non-zero
+   if successful.  This is called from lwlib.  */
+
+int
+x_alloc_nearest_color_for_widget (widget, cmap, color)
+     Widget widget;
+     Colormap cmap;
+     XColor *color;
+{
+  struct frame *f;
+  struct x_display_info *dpyinfo;
+  Lisp_Object tail, frame;
+  Widget parent;
+
+  dpyinfo = x_display_info_for_display (XtDisplay (widget));
+  
+  /* Find the top-level shell of the widget.  Note that this function
+     can be called when the widget is not yet realized, so XtWindow
+     (widget) == 0.  That's the reason we can't simply use
+     x_any_window_to_frame.  */
+  while (!XtIsTopLevelShell (widget))
+    widget = XtParent (widget);
+
+  /* Look for a frame with that top-level widget.  Allocate the color
+     on that frame to get the right gamma correction value.  */
+  for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
+    if (GC_FRAMEP (XCAR (tail))
+       && (f = XFRAME (XCAR (tail)),
+           (f->output_data.nothing != 1
+            && FRAME_X_DISPLAY_INFO (f) == dpyinfo))
+       && f->output_data.x->widget == widget)
+      return x_alloc_nearest_color (f, cmap, color);
+
+  abort ();
+}
+
+#endif /* USE_X_TOOLKIT */
+
+
+/* Allocate the color COLOR->pixel on SCREEN of DISPLAY, colormap
+   CMAP.  If an exact match can't be allocated, try the nearest color
+   available.  Value is non-zero if successful.  Set *COLOR to the
+   color allocated.  */
+
+int
+x_alloc_nearest_color (f, cmap, color)
+     struct frame *f;
+     Colormap cmap;
+     XColor *color;
+{
+  Display *display = FRAME_X_DISPLAY (f);
+  Screen *screen = FRAME_X_SCREEN (f);
+  int rc;
+
+  gamma_correct (f, color);
+  rc = XAllocColor (display, cmap, color);
+  if (rc == 0)
+    {
+      /* If we got to this point, the colormap is full, so we're going
+        to try to get the next closest color.  The algorithm used is
+        a least-squares matching, which is what X uses for closest
+        color matching with StaticColor visuals.  */
+      int nearest, i;
+      unsigned long nearest_delta = ~0;
+      int ncells = XDisplayCells (display, XScreenNumberOfScreen (screen));
+      XColor *cells = (XColor *) alloca (ncells * sizeof *cells);
+
+      for (i = 0; i < ncells; ++i)
+       cells[i].pixel = i;
+      XQueryColors (display, cmap, cells, ncells);
+
+      for (nearest = i = 0; i < ncells; ++i)
+       {
+         long dred   = (color->red   >> 8) - (cells[i].red   >> 8);
+         long dgreen = (color->green >> 8) - (cells[i].green >> 8);
+         long dblue  = (color->blue  >> 8) - (cells[i].blue  >> 8);
+         unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
+
+         if (delta < nearest_delta)
+           {
+             nearest = i;
+             nearest_delta = delta;
+           }
+       }
+      
+      color->red   = cells[nearest].red;
+      color->green = cells[nearest].green;
+      color->blue  = cells[nearest].blue;
+      rc = XAllocColor (display, cmap, color);
+    }
+
+  return rc;
+}
+
+
+/* Allocate a color which is lighter or darker than *PIXEL by FACTOR
+   or DELTA.  Try a color with RGB values multiplied by FACTOR first.
+   If this produces the same color as PIXEL, try a color where all RGB
+   values have DELTA added.  Return the allocated color in *PIXEL.
+   DISPLAY is the X display, CMAP is the colormap to operate on.
+   Value is non-zero if successful.  */
+
+static int
+x_alloc_lighter_color (f, display, cmap, pixel, factor, delta)
+     struct frame *f;
+     Display *display;
+     Colormap cmap;
+     unsigned long *pixel;
+     float factor;
+     int delta;
+{
+  XColor color, new;
+  int success_p;
+
+  /* Get RGB color values.  */
+  color.pixel = *pixel;
+  XQueryColor (display, cmap, &color);
+
+  /* Change RGB values by specified FACTOR.  Avoid overflow!  */
+  xassert (factor >= 0);
+  new.red = min (0xffff, factor * color.red);
+  new.green = min (0xffff, factor * color.green);
+  new.blue = min (0xffff, factor * color.blue);
+
+  /* Try to allocate the color.  */
+  success_p = x_alloc_nearest_color (f, cmap, &new);
+  if (success_p)
+    {
+      if (new.pixel == *pixel)
+       {
+         /* If we end up with the same color as before, try adding
+            delta to the RGB values.  */
+         int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
+         
+         /* If display has an immutable color map, freeing colors is
+            not necessary and some servers don't allow it.  So don't
+            do it.  */
+         if (class != StaticColor
+             && class != StaticGray
+             && class != TrueColor)
+           XFreeColors (display, cmap, &new.pixel, 1, 0);
+         
+         new.red = min (0xffff, delta + color.red);
+         new.green = min (0xffff, delta + color.green);
+         new.blue = min (0xffff, delta + color.blue);
+         success_p = x_alloc_nearest_color (f, cmap, &new);
+       }
+      else
+       success_p = 1;
+      *pixel = new.pixel;
+    }
+  
+  return success_p;
+}
+
+
+/* Set up the foreground color for drawing relief lines of glyph
+   string S.  RELIEF is a pointer to a struct relief containing the GC
+   with which lines will be drawn.  Use a color that is FACTOR or
+   DELTA lighter or darker than the relief's background which is found
+   in S->f->output_data.x->relief_background.  If such a color cannot
+   be allocated, use DEFAULT_PIXEL, instead.  */
+   
+static void
+x_setup_relief_color (f, relief, factor, delta, default_pixel)
+     struct frame *f;
+     struct relief *relief;
+     float factor;
+     int delta;
+     unsigned long default_pixel;
+{
+  XGCValues xgcv;
+  struct x_output *di = f->output_data.x;
+  unsigned long mask = GCForeground | GCLineWidth | GCGraphicsExposures;
+  unsigned long pixel;
+  unsigned long background = di->relief_background;
+  Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display *dpy = FRAME_X_DISPLAY (f);
+
+  xgcv.graphics_exposures = False;
+  xgcv.line_width = 1;
+
+  /* Free previously allocated color.  The color cell will be reused
+     when it has been freed as many times as it was allocated, so this
+     doesn't affect faces using the same colors.  */
+  if (relief->gc
+      && relief->allocated_p)
+    {
+      /* If display has an immutable color map, freeing colors is not
+        necessary and some servers don't allow it.  So don't do it.  */
+      int class = dpyinfo->visual->class;
+      if (class != StaticColor
+         && class != StaticGray
+         && class != TrueColor)
+       XFreeColors (dpy, cmap, &relief->pixel, 1, 0);
+      relief->allocated_p = 0;
+    }
+
+  /* Allocate new color.  */
+  xgcv.foreground = default_pixel;
+  pixel = background;
+  if (dpyinfo->n_planes != 1
+      && x_alloc_lighter_color (f, dpy, cmap, &pixel, factor, delta))
+    {
+      relief->allocated_p = 1;
+      xgcv.foreground = relief->pixel = pixel;
+    }
+  
+  if (relief->gc == 0)
+    {
+      xgcv.stipple = dpyinfo->gray;
+      mask |= GCStipple;
+      relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv);
+    }
+  else
+    XChangeGC (dpy, relief->gc, mask, &xgcv);
+}
+
+
+/* Set up colors for the relief lines around glyph string S.  */
+
+static void
+x_setup_relief_colors (s)
+     struct glyph_string *s;
+{
+  struct x_output *di = s->f->output_data.x;
+  unsigned long color;
+
+  if (s->face->use_box_color_for_shadows_p)
+    color = s->face->box_color;
+  else
+    {
+      XGCValues xgcv;
+      
+      /* Get the background color of the face.  */
+      XGetGCValues (s->display, s->gc, GCBackground, &xgcv);
+      color = xgcv.background;
+    }
+
+  if (di->white_relief.gc == 0
+      || color != di->relief_background)
+    {
+      di->relief_background = color;
+      x_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
+                           WHITE_PIX_DEFAULT (s->f));
+      x_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
+                           BLACK_PIX_DEFAULT (s->f));
+    }
+}
+
+
+/* Draw a relief on frame F inside the rectangle given by LEFT_X,
+   TOP_Y, RIGHT_X, and BOTTOM_Y.  WIDTH is the thickness of the relief
+   to draw, it must be >= 0.  RAISED_P non-zero means draw a raised
+   relief.  LEFT_P non-zero means draw a relief on the left side of
+   the rectangle.  RIGHT_P non-zero means draw a relief on the right
+   side of the rectangle.  CLIP_RECT is the clipping rectangle to use
+   when drawing.  */
+
+static void
+x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
+                   raised_p, left_p, right_p, clip_rect)
+     struct frame *f;
+     int left_x, top_y, right_x, bottom_y, left_p, right_p, raised_p;
+     XRectangle *clip_rect;
+{
+  int i;
+  GC gc;
+  
+  if (raised_p)
+    gc = f->output_data.x->white_relief.gc;
+  else
+    gc = f->output_data.x->black_relief.gc;
+  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
+
+  /* Top.  */
+  for (i = 0; i < width; ++i)
+    XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+              left_x + i * left_p, top_y + i,
+              right_x + 1 - i * right_p, top_y + i);
+
+  /* Left.  */
+  if (left_p)
+    for (i = 0; i < width; ++i)
+      XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+                left_x + i, top_y + i, left_x + i, bottom_y - i);
+
+  XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+  if (raised_p)
+    gc = f->output_data.x->black_relief.gc;
+  else
+    gc = f->output_data.x->white_relief.gc;
+  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, clip_rect, 1, Unsorted);
+  
+  /* Bottom.  */
+  for (i = 0; i < width; ++i)
+    XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+              left_x + i * left_p, bottom_y - i,
+              right_x + 1 - i * right_p, bottom_y - i);
+  
+  /* Right.  */
+  if (right_p)
+    for (i = 0; i < width; ++i)
+      XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
+                right_x - i, top_y + i + 1, right_x - i, bottom_y - i);
+
+  XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+}
+
+
+/* Draw a box on frame F inside the rectangle given by LEFT_X, TOP_Y,
+   RIGHT_X, and BOTTOM_Y.  WIDTH is the thickness of the lines to
+   draw, it must be >= 0.  LEFT_P non-zero means draw a line on the
+   left side of the rectangle.  RIGHT_P non-zero means draw a line
+   on the right side of the rectangle.  CLIP_RECT is the clipping
+   rectangle to use when drawing.  */
+
+static void
+x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+                left_p, right_p, clip_rect)
+     struct glyph_string *s;
+     int left_x, top_y, right_x, bottom_y, left_p, right_p;
+     XRectangle *clip_rect;
+{
+  XGCValues xgcv;
+  
+  XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+  XSetForeground (s->display, s->gc, s->face->box_color);
+  XSetClipRectangles (s->display, s->gc, 0, 0, clip_rect, 1, Unsorted);
+  
+  /* Top.  */
+  XFillRectangle (s->display, s->window, s->gc,
+                 left_x, top_y, right_x - left_x, width);
+
+  /* Left.  */
+  if (left_p)
+    XFillRectangle (s->display, s->window, s->gc,
+                   left_x, top_y, width, bottom_y - top_y);
+
+  /* Bottom.  */
+  XFillRectangle (s->display, s->window, s->gc,
+                 left_x, bottom_y - width, right_x - left_x, width);
+  
+  /* Right.  */
+  if (right_p)
+    XFillRectangle (s->display, s->window, s->gc,
+                   right_x - width, top_y, width, bottom_y - top_y);
+
+  XSetForeground (s->display, s->gc, xgcv.foreground);
+  XSetClipMask (s->display, s->gc, None);
+}
+
+
+/* Draw a box around glyph string S.  */
+
+static void
+x_draw_glyph_string_box (s)
+     struct glyph_string *s;
+{
+  int width, left_x, right_x, top_y, bottom_y, last_x, raised_p;
+  int left_p, right_p;
+  struct glyph *last_glyph;
+  XRectangle clip_rect;
+
+  last_x = window_box_right (s->w, s->area);
+  if (s->row->full_width_p
+      && !s->w->pseudo_window_p)
+    {
+      last_x += FRAME_X_RIGHT_FLAGS_AREA_WIDTH (s->f);
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (s->f))
+       last_x += FRAME_SCROLL_BAR_WIDTH (s->f) * CANON_X_UNIT (s->f);
+    }
+  
+  /* The glyph that may have a right box line.  */
+  last_glyph = (s->cmpcharp || s->img
+               ? s->first_glyph
+               : s->first_glyph + s->nchars - 1);
+
+  width = s->face->box_line_width;
+  raised_p = s->face->box == FACE_RAISED_BOX;
+  left_x = s->x;
+  right_x = ((s->row->full_width_p
+             ? last_x - 1
+             : min (last_x, s->x + s->background_width) - 1));
+  top_y = s->y;
+  bottom_y = top_y + s->height - 1;
+
+  left_p = (s->first_glyph->left_box_line_p
+           || (s->hl == DRAW_MOUSE_FACE
+               && (s->prev == NULL
+                   || s->prev->hl != s->hl)));
+  right_p = (last_glyph->right_box_line_p
+            || (s->hl == DRAW_MOUSE_FACE
+                && (s->next == NULL
+                    || s->next->hl != s->hl)));
+  
+  x_get_glyph_string_clip_rect (s, &clip_rect);
+
+  if (s->face->box == FACE_SIMPLE_BOX)
+    x_draw_box_rect (s, left_x, top_y, right_x, bottom_y, width,
+                    left_p, right_p, &clip_rect);
+  else
+    {
+      x_setup_relief_colors (s);
+      x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
+                         width, raised_p, left_p, right_p, &clip_rect);
+    }
+}
+
+
+/* Draw foreground of image glyph string S.  */
+
+static void
+x_draw_image_foreground (s)
+     struct glyph_string *s;
+{
+  int x;
+  int y = s->ybase - IMAGE_ASCENT (s->img);
+
+  /* If first glyph of S has a left box line, start drawing it to the
+     right of that line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + s->face->box_line_width;
+  else
+    x = s->x;
+
+  /* If there is a margin around the image, adjust x- and y-position
+     by that margin.  */
+  if (s->img->margin)
+    {
+      x += s->img->margin;
+      y += s->img->margin;
+    }
+
+  if (s->img->pixmap)
+    {
+      if (s->img->mask)
+       {
+         /* We can't set both a clip mask and use XSetClipRectangles
+            because the latter also sets a clip mask.  We also can't
+            trust on the shape extension to be available
+            (XShapeCombineRegion).  So, compute the rectangle to draw
+            manually.  */
+         unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+                               | GCFunction);
+         XGCValues xgcv;
+         XRectangle clip_rect, image_rect, r;
+
+         xgcv.clip_mask = s->img->mask;
+         xgcv.clip_x_origin = x;
+         xgcv.clip_y_origin = y;
+         xgcv.function = GXcopy;
+         XChangeGC (s->display, s->gc, mask, &xgcv);
+         
+         x_get_glyph_string_clip_rect (s, &clip_rect);
+         image_rect.x = x;
+         image_rect.y = y;
+         image_rect.width = s->img->width;
+         image_rect.height = s->img->height;
+         if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
+           XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+                      r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+       }
+      else
+       {
+         XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+                    0, 0, s->img->width, s->img->height, x, y);
+         
+         /* When the image has a mask, we can expect that at
+            least part of a mouse highlight or a block cursor will
+            be visible.  If the image doesn't have a mask, make
+            a block cursor visible by drawing a rectangle around
+            the image.  I believe it's looking better if we do
+            nothing here for mouse-face.  */
+         if (s->hl == DRAW_CURSOR)
+           XDrawRectangle (s->display, s->window, s->gc, x, y,
+                           s->img->width - 1, s->img->height - 1);
+       }
+    }
+  else
+    /* Draw a rectangle if image could not be loaded.  */
+    XDrawRectangle (s->display, s->window, s->gc, x, y,
+                   s->img->width - 1, s->img->height - 1);
+}
+
+
+/* Draw a relief around the image glyph string S.  */
+
+static void
+x_draw_image_relief (s)
+     struct glyph_string *s;
+{
+  int x0, y0, x1, y1, thick, raised_p;
+  XRectangle r;
+  int x;
+  int y = s->ybase - IMAGE_ASCENT (s->img);
+  
+  /* If first glyph of S has a left box line, start drawing it to the
+     right of that line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->x + s->face->box_line_width;
+  else
+    x = s->x;
+  
+  /* If there is a margin around the image, adjust x- and y-position
+     by that margin.  */
+  if (s->img->margin)
+    {
+      x += s->img->margin;
+      y += s->img->margin;
+    }
+  
+  if (s->hl == DRAW_IMAGE_SUNKEN
+      || s->hl == DRAW_IMAGE_RAISED)
+    {
+      thick = tool_bar_button_relief > 0 ? tool_bar_button_relief : 3;
+      raised_p = s->hl == DRAW_IMAGE_RAISED;
+    }
+  else
+    {
+      thick = abs (s->img->relief);
+      raised_p = s->img->relief > 0;
+    }
+  
+  x0 = x - thick;
+  y0 = y - thick;
+  x1 = x + s->img->width + thick - 1;
+  y1 = y + s->img->height + thick - 1;
+  
+  x_setup_relief_colors (s);
+  x_get_glyph_string_clip_rect (s, &r);
+  x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+}
+
+
+/* Draw the foreground of image glyph string S to PIXMAP.  */
+
+static void
+x_draw_image_foreground_1 (s, pixmap)
+     struct glyph_string *s;
+     Pixmap pixmap;
+{
+  int x;
+  int y = s->ybase - s->y - IMAGE_ASCENT (s->img);
+
+  /* If first glyph of S has a left box line, start drawing it to the
+     right of that line.  */
+  if (s->face->box != FACE_NO_BOX
+      && s->first_glyph->left_box_line_p)
+    x = s->face->box_line_width;
+  else
+    x = 0;
+
+  /* If there is a margin around the image, adjust x- and y-position
+     by that margin.  */
+  if (s->img->margin)
+    {
+      x += s->img->margin;
+      y += s->img->margin;
+    }
+
+  if (s->img->pixmap)
+    {
+      if (s->img->mask)
+       {
+         /* We can't set both a clip mask and use XSetClipRectangles
+            because the latter also sets a clip mask.  We also can't
+            trust on the shape extension to be available
+            (XShapeCombineRegion).  So, compute the rectangle to draw
+            manually.  */
+         unsigned long mask = (GCClipMask | GCClipXOrigin | GCClipYOrigin
+                               | GCFunction);
+         XGCValues xgcv;
+
+         xgcv.clip_mask = s->img->mask;
+         xgcv.clip_x_origin = x;
+         xgcv.clip_y_origin = y;
+         xgcv.function = GXcopy;
+         XChangeGC (s->display, s->gc, mask, &xgcv);
+
+         XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+                    0, 0, s->img->width, s->img->height, x, y);
+         XSetClipMask (s->display, s->gc, None);
+       }
+      else
+       {
+         XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
+                    0, 0, s->img->width, s->img->height, x, y);
+         
+         /* When the image has a mask, we can expect that at
+            least part of a mouse highlight or a block cursor will
+            be visible.  If the image doesn't have a mask, make
+            a block cursor visible by drawing a rectangle around
+            the image.  I believe it's looking better if we do
+            nothing here for mouse-face.  */
+         if (s->hl == DRAW_CURSOR)
+           XDrawRectangle (s->display, pixmap, s->gc, x, y,
+                           s->img->width - 1, s->img->height - 1);
+       }
+    }
+  else
+    /* Draw a rectangle if image could not be loaded.  */
+    XDrawRectangle (s->display, pixmap, s->gc, x, y,
+                   s->img->width - 1, s->img->height - 1);
+}
+
+
+/* Draw part of the background of glyph string S.  X, Y, W, and H
+   give the rectangle to draw.  */
+
+static void
+x_draw_glyph_string_bg_rect (s, x, y, w, h)
+     struct glyph_string *s;
+     int x, y, w, h;
+{
+  if (s->stippled_p)
+    {
+      /* Fill background with a stipple pattern.  */
+      XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+      XFillRectangle (s->display, s->window, s->gc, x, y, w, h);
+      XSetFillStyle (s->display, s->gc, FillSolid);
+    }
+  else
+    x_clear_glyph_string_rect (s, x, y, w, h);
+}
+
+
+/* Draw image glyph string S.  
+
+            s->y
+   s->x      +-------------------------
+            |   s->face->box
+            |
+            |     +-------------------------
+            |     |  s->img->margin
+            |     |
+            |     |       +-------------------
+            |     |       |  the image
+
+ */
+
+static void
+x_draw_image_glyph_string (s)
+     struct glyph_string *s;
+{
+  int x, y;
+  int box_line_width = s->face->box_line_width;
+  int margin = s->img->margin;
+  int height;
+  Pixmap pixmap = None;
+
+  height = s->height - 2 * box_line_width;
+
+  /* Fill background with face under the image.  Do it only if row is
+     taller than image or if image has a clip mask to reduce
+     flickering.  */
+  s->stippled_p = s->face->stipple != 0;
+  if (height > s->img->height
+      || margin
+      || s->img->mask
+      || s->img->pixmap == 0
+      || s->width != s->background_width)
+    {
+      if (box_line_width && s->first_glyph->left_box_line_p)
+       x = s->x + box_line_width;
+      else
+       x = s->x;
+      
+      y = s->y + box_line_width;
+      
+      if (s->img->mask)
+       {
+         /* Create a pixmap as large as the glyph string Fill it with
+            the background color.  Copy the image to it, using its
+            mask.  Copy the temporary pixmap to the display.  */
+         Screen *screen = FRAME_X_SCREEN (s->f);
+         int depth = DefaultDepthOfScreen (screen);
+
+         /* Create a pixmap as large as the glyph string.  */
+         pixmap = XCreatePixmap (s->display, s->window,
+                                 s->background_width,
+                                 s->height, depth);
+         
+         /* Don't clip in the following because we're working on the
+            pixmap.  */
+         XSetClipMask (s->display, s->gc, None);
+
+         /* Fill the pixmap with the background color/stipple.  */
+         if (s->stippled_p)
+           {
+             /* Fill background with a stipple pattern.  */
+             XSetFillStyle (s->display, s->gc, FillOpaqueStippled);
+             XFillRectangle (s->display, pixmap, s->gc,
+                             0, 0, s->background_width, s->height);
+             XSetFillStyle (s->display, s->gc, FillSolid);
+           }
+         else
+           {
+             XGCValues xgcv;
+             XGetGCValues (s->display, s->gc, GCForeground | GCBackground,
+                           &xgcv);
+             XSetForeground (s->display, s->gc, xgcv.background);
+             XFillRectangle (s->display, pixmap, s->gc,
+                             0, 0, s->background_width, s->height);
+             XSetForeground (s->display, s->gc, xgcv.foreground);
+           }
+       }
+      else
+       /* Implementation idea: Is it possible to construct a mask?
+          We could look at the color at the margins of the image, and
+          say that this color is probably the background color of the
+          image.  */
+       x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+      
+      s->background_filled_p = 1;
+    }
+
+  /* Draw the foreground.  */
+  if (pixmap != None)
+    {
+      x_draw_image_foreground_1 (s, pixmap);
+      x_set_glyph_string_clipping (s);
+      XCopyArea (s->display, pixmap, s->window, s->gc,
+                0, 0, s->background_width, s->height, s->x, s->y);
+      XFreePixmap (s->display, pixmap);
+    }
+  else
+    x_draw_image_foreground (s);
 
-#define FACE_DEFAULT (~0)
+  /* If we must draw a relief around the image, do it.  */
+  if (s->img->relief
+      || s->hl == DRAW_IMAGE_RAISED
+      || s->hl == DRAW_IMAGE_SUNKEN)
+    x_draw_image_relief (s);
+}
 
-       /* Setting appropriate font and gc for this charset.  */
-       if (charset != CHARSET_ASCII)
-         {
-           int font_id;
-           int fontset = FACE_FONTSET (face);
-           struct font_info *fontp;
-
-           if ((fontset < 0 && (fontset = FRAME_FONTSET (f)) < 0)
-               || !(fontp = FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
-                                          charset, NULL, fontset)))
-             goto font_not_found;
-
-           font = (XFontStruct *) (fontp->font);
-           gc = FACE_NON_ASCII_GC (face);
-           XSetFont (FRAME_X_DISPLAY (f), gc, font->fid);
-           baseline
-             = (font->max_byte1 != 0
-                ? (line_height + font->ascent - font->descent) / 2
-                : f->output_data.x->font_baseline - fontp->baseline_offset);
-           if (FONT_HEIGHT (font) <= line_height
-               && (font->ascent > baseline
-                   || font->descent > line_height - baseline))
-             /* Adjust baseline for this font to show the whole
-                 glyphs in a line.  */
-             baseline = line_height - font->descent;
-             
-           if (cmpcharp && cmpcharp->cmp_rule == NULL)
-             {
-               relative_compose = fontp->relative_compose;
-               default_ascent = fontp->default_ascent;
-             }
 
-           /* We have to change code points in the following cases.  */
-           if (fontp->font_encoder)
-             {
-               /* This font requires CCL program to calculate code
-                   point of characters.  */
-               struct ccl_program *ccl = fontp->font_encoder;
+/* Draw stretch glyph string S.  */
 
-               if (CHARSET_DIMENSION (charset) == 1)
-                 for (cp = buf; cp < buf + len; cp++)
-                   {
-                     ccl->reg[0] = charset;
-                     ccl->reg[1] = cp->byte2;
-                     ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
-                     cp->byte2 = ccl->reg[1];
-                   }
-               else
-                 for (cp = buf; cp < buf + len; cp++)
-                   {
-                     ccl->reg[0] = charset;
-                     ccl->reg[1] = cp->byte1, ccl->reg[2] = cp->byte2;
-                     ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
-                     cp->byte1 = ccl->reg[1], cp->byte2 = ccl->reg[2];
-                   }
-             }
-           else if (fontp->encoding[charset])
-             {
-               int enc = fontp->encoding[charset];
-
-               if ((enc == 1 || enc == 2) && CHARSET_DIMENSION (charset) == 2)
-                 for (cp = buf; cp < buf + len; cp++)
-                   cp->byte1 |= 0x80;
-               if (enc == 1 || enc == 3)
-                 for (cp = buf; cp < buf + len; cp++)
-                   cp->byte2 |= 0x80;
-             }
-         }
-       else
-         {
-         font_not_found:
-           if (charset == CHARSET_ASCII || charset == charset_latin_iso8859_1)
-             {
-               font = FACE_FONT (face);
-               if (font == (XFontStruct *) FACE_DEFAULT)
-                 font = f->output_data.x->font;
-               baseline = FONT_BASE (font);
-               if (charset == charset_latin_iso8859_1)
-                 {
-                   if (font->max_char_or_byte2 < 0x80)
-                     /* This font can't display Latin1 characters.  */
-                     font = NULL;
-                   else
-                     {
-                       for (cp = buf; cp < buf + len; cp++)
-                         cp->byte2 |= 0x80;
-                     }
-                 }
-             }
-           gc = FACE_GC (face);
-         }
+static void
+x_draw_stretch_glyph_string (s)
+     struct glyph_string *s;
+{
+  xassert (s->first_glyph->type == STRETCH_GLYPH);
+  s->stippled_p = s->face->stipple != 0;
 
-       /* Now override that if the cursor's on this character.  */
-       if (hl == 2)
-         {
-           /* The cursor overrides stippling.  */
-           stippled = 0;
+  if (s->hl == DRAW_CURSOR
+      && !x_stretch_cursor_p)
+    {
+      /* If `x-stretch-block-cursor' is nil, don't draw a block cursor
+        as wide as the stretch glyph.  */
+      int width = min (CANON_X_UNIT (s->f), s->background_width);
 
-           if (font == f->output_data.x->font
-               && face->background == f->output_data.x->background_pixel
-               && face->foreground == f->output_data.x->foreground_pixel
-               && !cmpcharp)
-             {
-               gc = f->output_data.x->cursor_gc;
-             }
-           /* Cursor on non-default face: must merge.  */
-           else
-             {
-               XGCValues xgcv;
-               unsigned long mask;
-
-               xgcv.background = f->output_data.x->cursor_pixel;
-               xgcv.foreground = face->background;
-               /* If the glyph would be invisible,
-                  try a different foreground.  */
-               if (xgcv.foreground == xgcv.background)
-                 xgcv.foreground = face->foreground;
-               if (xgcv.foreground == xgcv.background)
-                 xgcv.foreground = f->output_data.x->cursor_foreground_pixel;
-               if (xgcv.foreground == xgcv.background)
-                 xgcv.foreground = face->foreground;
-               /* Make sure the cursor is distinct from text in this face.  */
-               if (xgcv.background == face->background
-                   && xgcv.foreground == face->foreground)
-                 {
-                   xgcv.background = face->foreground;
-                   xgcv.foreground = face->background;
-                 }
-               if (font)
-                 xgcv.font = font->fid;
-               else
-                 xgcv.font = FACE_FONT (face)->fid;
-               xgcv.graphics_exposures = 0;
-               mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
-               if (FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc)
-                 XChangeGC (FRAME_X_DISPLAY (f),
-                            FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc,
-                            mask, &xgcv);
-               else
-                 FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc
-                   = XCreateGC (FRAME_X_DISPLAY (f), window, mask, &xgcv);
-               gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
-#if 0
-/* If this code is restored, it must also reset to the default stipple
-   if necessary. */
-               if (face->stipple && face->stipple != FACE_DEFAULT)
-                 XSetStipple (FRAME_X_DISPLAY (f), gc, face->stipple);
-#endif
-             }
-         }
+      /* Draw cursor.  */
+      x_draw_glyph_string_bg_rect (s, s->x, s->y, width, s->height);
 
-       if (font)
-         require_clipping = (!NILP (Vclip_large_size_font)
-                             && (font->ascent > baseline
-                                 || font->descent > line_height - baseline
-                                 || (!cmpcharp
-                                     && FONT_WIDTH (font) > glyph_width)));
+      /* Clear rest using the GC of the original non-cursor face.  */
+      if (width < s->background_width)
+       {
+         GC gc = s->face->gc;
+         int x = s->x + width, y = s->y;
+         int w = s->background_width - width, h = s->height;
+         XRectangle r;
 
-       if (font && (just_foreground || (cmpcharp && gidx > 0)))
-         background_filled = 1;
-       else if (stippled)
-         {
-           /* Turn stipple on.  */
-           XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillOpaqueStippled);
+         x_get_glyph_string_clip_rect (s, &r);
+         XSetClipRectangles (s->display, gc, 0, 0, &r, 1, Unsorted);
 
-           /* Draw stipple or background color on background.  */
-           XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
-                           left, top, run_width, line_height);
+         if (s->face->stipple)
+           {
+             /* Fill background with a stipple pattern.  */
+             XSetFillStyle (s->display, gc, FillOpaqueStippled);
+             XFillRectangle (s->display, s->window, gc, x, y, w, h);
+             XSetFillStyle (s->display, gc, FillSolid);
+           }
+         else
+           {
+             XGCValues xgcv;
+             XGetGCValues (s->display, gc, GCForeground | GCBackground, &xgcv);
+             XSetForeground (s->display, gc, xgcv.background);
+             XFillRectangle (s->display, s->window, gc, x, y, w, h);
+             XSetForeground (s->display, gc, xgcv.foreground);
+           }
+       }
+    }
+  else
+    x_draw_glyph_string_bg_rect (s, s->x, s->y, s->background_width,
+                                s->height);
+  
+  s->background_filled_p = 1;
+}
 
-           /* Turn stipple off.  */
-           XSetFillStyle (FRAME_X_DISPLAY (f), gc, FillSolid);
 
-           background_filled = 1;
-         }
-       else if (!font
-                || FONT_HEIGHT (font) < line_height
-                || FONT_WIDTH (font) < glyph_width
-                || cmpcharp)
-         {
-           /* Fill a area for the current run in background pixle of GC.  */
-           XGCValues xgcv;
-           unsigned long mask = GCForeground | GCBackground;
-           unsigned long fore, back;
-
-           /* The current code at first set foreground to background,
-             fill the area, then recover the original foreground.
-             Aren't there any smarter ways?  */
-
-           XGetGCValues (FRAME_X_DISPLAY (f), gc, mask, &xgcv);
-           XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
-           XFillRectangle (FRAME_X_DISPLAY (f), window, gc,
-                           left, top, run_width, line_height);
-           XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
-
-           background_filled = 1;
-           if (cmpcharp)
-             /* To assure not to fill background while drawing
-                remaining components.  */
-             just_foreground = 1;
-         }
-       else
-         background_filled = 0;
+/* Draw glyph string S.  */
 
-       if (font)
-         {
-           if (require_clipping)
-             {
-               Region region;  /* Region used for setting clip mask to GC.  */
-               XPoint x[4];    /* Data used for creating REGION.  */
-
-               x[0].x = x[3].x = left, x[1].x = x[2].x = left + glyph_width;
-               x[0].y = x[1].y = top,  x[2].y = x[3].y = top + line_height;
-               region = XPolygonRegion (x, 4, EvenOddRule);
-               XSetRegion (FRAME_X_DISPLAY (f), gc, region);
-               XDestroyRegion (region);
-             }
+static void
+x_draw_glyph_string (s)
+     struct glyph_string *s;
+{
+  /* If S draws into the background of its successor, draw the
+     background of the successor first so that S can draw into it.
+     This makes S->next use XDrawString instead of XDrawImageString.  */
+  if (s->next && s->right_overhang && !s->for_overlaps_p)
+    {
+      xassert (s->next->img == NULL);
+      x_set_glyph_string_gc (s->next);
+      x_set_glyph_string_clipping (s->next);
+      x_draw_glyph_string_background (s->next, 1);
+    }
 
-           if (!cmpcharp)
-             {
-               if (require_clipping || FONT_WIDTH (font) != glyph_width)
-                 for (i = 0; i < len; i++)
-                   {
-                     if (require_clipping && i > 0) 
-                       XSetClipOrigin (FRAME_X_DISPLAY (f), gc,
-                                       glyph_width * i, 0);
-                     if (background_filled)
-                       XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
-                                      left + glyph_width * i,
-                                      top + baseline, buf + i, 1);
-                     else
-                       XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
-                                           left + glyph_width * i,
-                                           top + baseline, buf + i, 1);
-                   }
-               else
-                 {
-                   if (background_filled)
-                     XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
-                                    left, top + baseline, buf, len);
-                   else
-                     XDrawImageString16 (FRAME_X_DISPLAY (f), window, gc,
-                                         left, top + baseline, buf, len);
-                 }
-             }
-           else
-             {
-               XCharStruct *pcm; /* Pointer to per char metric info.  */
+  /* Set up S->gc, set clipping and draw S.  */
+  x_set_glyph_string_gc (s);
+  x_set_glyph_string_clipping (s);
 
-               if ((cmpcharp->cmp_rule || relative_compose)
-                   && gidx == 0)
-                 {
-                   /* This is the first character.  Initialize variables.
-                      HIGHEST is the highest position of glyphs ever
-                      written, LOWEST the lowest position.  */
-                   int x_offset = 0;
-
-                   if (default_ascent
-                       && CHAR_TABLE_P (Vuse_default_ascent)
-                       && !NILP (Faref (Vuse_default_ascent, first_ch)))
-                     {
-                       highest = default_ascent;
-                       lowest = 0;
-                     }
-                   else
-                     {
-                       pcm = PER_CHAR_METRIC (font, buf);
-                       highest = pcm->ascent + 1;
-                       lowest = - pcm->descent;
-                     }
+  switch (s->first_glyph->type)
+    {
+    case IMAGE_GLYPH:
+      x_draw_image_glyph_string (s);
+      break;
 
-                   if (cmpcharp->cmp_rule)
-                     x_offset = (cmpcharp->col_offset[0]
-                                 * FONT_WIDTH (f->output_data.x->font));
-                   /* Draw the first character at the normal position.  */
-                   XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
-                                  left + x_offset, top + baseline, buf, 1);
-                   i = 1;
-                   gidx++;
-                 }
-               else
-                 i = 0;
+    case STRETCH_GLYPH:
+      x_draw_stretch_glyph_string (s);
+      break;
 
-               for (; i < len; i++, gidx++)
-                 {
-                   int x_offset = 0, y_offset = 0;
+    case CHAR_GLYPH:
+      if (s->for_overlaps_p)
+       s->background_filled_p = 1;
+      else
+       x_draw_glyph_string_background (s, 0);
+      x_draw_glyph_string_foreground (s);
+      break;
 
-                   if (relative_compose)
-                     {
-                       pcm = PER_CHAR_METRIC (font, buf + i);
-                       if (- pcm->descent >= relative_compose)
-                         {
-                           /* Draw above the current glyphs.  */
-                           y_offset = highest + pcm->descent;
-                           highest += pcm->ascent + pcm->descent;
-                         }
-                       else if (pcm->ascent <= 0)
-                         {
-                           /* Draw beneath the current glyphs.  */
-                           y_offset = lowest - pcm->ascent;
-                           lowest -= pcm->ascent + pcm->descent;
-                         }
-                     }
-                   else if (cmpcharp->cmp_rule)
-                     {
-                       int gref = (cmpcharp->cmp_rule[gidx] - 0xA0) / 9;
-                       int nref = (cmpcharp->cmp_rule[gidx] - 0xA0) % 9;
-                       int bottom, top;
-
-                       /* Re-encode GREF and NREF so that they specify
-                          only Y-axis information:
-                          0:top, 1:base, 2:bottom, 3:center  */
-                       gref = gref / 3 + (gref == 4) * 2;
-                       nref = nref / 3 + (nref == 4) * 2;
-
-                       pcm = PER_CHAR_METRIC (font, buf + i);
-                       bottom = ((gref == 0 ? highest : gref == 1 ? 0
-                                  : gref == 2 ? lowest
-                                  : (highest + lowest) / 2)
-                                 - (nref == 0 ? pcm->ascent + pcm->descent
-                                    : nref == 1 ? pcm->descent : nref == 2 ? 0
-                                    : (pcm->ascent + pcm->descent) / 2));
-                       top = bottom + (pcm->ascent + pcm->descent);
-                       if (top > highest)
-                         highest = top;
-                       if (bottom < lowest)
-                         lowest = bottom;
-                       y_offset = bottom + pcm->descent;
-                       x_offset = (cmpcharp->col_offset[gidx]
-                                   * FONT_WIDTH (f->output_data.x->font));
-                     }
-                   XDrawString16 (FRAME_X_DISPLAY (f), window, gc,
-                                  left + x_offset, top + baseline - y_offset,
-                                  buf + i, 1);
-                 }
-             }
-           if (require_clipping)
-             XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
+    default:
+      abort ();
+    }
 
-#if 0 /* Doesn't work, because it uses FRAME_CURRENT_GLYPHS,
-        which often is not up to date yet.  */
-           if (!just_foreground)
-             {
-               if (left == orig_left)
-                 redraw_previous_char (f, PIXEL_TO_CHAR_COL (f, left),
-                                       PIXEL_TO_CHAR_ROW (f, top), hl == 1);
-               if (n == 0)
-                 redraw_following_char (f, PIXEL_TO_CHAR_COL (f, left + len * FONT_WIDTH (font)),
-                                        PIXEL_TO_CHAR_ROW (f, top), hl == 1);
-             }
-#endif
-         }
-       if (!font)
-         {
-           /* Show rectangles to indicate that we found no font.  */
-           int limit = cmpcharp ? 1 : len;
+  if (!s->for_overlaps_p)
+    {
+      /* Draw underline.  */
+      if (s->face->underline_p)
+       {
+         unsigned long dy, h;
+
+         if (!XGetFontProperty (s->font, XA_UNDERLINE_THICKNESS, &h))
+           h = 1;
+         if (!XGetFontProperty (s->font, XA_UNDERLINE_POSITION, &dy))
+           dy = s->height - h;
+      
+         if (s->face->underline_defaulted_p)
+           XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                           s->width, h);
+         else
+           {
+             XGCValues xgcv;
+             XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+             XSetForeground (s->display, s->gc, s->face->underline_color);
+             XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                             s->width, h);
+             XSetForeground (s->display, s->gc, xgcv.foreground);
+           }
+       }
 
-           for (i = 0; i < limit; i++)
-             XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                             left + glyph_width * i, top,
-                             glyph_width - 1, line_height - 1);
-         }
-       else if (require_clipping && !NILP (Vhighlight_wrong_size_font))
-         {
-           /* Show ??? to indicate that we found a font of
-               inappropriate size.  */
-           int limit = cmpcharp ? 1 : len;
+      /* Draw overline.  */
+      if (s->face->overline_p)
+       {
+         unsigned long dy = 0, h = 1;
 
-           for (i = 0; i < limit; i++)
-             {
-               XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                          left + glyph_width * i, top + line_height - 1,
-                          left + glyph_width * i + 1, top + line_height - 1);
-               XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                          left + glyph_width * i, top + line_height - 3,
-                          left + glyph_width * i, top + line_height - 1);
-             }
-         }
+         if (s->face->overline_color_defaulted_p)
+           XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                           s->width, h);
+         else
+           {
+             XGCValues xgcv;
+             XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+             XSetForeground (s->display, s->gc, s->face->overline_color);
+             XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                             s->width, h);
+             XSetForeground (s->display, s->gc, xgcv.foreground);
+           }
+       }
+  
+      /* Draw strike-through.  */
+      if (s->face->strike_through_p)
+       {
+         unsigned long h = 1;
+         unsigned long dy = (s->height - h) / 2;
+
+         if (s->face->strike_through_color_defaulted_p)
+           XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                           s->width, h);
+         else
+           {
+             XGCValues xgcv;
+             XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
+             XSetForeground (s->display, s->gc, s->face->strike_through_color);
+             XFillRectangle (s->display, s->window, s->gc, s->x, s->y + dy,
+                             s->width, h);
+             XSetForeground (s->display, s->gc, xgcv.foreground);
+           }
+       }
+  
+      /* Draw relief.  */
+      if (s->face->box != FACE_NO_BOX)
+       x_draw_glyph_string_box (s);
+    }
+  
+  /* Reset clipping.  */
+  XSetClipMask (s->display, s->gc, None);
+}
+
+
+/* A work-list entry used during the construction of glyph_string
+   structures for a composite character.  */
+
+struct work
+{
+  /* Pointer to composite char info defining has the composite
+     character is drawn.  */
+  struct cmpchar_info *cmpcharp;
+
+  /* Start index in compcharp->glyph[].  */
+  int gidx;
+
+  /* Next in stack.  */
+  struct work *next;
+};
+
+
+static void x_fill_composite_glyph_string P_ ((struct glyph_string *,
+                                              int, struct work **,
+                                              struct work **, int));
+
+
+/* Load glyph string S with information from the top of *STACK for a
+   composite character.  FACE_ID is the id of the face in which S is
+   drawn.  *NEW is a pointer to a struct work not on the stack, that
+   can be used if this function needs to push a new structure on the
+   stack.  If it uses it, *NEW is set to null.  OVERLAPS_P non-zero
+   means S should draw the foreground only, and use its lines physical
+   height for clipping.  */
+
+static void
+x_fill_composite_glyph_string (s, face_id, stack, new, overlaps_p)
+     struct glyph_string *s;
+     int face_id;
+     struct work **stack, **new;
+     int overlaps_p;
+{
+  int i, c;
+  struct work *work;
+
+  xassert (s && *new && *stack);
+
+  s->for_overlaps_p = 1;
+  
+  /* Pop the work stack.  */
+  work = *stack;
+  *stack = work->next;
+  
+  /* For all glyphs of cmpcharp->glyph, starting at the offset
+     work->offset, until we reach the end of the definition or
+     encounter another composite char, get the font and face to use,
+     and add it to S.  */
+  for (i = work->gidx; i < work->cmpcharp->glyph_len; ++i)
+    {
+      c = FAST_GLYPH_CHAR (work->cmpcharp->glyph[i]);
+      if (CHAR_CHARSET (c) == CHARSET_COMPOSITION)
+       break;
+      s->face = x_get_char_face_and_encoding (s->f, c, face_id,
+                                             s->char2b + s->nchars, 1);
+      s->font = s->face->font;
+      s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+      ++s->nchars;
+    }
 
-       /* We should probably check for XA_UNDERLINE_POSITION and
-          XA_UNDERLINE_THICKNESS properties on the font, but let's
-          just get the thing working, and come back to that.  */
+  /* If we find another composite char in the glyph definition of
+     work->cmpcharp, put back the rest of the glyphs on the work
+     stack, and make a new entry for the composite char.  */
+  if (i < work->cmpcharp->glyph_len)
+    {
+      /* Push back an unprocessed rest of this glyph spec.  */
+      if (i < work->cmpcharp->glyph_len - 1)
        {
-         /* Setting underline position based on the metric of the
-            current font results in shaky underline if it strides
-            over different fonts.  So, we set the position based only
-            on the default font of this frame.  */
-         int underline_position = f->output_data.x->font_baseline + 1;
-
-         if (underline_position >= line_height)
-           underline_position = line_height - 1;
-
-         if (face->underline)
-           XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                           FACE_GC (face),
-                           left, top + underline_position, run_width, 1);
+         work->gidx = i + 1;
+         work->next = *stack;
+         *stack = work;
+         work = *new;
+         *new = NULL;
        }
 
-       if (!cmpcharp)
-         left += run_width;
-      }
+      /* Make an entry for the composite char on the work stack.  */
+      work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];
+      work->gidx = 0;
+      work->next = *stack;
+      *stack = work;
+    }
+
+  /* The width of this glyph string equals the width of the first
+     glyph.  All characters are drawn at the same x-position.  */
+  s->width = s->first_glyph->pixel_width;
+
+  /* If the specified font could not be loaded, use the frame's
+     default font, but record the fact that we couldn't load it in
+     the glyph string so that we can draw rectangles for the
+     characters of the glyph string.  */
+  if (s->font == NULL)
+    {
+      s->font_not_found_p = 1;
+      s->font = FRAME_FONT (s->f);
+    }
+
+  /* Adjust base line for subscript/superscript text.  */
+  s->ybase += s->first_glyph->voffset;
+  
+  xassert (s->face && s->face->gc);
+
+  /* This glyph string must always be drawn with 16-bit functions.  */
+  s->two_byte_p = 1;
+}
+
+
+/* Load glyph string S with a sequence of non-composite characters.
+   FACE_ID is the face id of the string.  START is the index of the
+   first glyph to consider, END is the index of the last + 1.
+   OVERLAPS_P non-zero means S should draw the foreground only, and
+   use its lines physical height for clipping.
+
+   Value is the index of the first glyph not in S.  */
+
+static int
+x_fill_glyph_string (s, face_id, start, end, overlaps_p)
+     struct glyph_string *s;
+     int face_id;
+     int start, end, overlaps_p;
+{
+  struct glyph *glyph, *last;
+  int voffset;
+  
+  xassert (s->charset != CHARSET_COMPOSITION);
+  xassert (s->f == XFRAME (s->w->frame));
+  xassert (s->nchars == 0);
+  xassert (start >= 0 && end > start);
+
+  s->for_overlaps_p = overlaps_p,
+  glyph = s->row->glyphs[s->area] + start;
+  last = s->row->glyphs[s->area] + end;
+  voffset = glyph->voffset;
+  
+  while (glyph < last
+        && glyph->type == CHAR_GLYPH
+        && glyph->voffset == voffset
+        /* Same face id implies same charset, nowadays.  */
+        && glyph->u.ch.face_id == face_id)
+    {
+      s->face = x_get_glyph_face_and_encoding (s->f, glyph,
+                                              s->char2b + s->nchars);
+      if (s->char2b[s->nchars].byte2 != 0)
+       s->two_byte_p = 1;
+      
+      ++s->nchars;
+      xassert (s->nchars <= end - start);
+      s->width += glyph->pixel_width;
+      ++glyph;
+    }
+
+  s->font = s->face->font;
+  s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+  
+  /* If the specified font could not be loaded, use the frame's font,
+     but record the fact that we couldn't load it in
+     S->font_not_found_p so that we can draw rectangles for the
+     characters of the glyph string.  */
+  if (s->font == NULL)
+    {
+      s->font_not_found_p = 1;
+      s->font = FRAME_FONT (s->f);
     }
 
-  return (left - orig_left);
+  /* Adjust base line for subscript/superscript text.  */
+  s->ybase += voffset;
+
+  xassert (s->face && s->face->gc);
+  return glyph - s->row->glyphs[s->area];
 }
-#endif /* 1 */
 
-#if 0
-/* This is the old single-face code.  */
+
+/* Fill glyph string S from image glyph S->first_glyph.  */
 
 static void
-dumpglyphs (f, left, top, gp, n, hl, font)
-     struct frame *f;
-     int left, top;
-     register GLYPH *gp; /* Points to first GLYPH. */
-     register int n;  /* Number of glyphs to display. */
-     int hl;
-     XFontStruct *font;
+x_fill_image_glyph_string (s)
+     struct glyph_string *s;
 {
-  register int len;
-  Window window = FRAME_X_WINDOW (f);
-  GC drawing_gc =   (hl == 2 ? f->output_data.x->cursor_gc
-                            : (hl ? f->output_data.x->reverse_gc
-                                  : f->output_data.x->normal_gc));
-
-  if (sizeof (GLYPH) == sizeof (XChar2b))
-    XDrawImageString16 (FRAME_X_DISPLAY (f), window, drawing_gc,
-                       left, top + FONT_BASE (font), (XChar2b *) gp, n);
-  else if (sizeof (GLYPH) == sizeof (unsigned char))
-    XDrawImageString (FRAME_X_DISPLAY (f), window, drawing_gc,
-                     left, top + FONT_BASE (font), (char *) gp, n);
+  xassert (s->first_glyph->type == IMAGE_GLYPH);
+  s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img.id);
+  xassert (s->img);
+  s->face = FACE_FROM_ID (s->f, s->first_glyph->u.img.face_id);
+  s->font = s->face->font;
+  s->width = s->first_glyph->pixel_width;
+  
+  /* Adjust base line for subscript/superscript text.  */
+  s->ybase += s->first_glyph->voffset;
+}
+
+
+/* Fill glyph string S from stretch glyph S->first_glyph.  */
+
+static void
+x_fill_stretch_glyph_string (s)
+     struct glyph_string *s;
+{
+  xassert (s->first_glyph->type == STRETCH_GLYPH);
+  s->face = FACE_FROM_ID (s->f, s->first_glyph->u.stretch.face_id);
+  s->font = s->face->font;
+  s->width = s->first_glyph->pixel_width;
+  
+  /* Adjust base line for subscript/superscript text.  */
+  s->ybase += s->first_glyph->voffset;
+}
+
+
+/* Initialize glyph string S.  CHAR2B is a suitably allocated vector
+   of XChar2b structures for S; it can't be allocated in
+   x_init_glyph_string because it must be allocated via `alloca'.  W
+   is the window on which S is drawn.  ROW and AREA are the glyph row
+   and area within the row from which S is constructed.  START is the
+   index of the first glyph structure covered by S.  HL is a
+   face-override for drawing S.  */
+   
+static void
+x_init_glyph_string (s, char2b, w, row, area, start, hl)
+     struct glyph_string *s;
+     XChar2b *char2b;
+     struct window *w;
+     struct glyph_row *row;
+     enum glyph_row_area area;
+     int start;
+     enum draw_glyphs_face hl;
+{
+  bzero (s, sizeof *s);
+  s->w = w;
+  s->f = XFRAME (w->frame);
+  s->display = FRAME_X_DISPLAY (s->f);
+  s->window = FRAME_X_WINDOW (s->f);
+  s->char2b = char2b;
+  s->hl = hl;
+  s->row = row;
+  s->area = area;
+  s->first_glyph = row->glyphs[area] + start;
+  s->height = row->height;
+  s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+
+  /* Display the internal border below the tool-bar window.  */
+  if (s->w == XWINDOW (s->f->tool_bar_window))
+    s->y -= s->f->output_data.x->internal_border_width;
+  
+  s->ybase = s->y + row->ascent;
+}
+
+
+/* Set background width of glyph string S.  START is the index of the
+   first glyph following S.  LAST_X is the right-most x-position + 1
+   in the drawing area.  */
+
+static INLINE void
+x_set_glyph_string_background_width (s, start, last_x)
+     struct glyph_string *s;
+     int start;
+     int last_x;
+{
+  /* If the face of this glyph string has to be drawn to the end of
+     the drawing area, set S->extends_to_end_of_line_p.  */
+  struct face *default_face = FACE_FROM_ID (s->f, DEFAULT_FACE_ID);
+  
+  if (start == s->row->used[s->area]
+      && s->hl == DRAW_NORMAL_TEXT
+      && ((s->area == TEXT_AREA && s->row->fill_line_p)
+         || s->face->background != default_face->background
+         || s->face->stipple != default_face->stipple))
+    s->extends_to_end_of_line_p = 1;
+  
+  /* If S extends its face to the end of the line, set its
+     background_width to the distance to the right edge of the drawing
+     area.  */
+  if (s->extends_to_end_of_line_p)
+    s->background_width = last_x - s->x + 1;
   else
-    /* What size of glyph ARE you using?  And does X have a function to
-       draw them?  */
-    abort ();
+    s->background_width = s->width;
 }
-#endif
-\f
-/* Output some text at the nominal frame cursor position.
-   Advance the cursor over the text.
-   Output LEN glyphs at START.
 
-   `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
-   controls the pixel values used for foreground and background.  */
 
-static
-XTwrite_glyphs (start, len)
-     register GLYPH *start;
-     int len;
+/* Add a glyph string for a stretch glyph to the list of strings
+   between HEAD and TAIL.  START is the index of the stretch glyph in
+   row area AREA of glyph row ROW.  END is the index of the last glyph
+   in that glyph row area.  X is the current output position assigned
+   to the new glyph string constructed.  HL overrides that face of the
+   glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn.  LAST_X
+   is the right-most x-position of the drawing area.  */
+
+#define BUILD_STRETCH_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL,    \
+                                HL, X, LAST_X)                             \
+     do                                                                            \
+       {                                                                   \
+        s = (struct glyph_string *) alloca (sizeof *s);                    \
+        x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL);            \
+        x_fill_stretch_glyph_string (s);                                   \
+        x_append_glyph_string (&HEAD, &TAIL, s);                           \
+        ++START;                                                           \
+         s->x = (X);                                                       \
+       }                                                                   \
+     while (0)
+
+
+/* Add a glyph string for an image glyph to the list of strings
+   between HEAD and TAIL.  START is the index of the image glyph in
+   row area AREA of glyph row ROW.  END is the index of the last glyph
+   in that glyph row area.  X is the current output position assigned
+   to the new glyph string constructed.  HL overrides that face of the
+   glyph; e.g. it is DRAW_CURSOR if a cursor has to be drawn.  LAST_X
+   is the right-most x-position of the drawing area.  */
+
+#define BUILD_IMAGE_GLYPH_STRING(W, ROW, AREA, START, END, HEAD, TAIL, \
+                                HL, X, LAST_X)                         \
+     do                                                                        \
+       {                                                               \
+        s = (struct glyph_string *) alloca (sizeof *s);                \
+        x_init_glyph_string (s, NULL, W, ROW, AREA, START, HL);        \
+        x_fill_image_glyph_string (s);                                 \
+        x_append_glyph_string (&HEAD, &TAIL, s);                       \
+        ++START;                                                       \
+         s->x = (X);                                                   \
+       }                                                               \
+     while (0)
+
+
+/* Add a glyph string for a sequence of character glyphs to the list
+   of strings between HEAD and TAIL.  START is the index of the first
+   glyph in row area AREA of glyph row ROW that is part of the new
+   glyph string.  END is the index of the last glyph in that glyph row
+   area.  X is the current output position assigned to the new glyph
+   string constructed.  HL overrides that face of the glyph; e.g. it
+   is DRAW_CURSOR if a cursor has to be drawn.  LAST_X is the
+   right-most x-position of the drawing area.  */
+
+#define BUILD_CHAR_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL, \
+                                X, LAST_X, OVERLAPS_P)                    \
+     do                                                                           \
+       {                                                                  \
+        int c, charset, face_id;                                          \
+        XChar2b *char2b;                                                  \
+                                                                          \
+        c = (ROW)->glyphs[AREA][START].u.ch.code;                         \
+        charset = CHAR_CHARSET (c);                                       \
+        face_id = (ROW)->glyphs[AREA][START].u.ch.face_id;                \
+                                                                          \
+        if (charset == CHARSET_COMPOSITION)                               \
+          {                                                               \
+            struct work *stack, *work, *new = NULL;                       \
+            int n = 0;                                                    \
+             struct glyph_string *first_s = NULL;                         \
+                                                                          \
+            /* Push an initial entry for character c on the stack.  */    \
+            stack = NULL;                                                 \
+            work = (struct work *) alloca (sizeof *work);                 \
+            work->cmpcharp = cmpchar_table[COMPOSITE_CHAR_ID (c)];        \
+            work->gidx = 0;                                               \
+            work->next = stack;                                           \
+            stack = work;                                                 \
+                                                                          \
+            /* While the stack is not empty, append glyph_strings         \
+               to head/tail for glyphs to draw.  */                       \
+            while (stack)                                                 \
+              {                                                           \
+                s = (struct glyph_string *) alloca (sizeof *s);           \
+                char2b = (XChar2b *) alloca (stack->cmpcharp->glyph_len   \
+                                             * sizeof (XChar2b));         \
+                x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL); \
+                x_append_glyph_string (&(HEAD), &(TAIL), s);              \
+                s->cmpcharp = stack->cmpcharp;                            \
+                s->gidx = stack->gidx;                                    \
+                s->charset = charset;                                     \
+                s->x = (X);                                               \
+                                                                          \
+                 if (n == 0)                                              \
+                  {                                                       \
+                    /* Don't draw the background except for the           \
+                       first glyph string.  */                            \
+                     s->background_filled_p = n > 0;                      \
+                    first_s = s;                                          \
+                  }                                                       \
+                ++n;                                                      \
+                                                                          \
+                if (new == NULL)                                          \
+                  new = (struct work *) alloca (sizeof *new);             \
+                x_fill_composite_glyph_string (s, face_id, &stack,        \
+                                               &new, OVERLAPS_P);         \
+              }                                                           \
+                                                                          \
+            ++START;                                                      \
+             s = first_s;                                                 \
+          }                                                               \
+        else                                                              \
+          {                                                               \
+            s = (struct glyph_string *) alloca (sizeof *s);               \
+            char2b = (XChar2b *) alloca ((END - START) * sizeof *char2b); \
+            x_init_glyph_string (s, char2b, W, ROW, AREA, START, HL);     \
+            x_append_glyph_string (&HEAD, &TAIL, s);                      \
+            s->charset = charset;                                         \
+            s->x = (X);                                                   \
+            START = x_fill_glyph_string (s, face_id, START, END,          \
+                                          OVERLAPS_P);                    \
+          }                                                               \
+       }                                                                  \
+     while (0)
+     
+
+/* Build a list of glyph strings between HEAD and TAIL for the glyphs
+   of AREA of glyph row ROW on window W between indices START and END.
+   HL overrides the face for drawing glyph strings, e.g. it is
+   DRAW_CURSOR to draw a cursor.  X and LAST_X are start and end
+   x-positions of the drawing area.
+
+   This is an ugly monster macro construct because we must use alloca
+   to allocate glyph strings (because x_draw_glyphs can be called
+   asynchronously).  */
+
+#define BUILD_GLYPH_STRINGS(W, ROW, AREA, START, END, HEAD, TAIL, HL,     \
+                           X, LAST_X, OVERLAPS_P)                         \
+     do                                                                           \
+       {                                                                  \
+        HEAD = TAIL = NULL;                                               \
+        while (START < END)                                               \
+          {                                                               \
+             struct glyph *first_glyph = (ROW)->glyphs[AREA] + START;     \
+             switch (first_glyph->type)                                           \
+              {                                                           \
+              case CHAR_GLYPH:                                            \
+                 BUILD_CHAR_GLYPH_STRINGS (W, ROW, AREA, START, END, HEAD, \
+                                          TAIL, HL, X, LAST_X,            \
+                                           OVERLAPS_P);                           \
+                break;                                                    \
+                                                                          \
+              case STRETCH_GLYPH:                                         \
+                BUILD_STRETCH_GLYPH_STRING (W, ROW, AREA, START, END,     \
+                                            HEAD, TAIL, HL, X, LAST_X);   \
+                break;                                                    \
+                                                                          \
+              case IMAGE_GLYPH:                                           \
+                BUILD_IMAGE_GLYPH_STRING (W, ROW, AREA, START, END, HEAD, \
+                                          TAIL, HL, X, LAST_X);           \
+                break;                                                    \
+                                                                          \
+              default:                                                    \
+                abort ();                                                 \
+              }                                                           \
+                                                                          \
+             x_set_glyph_string_background_width (s, START, LAST_X);      \
+            (X) += s->width;                                              \
+            }                                                             \
+       }                                                                  \
+     while (0)
+
+
+/* Draw glyphs between START and END in AREA of ROW on window W,
+   starting at x-position X.  X is relative to AREA in W.  HL is a
+   face-override with the following meaning:
+
+   DRAW_NORMAL_TEXT    draw normally
+   DRAW_CURSOR         draw in cursor face
+   DRAW_MOUSE_FACE     draw in mouse face.
+   DRAW_INVERSE_VIDEO  draw in mode line face
+   DRAW_IMAGE_SUNKEN   draw an image with a sunken relief around it
+   DRAW_IMAGE_RAISED   draw an image with a raised relief around it
+
+   If REAL_START is non-null, return in *REAL_START the real starting
+   position for display.  This can be different from START in case
+   overlapping glyphs must be displayed.  If REAL_END is non-null,
+   return in *REAL_END the real end position for display.  This can be
+   different from END in case overlapping glyphs must be displayed.
+
+   If OVERLAPS_P is non-zero, draw only the foreground of characters
+   and clip to the physical height of ROW.
+
+   Value is the x-position reached, relative to AREA of W.  */
+     
+static int
+x_draw_glyphs (w, x, row, area, start, end, hl, real_start, real_end,
+              overlaps_p)
+     struct window *w;
+     int x;
+     struct glyph_row *row;
+     enum glyph_row_area area;
+     int start, end;
+     enum draw_glyphs_face hl;
+     int *real_start, *real_end;
+     int overlaps_p;
 {
-  register int temp_length;
-  int mask;
-  struct frame *f;
+  struct glyph_string *head, *tail;
+  struct glyph_string *s;
+  int last_x, area_width;
+  int x_reached;
+  int i, j;
+
+  /* Let's rather be paranoid than getting a SEGV.  */
+  start = max (0, start);
+  end = min (end, row->used[area]);
+  if (real_start)
+    *real_start = start;
+  if (real_end)
+    *real_end = end;
+
+  /* Translate X to frame coordinates.  Set last_x to the right
+     end of the drawing area.  */
+  if (row->full_width_p)
+    {
+      /* X is relative to the left edge of W, without scroll bars
+        or flag areas.  */
+      struct frame *f = XFRAME (w->frame);
+      /* int width = FRAME_FLAGS_AREA_WIDTH (f);  */
+      int window_left_x = WINDOW_LEFT_MARGIN (w) * CANON_X_UNIT (f);
 
-  BLOCK_INPUT;
+      x += window_left_x;
+      area_width = XFASTINT (w->width) * CANON_X_UNIT (f);
+      last_x = window_left_x + area_width;
+
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+       {
+         int width = FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
+         if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+           last_x += width;
+         else
+           x -= width;
+       }
+
+      x += FRAME_INTERNAL_BORDER_WIDTH (f);
+      last_x -= FRAME_INTERNAL_BORDER_WIDTH (f);
+    }
+  else
+    {
+      x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, x);
+      area_width = window_box_width (w, area);
+      last_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, area, area_width);
+    }
 
-  do_line_dance ();
-  f = updating_frame;
-  if (f == 0)
+  /* Build a doubly-linked list of glyph_string structures between
+     head and tail from what we have to draw.  Note that the macro
+     BUILD_GLYPH_STRINGS will modify its start parameter.  That's
+     the reason we use a separate variable `i'.  */
+  i = start;
+  BUILD_GLYPH_STRINGS (w, row, area, i, end, head, tail, hl, x, last_x,
+                      overlaps_p);
+  if (tail)
+    x_reached = tail->x + tail->background_width;
+  else
+    x_reached = x;
+
+  /* If there are any glyphs with lbearing < 0 or rbearing > width in
+     the row, redraw some glyphs in front or following the glyph
+     strings built above.  */
+  if (!overlaps_p && row->contains_overlapping_glyphs_p)
+    {
+      int dummy_x = 0;
+      struct glyph_string *h, *t;
+
+      /* Compute overhangs for all glyph strings.  */
+      for (s = head; s; s = s->next)
+       x_compute_glyph_string_overhangs (s);
+
+      /* Prepend glyph strings for glyphs in front of the first glyph
+        string that are overwritten because of the first glyph
+        string's left overhang.  The background of all strings
+        prepended must be drawn because the first glyph string 
+        draws over it.  */
+      i = x_left_overwritten (head);
+      if (i >= 0)
+       {
+         j = i;
+         BUILD_GLYPH_STRINGS (w, row, area, j, start, h, t,
+                              DRAW_NORMAL_TEXT, dummy_x, last_x,
+                              overlaps_p);
+         start = i;
+         if (real_start)
+           *real_start = start;
+         x_compute_overhangs_and_x (t, head->x, 1);
+         x_prepend_glyph_string_lists (&head, &tail, h, t);
+       }
+
+      /* Prepend glyph strings for glyphs in front of the first glyph
+        string that overwrite that glyph string because of their
+        right overhang.  For these strings, only the foreground must
+        be drawn, because it draws over the glyph string at `head'.
+        The background must not be drawn because this would overwrite
+        right overhangs of preceding glyphs for which no glyph
+        strings exist.  */
+      i = x_left_overwriting (head);
+      if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (w, row, area, i, start, h, t,
+                              DRAW_NORMAL_TEXT, dummy_x, last_x,
+                              overlaps_p);
+         for (s = h; s; s = s->next)
+           s->background_filled_p = 1;
+         if (real_start)
+           *real_start = i;
+         x_compute_overhangs_and_x (t, head->x, 1);
+         x_prepend_glyph_string_lists (&head, &tail, h, t);
+       }
+
+      /* Append glyphs strings for glyphs following the last glyph
+        string tail that are overwritten by tail.  The background of
+        these strings has to be drawn because tail's foreground draws
+        over it.  */
+      i = x_right_overwritten (tail);
+      if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
+                              DRAW_NORMAL_TEXT, x, last_x,
+                              overlaps_p);
+         x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
+         x_append_glyph_string_lists (&head, &tail, h, t);
+         if (real_end)
+           *real_end = i;
+       }
+
+      /* Append glyph strings for glyphs following the last glyph
+        string tail that overwrite tail.  The foreground of such
+        glyphs has to be drawn because it writes into the background
+        of tail.  The background must not be drawn because it could
+        paint over the foreground of following glyphs.  */
+      i = x_right_overwriting (tail);
+      if (i >= 0)
+       {
+         BUILD_GLYPH_STRINGS (w, row, area, end, i, h, t,
+                              DRAW_NORMAL_TEXT, x, last_x,
+                              overlaps_p);
+         for (s = h; s; s = s->next)
+           s->background_filled_p = 1;
+         x_compute_overhangs_and_x (h, tail->x + tail->width, 0);
+         x_append_glyph_string_lists (&head, &tail, h, t);
+         if (real_end)
+           *real_end = i;
+       }
+    }
+
+  /* Draw all strings.  */
+  for (s = head; s; s = s->next)
+    x_draw_glyph_string (s);
+
+  /* Value is the x-position up to which drawn, relative to AREA of W.
+     This doesn't include parts drawn because of overhangs.  */
+  x_reached = FRAME_TO_WINDOW_PIXEL_X (w, x_reached);
+  if (!row->full_width_p)
     {
-      f = selected_frame;
-      /* If not within an update,
-        output at the frame's visible cursor.  */
-      curs_x = f->cursor_x;
-      curs_y = f->cursor_y;
+      if (area > LEFT_MARGIN_AREA)
+       x_reached -= window_box_width (w, LEFT_MARGIN_AREA);
+      if (area > TEXT_AREA)
+       x_reached -= window_box_width (w, TEXT_AREA);
     }
+  return x_reached;
+}
 
-  dumpglyphs (f,
-             CHAR_TO_PIXEL_COL (f, curs_x),
-             CHAR_TO_PIXEL_ROW (f, curs_y),
-             start, len, highlight, 0, NULL);
 
-  /* If we drew on top of the cursor, note that it is turned off.  */
-  if (curs_y == f->phys_cursor_y
-      && curs_x <= f->phys_cursor_x
-      && curs_x + len > f->phys_cursor_x)
-    f->phys_cursor_on = 0;
+/* Fix the display of area AREA of overlapping row ROW in window W.  */
 
-  if (updating_frame == 0)
-    x_display_cursor (f, 1, FRAME_CURSOR_X (f) + len, FRAME_CURSOR_Y (f));
+static void
+x_fix_overlapping_area (w, row, area)
+     struct window *w;
+     struct glyph_row *row;
+     enum glyph_row_area area;
+{
+  int i, x;
+  
+  BLOCK_INPUT;
+  
+  if (area == LEFT_MARGIN_AREA)
+    x = 0;
+  else if (area == TEXT_AREA)
+    x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
   else
-    curs_x += len;
+    x = (window_box_width (w, LEFT_MARGIN_AREA)
+        + window_box_width (w, TEXT_AREA));
+
+  for (i = 0; i < row->used[area];)
+    {
+      if (row->glyphs[area][i].overlaps_vertically_p)
+       {
+         int start = i, start_x = x;
+
+         do
+           {
+             x += row->glyphs[area][i].pixel_width;
+             ++i;
+           }
+         while (i < row->used[area]
+                && row->glyphs[area][i].overlaps_vertically_p);
 
+         x_draw_glyphs (w, start_x, row, area, start, i,
+                        (row->inverse_p
+                         ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
+                        NULL, NULL, 1);
+       }
+      else
+       {
+         x += row->glyphs[area][i].pixel_width;
+         ++i;
+       }
+    }
+  
   UNBLOCK_INPUT;
 }
-\f
-/* Clear to the end of the line.
-   Erase the current text line from the nominal cursor position (inclusive)
-   to column FIRST_UNUSED (exclusive).  The idea is that everything
-   from FIRST_UNUSED onward is already erased.  */
-
-static
-XTclear_end_of_line (first_unused)
-     register int first_unused;
-{
-  struct frame *f = updating_frame;
-  int mask;
-
-  if (f == 0)
-    abort ();
 
-  if (curs_y < 0 || curs_y >= f->height)
-    return;
-  if (first_unused <= 0)
-    return;
 
-  if (first_unused >= FRAME_WINDOW_WIDTH (f))
-    first_unused = FRAME_WINDOW_WIDTH (f);
+/* Output LEN glyphs starting at START at the nominal cursor position.
+   Advance the nominal cursor over the text.  The global variable
+   updated_window contains the window being updated, updated_row is
+   the glyph row being updated, and updated_area is the area of that
+   row being updated.  */
 
-  first_unused += FRAME_LEFT_SCROLL_BAR_WIDTH (f);
+static void
+x_write_glyphs (start, len)
+     struct glyph *start;
+     int len;
+{
+  int x, hpos, real_start, real_end;
 
+  xassert (updated_window && updated_row);
   BLOCK_INPUT;
+  
+  /* Write glyphs.  */
 
-  do_line_dance ();
+  hpos = start - updated_row->glyphs[updated_area];
+  x = x_draw_glyphs (updated_window, output_cursor.x,
+                    updated_row, updated_area,
+                    hpos, hpos + len,
+                    (updated_row->inverse_p
+                     ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT),
+                    &real_start, &real_end, 0);
 
-  /* Notice if the cursor will be cleared by this operation.  */
-  if (curs_y == f->phys_cursor_y
-      && curs_x <= f->phys_cursor_x
-      && f->phys_cursor_x < first_unused)
-    f->phys_cursor_on = 0;
-
-  XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-             CHAR_TO_PIXEL_COL (f, curs_x),
-             CHAR_TO_PIXEL_ROW (f, curs_y),
-             FONT_WIDTH (f->output_data.x->font) * (first_unused - curs_x),
-             f->output_data.x->line_height, False);
-#if 0
-  redraw_previous_char (f, curs_x, curs_y, highlight);
-#endif
+  /* If we drew over the cursor, note that it is not visible any more.  */
+  note_overwritten_text_cursor (updated_window, real_start,
+                               real_end - real_start);
 
   UNBLOCK_INPUT;
+  
+  /* Advance the output cursor.  */
+  output_cursor.hpos += len;
+  output_cursor.x = x;
 }
 
-static
-XTclear_frame ()
-{
-  int mask;
-  struct frame *f = updating_frame;
 
-  if (f == 0)
-    f = selected_frame;
+/* Insert LEN glyphs from START at the nominal cursor position.   */
 
-  f->phys_cursor_on = 0;       /* Cursor not visible.  */
-  curs_x = 0;                  /* Nominal cursor position is top left.  */
-  curs_y = 0;
+static void
+x_insert_glyphs (start, len)
+     struct glyph *start;
+     register int len;
+{
+  struct frame *f;
+  struct window *w;
+  int line_height, shift_by_width, shifted_region_width;
+  struct glyph_row *row;
+  struct glyph *glyph;
+  int frame_x, frame_y, hpos, real_start, real_end;
 
+  xassert (updated_window && updated_row);
   BLOCK_INPUT;
-
-  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
-
-  /* We have to clear the scroll bars, too.  If we have changed
-     colors or something like that, then they should be notified.  */
-  x_scroll_bar_clear (f);
-
-  XFlush (FRAME_X_DISPLAY (f));
+  w = updated_window;
+  f = XFRAME (WINDOW_FRAME (w));
+
+  /* Get the height of the line we are in.  */
+  row = updated_row;
+  line_height = row->height;
+
+  /* Get the width of the glyphs to insert.  */
+  shift_by_width = 0;
+  for (glyph = start; glyph < start + len; ++glyph)
+    shift_by_width += glyph->pixel_width;
+
+  /* Get the width of the region to shift right.  */
+  shifted_region_width = (window_box_width (w, updated_area)
+                         - output_cursor.x
+                         - shift_by_width);
+
+  /* Shift right.  */
+  frame_x = WINDOW_TO_FRAME_PIXEL_X (w, output_cursor.x);
+  frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, output_cursor.y);
+  XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
+            f->output_data.x->normal_gc,
+            frame_x, frame_y,
+            shifted_region_width, line_height,
+            frame_x + shift_by_width, frame_y);
+
+  /* Write the glyphs.  */
+  hpos = start - row->glyphs[updated_area];
+  x_draw_glyphs (w, output_cursor.x, row, updated_area, hpos, hpos + len,
+                DRAW_NORMAL_TEXT, &real_start, &real_end, 0);
+  note_overwritten_text_cursor (w, real_start, real_end - real_start);
+  
+  /* Advance the output cursor.  */
+  output_cursor.hpos += len;
+  output_cursor.x += shift_by_width;
   UNBLOCK_INPUT;
 }
-\f
-#if 0
-/* This currently does not work because FRAME_CURRENT_GLYPHS doesn't
-   always contain the right glyphs to use.
 
-   It also needs to be changed to look at the details of the font and
-   see whether there is really overlap, and do nothing when there is
-   not.  This can use font_char_overlap_left and font_char_overlap_right,
-   but just how to use them is not clear.  */
 
-/* Erase the character (if any) at the position just before X, Y in frame F,
-   then redraw it and the character before it.
-   This is necessary when we erase starting at X,
-   in case the character after X overlaps into the one before X.
-   Call this function with input blocked.  */
+/* Delete N glyphs at the nominal cursor position.  Not implemented
+   for X frames.  */
 
 static void
-redraw_previous_char (f, x, y, highlight_flag)
-     FRAME_PTR f;
-     int x, y;
-     int highlight_flag;
+x_delete_glyphs (n)
+     register int n;
 {
-  /* Erase the character before the new ones, in case
-     what was here before overlaps it.
-     Reoutput that character, and the previous character
-     (in case the previous character overlaps it).  */
-  if (x > 0)
-    {
-      int start_x = x - 2;
-      if (start_x < 0)
-       start_x = 0;
-      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                 CHAR_TO_PIXEL_COL (f, x - 1),
-                 CHAR_TO_PIXEL_ROW (f, y),
-                 FONT_WIDTH (f->output_data.x->font),
-                 f->output_data.x->line_height, False);
-
-      dumpglyphs (f, CHAR_TO_PIXEL_COL (f, start_x),
-                 CHAR_TO_PIXEL_ROW (f, y),
-                 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][start_x],
-                 x - start_x, highlight_flag, 1, NULL);
-    }
+  abort ();
 }
 
-/* Erase the character (if any) at the position X, Y in frame F,
-   then redraw it and the character after it.
-   This is necessary when we erase endng at X,
-   in case the character after X overlaps into the one before X.
-   Call this function with input blocked.  */
 
-static void
-redraw_following_char (f, x, y, highlight_flag)
-     FRAME_PTR f;
-     int x, y;
-     int highlight_flag;
-{
-  int limit = FRAME_CURRENT_GLYPHS (f)->used[y];
-  /* Erase the character after the new ones, in case
-     what was here before overlaps it.
-     Reoutput that character, and the following character
-     (in case the following character overlaps it).  */
-  if (x < limit
-      && FRAME_CURRENT_GLYPHS (f)->glyphs[y][x] != SPACEGLYPH)
-    {
-      int end_x = x + 2;
-      if (end_x > limit)
-       end_x = limit;
-      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                 CHAR_TO_PIXEL_COL (f, x),
-                 CHAR_TO_PIXEL_ROW (f, y),
-                 FONT_WIDTH (f->output_data.x->font),
-                 f->output_data.x->line_height, False);
+/* Erase the current text line from the nominal cursor position
+   (inclusive) to pixel column TO_X (exclusive).  The idea is that
+   everything from TO_X onward is already erased.
 
-      dumpglyphs (f, CHAR_TO_PIXEL_COL (f, x),
-                 CHAR_TO_PIXEL_ROW (f, y),
-                 &FRAME_CURRENT_GLYPHS (f)->glyphs[y][x],
-                 end_x - x, highlight_flag, 1, NULL);
+   TO_X is a pixel position relative to updated_area of
+   updated_window.  TO_X == -1 means clear to the end of this area.  */
+
+static void
+x_clear_end_of_line (to_x)
+     int to_x;
+{
+  struct frame *f;
+  struct window *w = updated_window;
+  int max_x, min_y, max_y;
+  int from_x, from_y, to_y;
+  
+  xassert (updated_window && updated_row);
+  f = XFRAME (w->frame);
+  
+  if (updated_row->full_width_p)
+    {
+      max_x = XFASTINT (w->width) * CANON_X_UNIT (f);
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+         && !w->pseudo_window_p)
+       max_x += FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f);
     }
-}
-#endif /* 0 */
-\f
-#if 0 /* Not in use yet */
+  else
+    max_x = window_box_width (w, updated_area);
+  max_y = window_text_bottom_y (w);
 
-/* Return 1 if character C in font F extends past its left edge.  */
+  /* TO_X == 0 means don't do anything.  TO_X < 0 means clear to end
+     of window.  For TO_X > 0, truncate to end of drawing area.  */
+  if (to_x == 0)
+    return;
+  else if (to_x < 0)
+    to_x = max_x;
+  else
+    to_x = min (to_x, max_x);
 
-static int
-font_char_overlap_left (font, c)
-     XFontStruct *font;
-     int c;
-{
-  XCharStruct *s;
+  to_y = min (max_y, output_cursor.y + updated_row->height);
+  
+  /* Notice if the cursor will be cleared by this operation.  */
+  if (!updated_row->full_width_p)
+    note_overwritten_text_cursor (w, output_cursor.hpos, -1);
 
-  /* Find the bounding-box info for C.  */
-  if (font->per_char == 0)
-    s = &font->max_bounds;
+  from_x = output_cursor.x;
+     
+  /* Translate to frame coordinates.  */
+  if (updated_row->full_width_p)
+    {
+      from_x = WINDOW_TO_FRAME_PIXEL_X (w, from_x);
+      to_x = WINDOW_TO_FRAME_PIXEL_X (w, to_x);
+    }
   else
     {
-      int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
-      int row, within;
-
-      /* Decode char into row number (byte 1) and code within row (byte 2).  */
-      row = c >> 8;
-      within = c & 0177;
-      if (!(within >= font->min_char_or_byte2
-           && within <= font->max_char_or_byte2
-           && row >= font->min_byte1
-           && row <= font->max_byte1))
-       {
-         /* If char is out of range, try the font's default char instead.  */
-         c = font->default_char;
-         row = c >> (BITS_PER_INT - 8);
-         within = c & 0177;
-       }
-      if (!(within >= font->min_char_or_byte2
-           && within <= font->max_char_or_byte2
-           && row >= font->min_byte1
-           && row <= font->max_byte1))
-       /* Still out of range means this char does not overlap.  */
-       return 0;
-      else
-       /* We found the info for this char.  */
-       s = (font->per_char + (within - font->min_char_or_byte2)
-            + row * rowlen);
+      from_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, from_x);
+      to_x = WINDOW_AREA_TO_FRAME_PIXEL_X (w, updated_area, to_x);
+    }
+  
+  min_y = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+  from_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (min_y, output_cursor.y));
+  to_y = WINDOW_TO_FRAME_PIXEL_Y (w, to_y);
+  
+  /* Prevent inadvertently clearing to end of the X window.  */
+  if (to_x > from_x && to_y > from_y)
+    {
+      BLOCK_INPUT;
+      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 from_x, from_y, to_x - from_x, to_y - from_y,
+                 False);
+      UNBLOCK_INPUT;
     }
-
-  return (s && s->lbearing < 0);
 }
 
-/* Return 1 if character C in font F extends past its right edge.  */
 
-static int
-font_char_overlap_right (font, c)
-     XFontStruct *font;
-     int c;
+/* Clear entire frame.  If updating_frame is non-null, clear that
+   frame.  Otherwise clear selected_frame.  */
+
+static void
+x_clear_frame ()
 {
-  XCharStruct *s;
+  struct frame *f;
 
-  /* Find the bounding-box info for C.  */
-  if (font->per_char == 0)
-    s = &font->max_bounds;
+  if (updating_frame)
+    f = updating_frame;
   else
-    {
-      int rowlen = font->max_char_or_byte2 - font->min_char_or_byte2 + 1;
-      int row, within;
+    f = selected_frame;
 
-      /* Decode char into row number (byte 1) and code within row (byte 2).  */
-      row = c >> 8;
-      within = c & 0177;
-      if (!(within >= font->min_char_or_byte2
-           && within <= font->max_char_or_byte2
-           && row >= font->min_byte1
-           && row <= font->max_byte1))
-       {
-         /* If char is out of range, try the font's default char instead.  */
-         c = font->default_char;
-         row = c >> (BITS_PER_INT - 8);
-         within = c & 0177;
-       }
-      if (!(within >= font->min_char_or_byte2
-           && within <= font->max_char_or_byte2
-           && row >= font->min_byte1
-           && row <= font->max_byte1))
-       /* Still out of range means this char does not overlap.  */
-       return 0;
-      else
-       /* We found the info for this char.  */
-       s = (font->per_char + (within - font->min_char_or_byte2)
-            + row * rowlen);
-    }
+  /* Clearing the frame will erase any cursor, so mark them all as no
+     longer visible.  */
+  mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
+  output_cursor.hpos = output_cursor.vpos = 0;
+  output_cursor.x = -1;
+
+  /* We don't set the output cursor here because there will always
+     follow an explicit cursor_to.  */
+  BLOCK_INPUT;
+  XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+
+  /* We have to clear the scroll bars, too.  If we have changed
+     colors or something like that, then they should be notified.  */
+  x_scroll_bar_clear (f);
 
-  return (s && s->rbearing >= s->width);
+  XFlush (FRAME_X_DISPLAY (f));
+  UNBLOCK_INPUT;
 }
-#endif /* 0 */
+
+
 \f
 /* Invert the middle quarter of the frame for .15 sec.  */
 
-/* We use the select system call to do the waiting, so we have to make sure
-   it's available.  If it isn't, we just won't do visual bells.  */
+/* We use the select system call to do the waiting, so we have to make
+   sure it's available.  If it isn't, we just won't do visual bells.  */
+
 #if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
 
-/* Subtract the `struct timeval' values X and Y,
-   storing the result in RESULT.
-   Return 1 if the difference is negative, otherwise 0.  */
+
+/* Subtract the `struct timeval' values X and Y, storing the result in
+   *RESULT.  Return 1 if the difference is negative, otherwise 0.  */
 
 static int
 timeval_subtract (result, x, y)
      struct timeval *result, x, y;
 {
-  /* Perform the carry for the later subtraction by updating y.
-     This is safer because on some systems
-     the tv_sec member is unsigned.  */
+  /* Perform the carry for the later subtraction by updating y.  This
+     is safer because on some systems the tv_sec member is unsigned.  */
   if (x.tv_usec < y.tv_usec)
     {
       int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
       y.tv_usec -= 1000000 * nsec;
       y.tv_sec += nsec;
     }
+  
   if (x.tv_usec - y.tv_usec > 1000000)
     {
       int nsec = (y.tv_usec - x.tv_usec) / 1000000;
@@ -1444,14 +4803,17 @@ timeval_subtract (result, x, y)
       y.tv_sec -= nsec;
     }
 
-  /* Compute the time remaining to wait.  tv_usec is certainly positive.  */
+  /* Compute the time remaining to wait.  tv_usec is certainly
+     positive.  */
   result->tv_sec = x.tv_sec - y.tv_sec;
   result->tv_usec = x.tv_usec - y.tv_usec;
 
-  /* Return indication of whether the result should be considered negative.  */
+  /* Return indication of whether the result should be considered
+     negative.  */
   return x.tv_sec < y.tv_sec;
 }
 
+void
 XTflash (f)
      struct frame *f;
 {
@@ -1460,8 +4822,8 @@ XTflash (f)
   {
     GC gc;
 
-    /* Create a GC that will use the GXxor function to flip foreground pixels
-       into background pixels.  */
+    /* Create a GC that will use the GXxor function to flip foreground
+       pixels into background pixels.  */
     {
       XGCValues values;
 
@@ -1495,6 +4857,9 @@ XTflash (f)
        case vertical_scroll_bar_right:
          flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
          break;
+
+       default:
+         break;
        }
 
       width = flash_right - flash_left;
@@ -1503,7 +4868,9 @@ XTflash (f)
       if (height > 3 * FRAME_LINE_HEIGHT (f))
        {
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                         flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
+                         flash_left,
+                         (FRAME_INTERNAL_BORDER_WIDTH (f)
+                          + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
                          width, flash_height);
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
@@ -1517,10 +4884,10 @@ XTflash (f)
                        flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
                        width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
 
-      XFlush (FRAME_X_DISPLAY (f));
+      x_flush (f);
 
       {
-       struct timeval wakeup, now;
+       struct timeval wakeup;
 
        EMACS_GET_TIME (wakeup);
 
@@ -1550,7 +4917,9 @@ XTflash (f)
       if (height > 3 * FRAME_LINE_HEIGHT (f))
        {
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
-                         flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
+                         flash_left,
+                         (FRAME_INTERNAL_BORDER_WIDTH (f)
+                          + FRAME_TOOL_BAR_LINES (f) * CANON_Y_UNIT (f)),
                          width, flash_height);
          XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
                          flash_left,
@@ -1565,20 +4934,21 @@ XTflash (f)
                        width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
 
       XFreeGC (FRAME_X_DISPLAY (f), gc);
-      XFlush (FRAME_X_DISPLAY (f));
+      x_flush (f);
     }
   }
 
   UNBLOCK_INPUT;
 }
 
-#endif
+#endif /* defined (HAVE_TIMEVAL) && defined (HAVE_SELECT) */
 
 
 /* Make audible bell.  */
 
 #define XRINGBELL XBell (FRAME_X_DISPLAY (selected_frame), 0)
 
+void
 XTring_bell ()
 {
   if (FRAME_X_DISPLAY (selected_frame) == 0)
@@ -1596,263 +4966,481 @@ XTring_bell ()
       UNBLOCK_INPUT;
     }
 }
+
 \f
-/* Insert and delete character.
-   These are not supposed to be used because we are supposed to turn
-   off the feature of using them.  */
+/* Specify how many text lines, from the top of the window,
+   should be affected by insert-lines and delete-lines operations.
+   This, and those operations, are used only within an update
+   that is bounded by calls to x_update_begin and x_update_end.  */
 
-static
-XTinsert_glyphs (start, len)
-     register char *start;
-     register int len;
+static void
+XTset_terminal_window (n)
+     register int n;
 {
-  abort ();
+  /* This function intentionally left blank.  */
 }
 
-static
-XTdelete_glyphs (n)
-     register int n;
+
+\f
+/***********************************************************************
+                             Line Dance
+ ***********************************************************************/
+
+/* Perform an insert-lines or delete-lines operation, inserting N
+   lines or deleting -N lines at vertical position VPOS.  */
+
+static void
+x_ins_del_lines (vpos, n)
+     int vpos, n;
 {
   abort ();
 }
-\f
-/* Specify how many text lines, from the top of the window,
-   should be affected by insert-lines and delete-lines operations.
-   This, and those operations, are used only within an update
-   that is bounded by calls to XTupdate_begin and XTupdate_end.  */
 
-static
-XTset_terminal_window (n)
-     register int n;
+
+/* Scroll part of the display as described by RUN.  */
+
+static void
+x_scroll_run (w, run)
+     struct window *w;
+     struct run *run;
 {
-  if (updating_frame == 0)
-    abort ();
+  struct frame *f = XFRAME (w->frame);
+  int x, y, width, height, from_y, to_y, bottom_y;
 
-  if ((n <= 0) || (n > updating_frame->height))
-    flexlines = updating_frame->height;
+  /* Get frame-relative bounding box of the text display area of W,
+     without mode lines.  Include in this box the flags areas to the
+     left and right of W.  */
+  window_box (w, -1, &x, &y, &width, &height);
+  width += FRAME_X_FLAGS_AREA_WIDTH (f);
+  x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
+
+  from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
+  to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
+  bottom_y = y + height;
+
+  if (to_y < from_y)
+    {
+      /* Scrolling up.  Make sure we don't copy part of the mode
+        line at the bottom.  */
+      if (from_y + run->height > bottom_y)
+       height = bottom_y - from_y;
+      else
+       height = run->height;
+    }
   else
-    flexlines = n;
-}
-\f
-/* These variables need not be per frame
-   because redisplay is done on a frame-by-frame basis
-   and the line dance for one frame is finished before
-   anything is done for anoter frame.  */
+    {
+      /* Scolling down.  Make sure we don't copy over the mode line.
+        at the bottom.  */
+      if (to_y + run->height > bottom_y)
+       height = bottom_y - to_y;
+      else
+       height = run->height;
+    }
 
-/* Array of line numbers from cached insert/delete operations.
-   line_dance[i] is the old position of the line that we want
-   to move to line i, or -1 if we want a blank line there.  */
-static int *line_dance;
+  BLOCK_INPUT;
+  
+  /* Cursor off.  Will be switched on again in x_update_window_end.  */
+  updated_window = w;
+  x_clear_cursor (w);
+
+  XCopyArea (FRAME_X_DISPLAY (f),
+            FRAME_X_WINDOW (f), FRAME_X_WINDOW (f),
+            f->output_data.x->normal_gc,
+            x, from_y,
+            width, height,
+            x, to_y);
+  
+  UNBLOCK_INPUT;
+}
 
-/* Allocated length of that array.  */
-static int line_dance_len;
 
-/* Flag indicating whether we've done any work.  */
-static int line_dance_in_progress;
+\f
+/***********************************************************************
+                          Exposure Events
+ ***********************************************************************/
+                                                                       
+/* Redisplay an exposed area of frame F.  X and Y are the upper-left
+   corner of the exposed rectangle.  W and H are width and height of
+   the exposed area.  All are pixel values.  W or H zero means redraw
+   the entire frame.  */
 
-/* Perform an insert-lines or delete-lines operation,
-   inserting N lines or deleting -N lines at vertical position VPOS.  */
-XTins_del_lines (vpos, n)
-     int vpos, n;
+static void
+expose_frame (f, x, y, w, h)
+     struct frame *f;
+     int x, y, w, h;
 {
-  register int fence, i;
+  XRectangle r;
 
-  if (vpos >= flexlines)
-    return;
+  TRACE ((stderr, "expose_frame "));
 
-  if (!line_dance_in_progress)
+  /* No need to redraw if frame will be redrawn soon.  */
+  if (FRAME_GARBAGED_P (f))
     {
-      int ht = updating_frame->height;
-      if (ht > line_dance_len)
-       {
-         line_dance = (int *)xrealloc (line_dance, ht * sizeof (int));
-         line_dance_len = ht;
-       }
-      for (i = 0; i < ht; ++i) line_dance[i] = i;
-      line_dance_in_progress = 1;
+      TRACE ((stderr, " garbaged\n"));
+      return;
     }
-  if (n >= 0)
+
+  /* If basic faces haven't been realized yet, there is no point in
+     trying to redraw anything.  This can happen when we get an expose
+     event while Emacs is starting, e.g. by moving another window.  */
+  if (FRAME_FACE_CACHE (f) == NULL
+      || FRAME_FACE_CACHE (f)->used < BASIC_FACE_ID_SENTINEL)
+    {
+      TRACE ((stderr, " no faces\n"));
+      return;
+    }
+
+  if (w == 0 || h == 0)
     {
-      if (n > flexlines - vpos)
-       n = flexlines - vpos;
-      fence = vpos + n;
-      for (i = flexlines; --i >= fence;)
-       line_dance[i] = line_dance[i-n];
-      for (i = fence; --i >= vpos;)
-       line_dance[i] = -1;
+      r.x = r.y = 0;
+      r.width = CANON_X_UNIT (f) * f->width;
+      r.height = CANON_Y_UNIT (f) * f->height;
     }
   else
     {
-      n = -n;
-      if (n > flexlines - vpos)
-       n = flexlines - vpos;
-      fence = flexlines - n;
-      for (i = vpos; i < fence; ++i)
-       line_dance[i] = line_dance[i + n];
-      for (i = fence; i < flexlines; ++i)
-       line_dance[i] = -1;
+      r.x = x;
+      r.y = y;
+      r.width = w;
+      r.height = h;
+    }
+
+  TRACE ((stderr, "(%d, %d, %d, %d)\n", r.x, r.y, r.width, r.height));
+  expose_window_tree (XWINDOW (f->root_window), &r);
+
+  if (WINDOWP (f->tool_bar_window))
+    {
+      struct window *w = XWINDOW (f->tool_bar_window);
+      XRectangle window_rect;
+      XRectangle intersection_rect;
+      int window_x, window_y, window_width, window_height;
+      
+
+      window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+      window_rect.x = window_x;
+      window_rect.y = window_y;
+      window_rect.width = window_width;
+      window_rect.height = window_height;
+
+      if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
+       expose_window (w, &intersection_rect);
+    }
+
+#ifndef USE_X_TOOLKIT
+  if (WINDOWP (f->menu_bar_window))
+    {
+      struct window *w = XWINDOW (f->menu_bar_window);
+      XRectangle window_rect;
+      XRectangle intersection_rect;
+      int window_x, window_y, window_width, window_height;
+      
+
+      window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+      window_rect.x = window_x;
+      window_rect.y = window_y;
+      window_rect.width = window_width;
+      window_rect.height = window_height;
+
+      if (x_intersect_rectangles (&r, &window_rect, &intersection_rect))
+       expose_window (w, &intersection_rect);
     }
+#endif /* not USE_X_TOOLKIT */
 }
 
-/* Here's where we actually move the pixels around.
-   Must be called with input blocked.  */
+
+/* Redraw (parts) of all windows in the window tree rooted at W that
+   intersect R.  R contains frame pixel coordinates.  */
+
 static void
-do_line_dance ()
+expose_window_tree (w, r)
+     struct window *w;
+     XRectangle *r;
 {
-  register int i, j, distance;
-  register struct frame *f;
-  int ht;
-  int intborder;
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       expose_window_tree (XWINDOW (w->hchild), r);
+      else if (!NILP (w->vchild))
+       expose_window_tree (XWINDOW (w->vchild), r);
+      else
+       {
+         XRectangle window_rect;
+         XRectangle intersection_rect;
+         struct frame *f = XFRAME (w->frame);
+         int window_x, window_y, window_width, window_height;
+
+         /* Frame-relative pixel rectangle of W.  */
+         window_box (w, -1, &window_x, &window_y, &window_width,
+                     &window_height);
+         window_rect.x
+           = (window_x
+              - FRAME_X_LEFT_FLAGS_AREA_WIDTH (f)
+              - FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
+         window_rect.y = window_y;
+         window_rect.width
+           = (window_width
+              + FRAME_X_FLAGS_AREA_WIDTH (f)
+              + FRAME_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f));
+         window_rect.height
+           = window_height + CURRENT_MODE_LINE_HEIGHT (w);
+
+         if (x_intersect_rectangles (r, &window_rect, &intersection_rect))
+           expose_window (w, &intersection_rect);
+       }
 
-  /* Must check this flag first.  If it's not set, then not only is the
-     array uninitialized, but we might not even have a frame.  */
-  if (!line_dance_in_progress)
-    return;
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
 
-  f = updating_frame;
-  if (f == 0)
-    abort ();
 
-  ht = f->height;
-  intborder = CHAR_TO_PIXEL_COL (f, FRAME_LEFT_SCROLL_BAR_WIDTH (f));
+/* Redraw the part of glyph row area AREA of glyph row ROW on window W
+   which intersects rectangle R.  R is in window-relative coordinates.  */
 
-  x_update_cursor (updating_frame, 0);
+static void
+expose_area (w, row, r, area)
+     struct window *w;
+     struct glyph_row *row;
+     XRectangle *r;
+     enum glyph_row_area area;
+{
+  int x;
+  struct glyph *first = row->glyphs[area];
+  struct glyph *end = row->glyphs[area] + row->used[area];
+  struct glyph *last;
+  int first_x;
+
+  /* Set x to the window-relative start position for drawing glyphs of
+     AREA.  The first glyph of the text area can be partially visible.
+     The first glyphs of other areas cannot.  */
+  if (area == LEFT_MARGIN_AREA)
+    x = 0;
+  else if (area == TEXT_AREA)
+    x = row->x + window_box_width (w, LEFT_MARGIN_AREA);
+  else
+    x = (window_box_width (w, LEFT_MARGIN_AREA)
+        + window_box_width (w, TEXT_AREA));
+
+  if (area == TEXT_AREA && row->fill_line_p)
+    /* If row extends face to end of line write the whole line.  */
+    x_draw_glyphs (w, x, row, area,
+                  0, row->used[area],
+                  row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
+                  NULL, NULL, 0);
+  else
+    {
+      /* Find the first glyph that must be redrawn.  */
+      while (first < end
+            && x + first->pixel_width < r->x)
+       {
+         x += first->pixel_width;
+         ++first;
+       }
+      
+      /* Find the last one.  */
+      last = first;
+      first_x = x;
+      while (last < end
+            && x < r->x + r->width)
+       {
+         x += last->pixel_width;
+         ++last;
+       }
+      
+      /* Repaint.  */
+      if (last > first)
+       x_draw_glyphs (w, first_x, row, area,
+                      first - row->glyphs[area],
+                      last - row->glyphs[area],
+                      row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
+                      NULL, NULL, 0);
+    }
+}
+      
 
-  for (i = 0; i < ht; ++i)
-    if (line_dance[i] != -1 && (distance = line_dance[i]-i) > 0)
-      {
-       for (j = i; (j < ht && line_dance[j] != -1
-                    && line_dance[j]-j == distance); ++j);
-       /* Copy [i,j) upward from [i+distance,j+distance) */
-       XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                  FRAME_X_WINDOW (f), f->output_data.x->normal_gc,
-                  intborder, CHAR_TO_PIXEL_ROW (f, i+distance),
-                  FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
-                  (j-i) * f->output_data.x->line_height,
-                  intborder, CHAR_TO_PIXEL_ROW (f, i));
-       i = j-1;
-      }
+/* Redraw the parts of the glyph row ROW on window W intersecting
+   rectangle R.  R is in window-relative coordinates.  */
 
-  for (i = ht; --i >=0; )
-    if (line_dance[i] != -1 && (distance = line_dance[i]-i) < 0)
-      {
-       for (j = i; (--j >= 0 && line_dance[j] != -1
-                    && line_dance[j]-j == distance););
-       /* Copy (j,i] downward from (j+distance, i+distance] */
-       XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                  FRAME_X_WINDOW (f), f->output_data.x->normal_gc,
-                  intborder, CHAR_TO_PIXEL_ROW (f, j+1+distance),
-                  FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
-                  (i-j) * f->output_data.x->line_height,
-                  intborder, CHAR_TO_PIXEL_ROW (f, j+1));
-       i = j+1;
-      }
+static void
+expose_line (w, row, r)
+     struct window *w;
+     struct glyph_row *row;
+     XRectangle *r;
+{
+  xassert (row->enabled_p);
+  
+  if (row->mode_line_p || w->pseudo_window_p)
+    x_draw_glyphs (w, 0, row, TEXT_AREA, 0, row->used[TEXT_AREA],
+                  row->inverse_p ? DRAW_INVERSE_VIDEO : DRAW_NORMAL_TEXT,
+                  NULL, NULL, 0);
+  else
+    {
+      if (row->used[LEFT_MARGIN_AREA])
+       expose_area (w, row, r, LEFT_MARGIN_AREA);
+      if (row->used[TEXT_AREA])
+       expose_area (w, row, r, TEXT_AREA);
+      if (row->used[RIGHT_MARGIN_AREA])
+       expose_area (w, row, r, RIGHT_MARGIN_AREA);
+      x_draw_row_bitmaps (w, row);
+    }
+}
 
-  for (i = 0; i < ht; ++i)
-    if (line_dance[i] == -1)
-      {
-       for (j = i; j < ht && line_dance[j] == -1; ++j);
-       /* Clear [i,j) */
-       XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                   intborder, CHAR_TO_PIXEL_ROW (f, i),
-                   FRAME_WINDOW_WIDTH (f) * FONT_WIDTH (f->output_data.x->font),
-                   (j-i) * f->output_data.x->line_height, False);
-       i = j-1;
-      }
-  line_dance_in_progress = 0;
+
+/* Return non-zero if W's cursor intersects rectangle R.  */
+
+static int
+x_phys_cursor_in_rect_p (w, r)
+     struct window *w;
+     XRectangle *r;
+{
+  XRectangle cr, result;
+  struct glyph *cursor_glyph;
+
+  cursor_glyph = get_phys_cursor_glyph (w);
+  if (cursor_glyph)
+    {
+      cr.x = w->phys_cursor.x;
+      cr.y = w->phys_cursor.y;
+      cr.width = cursor_glyph->pixel_width;
+      cr.height = w->phys_cursor_height;
+      return x_intersect_rectangles (&cr, r, &result);
+    }
+  else
+    return 0;
 }
-\f
-/* Support routines for exposure events.  */
-static void clear_cursor ();
 
-/* Output into a rectangle of an X-window (for frame F)
-   the characters in f->phys_lines that overlap that rectangle.
-   TOP and LEFT are the position of the upper left corner of the rectangle.
-   ROWS and COLS are the size of the rectangle.
-   Call this function with input blocked.  */
+
+/* Redraw a rectangle of window W.  R is a rectangle in window
+   relative coordinates.  Call this function with input blocked.  */
 
 static void
-dumprectangle (f, left, top, cols, rows)
-     struct frame *f;
-     register int left, top, cols, rows;
+expose_window (w, r)
+     struct window *w;
+     XRectangle *r;
 {
-  register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
-  int cursor_cleared = 0;
-  int bottom, right;
-  register int y;
-
-  if (FRAME_GARBAGED_P (f))
+  struct glyph_row *row;
+  int y;
+  int yb = window_text_bottom_y (w);
+  int cursor_cleared_p;
+
+  /* If window is not yet fully initialized, do nothing.  This can
+     happen when toolkit scroll bars are used and a window is split.
+     Reconfiguring the scroll bar will generate an expose for a newly
+     created window.  */
+  if (w->current_matrix == NULL)
     return;
 
-  /* Express rectangle as four edges, instead of position-and-size.  */
-  bottom = top + rows;
-  right = left + cols;
-
-  /* Convert rectangle edges in pixels to edges in chars.
-     Round down for left and top, up for right and bottom.  */
-  top  = PIXEL_TO_CHAR_ROW (f, top);
-  left = PIXEL_TO_CHAR_COL (f, left);
-  bottom += (f->output_data.x->line_height - 1);
-  right += (FONT_WIDTH (f->output_data.x->font) - 1);
-  bottom = PIXEL_TO_CHAR_ROW (f, bottom);
-  right = PIXEL_TO_CHAR_COL (f, right);
-
-  /* Clip the rectangle to what can be visible.  */
-  if (left < 0)
-    left = 0;
-  if (top < 0)
-    top = 0;
-  if (right > FRAME_WINDOW_WIDTH (f))
-    right = FRAME_WINDOW_WIDTH (f);
-  if (bottom > f->height)
-    bottom = f->height;
-
-  /* Get size in chars of the rectangle.  */
-  cols = right - left;
-  rows = bottom - top;
-
-  /* If rectangle has zero area, return.  */
-  if (rows <= 0) return;
-  if (cols <= 0) return;
-
-  /* Turn off the cursor if it is in the rectangle.
-     We will turn it back on afterward.  */
-  if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
-      && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
-    {
-      clear_cursor (f);
-      cursor_cleared = 1;
-    }
+  TRACE ((stderr, "expose_window (%d, %d, %d, %d)\n",
+         r->x, r->y, r->width, r->height));
 
+  /* Convert to window coordinates.  */
+  r->x = FRAME_TO_WINDOW_PIXEL_X (w, r->x);
+  r->y = FRAME_TO_WINDOW_PIXEL_Y (w, r->y);
+
+  /* Turn off the cursor.  */
+  if (!w->pseudo_window_p
+      && x_phys_cursor_in_rect_p (w, r))
+    {
+      x_clear_cursor (w);
+      cursor_cleared_p = 1;
+    }
+  else
+    cursor_cleared_p = 0;
+
+  /* Find the first row intersecting the rectangle R.  */
+  row = w->current_matrix->rows;
+  y = 0;
+  while (row->enabled_p
+        && y < yb
+        && y + row->height < r->y)
+    {
+      y += row->height;
+      ++row;
+    }
+       
   /* Display the text in the rectangle, one text line at a time.  */
+  while (row->enabled_p
+        && y < yb
+        && y < r->y + r->height)
+    {
+      expose_line (w, row, r);
+      y += row->height;
+      ++row;
+    }
 
-  for (y = top; y < bottom; y++)
+  /* Display the mode line if there is one.  */
+  if (WINDOW_WANTS_MODELINE_P (w)
+      && (row = MATRIX_MODE_LINE_ROW (w->current_matrix),
+         row->enabled_p)
+      && row->y < r->y + r->height)
+    expose_line (w, row, r);
+
+  if (!w->pseudo_window_p)
     {
-      GLYPH *line = &active_frame->glyphs[y][left];
+      /* Draw border between windows.  */
+      x_draw_vertical_border (w);
+      
+      /* Turn the cursor on again.  */
+      if (cursor_cleared_p)
+       x_update_window_cursor (w, 1);
+    }
+}
 
-      if (! active_frame->enable[y] || left > active_frame->used[y])
-       continue;
 
-      while (*line & GLYPH_MASK_PADDING)
+/* Determine the intersection of two rectangles R1 and R2.  Return
+   the intersection in *RESULT.  Value is non-zero if RESULT is not
+   empty.  */
+
+static int
+x_intersect_rectangles (r1, r2, result)
+     XRectangle *r1, *r2, *result;
+{
+  XRectangle *left, *right;
+  XRectangle *upper, *lower;
+  int intersection_p = 0;
+  
+  /* Rearrange so that R1 is the left-most rectangle.  */
+  if (r1->x < r2->x)
+    left = r1, right = r2;
+  else
+    left = r2, right = r1;
+
+  /* X0 of the intersection is right.x0, if this is inside R1,
+     otherwise there is no intersection.  */
+  if (right->x <= left->x + left->width)
+    {
+      result->x = right->x;
+      
+      /* The right end of the intersection is the minimum of the
+        the right ends of left and right.  */
+      result->width = (min (left->x + left->width, right->x + right->width)
+                      - result->x);
+
+      /* Same game for Y.  */
+      if (r1->y < r2->y)
+       upper = r1, lower = r2;
+      else
+       upper = r2, lower = r1;
+
+      /* The upper end of the intersection is lower.y0, if this is inside
+        of upper.  Otherwise, there is no intersection.  */
+      if (lower->y <= upper->y + upper->height)
        {
-         /* We must display the whole glyph of a wide-column
-             character.  */
-         left--;
-         line--;
-         cols++;
+         result->y = lower->y;
+         
+         /* The lower end of the intersection is the minimum of the lower
+            ends of upper and lower.  */
+         result->height = (min (lower->y + lower->height, 
+                                upper->y + upper->height)
+                           - result->y);
+         intersection_p = 1;
        }
-      dumpglyphs (f,
-                 CHAR_TO_PIXEL_COL (f, left),
-                 CHAR_TO_PIXEL_ROW (f, y),
-                 line, min (cols, active_frame->used[y] - left),
-                 active_frame->highlight[y], 0, NULL);
     }
 
-  /* Turn the cursor on if we turned it off.  */
-
-  if (cursor_cleared)
-    x_update_cursor (f, 1);
+  return intersection_p;
 }
+
+
+
+
 \f
 static void
 frame_highlight (f)
@@ -1884,9 +5472,6 @@ frame_unhighlight (f)
   x_update_cursor (f, 1);
 }
 
-static void XTframe_rehighlight ();
-static void x_frame_rehighlight ();
-
 /* The focus has changed.  Update the frames as necessary to reflect
    the new situation.  Note that we can't change the selected frame
    here, because the Lisp code we are interrupting might become confused.
@@ -1899,7 +5484,6 @@ x_new_focus_frame (dpyinfo, frame)
      struct frame *frame;
 {
   struct frame *old_focus = dpyinfo->x_focus_frame;
-  int events_enqueued = 0;
 
   if (frame != dpyinfo->x_focus_frame)
     {
@@ -1938,11 +5522,12 @@ x_mouse_leave (dpyinfo)
 
 /* The focus has changed, or we have redirected a frame's focus to
    another frame (this happens when a frame uses a surrogate
-   minibuffer frame).  Shift the highlight as appropriate.
+   mini-buffer frame).  Shift the highlight as appropriate.
 
    The FRAME argument doesn't necessarily have anything to do with which
-   frame is being highlighted or unhighlighted; we only use it to find
+   frame is being highlighted or un-highlighted; we only use it to find
    the appropriate X display info.  */
+
 static void
 XTframe_rehighlight (frame)
      struct frame *frame;
@@ -1979,8 +5564,10 @@ x_frame_rehighlight (dpyinfo)
        frame_highlight (dpyinfo->x_highlight_frame);
     }
 }
+
+
 \f
-/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
+/* Keyboard processing - modifier keys, vendor-specific keysyms, etc.  */
 
 /* Initialize mode_switch_bit and modifier_meaning.  */
 static void
@@ -2013,7 +5600,7 @@ x_find_modifier_meanings (dpyinfo)
   /* Scan the modifier table to see which modifier bits the Meta and
      Alt keysyms are on.  */
   {
-    int row, col;      /* The row and column in the modifier table. */
+    int row, col;      /* The row and column in the modifier table.  */
 
     for (row = 3; row < 8; row++)
       for (col = 0; col < mods->max_keypermod; col++)
@@ -2086,6 +5673,7 @@ x_find_modifier_meanings (dpyinfo)
 
 /* Convert between the modifier bits X uses and the modifier bits
    Emacs uses.  */
+
 static unsigned int
 x_x_to_emacs_modifiers (dpyinfo, state)
      struct x_display_info *dpyinfo;
@@ -2126,13 +5714,15 @@ x_get_keysym_name (keysym)
 
   return value;
 }
+
+
 \f
 /* Mouse clicks and mouse movement.  Rah.  */
 
-/* Given a pixel position (PIX_X, PIX_Y) on the frame F, return
-   glyph co-ordinates in (*X, *Y).  Set *BOUNDS to the rectangle
-   that the glyph at X, Y occupies, if BOUNDS != 0.
-   If NOCLIP is nonzero, do not force the value into range.  */
+/* Given a pixel position (PIX_X, PIX_Y) on frame F, return glyph
+   co-ordinates in (*X, *Y).  Set *BOUNDS to the rectangle that the
+   glyph at X, Y occupies, if BOUNDS != 0.  If NOCLIP is non-zero, do
+   not force the value into range.  */
 
 void
 pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
@@ -2142,7 +5732,7 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
      XRectangle *bounds;
      int noclip;
 {
-  /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to round down
+  /* Arrange for the division in PIXEL_TO_CHAR_COL etc.  to round down
      even for negative values.  */
   if (pix_x < 0)
     pix_x -= FONT_WIDTH ((f)->output_data.x->font) - 1;
@@ -2177,16 +5767,51 @@ pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
   *y = pix_y;
 }
 
-void
-glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
-     FRAME_PTR f;
-     register int x, y;
-     register int *pix_x, *pix_y;
+
+/* Given HPOS/VPOS in the current matrix of W, return corresponding
+   frame-relative pixel positions in *FRAME_X and *FRAME_Y.  If we
+   can't tell the positions because W's display is not up to date,
+   return 0.  */
+
+int
+glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
+     struct window *w;
+     int hpos, vpos;
+     int *frame_x, *frame_y;
 {
-  *pix_x = CHAR_TO_PIXEL_COL (f, x);
-  *pix_y = CHAR_TO_PIXEL_ROW (f, y);
+  int success_p;
+
+  xassert (hpos >= 0 && hpos < w->current_matrix->matrix_w);
+  xassert (vpos >= 0 && vpos < w->current_matrix->matrix_h);
+
+  if (display_completed)
+    {
+      struct glyph_row *row = MATRIX_ROW (w->current_matrix, vpos);
+      struct glyph *glyph = row->glyphs[TEXT_AREA];
+      struct glyph *end = glyph + min (hpos, row->used[TEXT_AREA]);
+
+      *frame_y = row->y;
+      *frame_x = row->x;
+      while (glyph < end)
+       {
+         *frame_x += glyph->pixel_width;
+         ++glyph;
+       }
+
+      success_p = 1;
+    }
+  else
+    {
+      *frame_y = *frame_x = 0;
+      success_p = 0;
+    }
+
+  *frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, *frame_y);
+  *frame_x = WINDOW_TO_FRAME_PIXEL_X (w, *frame_x);
+  return success_p;
 }
 
+
 /* Prepare a mouse-event in *RESULT for placement in the input queue.
 
    If the event is a button press, then note that we have grabbed
@@ -2209,20 +5834,14 @@ construct_mouse_click (result, event, f)
                          ? up_modifier
                          : down_modifier));
 
-  {
-    int row, column;
-
-#if 0
-    pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL, 0);
-    XSETFASTINT (result->x, column);
-    XSETFASTINT (result->y, row);
-#endif
-    XSETINT (result->x, event->x);
-    XSETINT (result->y, event->y);
-    XSETFRAME (result->frame_or_window, f);
-  }
+  XSETINT (result->x, event->x);
+  XSETINT (result->y, event->y);
+  XSETFRAME (result->frame_or_window, f);
+  return Qnil;
 }
 
+#if 0 /* This function isn't called. --gerd  */
+
 /* Prepare a menu-event in *RESULT for placement in the input queue.  */
 
 static Lisp_Object
@@ -2246,6 +5865,9 @@ construct_menu_click (result, event, f)
   XSETINT (result->y, -1);
   XSETFRAME (result->frame_or_window, f);
 }
+
+#endif /* 0 */
+
 \f
 /* Function to report a mouse movement to the mainstream Emacs code.
    The input handler calls this.
@@ -2255,18 +5877,22 @@ construct_menu_click (result, event, f)
    the mainstream emacs code by setting mouse_moved.  If not, ask for
    another motion event, so we can check again the next time it moves.  */
 
+static XMotionEvent last_mouse_motion_event;
+static Lisp_Object last_mouse_motion_frame;
+
 static void
 note_mouse_movement (frame, event)
      FRAME_PTR frame;
      XMotionEvent *event;
 {
   last_mouse_movement_time = event->time;
+  last_mouse_motion_event = *event;
+  XSETFRAME (last_mouse_motion_frame, frame);
 
   if (event->window != FRAME_X_WINDOW (frame))
     {
       frame->mouse_moved = 1;
       last_mouse_scroll_bar = Qnil;
-
       note_mouse_highlight (frame, -1, -1);
     }
 
@@ -2278,356 +5904,890 @@ note_mouse_movement (frame, event)
     {
       frame->mouse_moved = 1;
       last_mouse_scroll_bar = Qnil;
-
       note_mouse_highlight (frame, event->x, event->y);
     }
 }
 
 /* This is used for debugging, to turn off note_mouse_highlight.  */
-static int disable_mouse_highlight;
 
-/* Take proper action when the mouse has moved to position X, Y on frame F
-   as regards highlighting characters that have mouse-face properties.
-   Also dehighlighting chars where the mouse was before.
+ int disable_mouse_highlight;
+
+
+\f
+/************************************************************************
+                             Mouse Face
+ ************************************************************************/
+
+/* Find the glyph under window-relative coordinates X/Y in window W.
+   Consider only glyphs from buffer text, i.e. no glyphs from overlay
+   strings.  Return in *HPOS and *VPOS the row and column number of
+   the glyph found.  Return in *AREA the glyph area containing X.
+   Value is a pointer to the glyph found or null if X/Y is not on
+   text, or we can't tell because W's current matrix is not up to
+   date.  */
+
+static struct glyph *
+x_y_to_hpos_vpos (w, x, y, hpos, vpos, area)
+     struct window *w;
+     int x, y;
+     int *hpos, *vpos, *area;
+{
+  struct glyph *glyph, *end;
+  struct glyph_row *row;
+  int x0, i, left_area_width;
+
+  /* Find row containing Y.  Give up if some row is not enabled.  */
+  for (i = 0; i < w->current_matrix->nrows; ++i)
+    {
+      row = MATRIX_ROW (w->current_matrix, i);
+      if (!row->enabled_p)
+       return NULL;
+      if (y >= row->y && y < MATRIX_ROW_BOTTOM_Y (row))
+       break;
+    }
+
+  *vpos = i;
+  *hpos = 0;
+
+  /* Give up if Y is not in the window.  */
+  if (i == w->current_matrix->nrows)
+    return NULL;
+
+  /* Get the glyph area containing X.  */
+  if (w->pseudo_window_p)
+    {
+      *area = TEXT_AREA;
+      x0 = 0;
+    }
+  else
+    {
+      left_area_width = window_box_width (w, LEFT_MARGIN_AREA);
+      if (x < left_area_width)
+       {
+         *area = LEFT_MARGIN_AREA;
+         x0 = 0;
+       }
+      else if (x < left_area_width + window_box_width (w, TEXT_AREA))
+       {
+         *area = TEXT_AREA;
+         x0 = row->x + left_area_width;
+       }
+      else
+       {
+         *area = RIGHT_MARGIN_AREA;
+         x0 = left_area_width + window_box_width (w, TEXT_AREA);
+       }
+    }
+
+  /* Find glyph containing X.  */
+  glyph = row->glyphs[*area];
+  end = glyph + row->used[*area];
+  while (glyph < end)
+    {
+      if (x < x0 + glyph->pixel_width)
+       {
+         if (w->pseudo_window_p)
+           break;
+         else if (BUFFERP (glyph->object))
+           break;
+       }
+      
+      x0 += glyph->pixel_width;
+      ++glyph;
+    }
+
+  if (glyph == end)
+    return NULL;
+
+  *hpos = glyph - row->glyphs[*area];
+  return glyph;
+}
+
+
+/* Convert frame-relative x/y to coordinates relative to window W.
+   Takes pseudo-windows into account.  */
+
+static void
+frame_to_window_pixel_xy (w, x, y)
+     struct window *w;
+     int *x, *y;
+{
+  if (w->pseudo_window_p)
+    {
+      /* A pseudo-window is always full-width, and starts at the
+        left edge of the frame, plus a frame border.  */
+      struct frame *f = XFRAME (w->frame);
+      *x -= FRAME_INTERNAL_BORDER_WIDTH_SAFE (f);
+      *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+    }
+  else
+    {
+      *x = FRAME_TO_WINDOW_PIXEL_X (w, *x);
+      *y = FRAME_TO_WINDOW_PIXEL_Y (w, *y);
+    }
+}
+
+
+/* Take proper action when mouse has moved to the mode or top line of
+   window W, x-position X.  MODE_LINE_P non-zero means mouse is on the
+   mode line.  X is relative to the start of the text display area of
+   W, so the width of bitmap areas and scroll bars must be subtracted
+   to get a position relative to the start of the mode line.  */
+
+static void
+note_mode_line_highlight (w, x, mode_line_p)
+     struct window *w;
+     int x, mode_line_p;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
+  struct glyph_row *row;
+
+  if (mode_line_p)
+    row = MATRIX_MODE_LINE_ROW (w->current_matrix);
+  else
+    row = MATRIX_HEADER_LINE_ROW (w->current_matrix);
+  
+  if (row->enabled_p)
+    {
+      struct glyph *glyph, *end;
+      Lisp_Object help, map;
+      int x0;
+      
+      /* Find the glyph under X.  */
+      glyph = row->glyphs[TEXT_AREA];
+      end = glyph + row->used[TEXT_AREA];
+      x0 = - (FRAME_LEFT_SCROLL_BAR_WIDTH (f) * CANON_X_UNIT (f)
+             + FRAME_X_LEFT_FLAGS_AREA_WIDTH (f));
+      while (glyph < end
+            && x >= x0 + glyph->pixel_width)
+       {
+         x0 += glyph->pixel_width;
+         ++glyph;
+       }
+
+      if (glyph < end
+         && STRINGP (glyph->object)
+         && XSTRING (glyph->object)->intervals
+         && glyph->charpos >= 0
+         && glyph->charpos < XSTRING (glyph->object)->size)
+       {
+         /* If we're on a string with `help-echo' text property,
+            arrange for the help to be displayed.  This is done by
+            setting the global variable help_echo to the help string.  */
+         help = Fget_text_property (make_number (glyph->charpos),
+                                    Qhelp_echo, glyph->object);
+         if (STRINGP (help))
+           help_echo = help;
+
+         /* Change the mouse pointer according to what is under X/Y.  */
+         map = Fget_text_property (make_number (glyph->charpos),
+                                   Qlocal_map, glyph->object);
+         if (!NILP (Fkeymapp (map)))
+           cursor = f->output_data.x->nontext_cursor;
+       }
+    }
+
+  XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), cursor);
+}
+
+
+/* Take proper action when the mouse has moved to position X, Y on
+   frame F as regards highlighting characters that have mouse-face
+   properties.  Also de-highlighting chars where the mouse was before.
    X and Y can be negative or out of range.  */
 
 static void
 note_mouse_highlight (f, x, y)
-     FRAME_PTR f;
+     struct frame *f;
      int x, y;
 {
-  int row, column, portion;
-  XRectangle new_glyph;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  int portion;
   Lisp_Object window;
   struct window *w;
 
+  /* When a menu is active, don't highlight because this looks odd.  */
+#ifdef USE_X_TOOLKIT
+  if (popup_activated ())
+    return;
+#endif
+
   if (disable_mouse_highlight)
     return;
 
-  FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_x = x;
-  FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_y = y;
-  FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame = f;
+  dpyinfo->mouse_face_mouse_x = x;
+  dpyinfo->mouse_face_mouse_y = y;
+  dpyinfo->mouse_face_mouse_frame = f;
 
-  if (FRAME_X_DISPLAY_INFO (f)->mouse_face_defer)
+  if (dpyinfo->mouse_face_defer)
     return;
 
   if (gc_in_progress)
     {
-      FRAME_X_DISPLAY_INFO (f)->mouse_face_deferred_gc = 1;
+      dpyinfo->mouse_face_deferred_gc = 1;
       return;
     }
 
-  /* Find out which glyph the mouse is on.  */
-  pixel_to_glyph_coords (f, x, y, &column, &row,
-                        &new_glyph, FRAME_X_DISPLAY_INFO (f)->grabbed);
-
   /* Which window is that in?  */
-  window = window_from_coordinates (f, column, row, &portion);
-  w = XWINDOW (window);
+  window = window_from_coordinates (f, x, y, &portion, 1);
 
   /* If we were displaying active text in another window, clear that.  */
-  if (! EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window))
-    clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
+  if (! EQ (window, dpyinfo->mouse_face_window))
+    clear_mouse_face (dpyinfo);
+
+  /* Not on a window -> return.  */
+  if (!WINDOWP (window))
+    return;
+
+  /* Convert to window-relative pixel coordinates.  */
+  w = XWINDOW (window);
+  frame_to_window_pixel_xy (w, &x, &y);
+
+  /* Handle tool-bar window differently since it doesn't display a
+     buffer.  */
+  if (EQ (window, f->tool_bar_window))
+    {
+      note_tool_bar_highlight (f, x, y);
+      return;
+    }
+
+  if (portion == 1 || portion == 3)
+    {
+      /* Mouse is on the mode or top line.  */
+      note_mode_line_highlight (w, x, portion == 1);
+      return;
+    }
+  else
+    XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                  f->output_data.x->text_cursor);
 
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
-  if (WINDOWP (window) && portion == 0 && row >= 0 && column >= 0
-      && row < FRAME_HEIGHT (f) && column < FRAME_WIDTH (f)
+  if (/* Within text portion of the window.  */
+      portion == 0
       && EQ (w->window_end_valid, w->buffer)
       && XFASTINT (w->last_modified) == BUF_MODIFF (XBUFFER (w->buffer))
       && (XFASTINT (w->last_overlay_modified)
          == BUF_OVERLAY_MODIFF (XBUFFER (w->buffer))))
     {
-      int *ptr = FRAME_CURRENT_GLYPHS (f)->charstarts[row];
-      int i, pos;
+      int hpos, vpos, pos, i, area;
+      struct glyph *glyph;
 
-      /* Find which buffer position the mouse corresponds to.  */
-      for (i = column; i >= 0; i--)
-       if (ptr[i] > 0)
-         break;
-      pos = ptr[i];
-      /* Is it outside the displayed active region (if any)?  */
-      if (pos <= 0)
-       clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
-      else if (! (EQ (window, FRAME_X_DISPLAY_INFO (f)->mouse_face_window)
-                 && row >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
-                 && row <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
-                 && (row > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
-                     || column >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col)
-                 && (row < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
-                     || column < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
-                     || FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end)))
+      /* Find the glyph under X/Y.  */
+      glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area);
+
+      /* Clear mouse face if X/Y not over text.  */
+      if (glyph == NULL
+         || area != TEXT_AREA
+         || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
        {
-         Lisp_Object mouse_face, overlay, position;
-         Lisp_Object *overlay_vec;
-         int len, noverlays, ignor1;
-         struct buffer *obuf;
-         int obegv, ozv;
-
-         /* If we get an out-of-range value, return now; avoid an error.  */
-         if (pos > BUF_Z (XBUFFER (w->buffer)))
-           return;
-
-         /* Make the window's buffer temporarily current for
-            overlays_at and compute_char_face.  */
-         obuf = current_buffer;
-         current_buffer = XBUFFER (w->buffer);
-         obegv = BEGV;
-         ozv = ZV;
-         BEGV = BEG;
-         ZV = Z;
-
-         /* Yes.  Clear the display of the old active region, if any.  */
-         clear_mouse_face (FRAME_X_DISPLAY_INFO (f));
-
-         /* Is this char mouse-active?  */
-         XSETINT (position, pos);
-
-         len = 10;
-         overlay_vec = (Lisp_Object *) xmalloc (len * sizeof (Lisp_Object));
-
-         /* Put all the overlays we want in a vector in overlay_vec.
-            Store the length in len.  */
-         noverlays = overlays_at (pos, 1, &overlay_vec, &len,
-                                  NULL, NULL);
-         noverlays = sort_overlays (overlay_vec, noverlays, w);
-
-         /* Find the highest priority overlay that has a mouse-face prop.  */
-         overlay = Qnil;
-         for (i = 0; i < noverlays; i++)
-           {
-             mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
-             if (!NILP (mouse_face))
-               {
-                 overlay = overlay_vec[i];
-                 break;
-               }
-           }
-         free (overlay_vec);
-         /* If no overlay applies, get a text property.  */
-         if (NILP (overlay))
-           mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
+         clear_mouse_face (dpyinfo);
+         return;
+       }
 
-         /* Handle the overlay case.  */
-         if (! NILP (overlay))
-           {
-             /* Find the range of text around this char that
-                should be active.  */
-             Lisp_Object before, after;
-             int ignore;
-
-             before = Foverlay_start (overlay);
-             after = Foverlay_end (overlay);
-             /* Record this as the current active region.  */
-             fast_find_position (window, XFASTINT (before),
-                                 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
-                                 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
-               = !fast_find_position (window, XFASTINT (after),
-                                      &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
-                                      &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
-               = compute_char_face (f, w, pos, 0, 0,
-                                    &ignore, pos + 1, 1);
-
-             /* Display it as active.  */
-             show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
-           }
-         /* Handle the text property case.  */
-         else if (! NILP (mouse_face))
-           {
-             /* Find the range of text around this char that
-                should be active.  */
-             Lisp_Object before, after, beginning, end;
-             int ignore;
-
-             beginning = Fmarker_position (w->start);
-             XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
-                            - XFASTINT (w->window_end_pos)));
-             before
-               = Fprevious_single_property_change (make_number (pos + 1),
-                                                   Qmouse_face,
-                                                   w->buffer, beginning);
-             after
-               = Fnext_single_property_change (position, Qmouse_face,
-                                               w->buffer, end);
-             /* Record this as the current active region.  */
-             fast_find_position (window, XFASTINT (before),
-                                 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col,
-                                 &FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row);
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_past_end
-               = !fast_find_position (window, XFASTINT (after),
-                                      &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col,
-                                      &FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row);
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_window = window;
-             FRAME_X_DISPLAY_INFO (f)->mouse_face_face_id
-               = compute_char_face (f, w, pos, 0, 0,
-                                    &ignore, pos + 1, 1);
-
-             /* Display it as active.  */
-             show_mouse_face (FRAME_X_DISPLAY_INFO (f), 1);
-           }
-         BEGV = obegv;
-         ZV = ozv;
-         current_buffer = obuf;
+      pos = glyph->charpos;
+      xassert (w->pseudo_window_p || BUFFERP (glyph->object));
+
+      /* Check for mouse-face and help-echo.  */
+      {
+       Lisp_Object mouse_face, overlay, position;
+       Lisp_Object *overlay_vec;
+       int len, noverlays;
+       struct buffer *obuf;
+       int obegv, ozv;
+
+       /* If we get an out-of-range value, return now; avoid an error.  */
+       if (pos > BUF_Z (XBUFFER (w->buffer)))
+         return;
+
+       /* Make the window's buffer temporarily current for
+          overlays_at and compute_char_face.  */
+       obuf = current_buffer;
+       current_buffer = XBUFFER (w->buffer);
+       obegv = BEGV;
+       ozv = ZV;
+       BEGV = BEG;
+       ZV = Z;
+
+       /* Is this char mouse-active or does it have help-echo?  */
+       XSETINT (position, pos);
+
+       /* Put all the overlays we want in a vector in overlay_vec.
+          Store the length in len.  If there are more than 10, make
+          enough space for all, and try again.  */
+       len = 10;
+       overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+       noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
+       if (noverlays > len)
+         {
+           len = noverlays;
+           overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
+           noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL);
+         }
+         
+       noverlays = sort_overlays (overlay_vec, noverlays, w);
+
+       /* Check mouse-face highlighting.  */
+       if (! (EQ (window, dpyinfo->mouse_face_window)
+              && vpos >= dpyinfo->mouse_face_beg_row
+              && vpos <= dpyinfo->mouse_face_end_row
+              && (vpos > dpyinfo->mouse_face_beg_row
+                  || hpos >= dpyinfo->mouse_face_beg_col)
+              && (vpos < dpyinfo->mouse_face_end_row
+                  || hpos < dpyinfo->mouse_face_end_col
+                  || dpyinfo->mouse_face_past_end)))
+         {
+           /* Clear the display of the old active region, if any.  */
+           clear_mouse_face (dpyinfo);
+
+           /* Find the highest priority overlay that has a mouse-face prop.  */
+           overlay = Qnil;
+           for (i = 0; i < noverlays; i++)
+             {
+               mouse_face = Foverlay_get (overlay_vec[i], Qmouse_face);
+               if (!NILP (mouse_face))
+                 {
+                   overlay = overlay_vec[i];
+                   break;
+                 }
+             }
+
+           /* If no overlay applies, get a text property.  */
+           if (NILP (overlay))
+             mouse_face = Fget_text_property (position, Qmouse_face, w->buffer);
+
+           /* Handle the overlay case.  */
+           if (! NILP (overlay))
+             {
+               /* Find the range of text around this char that
+                  should be active.  */
+               Lisp_Object before, after;
+               int ignore;
+
+               before = Foverlay_start (overlay);
+               after = Foverlay_end (overlay);
+               /* Record this as the current active region.  */
+               fast_find_position (w, XFASTINT (before),
+                                   &dpyinfo->mouse_face_beg_col,
+                                   &dpyinfo->mouse_face_beg_row,
+                                   &dpyinfo->mouse_face_beg_x,
+                                   &dpyinfo->mouse_face_beg_y);
+               dpyinfo->mouse_face_past_end
+                 = !fast_find_position (w, XFASTINT (after),
+                                        &dpyinfo->mouse_face_end_col,
+                                        &dpyinfo->mouse_face_end_row,
+                                        &dpyinfo->mouse_face_end_x,
+                                        &dpyinfo->mouse_face_end_y);
+               dpyinfo->mouse_face_window = window;
+               dpyinfo->mouse_face_face_id
+                 = face_at_buffer_position (w, pos, 0, 0,
+                                            &ignore, pos + 1, 1);
+
+               /* Display it as active.  */
+               show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             }
+           /* Handle the text property case.  */
+           else if (! NILP (mouse_face))
+             {
+               /* Find the range of text around this char that
+                  should be active.  */
+               Lisp_Object before, after, beginning, end;
+               int ignore;
+
+               beginning = Fmarker_position (w->start);
+               XSETINT (end, (BUF_Z (XBUFFER (w->buffer))
+                              - XFASTINT (w->window_end_pos)));
+               before
+                 = Fprevious_single_property_change (make_number (pos + 1),
+                                                     Qmouse_face,
+                                                     w->buffer, beginning);
+               after
+                 = Fnext_single_property_change (position, Qmouse_face,
+                                                 w->buffer, end);
+               /* Record this as the current active region.  */
+               fast_find_position (w, XFASTINT (before),
+                                   &dpyinfo->mouse_face_beg_col,
+                                   &dpyinfo->mouse_face_beg_row,
+                                   &dpyinfo->mouse_face_beg_x,
+                                   &dpyinfo->mouse_face_beg_y);
+               dpyinfo->mouse_face_past_end
+                 = !fast_find_position (w, XFASTINT (after),
+                                        &dpyinfo->mouse_face_end_col,
+                                        &dpyinfo->mouse_face_end_row,
+                                        &dpyinfo->mouse_face_end_x,
+                                        &dpyinfo->mouse_face_end_y);
+               dpyinfo->mouse_face_window = window;
+               dpyinfo->mouse_face_face_id
+                 = face_at_buffer_position (w, pos, 0, 0,
+                                            &ignore, pos + 1, 1);
+
+               /* Display it as active.  */
+               show_mouse_face (dpyinfo, DRAW_MOUSE_FACE);
+             }
+         }
+
+       /* Look for a `help-echo' property.  */
+       {
+         Lisp_Object help;
+
+         /* Check overlays first.  */
+         help = Qnil;
+         for (i = 0; i < noverlays && !STRINGP (help); ++i)
+           help = Foverlay_get (overlay_vec[i], Qhelp_echo); 
+           
+         /* Try text properties.  */
+         if (!STRINGP (help)
+             && ((STRINGP (glyph->object)
+                  && glyph->charpos >= 0
+                  && glyph->charpos < XSTRING (glyph->object)->size)
+                 || (BUFFERP (glyph->object)
+                     && glyph->charpos >= BEGV
+                     && glyph->charpos < ZV)))
+           help = Fget_text_property (make_number (glyph->charpos),
+                                      Qhelp_echo, glyph->object);
+           
+         if (STRINGP (help))
+           help_echo = help;
        }
+         
+       BEGV = obegv;
+       ZV = ozv;
+       current_buffer = obuf;
+      }
     }
 }
+
+static void
+redo_mouse_highlight ()
+{
+  if (!NILP (last_mouse_motion_frame)
+      && FRAME_LIVE_P (XFRAME (last_mouse_motion_frame)))
+    note_mouse_highlight (XFRAME (last_mouse_motion_frame),
+                         last_mouse_motion_event.x,
+                         last_mouse_motion_event.y);
+}
+
+
 \f
-/* Find the row and column of position POS in window WINDOW.
-   Store them in *COLUMNP and *ROWP.
-   This assumes display in WINDOW is up to date.
-   If POS is above start of WINDOW, return coords
-   of start of first screen line.
-   If POS is after end of WINDOW, return coords of end of last screen line.
+/***********************************************************************
+                              Tool-bars
+ ***********************************************************************/
+
+static int x_tool_bar_item P_ ((struct frame *, int, int,
+                               struct glyph **, int *, int *, int *));
+
+/* Tool-bar item index of the item on which a mouse button was pressed
+   or -1.  */
+
+static int last_tool_bar_item;
+
+
+/* Get information about the tool-bar item at position X/Y on frame F.
+   Return in *GLYPH a pointer to the glyph of the tool-bar item in
+   the current matrix of the tool-bar window of F, or NULL if not
+   on a tool-bar item.  Return in *PROP_IDX the index of the tool-bar
+   item in F->current_tool_bar_items.  Value is
 
-   Value is 1 if POS is in range, 0 if it was off screen.  */
+   -1  if X/Y is not on a tool-bar item
+   0   if X/Y is on the same item that was highlighted before.
+   1   otherwise.  */
 
 static int
-fast_find_position (window, pos, columnp, rowp)
-     Lisp_Object window;
-     int pos;
-     int *columnp, *rowp;
+x_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
+     struct frame *f;
+     int x, y;
+     struct glyph **glyph;
+     int *hpos, *vpos, *prop_idx;
+{
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  struct window *w = XWINDOW (f->tool_bar_window);
+  int area;
+
+  /* Find the glyph under X/Y.  */
+  *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area);
+  if (*glyph == NULL)
+    return -1;
+
+  /* Get the start of this tool-bar item's properties in
+     f->current_tool_bar_items.  */
+  if (!tool_bar_item_info (f, *glyph, prop_idx))
+    return -1;
+
+  /* Is mouse on the highlighted item?  */
+  if (EQ (f->tool_bar_window, dpyinfo->mouse_face_window)
+      && *vpos >= dpyinfo->mouse_face_beg_row
+      && *vpos <= dpyinfo->mouse_face_end_row
+      && (*vpos > dpyinfo->mouse_face_beg_row
+         || *hpos >= dpyinfo->mouse_face_beg_col)
+      && (*vpos < dpyinfo->mouse_face_end_row
+         || *hpos < dpyinfo->mouse_face_end_col
+         || dpyinfo->mouse_face_past_end))
+    return 0;
+  
+  return 1;
+}
+
+
+/* Handle mouse button event on the tool-bar of frame F, at
+   frame-relative coordinates X/Y.  EVENT_TYPE is either ButtionPress
+   or ButtonRelase.  */
+
+static void
+x_handle_tool_bar_click (f, button_event)
+     struct frame *f;
+     XButtonEvent *button_event;
+{
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  struct window *w = XWINDOW (f->tool_bar_window);
+  int hpos, vpos, prop_idx;
+  struct glyph *glyph;
+  Lisp_Object enabled_p;
+  int x = button_event->x;
+  int y = button_event->y;
+  
+  /* If not on the highlighted tool-bar item, return.  */
+  frame_to_window_pixel_xy (w, &x, &y);
+  if (x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
+    return;
+
+  /* If item is disabled, do nothing.  */
+  enabled_p = (XVECTOR (f->current_tool_bar_items)
+              ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
+  if (NILP (enabled_p))
+    return;
+  
+  if (button_event->type == ButtonPress)
+    {
+      /* Show item in pressed state.  */
+      show_mouse_face (dpyinfo, DRAW_IMAGE_SUNKEN);
+      dpyinfo->mouse_face_image_state = DRAW_IMAGE_SUNKEN;
+      last_tool_bar_item = prop_idx;
+    }
+  else
+    {
+      Lisp_Object key, frame;
+      struct input_event event;
+
+      /* Show item in released state.  */
+      show_mouse_face (dpyinfo, DRAW_IMAGE_RAISED);
+      dpyinfo->mouse_face_image_state = DRAW_IMAGE_RAISED;
+
+      key = (XVECTOR (f->current_tool_bar_items)
+            ->contents[prop_idx + TOOL_BAR_ITEM_KEY]);
+
+      XSETFRAME (frame, f);
+      event.kind = TOOL_BAR_EVENT;
+      event.frame_or_window = Fcons (frame, Fcons (Qtool_bar, Qnil));
+      kbd_buffer_store_event (&event);
+
+      event.kind = TOOL_BAR_EVENT;
+      event.frame_or_window = Fcons (frame, key);
+      event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
+                                               button_event->state);
+      kbd_buffer_store_event (&event);
+      last_tool_bar_item = -1;
+    }
+}
+
+
+/* Possibly highlight a tool-bar item on frame F when mouse moves to
+   tool-bar window-relative coordinates X/Y.  Called from
+   note_mouse_highlight.  */
+
+static void
+note_tool_bar_highlight (f, x, y)
+     struct frame *f;
+     int x, y;
 {
+  Lisp_Object window = f->tool_bar_window;
   struct window *w = XWINDOW (window);
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  int hpos, vpos;
+  struct glyph *glyph;
+  struct glyph_row *row;
+  int i, j, area;
+  Lisp_Object enabled_p;
+  int prop_idx;
+  enum draw_glyphs_face draw = DRAW_IMAGE_RAISED;
+  int on_highlight_p, mouse_down_p, rc;
+
+  /* Function note_mouse_highlight is called with negative x(y
+     values when mouse moves outside of the frame.  */
+  if (x <= 0 || y <= 0)
+    {
+      clear_mouse_face (dpyinfo);
+      return;
+    }
+
+  rc = x_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
+  if (rc < 0)
+    {
+      /* Not on tool-bar item.  */
+      clear_mouse_face (dpyinfo);
+      return;
+    }
+  else if (rc == 0)
+    /* On same tool-bar item as before.  */
+    goto set_help_echo;
+
+  clear_mouse_face (dpyinfo);
+  
+  /* Mouse is down, but on different tool-bar item?  */
+  mouse_down_p = (dpyinfo->grabbed
+                 && f == last_mouse_frame
+                 && FRAME_LIVE_P (f));
+  if (mouse_down_p
+      && last_tool_bar_item != prop_idx)
+    return;
+
+  dpyinfo->mouse_face_image_state = DRAW_NORMAL_TEXT;
+  draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
+  
+  /* If tool-bar item is not enabled, don't highlight it.  */
+  enabled_p = (XVECTOR (f->current_tool_bar_items)
+              ->contents[prop_idx + TOOL_BAR_ITEM_ENABLED_P]);
+  if (!NILP (enabled_p))
+    {
+      /* Compute the x-position of the glyph.  In front and past the
+        image is a space.  We include this is the highlighted area.  */
+      row = MATRIX_ROW (w->current_matrix, vpos);
+      for (i = x = 0; i < hpos; ++i)
+       x += row->glyphs[TEXT_AREA][i].pixel_width;
+      
+      /* Record this as the current active region.  */
+      dpyinfo->mouse_face_beg_col = hpos;
+      dpyinfo->mouse_face_beg_row = vpos;
+      dpyinfo->mouse_face_beg_x = x;
+      dpyinfo->mouse_face_beg_y = row->y;
+      dpyinfo->mouse_face_past_end = 0;
+      
+      dpyinfo->mouse_face_end_col = hpos + 1;
+      dpyinfo->mouse_face_end_row = vpos;
+      dpyinfo->mouse_face_end_x = x + glyph->pixel_width;
+      dpyinfo->mouse_face_end_y = row->y;
+      dpyinfo->mouse_face_window = window;
+      dpyinfo->mouse_face_face_id = TOOL_BAR_FACE_ID;
+      
+      /* Display it as active.  */
+      show_mouse_face (dpyinfo, draw);
+      dpyinfo->mouse_face_image_state = draw;
+    }
+      
+ set_help_echo:
+  
+  /* Set help_echo to a help string.to display for this tool-bar item.
+     XTread_socket does the rest.  */
+  help_echo = (XVECTOR (f->current_tool_bar_items)
+              ->contents[prop_idx + TOOL_BAR_ITEM_HELP]);
+  if (!STRINGP (help_echo))
+    help_echo = (XVECTOR (f->current_tool_bar_items)
+                ->contents[prop_idx + TOOL_BAR_ITEM_CAPTION]);
+}
+
+
+\f
+/* Find the glyph matrix position of buffer position POS in window W.
+   *HPOS, *VPOS, *X, and *Y are set to the positions found.  W's
+   current glyphs must be up to date.  If POS is above window start
+   return (0, 0, 0, 0).  If POS is after end of W, return end of
+   last line in W.  */
+
+static int
+fast_find_position (w, pos, hpos, vpos, x, y)
+     struct window *w;
+     int pos;
+     int *hpos, *vpos, *x, *y;
+{
   int i;
-  int row = 0;
-  int left = WINDOW_LEFT_MARGIN (w);
-  int top = XFASTINT (w->top);
-  int height = XFASTINT (w->height) - ! MINI_WINDOW_P (w);
-  int width = window_internal_width (w);
-  int *charstarts;
   int lastcol;
-  int maybe_next_line = 0;
-
-  /* Find the right row.  */
-  for (i = 0;
-       i < height;
-       i++)
+  int maybe_next_line_p = 0;
+  int line_start_position;
+  int yb = window_text_bottom_y (w);
+  struct glyph_row *row = MATRIX_ROW (w->current_matrix, 0);
+  struct glyph_row *best_row = row;
+  int row_vpos = 0, best_row_vpos = 0;
+  int current_x;
+
+  while (row->y < yb)
     {
-      int linestart = FRAME_CURRENT_GLYPHS (f)->charstarts[top + i][left];
-      if (linestart > pos)
+      if (row->used[TEXT_AREA])
+       line_start_position = row->glyphs[TEXT_AREA]->charpos;
+      else
+       line_start_position = 0;
+
+      if (line_start_position > pos)
        break;
       /* If the position sought is the end of the buffer,
         don't include the blank lines at the bottom of the window.  */
-      if (linestart == pos && pos == BUF_ZV (XBUFFER (w->buffer)))
+      else if (line_start_position == pos
+              && pos == BUF_ZV (XBUFFER (w->buffer)))
        {
-         maybe_next_line = 1;
+         maybe_next_line_p = 1;
          break;
        }
-      if (linestart > 0)
-       row = i;
+      else if (line_start_position > 0)
+       {
+         best_row = row;
+         best_row_vpos = row_vpos;
+       }
+      
+      ++row;
+      ++row_vpos;
     }
-
-  /* Find the right column with in it.  */
-  charstarts = FRAME_CURRENT_GLYPHS (f)->charstarts[top + row];
-  lastcol = left;
-  for (i = 0; i < width; i++)
+  
+  /* Find the right column within BEST_ROW.  */
+  lastcol = 0;
+  current_x = best_row->x;
+  for (i = 0; i < best_row->used[TEXT_AREA]; i++)
     {
-      if (charstarts[left + i] == pos)
+      struct glyph *glyph = best_row->glyphs[TEXT_AREA] + i;
+      int charpos;
+
+      charpos = glyph->charpos;
+      if (charpos == pos)
        {
-         *rowp = row + top;
-         *columnp = i + left;
+         *hpos = i;
+         *vpos = best_row_vpos;
+         *x = current_x;
+         *y = best_row->y;
          return 1;
        }
-      else if (charstarts[left + i] > pos)
+      else if (charpos > pos)
        break;
-      else if (charstarts[left + i] > 0)
-       lastcol = left + i;
+      else if (charpos > 0)
+       lastcol = i;
+
+      current_x += glyph->pixel_width;
     }
 
   /* If we're looking for the end of the buffer,
      and we didn't find it in the line we scanned,
      use the start of the following line.  */
-  if (maybe_next_line)
+  if (maybe_next_line_p)
     {
-      row++;
-      lastcol = left;
+      ++best_row;
+      ++best_row_vpos;
+      lastcol = 0;
+      current_x = best_row->x;
     }
 
-  *rowp = row + top;
-  *columnp = lastcol;
+  *vpos = best_row_vpos;
+  *hpos = lastcol + 1;
+  *x = current_x;
+  *y = best_row->y;
   return 0;
 }
 
+
 /* Display the active region described by mouse_face_*
    in its mouse-face if HL > 0, in its normal face if HL = 0.  */
 
 static void
-show_mouse_face (dpyinfo, hl)
+show_mouse_face (dpyinfo, draw)
      struct x_display_info *dpyinfo;
-     int hl;
+     enum draw_glyphs_face draw;
 {
   struct window *w = XWINDOW (dpyinfo->mouse_face_window);
-  int width = window_internal_width (w);
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
   int i;
-  int cursor_off = 0;
-  int old_curs_x = curs_x;
-  int old_curs_y = curs_y;
-
-  /* Set these variables temporarily
-     so that if we have to turn the cursor off and on again
-     we will put it back at the same place.  */
-  curs_x = f->phys_cursor_x;
-  curs_y = f->phys_cursor_y;  
-  for (i = FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row;
-       i <= FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row; i++)
-    {
-      int column = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
-                   ? FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col
-                   : WINDOW_LEFT_MARGIN (w));
-      int endcolumn = (i == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
-                      ? FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col
-                      : WINDOW_LEFT_MARGIN (w) + width);
-      endcolumn = min (endcolumn, FRAME_CURRENT_GLYPHS (f)->used[i]);
-
-      /* If the cursor's in the text we are about to rewrite,
-        turn the cursor off.  */
-      if (i == curs_y
-         && curs_x >= column - 1
-         && curs_x <= endcolumn)
+  int cursor_off_p = 0;
+  struct cursor_pos saved_cursor;
+
+  saved_cursor = output_cursor;
+  
+  /* If window is in the process of being destroyed, don't bother
+     to do anything.  */
+  if (w->current_matrix == NULL)
+    goto set_x_cursor;
+
+  /* Recognize when we are called to operate on rows that don't exist
+     anymore.  This can happen when a window is split.  */
+  if (dpyinfo->mouse_face_end_row >= w->current_matrix->nrows)
+    goto set_x_cursor;
+
+  set_output_cursor (&w->phys_cursor);
+
+  /* Note that mouse_face_beg_row etc. are window relative.  */
+  for (i = dpyinfo->mouse_face_beg_row;
+       i <= dpyinfo->mouse_face_end_row;
+       i++)
+    {
+      int start_hpos, end_hpos, start_x;
+      struct glyph_row *row = MATRIX_ROW (w->current_matrix, i);
+
+      /* Don't do anything if row doesn't have valid contents.  */
+      if (!row->enabled_p)
+       continue;
+
+      /* For all but the first row, the highlight starts at column 0.  */
+      if (i == dpyinfo->mouse_face_beg_row)
+       {
+         start_hpos = dpyinfo->mouse_face_beg_col;
+         start_x = dpyinfo->mouse_face_beg_x;
+       }
+      else
        {
-         x_update_cursor (f, 0);
-         cursor_off = 1;
+         start_hpos = 0;
+         start_x = 0;
        }
 
-      dumpglyphs (f,
-                 CHAR_TO_PIXEL_COL (f, column),
-                 CHAR_TO_PIXEL_ROW (f, i),
-                 FRAME_CURRENT_GLYPHS (f)->glyphs[i] + column,
-                 endcolumn - column,
-                 /* Highlight with mouse face if hl > 0.  */
-                 hl > 0 ? 3 : 0, 0, NULL);
+      if (i == dpyinfo->mouse_face_end_row)
+       end_hpos = dpyinfo->mouse_face_end_col;
+      else
+       end_hpos = row->used[TEXT_AREA];
+
+      /* If the cursor's in the text we are about to rewrite, turn the
+        cursor off.  */
+      if (!w->pseudo_window_p
+         && i == output_cursor.vpos
+         && output_cursor.hpos >= start_hpos - 1
+         && output_cursor.hpos <= end_hpos)
+       {
+         x_update_window_cursor (w, 0);
+         cursor_off_p = 1;
+       }
+
+      if (end_hpos > start_hpos)
+       x_draw_glyphs (w, start_x, row, updated_area, 
+                      start_hpos, end_hpos, draw, NULL, NULL, 0);
     }
 
   /* If we turned the cursor off, turn it back on.  */
-  if (cursor_off)
-    x_display_cursor (f, 1, curs_x, curs_y);
+  if (cursor_off_p)
+    x_display_cursor (w, 1,
+                     output_cursor.hpos, output_cursor.vpos,
+                     output_cursor.x, output_cursor.y);
 
-  curs_x = old_curs_x;
-  curs_y = old_curs_y;
+  output_cursor = saved_cursor;
 
-  /* Change the mouse cursor according to the value of HL.  */
-  if (hl > 0)
+ set_x_cursor:
+  
+  /* Change the mouse cursor.  */
+  if (draw == DRAW_NORMAL_TEXT)
+    XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                  f->output_data.x->text_cursor);
+  else if (draw == DRAW_MOUSE_FACE)
     XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                   f->output_data.x->cross_cursor);
   else
     XDefineCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                  f->output_data.x->text_cursor);
+                  f->output_data.x->nontext_cursor);
 }
 
 /* Clear out the mouse-highlighted active region.
-   Redraw it unhighlighted first.  */
+   Redraw it un-highlighted first.  */
 
-static void
+void
 clear_mouse_face (dpyinfo)
      struct x_display_info *dpyinfo;
 {
+  if (tip_frame)
+    return;
+  
   if (! NILP (dpyinfo->mouse_face_window))
-    show_mouse_face (dpyinfo, 0);
+    show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
 
   dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
   dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
@@ -2637,6 +6797,7 @@ clear_mouse_face (dpyinfo)
 /* Just discard the mouse face information for frame F, if any.
    This is used when the size of F is changed.  */
 
+void
 cancel_mouse_face (f)
      FRAME_PTR f;
 {
@@ -2667,7 +6828,7 @@ static void x_scroll_bar_report_motion ();
    mouse is on, *bar_window to nil, and *x and *y to the character cell
    the mouse is over.
 
-   Set *time to the server timestamp for the time at which the mouse
+   Set *time to the server time-stamp for the time at which the mouse
    was at this position.
 
    Don't store anything if we don't have a valid set of values to report.
@@ -2688,7 +6849,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time)
 
   BLOCK_INPUT;
 
-  if (! NILP (last_mouse_scroll_bar))
+  if (! NILP (last_mouse_scroll_bar) && insist == 0)
     x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
   else
     {
@@ -2733,7 +6894,7 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time)
       {
        Window win, child;
        int win_x, win_y;
-       int parent_x, parent_y;
+       int parent_x = 0, parent_y = 0;
        int count;
 
        win = root;
@@ -2817,19 +6978,45 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time)
              }
          }
 
-       if (f1 == 0 && insist)
+       if (f1 == 0 && insist > 0)
          f1 = selected_frame;
 
        if (f1)
          {
+           /* Ok, we found a frame.  Store all the values.
+              last_mouse_glyph is a rectangle used to reduce the
+              generation of mouse events.  To not miss any motion
+              events, we must divide the frame into rectangles of the
+              size of the smallest character that could be displayed
+              on it, i.e. into the same rectangles that matrices on
+              the frame are divided into.  */
+
+#if OLD_REDISPLAY_CODE
            int ignore1, ignore2;
-
-           /* Ok, we found a frame.  Store all the values.  */
-
            pixel_to_glyph_coords (f1, win_x, win_y, &ignore1, &ignore2,
                                   &last_mouse_glyph,
                                   FRAME_X_DISPLAY_INFO (f1)->grabbed
                                   || insist);
+#else
+           {
+             int width = FRAME_SMALLEST_CHAR_WIDTH (f1);
+             int height = FRAME_SMALLEST_FONT_HEIGHT (f1);
+             int x = win_x;
+             int y = win_y;
+             
+             /* Arrange for the division in PIXEL_TO_CHAR_COL etc. to
+                round down even for negative values.  */
+             if (x < 0)
+               x -= width - 1;
+             if (y < 0)
+               y -= height - 1;
+             
+             last_mouse_glyph.width  = width;
+             last_mouse_glyph.height = height;
+             last_mouse_glyph.x = (x + width - 1) / width * width;
+             last_mouse_glyph.y = (y + height - 1) / height * height;
+           }
+#endif
 
            *bar_window = Qnil;
            *part = 0;
@@ -2843,6 +7030,24 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time)
 
   UNBLOCK_INPUT;
 }
+
+
+DEFUN ("xt-process-timeouts", Fxt_process_timeouts, Sxt_process_timeouts,
+       0, 0, 0,
+  "Arrange for Xt timeout callbacks to be called.")
+  ()
+{
+#ifdef USE_X_TOOLKIT
+  BLOCK_INPUT;
+  while (XtAppPending (Xt_app_con) & XtIMTimer)
+    XtAppProcessEvent (Xt_app_con, XtIMTimer);
+  UNBLOCK_INPUT;
+#endif /* USE_X_TOOLKIT */
+  
+  return Qnil;
+}
+
+
 \f
 /* Scroll bar support.  */
 
@@ -2853,15 +7058,15 @@ static struct scroll_bar *
 x_window_to_scroll_bar (window_id)
      Window window_id;
 {
-  Lisp_Object tail, frame;
+  Lisp_Object tail;
 
   for (tail = Vframe_list;
        XGCTYPE (tail) == Lisp_Cons;
-       tail = XCONS (tail)->cdr)
+       tail = XCDR (tail))
     {
       Lisp_Object frame, bar, condemned;
 
-      frame = XCONS (tail)->car;
+      frame = XCAR (tail);
       /* All elements of Vframe_list should be frames.  */
       if (! GC_FRAMEP (frame))
        abort ();
@@ -2883,23 +7088,626 @@ x_window_to_scroll_bar (window_id)
   return 0;
 }
 
-/* Open a new X window to serve as a scroll bar, and return the
-   scroll bar vector for it.  */
+
+\f
+/************************************************************************
+                        Toolkit scroll bars
+ ************************************************************************/
+
+#if USE_TOOLKIT_SCROLL_BARS
+
+static void x_scroll_bar_to_input_event P_ ((XEvent *, struct input_event *));
+static void x_send_scroll_bar_event P_ ((Lisp_Object, int, int, int));
+static void x_create_toolkit_scroll_bar P_ ((struct frame *,
+                                            struct scroll_bar *));
+static void x_set_toolkit_scroll_bar_thumb P_ ((struct scroll_bar *,
+                                               int, int, int));
+
+
+/* Id of action hook installed for scroll bars.  */
+
+static XtActionHookId action_hook_id;
+
+/* Lisp window being scrolled.  Set when starting to interact with
+   a toolkit scroll bar, reset to nil when ending the interaction.  */
+
+static Lisp_Object window_being_scrolled;
+
+/* Last scroll bar part sent in xm_scroll_callback.  */
+
+static int last_scroll_bar_part;
+
+
+/* Action hook installed via XtAppAddActionHook when toolkit scroll
+   bars are used..  The hoos is responsible for detecting when
+   the user ends an interaction with the scroll bar, and generates
+   a `end-scroll' scroll_bar_click' event if so.  */
+
+static void
+xt_action_hook (widget, client_data, action_name, event, params,
+               num_params)
+     Widget widget;
+     XtPointer client_data;
+     String action_name;
+     XEvent *event;
+     String *params;
+     Cardinal *num_params;
+{
+  int scroll_bar_p;
+  char *end_action;
+  
+#ifdef USE_MOTIF
+  scroll_bar_p = XmIsScrollBar (widget);
+  end_action = "Release";
+#elif defined HAVE_XAW3D
+  scroll_bar_p = XtIsSubclass (widget, scrollbarWidgetClass);
+  end_action = "EndScroll";
+#else
+#error unknown scroll bar toolkit
+#endif /* HAVE_XAW3D */
+
+  /* Although LessTif uses XtTimeouts like Xaw3d, the timer hack to
+     let Xt timeouts be processed doesn't work.  */
+  if (scroll_bar_p
+      && strcmp (action_name, end_action) == 0
+      && WINDOWP (window_being_scrolled))
+    {
+      struct window *w;
+      
+      x_send_scroll_bar_event (window_being_scrolled,
+                              scroll_bar_end_scroll, 0, 0);
+      w = XWINDOW (window_being_scrolled);
+      XSCROLL_BAR (w->vertical_scroll_bar)->dragging = Qnil;
+      window_being_scrolled = Qnil;
+      last_scroll_bar_part = -1;
+    }
+}
+
+
+/* Send a client message with message type Xatom_Scrollbar for a
+   scroll action to the frame of WINDOW.  PART is a value identifying
+   the part of the scroll bar that was clicked on.  PORTION is the
+   amount to scroll of a whole of WHOLE.  */
+
+static void
+x_send_scroll_bar_event (window, part, portion, whole)
+     Lisp_Object window;
+     int part, portion, whole;
+{
+  XEvent event;
+  XClientMessageEvent *ev = (XClientMessageEvent *) &event;
+  struct frame *f = XFRAME (XWINDOW (window)->frame);
+
+  /* Construct a ClientMessage event to send to the frame.  */
+  ev->type = ClientMessage;
+  ev->message_type = FRAME_X_DISPLAY_INFO (f)->Xatom_Scrollbar;
+  ev->display = FRAME_X_DISPLAY (f);
+  ev->window = FRAME_X_WINDOW (f);
+  ev->format = 32;
+  ev->data.l[0] = (long) window;
+  ev->data.l[1] = (long) part;
+  ev->data.l[2] = (long) 0;
+  ev->data.l[3] = (long) portion;
+  ev->data.l[4] = (long) whole;
+
+  /* Setting the event mask to zero means that the message will
+     be sent to the client that created the window, and if that
+     window no longer exists, no event will be sent.  */
+  BLOCK_INPUT;
+  XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event);
+  UNBLOCK_INPUT;
+}
+
+
+/* Transform a scroll bar ClientMessage EVENT to an Emacs input event
+   in *IEVENT.  */
+
+static void
+x_scroll_bar_to_input_event (event, ievent)
+     XEvent *event;
+     struct input_event *ievent;
+{
+  XClientMessageEvent *ev = (XClientMessageEvent *) event;
+  Lisp_Object window = (Lisp_Object) ev->data.l[0];
+  struct frame *f = XFRAME (XWINDOW (window)->frame);
+  
+  ievent->kind = scroll_bar_click;
+  ievent->frame_or_window = window;
+  ievent->timestamp = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
+  ievent->part = ev->data.l[1];
+  ievent->code = ev->data.l[2];
+  ievent->x = make_number ((int) ev->data.l[3]);
+  ievent->y = make_number ((int) ev->data.l[4]);
+  ievent->modifiers = 0;
+}
+
+
+#ifdef USE_MOTIF
+
+/* Minimum and maximum values used for Motif scroll bars.  */
+
+#define XM_SB_MIN 1
+#define XM_SB_MAX 10000000
+#define XM_SB_RANGE (XM_SB_MAX - XM_SB_MIN)
+
+
+/* Scroll bar callback for Motif scroll bars.  WIDGET is the scroll
+   bar widget.  CLIENT_DATA is a pointer to the scroll_bar structure.
+   CALL_DATA is a pointer a a XmScrollBarCallbackStruct.  */
+
+static void
+xm_scroll_callback (widget, client_data, call_data)
+     Widget widget;
+     XtPointer client_data, call_data;
+{
+  struct scroll_bar *bar = (struct scroll_bar *) client_data;
+  XmScrollBarCallbackStruct *cs = (XmScrollBarCallbackStruct *) call_data;
+  double percent;
+  int part = -1, whole = 0, portion = 0;
+
+  switch (cs->reason)
+    {
+    case XmCR_DECREMENT:
+      bar->dragging = Qnil;
+      part = scroll_bar_up_arrow;
+      break;
+
+    case XmCR_INCREMENT:
+      bar->dragging = Qnil;
+      part = scroll_bar_down_arrow;
+      break;
+
+    case XmCR_PAGE_DECREMENT:
+      bar->dragging = Qnil;
+      part = scroll_bar_above_handle;
+      break;
+
+    case XmCR_PAGE_INCREMENT:
+      bar->dragging = Qnil;
+      part = scroll_bar_below_handle;
+      break;
+
+    case XmCR_TO_TOP:
+      bar->dragging = Qnil;
+      part = scroll_bar_to_top;
+      break;
+      
+    case XmCR_TO_BOTTOM:
+      bar->dragging = Qnil;
+      part = scroll_bar_to_bottom;
+      break;
+
+    case XmCR_DRAG:
+      {
+       int slider_size;
+       int dragging_down_p = (INTEGERP (bar->dragging)
+                              && XINT (bar->dragging) <= cs->value);
+
+       /* Get the slider size.  */
+       BLOCK_INPUT;
+       XtVaGetValues (widget, XmNsliderSize, &slider_size, NULL);
+       UNBLOCK_INPUT;
+
+       /* At the max position of the scroll bar, do a line-wise
+          movement.  Without doing anything, the LessTif scroll bar
+          calls us with the same cs->value again and again.  If we
+          want to make sure that we can reach the end of the buffer,
+          we have to do something.
+
+          Implementation note: setting bar->dragging always to
+          cs->value gives a smoother movement at the max position.
+          Setting it to nil when doing line-wise movement gives
+          a better slider behavior. */
+       
+       if (cs->value + slider_size == XM_SB_MAX
+           || (dragging_down_p
+               && last_scroll_bar_part == scroll_bar_down_arrow))
+         {
+           part = scroll_bar_down_arrow;
+           bar->dragging = Qnil;
+         }
+       else
+         {
+           whole = XM_SB_RANGE;
+           portion = min (cs->value - XM_SB_MIN, XM_SB_MAX - slider_size);
+           part = scroll_bar_handle;
+           bar->dragging = make_number (cs->value);
+         }
+      }
+      break;
+      
+    case XmCR_VALUE_CHANGED:
+      break;
+    };
+
+  if (part >= 0)
+    {
+      window_being_scrolled = bar->window;
+      last_scroll_bar_part = part;
+      x_send_scroll_bar_event (bar->window, part, portion, whole);
+    }
+}
+
+
+#else /* not USE_MOTIF, i.e. XAW3D.  */
+
+
+/* Xaw3d scroll bar callback.  Invoked when the thumb is dragged.
+   WIDGET is the scroll bar widget.  CLIENT_DATA is a pointer to the
+   scroll bar struct.  CALL_DATA is a pointer to a float saying where
+   the thumb is.  */
+
+static void
+xaw3d_jump_callback (widget, client_data, call_data)
+     Widget widget;
+     XtPointer client_data, call_data;
+{
+  struct scroll_bar *bar = (struct scroll_bar *) client_data;
+  float top = *(float *) call_data;
+  float shown;
+  int whole, portion;
+  int dragging_down_p, part;
+  double epsilon = 0.01;
+
+  /* Get the size of the thumb, a value between 0 and 1.  */
+  BLOCK_INPUT;
+  XtVaGetValues (widget, XtNshown, &shown, NULL);
+  UNBLOCK_INPUT;
+
+  whole = 10000000;
+  portion = shown < 1 ? top * whole : 0;
+  dragging_down_p = (INTEGERP (bar->dragging)
+                    && XINT (bar->dragging) < portion);
+
+  if (shown < 1
+      && (abs (top + shown - 1) < epsilon
+         || (dragging_down_p
+             && last_scroll_bar_part == scroll_bar_down_arrow)))
+    part = scroll_bar_down_arrow;
+  else
+    part = scroll_bar_handle;
+
+  window_being_scrolled = bar->window;
+  bar->dragging = make_number (portion);
+  last_scroll_bar_part = part;
+  x_send_scroll_bar_event (bar->window, part, portion, whole);
+}
+
+
+/* Xaw3d scroll bar callback.  Invoked for incremental scrolling.,
+   i.e. line or page up or down.  WIDGET is the Xaw3d scroll bar
+   widget.  CLIENT_DATA is a pointer to the scroll_bar structure for
+   the scroll bar.  CALL_DATA is an integer specifying the action that
+   has taken place.  It's magnitude is in the range 0..height of the
+   scroll bar.  Negative values mean scroll towards buffer start.
+   Values < height of scroll bar mean line-wise movement.  */
+
+static void
+xaw3d_scroll_callback (widget, client_data, call_data)
+     Widget widget;
+     XtPointer client_data, call_data;
+{
+  struct scroll_bar *bar = (struct scroll_bar *) client_data;
+  int position = (int) call_data;
+  Dimension height;
+  int part;
+
+  /* Get the height of the scroll bar.  */
+  BLOCK_INPUT;
+  XtVaGetValues (widget, XtNheight, &height, NULL);
+  UNBLOCK_INPUT;
+
+  if (position < 0)
+    {
+      if (abs (position) < height)
+       part = scroll_bar_up_arrow;
+      else
+       part = scroll_bar_above_handle;
+    }
+  else
+    {
+      if (abs (position) < height)
+       part = scroll_bar_down_arrow;
+      else
+       part = scroll_bar_below_handle;
+    }
+
+  window_being_scrolled = bar->window;
+  bar->dragging = Qnil;
+  last_scroll_bar_part = part;
+  x_send_scroll_bar_event (bar->window, part, 0, 0);
+}
+
+
+#endif /* not USE_MOTIF */
+
+
+/* Create the widget for scroll bar BAR on frame F.  Record the widget
+   and X window of the scroll bar in BAR.  */
+
+static void
+x_create_toolkit_scroll_bar (f, bar)
+     struct frame *f;
+     struct scroll_bar *bar;
+{
+  Window xwindow;
+  Widget widget;
+  Arg av[20];
+  int ac = 0;
+  char *scroll_bar_name = "verticalScrollBar";
+  unsigned long pixel;
+
+  BLOCK_INPUT;
+
+#ifdef USE_MOTIF
+  /* LessTif 0.85, problems:
+
+     1. When the mouse if over the scroll bar, the scroll bar will
+     get keyboard events.  I didn't find a way to turn this off.
+
+     2. Do we have to explicitly set the cursor to get an arrow
+     cursor (see below)?  */
+  
+  /* Set resources.  Create the widget.  */
+  XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+  XtSetArg (av[ac], XmNminimum, XM_SB_MIN); ++ac;
+  XtSetArg (av[ac], XmNmaximum, XM_SB_MAX); ++ac;
+  XtSetArg (av[ac], XmNorientation, XmVERTICAL); ++ac;
+  XtSetArg (av[ac], XmNprocessingDirection, XmMAX_ON_BOTTOM), ++ac;
+  XtSetArg (av[ac], XmNincrement, 1); ++ac;
+  XtSetArg (av[ac], XmNpageIncrement, 1); ++ac;
+
+  pixel = f->output_data.x->scroll_bar_foreground_pixel;
+  if (pixel != -1)
+    {
+      XtSetArg (av[ac], XmNforeground, pixel);
+      ++ac;
+    }
+  
+  pixel = f->output_data.x->scroll_bar_background_pixel;
+  if (pixel != -1)
+    {
+      XtSetArg (av[ac], XmNbackground, pixel);
+      ++ac;
+    }
+  
+  widget = XmCreateScrollBar (f->output_data.x->edit_widget,
+                             scroll_bar_name, av, ac);
+
+  /* Add one callback for everything that can happen.  */
+  XtAddCallback (widget, XmNdecrementCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNdragCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNincrementCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNpageDecrementCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNpageIncrementCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNtoBottomCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  XtAddCallback (widget, XmNtoTopCallback, xm_scroll_callback,
+                (XtPointer) bar);
+  
+  /* Realize the widget.  Only after that is the X window created.  */
+  XtRealizeWidget (widget);
+
+  /* Set the cursor to an arrow.  I didn't find a resource to do that.
+     And I'm wondering why it hasn't an arrow cursor by default.  */
+  XDefineCursor (XtDisplay (widget), XtWindow (widget),
+                f->output_data.x->nontext_cursor);
+  
+#elif defined HAVE_XAW3D
+  
+  /* Set resources.  Create the widget.  The background of the
+     Xaw3d scroll bar widget is a little bit light for my taste.
+     We don't alter it here to let users change it according
+     to their taste with `emacs*verticalScrollBar.background: xxx'.  */
+  XtSetArg (av[ac], XtNmappedWhenManaged, False); ++ac;
+  XtSetArg (av[ac], XtNorientation, XtorientVertical); ++ac;
+  XtSetArg (av[ac], XtNcursorName, "left_ptr"); ++ac;
+  XtSetArg (av[ac], XtNbeNiceToColormap, True); ++ac;
+  
+  pixel = f->output_data.x->scroll_bar_foreground_pixel;
+  if (pixel != -1)
+    {
+      XtSetArg (av[ac], XtNforeground, pixel);
+      ++ac;
+    }
+  
+  pixel = f->output_data.x->scroll_bar_background_pixel;
+  if (pixel != -1)
+    {
+      XtSetArg (av[ac], XtNbackground, pixel);
+      ++ac;
+    }
+  
+  widget = XtCreateWidget (scroll_bar_name, scrollbarWidgetClass,
+                          f->output_data.x->edit_widget, av, ac);
+  
+  /* Define callbacks.  */
+  XtAddCallback (widget, XtNjumpProc, xaw3d_jump_callback, (XtPointer) bar);
+  XtAddCallback (widget, XtNscrollProc, xaw3d_scroll_callback,
+                (XtPointer) bar);
+  
+  /* Realize the widget.  Only after that is the X window created.  */
+  XtRealizeWidget (widget);
+  
+#endif /* HAVE_XAW3D */
+
+  /* Install an action hook that let's us detect when the user
+     finishes interacting with a scroll bar.  */
+  if (action_hook_id == 0)
+    action_hook_id = XtAppAddActionHook (Xt_app_con, xt_action_hook, 0);
+  
+  /* Remember X window and widget in the scroll bar vector.  */
+  SET_SCROLL_BAR_X_WIDGET (bar, widget);
+  xwindow = XtWindow (widget);
+  SET_SCROLL_BAR_X_WINDOW (bar, xwindow);
+
+  UNBLOCK_INPUT;
+}
+
+
+/* Set the thumb size and position of scroll bar BAR.  We are currently
+   displaying PORTION out of a whole WHOLE, and our position POSITION.  */
+
+static void
+x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
+     struct scroll_bar *bar;
+     int portion, position, whole;
+{
+  float top, shown;
+  Arg av[2];
+  Widget widget = SCROLL_BAR_X_WIDGET (bar);
+
+  if (whole == 0)
+    top = 0, shown = 1;
+  else
+    {
+      top = (float) position / whole;
+      shown = (float) portion / whole;
+    }
+
+  BLOCK_INPUT;
+
+#ifdef USE_MOTIF
+  {
+    int size, value;
+    Boolean arrow1_selected, arrow2_selected;
+    unsigned char flags;
+    XmScrollBarWidget sb;
+
+    /* Slider size.  Must be in the range [1 .. MAX - MIN] where NAX
+       is the scroll bar's maximum and MIN is the scroll bar's minimum
+       value.  */
+    size = shown * XM_SB_RANGE;
+    size = min (size, XM_SB_RANGE);
+    size = max (size, 1);
+
+    /* Position.  Must be in the range [MIN .. MAX - SLIDER_SIZE].  */
+    value = top * XM_SB_RANGE;
+    value = min (value, XM_SB_MAX - size);
+    value = max (value, XM_SB_MIN);
+
+    /* LessTif: Calling XmScrollBarSetValues after an increment or
+       decrement turns off auto-repeat LessTif-internally.  This can
+       be seen in ScrollBar.c which resets Arrow1Selected and
+       Arrow2Selected.  It also sets internal flags so that LessTif
+       believes the mouse is in the slider.  We either have to change
+       our code, or work around that by accessing private data. */
+
+    sb = (XmScrollBarWidget) widget;
+    arrow1_selected = sb->scrollBar.arrow1_selected;
+    arrow2_selected = sb->scrollBar.arrow2_selected;
+    flags = sb->scrollBar.flags;
+    
+    if (NILP (bar->dragging))
+      XmScrollBarSetValues (widget, value, size, 0, 0, False);
+    else if (last_scroll_bar_part == scroll_bar_down_arrow)
+      /* This has the negative side effect that the slider value is
+        not would it would be if we scrolled here using line-wise or
+        page-wise movement.  */
+      XmScrollBarSetValues (widget, value, XM_SB_RANGE - value, 0, 0, False);
+    else
+      {
+       /* If currently dragging, only update the slider size.
+          This reduces flicker effects.  */
+       int old_value, old_size, increment, page_increment;
+       
+       XmScrollBarGetValues (widget, &old_value, &old_size,
+                             &increment, &page_increment);
+       XmScrollBarSetValues (widget, old_value,
+                             min (size, XM_SB_RANGE - old_value),
+                             0, 0, False);
+      }
+    
+    sb->scrollBar.arrow1_selected = arrow1_selected;
+    sb->scrollBar.arrow2_selected = arrow2_selected;
+    sb->scrollBar.flags = flags;
+  }
+#elif defined HAVE_XAW3D
+  {
+    /* Restrict to [0 1].  */
+    top = max (0, min (1, top));
+    shown = max (0, min (1, shown));
+
+    /* If the call to XawScrollbarSetThumb below doesn't seem to work,
+       check that your system's configuration file contains a define
+       for `NARROWPROTO'.  See s/freebsd.h for an example.  */
+    if (NILP (bar->dragging))
+      {
+       float old_top, old_shown;
+       XtVaGetValues (widget, XtNtopOfThumb, &old_top, XtNshown, &old_shown,
+                      NULL);
+       if (top != old_top || shown != old_shown)
+         XawScrollbarSetThumb (widget, top, shown);
+      }
+    else
+      {
+       ScrollbarWidget sb = (ScrollbarWidget) widget;
+       int scroll_mode = sb->scrollbar.scroll_mode;
+
+       sb->scrollbar.scroll_mode = 0;
+       
+       if (last_scroll_bar_part == scroll_bar_down_arrow)
+         XawScrollbarSetThumb (widget, top, 1 - top);
+       else
+         {
+           float old_top;
+           XtVaGetValues (widget, XtNtopOfThumb, &old_top, NULL);
+           XawScrollbarSetThumb (widget, old_top, min (shown, 1 - old_top));
+         }
+       
+       sb->scrollbar.scroll_mode = scroll_mode;
+      }
+  }
+#endif /* HAVE_XAW3D */
+
+  UNBLOCK_INPUT;
+}
+
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
+
+\f
+/************************************************************************
+                        Scroll bars, general
+ ************************************************************************/
+                                                                        
+/* Create a scroll bar and return the scroll bar vector for it.  W is
+   the Emacs window on which to create the scroll bar. TOP, LEFT,
+   WIDTH and HEIGHT are.the pixel coordinates and dimensions of the
+   scroll bar. */
+
 static struct scroll_bar *
-x_scroll_bar_create (window, top, left, width, height)
-     struct window *window;
+x_scroll_bar_create (w, top, left, width, height)
+     struct window *w;
      int top, left, width, height;
 {
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
+  struct frame *f = XFRAME (w->frame);
+#ifdef USE_X_TOOLKIT
+  Arg av[10];
+#endif
+  int ac = 0;
+  Window window;
   struct scroll_bar *bar
     = XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
 
   BLOCK_INPUT;
 
+#if USE_TOOLKIT_SCROLL_BARS
+  x_create_toolkit_scroll_bar (f, bar);
+#else /* not USE_TOOLKIT_SCROLL_BARS */
   {
     XSetWindowAttributes a;
     unsigned long mask;
-    a.background_pixel = f->output_data.x->background_pixel;
+
+    a.background_pixel = f->output_data.x->scroll_bar_background_pixel;
+    if (a.background_pixel == -1)
+      a.background_pixel = f->output_data.x->background_pixel;
+    
     a.event_mask = (ButtonPressMask | ButtonReleaseMask
                    | ButtonMotionMask | PointerMotionHintMask
                    | ExposureMask);
@@ -2907,36 +7715,31 @@ x_scroll_bar_create (window, top, left, width, height)
 
     mask = (CWBackPixel | CWEventMask | CWCursor);
 
-#if 0
-
-    ac = 0;
-    XtSetArg (al[ac], XtNx, left); ac++;
-    XtSetArg (al[ac], XtNy, top); ac++;
-    XtSetArg (al[ac], XtNwidth, width); ac++;
-    XtSetArg (al[ac], XtNheight, height); ac++;
-    XtSetArg (al[ac], XtNborderWidth, 0); ac++;
-    sb_widget = XtCreateManagedWidget ("box",
-                                      boxWidgetClass,
-                                      f->output_data.x->edit_widget, al, ac);
-    SET_SCROLL_BAR_X_WINDOW
-      (bar, sb_widget->core.window);
-#endif
-    SET_SCROLL_BAR_X_WINDOW
-      (bar,
-       XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-
-                     /* Position and size of scroll bar.  */
-                     left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, top,
-                     width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, height,
-
-                     /* Border width, depth, class, and visual.  */
-                     0, CopyFromParent, CopyFromParent, CopyFromParent,
-
-                     /* Attributes.  */
-                     mask, &a));
+    /* Clear the area of W that will serve as a scroll bar.  This is
+       for the case that a window has been split horizontally.  In
+       this case, no clear_frame is generated to reduce flickering.  */
+    XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+               left, top, width,
+               window_box_height (w), False);
+
+    window = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                           /* Position and size of scroll bar.  */
+                           left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                           top,
+                           width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+                           height,
+                           /* Border width, depth, class, and visual.  */
+                            0,
+                           CopyFromParent,
+                           CopyFromParent,
+                           CopyFromParent,
+                            /* Attributes.  */
+                           mask, &a);
+    SET_SCROLL_BAR_X_WINDOW (bar, window);
   }
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 
-  XSETWINDOW (bar->window, window);
+  XSETWINDOW (bar->window, w);
   XSETINT (bar->top, top);
   XSETINT (bar->left, left);
   XSETINT (bar->width, width);
@@ -2949,33 +7752,46 @@ x_scroll_bar_create (window, top, left, width, height)
   bar->next = FRAME_SCROLL_BARS (f);
   bar->prev = Qnil;
   XSETVECTOR (FRAME_SCROLL_BARS (f), bar);
-  if (! NILP (bar->next))
+  if (!NILP (bar->next))
     XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
 
+  /* Map the window/widget.  */
+#if USE_TOOLKIT_SCROLL_BARS
+  XtMapWidget (SCROLL_BAR_X_WIDGET (bar));
+  XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
+                    left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                    top,
+                    width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+                    height, 0);
+#else /* not USE_TOOLKIT_SCROLL_BARS */
   XMapRaised (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 
   UNBLOCK_INPUT;
-
   return bar;
 }
 
+
 /* Draw BAR's handle in the proper position.
+   
    If the handle is already drawn from START to END, don't bother
    redrawing it, unless REBUILD is non-zero; in that case, always
    redraw it.  (REBUILD is handy for drawing the handle after expose
    events.)
 
    Normally, we want to constrain the start and end of the handle to
-   fit inside its rectangle, but if the user is dragging the scroll bar
-   handle, we want to let them drag it down all the way, so that the
-   bar's top is as far down as it goes; otherwise, there's no way to
-   move to the very end of the buffer.  */
+   fit inside its rectangle, but if the user is dragging the scroll
+   bar handle, we want to let them drag it down all the way, so that
+   the bar's top is as far down as it goes; otherwise, there's no way
+   to move to the very end of the buffer.  */
+
 static void
 x_scroll_bar_set_handle (bar, start, end, rebuild)
      struct scroll_bar *bar;
      int start, end;
      int rebuild;
 {
+#ifndef USE_TOOLKIT_SCROLL_BARS
   int dragging = ! NILP (bar->dragging);
   Window w = SCROLL_BAR_X_WINDOW (bar);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
@@ -3035,6 +7851,11 @@ x_scroll_bar_set_handle (bar, start, end, rebuild)
                  inside_width, start,
                  False);
 
+    /* Change to proper foreground color if one is specified.  */
+    if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+      XSetForeground (FRAME_X_DISPLAY (f), gc,
+                     f->output_data.x->scroll_bar_foreground_pixel);
+
     /* Draw the handle itself.  */
     XFillRectangle (FRAME_X_DISPLAY (f), w, gc,
 
@@ -3043,6 +7864,10 @@ x_scroll_bar_set_handle (bar, start, end, rebuild)
                    VERTICAL_SCROLL_BAR_TOP_BORDER + start,
                    inside_width, end - start);
 
+    /* Restore the foreground color of the GC if we changed it above.  */
+    if (f->output_data.x->scroll_bar_foreground_pixel != -1)
+      XSetForeground (FRAME_X_DISPLAY (f), gc,
+                     f->output_data.x->foreground_pixel);
 
     /* Draw the empty space below the handle.  Note that we can't
        clear zero-height areas; that means "clear to end of window." */
@@ -3052,56 +7877,19 @@ x_scroll_bar_set_handle (bar, start, end, rebuild)
                  /* x, y, width, height, and exposures.  */
                  VERTICAL_SCROLL_BAR_LEFT_BORDER,
                  VERTICAL_SCROLL_BAR_TOP_BORDER + end,
-                 inside_width, inside_height - end,
-                 False);
-
-  }
-
-  UNBLOCK_INPUT;
-}
-
-/* Move a scroll bar around on the screen, to accommodate changing
-   window configurations.  */
-static void
-x_scroll_bar_move (bar, top, left, width, height)
-     struct scroll_bar *bar;
-     int top, left, width, height;
-{
-  Window w = SCROLL_BAR_X_WINDOW (bar);
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
-
-  BLOCK_INPUT;
-
-  {
-    XWindowChanges wc;
-    unsigned int mask = 0;
-
-    wc.x = left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
-    wc.y = top;
-
-    wc.width = width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
-    wc.height = height;
-
-    if (left != XINT (bar->left))      mask |= CWX;
-    if (top != XINT (bar->top))                mask |= CWY;
-    if (width != XINT (bar->width))    mask |= CWWidth;
-    if (height != XINT (bar->height))  mask |= CWHeight;
+                 inside_width, inside_height - end,
+                 False);
 
-    if (mask)
-      XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
-                       mask, &wc);
   }
 
-  XSETINT (bar->left, left);
-  XSETINT (bar->top, top);
-  XSETINT (bar->width, width);
-  XSETINT (bar->height, height);
-
   UNBLOCK_INPUT;
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 }
 
-/* Destroy the X window for BAR, and set its Emacs window's scroll bar
-   to nil.  */
+
+/* Destroy scroll bar BAR, and set its Emacs window's scroll bar to
+   nil.  */
+
 static void
 x_scroll_bar_remove (bar)
      struct scroll_bar *bar;
@@ -3110,57 +7898,159 @@ x_scroll_bar_remove (bar)
 
   BLOCK_INPUT;
 
-  /* Destroy the window.  */
+#if USE_TOOLKIT_SCROLL_BARS
+  XtDestroyWidget (SCROLL_BAR_X_WIDGET (bar));
+#else /* not USE_TOOLKIT_SCROLL_BARS */
   XDestroyWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar));
-
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
+  
   /* Disassociate this scroll bar from its window.  */
   XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
 
   UNBLOCK_INPUT;
 }
 
+
 /* Set the handle of the vertical scroll bar for WINDOW to indicate
    that we are displaying PORTION characters out of a total of WHOLE
    characters, starting at POSITION.  If WINDOW has no scroll bar,
    create one.  */
+
 static void
-XTset_vertical_scroll_bar (window, portion, whole, position)
-     struct window *window;
+XTset_vertical_scroll_bar (w, portion, whole, position)
+     struct window *w;
      int portion, whole, position;
 {
-  FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
-  int top = XINT (window->top);
-  int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
-  int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
-
-  /* Where should this scroll bar be, pixelwise?  */
-  int pixel_top  = CHAR_TO_PIXEL_ROW (f, top);
-  int pixel_left = CHAR_TO_PIXEL_COL (f, left);
-  int pixel_width
-    = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
-       ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
-       : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
-  int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
-
+  struct frame *f = XFRAME (w->frame);
   struct scroll_bar *bar;
+  int top, height, left, sb_left, width, sb_width;
+  int window_x, window_y, window_width, window_height;
+
+  /* Get window dimensions.  */
+  window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+  top = window_y;
+  width = FRAME_SCROLL_BAR_COLS (f) * CANON_X_UNIT (f);
+  height = window_height;
+
+  /* Compute the left edge of the scroll bar area.  */
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+    left = XINT (w->left) + XINT (w->width) - FRAME_SCROLL_BAR_COLS (f);
+  else
+    left = XFASTINT (w->left);
+  left *= CANON_X_UNIT (f);
+  left += FRAME_INTERNAL_BORDER_WIDTH (f);
+
+  /* Compute the width of the scroll bar which might be less than
+     the width of the area reserved for the scroll bar.  */
+  if (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0)
+    sb_width = FRAME_SCROLL_BAR_PIXEL_WIDTH (f);
+  else
+    sb_width = width;
 
+  /* Compute the left edge of the scroll bar.  */
+#ifdef USE_TOOLKIT_SCROLL_BARS
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+    sb_left = left + width - sb_width - (width - sb_width) / 2; 
+  else
+    sb_left = left + (width - sb_width) / 2;
+#else
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
+    sb_left = left + width - sb_width; 
+  else
+    sb_left = left;
+#endif
+  
   /* Does the scroll bar exist yet?  */
-  if (NILP (window->vertical_scroll_bar))
-    bar = x_scroll_bar_create (window,
-                             pixel_top, pixel_left,
-                             pixel_width, pixel_height);
+  if (NILP (w->vertical_scroll_bar))
+    {
+      BLOCK_INPUT;
+      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 left, top, width, height, False);
+      UNBLOCK_INPUT;
+      bar = x_scroll_bar_create (w, top, sb_left, sb_width, height);
+    }
   else
     {
       /* It may just need to be moved and resized.  */
-      bar = XSCROLL_BAR (window->vertical_scroll_bar);
-      x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
+      unsigned int mask = 0;
+      
+      bar = XSCROLL_BAR (w->vertical_scroll_bar);
+
+      BLOCK_INPUT;
+
+      if (sb_left != XINT (bar->left))
+       mask |= CWX;
+      if (top != XINT (bar->top))
+       mask |= CWY;
+      if (sb_width != XINT (bar->width))
+       mask |= CWWidth;
+      if (height != XINT (bar->height))        
+       mask |= CWHeight;
+      
+#ifdef USE_TOOLKIT_SCROLL_BARS
+
+      /* Since toolkit scroll bars are smaller than the space reserved
+        for them on the frame, we have to clear "under" them.  */
+      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 left, top, width, height, False);
+
+      /* Move/size the scroll bar widget.  */
+      if (mask)
+       XtConfigureWidget (SCROLL_BAR_X_WIDGET (bar),
+                          sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                          top,
+                          sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
+                          height, 0);
+
+#else /* not USE_TOOLKIT_SCROLL_BARS */
+  
+      if (VERTICAL_SCROLL_BAR_WIDTH_TRIM)
+       {
+         /* Clear areas not covered by the scroll bar.  This makes sure a
+            previous mode line display is cleared after C-x 2 C-x 1, for
+            example.  Non-toolkit scroll bars are as wide as the area
+            reserved for scroll bars - trim at both sides.  */
+         XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     left, top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                     height, False);
+         XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                     left + width - VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                     top, VERTICAL_SCROLL_BAR_WIDTH_TRIM,
+                     height, False);
+       }
+      
+      /* Move/size the scroll bar window.  */
+      if (mask)
+       {
+         XWindowChanges wc;
+         
+         wc.x = sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+         wc.y = top;
+         wc.width = sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2;
+         wc.height = height;
+         XConfigureWindow (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (bar),
+                           mask, &wc);
+       }
+  
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
+
+      /* Remember new settings.  */
+      XSETINT (bar->left, sb_left);
+      XSETINT (bar->top, top);
+      XSETINT (bar->width, sb_width);
+      XSETINT (bar->height, height);
+      
+      UNBLOCK_INPUT;
     }
 
+#if USE_TOOLKIT_SCROLL_BARS
+  x_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
+#else /* not USE_TOOLKIT_SCROLL_BARS */
   /* Set the scroll bar's current state, unless we're currently being
      dragged.  */
   if (NILP (bar->dragging))
     {
-      int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, pixel_height);
+      int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, height);
 
       if (whole == 0)
        x_scroll_bar_set_handle (bar, 0, top_range, 0);
@@ -3168,12 +8058,12 @@ XTset_vertical_scroll_bar (window, portion, whole, position)
        {
          int start = ((double) position * top_range) / whole;
          int end = ((double) (position + portion) * top_range) / whole;
-
          x_scroll_bar_set_handle (bar, start, end, 0);
        }
     }
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 
-  XSETVECTOR (window->vertical_scroll_bar, bar);
+  XSETVECTOR (w->vertical_scroll_bar, bar);
 }
 
 
@@ -3187,7 +8077,8 @@ XTset_vertical_scroll_bar (window, portion, whole, position)
 
 /* Arrange for all scroll bars on FRAME to be removed at the next call
    to `*judge_scroll_bars_hook'.  A scroll bar may be spared if
-   `*redeem_scroll_bar_hook' is applied to its window before the judgement.  */
+   `*redeem_scroll_bar_hook' is applied to its window before the judgment.  */
+
 static void
 XTcondemn_scroll_bars (frame)
      FRAME_PTR frame;
@@ -3206,7 +8097,7 @@ XTcondemn_scroll_bars (frame)
     }
 }
 
-/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
+/* Un-mark WINDOW's scroll bar for deletion in this judgment cycle.
    Note that WINDOW isn't necessarily condemned at all.  */
 static void
 XTredeem_scroll_bar (window)
@@ -3255,6 +8146,7 @@ XTredeem_scroll_bar (window)
 
 /* Remove all scroll bars on FRAME that haven't been saved since the
    last call to `*condemn_scroll_bars_hook'.  */
+
 static void
 XTjudge_scroll_bars (f)
      FRAME_PTR f;
@@ -3282,15 +8174,19 @@ XTjudge_scroll_bars (f)
 }
 
 
-/* Handle an Expose or GraphicsExpose event on a scroll bar.
+/* Handle an Expose or GraphicsExpose event on a scroll bar.  This
+   is a no-op when using toolkit scroll bars.
 
    This may be called from a signal handler, so we have to ignore GC
    mark bits.  */
+
 static void
 x_scroll_bar_expose (bar, event)
      struct scroll_bar *bar;
      XEvent *event;
 {
+#ifndef USE_TOOLKIT_SCROLL_BARS
+
   Window w = SCROLL_BAR_X_WINDOW (bar);
   FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
   GC gc = f->output_data.x->normal_gc;
@@ -3300,7 +8196,7 @@ x_scroll_bar_expose (bar, event)
 
   x_scroll_bar_set_handle (bar, XINT (bar->start), XINT (bar->end), 1);
 
-  /* Draw a one-pixel border just inside the edges of the scroll bar. */
+  /* Draw a one-pixel border just inside the edges of the scroll bar.  */
   XDrawRectangle (FRAME_X_DISPLAY (f), w, gc,
 
                  /* x, y, width, height */
@@ -3309,6 +8205,8 @@ x_scroll_bar_expose (bar, event)
                  XINT (bar->height) - 1);
     
   UNBLOCK_INPUT;
+
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 }
 
 /* Handle a mouse click on the scroll bar BAR.  If *EMACS_EVENT's kind
@@ -3316,6 +8214,7 @@ x_scroll_bar_expose (bar, event)
 
    This may be called from a signal handler, so we have to ignore GC
    mark bits.  */
+
 static void
 x_scroll_bar_handle_click (bar, event, emacs_event)
      struct scroll_bar *bar;
@@ -3337,9 +8236,11 @@ x_scroll_bar_handle_click (bar, event, emacs_event)
   emacs_event->frame_or_window = bar->window;
   emacs_event->timestamp = event->xbutton.time;
   {
+#if 0
     FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
     int internal_height
       = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
+#endif
     int top_range
       = VERTICAL_SCROLL_BAR_TOP_RANGE (f, XINT (bar->height));
     int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
@@ -3396,6 +8297,7 @@ x_scroll_bar_handle_click (bar, event, emacs_event)
 
    This may be called from a signal handler, so we have to ignore GC
    mark bits.  */
+
 static void
 x_scroll_bar_note_movement (bar, event)
      struct scroll_bar *bar;
@@ -3425,6 +8327,7 @@ x_scroll_bar_note_movement (bar, event)
 
 /* Return information to the user about the current position of the mouse
    on the scroll bar.  */
+
 static void
 x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
      FRAME_PTR *fp;
@@ -3459,8 +8362,10 @@ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
     ;
   else
     {
+#if 0
       int inside_height
        = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (f, XINT (bar->height));
+#endif
       int top_range
        = VERTICAL_SCROLL_BAR_TOP_RANGE     (f, XINT (bar->height));
 
@@ -3504,9 +8409,11 @@ x_scroll_bar_report_motion (fp, bar_window, part, x, y, time)
    Clear out the scroll bars, and ask for expose events, so we can
    redraw them.  */
 
+void
 x_scroll_bar_clear (f)
      FRAME_PTR f;
 {
+#ifndef USE_TOOLKIT_SCROLL_BARS
   Lisp_Object bar;
 
   /* We can have scroll bars even if this is 0,
@@ -3517,18 +8424,20 @@ x_scroll_bar_clear (f)
         bar = XSCROLL_BAR (bar)->next)
       XClearArea (FRAME_X_DISPLAY (f), SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
                  0, 0, 0, 0, True);
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
 }
 
-/* This processes Expose events from the menubar specific X event
+/* This processes Expose events from the menu-bar specific X event
    loop in xmenu.c.  This allows to redisplay the frame if necessary
-   when handling menubar or popup items.  */
+   when handling menu-bar or pop-up items.  */
 
-void
+int
 process_expose_from_menu (event)
      XEvent event;
 {
   FRAME_PTR f;
   struct x_display_info *dpyinfo;
+  int frame_exposed_p = 0;
 
   BLOCK_INPUT;
 
@@ -3545,9 +8454,10 @@ process_expose_from_menu (event)
        }
       else
        {
-         dumprectangle (x_window_to_frame (dpyinfo, event.xexpose.window),
-                        event.xexpose.x, event.xexpose.y,
-                        event.xexpose.width, event.xexpose.height);
+         expose_frame (x_window_to_frame (dpyinfo, event.xexpose.window),
+                       event.xexpose.x, event.xexpose.y,
+                       event.xexpose.width, event.xexpose.height);
+         frame_exposed_p = 1;
        }
     }
   else
@@ -3560,6 +8470,7 @@ process_expose_from_menu (event)
     }
 
   UNBLOCK_INPUT;
+  return frame_exposed_p;
 }
 \f
 /* Define a queue to save up SelectionRequest events for later handling.  */
@@ -3573,6 +8484,7 @@ struct selection_event_queue
 static struct selection_event_queue *queue;
 
 /* Nonzero means queue up certain events--don't process them yet.  */
+
 static int x_queue_selection_requests;
 
 /* Queue up an X event *EVENT, to be processed later.  */
@@ -3583,7 +8495,7 @@ x_queue_event (f, event)
      XEvent *event;
 {
   struct selection_event_queue *queue_tmp
-    = (struct selection_event_queue *) malloc (sizeof (struct selection_event_queue));
+    = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
 
   if (queue_tmp != NULL)
     {
@@ -3605,7 +8517,7 @@ x_unqueue_events (display)
       struct selection_event_queue *queue_tmp = queue;
       XPutBackEvent (display, &queue_tmp->event);
       queue = queue_tmp->next;
-      free ((char *)queue_tmp);
+      xfree ((char *)queue_tmp);
     }
 }
 
@@ -3630,9 +8542,10 @@ x_stop_queuing_selection_requests (display)
 \f
 /* The main X event-reading loop - XTread_socket.  */
 
-/* Timestamp of enter window event.  This is only used by XTread_socket,
+/* Time stamp of enter window event.  This is only used by XTread_socket,
    but we have to put it out here, since static variables within functions
    sometimes don't work.  */
+
 static Time enter_timestamp;
 
 /* This holds the state XLookupString needs to implement dead keys
@@ -3641,39 +8554,48 @@ static Time enter_timestamp;
    me that letting the compiler initialize it to zeros will work okay.
 
    This must be defined outside of XTread_socket, for the same reasons
-   given for enter_timestamp, above.  */
+   given for enter_time stamp, above.  */
+
 static XComposeStatus compose_status;
 
 /* Record the last 100 characters stored
    to help debug the loss-of-chars-during-GC problem.  */
+
 static int temp_index;
 static short temp_buffer[100];
 
 /* Set this to nonzero to fake an "X I/O error"
    on a particular display.  */
+
 struct x_display_info *XTread_socket_fake_io_error;
 
 /* When we find no input here, we occasionally do a no-op command
    to verify that the X server is still running and we can still talk with it.
    We try all the open displays, one by one.
    This variable is used for cycling thru the displays.  */
+
 static struct x_display_info *next_noop_dpyinfo;
 
-#define SET_SAVED_MENU_EVENT(size) { \
-  if (f->output_data.x->saved_menu_event == 0) \
-    f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent)); \
-  bcopy (&event, f->output_data.x->saved_menu_event, size); \
-  if (numchars >= 1) \
-    { \
-      bufp->kind = menu_bar_activate_event; \
-      XSETFRAME (bufp->frame_or_window, f); \
-      bufp++; \
-      count++; \
-      numchars--; \
-    } \
-  }
+#define SET_SAVED_MENU_EVENT(size)                                     \
+     do                                                                        \
+       {                                                               \
+        if (f->output_data.x->saved_menu_event == 0)                   \
+           f->output_data.x->saved_menu_event                          \
+            = (XEvent *) xmalloc (sizeof (XEvent));                    \
+         bcopy (&event, f->output_data.x->saved_menu_event, size);     \
+         if (numchars >= 1)                                            \
+           {                                                           \
+             bufp->kind = menu_bar_activate_event;                     \
+             XSETFRAME (bufp->frame_or_window, f);                     \
+             bufp++;                                                   \
+             count++;                                                  \
+             numchars--;                                               \
+           }                                                           \
+       }                                                               \
+     while (0)
+
 #define SET_SAVED_BUTTON_EVENT SET_SAVED_MENU_EVENT (sizeof (XButtonEvent))
-#define SET_SAVED_KEY_EVENT SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
+#define SET_SAVED_KEY_EVENT    SET_SAVED_MENU_EVENT (sizeof (XKeyEvent))
 
 /* Read events coming from the X server.
    This routine is called by the SIGIO handler.
@@ -3695,13 +8617,9 @@ XTread_socket (sd, bufp, numchars, expected)
 {
   int count = 0;
   int nbytes = 0;
-  int mask;
-  int items_pending;           /* How many items are in the X queue. */
   XEvent event;
   struct frame *f;
   int event_found = 0;
-  int prefix;
-  Lisp_Object part;
   struct x_display_info *dpyinfo;
 #ifdef HAVE_X_I18N
   Status status_return;
@@ -3720,7 +8638,7 @@ XTread_socket (sd, bufp, numchars, expected)
   input_signal_count++;
 
   if (numchars <= 0)
-    abort ();                  /* Don't think this happens. */
+    abort ();                  /* Don't think this happens.  */
 
   /* Find the display we are supposed to read input for.
      It's the one communicating on descriptor SD.  */
@@ -3731,7 +8649,7 @@ XTread_socket (sd, bufp, numchars, expected)
       /* If available, Xlib uses FIOSNBIO to make the socket
         non-blocking, and then looks for EWOULDBLOCK.  If O_NDELAY is set,
         FIOSNBIO is ignored, and instead of signaling EWOULDBLOCK,
-        a read returns 0, which Xlib interprets as equivalent to EPIPE. */
+        a read returns 0, which Xlib interprets as equivalent to EPIPE.  */
       fcntl (dpyinfo->connection, F_SETFL, 0);
 #endif /* ! defined (FIOSNBIO) */
 #endif
@@ -3760,18 +8678,29 @@ XTread_socket (sd, bufp, numchars, expected)
          x_io_error_quitter (dpyinfo->display);
        }
 
-      while (XPending (dpyinfo->display) != 0)
+      while (XPending (dpyinfo->display))
        {
-#ifdef USE_X_TOOLKIT
-          /* needed to raise Motif submenus */
-         XtAppNextEvent (Xt_app_con, &event);
-#else
          XNextEvent (dpyinfo->display, &event);
-#endif
+
+         if (display_busy_cursor_p)
+           {
+             /* Setting inhibit_busy_cursor to 2 inhibits busy-cursor
+                display until the next X event is read and we come
+                here again.  Setting it to 1 inhibits busy-cursor
+                display for direct commands.  */
+             if (event.type == MotionNotify
+                 || event.type == EnterNotify
+                 || (dpyinfo->grabbed
+                     && event.type != ButtonRelease))
+               inhibit_busy_cursor = 2;
+             else
+               inhibit_busy_cursor = 1;
+           }
+
 #ifdef HAVE_X_I18N
          {
            struct frame *f1 = x_any_window_to_frame (dpyinfo,
-                                                     &event.xclient.window);
+                                                     event.xclient.window);
            /* The necessity of the following line took me
               a full work-day to decipher from the docs!!  */
            if (f1 != 0 && FRAME_XIC (f1) && XFilterEvent (&event, None))
@@ -3791,30 +8720,44 @@ XTread_socket (sd, bufp, numchars, expected)
                    if (event.xclient.data.l[0]
                        == dpyinfo->Xatom_wm_take_focus)
                      {
-                       f = x_window_to_frame (dpyinfo, event.xclient.window);
-                       /* Since we set WM_TAKE_FOCUS, we must call
-                          XSetInputFocus explicitly.  But not if f is null,
-                          since that might be an event for a deleted frame.  */
+                       /* Use x_any_window_to_frame because this
+                          could be the shell widget window
+                          if the frame has no title bar.  */
+                       f = x_any_window_to_frame (dpyinfo, event.xclient.window);
 #ifdef HAVE_X_I18N
                        /* Not quite sure this is needed -pd */
-                       if (f)
+                       if (f && FRAME_XIC (f))
                          XSetICFocus (FRAME_XIC (f));
 #endif
+                       /* Since we set WM_TAKE_FOCUS, we must call
+                          XSetInputFocus explicitly.  But not if f is null,
+                          since that might be an event for a deleted frame.  */
                        if (f)
-                         XSetInputFocus (event.xclient.display,
-                                         event.xclient.window,
-                                         RevertToPointerRoot,
-                                         event.xclient.data.l[1]);
+                         {
+                           Display *d = event.xclient.display;
+                           /* Catch and ignore errors, in case window has been
+                              iconified by a window manager such as GWM.  */
+                           int count = x_catch_errors (d);
+                           XSetInputFocus (d, event.xclient.window,
+                                           /* The ICCCM says this is
+                                              the only valid choice.  */
+                                           RevertToParent,
+                                           event.xclient.data.l[1]);
+                           /* This is needed to detect the error
+                              if there is an error.  */
+                           XSync (d, False);
+                           x_uncatch_errors (d, count);
+                         }  
                        /* Not certain about handling scroll bars here */
                      }
                    else if (event.xclient.data.l[0]
                             == dpyinfo->Xatom_wm_save_yourself)
                      {
                        /* Save state modify the WM_COMMAND property to
-                          something which can reinstate us. This notifies
+                          something which can reinstate us.  This notifies
                           the session manager, who's looking for such a
                           PropertyNotify.  Can restart processing when
-                          a keyboard or mouse event arrives. */
+                          a keyboard or mouse event arrives.  */
                        if (numchars > 0)
                          {
                            f = x_top_window_to_frame (dpyinfo,
@@ -3883,6 +8826,35 @@ XTread_socket (sd, bufp, numchars, expected)
                                            &event, NULL);
                  }
 #endif /* HACK_EDITRES */
+               else if ((event.xclient.message_type
+                         == dpyinfo->Xatom_DONE)
+                        || (event.xclient.message_type
+                            == dpyinfo->Xatom_PAGE))
+                 {
+                   /* Ghostview job completed.  Kill it.  We could
+                      reply with "Next" if we received "Page", but we
+                      currently never do because we are interested in
+                      images, only, which should have 1 page.  */
+                   Window gs_window = (Window) event.xclient.data.l[0];
+                   Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
+                   struct frame *f
+                     = x_window_to_frame (dpyinfo, event.xclient.window);
+                   x_kill_gs_process (pixmap, f);
+                   expose_frame (f, 0, 0, 0, 0);
+                 }
+#ifdef USE_TOOLKIT_SCROLL_BARS
+               /* Scroll bar callbacks send a ClientMessage from which
+                  we construct an input_event.  */
+               else if (event.xclient.message_type
+                        == dpyinfo->Xatom_Scrollbar)
+                 {
+                   x_scroll_bar_to_input_event (&event, bufp);
+                   ++bufp, ++count, --numchars;
+                   goto out;
+                 }
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+               else
+                 goto OTHER;
              }
              break;
 
@@ -3891,10 +8863,10 @@ XTread_socket (sd, bufp, numchars, expected)
              if (! x_window_to_frame (dpyinfo, event.xselection.requestor))
                goto OTHER;
 #endif /* not USE_X_TOOLKIT */
-             x_handle_selection_notify (&event);
+             x_handle_selection_notify (&event.xselection);
              break;
 
-           case SelectionClear:        /* Someone has grabbed ownership. */
+           case SelectionClear:        /* Someone has grabbed ownership.  */
 #ifdef USE_X_TOOLKIT
              if (! x_window_to_frame (dpyinfo, event.xselectionclear.window))
                goto OTHER;
@@ -3917,7 +8889,7 @@ XTread_socket (sd, bufp, numchars, expected)
              }
              break;
 
-           case SelectionRequest:      /* Someone wants our selection. */
+           case SelectionRequest:      /* Someone wants our selection.  */
 #ifdef USE_X_TOOLKIT
              if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner))
                goto OTHER;
@@ -3952,7 +8924,7 @@ XTread_socket (sd, bufp, numchars, expected)
              if (!x_any_window_to_frame (dpyinfo, event.xproperty.window))
                goto OTHER;
 #endif /* not USE_X_TOOLKIT */
-             x_handle_property_notify (&event);
+             x_handle_property_notify (&event.xproperty);
              break;
 
            case ReparentNotify:
@@ -3979,13 +8951,17 @@ XTread_socket (sd, bufp, numchars, expected)
                      SET_FRAME_GARBAGED (f);
                    }
                  else
-                   dumprectangle (x_window_to_frame (dpyinfo,
-                                                     event.xexpose.window),
-                                  event.xexpose.x, event.xexpose.y,
-                                  event.xexpose.width, event.xexpose.height);
+                   expose_frame (x_window_to_frame (dpyinfo,
+                                                    event.xexpose.window),
+                                 event.xexpose.x, event.xexpose.y,
+                                 event.xexpose.width, event.xexpose.height);
                }
              else
                {
+#ifdef USE_TOOLKIT_SCROLL_BARS
+                 /* Dispatch event to the widget.  */
+                 goto OTHER;
+#else /* not USE_TOOLKIT_SCROLL_BARS */
                  struct scroll_bar *bar
                    = x_window_to_scroll_bar (event.xexpose.window);
 
@@ -3995,6 +8971,7 @@ XTread_socket (sd, bufp, numchars, expected)
                  else
                    goto OTHER;
 #endif /* USE_X_TOOLKIT */
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
                }
              break;
 
@@ -4004,10 +8981,10 @@ XTread_socket (sd, bufp, numchars, expected)
              f = x_window_to_frame (dpyinfo, event.xgraphicsexpose.drawable);
              if (f)
                {
-                 dumprectangle (f,
-                                event.xgraphicsexpose.x, event.xgraphicsexpose.y,
-                                event.xgraphicsexpose.width,
-                                event.xgraphicsexpose.height);
+                 expose_frame (f,
+                               event.xgraphicsexpose.x, event.xgraphicsexpose.y,
+                               event.xgraphicsexpose.width,
+                               event.xgraphicsexpose.height);
                }
 #ifdef USE_X_TOOLKIT
              else
@@ -4016,11 +8993,18 @@ XTread_socket (sd, bufp, numchars, expected)
              break;
 
            case NoExpose:              /* This occurs when an XCopyArea's
-                                     source area was completely
-                                     available */
+                                          source area was completely
+                                          available */
              break;
 
            case UnmapNotify:
+             /* Redo the mouse-highlight after the tooltip has gone.  */
+             if (event.xmap.window == tip_window)
+               {
+                 tip_window = 0;
+                 redo_mouse_highlight ();
+               }
+             
              f = x_top_window_to_frame (dpyinfo, event.xunmap.window);
              if (f)            /* F may no longer exist if
                                       the frame was deleted.  */
@@ -4049,8 +9033,14 @@ XTread_socket (sd, bufp, numchars, expected)
              goto OTHER;
 
            case MapNotify:
-             /* We use x_top_window_to_frame because map events can come
-                for subwindows and they don't mean that the frame is visible.  */
+             if (event.xmap.window == tip_window)
+               /* The tooltip has been drawn already.  Avoid
+                  the SET_FRAME_GARBAGED below.  */
+               goto OTHER;
+             
+             /* We use x_top_window_to_frame because map events can
+                come for sub-windows and they don't mean that the
+                frame is visible.  */
              f = x_top_window_to_frame (dpyinfo, event.xmap.window);
              if (f)
                {
@@ -4071,7 +9061,7 @@ XTread_socket (sd, bufp, numchars, expected)
                      numchars--;
                    }
                  else if (! NILP (Vframe_list)
-                          && ! NILP (XCONS (Vframe_list)->cdr))
+                          && ! NILP (XCDR (Vframe_list)))
                    /* Force a redisplay sooner or later
                       to update the frame titles
                       in case this is the second frame.  */
@@ -4079,13 +9069,24 @@ XTread_socket (sd, bufp, numchars, expected)
                }
              goto OTHER;
 
-             /* Turn off processing if we become fully obscured. */
-           case VisibilityNotify:
-             break;
-
            case KeyPress:
              f = x_any_window_to_frame (dpyinfo, event.xkey.window);
 
+#ifdef USE_MOTIF
+             /* I couldn't find a way to prevent LessTif scroll bars
+                from consuming key events.  */
+             if (f == 0)
+               {
+                 Widget widget = XtWindowToWidget (dpyinfo->display,
+                                                   event.xkey.window);
+                 if (widget && XmIsScrollBar (widget))
+                   {
+                     widget = XtParent (widget);
+                     f = x_any_window_to_frame (dpyinfo, XtWindow (widget));
+                   }
+               }
+#endif /* USE_MOTIF */
+
              if (f != 0)
                {
                  KeySym keysym, orig_keysym;
@@ -4094,21 +9095,6 @@ XTread_socket (sd, bufp, numchars, expected)
                  unsigned char copy_buffer[81];
                  int modifiers;
 
-#if 0 /* This was how we made f10 work in Motif.
-        The drawback is, you can't type at Emacs when the
-        the mouse is in the menu bar.  So it is better to
-        turn off f10 in Motif and let Emacs handle it.  */
-#ifdef USE_MOTIF
-                  if (lw_window_is_in_menubar (event.xkey.window,
-                                               f->output_data.x->menubar_widget
-                                               ))
-                    {
-                      SET_SAVED_KEY_EVENT;
-                      break;
-                    }
-#endif /* USE_MOTIF */
-#endif /* 0 */
-
                  event.xkey.state
                    |= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
                                               extra_keyboard_modifiers);
@@ -4143,6 +9129,13 @@ XTread_socket (sd, bufp, numchars, expected)
                                                &event.xkey, copy_buffer,
                                                80, &keysym,
                                                &status_return);
+                     if (status_return == XLookupNone)
+                       break;
+                     else if (status_return == XLookupChars)
+                       keysym = NoSymbol;
+                     else if (status_return != XLookupKeySym
+                              && status_return != XLookupBoth)
+                       abort ();
                    }
                  else
                    nbytes = XLookupString (&event.xkey, copy_buffer,
@@ -4161,6 +9154,7 @@ XTread_socket (sd, bufp, numchars, expected)
 #ifdef XK_ISO_Left_Tab
                           || (keysym >= XK_ISO_Left_Tab && keysym <= XK_ISO_Enter)
 #endif
+                          || (keysym >= XK_Kanji && keysym <= XK_Eisu_toggle)
                           || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
                           || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
 #ifdef HPUX
@@ -4238,6 +9232,10 @@ XTread_socket (sd, bufp, numchars, expected)
                          bufp++;
                          count++;
                          numchars--;
+                         
+                         if (display_busy_cursor_p)
+                           if (keysym != XK_Return || minibuf_level == 0)
+                             inhibit_busy_cursor = 2;
                        }
                      else if (numchars > nbytes)
                        {
@@ -4260,6 +9258,9 @@ XTread_socket (sd, bufp, numchars, expected)
 
                          count += nbytes;
                          numchars -= nbytes;
+
+                         if (keysym == NoSymbol)
+                           break;
                        }
                      else
                        abort ();
@@ -4270,32 +9271,68 @@ XTread_socket (sd, bufp, numchars, expected)
              goto OTHER;
 
              /* Here's a possible interpretation of the whole
-                FocusIn-EnterNotify FocusOut-LeaveNotify mess.  If you get a
-                FocusIn event, you have to get a FocusOut event before you
-                relinquish the focus.  If you haven't received a FocusIn event,
-                then a mere LeaveNotify is enough to free you.  */
+                FocusIn-EnterNotify FocusOut-LeaveNotify mess.  If
+                you get a FocusIn event, you have to get a FocusOut
+                event before you relinquish the focus.  If you
+                haven't received a FocusIn event, then a mere
+                LeaveNotify is enough to free you.  */
 
            case EnterNotify:
-             f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
+             {
+               int from_menu_bar_p = 0;
+               
+               f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
+
+#ifdef LESSTIF_VERSION
+               /* When clicking outside of a menu bar popup to close
+                  it, we get a FocusIn/ EnterNotify sequence of
+                  events.  The flag event.xcrossing.focus is not set
+                  in the EnterNotify event of that sequence because
+                  the focus is in the menu bar,
+                  event.xcrossing.window is the frame's X window.
+                  Unconditionally setting the focus frame to null in
+                  this case is not the right thing, because no event
+                  follows that could set the focus frame to the right
+                  value.
+
+                  This could be a LessTif bug, but I wasn't able to
+                  reproduce the behavior in a simple test program.
+
+                  (gerd, LessTif 0.88.1).  */
+               
+               if (!event.xcrossing.focus
+                   && f
+                   && f->output_data.x->menubar_widget)
+                 {
+                   Window focus;
+                   int revert;
+                   
+                   XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
+                   if (focus == XtWindow (f->output_data.x->menubar_widget))
+                     from_menu_bar_p = 1;
+                 }
+#endif /* LESSTIF_VERSION */
 
-             if (event.xcrossing.focus)                /* Entered Window */
-               {
-                 /* Avoid nasty pop/raise loops. */
-                 if (f && (!(f->auto_raise)
-                           || !(f->auto_lower)
-                           || (event.xcrossing.time - enter_timestamp) > 500))
-                   {
-                     x_new_focus_frame (dpyinfo, f);
-                     enter_timestamp = event.xcrossing.time;
-                   }
-               }
-             else if (f == dpyinfo->x_focus_frame)
-               x_new_focus_frame (dpyinfo, 0);
-             /* EnterNotify counts as mouse movement,
-                so update things that depend on mouse position.  */
-             if (f)
-               note_mouse_movement (f, &event.xmotion);
-             goto OTHER;
+               if (event.xcrossing.focus || from_menu_bar_p)
+                 {
+                   /* Avoid nasty pop/raise loops.  */
+                   if (f && (!(f->auto_raise)
+                             || !(f->auto_lower)
+                             || (event.xcrossing.time - enter_timestamp) > 500))
+                     {
+                       x_new_focus_frame (dpyinfo, f);
+                       enter_timestamp = event.xcrossing.time;
+                     }
+                 }
+               else if (f == dpyinfo->x_focus_frame)
+                 x_new_focus_frame (dpyinfo, 0);
+             
+               /* EnterNotify counts as mouse movement,
+                  so update things that depend on mouse position.  */
+               if (f && !f->output_data.x->busy_p)
+                 note_mouse_movement (f, &event.xmotion);
+               goto OTHER;
+             }
 
            case FocusIn:
              f = x_any_window_to_frame (dpyinfo, event.xfocus.window);
@@ -4315,12 +9352,44 @@ XTread_socket (sd, bufp, numchars, expected)
              f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
              if (f)
                {
+                 Lisp_Object frame;
+                 int from_menu_bar_p = 0;
+                 
                  if (f == dpyinfo->mouse_face_mouse_frame)
-                   /* If we move outside the frame,
-                      then we're certainly no longer on any text in the frame.  */
-                   clear_mouse_face (dpyinfo);
+                   {
+                     /* If we move outside the frame, then we're
+                        certainly no longer on any text in the frame.  */
+                     clear_mouse_face (dpyinfo);
+                     dpyinfo->mouse_face_mouse_frame = 0;
+                   }
+
+                 /* Generate a nil HELP_EVENT to cancel a help-echo.
+                    Do it only if there's something to cancel.
+                    Otherwise, the startup message is cleared when
+                    the mouse leaves the frame.  */
+                 if (any_help_event_p)
+                   {
+                     XSETFRAME (frame, f);
+                     bufp->kind = HELP_EVENT;
+                     bufp->frame_or_window = Fcons (frame, Qnil);
+                     ++bufp, ++count, --numchars;
+                   }
 
-                 if (event.xcrossing.focus)
+#ifdef LESSTIF_VERSION
+                 /* Please see the comment at the start of the
+                     EnterNotify case.  */
+                 if (!event.xcrossing.focus
+                     && f->output_data.x->menubar_widget)
+                   {
+                     Window focus;
+                     int revert;
+                     XGetInputFocus (FRAME_X_DISPLAY (f), &focus, &revert);
+                     if (focus == XtWindow (f->output_data.x->menubar_widget))
+                       from_menu_bar_p = 1;
+                   }
+#endif /* LESSTIF_VERSION */
+               
+                 if (event.xcrossing.focus || from_menu_bar_p)
                    x_mouse_leave (dpyinfo);
                  else
                    {
@@ -4349,40 +9418,65 @@ XTread_socket (sd, bufp, numchars, expected)
 
            case MotionNotify:
              {
+               previous_help_echo = help_echo;
+               help_echo = Qnil;
+               
                if (dpyinfo->grabbed && last_mouse_frame
                    && FRAME_LIVE_P (last_mouse_frame))
                  f = last_mouse_frame;
                else
                  f = x_window_to_frame (dpyinfo, event.xmotion.window);
+
                if (f)
                  note_mouse_movement (f, &event.xmotion);
                else
                  {
+#ifndef USE_X_TOOLKIT
                    struct scroll_bar *bar
                      = x_window_to_scroll_bar (event.xmotion.window);
 
                    if (bar)
                      x_scroll_bar_note_movement (bar, &event);
+#endif /* USE_X_TOOLKIT */
 
-                   /* If we move outside the frame,
-                      then we're certainly no longer on any text in the frame.  */
+                   /* If we move outside the frame, then we're
+                      certainly no longer on any text in the frame.  */
                    clear_mouse_face (dpyinfo);
                  }
+
+               /* If the contents of the global variable help_echo
+                  has changed, generate a HELP_EVENT.  */
+               if (STRINGP (help_echo)
+                   || STRINGP (previous_help_echo))
+                 {
+                   Lisp_Object frame;
+
+                   if (f)
+                     XSETFRAME (frame, f);
+                   else
+                     frame = Qnil;
+
+                   any_help_event_p = 1;
+                   bufp->kind = HELP_EVENT;
+                   bufp->frame_or_window = Fcons (frame, help_echo);
+                   ++bufp, ++count, --numchars;
+                 }
+               
+               goto OTHER;
              }
-             goto OTHER;
 
            case ConfigureNotify:
              f = x_top_window_to_frame (dpyinfo, event.xconfigure.window);
              if (f)
                {
+                 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
+                 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
+
 #ifndef USE_X_TOOLKIT
                  /* In the toolkit version, change_frame_size
                     is called by the code that handles resizing
                     of the EmacsFrame widget.  */
 
-                 int rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
-                 int columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
-
                  /* Even if the number of character rows and columns has
                     not changed, the font size may have changed, so we need
                     to check the pixel dimensions as well.  */
@@ -4391,7 +9485,7 @@ XTread_socket (sd, bufp, numchars, expected)
                      || event.xconfigure.width != f->output_data.x->pixel_width
                      || event.xconfigure.height != f->output_data.x->pixel_height)
                    {
-                     change_frame_size (f, rows, columns, 0, 1);
+                     change_frame_size (f, rows, columns, 0, 1, 0);
                      SET_FRAME_GARBAGED (f);
                      cancel_mouse_face (f);
                    }
@@ -4412,6 +9506,16 @@ XTread_socket (sd, bufp, numchars, expected)
                      f->output_data.x->win_gravity = NorthWestGravity;
                      x_wm_set_size_hint (f, (long) 0, 0);
                    }
+#ifdef USE_MOTIF
+                 /* Some window managers pass (0,0) as the location of
+                    the window, and the Motif event handler stores it
+                    in the emacs widget, which messes up Motif menus.  */
+                 if (event.xconfigure.x == 0 && event.xconfigure.y == 0)
+                   {
+                     event.xconfigure.x = f->output_data.x->widget->core.x;
+                     event.xconfigure.y = f->output_data.x->widget->core.y;
+                   }
+#endif /* USE_MOTIF */
                }
              goto OTHER;
 
@@ -4421,11 +9525,13 @@ XTread_socket (sd, bufp, numchars, expected)
                /* If we decide we want to generate an event to be seen
                   by the rest of Emacs, we put it here.  */
                struct input_event emacs_event;
+               int tool_bar_p = 0;
+               
                emacs_event.kind = no_event;
-
                bzero (&compose_status, sizeof (compose_status));
 
-               if (dpyinfo->grabbed && last_mouse_frame
+               if (dpyinfo->grabbed
+                   && last_mouse_frame
                    && FRAME_LIVE_P (last_mouse_frame))
                  f = last_mouse_frame;
                else
@@ -4433,22 +9539,56 @@ XTread_socket (sd, bufp, numchars, expected)
 
                if (f)
                  {
-                   if (!dpyinfo->x_focus_frame || f == dpyinfo->x_focus_frame)
-                     construct_mouse_click (&emacs_event, &event, f);
+                   /* Is this in the tool-bar?  */
+                   if (WINDOWP (f->tool_bar_window)
+                       && XFASTINT (XWINDOW (f->tool_bar_window)->height))
+                     {
+                       Lisp_Object window;
+                       int p, x, y;
+
+                       x = event.xbutton.x;
+                       y = event.xbutton.y;
+
+                       /* Set x and y.  */
+                       window = window_from_coordinates (f, x, y, &p, 1);
+                       if (EQ (window, f->tool_bar_window))
+                         {
+                           x_handle_tool_bar_click (f, &event.xbutton);
+                           tool_bar_p = 1;
+                         }
+                     }
+
+                   if (!tool_bar_p)
+                     if (!dpyinfo->x_focus_frame
+                         || f == dpyinfo->x_focus_frame)
+                       construct_mouse_click (&emacs_event, &event, f);
                  }
                else
                  {
+#ifndef USE_TOOLKIT_SCROLL_BARS
                    struct scroll_bar *bar
                      = x_window_to_scroll_bar (event.xbutton.window);
 
                    if (bar)
                      x_scroll_bar_handle_click (bar, &event, &emacs_event);
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
                  }
 
                if (event.type == ButtonPress)
                  {
                    dpyinfo->grabbed |= (1 << event.xbutton.button);
                    last_mouse_frame = f;
+                   /* Ignore any mouse motion that happened
+                      before this event; any subsequent mouse-movement
+                      Emacs events should reflect only motion after
+                      the ButtonPress.  */
+                   if (f != 0)
+                     f->mouse_moved = 0;
+                   
+                   if (!tool_bar_p)
+                     last_tool_bar_item = -1;
+                   if (display_busy_cursor_p)
+                     inhibit_busy_cursor = 2;
                  }
                else
                  {
@@ -4487,6 +9627,7 @@ XTread_socket (sd, bufp, numchars, expected)
                    last_mouse_press_frame = Qnil;
                    goto OTHER;
                  }
+
 #ifdef USE_MOTIF /* This should do not harm for Lucid,
                    but I am trying to be cautious.  */
                else if (event.type == ButtonRelease)
@@ -4495,11 +9636,9 @@ XTread_socket (sd, bufp, numchars, expected)
                      {
                        f = XFRAME (last_mouse_press_frame);
                        if (f->output_data.x)
-                         {
-                           SET_SAVED_BUTTON_EVENT;
-                         }
+                         SET_SAVED_BUTTON_EVENT;
                      }
-                   else 
+                   else
                      goto OTHER;
                  }
 #endif /* USE_MOTIF */
@@ -4510,9 +9649,13 @@ XTread_socket (sd, bufp, numchars, expected)
              break;
 
            case CirculateNotify:
-             break;
+             goto OTHER;
+             
            case CirculateRequest:
-             break;
+             goto OTHER;
+
+           case VisibilityNotify:
+             goto OTHER;
 
            case MappingNotify:
              /* Someone has changed the keyboard mapping - update the
@@ -4539,6 +9682,8 @@ XTread_socket (sd, bufp, numchars, expected)
        }
     }
 
+ out:;
+
   /* On some systems, an X bug causes Emacs to get no more events
      when the window is destroyed.  Detect that.  (1994.)  */
   if (! event_found)
@@ -4561,7 +9706,7 @@ XTread_socket (sd, bufp, numchars, expected)
        }
     }
 
-  /* If the focus was just given to an autoraising frame,
+  /* If the focus was just given to an auto-raising frame,
      raise it now.  */
   /* ??? This ought to be able to handle more than one such frame.  */
   if (pending_autoraise_frame)
@@ -4573,283 +9718,531 @@ XTread_socket (sd, bufp, numchars, expected)
   UNBLOCK_INPUT;
   return count;
 }
+
+
+
 \f
-/* Drawing the cursor.  */
+/***********************************************************************
+                            Text Cursor
+ ***********************************************************************/
+
+/* Note if the text cursor of window W has been overwritten by a
+   drawing operation that outputs N glyphs starting at HPOS in the
+   line given by output_cursor.vpos.  N < 0 means all the rest of the
+   line after HPOS has been written.  */
+
+static void
+note_overwritten_text_cursor (w, hpos, n)
+     struct window *w;
+     int hpos, n;
+{
+  if (updated_area == TEXT_AREA
+      && output_cursor.vpos == w->phys_cursor.vpos
+      && hpos <= w->phys_cursor.hpos
+      && (n < 0
+         || hpos + n > w->phys_cursor.hpos))
+    w->phys_cursor_on_p = 0;
+}
 
 
-/* Draw a hollow box cursor on frame F at X, Y.
-   Don't change the inside of the box.  */
+/* Set clipping for output in glyph row ROW.  W is the window in which
+   we operate.  GC is the graphics context to set clipping in.
+   WHOLE_LINE_P non-zero means include the areas used for truncation
+   mark display and alike in the clipping rectangle.
+
+   ROW may be a text row or, e.g., a mode line.  Text rows must be
+   clipped to the interior of the window dedicated to text display,
+   mode lines must be clipped to the whole window.  */
 
 static void
-x_draw_box (f, x, y)
-     struct frame *f;
-     int x, y;
+x_clip_to_row (w, row, gc, whole_line_p)
+     struct window *w;
+     struct glyph_row *row;
+     GC gc;
+     int whole_line_p;
 {
-  int left = CHAR_TO_PIXEL_COL (f, x);
-  int top  = CHAR_TO_PIXEL_ROW (f, y);
-  int width = FONT_WIDTH (f->output_data.x->font);
-  int height = f->output_data.x->line_height;
-  int c = FAST_GLYPH_CHAR (f->phys_cursor_glyph);
-  int charset = CHAR_CHARSET (c);
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  XRectangle clip_rect;
+  int window_x, window_y, window_width, window_height;
+
+  window_box (w, -1, &window_x, &window_y, &window_width, &window_height);
+
+  clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0);
+  clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+  clip_rect.y = max (clip_rect.y, window_y);
+  clip_rect.width = window_width;
+  clip_rect.height = row->visible_height;
 
-  /* If cursor is on a multi-column character, multiply WIDTH by columns.  */
-  width *= (charset == CHARSET_COMPOSITION
-           ? cmpchar_table[COMPOSITE_CHAR_ID (c)]->width
-           : CHARSET_WIDTH (charset));
-  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                 f->output_data.x->cursor_gc,
-                 left, top, width - 1, height - 1);
+  /* If clipping to the whole line, including trunc marks, extend
+     the rectangle to the left and increase its width.  */
+  if (whole_line_p)
+    {
+      clip_rect.x -= FRAME_X_LEFT_FLAGS_AREA_WIDTH (f);
+      clip_rect.width += FRAME_X_FLAGS_AREA_WIDTH (f);
+    }
+
+  XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, &clip_rect, 1, Unsorted);
 }
 
-/* Clear the cursor of frame F to background color,
-   and mark the cursor as not shown.
-   This is used when the text where the cursor is
-   is about to be rewritten.  */
+
+/* Draw a hollow box cursor on window W in glyph row ROW.  */
 
 static void
-clear_cursor (f)
-     struct frame *f;
+x_draw_hollow_cursor (w, row)
+     struct window *w;
+     struct glyph_row *row;
 {
-  int mask;
-
-  if (! FRAME_VISIBLE_P (f)
-      || ! f->phys_cursor_on)
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  Display *dpy = FRAME_X_DISPLAY (f);
+  int x, y, wd, h;
+  XGCValues xgcv;
+  struct glyph *cursor_glyph;
+  GC gc;
+
+  /* Compute frame-relative coordinates from window-relative
+     coordinates.  */
+  x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+  y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
+       + row->ascent - w->phys_cursor_ascent);
+  h = row->height - 1;
+
+  /* Get the glyph the cursor is on.  If we can't tell because
+     the current matrix is invalid or such, give up.  */
+  cursor_glyph = get_phys_cursor_glyph (w);
+  if (cursor_glyph == NULL)
     return;
 
-  x_update_cursor (f, 0);
-  f->phys_cursor_on = 0;
+  /* Compute the width of the rectangle to draw.  If on a stretch
+     glyph, and `x-stretch-block-cursor' is nil, don't draw a
+     rectangle as wide as the glyph, but use a canonical character
+     width instead.  */
+  wd = cursor_glyph->pixel_width - 1;
+  if (cursor_glyph->type == STRETCH_GLYPH
+      && !x_stretch_cursor_p)
+    wd = min (CANON_X_UNIT (f), wd);
+  
+  /* The foreground of cursor_gc is typically the same as the normal
+     background color, which can cause the cursor box to be invisible.  */
+  xgcv.foreground = f->output_data.x->cursor_pixel;
+  if (dpyinfo->scratch_cursor_gc)
+    XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv);
+  else
+    dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f),
+                                           GCForeground, &xgcv);
+  gc = dpyinfo->scratch_cursor_gc;
+
+  /* Set clipping, draw the rectangle, and reset clipping again.  */
+  x_clip_to_row (w, row, gc, 0);
+  XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h);
+  XSetClipMask (dpy, gc, None);
 }
 
-/* Redraw the glyph at ROW, COLUMN on frame F, in the style
-   HIGHLIGHT.  HIGHLIGHT is as defined for dumpglyphs.  Return the
-   glyph drawn.  */
+
+/* Draw a bar cursor on window W in glyph row ROW.
+
+   Implementation note: One would like to draw a bar cursor with an
+   angle equal to the one given by the font property XA_ITALIC_ANGLE.
+   Unfortunately, I didn't find a font yet that has this property set.
+   --gerd.  */
 
 static void
-x_draw_single_glyph (f, row, column, glyph, highlight)
-     struct frame *f;
-     int row, column;
-     GLYPH glyph;
-     int highlight;
+x_draw_bar_cursor (w, row)
+     struct window *w;
+     struct glyph_row *row;
 {
-  dumpglyphs (f,
-             CHAR_TO_PIXEL_COL (f, column),
-             CHAR_TO_PIXEL_ROW (f, row),
-             &glyph, 1, highlight, 0, NULL);
+  /* If cursor hpos is out of bounds, don't draw garbage.  This can
+     happen in mini-buffer windows when switching between echo area
+     glyphs and mini-buffer.  */
+  if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+    {
+      struct frame *f = XFRAME (w->frame);
+      struct glyph *cursor_glyph;
+      GC gc;
+      int x;
+      unsigned long mask;
+      XGCValues xgcv;
+      Display *dpy;
+      Window window;
+      
+      cursor_glyph = get_phys_cursor_glyph (w);
+      if (cursor_glyph == NULL)
+       return;
+
+      xgcv.background = f->output_data.x->cursor_pixel;
+      xgcv.foreground = f->output_data.x->cursor_pixel;
+      xgcv.graphics_exposures = 0;
+      mask = GCForeground | GCBackground | GCGraphicsExposures;
+      dpy = FRAME_X_DISPLAY (f);
+      window = FRAME_X_WINDOW (f);
+      gc = FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc;
+      
+      if (gc)
+       XChangeGC (dpy, gc, mask, &xgcv);
+      else
+       {
+         gc = XCreateGC (dpy, window, mask, &xgcv);
+         FRAME_X_DISPLAY_INFO (f)->scratch_cursor_gc = gc;
+       }
+
+      x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+      x_clip_to_row (w, row, gc, 0);
+      XFillRectangle (dpy, window, gc,
+                     x,
+                     WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
+                     min (cursor_glyph->pixel_width,
+                          f->output_data.x->cursor_width),
+                     row->height);
+      XSetClipMask (dpy, gc, None);
+    }
 }
 
+
+/* Clear the cursor of window W to background color, and mark the
+   cursor as not shown.  This is used when the text where the cursor
+   is is about to be rewritten.  */
+
 static void
-x_display_bar_cursor (f, on, x, y)
-     struct frame *f;
-     int on;
-     int x, y;
+x_clear_cursor (w)
+     struct window *w;
 {
-  struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
+  if (FRAME_VISIBLE_P (XFRAME (w->frame)) && w->phys_cursor_on_p)
+    x_update_window_cursor (w, 0);
+}
 
-  /* This is pointless on invisible frames, and dangerous on garbaged
-     frames; in the latter case, the frame may be in the midst of
-     changing its size, and x and y may be off the frame.  */
-  if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
-    return;
 
-  if (! on && ! f->phys_cursor_on)
-    return;
+/* Draw the cursor glyph of window W in glyph row ROW.  See the
+   comment of x_draw_glyphs for the meaning of HL.  */
 
-  /* If there is anything wrong with the current cursor state, remove it.  */
-  if (f->phys_cursor_on
-      && (!on
-         || f->phys_cursor_x != x
-         || f->phys_cursor_y != y
-         || f->output_data.x->current_cursor != bar_cursor))
-    {
-      /* Erase the cursor by redrawing the character underneath it.  */
-      x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
-                          f->phys_cursor_glyph,
-                          current_glyphs->highlight[f->phys_cursor_y]);
-      f->phys_cursor_on = 0;
-    }
-
-  /* If we now need a cursor in the new place or in the new form, do it so.  */
-  if (on
-      && (! f->phys_cursor_on
-         || (f->output_data.x->current_cursor != bar_cursor)))
-    {
-      f->phys_cursor_glyph
-       = ((current_glyphs->enable[y]
-           && x < current_glyphs->used[y])
-          ? current_glyphs->glyphs[y][x]
-          : SPACEGLYPH);
-      XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                     f->output_data.x->cursor_gc,
-                     CHAR_TO_PIXEL_COL (f, x),
-                     CHAR_TO_PIXEL_ROW (f, y),
-                     max (f->output_data.x->cursor_width, 1),
-                     f->output_data.x->line_height);
+static void
+x_draw_phys_cursor_glyph (w, row, hl)
+     struct window *w;
+     struct glyph_row *row;
+     enum draw_glyphs_face hl;
+{
+  /* If cursor hpos is out of bounds, don't draw garbage.  This can
+     happen in mini-buffer windows when switching between echo area
+     glyphs and mini-buffer.  */
+  if (w->phys_cursor.hpos < row->used[TEXT_AREA])
+    {
+      x_draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA,
+                    w->phys_cursor.hpos, w->phys_cursor.hpos + 1,
+                    hl, 0, 0, 0);
+
+      /* When we erase the cursor, and ROW is overlapped by other
+        rows, make sure that these overlapping parts of other rows
+        are redrawn.  */
+      if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
+       {
+         if (row > w->current_matrix->rows
+             && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
+           x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+
+         if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
+             && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
+           x_fix_overlapping_area (w, row + 1, TEXT_AREA);
+       }
+    }
+}
+
+
+/* Erase the image of a cursor of window W from the screen.  */
 
-      f->phys_cursor_x = x;
-      f->phys_cursor_y = y;
-      f->phys_cursor_on = 1;
+static void
+x_erase_phys_cursor (w)
+     struct window *w;
+{
+  struct frame *f = XFRAME (w->frame);
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  int hpos = w->phys_cursor.hpos;
+  int vpos = w->phys_cursor.vpos;
+  int mouse_face_here_p = 0;
+  struct glyph_matrix *active_glyphs = w->current_matrix;
+  struct glyph_row *cursor_row;
+  struct glyph *cursor_glyph;
+  enum draw_glyphs_face hl;
+
+  /* No cursor displayed or row invalidated => nothing to do on the
+     screen.  */
+  if (w->phys_cursor_type == NO_CURSOR)
+    goto mark_cursor_off;
+          
+  /* VPOS >= active_glyphs->nrows means that window has been resized.
+     Don't bother to erase the cursor.  */
+  if (vpos >= active_glyphs->nrows)
+    goto mark_cursor_off;
+
+  /* If row containing cursor is marked invalid, there is nothing we
+     can do.  */
+  cursor_row = MATRIX_ROW (active_glyphs, vpos);
+  if (!cursor_row->enabled_p)
+    goto mark_cursor_off;
+  
+  /* This can happen when the new row is shorter than the old one.
+     In this case, either x_draw_glyphs or clear_end_of_line
+     should have cleared the cursor.  Note that we wouldn't be
+     able to erase the cursor in this case because we don't have a
+     cursor glyph at hand.  */
+  if (w->phys_cursor.hpos >= cursor_row->used[TEXT_AREA])
+    goto mark_cursor_off;
+        
+  /* If the cursor is in the mouse face area, redisplay that when
+     we clear the cursor.  */
+  if (w == XWINDOW (dpyinfo->mouse_face_window)
+      && (vpos > dpyinfo->mouse_face_beg_row
+         || (vpos == dpyinfo->mouse_face_beg_row
+             && hpos >= dpyinfo->mouse_face_beg_col))
+      && (vpos < dpyinfo->mouse_face_end_row
+         || (vpos == dpyinfo->mouse_face_end_row
+             && hpos < dpyinfo->mouse_face_end_col))
+      /* Don't redraw the cursor's spot in mouse face if it is at the
+        end of a line (on a newline).  The cursor appears there, but
+        mouse highlighting does not.  */
+      && cursor_row->used[TEXT_AREA] > hpos)
+    mouse_face_here_p = 1;
+
+  /* Maybe clear the display under the cursor.  */
+  if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
+    {
+      int x;
+      int header_line_height = WINDOW_DISPLAY_HEADER_LINE_HEIGHT (w);
+
+      cursor_glyph = get_phys_cursor_glyph (w);
+      if (cursor_glyph == NULL)
+       goto mark_cursor_off;
 
-      f->output_data.x->current_cursor = bar_cursor;
+      x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x),
+      
+      XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 x,
+                 WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
+                                                  cursor_row->y)),
+                 cursor_glyph->pixel_width,
+                 cursor_row->visible_height,
+                 False);
     }
+  
+  /* Erase the cursor by redrawing the character underneath it.  */
+  if (mouse_face_here_p)
+    hl = DRAW_MOUSE_FACE;
+  else if (cursor_row->inverse_p)
+    hl = DRAW_INVERSE_VIDEO;
+  else
+    hl = DRAW_NORMAL_TEXT;
+  x_draw_phys_cursor_glyph (w, cursor_row, hl);
 
-  if (updating_frame != f)
-    XFlush (FRAME_X_DISPLAY (f));
+ mark_cursor_off:
+  w->phys_cursor_on_p = 0;
+  w->phys_cursor_type = NO_CURSOR;
 }
 
 
-/* Turn the displayed cursor of frame F on or off according to ON.
-   If ON is nonzero, where to put the cursor is specified by X and Y.  */
+/* Display or clear cursor of window W.  If ON is zero, clear the
+   cursor.  If it is non-zero, display the cursor.  If ON is nonzero,
+   where to put the cursor is specified by HPOS, VPOS, X and Y.  */
 
-static void
-x_display_box_cursor (f, on, x, y)
-     struct frame *f;
-     int on;
-     int x, y;
+void
+x_display_and_set_cursor (w, on, hpos, vpos, x, y)
+     struct window *w;
+     int on, hpos, vpos, x, y;
 {
-  struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
+  struct frame *f = XFRAME (w->frame);
+  int new_cursor_type;
+  struct glyph_matrix *current_glyphs;
+  struct glyph_row *glyph_row;
+  struct glyph *glyph;
 
   /* This is pointless on invisible frames, and dangerous on garbaged
-     frames; in the latter case, the frame may be in the midst of
-     changing its size, and x and y may be off the frame.  */
-  if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
+     windows and frames; in the latter case, the frame or window may
+     be in the midst of changing its size, and x and y may be off the
+     window.  */
+  if (! FRAME_VISIBLE_P (f)
+      || FRAME_GARBAGED_P (f)
+      || vpos >= w->current_matrix->nrows
+      || hpos >= w->current_matrix->matrix_w)
     return;
 
   /* If cursor is off and we want it off, return quickly.  */
-  if (!on && ! f->phys_cursor_on)
+  if (!on && !w->phys_cursor_on_p)
     return;
 
-  /* If cursor is currently being shown and we don't want it to be
-     or it is in the wrong place,
-     or we want a hollow box and it's not so, (pout!)
-     erase it.  */
-  if (f->phys_cursor_on
-      && (!on
-         || f->phys_cursor_x != x
-         || f->phys_cursor_y != y
-         || (f->output_data.x->current_cursor != hollow_box_cursor
-             && (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame))))
-    {
-      int mouse_face_here = 0;
-      struct frame_glyphs *active_glyphs = FRAME_CURRENT_GLYPHS (f);
-
-      /* If the cursor is in the mouse face area, redisplay that when
-        we clear the cursor.  */
-      if (f == FRAME_X_DISPLAY_INFO (f)->mouse_face_mouse_frame
-         &&
-         (f->phys_cursor_y > FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
-          || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_row
-              && f->phys_cursor_x >= FRAME_X_DISPLAY_INFO (f)->mouse_face_beg_col))
-         &&
-         (f->phys_cursor_y < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
-          || (f->phys_cursor_y == FRAME_X_DISPLAY_INFO (f)->mouse_face_end_row
-              && f->phys_cursor_x < FRAME_X_DISPLAY_INFO (f)->mouse_face_end_col))
-         /* Don't redraw the cursor's spot in mouse face
-            if it is at the end of a line (on a newline).
-            The cursor appears there, but mouse highlighting does not.  */
-         && active_glyphs->used[f->phys_cursor_y] > f->phys_cursor_x)
-       mouse_face_here = 1;
-
-      /* If the font is not as tall as a whole line,
-        we must explicitly clear the line's whole height.  */
-      if (FONT_HEIGHT (f->output_data.x->font) != f->output_data.x->line_height)
-       XClearArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                   CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
-                   CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
-                   FONT_WIDTH (f->output_data.x->font),
-                   f->output_data.x->line_height, False);
-      /* Erase the cursor by redrawing the character underneath it.  */
-      x_draw_single_glyph (f, f->phys_cursor_y, f->phys_cursor_x,
-                          f->phys_cursor_glyph,
-                          (mouse_face_here
-                           ? 3
-                           : current_glyphs->highlight[f->phys_cursor_y]));
-      f->phys_cursor_on = 0;
-    }
-
-  /* If we want to show a cursor,
-     or we want a box cursor and it's not so,
-     write it in the right place.  */
-  if (on
-      && (! f->phys_cursor_on
-         || (f->output_data.x->current_cursor != filled_box_cursor
-             && f == FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)))
-    {
-      f->phys_cursor_glyph
-       = ((current_glyphs->enable[y]
-           && x < current_glyphs->used[y])
-          ? current_glyphs->glyphs[y][x]
-          : SPACEGLYPH);
-      if (f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
+  current_glyphs = w->current_matrix;
+  glyph_row = MATRIX_ROW (current_glyphs, vpos);
+  glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+  
+  /* If cursor row is not enabled, we don't really know where to 
+     display the cursor.  */
+  if (!glyph_row->enabled_p)
+    {
+      w->phys_cursor_on_p = 0;
+      return;
+    }
+
+  xassert (interrupt_input_blocked);
+
+  /* Set new_cursor_type to the cursor we want to be displayed.  In a
+     mini-buffer window, we want the cursor only to appear if we are
+     reading input from this window.  For the selected window, we want
+     the cursor type given by the frame parameter.  If explicitly
+     marked off, draw no cursor.  In all other cases, we want a hollow
+     box cursor.  */
+  if (cursor_in_echo_area
+      && FRAME_HAS_MINIBUF_P (f)
+      && EQ (FRAME_MINIBUF_WINDOW (f), echo_area_window))
+    {
+      if (w == XWINDOW (echo_area_window))
+       new_cursor_type = FRAME_DESIRED_CURSOR (f);
+      else
+       new_cursor_type = HOLLOW_BOX_CURSOR;
+    }
+  else
+    {
+      if (w != XWINDOW (selected_window)
+         || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame)
        {
-         x_draw_box (f, x, y);
-         f->output_data.x->current_cursor = hollow_box_cursor;
+         if (MINI_WINDOW_P (w))
+           new_cursor_type = NO_CURSOR;
+         else
+           new_cursor_type = HOLLOW_BOX_CURSOR;
        }
+      else if (w->cursor_off_p)
+       new_cursor_type = NO_CURSOR;
       else
+       new_cursor_type = FRAME_DESIRED_CURSOR (f);
+    }
+
+  /* If cursor is currently being shown and we don't want it to be or
+     it is in the wrong place, or the cursor type is not what we want,
+     erase it.  */
+  if (w->phys_cursor_on_p
+      && (!on
+         || w->phys_cursor.x != x
+         || w->phys_cursor.y != y
+         || new_cursor_type != w->phys_cursor_type))
+    x_erase_phys_cursor (w);
+
+  /* If the cursor is now invisible and we want it to be visible,
+     display it.  */
+  if (on && !w->phys_cursor_on_p)
+    {
+      w->phys_cursor_ascent = glyph_row->ascent;
+      w->phys_cursor_height = glyph_row->height;
+      
+      /* Set phys_cursor_.* before x_draw_.* is called because some
+        of them may need the information.  */
+      w->phys_cursor.x = x;
+      w->phys_cursor.y = glyph_row->y;
+      w->phys_cursor.hpos = hpos;
+      w->phys_cursor.vpos = vpos;
+      w->phys_cursor_type = new_cursor_type;
+      w->phys_cursor_on_p = 1;
+
+      switch (new_cursor_type)
        {
-         x_draw_single_glyph (f, y, x,
-                              f->phys_cursor_glyph, 2);
-         f->output_data.x->current_cursor = filled_box_cursor;
-       }
+       case HOLLOW_BOX_CURSOR:
+         x_draw_hollow_cursor (w, glyph_row);
+         break;
+
+       case FILLED_BOX_CURSOR:
+         x_draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+         break;
 
-      f->phys_cursor_x = x;
-      f->phys_cursor_y = y;
-      f->phys_cursor_on = 1;
+       case BAR_CURSOR:
+         x_draw_bar_cursor (w, glyph_row);
+         break;
+
+       case NO_CURSOR:
+         break;
+
+       default:
+         abort ();
+       }
     }
 
+#ifndef XFlush
   if (updating_frame != f)
     XFlush (FRAME_X_DISPLAY (f));
+#endif
 }
 
-/* Display the cursor on frame F, or clear it, according to ON.
-   Also set the frame's cursor position to X and Y.  */
 
-x_display_cursor (f, on, x, y)
-     struct frame *f;
-     int on;
-     int x, y;
+/* Display the cursor on window W, or clear it.  X and Y are window
+   relative pixel coordinates.  HPOS and VPOS are glyph matrix
+   positions.  If W is not the selected window, display a hollow
+   cursor.  ON non-zero means display the cursor at X, Y which
+   correspond to HPOS, VPOS, otherwise it is cleared.  */
+
+void
+x_display_cursor (w, on, hpos, vpos, x, y)
+     struct window *w;
+     int on, hpos, vpos, x, y;
 {
   BLOCK_INPUT;
-
-  if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
-    x_display_box_cursor (f, on, x, y);
-  else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
-    x_display_bar_cursor (f, on, x, y);
-  else
-    /* Those are the only two we have implemented!  */
-    abort ();
-
+  x_display_and_set_cursor (w, on, hpos, vpos, x, y);
   UNBLOCK_INPUT;
 }
 
-/* Display the cursor on frame F, or clear it, according to ON.
+
+/* Display the cursor on window W, or clear it, according to ON_P.
    Don't change the cursor's position.  */
 
-x_update_cursor (f, on)
+void
+x_update_cursor (f, on_p)
      struct frame *f;
-     int on;
 {
-  BLOCK_INPUT;
+  x_update_cursor_in_window_tree (XWINDOW (f->root_window), on_p);
+}
 
-  if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
-    x_display_box_cursor (f, on, f->phys_cursor_x, f->phys_cursor_y);
-  else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
-    x_display_bar_cursor (f, on, f->phys_cursor_x, f->phys_cursor_y);
-  else
-    /* Those are the only two we have implemented!  */
-    abort ();
 
+/* Call x_update_window_cursor with parameter ON_P on all leaf windows
+   in the window tree rooted at W.  */
+
+static void
+x_update_cursor_in_window_tree (w, on_p)
+     struct window *w;
+     int on_p;
+{
+  while (w)
+    {
+      if (!NILP (w->hchild))
+       x_update_cursor_in_window_tree (XWINDOW (w->hchild), on_p);
+      else if (!NILP (w->vchild))
+       x_update_cursor_in_window_tree (XWINDOW (w->vchild), on_p);
+      else
+       x_update_window_cursor (w, on_p);
+
+      w = NILP (w->next) ? 0 : XWINDOW (w->next);
+    }
+}
+
+
+/* Switch the display of W's cursor on or off, according to the value
+   of ON.  */
+
+static void
+x_update_window_cursor (w, on)
+     struct window *w;
+     int on;
+{
+  BLOCK_INPUT;
+  x_display_and_set_cursor (w, on, w->phys_cursor.hpos, w->phys_cursor.vpos,
+                           w->phys_cursor.x, w->phys_cursor.y);
   UNBLOCK_INPUT;
 }
+
+
+
 \f
 /* Icons.  */
 
 /* Refresh bitmap kitchen sink icon for frame F
-   when we get an expose event for it. */
+   when we get an expose event for it.  */
 
+void
 refreshicon (f)
      struct frame *f;
 {
-  /* Normally, the window manager handles this function. */
+  /* Normally, the window manager handles this function.  */
 }
 
 /* Make the x-window of frame F use the gnu icon bitmap.  */
@@ -4859,8 +10252,7 @@ x_bitmap_icon (f, file)
      struct frame *f;
      Lisp_Object file;
 {
-  int mask, bitmap_id;
-  Window icon_window;
+  int bitmap_id;
 
   if (FRAME_X_WINDOW (f) == 0)
     return 1;
@@ -4881,7 +10273,7 @@ x_bitmap_icon (f, file)
                                       gnu_width, gnu_height);
 
       /* The first time we create the GNU bitmap,
-        this increments the refcount one extra time.
+        this increments the ref-count one extra time.
         As a result, the GNU bitmap is never freed.
         That way, we don't have to worry about allocating it again.  */
       x_reference_bitmap (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id);
@@ -4944,7 +10336,7 @@ static Lisp_Object x_error_message_string;
    x_error_message_string.  This is called from x_error_handler if
    x_catch_errors is in effect.  */
 
-static int
+static void
 x_error_catcher (display, error)
      Display *display;
      XErrorEvent *error;
@@ -5028,7 +10420,7 @@ x_had_errors_p (dpy)
 
 /* Forget about any errors we have had, since we did x_catch_errors on DPY.  */
 
-int
+void
 x_clear_errors (dpy)
      Display *dpy;
 {
@@ -5061,11 +10453,11 @@ x_trace_wire ()
    simply goes away.  SIGPIPE is handled by x_connection_signal.
    Don't need to do anything, because the write which caused the 
    SIGPIPE will fail, causing Xlib to invoke the X IO error handler,
-   which will do the appropriate cleanup for us. */
+   which will do the appropriate cleanup for us.  */
    
 static SIGTYPE
 x_connection_signal (signalnum)        /* If we don't have an argument, */
-     int signalnum;            /* some compilers complain in signal calls. */
+     int signalnum;            /* some compilers complain in signal calls.  */
 {
 #ifdef USG
   /* USG systems forget handlers when they are used;
@@ -5094,7 +10486,7 @@ x_connection_closed (display, error_message)
 
   dpyinfo->display = 0;
 
-  /* First delete frames whose minibuffers are on frames
+  /* First delete frames whose mini-buffers are on frames
      that are on the dead display.  */
   FOR_EACH_FRAME (tail, frame)
     {
@@ -5109,7 +10501,7 @@ x_connection_closed (display, error_message)
     }
 
   /* Now delete all remaining frames on the dead display.
-     We are now sure none of these is used as the minibuffer
+     We are now sure none of these is used as the mini-buffer
      for another frame that we need to delete.  */
   FOR_EACH_FRAME (tail, frame)
     if (FRAME_X_P (XFRAME (frame))
@@ -5146,7 +10538,7 @@ x_connection_closed (display, error_message)
    It kills all frames on the display that we got the error for.
    If that was the only one, it prints an error message and kills Emacs.  */
 
-static int
+static void
 x_error_quitter (display, error)
      Display *display;
      XErrorEvent *error;
@@ -5170,12 +10562,11 @@ x_error_handler (display, error)
      Display *display;
      XErrorEvent *error;
 {
-  char buf[256], buf1[356];
-
   if (! NILP (x_error_message_string))
     x_error_catcher (display, error);
   else
     x_error_quitter (display, error);
+  return 0;
 }
 
 /* This is the handler for X IO errors, always.
@@ -5190,6 +10581,7 @@ x_io_error_quitter (display)
 
   sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
   x_connection_closed (display, buf);
+  return 0;
 }
 \f
 /* Changing the font of the frame.  */
@@ -5222,7 +10614,10 @@ x_new_font (f, fontname)
       f->scroll_bar_cols = (f->scroll_bar_pixel_width + wid-1) / wid;
     }
   else
-    f->scroll_bar_cols = 2;
+    {
+      int wid = FONT_WIDTH (f->output_data.x->font);
+      f->scroll_bar_cols = (14 + wid - 1) / wid;
+    }
 
   /* Now make the frame display the given font.  */
   if (FRAME_X_WINDOW (f) != 0)
@@ -5282,7 +10677,7 @@ x_new_fontset (f, fontsetname)
   /* Since x_new_font doesn't update any fontset information, do it now.  */
   f->output_data.x->fontset = fontset;
   FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f),
-               CHARSET_ASCII, XSTRING (result)->data, fontset);
+               CHARSET_ASCII, fontsetp->fontname[CHARSET_ASCII], fontset);
 
   return build_string (fontsetname);
 }
@@ -5290,10 +10685,11 @@ x_new_fontset (f, fontsetname)
 /* Calculate the absolute position in frame F
    from its current recorded position values and gravity.  */
 
+void
 x_calc_absolute_position (f)
      struct frame *f;
 {
-  Window win, child;
+  Window child;
   int win_x = 0, win_y = 0;
   int flags = f->output_data.x->size_hint_flags;
   int this_window;
@@ -5342,7 +10738,7 @@ x_calc_absolute_position (f)
                                &newparent, &newchildren, &nchildren))
                break;
 
-             XFree (newchildren);
+             XFree ((char *) newchildren);
 
              f->output_data.x->parent_desc = newparent;
            }
@@ -5363,12 +10759,23 @@ x_calc_absolute_position (f)
                                  + f->output_data.x->left_pos);
 
   if (flags & YNegative)
-    /* We used to subtract f->output_data.x->menubar_height here
-       in the toolkit case, but PIXEL_HEIGHT already includes that.  */
-    f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
-                                - 2 * f->output_data.x->border_width - win_y
-                                - PIXEL_HEIGHT (f)
-                                + f->output_data.x->top_pos);
+    {
+      int menubar_height = 0;
+
+#ifdef USE_X_TOOLKIT
+      if (f->output_data.x->menubar_widget)
+       menubar_height
+         = (f->output_data.x->menubar_widget->core.height
+            + f->output_data.x->menubar_widget->core.border_width);
+#endif
+      
+      f->output_data.x->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
+                                  - 2 * f->output_data.x->border_width
+                                  - win_y
+                                  - PIXEL_HEIGHT (f)
+                                  - menubar_height
+                                  + f->output_data.x->top_pos);
+    }
 
   /* The left_pos and top_pos
      are now relative to the top and left screen edges,
@@ -5382,6 +10789,7 @@ x_calc_absolute_position (f)
    position values).  It is -1 when calling from x_set_frame_parameters,
    which means, do adjust for borders but don't change the gravity.  */
 
+void
 x_set_offset (f, xoff, yoff, change_gravity)
      struct frame *f;
      register int xoff, yoff;
@@ -5433,14 +10841,15 @@ x_set_offset (f, xoff, yoff, change_gravity)
    for this size change and subsequent size changes.
    Otherwise we leave the window gravity unchanged.  */
 
+void
 x_set_window_size (f, change_gravity, cols, rows)
      struct frame *f;
      int change_gravity;
      int cols, rows;
 {
+#ifndef USE_X_TOOLKIT
   int pixelwidth, pixelheight;
-  int mask;
-  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+#endif
 
   BLOCK_INPUT;
 
@@ -5466,6 +10875,8 @@ x_set_window_size (f, change_gravity, cols, rows)
        : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
        ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
        : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.x->font)));
+  f->output_data.x->flags_areas_extra
+    = FRAME_FLAGS_AREA_WIDTH (f);
   pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
   pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
 
@@ -5483,10 +10894,13 @@ x_set_window_size (f, change_gravity, cols, rows)
 
      We could just not bother storing any of this information here,
      and let the ConfigureNotify event set everything up, but that
-     might be kind of confusing to the lisp code, since size changes
+     might be kind of confusing to the Lisp code, since size changes
      wouldn't be reported in the frame parameters until some random
-     point in the future when the ConfigureNotify event arrives.  */
-  change_frame_size (f, rows, cols, 0, 0);
+     point in the future when the ConfigureNotify event arrives.
+
+     We pass 1 for DELAY since we can't run Lisp code inside of
+     a BLOCK_INPUT.  */
+  change_frame_size (f, rows, cols, 0, 1, 0);
   PIXEL_WIDTH (f) = pixelwidth;
   PIXEL_HEIGHT (f) = pixelheight;
 
@@ -5501,13 +10915,7 @@ x_set_window_size (f, change_gravity, cols, rows)
 #endif /* not USE_X_TOOLKIT */
 
   /* If cursor was outside the new size, mark it as off.  */
-  if (f->phys_cursor_y >= rows
-      || f->phys_cursor_x >= cols)
-    {
-      f->phys_cursor_x = 0;
-      f->phys_cursor_y = 0;
-      f->phys_cursor_on = 0;
-    }
+  mark_window_cursors_off (XWINDOW (f->root_window));
 
   /* Clear out any recollection of where the mouse highlighting was,
      since it might be in a place that's outside the new frame size. 
@@ -5559,6 +10967,7 @@ x_set_mouse_pixel_position (f, pix_x, pix_y)
 \f
 /* focus shifting, raising and lowering.  */
 
+void
 x_focus_on_frame (f)
      struct frame *f;
 {
@@ -5574,6 +10983,7 @@ x_focus_on_frame (f)
 #endif /* ! 0 */
 }
 
+void
 x_unfocus_frame (f)
      struct frame *f;
 {
@@ -5587,6 +10997,7 @@ x_unfocus_frame (f)
 
 /* Raise frame F.  */
 
+void
 x_raise_frame (f)
      struct frame *f;
 {
@@ -5605,6 +11016,7 @@ x_raise_frame (f)
 
 /* Lower frame F.  */
 
+void
 x_lower_frame (f)
      struct frame *f;
 {
@@ -5641,12 +11053,11 @@ XTframe_raise_lower (f, raise_flag)
    but it will become visible later when the window manager
    finishes with it.  */
 
+void
 x_make_frame_visible (f)
      struct frame *f;
 {
-  int mask;
   Lisp_Object type;
-  int starting_flags = f->output_data.x->size_hint_flags;
   int original_top, original_left;
 
   BLOCK_INPUT;
@@ -5702,7 +11113,7 @@ x_make_frame_visible (f)
     /* This must come after we set COUNT.  */
     UNBLOCK_INPUT;
 
-    /* Arriving X events are processed here.  */
+    /* We unblock here so that arriving X events are processed.  */
 
     /* Now move the window back to where it was "supposed to be".
        But don't do it if the gravity is negative.
@@ -5717,15 +11128,26 @@ x_make_frame_visible (f)
        && f->output_data.x->win_gravity == NorthWestGravity
        && previously_visible)
       {
+       Drawable rootw;
+       int x, y;
+       unsigned int width, height, border, depth;
+       
        BLOCK_INPUT;
 
-#ifdef USE_X_TOOLKIT
-       XMoveWindow (FRAME_X_DISPLAY (f), XtWindow (f->output_data.x->widget),
-                    original_left, original_top);
-#else /* not USE_X_TOOLKIT */
-       XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    original_left, original_top);
-#endif /* not USE_X_TOOLKIT */
+       /* On some window managers (such as FVWM) moving an existing
+          window, even to the same place, causes the window manager
+          to introduce an offset.  This can cause the window to move
+          to an unexpected location.  Check the geometry (a little
+          slow here) and then verify that the window is in the right
+          place.  If the window is not in the right place, move it
+          there, and take the potential window manager hit.  */
+       XGetGeometry (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                     &rootw, &x, &y, &width, &height, &border, &depth);
+
+       if (original_left != x || original_top != y)
+         XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+                      original_left, original_top);
+
        UNBLOCK_INPUT;
       }
 
@@ -5751,7 +11173,7 @@ x_make_frame_visible (f)
            /* It could be confusing if a real alarm arrives while processing
               the fake one.  Turn it off and let the handler reset it.  */
            alarm (0);
-           input_poll_signal ();
+           input_poll_signal (0);
          }
        /* Once we have handled input events,
           we should have received the MapNotify if one is coming.
@@ -5765,14 +11187,14 @@ x_make_frame_visible (f)
   }
 }
 
-/* Change from mapped state to withdrawn state. */
+/* Change from mapped state to withdrawn state.  */
 
 /* Make the frame visible (mapped and not iconified).  */
 
+void
 x_make_frame_invisible (f)
      struct frame *f;
 {
-  int mask;
   Window window;
 
 #ifdef USE_X_TOOLKIT
@@ -5822,7 +11244,7 @@ x_make_frame_invisible (f)
       if (! XSendEvent (FRAME_X_DISPLAY (f),
                        DefaultRootWindow (FRAME_X_DISPLAY (f)),
                        False,
-                       SubstructureRedirectMask|SubstructureNotifyMask,
+                       SubstructureRedirectMaskSubstructureNotifyMask,
                        &unmap))
        {
          UNBLOCK_INPUT_RESIGNAL;
@@ -5849,12 +11271,12 @@ x_make_frame_invisible (f)
   UNBLOCK_INPUT;
 }
 
-/* Change window state from mapped to iconified. */
+/* Change window state from mapped to iconified.  */
 
+void
 x_iconify_frame (f)
      struct frame *f;
 {
-  int mask;
   int result;
   Lisp_Object type;
 
@@ -5959,6 +11381,7 @@ x_iconify_frame (f)
 \f
 /* Destroy the X window of frame F.  */
 
+void
 x_destroy_window (f)
      struct frame *f;
 {
@@ -5986,7 +11409,8 @@ x_destroy_window (f)
 #endif
       XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->window_desc);
 #ifdef USE_X_TOOLKIT
-      XtDestroyWidget (f->output_data.x->widget);
+      if (f->output_data.x->widget)
+       XtDestroyWidget (f->output_data.x->widget);
       free_frame_menubar (f);
 #endif /* USE_X_TOOLKIT */
 
@@ -5995,7 +11419,7 @@ x_destroy_window (f)
     }
 
   if (f->output_data.x->saved_menu_event)
-    free (f->output_data.x->saved_menu_event);
+    xfree (f->output_data.x->saved_menu_event);
 
   xfree (f->output_data.x);
   f->output_data.x = 0;
@@ -6015,6 +11439,8 @@ x_destroy_window (f)
       dpyinfo->mouse_face_end_row
        = dpyinfo->mouse_face_end_col = -1;
       dpyinfo->mouse_face_window = Qnil;
+      dpyinfo->mouse_face_deferred_gc = 0;
+      dpyinfo->mouse_face_mouse_frame = 0;
     }
 
   UNBLOCK_INPUT;
@@ -6028,6 +11454,7 @@ x_destroy_window (f)
    If USER_POSITION is nonzero, we set the USPosition
    flag (this is useful when FLAGS is 0).  */
 
+void
 x_wm_set_size_hint (f, flags, user_position)
      struct frame *f;
      long flags;
@@ -6047,8 +11474,6 @@ x_wm_set_size_hint (f, flags, user_position)
   /* Setting PMaxSize caused various problems.  */
   size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
 
-  flexlines = f->height;
-
   size_hints.x = f->output_data.x->left_pos;
   size_hints.y = f->output_data.x->top_pos;
 
@@ -6150,7 +11575,9 @@ x_wm_set_size_hint (f, flags, user_position)
       }
   }
 
+#ifndef USE_X_TOOLKIT
  no_read:
+#endif
 
 #ifdef PWinGravity
   size_hints.win_gravity = f->output_data.x->win_gravity;
@@ -6171,6 +11598,8 @@ x_wm_set_size_hint (f, flags, user_position)
 }
 
 /* Used for IconicState or NormalState */
+
+void
 x_wm_set_window_state (f, state)
      struct frame *f;
      int state;
@@ -6190,15 +11619,14 @@ x_wm_set_window_state (f, state)
 #endif /* not USE_X_TOOLKIT */
 }
 
+void
 x_wm_set_icon_pixmap (f, pixmap_id)
      struct frame *f;
      int pixmap_id;
 {
   Pixmap icon_pixmap;
 
-#ifdef USE_X_TOOLKIT
-  Window window = XtWindow (f->output_data.x->widget);
-#else
+#ifndef USE_X_TOOLKIT
   Window window = FRAME_X_WINDOW (f);
 #endif
 
@@ -6239,6 +11667,7 @@ x_wm_set_icon_pixmap (f, pixmap_id)
 #endif /* not USE_X_TOOLKIT */
 }
 
+void
 x_wm_set_icon_position (f, icon_x, icon_y)
      struct frame *f;
      int icon_x, icon_y;
@@ -6257,9 +11686,12 @@ x_wm_set_icon_position (f, icon_x, icon_y)
 }
 
 \f
-/* Interface to fontset handler.  */
+/***********************************************************************
+                               Fonts
+ ***********************************************************************/
 
 /* Return a pointer to struct font_info of font FONT_IDX of frame F.  */
+
 struct font_info *
 x_get_font_info (f, font_idx)
      FRAME_PTR f;
@@ -6282,21 +11714,31 @@ x_list_fonts (f, pattern, size, maxnames)
      int size;
      int maxnames;
 {
-  Lisp_Object list = Qnil, patterns, newlist = Qnil, key, tem, second_best;
+  Lisp_Object list = Qnil, patterns, newlist = Qnil, key = Qnil;
+  Lisp_Object tem, second_best;
   Display *dpy = f != NULL ? FRAME_X_DISPLAY (f) : x_display_list->display;
+  int try_XLoadQueryFont = 0;
+  int count;
 
-  patterns = Fassoc (pattern, Valternative_fontname_alist);
+  patterns = Fassoc (pattern, Valternate_fontname_alist);
   if (NILP (patterns))
     patterns = Fcons (pattern, Qnil);
 
-  for (; CONSP (patterns); patterns = XCONS (patterns)->cdr)
+  if (maxnames == 1 && !size)
+    /* We can return any single font matching PATTERN.  */
+    try_XLoadQueryFont = 1;
+
+  for (; CONSP (patterns); patterns = XCDR (patterns))
     {
       int num_fonts;
       char **names;
 
-      pattern = XCONS (patterns)->car;
-      /* See if we cached the result for this particular query.  */
-      if (f && (tem = XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr,
+      pattern = XCAR (patterns);
+      /* See if we cached the result for this particular query.
+         The cache is an alist of the form:
+          (((PATTERN . MAXNAMES) (FONTNAME . WIDTH) ...) ...)
+      */
+      if (f && (tem = XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element),
                key = Fcons (pattern, make_number (maxnames)),
                !NILP (list = Fassoc (key, tem))))
        {
@@ -6306,8 +11748,70 @@ x_list_fonts (f, pattern, size, maxnames)
        }
 
       /* At first, put PATTERN in the cache.  */
+
       BLOCK_INPUT;
-      names = XListFonts (dpy, XSTRING (pattern)->data, maxnames, &num_fonts);
+      count = x_catch_errors (dpy);
+
+      if (try_XLoadQueryFont)
+       {
+         XFontStruct *font;
+         unsigned long value;
+
+         font = XLoadQueryFont (dpy, XSTRING (pattern)->data);
+         if (x_had_errors_p (dpy))
+           {
+             /* This error is perhaps due to insufficient memory on X
+                 server.  Let's just ignore it.  */
+             font = NULL;
+             x_clear_errors (dpy);
+           }
+
+         if (font
+             && XGetFontProperty (font, XA_FONT, &value))
+           {
+             char *name = (char *) XGetAtomName (dpy, (Atom) value);
+             int len = strlen (name);
+             char *tmp;
+
+             /* If DXPC (a Differential X Protocol Compressor)
+                 Ver.3.7 is running, XGetAtomName will return null
+                 string.  We must avoid such a name.  */
+             if (len == 0)
+               try_XLoadQueryFont = 0;
+             else
+               {
+                 num_fonts = 1;
+                 names = (char **) alloca (sizeof (char *));
+                 /* Some systems only allow alloca assigned to a
+                     simple var.  */
+                 tmp = (char *) alloca (len + 1);  names[0] = tmp;
+                 bcopy (name, names[0], len + 1);
+                 XFree (name);
+               }
+           }
+         else
+           try_XLoadQueryFont = 0;
+
+         if (font)
+           XFreeFont (dpy, font);
+       }
+
+      if (!try_XLoadQueryFont)
+       {
+         /* We try at least 10 fonts because XListFonts will return
+            auto-scaled fonts at the head.  */
+         names = XListFonts (dpy, XSTRING (pattern)->data, max (maxnames, 10),
+                             &num_fonts);
+         if (x_had_errors_p (dpy))
+           {
+             /* This error is perhaps due to insufficient memory on X
+                 server.  Let's just ignore it.  */
+             names = NULL;
+             x_clear_errors (dpy);
+           }
+       }
+
+      x_uncatch_errors (dpy, count);
       UNBLOCK_INPUT;
 
       if (names)
@@ -6318,9 +11822,10 @@ x_list_fonts (f, pattern, size, maxnames)
             Store that in the font cache for the display.  */
          for (i = 0; i < num_fonts; i++)
            {
+             int width = 0;
              char *p = names[i];
-             int average_width = -1, dashes = 0, width = 0;
-
+             int average_width = -1, dashes = 0;
+             
              /* Count the number of dashes in NAMES[I].  If there are
                14 dashes, and the field value following 12th dash
                (AVERAGE_WIDTH) is 0, this is a auto-scaled font which
@@ -6353,76 +11858,96 @@ x_list_fonts (f, pattern, size, maxnames)
                    }
                }
            }
-         XFreeFontNames (names);
+         if (!try_XLoadQueryFont)
+           XFreeFontNames (names);
        }
 
       /* Now store the result in the cache.  */
       if (f != NULL)
-       XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr
+       XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element)
          = Fcons (Fcons (key, list),
-                  XCONS (FRAME_X_DISPLAY_INFO (f)->name_list_element)->cdr);
+                  XCDR (FRAME_X_DISPLAY_INFO (f)->name_list_element));
 
     label_cached:
       if (NILP (list)) continue; /* Try the remaining alternatives.  */
 
       newlist = second_best = Qnil;
       /* Make a list of the fonts that have the right width.  */
-      for (; CONSP (list); list = XCONS (list)->cdr)
+      for (; CONSP (list); list = XCDR (list))
        {
-         tem = XCONS (list)->car;
+         int found_size;
+
+         tem = XCAR (list);
 
-         if (!CONSP (tem) || NILP (XCONS (tem)->car))
+         if (!CONSP (tem) || NILP (XCAR (tem)))
            continue;
          if (!size)
            {
-             newlist = Fcons (XCONS (tem)->car, newlist);
+             newlist = Fcons (XCAR (tem), newlist);
              continue;
            }
 
-         if (!INTEGERP (XCONS (tem)->cdr))
+         if (!INTEGERP (XCDR (tem)))
            {
              /* Since we have not yet known the size of this font, we
                must try slow function call XLoadQueryFont.  */
              XFontStruct *thisinfo;
 
              BLOCK_INPUT;
+             count = x_catch_errors (dpy);
              thisinfo = XLoadQueryFont (dpy,
-                                        XSTRING (XCONS (tem)->car)->data);
+                                        XSTRING (XCAR (tem))->data);
+             if (x_had_errors_p (dpy))
+               {
+                 /* This error is perhaps due to insufficient memory on X
+                    server.  Let's just ignore it.  */
+                 thisinfo = NULL;
+                 x_clear_errors (dpy);
+               }
+             x_uncatch_errors (dpy, count);
              UNBLOCK_INPUT;
 
              if (thisinfo)
                {
-                 XCONS (tem)->cdr =  make_number (thisinfo->max_bounds.width);
+                 XCDR (tem)
+                   = (thisinfo->min_bounds.width == 0
+                      ? make_number (0)
+                      : make_number (thisinfo->max_bounds.width));
                  XFreeFont (dpy, thisinfo);
                }
              else
                /* For unknown reason, the previous call of XListFont had
-                 retruned a font which can't be opened.  Record the size
+                 returned a font which can't be opened.  Record the size
                  as 0 not to try to open it again.  */
-               XCONS (tem)->cdr = make_number (0);
-           }
-         if (XINT (XCONS (tem)->cdr) == size)
-           newlist = Fcons (XCONS (tem)->car, newlist);
-         else if (NILP (second_best))
-           second_best = tem;
-         else if (XINT (XCONS (tem)->cdr) < size)
-           {
-             if (XINT (XCONS (second_best)->cdr) > size
-                 || XINT (XCONS (second_best)->cdr) < XINT (XCONS (tem)->cdr))
-               second_best = tem;
+               XCDR (tem) = make_number (0);
            }
-         else
+
+         found_size = XINT (XCDR (tem));
+         if (found_size == size)
+           newlist = Fcons (XCAR (tem), newlist);
+         else if (found_size > 0)
            {
-             if (XINT (XCONS (second_best)->cdr) > size
-                 && XINT (XCONS (second_best)->cdr) > XINT (XCONS (tem)->cdr))
+             if (NILP (second_best))
                second_best = tem;
+             else if (found_size < size)
+               {
+                 if (XINT (XCDR (second_best)) > size
+                     || XINT (XCDR (second_best)) < found_size)
+                   second_best = tem;
+               }
+             else
+               {
+                 if (XINT (XCDR (second_best)) > size
+                     && XINT (XCDR (second_best)) > found_size)
+                   second_best = tem;
+               }
            }
        }
       if (!NILP (newlist))
        break;
       else if (!NILP (second_best))
        {
-         newlist = Fcons (XCONS (second_best)->car, Qnil);
+         newlist = Fcons (XCAR (second_best), Qnil);
          break;
        }
     }
@@ -6430,6 +11955,96 @@ x_list_fonts (f, pattern, size, maxnames)
   return newlist;
 }  
 
+
+#if GLYPH_DEBUG
+
+/* Check that FONT is valid on frame F.  It is if it can be found in F's
+   font table.  */
+
+static void
+x_check_font (f, font)
+     struct frame *f;
+     XFontStruct *font;
+{
+  int i;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+
+  xassert (font != NULL);
+
+  for (i = 0; i < dpyinfo->n_fonts; i++)
+    if (dpyinfo->font_table[i].name 
+       && font == dpyinfo->font_table[i].font)
+      break;
+
+  xassert (i < dpyinfo->n_fonts);
+}
+
+#endif /* GLYPH_DEBUG != 0 */
+
+/* Set *W to the minimum width, *H to the minimum font height of FONT.
+   Note: There are (broken) X fonts out there with invalid XFontStruct
+   min_bounds contents.  For example, handa@etl.go.jp reports that
+   "-adobe-courier-medium-r-normal--*-180-*-*-m-*-iso8859-1" fonts
+   have font->min_bounds.width == 0.  */
+
+static INLINE void
+x_font_min_bounds (font, w, h)
+     XFontStruct *font;
+     int *w, *h;
+{
+  *h = FONT_HEIGHT (font);
+  *w = font->min_bounds.width;
+
+  /* Try to handle the case where FONT->min_bounds has invalid
+     contents.  Since the only font known to have invalid min_bounds
+     is fixed-width, use max_bounds if min_bounds seems to be invalid.  */
+  if (*w <= 0)
+    *w = font->max_bounds.width;
+}
+
+
+/* Compute the smallest character width and smallest font height over
+   all fonts available on frame F.  Set the members smallest_char_width
+   and smallest_font_height in F's x_display_info structure to
+   the values computed.  Value is non-zero if smallest_font_height or
+   smallest_char_width become smaller than they were before.  */
+
+static int
+x_compute_min_glyph_bounds (f)
+     struct frame *f;
+{
+  int i;
+  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
+  XFontStruct *font;
+  int old_width = dpyinfo->smallest_char_width;
+  int old_height = dpyinfo->smallest_font_height;
+  
+  dpyinfo->smallest_font_height = 100000;
+  dpyinfo->smallest_char_width = 100000;
+  
+  for (i = 0; i < dpyinfo->n_fonts; ++i)
+    if (dpyinfo->font_table[i].name)
+      {
+       struct font_info *fontp = dpyinfo->font_table + i;
+       int w, h;
+       
+       font = (XFontStruct *) fontp->font;
+       xassert (font != (XFontStruct *) ~0);
+       x_font_min_bounds (font, &w, &h);
+       
+       dpyinfo->smallest_font_height = min (dpyinfo->smallest_font_height, h);
+       dpyinfo->smallest_char_width = min (dpyinfo->smallest_char_width, w);
+      }
+
+  xassert (dpyinfo->smallest_char_width > 0
+          && dpyinfo->smallest_font_height > 0);
+
+  return (dpyinfo->n_fonts == 1
+         || dpyinfo->smallest_char_width < old_width
+         || dpyinfo->smallest_font_height < old_height);
+}
+
+
 /* Load font named FONTNAME of the size SIZE for frame F, and return a
    pointer to the structure font_info while allocating it dynamically.
    If SIZE is 0, load any size of font.
@@ -6443,11 +12058,12 @@ x_load_font (f, fontname, size)
 {
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
   Lisp_Object font_names;
+  int count;
 
   /* Get a list of all the fonts that match this name.  Once we
      have a list of matching fonts, we compare them against the fonts
      we already have by comparing names.  */
-  font_names = x_list_fonts (f, build_string (fontname), size, 256);
+  font_names = x_list_fonts (f, build_string (fontname), size, 1);
 
   if (!NILP (font_names))
     {
@@ -6455,11 +12071,12 @@ x_load_font (f, fontname, size)
       int i;
 
       for (i = 0; i < dpyinfo->n_fonts; i++)
-       for (tail = font_names; CONSP (tail); tail = XCONS (tail)->cdr)
-         if (!strcmp (dpyinfo->font_table[i].name,
-                      XSTRING (XCONS (tail)->car)->data)
-             || !strcmp (dpyinfo->font_table[i].full_name,
-                         XSTRING (XCONS (tail)->car)->data))
+       for (tail = font_names; CONSP (tail); tail = XCDR (tail))
+         if (dpyinfo->font_table[i].name
+             && (!strcmp (dpyinfo->font_table[i].name,
+                          XSTRING (XCAR (tail))->data)
+                 || !strcmp (dpyinfo->font_table[i].full_name,
+                             XSTRING (XCAR (tail))->data)))
            return (dpyinfo->font_table + i);
     }
 
@@ -6469,46 +12086,55 @@ x_load_font (f, fontname, size)
     XFontStruct *font;
     struct font_info *fontp;
     unsigned long value;
+    int i;
 
     /* If we have found fonts by x_list_font, load one of them.  If
        not, we still try to load a font by the name given as FONTNAME
        because XListFonts (called in x_list_font) of some X server has
        a bug of not finding a font even if the font surely exists and
        is loadable by XLoadQueryFont.  */
-    if (!NILP (font_names))
-      fontname = (char *) XSTRING (XCONS (font_names)->car)->data;
+    if (size > 0 && !NILP (font_names))
+      fontname = (char *) XSTRING (XCAR (font_names))->data;
 
     BLOCK_INPUT;
+    count = x_catch_errors (FRAME_X_DISPLAY (f));
     font = (XFontStruct *) XLoadQueryFont (FRAME_X_DISPLAY (f), fontname);
+    if (x_had_errors_p (FRAME_X_DISPLAY (f)))
+      {
+       /* This error is perhaps due to insufficient memory on X
+          server.  Let's just ignore it.  */
+       font = NULL;
+       x_clear_errors (FRAME_X_DISPLAY (f));
+      }
+    x_uncatch_errors (FRAME_X_DISPLAY (f), count);
     UNBLOCK_INPUT;
     if (!font)
       return NULL;
 
-    /* Do we need to create the table?  */
-    if (dpyinfo->font_table_size == 0)
-      {
-       dpyinfo->font_table_size = 16;
-       dpyinfo->font_table
-         = (struct font_info *) xmalloc (dpyinfo->font_table_size
-                                         * sizeof (struct font_info));
-      }
-    /* Do we need to grow the table?  */
-    else if (dpyinfo->n_fonts
-            >= dpyinfo->font_table_size)
+    /* Find a free slot in the font table.  */
+    for (i = 0; i < dpyinfo->n_fonts; ++i)
+      if (dpyinfo->font_table[i].name == NULL)
+       break;
+
+    /* If no free slot found, maybe enlarge the font table.  */
+    if (i == dpyinfo->n_fonts
+       && dpyinfo->n_fonts == dpyinfo->font_table_size)
       {
-       dpyinfo->font_table_size *= 2;
+       int sz;
+       dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
+       sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
        dpyinfo->font_table
-         = (struct font_info *) xrealloc (dpyinfo->font_table,
-                                          (dpyinfo->font_table_size
-                                           * sizeof (struct font_info)));
+         = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
       }
 
-    fontp = dpyinfo->font_table + dpyinfo->n_fonts;
+    fontp = dpyinfo->font_table + i;
+    if (i == dpyinfo->n_fonts)
+      ++dpyinfo->n_fonts;
 
     /* Now fill in the slots of *FONTP.  */
     BLOCK_INPUT;
     fontp->font = font;
-    fontp->font_idx = dpyinfo->n_fonts;
+    fontp->font_idx = i;
     fontp->name = (char *) xmalloc (strlen (fontname) + 1);
     bcopy (fontname, fontp->name, strlen (fontname) + 1);
 
@@ -6547,7 +12173,14 @@ x_load_font (f, fontname, size)
       fontp->full_name = fontp->name;
 
     fontp->size = font->max_bounds.width;
-    fontp->height = font->ascent + font->descent;
+    fontp->height = FONT_HEIGHT (font);
+    {
+      /* For some font, ascent and descent in max_bounds field is
+        larger than the above value.  */
+      int max_height = font->max_bounds.ascent + font->max_bounds.descent;
+      if (max_height > fontp->height)
+       fontp->height = max_height;
+    }
 
     if (NILP (font_names))
       {
@@ -6557,19 +12190,19 @@ x_load_font (f, fontname, size)
        Lisp_Object lispy_name = build_string (fontname);
        Lisp_Object lispy_full_name = build_string (fontp->full_name);
 
-       XCONS (dpyinfo->name_list_element)->cdr
+       XCDR (dpyinfo->name_list_element)
          = Fcons (Fcons (Fcons (lispy_name, make_number (256)),
                          Fcons (Fcons (lispy_full_name,
                                        make_number (fontp->size)),
                                 Qnil)),
-                  XCONS (dpyinfo->name_list_element)->cdr);
+                  XCDR (dpyinfo->name_list_element));
        if (full_name)
-         XCONS (dpyinfo->name_list_element)->cdr
+         XCDR (dpyinfo->name_list_element)
            = Fcons (Fcons (Fcons (lispy_full_name, make_number (256)),
                            Fcons (Fcons (lispy_full_name,
                                          make_number (fontp->size)),
                                   Qnil)),
-                    XCONS (dpyinfo->name_list_element)->cdr);
+                    XCDR (dpyinfo->name_list_element));
       }
 
     /* The slot `encoding' specifies how to map a character
@@ -6578,7 +12211,7 @@ x_load_font (f, fontname, size)
        the font code-points (0:0x20..0x7F, 1:0xA0..0xFF,
        0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF, or
        2:0xA020..0xFF7F).  For the moment, we don't know which charset
-       uses this font.  So, we set informatoin in fontp->encoding[1]
+       uses this font.  So, we set information in fontp->encoding[1]
        which is never used by any charset.  If mapping can't be
        decided, set FONT_ENCODING_NOT_DECIDED.  */
     fontp->encoding[1]
@@ -6614,15 +12247,21 @@ x_load_font (f, fontname, size)
       = (XGetFontProperty (font, dpyinfo->Xatom_MULE_DEFAULT_ASCENT, &value)
         ? (long) value : 0);
 
+    /* Set global flag fonts_changed_p to non-zero if the font loaded
+       has a character with a smaller width than any other character
+       before, or if the font loaded has a smalle>r height than any
+       other font loaded before.  If this happens, it will make a
+       glyph matrix reallocation necessary.  */
+    fonts_changed_p = x_compute_min_glyph_bounds (f);
     UNBLOCK_INPUT;
-    dpyinfo->n_fonts++;
-
     return fontp;
   }
 }
 
-/* Return a pointer to struct font_info of a font named FONTNAME for frame F.
-   If no such font is loaded, return NULL.  */
+
+/* Return a pointer to struct font_info of a font named FONTNAME for
+   frame F.  If no such font is loaded, return NULL.  */
+
 struct font_info *
 x_query_font (f, fontname)
      struct frame *f;
@@ -6632,14 +12271,49 @@ x_query_font (f, fontname)
   int i;
 
   for (i = 0; i < dpyinfo->n_fonts; i++)
-    if (!strcmp (dpyinfo->font_table[i].name, fontname)
-       || !strcmp (dpyinfo->font_table[i].full_name, fontname))
+    if (dpyinfo->font_table[i].name
+       && (!strcmp (dpyinfo->font_table[i].name, fontname)
+           || !strcmp (dpyinfo->font_table[i].full_name, fontname)))
       return (dpyinfo->font_table + i);
   return NULL;
 }
 
+
+/* Find a CCL program for a font specified by FONTP, and set the member
+ `encoder' of the structure.  */
+
+void
+x_find_ccl_program (fontp)
+     struct font_info *fontp;
+{
+  Lisp_Object list, elt;
+
+  for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
+    {
+      elt = XCAR (list);
+      if (CONSP (elt)
+         && STRINGP (XCAR (elt))
+         && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
+             >= 0))
+       break;
+    }
+  if (! NILP (list))
+    {
+      struct ccl_program *ccl
+       = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
+
+      if (setup_ccl_program (ccl, XCDR (elt)) < 0)
+       xfree (ccl);
+      else
+       fontp->font_encoder = ccl;
+    }
+}
+
+
 \f
-/* Initialization.  */
+/***********************************************************************
+                           Initialization
+ ***********************************************************************/
 
 #ifdef USE_X_TOOLKIT
 static XrmOptionDescRec emacs_options[] = {
@@ -6670,6 +12344,34 @@ same_x_server (name1, name2)
      char *name1, *name2;
 {
   int seen_colon = 0;
+  unsigned char *system_name = XSTRING (Vsystem_name)->data;
+  int system_name_length = strlen (system_name);
+  int length_until_period = 0;
+
+  while (system_name[length_until_period] != 0
+        && system_name[length_until_period] != '.')
+    length_until_period++;
+
+  /* Treat `unix' like an empty host name.  */
+  if (! strncmp (name1, "unix:", 5))
+    name1 += 4;
+  if (! strncmp (name2, "unix:", 5))
+    name2 += 4;
+  /* Treat this host's name like an empty host name.  */
+  if (! strncmp (name1, system_name, system_name_length)
+      && name1[system_name_length] == ':')
+    name1 += system_name_length;
+  if (! strncmp (name2, system_name, system_name_length)
+      && name2[system_name_length] == ':')
+    name2 += system_name_length;
+  /* Treat this host's domainless name like an empty host name.  */
+  if (! strncmp (name1, system_name, length_until_period)
+      && name1[length_until_period] == ':')
+    name1 += length_until_period;
+  if (! strncmp (name2, system_name, length_until_period)
+      && name2[length_until_period] == ':')
+    name2 += length_until_period;
+
   for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
     {
       if (*name1 == ':')
@@ -6683,14 +12385,34 @@ same_x_server (name1, name2)
 }
 #endif
 
+#if defined (HAVE_X_I18N) || (defined (USE_X_TOOLKIT) && defined (HAVE_X11XTR6))
+/* Recover from setlocale (LC_ALL, "").  */
+static void
+fixup_locale ()
+{
+  /* Currently we require strerror to use the "C" locale,
+     since we don't yet support decoding its string result.  */
+#ifdef LC_MESSAGES
+  setlocale (LC_MESSAGES, "C");
+#endif
+
+  /* The Emacs Lisp reader needs LC_NUMERIC to be "C",
+     so that numbers are read and printed properly for Emacs Lisp.  */
+  setlocale (LC_NUMERIC, "C");
+
+  /* Currently we require strftime to use the "C" locale,
+     since we don't yet support encoding its format argument,
+     or decoding its string result.  */
+  setlocale (LC_TIME, "C");
+}
+#endif
+
 struct x_display_info *
 x_term_init (display_name, xrm_option, resource_name)
      Lisp_Object display_name;
      char *xrm_option;
      char *resource_name;
 {
-  Lisp_Object frame;
-  char *defaultvalue;
   int connection;
   Display *dpy;
   struct x_display_info *dpyinfo;
@@ -6706,9 +12428,7 @@ x_term_init (display_name, xrm_option, resource_name)
 
 #ifdef HAVE_X_I18N
   setlocale (LC_ALL, "");
-  /* In case we just overrode what init_lread did, redo it.  */
-  setlocale (LC_NUMERIC, "C");
-  setlocale (LC_TIME, "C");
+  fixup_locale ();
 #endif
 
 #ifdef USE_X_TOOLKIT
@@ -6739,8 +12459,7 @@ x_term_init (display_name, xrm_option, resource_name)
 
 #ifdef HAVE_X11XTR6
     /* I think this is to compensate for XtSetLanguageProc.  */
-    setlocale (LC_NUMERIC, "C");
-    setlocale (LC_TIME, "C");
+    fixup_locale ();
 #endif
   }
 
@@ -6768,8 +12487,8 @@ x_term_init (display_name, xrm_option, resource_name)
     Lisp_Object tail;
 
     for (share = x_display_list, tail = x_display_name_list; share;
-        share = share->next, tail = XCONS (tail)->cdr)
-      if (same_x_server (XSTRING (XCONS (XCONS (tail)->car)->car)->data,
+        share = share->next, tail = XCDR (tail))
+      if (same_x_server (XSTRING (XCAR (XCAR (tail)))->data,
                         XSTRING (display_name)->data))
        break;
     if (share)
@@ -6790,7 +12509,7 @@ x_term_init (display_name, xrm_option, resource_name)
        all_kboards = dpyinfo->kboard;
        /* Don't let the initial kboard remain current longer than necessary.
           That would cause problems if a file loaded on startup tries to
-          prompt in the minibuffer.  */
+          prompt in the mini-buffer.  */
        if (current_kboard == initial_kboard)
          current_kboard = dpyinfo->kboard;
       }
@@ -6805,7 +12524,7 @@ x_term_init (display_name, xrm_option, resource_name)
   /* Put it on x_display_name_list as well, to keep them parallel.  */ 
   x_display_name_list = Fcons (Fcons (display_name, Qnil),
                               x_display_name_list);
-  dpyinfo->name_list_element = XCONS (x_display_name_list)->car;
+  dpyinfo->name_list_element = XCAR (x_display_name_list);
 
   dpyinfo->display = dpy;
 
@@ -6814,8 +12533,8 @@ x_term_init (display_name, xrm_option, resource_name)
 #endif /* ! 0 */
 
   dpyinfo->x_id_name
-    = (char *) xmalloc (XSTRING (Vinvocation_name)->size
-                       + XSTRING (Vsystem_name)->size
+    = (char *) xmalloc (STRING_BYTES (XSTRING (Vinvocation_name))
+                       + STRING_BYTES (XSTRING (Vsystem_name))
                        + 2);
   sprintf (dpyinfo->x_id_name, "%s@%s",
           XSTRING (Vinvocation_name)->data, XSTRING (Vsystem_name)->data);
@@ -6848,6 +12567,7 @@ x_term_init (display_name, xrm_option, resource_name)
   dpyinfo->grabbed = 0;
   dpyinfo->reference_count = 0;
   dpyinfo->icon_bitmap_id = -1;
+  dpyinfo->font_table = NULL;
   dpyinfo->n_fonts = 0;
   dpyinfo->font_table_size = 0;
   dpyinfo->bitmaps = 0;
@@ -6858,14 +12578,25 @@ x_term_init (display_name, xrm_option, resource_name)
   dpyinfo->mouse_face_deferred_gc = 0;
   dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
   dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
-  dpyinfo->mouse_face_face_id = 0;
+  dpyinfo->mouse_face_face_id = DEFAULT_FACE_ID;
   dpyinfo->mouse_face_window = Qnil;
   dpyinfo->mouse_face_mouse_x = dpyinfo->mouse_face_mouse_y = 0;
   dpyinfo->mouse_face_defer = 0;
   dpyinfo->x_focus_frame = 0;
   dpyinfo->x_focus_event_frame = 0;
   dpyinfo->x_highlight_frame = 0;
+  dpyinfo->image_cache = make_image_cache ();
 
+  {
+    int screen_number = XScreenNumberOfScreen (dpyinfo->screen);
+    double pixels = DisplayHeight (dpyinfo->display, screen_number);
+    double mm = DisplayHeightMM (dpyinfo->display, screen_number);
+    dpyinfo->resy = pixels * 25.4 / mm;
+    pixels = DisplayWidth (dpyinfo->display, screen_number);
+    mm = DisplayWidthMM (dpyinfo->display, screen_number);
+    dpyinfo->resx = pixels * 25.4 / mm;
+  }
+  
   dpyinfo->Xatom_wm_protocols
     = XInternAtom (dpyinfo->display, "WM_PROTOCOLS", False);
   dpyinfo->Xatom_wm_take_focus
@@ -6914,6 +12645,13 @@ x_term_init (display_name, xrm_option, resource_name)
   dpyinfo->Xatom_MULE_DEFAULT_ASCENT
     = XInternAtom (dpyinfo->display, "_MULE_DEFAULT_ASCENT", False);
 
+  /* Ghostscript support.  */
+  dpyinfo->Xatom_PAGE = XInternAtom (dpyinfo->display, "PAGE", False);
+  dpyinfo->Xatom_DONE = XInternAtom (dpyinfo->display, "DONE", False);
+  
+  dpyinfo->Xatom_Scrollbar = XInternAtom (dpyinfo->display, "SCROLLBAR",
+                                         False);
+
   dpyinfo->cut_buffers_initialized = 0;
 
   connection = ConnectionNumber (dpyinfo->display);
@@ -6930,6 +12668,16 @@ x_term_init (display_name, xrm_option, resource_name)
                                     1);
   }
 
+  {
+    extern int gray_bitmap_width, gray_bitmap_height;
+    extern unsigned char *gray_bitmap_bits;
+    dpyinfo->gray
+      = XCreatePixmapFromBitmapData (dpyinfo->display, dpyinfo->root_window,
+                                    gray_bitmap_bits,
+                                    gray_bitmap_width, gray_bitmap_height,
+                                    (unsigned long) 1, (unsigned long) 0, 1);
+  }
+
 #ifdef subprocesses
   /* This is only needed for distinguishing keyboard and process input.  */
   if (connection != 0)
@@ -6953,6 +12701,7 @@ x_term_init (display_name, xrm_option, resource_name)
 #endif /* ! defined (SIGIO) */
 
 #ifdef USE_LUCID
+#ifdef HAVE_X11R5 /* It seems X11R4 lacks XtCvtStringToFont, and XPointer.  */
   /* Make sure that we have a valid font for dialog boxes
      so that Xt does not crash.  */
   {
@@ -6975,7 +12724,7 @@ x_term_init (display_name, xrm_option, resource_name)
     x_uncatch_errors (dpy, count);
   }
 #endif
-
+#endif
 
   UNBLOCK_INPUT;
 
@@ -6994,22 +12743,22 @@ x_delete_display (dpyinfo)
   /* Discard this display from x_display_name_list and x_display_list.
      We can't use Fdelq because that can quit.  */
   if (! NILP (x_display_name_list)
-      && EQ (XCONS (x_display_name_list)->car, dpyinfo->name_list_element))
-    x_display_name_list = XCONS (x_display_name_list)->cdr;
+      && EQ (XCAR (x_display_name_list), dpyinfo->name_list_element))
+    x_display_name_list = XCDR (x_display_name_list);
   else
     {
       Lisp_Object tail;
 
       tail = x_display_name_list;
-      while (CONSP (tail) && CONSP (XCONS (tail)->cdr))
+      while (CONSP (tail) && CONSP (XCDR (tail)))
        {
-         if (EQ (XCONS (XCONS (tail)->cdr)->car,
+         if (EQ (XCAR (XCDR (tail)),
                  dpyinfo->name_list_element))
            {
-             XCONS (tail)->cdr = XCONS (XCONS (tail)->cdr)->cdr;
+             XCDR (tail) = XCDR (XCDR (tail));
              break;
            }
-         tail = XCONS (tail)->cdr;
+         tail = XCDR (tail);
        }
     }
 
@@ -7040,24 +12789,39 @@ x_delete_display (dpyinfo)
 \f
 /* Set up use of X before we make the first connection.  */
 
+static struct redisplay_interface x_redisplay_interface =
+{
+  x_produce_glyphs,
+  x_write_glyphs,
+  x_insert_glyphs,
+  x_clear_end_of_line,
+  x_scroll_run,
+  x_after_update_window_line,
+  x_update_window_begin,
+  x_update_window_end,
+  XTcursor_to,
+  x_flush,
+  x_get_glyph_overhangs,
+  x_fix_overlapping_area
+};
+
+void
 x_initialize ()
 {
-  clear_frame_hook = XTclear_frame;
-  clear_end_of_line_hook = XTclear_end_of_line;
-  ins_del_lines_hook = XTins_del_lines;
-  change_line_highlight_hook = XTchange_line_highlight;
-  insert_glyphs_hook = XTinsert_glyphs;
-  write_glyphs_hook = XTwrite_glyphs;
-  delete_glyphs_hook = XTdelete_glyphs;
+  rif = &x_redisplay_interface;
+
+  clear_frame_hook = x_clear_frame;
+  ins_del_lines_hook = x_ins_del_lines;
+  change_line_highlight_hook = x_change_line_highlight;
+  delete_glyphs_hook = x_delete_glyphs;
   ring_bell_hook = XTring_bell;
   reset_terminal_modes_hook = XTreset_terminal_modes;
   set_terminal_modes_hook = XTset_terminal_modes;
-  update_begin_hook = XTupdate_begin;
-  update_end_hook = XTupdate_end;
+  update_begin_hook = x_update_begin;
+  update_end_hook = x_update_end;
   set_terminal_window_hook = XTset_terminal_window;
   read_socket_hook = XTread_socket;
   frame_up_to_date_hook = XTframe_up_to_date;
-  cursor_to_hook = XTcursor_to;
   reassert_line_highlight_hook = XTreassert_line_highlight;
   mouse_position_hook = XTmouse_position;
   frame_rehighlight_hook = XTframe_rehighlight;
@@ -7066,6 +12830,7 @@ x_initialize ()
   condemn_scroll_bars_hook = XTcondemn_scroll_bars;
   redeem_scroll_bar_hook = XTredeem_scroll_bar;
   judge_scroll_bars_hook = XTjudge_scroll_bars;
+  estimate_mode_line_height_hook = x_estimate_mode_line_height;
 
   scroll_region_ok = 1;                /* we'll scroll partial frames */
   char_ins_del_ok = 0;         /* just as fast to write the line */
@@ -7076,7 +12841,9 @@ x_initialize ()
   baud_rate = 19200;
 
   x_noop_count = 0;
-
+  last_tool_bar_item = -1;
+  any_help_event_p = 0;
+  
   /* Try to use interrupt input; if we can't, then start polling.  */
   Fset_input_mode (Qt, Qnil, Qt, Qnil);
 
@@ -7091,7 +12858,7 @@ x_initialize ()
   XSetErrorHandler (x_error_handler);
   XSetIOErrorHandler (x_io_error_quitter);
 
-  /* Disable Window Change signals;  they are handled by X events. */
+  /* Disable Window Change signals;  they are handled by X events.  */
 #ifdef SIGWINCH
   signal (SIGWINCH, SIG_DFL);
 #endif /* ! defined (SIGWINCH) */
@@ -7099,6 +12866,7 @@ x_initialize ()
   signal (SIGPIPE, x_connection_signal);
 }
 
+
 void
 syms_of_xterm ()
 {
@@ -7116,6 +12884,30 @@ syms_of_xterm ()
 
   staticpro (&last_mouse_press_frame);
   last_mouse_press_frame = Qnil;
+
+  staticpro (&help_echo);
+  help_echo = Qnil;
+  staticpro (&previous_help_echo);
+  previous_help_echo = Qnil;
+
+  DEFVAR_BOOL ("x-stretch-cursor", &x_stretch_cursor_p,
+    "*Non-nil means draw block cursor as wide as the glyph under it.\n\
+For example, if a block cursor is over a tab, it will be drawn as\n\
+wide as that tab on the display.");
+  x_stretch_cursor_p = 0;
+
+  DEFVAR_BOOL ("x-toolkit-scroll-bars-p", &x_toolkit_scroll_bars_p,
+    "If not nil, Emacs uses toolkit scroll bars.");
+#if USE_TOOLKIT_SCROLL_BARS
+  x_toolkit_scroll_bars_p = 1;
+#else
+  x_toolkit_scroll_bars_p = 0;
+#endif
+
+  defsubr (&Sxt_process_timeouts);
+  staticpro (&last_mouse_motion_frame);
+  last_mouse_motion_frame = Qnil;
 }
 
 #endif /* not HAVE_X_WINDOWS */
+