(x_get_customization_string): Don't use value of strcpy.
[bpt/emacs.git] / src / xterm.c
index 70d5c9b..30f3403 100644 (file)
@@ -1,5 +1,5 @@
 /* X Communication module for terminals which understand the X protocol.
-   Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -25,15 +25,20 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    
 */
 
+#define NEW_SELECTIONS
+
+/* On 4.3 these lose if they come after xterm.h.  */
+/* On HP-UX 8.0 signal.h loses if it comes after config.h.  */
+/* Putting these at the beginning seems to be standard for other .c files.  */
+#include <stdio.h>
+#include <signal.h>
+
 #include "config.h"
 
 #ifdef HAVE_X_WINDOWS
 
 #include "lisp.h"
-
-/* On 4.3 these lose if they come after xterm.h.  */
-#include <stdio.h>
-#include <signal.h>
+#include "blockinput.h"
 
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
@@ -52,23 +57,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/ioctl.h>
 #include <strings.h>
 #else /* ! defined (BSD) */
-#include <sys/termio.h>
+#ifndef VMS
 #include <string.h>
+#endif
 #endif /* ! defined (BSD) */
 
-/* Allow m- file to inhibit use of FIONREAD.  */
-#ifdef BROKEN_FIONREAD
-#undef FIONREAD
-#endif /* ! defined (BROKEN_FIONREAD) */
-
-/* We are unable to use interrupts if FIONREAD is not available,
-   so flush SIGIO so we won't try.  */
-#ifndef FIONREAD
-#ifdef SIGIO
-#undef SIGIO
-#endif /* ! defined (SIGIO) */
-#endif /* FIONREAD */
-
+#include "systty.h"
 #include "systime.h"
 
 #include <fcntl.h>
@@ -99,6 +93,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 /*#include <X/Xproto.h>        */
 #endif /* ! defined (HAVE_X11) */
 
+#ifdef FD_SET
+/* We could get this from param.h, but better not to depend on finding that.
+   And better not to risk that it might define other symbols used in this
+   file.  */
+#ifdef FD_SETSIZE
+#define MAXDESC FD_SETSIZE
+#else
+#define MAXDESC 64
+#endif
+#define SELECT_TYPE fd_set
+#else /* no FD_SET */
+#define MAXDESC 32
+#define SELECT_TYPE int
+
+/* Define the macros to access a single-int bitmap of descriptors.  */
+#define FD_SET(n, p) (*(p) |= (1 << (n)))
+#define FD_CLR(n, p) (*(p) &= ~(1 << (n)))
+#define FD_ISSET(n, p) (*(p) & (1 << (n)))
+#define FD_ZERO(p) (*(p) = 0)
+#endif /* no FD_SET */
+
 /* For sending Meta-characters.  Do we need this? */
 #define METABIT 0200
 
@@ -128,20 +143,10 @@ static struct event_queue x_expose_queue;
 struct event_queue x_mouse_queue;
 #endif /* HAVE_X11 */
 
-/* Nonzero after BLOCK_INPUT; prevents input events from being
-   processed until later.  */
-
-int x_input_blocked;
-
 #if defined (SIGIO) && defined (FIONREAD)
 int BLOCK_INPUT_mask;
 #endif /* ! defined (SIGIO) && defined (FIONREAD) */
 
-/* Nonzero if input events came in while x_input_blocked was nonzero.
-   UNBLOCK_INPUT checks for this.  */
-
-int x_pending_input;
-
 /* The id of a bitmap used for icon windows.
    One such map is shared by all Emacs icon windows.
    This is zero if we have not yet had a need to create the bitmap.  */
@@ -156,22 +161,20 @@ static FONT_TYPE *icon_font_info;
 
 extern Lisp_Object Vcommand_line_args;
 char *hostname, *x_id_name;
-Lisp_Object invocation_name;
 
 /* This is the X connection that we are using.  */
 
 Display *x_current_display;
 
-/* The cursor to use for vertical scrollbars on x_current_display.  */
-static Cursor x_vertical_scrollbar_cursor;
+/* The cursor to use for vertical scroll bars on x_current_display.  */
+static Cursor x_vertical_scroll_bar_cursor;
 
-/* Frame being updated by update_frame.  */
-/* This is set by XTupdate_begin and looked at by all the
+/* 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.  */
-
-static struct frame *updating_frame;
+extern struct frame *updating_frame;
 
 /* The frame (if any) which has the X window that has keyboard focus.
    Zero if none.  This is examined by Ffocus_frame in frame.c.  Note
@@ -258,6 +261,9 @@ static WINDOWINFO_TYPE windowinfo;
 
 extern int errno;
 
+/* A mask of extra modifier bits to put into every keyboard char.  */
+extern int extra_keyboard_modifiers;
+
 extern Display *XOpenDisplay ();
 extern Window XCreateWindow ();
 
@@ -265,6 +271,7 @@ extern Cursor XCreateCursor ();
 extern FONT_TYPE *XOpenFont ();
 
 static void flashback ();
+static void redraw_previous_char ();
 
 #ifndef HAVE_X11
 static void dumpqueue ();
@@ -282,7 +289,7 @@ static int XTclear_end_of_line ();
    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_char and XTreassert_line_highlight.  */
+   being XTcursor_to, XTwrite_glyphs and XTreassert_line_highlight.  */
 
 extern int mouse_track_top, mouse_track_left, mouse_track_width;
 
@@ -295,7 +302,6 @@ XTupdate_begin (f)
   if (f == 0)
     abort ();
 
-  updating_frame = f;
   flexlines = f->height;
   highlight = 0;
 
@@ -328,7 +334,6 @@ XTupdate_end (f)
 
   x_display_cursor (f, 1);
 
-  updating_frame = 0;
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
@@ -401,65 +406,40 @@ XTcursor_to (row, col)
    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.
 
-   FONT is the default font to use (for glyphs whose font-code is 0).  */
+   FONT is the default font to use (for glyphs whose font-code is 0).
 
-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;
-     FONT_TYPE *font;
-{
-  register int len;
-  Window window = FRAME_X_WINDOW (f);
-  GC drawing_gc =   (hl == 2 ? f->display.x->cursor_gc
-                            : (hl ? f->display.x->reverse_gc
-                                  : f->display.x->normal_gc));
+   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.  */
 
-  if (sizeof (GLYPH) == sizeof (XChar2b))
-    XDrawImageString16 (x_current_display, window, drawing_gc,
-                       left, top + FONT_BASE (font), (XChar2b *) gp, n);
-  else if (sizeof (GLYPH) == sizeof (unsigned char))
-    XDrawImageString (x_current_display, window, drawing_gc,
-                     left, top + FONT_BASE (font), (char *) gp, n);
-  else
-    /* What size of glyph ARE you using?  And does X have a function to
-       draw them?  */
-    abort ();
-}
+#if 1
+/* This is the multi-face code.  */
 
-#if 0
 static void
-dumpglyphs (f, left, top, gp, n, hl, font)
+dumpglyphs (f, left, top, gp, n, hl)
      struct frame *f;
      int left, top;
      register GLYPH *gp; /* Points to first GLYPH. */
      register int n;  /* Number of glyphs to display. */
      int hl;
-     FONT_TYPE *font;
 {
-  char buf[f->width]; /* Holds characters to be displayed. */
+  /* Holds characters to be displayed. */
+  char *buf = (char *) alloca (f->width * sizeof (*buf));
   register char *cp;           /* Steps through buf[]. */
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
   Window window = FRAME_X_WINDOW (f);
-  int cursor_pixel = f->display.x->cursor_pixel;
-  int fg_pixel = f->display.x->foreground_pixel;
-  int bg_pixel = f->display.x->background_pixel;
-  int intborder = f->display.x->internal_border_width;
 
-  while (n)
+  while (n > 0)
     {
       /* Get the face-code of the next GLYPH.  */
       int cf, len;
       int g = *gp;
 
-      while (GLYPH_ALIAS_P (tbase, tlen, g))
-       g = GLYPH_ALIAS (tbase, g);
-       
-      cf = g >> 8;
+      GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
+      cf = GLYPH_FACE (g);
 
       /* Find the run of consecutive glyphs with the same face-code.
         Extract their character codes into BUF.  */
@@ -467,12 +447,11 @@ dumpglyphs (f, left, top, gp, n, hl, font)
       while (n > 0)
        {
          g = *gp;
-         while (GLYPH_ALIAS_P (tbase, tlen, g))
-           g = GLYPH_ALIAS (tbase, g);
-         if ((g >> 8) != cf)
+         GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
+         if (GLYPH_FACE (g) != cf)
            break;
 
-         *cp++ = 0377 & g;
+         *cp++ = GLYPH_CHAR (g);
          --n;
          ++gp;
        }
@@ -482,65 +461,137 @@ dumpglyphs (f, left, top, gp, n, hl, font)
 
       /* Now output this run of chars, with the font and pixel values
         determined by the face code CF.  */
-      if (cf == 0)
-       {
-#ifdef HAVE_X11
-         GC GC_cursor = f->display.x->cursor_gc;
-         GC GC_reverse = f->display.x->reverse_gc;
-         GC GC_normal = f->display.x->normal_gc;
-
-         XDrawImageString (x_current_display, window,
-                           (hl == 2
-                            ? GC_cursor
-                            : (hl ? GC_reverse : GC_normal)),
-                           left, top + FONT_BASE (font), buf, len);
-#else /* ! defined (HAVE_X11) */
-         XText (window, left, top,
-                buf,
-                len,
-                font->id,
-                (hl == 2
-                 ? (cursor_pixel == fg_pixel ? bg_pixel : fg_pixel)
-                 : hl ? bg_pixel : fg_pixel),
-                (hl == 2 ? cursor_pixel
-                 : hl ? fg_pixel : bg_pixel));
-#endif /* ! defined (HAVE_X11) */
-       }
-      else
+      {
+       struct face *face = FRAME_DEFAULT_FACE (f);
+       FONT_TYPE *font = FACE_FONT (face);
+       GC gc = FACE_GC (face);
+       int defaulted = 1;
+       int gc_temporary = 0;
+
+       /* First look at the face of the text itself.  */
+       if (cf != 0)
+         {
+           /* The face codes on the glyphs must be valid indices into the
+              frame's face table.  */
+           if (cf < 0 || cf >= FRAME_N_COMPUTED_FACES (f)
+               || FRAME_COMPUTED_FACES (f) [cf] == 0)
+             abort ();
+
+           if (cf == 1)
+             face = FRAME_MODE_LINE_FACE (f);
+           else
+             face = intern_face (f, FRAME_COMPUTED_FACES (f) [cf]);
+           font = FACE_FONT (face);
+           gc = FACE_GC (face);
+           defaulted = 0;
+         }
+
+       /* Then comes the distinction between modeline and normal text.  */
+       else if (hl == 0)
+         ;
+       else if (hl == 1)
+         {
+           face = FRAME_MODE_LINE_FACE (f);
+           font = FACE_FONT (face);
+           gc   = FACE_GC   (face);
+           defaulted = 0;
+         }
+
+#define FACE_DEFAULT (~0)
+
+       /* Now override that if the cursor's on this character.  */
+       if (hl == 2)
+         {
+           if (defaulted
+               || !face->font
+               || (int) face->font == FACE_DEFAULT)
+             {
+               gc = f->display.x->cursor_gc;
+             }
+           /* Cursor on non-default face: must merge.  */
+           else
+             {
+               XGCValues xgcv;
+               unsigned long mask;
+
+               xgcv.background = f->display.x->cursor_pixel;
+               xgcv.foreground = f->display.x->cursor_foreground_pixel;
+               xgcv.font = face->font->fid;
+               xgcv.graphics_exposures = 0;
+               mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
+               gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
+                               mask, &xgcv);
+#if 0
+               if (face->stipple && face->stipple != FACE_DEFAULT)
+                 XSetStipple (x_current_display, gc, face->stipple);
+#endif
+               gc_temporary = 1;
+             }
+         }
+
+       if ((int) font == FACE_DEFAULT)
+         font = f->display.x->font;
+
+       XDrawImageString (x_current_display, window, gc,
+                         left, top + FONT_BASE (font), buf, len);
+
+       if (gc_temporary)
+         XFreeGC (x_current_display, gc);
+
+       /* 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.  */
        {
-#ifdef HAVE_X11
-         if (FACE_IS_FONT (cf))
-           XDrawImageString (x_current_display, FRAME_X_WINDOW (f),
-                             FACE_GC (cf),
-                             left, top + FONT_BASE (FACE_FONT (cf)),
-                             buf, len);
-         else if (FACE_IS_IMAGE (cf))
-           XCopyPlane (x_current_display, FACE_IMAGE (cf),
-                       FRAME_X_WINDOW (f),
-                       f->display.x->normal_gc,
-                       0, 0,
-                       FACE_IMAGE_WIDTH (cf),
-                       FACE_IMAGE_HEIGHT (cf), left, top);
-         else
-           abort ();
-#else /* ! defined (HAVE_X11) */
-         register struct face *fp = x_face_table[cf];
-
-         XText (window, left, top,
-                buf,
-                len,
-                fp->font->id,
-                (hl == 2
-                 ? (cursor_pixel == fp->fg ? fp->bg : fp->fg)
-                 : hl ? fp->bg : fp->fg),
-                (hl == 2 ? cursor_pixel
-                 : hl ? fp->fg : fp->bg));
-#endif /* ! defined (HAVE_X11) */
+         int underline_position = 1;
+
+         if (font->descent <= underline_position)
+           underline_position = font->descent - 1;
+
+         if (face->underline)
+           XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
+                           FACE_GC (face),
+                           left, (top
+                                  + FONT_BASE (font)
+                                  + underline_position),
+                           len * FONT_WIDTH (font), 1);
        }
-      left += len * FONT_WIDTH (font);
+
+       left += len * FONT_WIDTH (font);
+      }
     }
 }
-#endif /* ! 0 */
+#endif /* 1 */
+
+#if 0
+/* This is the old single-face code.  */
+
+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;
+     FONT_TYPE *font;
+{
+  register int len;
+  Window window = FRAME_X_WINDOW (f);
+  GC drawing_gc =   (hl == 2 ? f->display.x->cursor_gc
+                            : (hl ? f->display.x->reverse_gc
+                                  : f->display.x->normal_gc));
+
+  if (sizeof (GLYPH) == sizeof (XChar2b))
+    XDrawImageString16 (x_current_display, window, drawing_gc,
+                       left, top + FONT_BASE (font), (XChar2b *) gp, n);
+  else if (sizeof (GLYPH) == sizeof (unsigned char))
+    XDrawImageString (x_current_display, window, drawing_gc,
+                     left, top + FONT_BASE (font), (char *) gp, n);
+  else
+    /* What size of glyph ARE you using?  And does X have a function to
+       draw them?  */
+    abort ();
+}
+#endif
 \f
 /* Output some text at the nominal frame cursor position.
    Advance the cursor over the text.
@@ -571,11 +622,9 @@ XTwrite_glyphs (start, len)
     }
 
   dumpglyphs (f,
-            (curs_x * FONT_WIDTH (f->display.x->font)
-             + f->display.x->internal_border_width),
-            (curs_y * FONT_HEIGHT (f->display.x->font)
-             + f->display.x->internal_border_width),
-            start, len, highlight, f->display.x->font);
+             CHAR_TO_PIXEL_COL (f, curs_x),
+             CHAR_TO_PIXEL_ROW (f, curs_y),
+             start, len, highlight);
 
   /* If we drew on top of the cursor, note that it is turned off.  */
   if (curs_y == f->phys_cursor_y
@@ -628,17 +677,17 @@ XTclear_end_of_line (first_unused)
 
 #ifdef HAVE_X11
   XClearArea (x_current_display, FRAME_X_WINDOW (f),
-             curs_x * FONT_WIDTH (f->display.x->font)
-             + f->display.x->internal_border_width,
-             curs_y * FONT_HEIGHT (f->display.x->font)
-             + f->display.x->internal_border_width,
+             CHAR_TO_PIXEL_COL (f, curs_x),
+             CHAR_TO_PIXEL_ROW (f, curs_y),
              FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
              FONT_HEIGHT (f->display.x->font), False);
-             
+#if 0
+  redraw_previous_char (f, curs_x, curs_y);
+#endif
 #else /* ! defined (HAVE_X11) */
   XPixSet (FRAME_X_WINDOW (f),
-          curs_x * FONT_WIDTH (f->display.x->font) + f->display.x->internal_border_width,
-          curs_y * FONT_HEIGHT (f->display.x->font) + f->display.x->internal_border_width,
+          CHAR_TO_PIXEL_COL (f, curs_x),
+          CHAR_TO_PIXEL_ROW (f, curs_y),
           FONT_WIDTH (f->display.x->font) * (first_unused - curs_x),
           FONT_HEIGHT (f->display.x->font),
           f->display.x->background_pixel);     
@@ -647,6 +696,38 @@ XTclear_end_of_line (first_unused)
   UNBLOCK_INPUT;
 }
 
+/* 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.  */
+
+static void
+redraw_previous_char (f, x, y)
+     FRAME_PTR f;
+     int x, y;
+{
+  /* 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 (x_current_display, FRAME_X_WINDOW (f),
+                 CHAR_TO_PIXEL_COL (f, x - 1),
+                 CHAR_TO_PIXEL_ROW (f, y),
+                 FONT_WIDTH (f->display.x->font),
+                 FONT_HEIGHT (f->display.x->font), 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);
+    }
+}
+
 static
 XTclear_frame ()
 {
@@ -661,95 +742,128 @@ XTclear_frame ()
   curs_y = 0;
   
   BLOCK_INPUT;
+
   XClear (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);
+
 #ifndef HAVE_X11
   dumpborder (f, 0);
 #endif /* HAVE_X11 */
+
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
 \f
-/* Paint horzontal bars down the frame for a visible bell.
-   Note that this may be way too slow on some machines. */
+/* 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.  */
+#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.  */
+
+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.  */
+  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;
+      y.tv_usec += 1000000 * nsec;
+      y.tv_sec -= nsec;
+    }
+
+  /* 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 x.tv_sec < y.tv_sec;
+}
 
 XTflash (f)
      struct frame *f;
 {
-  register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
-  register int i;
-  int x, y;
+  BLOCK_INPUT;
 
-  if (updating_frame != 0)
-    abort ();
+  {
+    GC gc;
 
-  BLOCK_INPUT;
-#ifdef HAVE_X11
-#if 0
-  for (i = f->height * FONT_HEIGHT (f->display.x->font) - 10;
-       i >= 0;    
-       i -= 100)          /* Should be NO LOWER than 75 for speed reasons. */
-    XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
-                   f->display.x->cursor_gc,
-                   0, i, f->width * FONT_WIDTH (f->display.x->font)
-                   + 2 * f->display.x->internal_border_width, 25);
-#endif /* ! 0 */
+    /* Create a GC that will use the GXxor function to flip foreground pixels
+       into background pixels.  */
+    {
+      XGCValues values;
 
-  x = (f->width * FONT_WIDTH (f->display.x->font)) / 4;
-  y = (f->height * FONT_HEIGHT (f->display.x->font)) / 4;
-  XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
-                 f->display.x->cursor_gc,
-                 x, y, 2 * x, 2 * y);
-  dumpglyphs (f, (x + f->display.x->internal_border_width),
-            (y + f->display.x->internal_border_width),
-            &active_frame->glyphs[(f->height / 4) + 1][(f->width / 4)],
-            1, 0, f->display.x->font);
+      values.function = GXxor;
+      values.foreground = (f->display.x->foreground_pixel
+                          ^ f->display.x->background_pixel);
+      
+      gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
+                     GCFunction | GCForeground, &values);
+    }
 
-#else /* ! defined (HAVE_X11) */
-  for (i = f->height * FONT_HEIGHT (f->display.x->font) - 10;
-       i >= 0;
-       i -= 50)
-    XPixFill (FRAME_X_WINDOW (f), 0, i,
-             f->width * FONT_WIDTH (f->display.x->font)
-             + 2 * f->display.x->internal_border_width, 10,
-             WHITE_PIX_DEFAULT, ClipModeClipped, GXinvert, AllPlanes);
-#endif /* ! defined (HAVE_X11) */
+    {
+      int width  = PIXEL_WIDTH  (f);
+      int height = PIXEL_HEIGHT (f);
 
-  XFlushQueue ();
-  UNBLOCK_INPUT;
-}
+      XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
+                     width/4, height/4, width/2, height/2);
+      XFlush (x_current_display);
 
-/* Flip background and forground colors of the frame. */
+      {
+       struct timeval wakeup, now;
 
-x_invert_frame (f)
-     struct frame *f;
-{
-#ifdef HAVE_X11
-  GC temp;
-  unsigned long pix_temp;
+       gettimeofday (&wakeup, (struct timezone *) 0);
 
-  x_display_cursor (f, 0);
-  XClearWindow (x_current_display, FRAME_X_WINDOW (f));
-  temp = f->display.x->normal_gc;
-  f->display.x->normal_gc = f->display.x->reverse_gc;
-  f->display.x->reverse_gc = temp;
-  pix_temp = f->display.x->foreground_pixel;
-  f->display.x->foreground_pixel = f->display.x->background_pixel;
-  f->display.x->background_pixel = pix_temp;
-
-  XSetWindowBackground (x_current_display, FRAME_X_WINDOW (f),
-                       f->display.x->background_pixel);
-  if (f->display.x->background_pixel == f->display.x->cursor_pixel)
-    {
-      f->display.x->cursor_pixel = f->display.x->foreground_pixel;
-      XSetBackground (x_current_display, f->display.x->cursor_gc,
-                     f->display.x->cursor_pixel);
-      XSetForeground (x_current_display, f->display.x->cursor_gc,
-                     f->display.x->background_pixel);
+       /* Compute time to wait until, propagating carry from usecs.  */
+       wakeup.tv_usec += 150000;
+       wakeup.tv_sec += (wakeup.tv_usec / 1000000);
+       wakeup.tv_usec %= 1000000;
+
+       /* Keep waiting until past the time wakeup.  */
+       while (1)
+         {
+           struct timeval timeout;
+
+           gettimeofday (&timeout, (struct timezone *)0);
+
+           /* In effect, timeout = wakeup - timeout.
+              Break if result would be negative.  */
+           if (timeval_subtract (&timeout, wakeup, timeout))
+             break;
+
+           /* Try to wait that long--but we might wake up sooner.  */
+           select (0, 0, 0, 0, &timeout);
+         }
+      }
+       
+      XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
+                     width/4, height/4, width/2, height/2);
+      XFreeGC (x_current_display, gc);
+      XFlush (x_current_display);
     }
-  redraw_frame (f);
-#endif /* ! defined (HAVE_X11) */
+  }
+
+  UNBLOCK_INPUT;
 }
 
+#endif
+
+
 /* Make audible bell.  */
 
 #ifdef HAVE_X11
@@ -760,15 +874,14 @@ x_invert_frame (f)
 
 XTring_bell ()
 {
+  if (x_current_display == 0)
+    return;
+
+#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
   if (visible_bell)
-#if 0
     XTflash (selected_frame);
-#endif /* ! 0 */
-    {
-      x_invert_frame (selected_frame);
-      x_invert_frame (selected_frame);
-    }
   else
+#endif
     {
       BLOCK_INPUT;
       XRINGBELL;
@@ -843,14 +956,14 @@ stufflines (n)
 #ifdef HAVE_X11
       XCopyArea (x_current_display, FRAME_X_WINDOW (f),
                 FRAME_X_WINDOW (f), f->display.x->normal_gc,
-                intborder, topregion * FONT_HEIGHT (f->display.x->font) + intborder,
+                intborder, CHAR_TO_PIXEL_ROW (f, topregion),
                 f->width * FONT_WIDTH (f->display.x->font),
                 length * FONT_HEIGHT (f->display.x->font), intborder,
-                newtop * FONT_HEIGHT (f->display.x->font) + intborder);
+                CHAR_TO_PIXEL_ROW (f, newtop));
 #else /* ! defined (HAVE_X11) */
       XMoveArea (FRAME_X_WINDOW (f),
-                intborder, topregion * FONT_HEIGHT (f->display.x->font) + intborder,
-                intborder, newtop * FONT_HEIGHT (f->display.x->font) + intborder,
+                intborder, CHAR_TO_PIXEL_ROW (f, topregion),
+                intborder, CHAR_TO_PIXEL_ROW (f, newtop),
                 f->width * FONT_WIDTH (f->display.x->font),
                 length * FONT_HEIGHT (f->display.x->font));
       /* Now we must process any ExposeRegion events that occur
@@ -867,13 +980,13 @@ stufflines (n)
     {
 #ifdef HAVE_X11
       XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder, 
-                 topregion * FONT_HEIGHT (f->display.x->font) + intborder,
+                 CHAR_TO_PIXEL_ROW (f, topregion),
                  f->width * FONT_WIDTH (f->display.x->font),
                  n * FONT_HEIGHT (f->display.x->font), False);
 #else /* ! defined (HAVE_X11) */
       XPixSet (FRAME_X_WINDOW (f),
               intborder,
-              topregion * FONT_HEIGHT (f->display.x->font) + intborder,
+              CHAR_TO_PIXEL_ROW (f, topregion),
               f->width * FONT_WIDTH (f->display.x->font),
               n * FONT_HEIGHT (f->display.x->font),
               f->display.x->background_pixel);
@@ -905,12 +1018,12 @@ scraplines (n)
        {
 #ifdef HAVE_X11
          XClearArea (x_current_display, FRAME_X_WINDOW (f), intborder,
-                     curs_y * FONT_HEIGHT (f->display.x->font) + intborder,
+                     CHAR_TO_PIXEL_ROW (f, curs_y),
                      f->width * FONT_WIDTH (f->display.x->font),
                      (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font), False);
 #else /* ! defined (HAVE_X11) */
          XPixSet (FRAME_X_WINDOW (f),
-                  intborder, curs_y * FONT_HEIGHT (f->display.x->font) + intborder,
+                  intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
                   f->width * FONT_WIDTH (f->display.x->font),
                   (flexlines - curs_y) * FONT_HEIGHT (f->display.x->font),
                   f->display.x->background_pixel);
@@ -923,20 +1036,20 @@ scraplines (n)
       XCopyArea (x_current_display, FRAME_X_WINDOW (f),
                 FRAME_X_WINDOW (f), f->display.x->normal_gc,
                 intborder,
-                (curs_y + n) * FONT_HEIGHT (f->display.x->font) + intborder,
+                CHAR_TO_PIXEL_ROW (f, curs_y + n),
                 f->width * FONT_WIDTH (f->display.x->font),
                 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font),
-                intborder, curs_y * FONT_HEIGHT (f->display.x->font) + intborder);
+                intborder, CHAR_TO_PIXEL_ROW (f, curs_y));
       XClearArea (x_current_display, FRAME_X_WINDOW (f),
                  intborder,
-                 (flexlines - n) * FONT_HEIGHT (f->display.x->font) + intborder,
+                 CHAR_TO_PIXEL_ROW (f, flexlines - n),
                  f->width * FONT_WIDTH (f->display.x->font),
                  n * FONT_HEIGHT (f->display.x->font), False);
 #else /* ! defined (HAVE_X11) */
       XMoveArea (FRAME_X_WINDOW (f),
                 intborder,
-                (curs_y + n) * FONT_HEIGHT (f->display.x->font) + intborder,
-                intborder, curs_y * FONT_HEIGHT (f->display.x->font) + intborder,
+                CHAR_TO_PIXEL_ROW (f, curs_y + n),
+                intborder, CHAR_TO_PIXEL_ROW (f, curs_y),
                 f->width * FONT_WIDTH (f->display.x->font),
                 (flexlines - (curs_y + n)) * FONT_HEIGHT (f->display.x->font));
       /* Now we must process any ExposeRegion events that occur
@@ -945,7 +1058,7 @@ scraplines (n)
         may want to copy this area to another area.  */
       x_read_exposes ();
       XPixSet (FRAME_X_WINDOW (f), intborder,
-              (flexlines - n) * FONT_HEIGHT (f->display.x->font) + intborder,
+              CHAR_TO_PIXEL_ROW (f, flexlines - n),
               f->width * FONT_WIDTH (f->display.x->font),
               n * FONT_HEIGHT (f->display.x->font), f->display.x->background_pixel);
 #endif /* ! defined (HAVE_X11) */
@@ -996,30 +1109,31 @@ dumprectangle (f, left, top, cols, rows)
   if (FRAME_GARBAGED_P (f))
     return;
 
-  top -= f->display.x->internal_border_width;
-  left -= f->display.x->internal_border_width;
-
   /* Express rectangle as four edges, instead of position-and-size.  */
   bottom = top + rows;
   right = left + cols;
 
 #ifndef HAVE_X11               /* Window manger does this for X11. */
-  /* If the rectangle includes any of the internal border area,
-     redisplay the border emphasis.  */
-  if (top < 0 || left < 0
-      || bottom > f->height * FONT_HEIGHT (f->display.x->font)
-      || right > f->width * FONT_WIDTH (f->display.x->font))
-    dumpborder (f, 0);
-#endif /* HAVE_X11             /* Window manger does this for X11. */ */
+  {
+    int intborder = f->display.x->internal_border_width;
+
+    /* If the rectangle includes any of the internal border area,
+       redisplay the border emphasis.  */
+    if (top < intborder || left < intborder
+       || bottom > intborder + f->height * FONT_HEIGHT (f->display.x->font)
+       || right > intborder + f->width * FONT_WIDTH (f->display.x->font))
+      dumpborder (f, 0);
+  }
+#endif /* HAVE_X11             Window manger does this for X11. */
   
   /* Convert rectangle edges in pixels to edges in chars.
      Round down for left and top, up for right and bottom.  */
-  top /= FONT_HEIGHT (f->display.x->font);
-  left /= FONT_WIDTH (f->display.x->font);
+  top  = PIXEL_TO_CHAR_ROW (f, top);
+  left = PIXEL_TO_CHAR_COL (f, left);
   bottom += (FONT_HEIGHT (f->display.x->font) - 1);
   right += (FONT_WIDTH (f->display.x->font) - 1);
-  bottom /= FONT_HEIGHT (f->display.x->font);
-  right /= FONT_WIDTH (f->display.x->font);
+  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)
@@ -1058,12 +1172,10 @@ dumprectangle (f, left, top, cols, rows)
        continue;
 
       dumpglyphs (f,
-                (left * FONT_WIDTH (f->display.x->font)
-                 + f->display.x->internal_border_width),
-                (y * FONT_HEIGHT (f->display.x->font)
-                 + f->display.x->internal_border_width),
-                line, min (cols, active_frame->used[y] - left),
-                active_frame->highlight[y], f->display.x->font);
+                 CHAR_TO_PIXEL_COL (f, left),
+                 CHAR_TO_PIXEL_ROW (f, y),
+                 line, min (cols, active_frame->used[y] - left),
+                 active_frame->highlight[y]);
     }
 
   /* Turn the cursor on if we turned it off.  */
@@ -1114,7 +1226,7 @@ x_do_pending_expose ()
          int intborder;
 
          frame = XCONS (tail)->car;
-         if (XTYPE (frame) != Lisp_Frame)
+         if (XGCTYPE (frame) != Lisp_Frame)
            continue;
          f = XFRAME (frame);
          if (! FRAME_X_P (f))
@@ -1129,16 +1241,16 @@ x_do_pending_expose ()
          clear_cursor (f);
          XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
          temp_width = ((windowinfo.width - 2 * intborder
-                        - f->display.x->v_scrollbar_width)
+                        - f->display.x->v_scroll_bar_width)
                        / FONT_WIDTH (f->display.x->font));
          temp_height = ((windowinfo.height- 2 * intborder
-                         - f->display.x->h_scrollbar_height)
+                         - f->display.x->h_scroll_bar_height)
                         / FONT_HEIGHT (f->display.x->font));
          if (temp_width != f->width || temp_height != f->height)
            {
              change_frame_size (f, max (1, temp_height),
                                  max (1, temp_width), 0, 1);
-             x_resize_scrollbars (f);
+             x_resize_scroll_bars (f);
            }
          f->display.x->left_pos = windowinfo.x;
          f->display.x->top_pos = windowinfo.y;
@@ -1168,9 +1280,14 @@ static void
 frame_highlight (frame)
      struct frame *frame;
 {
-  if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
-                     frame->display.x->border_pixel);
+  /* We used to only do this if Vx_no_window_manager was non-nil, but
+     the ICCCM (section 4.1.6) says that the window's border pixmap
+     and border pixel are window attributes which are "private to the
+     client", so we can always change it to whatever we want.  */
+  BLOCK_INPUT;
+  XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
+                   frame->display.x->border_pixel);
+  UNBLOCK_INPUT;
   x_display_cursor (frame, 1);
 }
 
@@ -1178,9 +1295,14 @@ static void
 frame_unhighlight (frame)
      struct frame *frame;
 {
-  if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
-                           frame->display.x->border_tile);
+  /* We used to only do this if Vx_no_window_manager was non-nil, but
+     the ICCCM (section 4.1.6) says that the window's border pixmap
+     and border pixel are window attributes which are "private to the
+     client", so we can always change it to whatever we want.  */
+  BLOCK_INPUT;
+  XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
+                         frame->display.x->border_tile);
+  UNBLOCK_INPUT;
   x_display_cursor (frame, 1);
 }
 #else /* ! defined (HAVE_X11) */
@@ -1233,7 +1355,7 @@ static void XTframe_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.
-   Each event gets marked with the frame in which it occured, so the
+   Each event gets marked with the frame in which it occurred, so the
    lisp code can tell when the switch took place by examining the events.  */
 
 static void
@@ -1279,7 +1401,7 @@ XTframe_rehighlight ()
   if (x_focus_frame)
     {
       x_highlight_frame =
-       ((XTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
+       ((XGCTYPE (FRAME_FOCUS_FRAME (x_focus_frame)) == Lisp_Frame)
         ? XFRAME (FRAME_FOCUS_FRAME (x_focus_frame))
         : x_focus_frame);
       if (! FRAME_LIVE_P (x_highlight_frame))
@@ -1300,53 +1422,7 @@ XTframe_rehighlight ()
     }
 }
 \f
-/* Mouse clicks and mouse movement.  Rah.  */
-#ifdef HAVE_X11
-
-/* 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.  */
-static void
-pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds)
-     FRAME_PTR f;
-     register unsigned int pix_x, pix_y;
-     register int *x, *y;
-     XRectangle *bounds;
-{
-  int ibw = f->display.x->internal_border_width;
-  int width, height;
-  FONT_TYPE *font = f->display.x->font;
-
-  width = FONT_WIDTH (font);
-  height = FONT_HEIGHT (font);
-
-  /* What line is it on?  */
-  if (pix_y < ibw)
-    *y = 0;
-  else if (pix_y > f->display.x->pixel_height - ibw)
-    *y = FRAME_HEIGHT (f) - 1;
-  else
-    *y = (pix_y - ibw) / height;
-
-  /* And what column?  */
-  if (pix_x < ibw)
-    *x = 0;
-  else if (pix_x > f->display.x->pixel_width - ibw)
-    *x = FRAME_WIDTH (f) - 1;
-  else
-    *x = (pix_x - ibw) / width;
-
-  if (bounds)
-    {
-      bounds->width = width;
-      bounds->height = height;
-      bounds->x = ibw + (*x * width);
-      bounds->y = ibw + (*y * height);
-    }
-}
-
-/* Any buttons grabbed. */
-unsigned int x_mouse_grabbed;
+/* Keyboard processing - modifier keys, vendor-specific keysyms, etc. */
 
 /* Which modifier keys are on which modifier bits?
 
@@ -1369,6 +1445,9 @@ unsigned int x_mouse_grabbed;
    (EVENT.state & x_shift_lock_mask) != 0.  */
 static int x_meta_mod_mask, x_shift_lock_mask;
 
+/* These are like x_meta_mod_mask, but for different modifiers.  */
+static int x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask;
+
 /* Initialize mode_switch_bit and modifier_meaning.  */
 static void
 x_find_modifier_meanings ()
@@ -1377,12 +1456,20 @@ x_find_modifier_meanings ()
   KeySym *syms;
   int syms_per_code;
   XModifierKeymap *mods;
-  int alt_mod_mask = 0;
 
   x_meta_mod_mask = 0;
   x_shift_lock_mask = 0;
+  x_alt_mod_mask = 0;
+  x_super_mod_mask = 0;
+  x_hyper_mod_mask = 0;
   
+#ifdef HAVE_X11R4
   XDisplayKeycodes (x_current_display, &min_code, &max_code);
+#else
+  min_code = x_current_display->min_keycode;
+  max_code = x_current_display->max_keycode;
+#endif
+
   syms = XGetKeyboardMapping (x_current_display,
                              min_code, max_code - min_code + 1,
                              &syms_per_code);
@@ -1416,7 +1503,17 @@ x_find_modifier_meanings ()
 
                  case XK_Alt_L:
                  case XK_Alt_R:
-                   alt_mod_mask |= (1 << row);
+                   x_alt_mod_mask |= (1 << row);
+                   break;
+
+                 case XK_Hyper_L:
+                 case XK_Hyper_R:
+                   x_hyper_mod_mask |= (1 << row);
+                   break;
+
+                 case XK_Super_L:
+                 case XK_Super_R:
+                   x_super_mod_mask |= (1 << row);
                    break;
 
                  case XK_Shift_Lock:
@@ -1432,25 +1529,102 @@ x_find_modifier_meanings ()
 
   /* If we couldn't find any meta keys, accept any alt keys as meta keys.  */
   if (! x_meta_mod_mask)
-    x_meta_mod_mask = alt_mod_mask;
+    {
+      x_meta_mod_mask = x_alt_mod_mask;
+      x_alt_mod_mask = 0;
+    }
 
+  /* If some keys are both alt and meta,
+     make them just meta, not alt.  */
+  if (x_alt_mod_mask & x_meta_mod_mask)
+    {
+      x_alt_mod_mask &= ~x_meta_mod_mask;
+    }
+  
   XFree ((char *) syms);
   XFreeModifiermap (mods);
 }
 
 
-/* Convert a set of X modifier bits to the proper form for a
-   struct input_event modifiers value.  */
-
+/* Convert between the modifier bits X uses and the modifier bits
+   Emacs uses.  */
 static unsigned int
-x_convert_modifiers (state)
+x_x_to_emacs_modifiers (state)
      unsigned int state;
 {
   return (  ((state & (ShiftMask | x_shift_lock_mask)) ? shift_modifier : 0)
          | ((state & ControlMask)                     ? ctrl_modifier  : 0)
-         | ((state & x_meta_mod_mask)                 ? meta_modifier  : 0));
+         | ((state & x_meta_mod_mask)                 ? meta_modifier  : 0)
+         | ((state & x_alt_mod_mask)                  ? alt_modifier  : 0)
+         | ((state & x_super_mod_mask)                ? super_modifier  : 0)
+         | ((state & x_hyper_mod_mask)                ? hyper_modifier  : 0));
+}
+
+static unsigned int
+x_emacs_to_x_modifiers (state)
+     unsigned int state;
+{
+  return (  ((state & alt_modifier)            ? x_alt_mod_mask   : 0)
+         | ((state & super_modifier)           ? x_super_mod_mask : 0)
+         | ((state & hyper_modifier)           ? x_hyper_mod_mask : 0)
+         | ((state & shift_modifier)           ? ShiftMask        : 0)
+         | ((state & ctrl_modifier)            ? ControlMask      : 0)
+         | ((state & meta_modifier)            ? x_meta_mod_mask  : 0));
 }
 
+/* Return true iff KEYSYM is a vendor-specific keysym that we should
+   return as a function key.  If you add a keysym to this, you should
+   make sure that the tables make_lispy_event uses contain a suitable
+   name for it.  */
+static int
+x_is_vendor_fkey (sym)
+     KeySym sym;
+{
+  return 0
+#ifdef DXK_Remove
+    || (sym == DXK_Remove)
+#endif
+      ;
+}
+
+\f
+/* Mouse clicks and mouse movement.  Rah.  */
+#ifdef HAVE_X11
+
+/* 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.  */
+static void
+pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds)
+     FRAME_PTR f;
+     register unsigned int pix_x, pix_y;
+     register int *x, *y;
+     XRectangle *bounds;
+{
+  pix_x = PIXEL_TO_CHAR_COL (f, pix_x);
+  pix_y = PIXEL_TO_CHAR_ROW (f, pix_y);
+
+  if (bounds)
+    {
+      bounds->width  = FONT_WIDTH  (f->display.x->font);
+      bounds->height = FONT_HEIGHT (f->display.x->font);
+      bounds->x = CHAR_TO_PIXEL_COL (f, pix_x);
+      bounds->y = CHAR_TO_PIXEL_ROW (f, pix_y);
+    }
+
+  if (pix_x < 0) pix_x = 0;
+  else if (pix_x > f->width) pix_x = f->width;
+
+  if (pix_y < 0) pix_y = 0;
+  else if (pix_y > f->height) pix_y = f->height;
+
+  *x = pix_x;
+  *y = pix_y;
+}
+
+/* Any buttons grabbed. */
+unsigned int x_mouse_grabbed;
+
 /* 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
@@ -1467,7 +1641,7 @@ construct_mouse_click (result, event, f)
   result->kind = mouse_click;
   XSET (result->code, Lisp_Int, event->button - Button1);
   result->timestamp = event->time;
-  result->modifiers = (x_convert_modifiers (event->state)
+  result->modifiers = (x_x_to_emacs_modifiers (event->state)
                       | (event->type == ButtonRelease
                          ? up_modifier 
                          : down_modifier));
@@ -1492,7 +1666,7 @@ construct_mouse_click (result, event, f)
     pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
     XFASTINT (result->x) = column;
     XFASTINT (result->y) = row;
-    result->frame = f;
+    XSET (result->frame_or_window, Lisp_Frame, f);
   }
 }
 
@@ -1520,14 +1694,15 @@ construct_mouse_click (result, event, f)
 static FRAME_PTR last_mouse_frame;
 static XRectangle last_mouse_glyph;
 
-/* If the last-checked mouse motion was in a scrollbar, this is that
-   scrollbar, the part being dragged, and the limits it is moving in.
-   Otherwise, this is zero.  */
-static struct scrollbar *last_mouse_bar;
-static FRAME_PTR last_mouse_bar_frame;
-static enum scrollbar_part last_mouse_part;
-static int last_mouse_scroll_range_start;
-static int last_mouse_scroll_range_end;
+/* 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
+   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.  */
+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
@@ -1545,7 +1720,7 @@ static Time last_mouse_movement_time;
    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 void
-note_mouse_position (frame, event)
+note_mouse_movement (frame, event)
      FRAME_PTR frame;
      XMotionEvent *event;
 
@@ -1557,7 +1732,10 @@ note_mouse_position (frame, event)
       || event->x >= last_mouse_glyph.x + last_mouse_glyph.width
       || event->y < last_mouse_glyph.y
       || event->y >= last_mouse_glyph.y + last_mouse_glyph.height)
-    mouse_moved = 1;
+    {
+      mouse_moved = 1;
+      last_mouse_scroll_bar = Qnil;
+    }
   else
     {
       /* It's on the same glyph.  Call XQueryPointer so we'll get an
@@ -1572,97 +1750,149 @@ note_mouse_position (frame, event)
     }
 }
 
+static struct scroll_bar *x_window_to_scroll_bar ();
+static void x_scroll_bar_report_motion ();
+
 /* Return the current position of the mouse.
 
+   If the mouse movement started in a scroll bar, set *f, *bar_window,
+   and *part to the frame, window, and scroll bar part that the mouse
+   is over.  Set *x and *y to the portion and whole of the mouse's
+   position on the scroll bar.
+
+   If the mouse movement started elsewhere, set *f to the frame the
+   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
+   was at this position.
+
+   Don't store anything if we don't have a valid set of values to report.
+
    This clears the mouse_moved flag, so we can wait for the next mouse
-   position.  This also calls XQueryPointer, which will cause the
-   server to give us another MotionNotify when the mouse moves again.
-   */
+   movement.  This also calls XQueryPointer, which will cause the
+   server to give us another MotionNotify when the mouse moves
+   again. */
 
 static void
-XTmouse_position (f, bar, part, x, y, time)
+XTmouse_position (f, bar_window, part, x, y, time)
      FRAME_PTR *f;
-     struct scrollbar **bar;
-     enum scrollbar_part *part;
+     Lisp_Object *bar_window;
+     enum scroll_bar_part *part;
      Lisp_Object *x, *y;
      unsigned long *time;
 {
-  int ix, iy, dummy;
-  Display *d = x_current_display;
-  Window guess, root, child;
+  FRAME_PTR f1;
 
   BLOCK_INPUT;
 
-  /* I would like to have an X function that just told me the
-     innermost window containing the mouse.  
-
-  /* There doesn't seem to be any way to just get the innermost window
-     containing the pointer, no matter what X frame it's on; you have
-     to guess a window, and then X will tell you which one of that
-     window's children it's in.  If the pointer isn't in any of that
-     window's children, it gives you a root window that contains it.
-
-     So we start with the selected frame's window and chase down
-     branches under the guidance of XQueryPointer until we hit a leaf
-     (all of the Emacs windows we care about are leaf windows).  If at
-     any time XQueryPointer returns false, that means that the current
-     window does not contain the pointer any more (perhaps it moved),
-     so we start with the root window XQueryPointer has given us and
-     start again.  */
-
-  guess = FRAME_X_WINDOW (selected_frame);
-  for (;;)
-    if (XQueryPointer (d, guess, &root, &child,
-                      &dummy, &dummy, &ix, &iy, (unsigned int *) &dummy))
-      {
-       if (child == None)
-         /* Guess is a leaf window, and it contains the pointer.  */
-         break;
-       else 
-         guess = child;
-      }
-    else
-      /* When XQueryPointer returns False, the pointer isn't in guess
-         anymore, but root is the root window of the frame we should
-         try instead.  */
-      guess = root;
-
-  if (last_mouse_bar)
-    {
-      *f = last_mouse_bar_frame;
-      *bar = last_mouse_bar;
-      *part = last_mouse_part;
-
-      if (iy < last_mouse_scroll_range_start)
-       iy = last_mouse_scroll_range_start;
-      if (iy > last_mouse_scroll_range_end)
-       iy = last_mouse_scroll_range_end;
-      XSETINT (*x, iy - last_mouse_scroll_range_start);
-      XSETINT (*y, (last_mouse_scroll_range_end
-                   - last_mouse_scroll_range_start));
-    }
+  if (! NILP (last_mouse_scroll_bar))
+    x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
   else
     {
-      *f = last_mouse_frame = x_window_to_frame (guess);
-      if (! *f)
-       *x = *y = Qnil;
-      else
-       {
-         pixel_to_glyph_coords (*f, ix, iy, &ix, &iy, &last_mouse_glyph);
-         XSET (*x, Lisp_Int, ix);
-         XSET (*y, Lisp_Int, iy);
-       }
-    }
+      Window root;
+      int root_x, root_y;
 
-  mouse_moved = 0;
-  last_mouse_bar = 0;
+      Window dummy_window;
+      int dummy;
 
-  /* I don't know how to find the time for the last movement; it seems
-     like XQueryPointer ought to return it, but it doesn't.  So, we'll
-     return the time of the last MotionNotify event we received.  Note
-     that the use of motion hints means that this isn't guaranteed to
-     be accurate at all.  */
-  *time = last_mouse_movement_time;
+      mouse_moved = 0;
+      last_mouse_scroll_bar = Qnil;
+
+      /* Figure out which root window we're on.  */
+      XQueryPointer (x_current_display,
+                    DefaultRootWindow (x_current_display),
+
+                    /* The root window which contains the pointer.  */
+                    &root,
+
+                    /* Trash which we can't trust if the pointer is on
+                       a different screen.  */
+                    &dummy_window,
+
+                    /* The position on that root window.  */
+                    &root_x, &root_y, 
+
+                    /* More trash we can't trust.  */
+                    &dummy, &dummy,
+
+                    /* Modifier keys and pointer buttons, about which
+                       we don't care.  */
+                    (unsigned int *) &dummy);
+
+      /* Now we have a position on the root; find the innermost window
+        containing the pointer.  */
+      {
+       Window win, child;
+       int win_x, win_y;
+       int parent_x, parent_y;
+
+       win = root;
+       for (;;)
+         {
+           XTranslateCoordinates (x_current_display,
+                              
+                                  /* From-window, to-window.  */
+                                  root, win,
+
+                                  /* From-position, to-position.  */
+                                  root_x, root_y, &win_x, &win_y,
+
+                                  /* Child of win.  */
+                                  &child);
+
+           if (child == None)
+             break;
+
+           win = child;
+           parent_x = win_x;
+           parent_y = win_y;
+         }
+
+       /* Now we know that:
+          win is the innermost window containing the pointer
+          (XTC says it has no child containing the pointer),
+          win_x and win_y are the pointer's position in it
+          (XTC did this the last time through), and
+          parent_x and parent_y are the pointer's position in win's parent.
+          (They are what win_x and win_y were when win was child.
+          If win is the root window, it has no parent, and
+          parent_{x,y} are invalid, but that's okay, because we'll
+          never use them in that case.)  */
+
+       /* Is win one of our frames?  */
+       f1 = x_window_to_frame (win);
+      
+       /* If not, is it one of our scroll bars?  */
+       if (! f1)
+         {
+           struct scroll_bar *bar = x_window_to_scroll_bar (win);
+
+           if (bar)
+             {
+               f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+               win_x = parent_x;
+               win_y = parent_y;
+             }
+         }
+
+       if (f1)
+         {
+           /* Ok, we found a frame.  Convert from pixels to characters
+              and store all the values.  */
+
+           pixel_to_glyph_coords (f1, win_x, win_y, &win_x, &win_y,
+                                  &last_mouse_glyph);
+
+           *bar_window = Qnil;
+           *part = 0;
+           *f = f1;
+           XSET (*x, Lisp_Int, win_x);
+           XSET (*y, Lisp_Int, win_y);
+           *time = last_mouse_movement_time;
+         }
+      }
+    }
 
   UNBLOCK_INPUT;
 }
@@ -1671,54 +1901,55 @@ XTmouse_position (f, bar, part, x, y, time)
 #define XEvent XKeyPressedEvent
 #endif /* ! defined (HAVE_X11) */
 \f
-/* Scrollbar support.  */
+/* Scroll bar support.  */
 
-/* Map an X window that implements a scroll bar to the struct
-   scrollbar representing it.  */
-static struct scrollbar *
-x_window_to_scrollbar (window_id)
+/* Given an X window ID, find the struct scroll_bar which manages it.
+   This can be called in GC, so we have to make sure to strip off mark
+   bits.  */
+static struct scroll_bar *
+x_window_to_scroll_bar (window_id)
      Window window_id;
 {
   Lisp_Object tail, frame;
-  struct frame *f;
 
-  for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
+  for (tail = Vframe_list;
+       XGCTYPE (tail) == Lisp_Cons;
+       tail = XCONS (tail)->cdr)
     {
-      struct scrollbar *bar;
       Lisp_Object frame = XCONS (tail)->car;
+      Lisp_Object bar, condemned;
 
       /* All elements of Vframe_list should be frames.  */
-      if (XTYPE (frame) != Lisp_Frame)
+      if (XGCTYPE (frame) != Lisp_Frame)
        abort ();
 
-      /* Scan this frame's scrollbar list for a scrollbar with the
+      /* Scan this frame's scroll bar list for a scroll bar with the
          right window ID.  */
-      for (bar = XFRAME (frame)->display.x->vertical_scrollbars;
-          bar;
-          bar = bar->next)
-       if (bar->window == window_id)
-         return bar;
+      condemned = FRAME_CONDEMNED_SCROLL_BARS (XFRAME (frame));
+      for (bar = FRAME_SCROLL_BARS (XFRAME (frame));
+          /* This trick allows us to search both the ordinary and
+              condemned scroll bar lists with one loop.  */
+          ! GC_NILP (bar) || (bar = condemned,
+                              condemned = Qnil,
+                              ! GC_NILP (bar));
+          bar = XSCROLL_BAR(bar)->next)
+       if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id)
+         return XSCROLL_BAR (bar);
     }
 
   return 0;
 }
 
-
-/* Open a new X window to serve as a scrollbar.  */
-static struct scrollbar *
-x_scrollbar_create (frame, top, left, width, height)
-     FRAME_PTR frame;
+/* Open a new X window to serve as a scroll bar, and return the
+   scroll bar vector for it.  */
+static struct scroll_bar *
+x_scroll_bar_create (window, top, left, width, height)
+     struct window *window;
      int top, left, width, height;
 {
-  struct x_display *d = frame->display.x;
-
-  /* We can't signal a malloc error from within redisplay, so call
-     malloc instead of xmalloc.  */
-  struct scrollbar *bar =
-    (struct scrollbar *) malloc (sizeof (struct scrollbar));
-
-  if (! bar)
-    return 0;
+  FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
+  struct scroll_bar *bar =
+    XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
 
   BLOCK_INPUT;
 
@@ -1726,412 +1957,603 @@ x_scrollbar_create (frame, top, left, width, height)
     XSetWindowAttributes a;
     unsigned long mask;
 
-    a.background_pixel = d->background_pixel;
-    a.border_pixel = d->foreground_pixel;
-    a.event_mask = (KeyPressMask
-                   | ButtonPressMask | ButtonReleaseMask
-                   | ButtonMotionMask);
-    a.cursor = x_vertical_scrollbar_cursor;
+    a.background_pixel = frame->display.x->background_pixel;
+    a.event_mask = (ButtonPressMask | ButtonReleaseMask
+                   | ButtonMotionMask | PointerMotionHintMask
+                   | ExposureMask);
+    a.cursor = x_vertical_scroll_bar_cursor;
 
-    mask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
+    mask = (CWBackPixel | CWEventMask | CWCursor);
 
-    bar->window =
-      XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
+    SET_SCROLL_BAR_X_WINDOW
+      (bar, 
+       XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
 
-                    /* Position and size of scrollbar.  */
-                    top, left, width, height,
+                     /* Position and size of scroll bar.  */
+                     left, top, width, height,
 
-                    /* Border width, depth, class, and visual.  */
-                    1, CopyFromParent, CopyFromParent, CopyFromParent,
+                     /* Border width, depth, class, and visual.  */
+                     0, CopyFromParent, CopyFromParent, CopyFromParent,
 
-                    /* Attributes.  */
-                    mask, &a);
+                     /* Attributes.  */
+                     mask, &a));
   }
 
-  bar->frame = frame;
-  bar->top = top;
-  bar->left = left;
-  bar->width = width;
-  bar->height = height;
-  bar->start = bar->end = 0;
-  bar->judge_timestamp = d->judge_timestamp;
-  bar->dragging = -1;
+  XSET (bar->window, Lisp_Window, window);
+  XSET (bar->top,    Lisp_Int, top);
+  XSET (bar->left,   Lisp_Int, left);
+  XSET (bar->width,  Lisp_Int, width);
+  XSET (bar->height, Lisp_Int, height);
+  XSET (bar->start,  Lisp_Int, 0);
+  XSET (bar->end,    Lisp_Int, 0);
+  bar->dragging = Qnil;
 
   /* Add bar to its frame's list of scroll bars.  */
-  bar->next = d->vertical_scrollbars;
-  d->vertical_scrollbars = bar;
+  bar->next = FRAME_SCROLL_BARS (frame);
+  bar->prev = Qnil;
+  XSET (FRAME_SCROLL_BARS (frame), Lisp_Vector, bar);
+  if (! NILP (bar->next))
+    XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
 
-  XMapWindow (x_current_display, bar->window);
+  XMapWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
 
   UNBLOCK_INPUT;
+
+  return bar;
 }
 
-/* Draw BAR's handle in the proper position.  */
+/* 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.  */
 static void
-x_scrollbar_set_handle (bar, start, end)
-     struct scrollbar *bar;
+x_scroll_bar_set_handle (bar, start, end, rebuild)
+     struct scroll_bar *bar;
      int start, end;
+     int rebuild;
 {
+  int dragging = ! NILP (bar->dragging);
+  Window w = SCROLL_BAR_X_WINDOW (bar);
+  GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
+
+  /* If the display is already accurate, do nothing.  */
+  if (! rebuild
+      && start == XINT (bar->start)
+      && end == XINT (bar->end))
+    return;
+
   BLOCK_INPUT;
 
   {
-    int inside_width = (bar->width
-                       - VERTICAL_SCROLLBAR_LEFT_BORDER
-                       - VERTICAL_SCROLLBAR_RIGHT_BORDER);
-    int inside_height = (bar->height
-                        - VERTICAL_SCROLLBAR_TOP_BORDER
-                        - VERTICAL_SCROLLBAR_BOTTOM_BORDER);
+    int inside_width = VERTICAL_SCROLL_BAR_INSIDE_WIDTH (XINT (bar->width));
+    int inside_height = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
+    int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
 
     /* Make sure the values are reasonable, and try to preserve
        the distance between start and end.  */
-    if (end < start)
-      end = start;
-    if (start < VERTICAL_SCROLLBAR_TOP_BORDER)
-      {
-       end = VERTICAL_SCROLLBAR_TOP_BORDER + (end - start);
-       start = VERTICAL_SCROLLBAR_TOP_BORDER;
-      }
-    if (end > bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER)
-      {
-       start = ((bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER)
-                - (end - start));
-       end = bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER;
-      }
-    if (start < VERTICAL_SCROLLBAR_TOP_BORDER)
-      start = VERTICAL_SCROLLBAR_TOP_BORDER;
+    {
+      int length = end - start;
+
+      if (start < 0)
+       start = 0;
+      else if (start > top_range)
+       start = top_range;
+      end = start + length;
+
+      if (end < start)
+       end = start;
+      else if (end > top_range && ! dragging)
+       end = top_range;
+    }
 
-    /* Draw the empty space above the handle.  */
-    XClearArea (x_current_display, bar->window,
+    /* Store the adjusted setting in the scroll bar.  */
+    XSET (bar->start, Lisp_Int, start);
+    XSET (bar->end, Lisp_Int, end);
 
-               /* x, y, width, height, and exposures.  */
-               VERTICAL_SCROLLBAR_LEFT_BORDER,
-               VERTICAL_SCROLLBAR_TOP_BORDER,
-               inside_width + 1, start + 1,
-               False);
+    /* Clip the end position, just for display.  */
+    if (end > top_range)
+      end = top_range;
+
+    /* Draw bottom positions VERTICAL_SCROLL_BAR_MIN_HANDLE pixels
+       below top positions, to make sure the handle is always at least
+       that many pixels tall.  */
+    end += VERTICAL_SCROLL_BAR_MIN_HANDLE;
+
+    /* Draw the empty space above the handle.  Note that we can't clear
+       zero-height areas; that means "clear to end of window."  */
+    if (0 < start)
+      XClearArea (x_current_display, w,
+
+                 /* x, y, width, height, and exposures.  */
+                 VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                 VERTICAL_SCROLL_BAR_TOP_BORDER,
+                 inside_width, start,
+                 False);
 
     /* Draw the handle itself.  */
-    XFillRectangle (x_current_display, bar->window,
-                   bar->frame->display.x->normal_gc,
+    XFillRectangle (x_current_display, w, gc,
 
                    /* x, y, width, height */
-                   VERTICAL_SCROLLBAR_LEFT_BORDER, start,
-                   inside_width, (end - start) + 1);
+                   VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                   VERTICAL_SCROLL_BAR_TOP_BORDER + start,
+                   inside_width, end - start);
 
 
-    /* Draw the empty space below the handle.  */
-    XClearArea (x_current_display, bar->window,
+    /* Draw the empty space below the handle.  Note that we can't
+       clear zero-height areas; that means "clear to end of window." */
+    if (end < inside_height)
+      XClearArea (x_current_display, w,
 
-               /* x, y, width, height, and exposures.  */
-               VERTICAL_SCROLLBAR_LEFT_BORDER,
-               VERTICAL_SCROLLBAR_TOP_BORDER + end,
-               inside_width + 1, (inside_height - end) + 1,
-               False);
+                 /* x, y, width, height, and exposures.  */
+                 VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
+                 inside_width, inside_height - end,
+                 False);
 
-    bar->start = start;
-    bar->end = end;
   }
 
   UNBLOCK_INPUT;
 }
 
-/* Remove the scrollbar BAR.  */
+/* Move a scroll bar around on the screen, to accommodate changing
+   window configurations.  */
 static void
-x_scrollbar_remove (bar)
-     struct scrollbar *bar;
+x_scroll_bar_move (bar, top, left, width, height)
+     struct scroll_bar *bar;
+     int top, left, width, height;
 {
   BLOCK_INPUT;
 
-  /* Remove bar from the frame's list.  */
   {
-    struct scrollbar **ptr;
+    XWindowChanges wc;
+    unsigned int mask = 0;
 
-    for (ptr = &bar->frame->display.x->vertical_scrollbars;
-        *ptr;
-        ptr = &(*ptr)->next)
-      if (*ptr == bar)
-       {
-         *ptr = bar->next;
-         break;
-       }
-  }
+    wc.x = left;
+    wc.y = top;
+    wc.width = width;
+    wc.height = height;
 
-  /* Destroy the window.  */
-  XDestroyWindow (x_current_display, bar->window);
+    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;
+    
+    if (mask)
+      XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
+                       mask, &wc);
+  }
 
-  /* Free the storage.  */
-  free (bar);
+  XSET (bar->left,   Lisp_Int, left);
+  XSET (bar->top,    Lisp_Int, top);
+  XSET (bar->width,  Lisp_Int, width);
+  XSET (bar->height, Lisp_Int, height);
 
   UNBLOCK_INPUT;
 }
 
+/* Destroy the X window for BAR, and set its Emacs window's scroll bar
+   to nil.  */
 static void
-x_scrollbar_move (bar, top, left, width, height)
-     struct scrollbar *bar;
-     int top, left, width, height;
+x_scroll_bar_remove (bar)
+     struct scroll_bar *bar;
 {
-  BLOCK_INPUT;
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 
-  {
-    XWindowChanges wc;
-    unsigned int mask = 0;
-
-    wc.x = left;
-    wc.y = top;
-    wc.width = width;
-    wc.height = height;
+  BLOCK_INPUT;
 
-    if (left != bar->left)     mask |= CWX;
-    if (top != bar->top)       mask |= CWY;
-    if (width != bar->width)   mask |= CWWidth;
-    if (height != bar->height) mask |= CWHeight;
+  /* Destroy the window.  */
+  XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
 
-    XConfigureWindow (x_current_display, bar->window, mask, &wc);
-  }
+  /* Disassociate this scroll bar from its window.  */
+  XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
 
   UNBLOCK_INPUT;
 }
 
-/* Set BAR to be the vertical scroll bar for WINDOW.  Set its handle
-   to indicate that we are displaying PORTION characters out of a
-   total of WHOLE characters, starting at POSITION.  Return BAR.  If
-   BAR is zero, create a new scrollbar and return a pointer to it.  */
-static struct scrollbar *
-XTset_scrollbar (bar, window, portion, whole, position)
-     struct scrollbar *bar;
+/* 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;
      int portion, whole, position;
 {
   FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
-  struct x_display *d = f->display.x;
   int top = XINT (window->top);
-  int left = WINDOW_VERTICAL_SCROLLBAR_COLUMN (window);
-  int height = WINDOW_VERTICAL_SCROLLBAR_HEIGHT (window);
-
-  /* Where should this scrollbar be, pixelwise?  */
-  int pixel_top  = (d->internal_border_width + top  * FONT_HEIGHT (d->font));
-  int pixel_left = (d->internal_border_width + left * FONT_WIDTH  (d->font));
-  int pixel_width = VERTICAL_SCROLLBAR_PIXEL_WIDTH (f);
-  int pixel_height = VERTICAL_SCROLLBAR_PIXEL_HEIGHT (f, height);
-
-  /* Does the scrollbar exist yet?  */
-  if (! bar)
-    bar = x_scrollbar_create (f,
+  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 = VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f);
+  int pixel_height = VERTICAL_SCROLL_BAR_PIXEL_HEIGHT (f, height);
+
+  struct scroll_bar *bar;
+
+  /* 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);
   else
-    /* It may just need to be moved and resized.  */
-    x_scrollbar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
+    {
+      /* 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);
+    }
 
-  /* Set the scrollbar's current state, unless we're currently being
+  /* Set the scroll bar's current state, unless we're currently being
      dragged.  */
-
-  if (bar && bar->dragging == -1)
+  if (NILP (bar->dragging))
     {
-      int inside_height = (pixel_height
-                          - VERTICAL_SCROLLBAR_TOP_BORDER
-                          - VERTICAL_SCROLLBAR_BOTTOM_BORDER);
-      int start = (position * inside_height) / whole;
-      int end = ((position + portion) * inside_height) / whole;
+      int top_range =
+       VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
 
-      x_scrollbar_set_handle (bar, start, end);
+      if (whole == 0)
+       x_scroll_bar_set_handle (bar, 0, top_range, 0);
+      else
+       {
+         int start = ((double) position * top_range) / whole;
+         int end = ((double) (position + portion) * top_range) / whole;
+
+         x_scroll_bar_set_handle (bar, start, end, 0);
+       }
     }
 
-  return bar;
+  XSET (window->vertical_scroll_bar, Lisp_Vector, bar);
 }
 
+
 /* The following three hooks are used when we're doing a thorough
-   redisplay of the frame.  We don't explicitly know which scrollbars
+   redisplay of the frame.  We don't explicitly know which scroll bars
    are going to be deleted, because keeping track of when windows go
-   away is a real pain - can you say set-window-configuration?
-   Instead, we just assert at the beginning of redisplay that *all*
-   scrollbars are to be removed, and then save scrollbars from the
-   firey pit when we actually redisplay their window.  */
-
-/* Arrange for all scrollbars on FRAME to be removed at the next call
-   to `*judge_scrollbars_hook'.  A scrollbar may be spared if
-   `*redeem_scrollbar_hook' is applied to it before the judgement.  */
+   away is a real pain - "Can you say set-window-configuration, boys
+   and girls?"  Instead, we just assert at the beginning of redisplay
+   that *all* scroll bars are to be removed, and then save a scroll bar
+   from the fiery pit when we actually redisplay its window.  */
+
+/* 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.  */
 static void 
-XTcondemn_scrollbars (frame)
+XTcondemn_scroll_bars (frame)
      FRAME_PTR frame;
 {
-  /* Any scrollbars which don't get caught up to this will be deleted.  */
-  frame->display.x->judge_timestamp++;
+  /* The condemned list should be empty at this point; if it's not,
+     then the rest of Emacs isn't using the condemn/redeem/judge
+     protocol correctly.  */
+  if (! NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
+    abort ();
+
+  /* Move them all to the "condemned" list.  */
+  FRAME_CONDEMNED_SCROLL_BARS (frame) = FRAME_SCROLL_BARS (frame);
+  FRAME_SCROLL_BARS (frame) = Qnil;
 }
 
-/* Unmark BAR for deletion in this judgement cycle.  */
+/* Unmark WINDOW's scroll bar for deletion in this judgement cycle.
+   Note that WINDOW isn't necessarily condemned at all.  */
 static void
-XTredeem_scrollbar (bar)
-     struct scrollbar *bar;
+XTredeem_scroll_bar (window)
+     struct window *window;
 {
-  bar->judge_timestamp = bar->frame->display.x->judge_timestamp;
+  struct scroll_bar *bar;
+
+  /* We can't redeem this window's scroll bar if it doesn't have one.  */
+  if (NILP (window->vertical_scroll_bar))
+    abort ();
+
+  bar = XSCROLL_BAR (window->vertical_scroll_bar);
+
+  /* Unlink it from the condemned list.  */
+  {
+    FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
+
+    if (NILP (bar->prev))
+      {
+       /* If the prev pointer is nil, it must be the first in one of
+           the lists.  */
+       if (EQ (FRAME_SCROLL_BARS (f), window->vertical_scroll_bar))
+         /* It's not condemned.  Everything's fine.  */
+         return;
+       else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
+                    window->vertical_scroll_bar))
+         FRAME_CONDEMNED_SCROLL_BARS (f) = bar->next;
+       else
+         /* If its prev pointer is nil, it must be at the front of
+             one or the other!  */
+         abort ();
+      }
+    else
+      XSCROLL_BAR (bar->prev)->next = bar->next;
+
+    if (! NILP (bar->next))
+      XSCROLL_BAR (bar->next)->prev = bar->prev;
+
+    bar->next = FRAME_SCROLL_BARS (f);
+    bar->prev = Qnil;
+    XSET (FRAME_SCROLL_BARS (f), Lisp_Vector, bar);
+    if (! NILP (bar->next))
+      XSET (XSCROLL_BAR (bar->next)->prev, Lisp_Vector, bar);
+  }
 }
 
-/* Remove all scrollbars on FRAME that haven't been saved since the
-   last call to `*condemn_scrollbars_hook'.  */
+/* Remove all scroll bars on FRAME that haven't been saved since the
+   last call to `*condemn_scroll_bars_hook'.  */
 static void
-XTjudge_scrollbars(frame)
-     FRAME_PTR frame;
+XTjudge_scroll_bars (f)
+     FRAME_PTR f;
 {
-  int judge_timestamp = frame->display.x->judge_timestamp;
-  struct scrollbar *bar, *next;
+  Lisp_Object bar, next;
+
+  bar = FRAME_CONDEMNED_SCROLL_BARS (f);
 
-  for (bar = frame->display.x->vertical_scrollbars; bar; bar = next)
+  /* Clear out the condemned list now so we won't try to process any
+     more events on the hapless scroll bars.  */
+  FRAME_CONDEMNED_SCROLL_BARS (f) = Qnil;
+
+  for (; ! NILP (bar); bar = next)
     {
-      next = bar->next;
-      if (bar->judge_timestamp < judge_timestamp)
-       x_scrollbar_remove (bar);
+      struct scroll_bar *b = XSCROLL_BAR (bar);
+
+      x_scroll_bar_remove (b);
+
+      next = b->next;
+      b->next = b->prev = Qnil;
     }
+
+  /* Now there should be no references to the condemned scroll bars,
+     and they should get garbage-collected.  */
 }
 
 
-/* Handle an Expose or GraphicsExpose event on a scrollbar.  */
+/* Handle an Expose or GraphicsExpose event on a scroll bar.
+
+   This may be called from a signal handler, so we have to ignore GC
+   mark bits.  */
 static void
-x_scrollbar_expose (bar, event)
-     struct scrollbar *bar;
+x_scroll_bar_expose (bar, event)
+     struct scroll_bar *bar;
      XEvent *event;
 {
+  Window w = SCROLL_BAR_X_WINDOW (bar);
+  GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
+
   BLOCK_INPUT;
 
-  x_scrollbar_set_handle (bar, bar->start, bar->end);
+  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. */
+  XDrawRectangle (x_current_display, w, gc,
+
+                 /* x, y, width, height */
+                 0, 0, XINT (bar->width) - 1, XINT (bar->height) - 1);
 
-  /* Draw the extra-thick border on the right.  */
-  XFillRectangle (x_current_display, bar->window,
-                 bar->frame->display.x->normal_gc,
+  /* Draw another line to make the extra-thick border on the right.  */
+  XFillRectangle (x_current_display, w, gc,
 
                  /* x, y, width, height */
-                 bar->width - VERTICAL_SCROLLBAR_RIGHT_BORDER, 0,
-                 VERTICAL_SCROLLBAR_RIGHT_BORDER, bar->height + 1);
+                 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
 
   UNBLOCK_INPUT;
 }
 
-/* Handle an exposure event which might be over the extra scrollbar space.  */
+/* Handle a mouse click on the scroll bar BAR.  If *EMACS_EVENT's kind
+   is set to something other than no_event, it is enqueued.
+
+   This may be called from a signal handler, so we have to ignore GC
+   mark bits.  */
 static void
-x_scrollbar_background_expose (frame, event)
-     FRAME_PTR frame;
+x_scroll_bar_handle_click (bar, event, emacs_event)
+     struct scroll_bar *bar;
      XEvent *event;
+     struct input_event *emacs_event;
 {
-  /* Where is the extra scrollbar space, anyway?  */
-  int width = VERTICAL_SCROLLBAR_PIXEL_WIDTH (frame);
-  int height = PIXEL_HEIGHT (frame);
-  int x = PIXEL_WIDTH (frame) - width;
-  int y = 0;
+  if (XGCTYPE (bar->window) != Lisp_Window)
+    abort ();
 
-  BLOCK_INPUT;
+  emacs_event->kind = scroll_bar_click;
+  XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1);
+  emacs_event->modifiers =
+    (x_x_to_emacs_modifiers (event->xbutton.state)
+     | (event->type == ButtonRelease
+       ? up_modifier
+       : down_modifier));
+  emacs_event->frame_or_window = bar->window;
+  emacs_event->timestamp = event->xbutton.time;
+  {
+    int internal_height =
+      VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
+    int top_range =
+      VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
+    int y = event->xbutton.y - VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+    if (y < 0) y = 0;
+    if (y > top_range) y = top_range;
+
+    if (y < XINT (bar->start))
+      emacs_event->part = scroll_bar_above_handle;
+    else if (y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+      emacs_event->part = scroll_bar_handle;
+    else
+      emacs_event->part = scroll_bar_below_handle;
 
-  /* Clear it out.  */
-  XClearArea (x_current_display, FRAME_X_WINDOW (frame),
+    /* Just because the user has clicked on the handle doesn't mean
+       they want to drag it.  Lisp code needs to be able to decide
+       whether or not we're dragging.  */
+#if 0
+    /* If the user has just clicked on the handle, record where they're
+       holding it.  */
+    if (event->type == ButtonPress
+       && emacs_event->part == scroll_bar_handle)
+      XSET (bar->dragging, Lisp_Int, y - XINT (bar->start));
+#endif
 
-             /* x, y, width, height, expose */
-             x, y, width+1, height+1, False);
+    /* If the user has released the handle, set it to its final position.  */
+    if (event->type == ButtonRelease
+       && ! NILP (bar->dragging))
+      {
+       int new_start = y - XINT (bar->dragging);
+       int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
 
-  /* Draw the border.  */
-  XDrawRectangle (x_current_display, FRAME_X_WINDOW (frame),
-                 frame->display.x->normal_gc,
-                 x, y, width, height);
+       x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+       bar->dragging = Qnil;
+      }
 
-  /* Draw the extra-thick border on the right edge.  */
-  XFillRectangle (x_current_display, FRAME_X_WINDOW (frame),
-                frame->display.x->normal_gc,
-                x + width - VERTICAL_SCROLLBAR_RIGHT_BORDER, 0,
-                VERTICAL_SCROLLBAR_RIGHT_BORDER, height + 1);
+    /* Same deal here as the other #if 0.  */
+#if 0
+    /* Clicks on the handle are always reported as occurring at the top of 
+       the handle.  */
+    if (emacs_event->part == scroll_bar_handle)
+      emacs_event->x = bar->start;
+    else
+      XSET (emacs_event->x, Lisp_Int, y);
+#else
+    XSET (emacs_event->x, Lisp_Int, y);
+#endif
 
-  UNBLOCK_INPUT;
+    XSET (emacs_event->y, Lisp_Int, top_range);
+  }
 }
 
-/* Handle a mouse click on the scrollbar BAR.  If *EMACS_EVENT's kind
-   is set to something other than no_event, it is enqueued.  */
+/* Handle some mouse motion while someone is dragging the scroll bar.
+
+   This may be called from a signal handler, so we have to ignore GC
+   mark bits.  */
 static void
-x_scrollbar_handle_click (bar, event, emacs_event)
-     struct scrollbar *bar;
+x_scroll_bar_note_movement (bar, event)
+     struct scroll_bar *bar;
      XEvent *event;
-     struct input_event *emacs_event;
 {
-  emacs_event->kind = scrollbar_click;
-  XSETINT (emacs_event->code, event->xbutton.button - Button1);
-  emacs_event->modifiers =
-    (x_convert_modifiers (event->xbutton.state)
-     | (event->type == ButtonRelease
-       ? up_modifier
-       : down_modifier));
-  emacs_event->part =
-    ((event->xbutton.x < bar->start) ? scrollbar_above_handle
-     : (event->xbutton.x < bar->end) ? scrollbar_handle
-     : scrollbar_below_handle);
-  emacs_event->scrollbar = bar;
-
-  if (event->xbutton.y < VERTICAL_SCROLLBAR_TOP_BORDER)
-    event->xbutton.y = VERTICAL_SCROLLBAR_TOP_BORDER;
-  if (event->xbutton.y > bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER)
-    event->xbutton.y = bar->height - VERTICAL_SCROLLBAR_BOTTOM_BORDER;
-  XSETINT (emacs_event->x,
-          event->xbutton.y - VERTICAL_SCROLLBAR_TOP_BORDER);
-  XSETINT (emacs_event->y,
-          (bar->height
-           - VERTICAL_SCROLLBAR_TOP_BORDER
-           - VERTICAL_SCROLLBAR_BOTTOM_BORDER));
-
-  emacs_event->frame = bar->frame;
-  emacs_event->timestamp = event->xbutton.time;
+  last_mouse_movement_time = event->xmotion.time;
 
-  if (event->type == ButtonPress
-      && emacs_event->part == scrollbar_handle)
-    bar->dragging = event->xbutton.x - bar->start;
-  else
+  mouse_moved = 1;
+  XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
+
+  /* If we're dragging the bar, display it.  */
+  if (! GC_NILP (bar->dragging))
     {
-      int new_start = event->xbutton.x - bar->dragging;
-      int new_end = new_start + (bar->end - bar->start);
+      /* Where should the handle be now?  */
+      int new_start = event->xmotion.y - XINT (bar->dragging);
 
-      x_scrollbar_set_handle (bar, new_start, new_end);
-      bar->dragging = -1;
+      if (new_start != XINT (bar->start))
+       {
+         int new_end = new_start + (XINT (bar->end) - XINT (bar->start));
+       
+         x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+       }
     }
-}
 
+  /* Call XQueryPointer so we'll get an event the next time the mouse
+     moves and we can see *still* on the same position.  */
+  {
+    int dummy;
+      
+    XQueryPointer (event->xmotion.display, event->xmotion.window,
+                  (Window *) &dummy, (Window *) &dummy,
+                  &dummy, &dummy, &dummy, &dummy,
+                  (unsigned int *) &dummy);
+  }
+}
 
-/* Handle some mouse motion while someone is dragging the scrollbar.  */
+/* Return information to the user about the current position of the mouse
+   on the scroll bar.  */
 static void
-x_scrollbar_handle_motion (bar, event)
-     struct scrollbar *bar;
-     XEvent *event;
+x_scroll_bar_report_motion (f, bar_window, part, x, y, time)
+     FRAME_PTR *f;
+     Lisp_Object *bar_window;
+     enum scroll_bar_part *part;
+     Lisp_Object *x, *y;
+     unsigned long *time;
 {
-  last_mouse_movement_time = event->xmotion.time;
+  struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
+  int win_x, win_y;
+  Window dummy_window;
+  int dummy_coord;
+  unsigned int dummy_mask;
+
+  BLOCK_INPUT;
+
+  /* Get the mouse's position relative to the scroll bar window, and
+     report that.  */
+  if (! XQueryPointer (x_current_display,
+                      SCROLL_BAR_X_WINDOW (bar),
+
+                      /* Root, child, root x and root y.  */
+                      &dummy_window, &dummy_window,
+                      &dummy_coord, &dummy_coord,
+
+                      /* Position relative to scroll bar.  */
+                      &win_x, &win_y,
+
+                      /* Mouse buttons and modifier keys.  */
+                      &dummy_mask))
+    *f = 0;
+  else
+    {
+      int inside_height
+       = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
+      int top_range
+       = VERTICAL_SCROLL_BAR_TOP_RANGE     (XINT (bar->height));
+
+      win_y -= VERTICAL_SCROLL_BAR_TOP_BORDER;
+
+      if (! NILP (bar->dragging))
+       win_y -= XINT (bar->dragging);
+
+      if (win_y < 0)
+       win_y = 0;
+      if (win_y > top_range)
+       win_y = top_range;
+
+      *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+      *bar_window = bar->window;
+
+      if (! NILP (bar->dragging))
+       *part = scroll_bar_handle;
+      else if (win_y < XINT (bar->start))
+       *part = scroll_bar_above_handle;
+      else if (win_y < XINT (bar->end) + VERTICAL_SCROLL_BAR_MIN_HANDLE)
+       *part = scroll_bar_handle;
+      else
+       *part = scroll_bar_below_handle;
+
+      XSET (*x, Lisp_Int, win_y);
+      XSET (*y, Lisp_Int, top_range);
+
+      mouse_moved = 0;
+      last_mouse_scroll_bar = Qnil;
+    }
+
+  *time = last_mouse_movement_time;
+
+  UNBLOCK_INPUT;
+}
 
-  mouse_moved = 1;
-  last_mouse_bar = bar;
-  last_mouse_bar_frame = bar->frame;
-  last_mouse_part = (bar->dragging == -1 ? scrollbar_handle
-                    : (event->xbutton.x < bar->start) ? scrollbar_above_handle
-                    : (event->xbutton.x < bar->end) ? scrollbar_handle
-                    : scrollbar_below_handle);
-  last_mouse_scroll_range_start = bar->top + VERTICAL_SCROLLBAR_TOP_BORDER;
-  last_mouse_scroll_range_end = (bar->top
-                                + bar->height
-                                - VERTICAL_SCROLLBAR_BOTTOM_BORDER);
 
-  /* If we're dragging the bar, display it.  */
-  if (bar->dragging != -1)
-    {
-      /* Where should the handle be now?  */
-      int new_start = event->xmotion.x - bar->dragging;
+/* The screen has been cleared so we may have changed foreground or
+   background colors, and the scroll bars may need to be redrawn.
+   Clear out the scroll bars, and ask for expose events, so we can
+   redraw them.  */
 
-      if (new_start != bar->start)
-       {
-         int new_end = new_start + (bar->end - bar->start);
-       
-         x_scrollbar_set_handle (bar, new_start, new_end);
-       }
-    }
+x_scroll_bar_clear (f)
+     FRAME_PTR f;
+{
+  Lisp_Object bar;
 
-  /* Call XQueryPointer so we'll get an event the next time the mouse
-     moves and we can see *still* on the same position.  */
-  {
-    int dummy;
-      
-    XQueryPointer (event->xmotion.display, event->xmotion.window,
-                  (Window *) &dummy, (Window *) &dummy,
-                  &dummy, &dummy, &dummy, &dummy,
-                  (unsigned int *) &dummy);
-  }
+  for (bar = FRAME_SCROLL_BARS (f);
+       XTYPE (bar) == Lisp_Vector;
+       bar = XSCROLL_BAR (bar)->next)
+    XClearArea (x_current_display, SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)),
+               0, 0, 0, 0, True);
 }
 
 
@@ -2164,6 +2586,14 @@ Atom Xatom_wm_delete_window;
 Atom Xatom_wm_configure_denied;          /* When our config request is denied */
 Atom Xatom_wm_window_moved;      /* When the WM moves us. */
 
+/* Window manager communication.  */
+Atom Xatom_wm_change_state;
+
+/* Record the last 100 characters stored
+   to help debug the loss-of-chars-during-GC problem.  */
+int temp_index;
+short temp_buffer[100];
+
 /* Read events coming from the X server.
    This routine is called by the SIGIO handler.
    We return as soon as there are no more events to be read.
@@ -2190,17 +2620,17 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
   int items_pending;           /* How many items are in the X queue. */
   XEvent event;
   struct frame *f;
-  int event_found;
+  int event_found = 0;
   int prefix;
   Lisp_Object part;
 
-  if (x_input_blocked)
+  if (interrupt_input_blocked)
     {
-      x_pending_input = 1;
+      interrupt_input_pending = 1;
       return -1;
     }
 
-  x_pending_input = 0;
+  interrupt_input_pending = 0;
   BLOCK_INPUT;
        
   if (numchars <= 0)
@@ -2244,7 +2674,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                    f = x_window_to_frame (event.xclient.window);
                    if (f)
                      x_focus_on_frame (f);
-                   /* Not certain about handling scrollbars here */
+                   /* Not certain about handling scroll bars here */
                  }
                else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
                  {
@@ -2280,18 +2710,65 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          }
          break;
 
+#ifdef NEW_SELECTIONS
+       case SelectionNotify:
+         x_handle_selection_notify (&event);
+         break;
+#endif
+
        case SelectionClear:    /* Someone has grabbed ownership. */
+#ifdef NEW_SELECTIONS
+         {
+           XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
+
+           if (numchars == 0)
+             abort ();
+
+           bufp->kind = selection_clear_event;
+           SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
+           SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
+           SELECTION_EVENT_TIME (bufp) = eventp->time;
+           bufp++;
+
+           count += 1;
+           numchars -= 1;
+         }
+#else
          x_disown_selection (event.xselectionclear.window,
                              event.xselectionclear.selection,
                              event.xselectionclear.time);
+#endif
          break;
 
        case SelectionRequest:  /* Someone wants our selection. */
+#ifdef NEW_SELECTIONS
+         {
+           XSelectionRequestEvent *eventp = (XSelectionRequestEvent *) &event;
+
+           if (numchars == 0)
+             abort ();
+
+           bufp->kind = selection_request_event;
+           SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
+           SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
+           SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
+           SELECTION_EVENT_TARGET (bufp) = eventp->target;
+           SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
+           SELECTION_EVENT_TIME (bufp) = eventp->time;
+           bufp++;
+
+           count += 1;
+           numchars -= 1;
+         }
+#else
          x_answer_selection_request (event);
+#endif
          break;
 
        case PropertyNotify:
-
+#ifdef NEW_SELECTIONS
+         x_handle_property_notify (&event);
+#else
          /* If we're being told about a root window property, then it's
             a cut buffer change.  */
          if (event.xproperty.window == ROOT_WINDOW)
@@ -2305,6 +2782,13 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                 about re-selecting. */
              x_send_incremental (event);
            }
+#endif
+         break;
+
+       case ReparentNotify:
+         f = x_window_to_frame (event.xreparent.window);
+         if (f)
+           f->display.x->parent_desc = event.xreparent.parent;
          break;
 
        case Expose:
@@ -2322,16 +2806,15 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                  dumprectangle (x_window_to_frame (event.xexpose.window),
                                 event.xexpose.x, event.xexpose.y,
                                 event.xexpose.width, event.xexpose.height);
-                 x_scrollbar_background_expose (f, &event);
                }
            }
          else
            {
-             struct scrollbar *bar
-               = x_window_to_scrollbar (event.xexpose.window);
+             struct scroll_bar *bar
+               = x_window_to_scroll_bar (event.xexpose.window);
 
              if (bar)
-               x_scrollbar_expose (bar, &event);
+               x_scroll_bar_expose (bar, &event);
            }
          break;
 
@@ -2345,7 +2828,6 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                             event.xgraphicsexpose.x, event.xgraphicsexpose.y,
                             event.xgraphicsexpose.width,
                             event.xgraphicsexpose.height);
-             x_scrollbar_background_expose (f, &event);
            }
          break;
 
@@ -2411,6 +2893,12 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                 disabled; you don't want to spend time updating a
                 display that won't ever be seen.  */
              f->async_visible = 0;
+             /* The window manager never makes a window invisible
+                ("withdrawn"); all it does is switch between visible
+                and iconified.  Frames get into the invisible state
+                only through x_make_frame_invisible.  */
+             if (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f))
+               f->async_iconified = 1;
            }
          break;
 
@@ -2447,18 +2935,19 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 
          if (f != 0)
            {
-             KeySym keysym;
+             KeySym keysym, orig_keysym;
              char copy_buffer[80];
-             int modifiers = event.xkey.state;
+             int modifiers;
 
-             /* Some keyboards generate different characters
-                depending on the state of the meta key, in an attempt
-                to support non-English typists.  It would be nice to
-                keep this functionality somehow, but for now, we will
-                just clear the meta-key flag to get the 'pure' character.  */
-             event.xkey.state &= ~Mod1Mask;
+             event.xkey.state
+               |= x_emacs_to_x_modifiers (extra_keyboard_modifiers);
+             modifiers = event.xkey.state;
 
              /* This will have to go some day...  */
+
+             /* make_lispy_event turns chars into control chars.
+                Don't do it here because XLookupString is too eager.  */
+             event.xkey.state &= ~ControlMask;
              nbytes =
                XLookupString (&event.xkey, copy_buffer, 80, &keysym,
                               &compose_status);
@@ -2466,19 +2955,44 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
              /* Strip off the vendor-specific keysym bit, and take a shot
                 at recognizing the codes.  HP servers have extra keysyms
                 that fit into the MiscFunctionKey category.  */
+             orig_keysym = keysym;
              keysym &= ~(1<<28);
 
              if (numchars > 1)
                {
-                 if (IsCursorKey (keysym)          /* 0xff50 <= x < 0xff60 */
-                     || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */
-                     || IsKeypadKey (keysym)       /* 0xff80 <= x < 0xffbe */
-                     || IsFunctionKey (keysym))    /* 0xffbe <= x < 0xffe1 */
+                 if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
+                      || keysym == XK_Delete
+                      || IsCursorKey (keysym) /* 0xff50 <= x < 0xff60 */
+                      || IsMiscFunctionKey (keysym) /* 0xff60 <= x < VARIES */
+#ifdef HPUX
+                      /* This recognizes the "extended function keys".
+                         It seems there's no cleaner way.
+                         Test IsModifierKey to avoid handling mode_switch
+                         incorrectly.  */
+                      || ((unsigned) (keysym) >= XK_Select
+                          && (unsigned)(keysym) < XK_KP_Space)
+#endif
+                      || IsKeypadKey (keysym) /* 0xff80 <= x < 0xffbe */
+                      || IsFunctionKey (keysym) /* 0xffbe <= x < 0xffe1 */
+                      || x_is_vendor_fkey (orig_keysym))
+                     && ! (IsModifierKey (orig_keysym)
+#ifndef HAVE_X11R5
+#ifdef XK_Mode_switch
+                           || ((unsigned)(orig_keysym) == XK_Mode_switch)
+#endif
+#ifdef XK_Num_Lock
+                           || ((unsigned)(orig_keysym) == XK_Num_Lock)
+#endif
+#endif /* not HAVE_X11R5 */
+                           ))
                    {
+                     if (temp_index == sizeof temp_buffer / sizeof (short))
+                       temp_index = 0;
+                     temp_buffer[temp_index++] = keysym;
                      bufp->kind = non_ascii_keystroke;
-                     XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff50);
-                     bufp->frame = f;
-                     bufp->modifiers = x_convert_modifiers (modifiers);
+                     XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00);
+                     XSET (bufp->frame_or_window, Lisp_Frame, f);
+                     bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
                      bufp->timestamp = event.xkey.time;
                      bufp++;
                      count++;
@@ -2488,30 +3002,27 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                    {
                      register int i;
 
-                     if (nbytes == 1)
+                     for (i = 0; i < nbytes; i++)
                        {
-                         if (modifiers & x_meta_mod_mask)
-                           *copy_buffer |= METABIT;
+                         if (temp_index == sizeof temp_buffer / sizeof (short))
+                           temp_index = 0;
+                         temp_buffer[temp_index++] = copy_buffer[i];
                          bufp->kind = ascii_keystroke;
-                         XSET (bufp->code, Lisp_Int, *copy_buffer);
-                         bufp->frame = f;
+                         XSET (bufp->code, Lisp_Int, copy_buffer[i]);
+                         XSET (bufp->frame_or_window, Lisp_Frame, f);
+                         bufp->modifiers = x_x_to_emacs_modifiers (modifiers);
                          bufp->timestamp = event.xkey.time;
                          bufp++;
                        }
-                     else
-                       for (i = nbytes - 1; i > 1; i--)
-                         {
-                           bufp->kind = ascii_keystroke;
-                           XSET (bufp->code, Lisp_Int, copy_buffer[i]);
-                           bufp->frame = f;
-                           bufp->timestamp = event.xkey.time;
-                           bufp++;
-                         }
 
                      count += nbytes;
                      numchars -= nbytes;
                    }
+                 else
+                   abort ();
                }
+             else
+               abort ();
            }
          break;
 #else /* ! defined (HAVE_X11) */
@@ -2553,7 +3064,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                    bufp->kind = ascii_keystroke;
                    XSET (bufp->code, Lisp_Int, where_mapping[i]);
                    XSET (bufp->time, Lisp_Int, event.xkey.time);
-                   bufp->frame = f;
+                   XSET (bufp->frame_or_window, Lisp_Frame, f);
                    bufp++;
                  }
                count += nbytes;
@@ -2668,46 +3179,70 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          {
            f = x_window_to_frame (event.xmotion.window);
            if (f)
-             note_mouse_position (f, &event.xmotion);
+             note_mouse_movement (f, &event.xmotion);
            else
              {
-               struct scrollbar *bar =
-                 x_window_to_scrollbar (event.xmotion.window);
+               struct scroll_bar *bar =
+                 x_window_to_scroll_bar (event.xmotion.window);
 
                if (bar)
-                 x_scrollbar_handle_motion (bar, &event);
+                 x_scroll_bar_note_movement (bar, &event);
              }
          }
          break;
 
        case ConfigureNotify:
-         {
-           int rows, columns;
-           f = x_window_to_frame (event.xconfigure.window);
-           if (!f)
-             break;
-
-           columns = PIXEL_TO_CHAR_WIDTH (f, event.xconfigure.width);
-           rows = PIXEL_TO_CHAR_HEIGHT (f, event.xconfigure.height);
+         f = x_window_to_frame (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);
+
+             /* 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.  */
+             if (columns != f->width
+                 || rows != f->height
+                 || event.xconfigure.width != f->display.x->pixel_width
+                 || event.xconfigure.height != f->display.x->pixel_height)
+               {
+                 change_frame_size (f, rows, columns, 0, 1);
+                 SET_FRAME_GARBAGED (f);
+               }
 
-           /* 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.  */
-           if (columns != f->width
-               || rows != f->height
-               || event.xconfigure.width != f->display.x->pixel_width
-               || event.xconfigure.height != f->display.x->pixel_height)
-             {
-               change_frame_size (f, rows, columns, 0, 1);
-               SET_FRAME_GARBAGED (f);
-             }
+             if (! event.xconfigure.send_event)
+               {
+                 Window win, child;
+                 int win_x, win_y;
+
+                 /* Find the position of the outside upper-left corner of
+                    the window, in the root coordinate system.  Don't
+                    refer to the parent window here; we may be processing
+                    this event after the window manager has changed our
+                    parent, but before we have reached the ReparentNotify.  */
+                 XTranslateCoordinates (x_current_display,
+                              
+                                        /* From-window, to-window.  */
+                                        f->display.x->window_desc,
+                                        ROOT_WINDOW,
+
+                                        /* From-position, to-position.  */
+                                        -event.xconfigure.border_width,
+                                        -event.xconfigure.border_width,
+                                        &win_x, &win_y,
+
+                                        /* Child of win.  */
+                                        &child);
+                 event.xconfigure.x = win_x;
+                 event.xconfigure.y = win_y;
+               }
 
-           f->display.x->pixel_width = event.xconfigure.width;
-           f->display.x->pixel_height = event.xconfigure.height;
-           f->display.x->left_pos = event.xconfigure.x;
-           f->display.x->top_pos = event.xconfigure.y;
-           break;
-         }
+             f->display.x->pixel_width = event.xconfigure.width;
+             f->display.x->pixel_height = event.xconfigure.height;
+             f->display.x->left_pos = event.xconfigure.x;
+             f->display.x->top_pos = event.xconfigure.y;
+           }
+         break;
 
        case ButtonPress:
        case ButtonRelease:
@@ -2722,15 +3257,15 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
              {
                if (!x_focus_frame || (f == x_focus_frame))
                  construct_mouse_click (&emacs_event,
-                                        &event, f, Qnil, 0);
+                                        &event, f);
              }
            else
              {
-               struct scrollbar *bar =
-                 x_window_to_scrollbar (event.xbutton.window);
+               struct scroll_bar *bar =
+                 x_window_to_scroll_bar (event.xbutton.window);
 
                if (bar)
-                 x_scrollbar_handle_click (bar, &event, &emacs_event);
+                 x_scroll_bar_handle_click (bar, &event, &emacs_event);
              }
 
            if (numchars >= 1 && emacs_event.kind != no_event)
@@ -2768,13 +3303,13 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            {
              bufp->kind = ascii_keystroke;
              bufp->code = (char) 'X' & 037; /* C-x */
-             bufp->frame = f;
+             XSET (bufp->frame_or_window, Lisp_Frame, f);
              XSET (bufp->time, Lisp_Int, event.xkey.time);
              bufp++;
 
              bufp->kind = ascii_keystroke;
              bufp->code = (char) 0; /* C-@ */
-             bufp->frame = f;
+             XSET (bufp->frame_or_window, Lisp_Frame, f);
              XSET (bufp->time, Lisp_Int, event.xkey.time);
              bufp++;
 
@@ -2811,24 +3346,23 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
        }
     }
 
-#if 0
 #ifdef HAVE_SELECT
   if (expected && ! event_found)
     {
       /* AOJ 880406: if select returns true but XPending doesn't, it means that
         there is an EOF condition; in other words, that X has died.
         Act as if there had been a hangup. */
-
       int fd = ConnectionNumber (x_current_display);
-      int mask = 1 << fd;
+      SELECT_TYPE mask;
+      EMACS_TIME timeout;
 
-      if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
-                      (EMACS_TIME) 0)
+      FD_SET(fd, &mask);
+      EMACS_SET_SECS_USECS (timeout, 0, 0);
+      if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0, &timeout)
          && !XStuffPending ())
        kill (getpid (), SIGHUP);
     }
 #endif /* ! defined (HAVE_SELECT) */
-#endif /* ! 0 */
 
 #ifndef HAVE_X11
   if (updating_frame == 0)
@@ -2914,15 +3448,12 @@ static void
 x_draw_box (f)
      struct frame *f;
 {
-  int left = f->cursor_x * FONT_WIDTH (f->display.x->font)
-    + f->display.x->internal_border_width;
-  int top = f->cursor_y * FONT_HEIGHT (f->display.x->font)
-    + f->display.x->internal_border_width;
+  int left = CHAR_TO_PIXEL_COL (f, f->cursor_x);
+  int top  = CHAR_TO_PIXEL_ROW (f, f->cursor_y);
   int width = FONT_WIDTH (f->display.x->font);
   int height = FONT_HEIGHT (f->display.x->font);
 
 #ifdef HAVE_X11
-  /* Perhaps we should subtract 1 from width and height... */
   XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
                  f->display.x->cursor_gc,
                  left, top, width - 1, height - 1);
@@ -2962,93 +3493,98 @@ clear_cursor (f)
 
 #ifdef HAVE_X11
   x_display_cursor (f, 0);
-#if 0
-  XClearArea (x_current_display, FRAME_X_WINDOW (f),
-             f->phys_cursor_x * FONT_WIDTH (f->display.x->font)
-             + f->display.x->internal_border_width,
-             f->phys_cursor_y * FONT_HEIGHT (f->display.x->font)
-             + f->display.x->internal_border_width,
-             FONT_WIDTH (f->display.x->font) + 1, FONT_HEIGHT (f->display.x->font) + 1, False);
-#endif /* ! 0 */
 #else /* ! defined (HAVE_X11) */
   XPixSet (FRAME_X_WINDOW (f),
-          f->phys_cursor_x * FONT_WIDTH (f->display.x->font) + f->display.x->internal_border_width,
-          f->phys_cursor_y * FONT_HEIGHT (f->display.x->font) + f->display.x->internal_border_width,
+          CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
+          CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
           FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font),
           f->display.x->background_pixel);
 #endif /* ! defined (HAVE_X11) */
   f->phys_cursor_x = -1;
 }
 
+/* Redraw the glyph at ROW, COLUMN on frame F, in the style
+   HIGHLIGHT.  HIGHLIGHT is as defined for dumpglyphs.  Return the
+   glyph drawn.  */
+
+static void
+x_draw_single_glyph (f, row, column, glyph, highlight)
+     struct frame *f;
+     int row, column;
+     GLYPH glyph;
+     int highlight;
+{
+  dumpglyphs (f,
+             CHAR_TO_PIXEL_COL (f, column),
+             CHAR_TO_PIXEL_ROW (f, row),
+             &glyph, 1, highlight);
+}
+
 static void
 x_display_bar_cursor (f, on)
      struct frame *f;
      int on;
 {
-  register int phys_x = f->phys_cursor_x;
-  register int phys_y = f->phys_cursor_y;
-  register int x1;
-  register int y1;
-  register int y2;
+  struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
 
-  if (! FRAME_VISIBLE_P (f) || (! on && f->phys_cursor_x < 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 curs_x and curs_y may be off the frame.  */
+  if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
     return;
 
-#ifdef HAVE_X11
-  if (phys_x >= 0 &&
-      (!on || phys_x != f->cursor_x || phys_y != f->cursor_y))
-    {
-      x1 = phys_x * FONT_WIDTH (f->display.x->font)
-       + f->display.x->internal_border_width;
-      y1 = phys_y * FONT_HEIGHT (f->display.x->font)
-       + f->display.x->internal_border_width - 1;
-      y2 = y1 + FONT_HEIGHT (f->display.x->font) + 1;
+  if (! on && f->phys_cursor_x < 0)
+    return;
 
-      XDrawLine (x_current_display, FRAME_X_WINDOW (f),
-                f->display.x->reverse_gc, x1, y1, x1, y2);
+  /* If we're not updating, then we want to use the current frame's
+     cursor position, not our local idea of where the cursor ought to be.  */
+  if (f != updating_frame)
+    {
+      curs_x = FRAME_CURSOR_X (f);
+      curs_y = FRAME_CURSOR_Y (f);
+    }
 
-      f->phys_cursor_x = phys_x = -1;
+  /* If there is anything wrong with the current cursor state, remove it.  */
+  if (f->phys_cursor_x >= 0
+      && (!on
+         || f->phys_cursor_x != curs_x
+         || f->phys_cursor_y != curs_y
+         || f->display.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_x = -1;
     }
 
-  if (on && f == x_highlight_frame)
+  /* If we now need a cursor in the new place or in the new form, do it so.  */
+  if (on
+      && (f->phys_cursor_x < 0
+         || (f->display.x->current_cursor != bar_cursor)))
     {
-      x1 = f->cursor_x * FONT_WIDTH (f->display.x->font)
-       + f->display.x->internal_border_width;
-      y1 = f->cursor_y * FONT_HEIGHT (f->display.x->font)
-       + f->display.x->internal_border_width - 1;
-      y2 = y1 + FONT_HEIGHT (f->display.x->font) + 1;
+      f->phys_cursor_glyph
+       = ((current_glyphs->enable[curs_y]
+           && curs_x < current_glyphs->used[curs_y])
+          ? current_glyphs->glyphs[curs_y][curs_x]
+          : SPACEGLYPH);
+      XFillRectangle (x_current_display, FRAME_X_WINDOW (f),
+                     f->display.x->cursor_gc,
+                     CHAR_TO_PIXEL_COL (f, curs_x),
+                     CHAR_TO_PIXEL_ROW (f, curs_y),
+                     1, FONT_HEIGHT (f->display.x->font));
 
-      XDrawLine (x_current_display, FRAME_X_WINDOW (f),
-                f->display.x->cursor_gc, x1, y1, x1, y2);
+      f->phys_cursor_x = curs_x;
+      f->phys_cursor_y = curs_y;
 
-      f->phys_cursor_x = f->cursor_x;
-      f->phys_cursor_y = f->cursor_y;
+      f->display.x->current_cursor = bar_cursor;
     }
-#else /* ! defined (HAVE_X11) */
-  Give it up, dude.
-#endif /* ! defined (HAVE_X11) */
-}
-
-
-/* Redraw the glyph at ROW, COLUMN on frame F, in the style
-   HIGHLIGHT.  HIGHLIGHT is as defined for dumpglyphs.  Return the
-   glyph drawn.  */
 
-static void
-x_draw_single_glyph (f, row, column, glyph, highlight)
-     struct frame *f;
-     int row, column;
-     GLYPH glyph;
-     int highlight;
-{
-  dumpglyphs (f,
-             (column * FONT_WIDTH (f->display.x->font)
-              + f->display.x->internal_border_width),
-             (row * FONT_HEIGHT (f->display.x->font)
-              + f->display.x->internal_border_width),
-             &glyph, 1, highlight, f->display.x->font);
+  if (updating_frame != f)
+    XFlushQueue ();
 }
 
+
 /* 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 F->cursor_x and F->cursor_y.  */
@@ -3060,6 +3596,16 @@ x_display_box_cursor (f, on)
 {
   struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
 
+  /* 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 curs_x and curs_y may be off the frame.  */
+  if (! FRAME_VISIBLE_P (f) || FRAME_GARBAGED_P (f))
+    return;
+
+  /* If cursor is off and we want it off, return quickly.  */
+  if (!on && f->phys_cursor_x < 0)
+    return;
+
   /* If we're not updating, then we want to use the current frame's
      cursor position, not our local idea of where the cursor ought to be.  */
   if (f != updating_frame)
@@ -3068,13 +3614,6 @@ x_display_box_cursor (f, on)
       curs_y = FRAME_CURSOR_Y (f);
     }
 
-  if (! FRAME_VISIBLE_P (f))
-    return;
-
-  /* If cursor is off and we want it off, return quickly.  */
-  if (!on && f->phys_cursor_x < 0)
-    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!)
@@ -3083,7 +3622,7 @@ x_display_box_cursor (f, on)
       && (!on
          || f->phys_cursor_x != curs_x
          || f->phys_cursor_y != curs_y
-         || (f->display.x->text_cursor_kind != hollow_box_cursor
+         || (f->display.x->current_cursor != hollow_box_cursor
              && (f != x_highlight_frame))))
     {
       /* Erase the cursor by redrawing the character underneath it.  */
@@ -3098,7 +3637,7 @@ x_display_box_cursor (f, on)
      write it in the right place.  */
   if (on
       && (f->phys_cursor_x < 0
-         || (f->display.x->text_cursor_kind != filled_box_cursor
+         || (f->display.x->current_cursor != filled_box_cursor
              && f == x_highlight_frame)))
     {
       f->phys_cursor_glyph
@@ -3109,13 +3648,13 @@ x_display_box_cursor (f, on)
       if (f != x_highlight_frame)
        {
          x_draw_box (f);
-         f->display.x->text_cursor_kind = hollow_box_cursor;
+         f->display.x->current_cursor = hollow_box_cursor;
        }
       else
        {
          x_draw_single_glyph (f, curs_y, curs_x,
                               f->phys_cursor_glyph, 2);
-         f->display.x->text_cursor_kind = filled_box_cursor;
+         f->display.x->current_cursor = filled_box_cursor;
        }
 
       f->phys_cursor_x = curs_x;
@@ -3126,16 +3665,17 @@ x_display_box_cursor (f, on)
     XFlushQueue ();
 }
 
-extern Lisp_Object Vbar_cursor;
-
 x_display_cursor (f, on)
      struct frame *f;
      int on;
 {
-  if (EQ (Vbar_cursor, Qnil))
+  if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
     x_display_box_cursor (f, on);
-  else
+  else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
     x_display_bar_cursor (f, on);
+  else
+    /* Those are the only two we have implemented!  */
+    abort ();
 }
 \f
 /* Icons.  */
@@ -3180,8 +3720,7 @@ refreshicon (f)
 #endif /* ! defined (HAVE_X11) */
 }
 
-/* Make the x-window of frame F use the kitchen-sink icon
-   that's a window generated by Emacs.  */
+/* Make the x-window of frame F use the gnu icon bitmap.  */
 
 int
 x_bitmap_icon (f)
@@ -3194,12 +3733,10 @@ x_bitmap_icon (f)
     return 1;
 
 #ifdef HAVE_X11
-  if (icon_bitmap)
-    XFreePixmap (x_current_display, icon_bitmap);
-  
-  icon_bitmap =
-    XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
-                          gnu_bits, gnu_width, gnu_height);
+  if (! icon_bitmap)
+    icon_bitmap =
+      XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
+                            gnu_bits, gnu_width, gnu_height);
   x_wm_set_icon_pixmap (f, icon_bitmap);
   f->display.x->icon_bitmap_flag = 1;
 #else /* ! defined (HAVE_X11) */
@@ -3257,12 +3794,6 @@ x_text_icon (f, icon_name)
   if (FRAME_X_WINDOW (f) == 0)
     return 1;
 
-  if (icon_font_info == 0)
-    icon_font_info
-      = XGetFont (XGetDefault (XDISPLAY
-                              (char *) XSTRING (invocation_name)->data,
-                              "BodyFont"));
-
 #ifdef HAVE_X11
   if (icon_name)
     f->display.x->icon_label = icon_name;
@@ -3270,12 +3801,20 @@ x_text_icon (f, icon_name)
     if (! f->display.x->icon_label)
       f->display.x->icon_label = " *emacs* ";
   
+#if 0
   XSetIconName (x_current_display, FRAME_X_WINDOW (f),
                (char *) f->display.x->icon_label);
+#endif
   
   f->display.x->icon_bitmap_flag = 0;
   x_wm_set_icon_pixmap (f, 0);
 #else /* ! defined (HAVE_X11) */
+  if (icon_font_info == 0)
+    icon_font_info
+      = XGetFont (XGetDefault (XDISPLAY
+                              (char *) XSTRING (Vinvocation_name)->data,
+                              "BodyFont"));
+
   if (f->display.x->icon_desc)
     {
       XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
@@ -3311,21 +3850,23 @@ x_text_icon (f, icon_name)
 \f
 /* Handling X errors.  */
 
-/* A handler for SIGPIPE, when it occurs on the X server's connection.
-   This basically does an orderly shutdown of Emacs.  */
+/* Shut down Emacs in an orderly fashion, because of a SIGPIPE on the
+   X server's connection, or an error reported via the X protocol.  */
 
 static SIGTYPE
 x_connection_closed ()
 {
   if (_Xdebug)
     abort ();
-  else
-    Fkill_emacs (make_number (70));
+
+  shut_down_emacs (0, 1, Qnil);
+
+  exit (70);
 }
 
-/* An X error handler which prints an error message and then kills Emacs.  
-   This is what's normally installed as Xlib's handler for protocol and 
-   I/O errors.  */
+/* An X error handler which prints an error message and then kills
+   Emacs.  This is what's normally installed as Xlib's handler for
+   protocol errors.  */
 static int
 x_error_quitter (display, error)
      Display *display;
@@ -3333,10 +3874,6 @@ x_error_quitter (display, error)
 {
   char buf[256];
 
-  /* While we're testing Emacs 19, we'll just dump core whenever we
-     get an X error, so we can figure out why it happened.  */
-  abort ();
-
   /* Note that there is no real way portable across R3/R4 to get the 
      original error handler.  */
 
@@ -3344,11 +3881,37 @@ x_error_quitter (display, error)
   fprintf (stderr, "X protocol error: %s on protocol request %d\n",
           buf, error->request_code);
 
+#if 0
+  /* While we're testing Emacs 19, we'll just dump core whenever we
+     get an X error, so we can figure out why it happened.  */
+  abort ();
+#endif
+
+  x_connection_closed ();
+}
+
+/* A handler for X IO errors which prints an error message and then
+   kills Emacs.  This is what is always installed as Xlib's handler
+   for I/O errors.  */
+static int
+x_io_error_quitter (display)
+     Display *display;
+{
+  fprintf (stderr, "Connection to X server %s lost.\n",
+          XDisplayName (DisplayString (display)));
+
+#if 0
+  /* While we're testing Emacs 19, we'll just dump core whenever we
+     get an X error, so we can figure out why it happened.  */
+  abort ();
+#endif
+
   x_connection_closed ();
 }
 
 /* A buffer for storing X error messages.  */
-static char (*x_caught_error_message)[200];
+static char *x_caught_error_message;
+#define X_CAUGHT_ERROR_MESSAGE_SIZE 200
 
 /* An X error handler which stores the error message in
    x_caught_error_message.  This is what's installed when
@@ -3359,7 +3922,7 @@ x_error_catcher (display, error)
      XErrorEvent *error;
 {
   XGetErrorText (display, error->error_code,
-                *x_caught_error_message, sizeof (*x_caught_error_message));
+                x_caught_error_message, X_CAUGHT_ERROR_MESSAGE_SIZE);
 }
 
 
@@ -3382,9 +3945,9 @@ x_catch_errors ()
   XSync (x_current_display, False);
 
   /* Set up the error buffer.  */
-  x_caught_error_message =
-    (char (*)[]) xmalloc (sizeof (*x_caught_error_message));
-  (*x_caught_error_message)[0] = '\0';
+  x_caught_error_message
+    = (char*) xmalloc (X_CAUGHT_ERROR_MESSAGE_SIZE);
+  x_caught_error_message[0] = '\0';
 
   /* Install our little error handler.  */
   XHandleError (x_error_catcher);
@@ -3400,13 +3963,11 @@ x_check_errors (format)
   /* Make sure to catch any errors incurred so far.  */
   XSync (x_current_display, False);
 
-  if ((*x_caught_error_message)[0])
+  if (x_caught_error_message[0])
     {
-      char buf[256];
-
-      sprintf (buf, format, *x_caught_error_message);
-      free (x_caught_error_message);
+      char buf[X_CAUGHT_ERROR_MESSAGE_SIZE + 56];
 
+      sprintf (buf, format, x_caught_error_message);
       x_uncatch_errors ();
       error (buf);
     }
@@ -3415,7 +3976,8 @@ x_check_errors (format)
 void
 x_uncatch_errors ()
 {
-  free (x_caught_error_message);
+  xfree (x_caught_error_message);
+  x_caught_error_message = 0;
   XHandleError (x_error_quitter);
 }
 
@@ -3436,8 +3998,14 @@ x_trace_wire ()
 
 #ifdef HAVE_X11
 
+struct font_info
+{
+  XFontStruct *font;
+  char *name;
+};
+
 /* A table of all the fonts we have already loaded.  */
-static XFontStruct **x_font_table;
+static struct font_info *x_font_table;
 
 /* The current capacity of x_font_table.  */
 static int x_font_table_size;
@@ -3447,11 +4015,11 @@ static int x_font_table_size;
    0 <= n_fonts <= x_font_table_size.  */
 static int n_fonts;
 
+Lisp_Object
 x_new_font (f, fontname)
      struct frame *f;
      register char *fontname;
 {
-  XFontStruct *temp;
   int already_loaded;
   int n_matching_fonts;
   XFontStruct *font_info;
@@ -3460,66 +4028,89 @@ x_new_font (f, fontname)
   /* 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 font ids.  */
-  font_names = (char **) XListFontsWithInfo (x_current_display, fontname,
-                                            1024, &n_matching_fonts,
-                                            &font_info);
-  /* If the server couldn't find any fonts whose named matched fontname,
-     return an error code.  */
-  if (n_matching_fonts == 0)
-    return 1;
+  font_names = (char **) XListFonts (x_current_display, fontname,
+                                    1024, &n_matching_fonts);
+  /* Apparently it doesn't set n_matching_fonts to zero when it can't
+     find any matches; font_names == 0 is the only clue.  */
+  if (! font_names)
+    n_matching_fonts = 0;
+
+  /* Don't just give up if n_matching_fonts is 0.
+     Apparently there's a bug on Suns: XListFontsWithInfo can
+     fail to find a font, but XLoadQueryFont may still find it.  */
 
   /* See if we've already loaded a matching font. */
-  {
-    int i, j;
+  already_loaded = -1;
+  if (n_matching_fonts != 0)
+    {
+      int i, j;
 
-    already_loaded = 0;
-    for (i = 0; i < n_fonts; i++)
-      for (j = 0; j < n_matching_fonts; j++)
-       if (x_font_table[i]->fid == font_info[j].fid)
-         {
-           already_loaded = i;
-           goto found_font;
-         }
-  }
+      for (i = 0; i < n_fonts; i++)
+       for (j = 0; j < n_matching_fonts; j++)
+         if (!strcmp (x_font_table[i].name, font_names[j]))
+           {
+             already_loaded = i;
+             fontname = font_names[j];
+             goto found_font;
+           }
+    }
  found_font:
   
   /* If we have, just return it from the table.  */
-  if (already_loaded)
-    f->display.x->font = x_font_table[already_loaded];
+  if (already_loaded >= 0)
+    f->display.x->font = x_font_table[already_loaded].font;
   
   /* Otherwise, load the font and add it to the table.  */
   else
     {
+      int i;
       XFontStruct *font;
 
+      /* Try to find a character-cell font in the list.  */
+#if 0 
+      /* A laudable goal, but this isn't how to do it.  */
+      for (i = 0; i < n_matching_fonts; i++)
+       if (! font_info[i].per_char)
+         break;
+#else
+      i = 0;
+#endif
+
+      /* See comment above.  */
+      if (n_matching_fonts != 0)
+       fontname = font_names[i];
+
       font = (XFontStruct *) XLoadQueryFont (x_current_display, fontname);
       if (! font)
-       return 1;
+       {
+         /* Free the information from XListFonts.  */
+         if (n_matching_fonts)
+           XFreeFontNames (font_names);
+         return Qnil;
+       }
 
       /* Do we need to create the table?  */
       if (x_font_table_size == 0)
        {
          x_font_table_size = 16;
          x_font_table
-           = (XFontStruct **) xmalloc (x_font_table_size
-                                       * sizeof (x_font_table[0]));
+           = (struct font_info *) xmalloc (x_font_table_size
+                                           * sizeof (x_font_table[0]));
        }
       /* Do we need to grow the table?  */
       else if (n_fonts >= x_font_table_size)
        {
          x_font_table_size *= 2;
          x_font_table
-           = (XFontStruct **) xrealloc (x_font_table,
-                                        (x_font_table_size
-                                         * sizeof (x_font_table[0])));
+           = (struct font_info *) xrealloc (x_font_table,
+                                            (x_font_table_size
+                                             * sizeof (x_font_table[0])));
        }
 
-      f->display.x->font = x_font_table[n_fonts++] = font;
+      x_font_table[n_fonts].name = (char *) xmalloc (strlen (fontname));
+      bcopy (fontname, x_font_table[n_fonts].name, strlen (fontname) + 1);
+      f->display.x->font = x_font_table[n_fonts++].font = font;
     }
-  
-  /* Free the information from XListFontsWithInfo.  The data
-     we actually retain comes from XLoadQueryFont.  */
-  XFreeFontInfo (font_names, font_info, n_matching_fonts);
 
   /* Now make the frame display the given font.  */
   if (FRAME_X_WINDOW (f) != 0)
@@ -3534,7 +4125,16 @@ x_new_font (f, fontname)
       x_set_window_size (f, f->width, f->height);
     }
 
-  return 0;
+  {
+    Lisp_Object lispy_name = build_string (fontname);
+
+
+    /* Free the information from XListFonts.  The data
+       we actually retain comes from XLoadQueryFont.  */
+    XFreeFontNames (font_names);
+
+    return lispy_name;
+  }
 }
 #else /* ! defined (HAVE_X11) */
 x_new_font (f, newname)
@@ -3567,12 +4167,16 @@ x_calc_absolute_position (f)
 {
 #ifdef HAVE_X11
   if (f->display.x->left_pos < 0)
-    f->display.x->left_pos
-      = x_screen_width - PIXEL_WIDTH (f) + f->display.x->left_pos;
+    f->display.x->left_pos = (x_screen_width 
+                             - 2 * f->display.x->border_width
+                             - PIXEL_WIDTH (f)
+                             + f->display.x->left_pos);
 
   if (f->display.x->top_pos < 0)
-    f->display.x->top_pos
-      = x_screen_height - PIXEL_HEIGHT (f) + f->display.x->top_pos;
+    f->display.x->top_pos = (x_screen_height
+                            - 2 * f->display.x->border_width
+                            - PIXEL_HEIGHT (f)
+                            + f->display.x->top_pos);
 #else /* ! defined (HAVE_X11) */
   WINDOWINFO_TYPE parentinfo;
 
@@ -3613,14 +4217,13 @@ x_set_window_size (f, cols, rows)
 {
   int pixelwidth, pixelheight;
   int mask;
-  int ibw = f->display.x->internal_border_width;
 
   BLOCK_INPUT;
 
   check_frame_size (f, &rows, &cols);
-  f->display.x->vertical_scrollbar_extra =
-    (FRAME_HAS_VERTICAL_SCROLLBARS (f)
-     ? VERTICAL_SCROLLBAR_PIXEL_WIDTH (f)
+  f->display.x->vertical_scroll_bar_extra =
+    (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
+     ? VERTICAL_SCROLL_BAR_PIXEL_WIDTH (f)
      : 0);
   pixelwidth = CHAR_TO_PIXEL_WIDTH (f, cols);
   pixelheight = CHAR_TO_PIXEL_HEIGHT (f, rows);
@@ -3633,12 +4236,23 @@ x_set_window_size (f, cols, rows)
   /* Now, strictly speaking, we can't be sure that this is accurate,
      but the window manager will get around to dealing with the size
      change request eventually, and we'll hear how it went when the
-     ConfigureNotify event gets here.  */
-  FRAME_WIDTH (f) = cols;
-  FRAME_WIDTH (f) = rows;
+     ConfigureNotify event gets here.
+
+     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
+     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);
   PIXEL_WIDTH (f) = pixelwidth;
   PIXEL_HEIGHT (f) = pixelheight;
 
+  /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
+     receive in the ConfigureNotify event; if we get what we asked
+     for, then the event won't cause the screen to become garbaged, so
+     we have to make sure to do it here.  */
+  SET_FRAME_GARBAGED (f);
+
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
@@ -3647,10 +4261,11 @@ x_set_window_size (f, cols, rows)
 x_set_resize_hint (f)
      struct frame *f;
 {
-
-  XSetResizeHint (FRAME_X_WINDOW (f), 2 * f->display.x->internal_border_width,
+  XSetResizeHint (FRAME_X_WINDOW (f),
+                 2 * f->display.x->internal_border_width,
                  2 * f->display.x->internal_border_width,
-                 FONT_WIDTH (f->display.x->font), FONT_HEIGHT (f->display.x->font));
+                 FONT_WIDTH (f->display.x->font),
+                 FONT_HEIGHT (f->display.x->font));
 }
 #endif /* HAVE_X11 */
 \f
@@ -3664,12 +4279,8 @@ x_set_mouse_position (f, x, y)
 
   x_raise_frame (f);
 
-  pix_x = (f->display.x->internal_border_width
-          + x * FONT_WIDTH (f->display.x->font)
-          + FONT_WIDTH (f->display.x->font) / 2);
-  pix_y = (f->display.x->internal_border_width
-          + y * FONT_HEIGHT (f->display.x->font)
-          + FONT_HEIGHT (f->display.x->font) / 2);
+  pix_x = CHAR_TO_PIXEL_COL (f, x) + FONT_WIDTH  (f->display.x->font) / 2;
+  pix_y = CHAR_TO_PIXEL_ROW (f, y) + FONT_HEIGHT (f->display.x->font) / 2;
 
   if (pix_x < 0) pix_x = 0;
   if (pix_x > PIXEL_WIDTH (f)) pix_x = PIXEL_WIDTH (f);
@@ -3738,6 +4349,18 @@ x_lower_frame (f)
     }
 }
 
+static void
+XTframe_raise_lower (f, raise)
+     FRAME_PTR f;
+     int raise;
+{
+  if (raise)
+    x_raise_frame (f);
+  else
+    x_lower_frame (f);
+}
+
+
 /* Change from withdrawn state to mapped state. */
 
 x_make_frame_visible (f)
@@ -3754,7 +4377,7 @@ x_make_frame_visible (f)
        x_wm_set_window_state (f, NormalState);
 
       XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
-      if (FRAME_HAS_VERTICAL_SCROLLBARS (f))
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
        XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
 #else /* ! defined (HAVE_X11) */
       XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
@@ -3782,7 +4405,11 @@ x_make_frame_invisible (f)
 {
   int mask;
 
-  if (! f->async_visible)
+  /* Don't keep the highlight on an invisible frame.  */
+  if (x_highlight_frame == f)
+    x_highlight_frame = 0;
+
+  if (! f->async_visible && ! f->async_iconified)
     return;
 
   BLOCK_INPUT;
@@ -3793,7 +4420,7 @@ x_make_frame_invisible (f)
                         DefaultScreen (x_current_display)))
     {
       UNBLOCK_INPUT_RESIGNAL;
-      error ("can't notify window manager of window withdrawl");
+      error ("can't notify window manager of window withdrawal");
     }
 
 #else /* ! defined (HAVE_X11R4) */
@@ -3836,9 +4463,6 @@ x_make_frame_invisible (f)
   UNBLOCK_INPUT;
 }
 
-/* Window manager communication.  Created in Fx_open_connection. */
-extern Atom Xatom_wm_change_state;
-
 /* Change window state from mapped to iconified. */
 
 x_iconify_frame (f)
@@ -3846,6 +4470,10 @@ x_iconify_frame (f)
 {
   int mask;
 
+  /* Don't keep the highlight on an invisible frame.  */
+  if (x_highlight_frame == f)
+    x_highlight_frame = 0;
+
   if (f->async_iconified)
     return;
 
@@ -3881,6 +4509,14 @@ x_iconify_frame (f)
      IconicState.  */
   x_wm_set_window_state (f, IconicState);
 
+  if (!FRAME_VISIBLE_P (f))
+    {
+      /* If the frame was withdrawn, before, we must map it.  */
+      XMapWindow (XDISPLAY FRAME_X_WINDOW (f));
+      if (FRAME_HAS_VERTICAL_SCROLL_BARS (f))
+       XMapSubwindows (x_current_display, FRAME_X_WINDOW (f));
+    }
+
   f->async_iconified = 1;
 #else /* ! defined (HAVE_X11) */
   XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
@@ -3897,28 +4533,27 @@ x_iconify_frame (f)
   UNBLOCK_INPUT;
 }
 
-/* Destroy the X window of frame F.
-   DISPL is the former f->display (since f->display
-   has already been nulled out).  */
+/* Destroy the X window of frame F.  */
 
-x_destroy_window (f, displ)
+x_destroy_window (f)
      struct frame *f;
-     union display displ;
 {
-  int mask;
-
   BLOCK_INPUT;
-  if (displ.x->icon_desc != 0)
-    XDestroyWindow (XDISPLAY displ.x->icon_desc);
-  XDestroyWindow (XDISPLAY displ.x->window_desc);
+
+  if (f->display.x->icon_desc != 0)
+    XDestroyWindow (XDISPLAY f->display.x->icon_desc);
+  XDestroyWindow (XDISPLAY f->display.x->window_desc);
+  free_frame_faces (f);
   XFlushQueue ();
-  UNBLOCK_INPUT;
 
-  free (displ.x);
+  xfree (f->display.x);
+  f->display.x = 0;
   if (f == x_focus_frame)
     x_focus_frame = 0;
   if (f == x_highlight_frame)
     x_highlight_frame = 0;
+
+  UNBLOCK_INPUT;
 }
 \f
 /* Manage event queues for X10.  */
@@ -4006,7 +4641,7 @@ x_wm_set_size_hint (f, prompting)
   XSizeHints size_hints;
   Window window = FRAME_X_WINDOW (f);
 
-  size_hints.flags = PResizeInc | PMinSize | PMaxSize;
+  size_hints.flags = PResizeInc | PMinSize /* | PMaxSize */;
 
   flexlines = f->height;
 
@@ -4016,9 +4651,10 @@ x_wm_set_size_hint (f, prompting)
   size_hints.width = PIXEL_WIDTH (f);
   size_hints.width_inc = FONT_WIDTH (f->display.x->font);
   size_hints.height_inc = FONT_HEIGHT (f->display.x->font);
-  size_hints.max_width  = PIXEL_TO_CHAR_WIDTH  (f, x_screen_width);
-  size_hints.max_height = PIXEL_TO_CHAR_HEIGHT (f, x_screen_height);
-    
+#if 0
+  size_hints.max_width = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
+  size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
+#endif    
   {
     int base_width, base_height;
 
@@ -4059,7 +4695,8 @@ x_wm_set_size_hint (f, prompting)
     {
       XSizeHints hints;                /* Sometimes I hate X Windows... */
       
-      XGetNormalHints (x_current_display, window, &hints);
+      if (XGetNormalHints (x_current_display, window, &hints) == 0)
+       hints.flags = 0;
       if (hints.flags & PSize)
        size_hints.flags |= PSize;
       if (hints.flags & PPosition)
@@ -4096,8 +4733,13 @@ x_wm_set_icon_pixmap (f, icon_pixmap)
 {
   Window window = FRAME_X_WINDOW (f);
 
-  f->display.x->wm_hints.flags |= IconPixmapHint;
-  f->display.x->wm_hints.icon_pixmap = icon_pixmap ? icon_pixmap : None;
+  if (icon_pixmap)
+    {
+      f->display.x->wm_hints.icon_pixmap = icon_pixmap;
+      f->display.x->wm_hints.flags |= IconPixmapHint;
+    }
+  else
+    f->display.x->wm_hints.flags &= ~IconPixmapHint;
 
   XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
 }
@@ -4124,15 +4766,18 @@ x_term_init (display_name)
 {
   Lisp_Object frame;
   char *defaultvalue;
+#ifndef F_SETOWN_BUG
 #ifdef F_SETOWN
   extern int old_fcntl_owner;
 #endif /* ! defined (F_SETOWN) */
+#endif /* F_SETOWN_BUG */
   
   x_focus_frame = x_highlight_frame = 0;
 
   x_current_display = XOpenDisplay (display_name);
   if (x_current_display == 0)
-    fatal ("X server %s not responding; check the DISPLAY environment variable or use \"-d\"\n",
+    fatal ("X server %s not responding.\n\
+Check the DISPLAY environment variable or use \"-d\"\n",
           display_name);
 
 #ifdef HAVE_X11
@@ -4145,8 +4790,6 @@ x_term_init (display_name)
     XSetAfterFunction (x_current_display, x_trace_wire);
 #endif /* ! 0 */
 
-    invocation_name = Ffile_name_nondirectory (Fcar (Vcommand_line_args));
-
     /* Try to get the host name; if the buffer is too short, try
        again.  Apparently, the only indication gethostname gives of
        whether the buffer was large enough is the presence or absence
@@ -4163,37 +4806,43 @@ x_term_init (display_name)
        hostname_size <<= 1;
        hostname = (char *) xrealloc (hostname, hostname_size);
       }
-    x_id_name = (char *) xmalloc (XSTRING (invocation_name)->size
+    x_id_name = (char *) xmalloc (XSTRING (Vinvocation_name)->size
                                + strlen (hostname)
                                + 2);
-    sprintf (x_id_name, "%s@%s", XSTRING (invocation_name)->data, hostname);
+    sprintf (x_id_name, "%s@%s", XSTRING (Vinvocation_name)->data, hostname);
   }
 
   /* Figure out which modifier bits mean what.  */
   x_find_modifier_meanings ();
 
-  /* Get the scrollbar cursor.  */
-  x_vertical_scrollbar_cursor =
-    XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
+  /* Get the scroll bar cursor.  */
+  x_vertical_scroll_bar_cursor
+    XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
 
+#if 0
   /* Watch for PropertyNotify events on the root window; we use them
      to figure out when to invalidate our cache of the cut buffers.  */
   x_watch_cut_buffer_cache ();
+#endif
 
-  dup2 (ConnectionNumber (x_current_display), 0);
+  if (ConnectionNumber (x_current_display) != 0)
+    {
+      dup2 (ConnectionNumber (x_current_display), 0);
 
 #ifndef SYSV_STREAMS
-  /* Streams somehow keeps track of which descriptor number
-     is being used to talk to X.  So it is not safe to substitute
-     descriptor 0.  But it is safe to make descriptor 0 a copy of it.  */
-  close (ConnectionNumber (x_current_display));
-  ConnectionNumber (x_current_display) = 0;    /* Looks a little strange?
+      /* Streams somehow keeps track of which descriptor number
+        is being used to talk to X.  So it is not safe to substitute
+        descriptor 0.  But it is safe to make descriptor 0 a copy of it.  */
+      close (ConnectionNumber (x_current_display));
+      ConnectionNumber (x_current_display) = 0;        /* Looks a little strange?
                                                 * check the def of the macro;
                                                 * it is a genuine lvalue */
 #endif /* SYSV_STREAMS */
+    }
 
 #endif /* ! defined (HAVE_X11) */
   
+#ifndef F_SETOWN_BUG
 #ifdef F_SETOWN
   old_fcntl_owner = fcntl (0, F_GETOWN, 0);
 #ifdef F_SETOWN_SOCK_NEG
@@ -4202,16 +4851,12 @@ x_term_init (display_name)
   fcntl (0, F_SETOWN, getpid ());
 #endif /* ! defined (F_SETOWN_SOCK_NEG) */
 #endif /* ! defined (F_SETOWN) */
+#endif /* F_SETOWN_BUG */
 
 #ifdef SIGIO
   init_sigio ();
 #endif /* ! defined (SIGIO) */
 
-  /* Must use interrupt input because we cannot otherwise
-     arrange for C-g to be noticed immediately.
-     We cannot connect it to SIGINT.  */
-  Fset_input_mode (Qt, Qnil, Qt, Qnil);
-
   expose_all_windows = 0;
 
   clear_frame_hook = XTclear_frame;
@@ -4232,10 +4877,11 @@ x_term_init (display_name)
   reassert_line_highlight_hook = XTreassert_line_highlight;
   mouse_position_hook = XTmouse_position;
   frame_rehighlight_hook = XTframe_rehighlight;
-  set_vertical_scrollbar_hook = XTset_scrollbar;
-  condemn_scrollbars_hook = XTcondemn_scrollbars;
-  redeem_scrollbar_hook = XTredeem_scrollbar;
-  judge_scrollbars_hook = XTjudge_scrollbars;
+  frame_raise_lower_hook = XTframe_raise_lower;
+  set_vertical_scroll_bar_hook = XTset_vertical_scroll_bar;
+  condemn_scroll_bars_hook = XTcondemn_scroll_bars;
+  redeem_scroll_bar_hook = XTredeem_scroll_bar;
+  judge_scroll_bars_hook = XTjudge_scroll_bars;
   
   scroll_region_ok = 1;                /* we'll scroll partial frames */
   char_ins_del_ok = 0;         /* just as fast to write the line */
@@ -4245,10 +4891,13 @@ x_term_init (display_name)
                                   off the bottom */
   baud_rate = 19200;
 
+  /* Try to use interrupt input; if we can't, then start polling.  */
+  Fset_input_mode (Qt, Qnil, Qt, Qnil);
+
   /* Note that there is no real way portable across R3/R4 to get the 
      original error handler.  */
   XHandleError (x_error_quitter);
-  XHandleIOError (x_error_quitter);
+  XHandleIOError (x_io_error_quitter);
 
   /* Disable Window Change signals;  they are handled by X events. */
 #ifdef SIGWINCH
@@ -4261,8 +4910,7 @@ x_term_init (display_name)
 void
 syms_of_xterm ()
 {
-  staticpro (&invocation_name);
-  invocation_name = Qnil;
+  staticpro (&last_mouse_scroll_bar);
 }
 #endif /* ! defined (HAVE_X11) */
 #endif /* ! defined (HAVE_X_WINDOWS) */