(x_alt_mod_mask, x_super_mod_mask, x_hyper_mod_mask): New variables.
[bpt/emacs.git] / src / xterm.c
index dd07185..5ccb3c4 100644 (file)
@@ -1,11 +1,11 @@
 /* X Communication module for terminals which understand the X protocol.
-   Copyright (C) 1989 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 1, or (at your option)
+the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -31,50 +31,47 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "lisp.h"
 
-/* On 4.3 this loses if it comes after xterm.h.  */
+/* On 4.3 these lose if they come after xterm.h.  */
+#include <stdio.h>
 #include <signal.h>
 
 /* This may include sys/types.h, and that somehow loses
    if this is not done before the other system files.  */
 #include "xterm.h"
+#include <X11/cursorfont.h>
 
+#ifndef USG
 /* Load sys/types.h if not already loaded.
    In some systems loading it twice is suicidal.  */
 #ifndef makedev
 #include <sys/types.h>
-#endif
+#endif /* makedev */
+#endif /* USG */
 
 #ifdef BSD
 #include <sys/ioctl.h>
 #include <strings.h>
-#else
+#else /* ! defined (BSD) */
 #include <sys/termio.h>
 #include <string.h>
-#endif
+#endif /* ! defined (BSD) */
 
 /* Allow m- file to inhibit use of FIONREAD.  */
 #ifdef BROKEN_FIONREAD
 #undef FIONREAD
-#endif
+#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
-#endif
+#endif /* ! defined (SIGIO) */
+#endif /* FIONREAD */
 
-#ifdef NEED_TIME_H
-#include <time.h>
-#else /* not NEED_TIME_H */
-#ifdef HAVE_TIMEVAL
-#include <sys/time.h>
-#endif /* HAVE_TIMEVAL */
-#endif /* not NEED_TIME_H */
+#include "systime.h"
 
 #include <fcntl.h>
-#include <stdio.h>
 #include <ctype.h>
 #include <errno.h>
 #include <setjmp.h>
@@ -88,18 +85,19 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #if 0
 #include "sink.h"
 #include "sinkmask.h"
-#endif
+#endif /* ! 0 */
 #include "gnu.h"
-#include "screen.h"
+#include "frame.h"
 #include "disptab.h"
 #include "buffer.h"
+#include "window.h"
 
 #ifdef HAVE_X11
 #define XMapWindow XMapRaised          /* Raise them when mapping. */
-#else
+#else /* ! defined (HAVE_X11) */
 #include <X/Xkeyboard.h>
 /*#include <X/Xproto.h>        */
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 /* For sending Meta-characters.  Do we need this? */
 #define METABIT 0200
@@ -109,8 +107,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* Nonzero means we must reprint all windows
    because 1) we received an ExposeWindow event
-   or 2) we received too many ExposeRegion events to record.  */
+   or 2) we received too many ExposeRegion events to record.
 
+   This is never needed under X11.  */
 static int expose_all_windows;
 
 /* Nonzero means we must reprint all icon windows.  */
@@ -127,7 +126,7 @@ static struct event_queue x_expose_queue;
    are copied into this queue for later processing.  */
 
 struct event_queue x_mouse_queue;
-#endif
+#endif /* HAVE_X11 */
 
 /* Nonzero after BLOCK_INPUT; prevents input events from being
    processed until later.  */
@@ -136,17 +135,13 @@ int x_input_blocked;
 
 #if defined (SIGIO) && defined (FIONREAD)
 int BLOCK_INPUT_mask;
-#endif
+#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;
 
-/* Nonzero if in redisplay ();  prevents us from calling it recursively */
-
-int in_display;
-
 /* 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.  */
@@ -167,27 +162,39 @@ Lisp_Object invocation_name;
 
 Display *x_current_display;
 
-/* Screen being updated by update_screen.  */
+/* 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
    XT functions.  It is zero while not inside an update.
-   In that case, the XT functions assume that `selected_screen'
-   is the screen to apply to.  */
-
-static struct screen *updating_screen;
-
-/* The screen (if any) which has the X window that has keyboard focus.
-   Zero if none.  This is examined by Ffocus_screen in screen.c.  */
-struct screen *x_focus_screen;
-
-/* The screen which currently has the visual highlight, and should get
-   keyboard input (other sorts of input have the screen encoded in the
-   event).  It points to the X focus screen's selected window's
-   screen.  It differs from x_focus_screen when we're using a global
+   In that case, the XT functions assume that `selected_frame'
+   is the frame to apply to.  */
+
+static 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
+   that a mere EnterNotify event can set this; if you need to know the
+   last frame specified in a FocusIn or FocusOut event, use
+   x_focus_event_frame.  */
+struct frame *x_focus_frame;
+
+/* The last frame mentioned in a FocusIn or FocusOut event.  This is
+   separate from x_focus_frame, because whether or not LeaveNotify
+   events cause us to lose focus depends on whether or not we have
+   received a FocusIn event for it.  */
+struct frame *x_focus_event_frame;
+
+/* The frame which currently has the visual highlight, and should get
+   keyboard input (other sorts of input have the frame encoded in the
+   event).  It points to the X focus frame's selected window's
+   frame.  It differs from x_focus_frame when we're using a global
    minibuffer.  */
-static struct screen *x_highlight_screen;
+static struct frame *x_highlight_frame;
 
 /* From .Xdefaults, the value of "emacs.WarpMouse".  If non-zero,
-   mouse is moved to inside of screen when screen is de-iconified.  */
+   mouse is moved to inside of frame when frame is de-iconified.  */
 
 static int warp_mouse_on_deiconify;
 
@@ -223,7 +230,7 @@ extern Window requestor_window;
 /* Nonzero enables some debugging for the X interface code. */
 extern int _Xdebug;
 
-#else /* X10 stuff */
+#else /* ! defined (HAVE_X11) */
 
 /* Bit patterns for the mouse cursor.  */
 
@@ -243,7 +250,7 @@ static short grey_bits[] = {
   0x0005, 0x000a, 0x0005, 0x000a};
 
 static Pixmap GreyPixmap = 0;
-#endif /* X10 stuff */
+#endif /* ! defined (HAVE_X11) */
 
 /* From time to time we get info on an Emacs window, here.  */
 
@@ -251,6 +258,9 @@ static WINDOWINFO_TYPE windowinfo;
 
 extern int errno;
 
+/* See keyboard.c.  */
+extern int extra_keyboard_modifiers;
+
 extern Display *XOpenDisplay ();
 extern Window XCreateWindow ();
 
@@ -261,63 +271,67 @@ static void flashback ();
 
 #ifndef HAVE_X11
 static void dumpqueue ();
-#endif
+#endif /* HAVE_X11 */
 
 void dumpborder ();
-static XTcursor_to ();
-static XTclear_end_of_line ();
+static int XTcursor_to ();
+static int XTclear_end_of_line ();
+
 \f
-/* These hooks are called by update_screen at the beginning and end
-   of a screen update.  We record in `updating_screen' the identity
-   of the screen being updated, so that the XT... functions do not
-   need to take a screen as argument.  Most of the XT... functions
+/* Starting and ending updates. 
+
+   These hooks are called by update_frame at the beginning and end
+   of a frame update.  We record in `updating_frame' the identity
+   of the frame being updated, so that the XT... functions do not
+   need to take a frame as argument.  Most of the XT... functions
    should never be called except during an update, the only exceptions
    being XTcursor_to, XTwrite_char and XTreassert_line_highlight.  */
 
 extern int mouse_track_top, mouse_track_left, mouse_track_width;
 
 static
-XTupdate_begin (s)
-     struct screen *s;
+XTupdate_begin (f)
+     struct frame *f;
 {      
   int mask;
 
-  if (s == 0)
+  if (f == 0)
     abort ();
 
-  updating_screen = s;
-  flexlines = s->height;
+  updating_frame = f;
+  flexlines = f->height;
   highlight = 0;
 
   BLOCK_INPUT;
 #ifndef HAVE_X11
   dumpqueue ();
-#endif
+#endif /* HAVE_X11 */
   UNBLOCK_INPUT;
 }
 
+#ifndef HAVE_X11
 static void x_do_pending_expose ();
+#endif
 
 static
-XTupdate_end (s)
-     struct screen *s;
+XTupdate_end (f)
+     struct frame *f;
 {      
   int mask;
 
-  if (updating_screen == 0
-      || updating_screen != s)
+  if (updating_frame == 0
+      || updating_frame != f)
     abort ();
 
   BLOCK_INPUT;
 #ifndef HAVE_X11
   dumpqueue ();
-#endif
-  adjust_scrollbars (s);
   x_do_pending_expose ();
+#endif /* HAVE_X11 */
 
-  x_display_cursor (s, 1);
+  x_display_cursor (f, 1);
 
-  updating_screen = 0;
+  updating_frame = 0;
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
@@ -341,7 +355,7 @@ XTchange_line_highlight (new_highlight, vpos, first_unused_hpos)
 {
   highlight = new_highlight;
   XTcursor_to (vpos, 0);
-  XTclear_end_of_line (updating_screen->width);
+  XTclear_end_of_line (updating_frame->width);
 }
 
 /* This is used when starting Emacs and when restarting after suspend.
@@ -360,14 +374,14 @@ XTset_terminal_modes ()
 static
 XTreset_terminal_modes ()
 {
-/*  XTclear_screen ();  */
+/*  XTclear_frame ();  */
 }
 \f
-/* Set the nominal cursor position of the screen:
-   where display update commands will take effect.
+/* Set the nominal cursor position of the frame.
+   This is where display update commands will take effect.
    This does not affect the place where the cursor-box is displayed.  */
 
-static
+static int
 XTcursor_to (row, col)
      register int row, col;
 {
@@ -377,10 +391,10 @@ XTcursor_to (row, col)
   curs_x = col;
   curs_y = row;
 
-  if (updating_screen == 0)
+  if (updating_frame == 0)
     {
       BLOCK_INPUT;
-      x_display_cursor (selected_screen, 1);
+      x_display_cursor (selected_frame, 1);
       XFlushQueue ();
       UNBLOCK_INPUT;
     }
@@ -393,8 +407,8 @@ XTcursor_to (row, col)
    FONT is the default font to use (for glyphs whose font-code is 0).  */
 
 static void
-dumpglyphs (s, left, top, gp, n, hl, font)
-     struct screen *s;
+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. */
@@ -402,10 +416,10 @@ dumpglyphs (s, left, top, gp, n, hl, font)
      FONT_TYPE *font;
 {
   register int len;
-  Window window = s->display.x->window_desc;
-  GC drawing_gc =   (hl == 2 ? s->display.x->cursor_gc
-                            : (hl ? s->display.x->reverse_gc
-                                  : s->display.x->normal_gc));
+  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,
@@ -421,23 +435,23 @@ dumpglyphs (s, left, top, gp, n, hl, font)
 
 #if 0
 static void
-dumpglyphs (s, left, top, gp, n, hl, font)
-     struct screen *s;
+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;
 {
-  char buf[s->width]; /* Holds characters to be displayed. */
+  char buf[f->width]; /* Holds characters to be displayed. */
   register char *cp;           /* Steps through buf[]. */
   register int tlen = GLYPH_TABLE_LENGTH;
   register Lisp_Object *tbase = GLYPH_TABLE_BASE;
-  Window window = s->display.x->window_desc;
-  int cursor_pixel = s->display.x->cursor_pixel;
-  int fg_pixel = s->display.x->foreground_pixel;
-  int bg_pixel = s->display.x->background_pixel;
-  int intborder = s->display.x->internal_border_width;
+  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)
     {
@@ -474,16 +488,16 @@ dumpglyphs (s, left, top, gp, n, hl, font)
       if (cf == 0)
        {
 #ifdef HAVE_X11
-         GC GC_cursor = s->display.x->cursor_gc;
-         GC GC_reverse = s->display.x->reverse_gc;
-         GC GC_normal = s->display.x->normal_gc;
+         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
+#else /* ! defined (HAVE_X11) */
          XText (window, left, top,
                 buf,
                 len,
@@ -493,26 +507,26 @@ dumpglyphs (s, left, top, gp, n, hl, font)
                  : hl ? bg_pixel : fg_pixel),
                 (hl == 2 ? cursor_pixel
                  : hl ? fg_pixel : bg_pixel));
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
        }
       else
        {
 #ifdef HAVE_X11
          if (FACE_IS_FONT (cf))
-           XDrawImageString (x_current_display, s->display.x->window_desc,
+           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),
-                       s->display.x->window_desc,
-                       s->display.x->normal_gc,
+                       FRAME_X_WINDOW (f),
+                       f->display.x->normal_gc,
                        0, 0,
                        FACE_IMAGE_WIDTH (cf),
                        FACE_IMAGE_HEIGHT (cf), left, top);
          else
            abort ();
-#else
+#else /* ! defined (HAVE_X11) */
          register struct face *fp = x_face_table[cf];
 
          XText (window, left, top,
@@ -524,15 +538,15 @@ dumpglyphs (s, left, top, gp, n, hl, font)
                  : hl ? fp->bg : fp->fg),
                 (hl == 2 ? cursor_pixel
                  : hl ? fp->fg : fp->bg));
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
        }
       left += len * FONT_WIDTH (font);
     }
 }
-#endif
+#endif /* ! 0 */
 \f
-/* Output some text at the nominal screen cursor position,
-   advancing the cursor over the text.
+/* Output some text at the nominal frame cursor position.
+   Advance the cursor over the text.
    Output LEN glyphs at START.
 
    `highlight', set up by XTreassert_line_highlight or XTchange_line_highlight,
@@ -545,38 +559,36 @@ XTwrite_glyphs (start, len)
 {
   register int temp_length;
   int mask;
-  struct screen *s;
+  struct frame *f;
 
   BLOCK_INPUT;
 
-  s = updating_screen;
-  if (s == 0)
+  f = updating_frame;
+  if (f == 0)
     {
-      s = selected_screen;
+      f = selected_frame;
       /* If not within an update,
-        output at the screen's visible cursor.  */
-      curs_x = s->cursor_x;
-      curs_y = s->cursor_y;
+        output at the frame's visible cursor.  */
+      curs_x = f->cursor_x;
+      curs_y = f->cursor_y;
     }
 
-  dumpglyphs (s,
-            (curs_x * FONT_WIDTH (s->display.x->font)
-             + s->display.x->internal_border_width),
-            (curs_y * FONT_HEIGHT (s->display.x->font)
-             + s->display.x->internal_border_width),
-            start, len, highlight, s->display.x->font);
+  dumpglyphs (f,
+             CHAR_TO_PIXEL_COL (f, curs_x),
+             CHAR_TO_PIXEL_ROW (f, curs_y),
+             start, len, highlight, f->display.x->font);
 
   /* If we drew on top of the cursor, note that it is turned off.  */
-  if (curs_y == s->phys_cursor_y
-      && curs_x <= s->phys_cursor_x
-      && curs_x + len > s->phys_cursor_x)
-    s->phys_cursor_x = -1;
+  if (curs_y == f->phys_cursor_y
+      && curs_x <= f->phys_cursor_x
+      && curs_x + len > f->phys_cursor_x)
+    f->phys_cursor_x = -1;
   
-  if (updating_screen == 0)
+  if (updating_frame == 0)
     {
-      s->cursor_x += len;
-      x_display_cursor (s, 1);
-      s->cursor_x -= len;
+      f->cursor_x += len;
+      x_display_cursor (f, 1);
+      f->cursor_x -= len;
     }
   else
     curs_x += len;
@@ -584,179 +596,207 @@ XTwrite_glyphs (start, len)
   UNBLOCK_INPUT;
 }
 \f
-/* Erase the current text line from the nominal cursor position (inclusive)
+/* Clear to the end of the line.
+   Erase the current text line from the nominal cursor position (inclusive)
    to column FIRST_UNUSED (exclusive).  The idea is that everything
    from FIRST_UNUSED onward is already erased.  */
   
-static
+static int
 XTclear_end_of_line (first_unused)
      register int first_unused;
 {
-  struct screen *s = updating_screen;
+  struct frame *f = updating_frame;
   int mask;
 
-  if (s == 0)
+  if (f == 0)
     abort ();
 
-  if (curs_y < 0 || curs_y >= s->height)
+  if (curs_y < 0 || curs_y >= f->height)
     return;
   if (first_unused <= 0)
     return;
 
-  if (first_unused >= s->width)
-    first_unused = s->width;
+  if (first_unused >= f->width)
+    first_unused = f->width;
 
   BLOCK_INPUT;
 
   /* Notice if the cursor will be cleared by this operation.  */
-  if (curs_y == s->phys_cursor_y
-      && curs_x <= s->phys_cursor_x
-      && s->phys_cursor_x < first_unused)
-    s->phys_cursor_x = -1;
+  if (curs_y == f->phys_cursor_y
+      && curs_x <= f->phys_cursor_x
+      && f->phys_cursor_x < first_unused)
+    f->phys_cursor_x = -1;
 
 #ifdef HAVE_X11
-  XClearArea (x_current_display, s->display.x->window_desc,
-             curs_x * FONT_WIDTH (s->display.x->font)
-             + s->display.x->internal_border_width,
-             curs_y * FONT_HEIGHT (s->display.x->font)
-             + s->display.x->internal_border_width,
-             FONT_WIDTH (s->display.x->font) * (first_unused - curs_x),
-             FONT_HEIGHT (s->display.x->font), False);
+  XClearArea (x_current_display, FRAME_X_WINDOW (f),
+             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);
              
-#else
-  XPixSet (s->display.x->window_desc,
-          curs_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width,
-          curs_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width,
-          FONT_WIDTH (s->display.x->font) * (first_unused - curs_x),
-          FONT_HEIGHT (s->display.x->font),
-          s->display.x->background_pixel);     
-#endif /* HAVE_X11 */
+#else /* ! defined (HAVE_X11) */
+  XPixSet (FRAME_X_WINDOW (f),
+          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);     
+#endif /* ! defined (HAVE_X11) */
 
   UNBLOCK_INPUT;
 }
 
 static
-XTclear_screen ()
+XTclear_frame ()
 {
   int mask;
-  struct screen *s = updating_screen;
+  struct frame *f = updating_frame;
 
-  if (s == 0)
-    s = selected_screen;
+  if (f == 0)
+    f = selected_frame;
 
-  s->phys_cursor_x = -1;       /* Cursor not visible.  */
+  f->phys_cursor_x = -1;       /* Cursor not visible.  */
   curs_x = 0;                  /* Nominal cursor position is top left.  */
   curs_y = 0;
   
   BLOCK_INPUT;
-  XClear (s->display.x->window_desc);
+
+  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 (s, 0);
-#endif
+  dumpborder (f, 0);
+#endif /* HAVE_X11 */
+
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
 \f
-/* Paint horzontal bars down the screen 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 avaliable.  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.  */
 
-XTflash (s)
-     struct screen *s;
+static int
+timeval_subtract (result, x, y)
+     struct timeval *result, x, y;
 {
-  register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s);
-  register int i;
-  int 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;
+    }
 
-  if (updating_screen != 0)
-    abort ();
+  /* 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;
+{
   BLOCK_INPUT;
-#ifdef HAVE_X11
-#if 0
-  for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10;
-       i >= 0;    
-       i -= 100)          /* Should be NO LOWER than 75 for speed reasons. */
-    XFillRectangle (x_current_display, s->display.x->window_desc,
-                   s->display.x->cursor_gc,
-                   0, i, s->width * FONT_WIDTH (s->display.x->font)
-                   + 2 * s->display.x->internal_border_width, 25);
-#endif
 
-  x = (s->width * FONT_WIDTH (s->display.x->font)) / 4;
-  y = (s->height * FONT_HEIGHT (s->display.x->font)) / 4;
-  XFillRectangle (x_current_display, s->display.x->window_desc,
-                 s->display.x->cursor_gc,
-                 x, y, 2 * x, 2 * y);
-  dumpglyphs (s, (x + s->display.x->internal_border_width),
-            (y + s->display.x->internal_border_width),
-            &active_screen->glyphs[(s->height / 4) + 1][(s->width / 4)],
-            1, 0, s->display.x->font);
-
-#else /* X10 */
-  for (i = s->height * FONT_HEIGHT (s->display.x->font) - 10;
-       i >= 0;
-       i -= 50)
-    XPixFill (s->display.x->window_desc, 0, i,
-             s->width * FONT_WIDTH (s->display.x->font)
-             + 2 * s->display.x->internal_border_width, 10,
-             WHITE_PIX_DEFAULT, ClipModeClipped, GXinvert, AllPlanes);
-#endif /* X10 */
+  {
+    GC gc;
 
-  XFlushQueue ();
-  UNBLOCK_INPUT;
-}
+    /* Create a GC that will use the GXxor function to flip foreground pixels
+       into background pixels.  */
+    {
+      XGCValues values;
 
-/* Flip background and forground colors of the screen. */
+      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);
+    }
 
-x_invert_screen (s)
-     struct screen *s;
-{
-#ifdef HAVE_X11
-  GC temp;
-  unsigned long pix_temp;
-
-  x_display_cursor (s, 0);
-  XClearWindow (x_current_display, s->display.x->window_desc);
-  temp = s->display.x->normal_gc;
-  s->display.x->normal_gc = s->display.x->reverse_gc;
-  s->display.x->reverse_gc = temp;
-  pix_temp = s->display.x->foreground_pixel;
-  s->display.x->foreground_pixel = s->display.x->background_pixel;
-  s->display.x->background_pixel = pix_temp;
-
-  XSetWindowBackground (x_current_display, s->display.x->window_desc,
-                       s->display.x->background_pixel);
-  if (s->display.x->background_pixel == s->display.x->cursor_pixel)
     {
-      s->display.x->cursor_pixel = s->display.x->foreground_pixel;
-      XSetBackground (x_current_display, s->display.x->cursor_gc,
-                     s->display.x->cursor_pixel);
-      XSetForeground (x_current_display, s->display.x->cursor_gc,
-                     s->display.x->background_pixel);
+      int width  = PIXEL_WIDTH  (f);
+      int height = PIXEL_HEIGHT (f);
+
+      XFillRectangle (x_current_display, FRAME_X_WINDOW (f), gc,
+                     width/4, height/4, width/2, height/2);
+      XFlush (x_current_display);
+
+      {
+       struct timeval wakeup, now;
+
+       gettimeofday (&wakeup, (struct timezone *) 0);
+
+       /* 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_screen (s);
-#endif /* X11 */
+  }
+
+  UNBLOCK_INPUT;
 }
 
+#endif
+
+
 /* Make audible bell.  */
 
 #ifdef HAVE_X11
 #define XRINGBELL XBell(x_current_display, 0)
-#else
+#else /* ! defined (HAVE_X11) */
 #define XRINGBELL XFeep(0);
-#endif
+#endif /* ! defined (HAVE_X11) */
 
 XTring_bell ()
 {
+#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
   if (visible_bell)
-#if 0
-    XTflash (selected_screen);
-#endif
-    {
-      x_invert_screen (selected_screen);
-      x_invert_screen (selected_screen);
-    }
+    XTflash (selected_frame);
   else
+#endif
     {
       BLOCK_INPUT;
       XRINGBELL;
@@ -765,8 +805,9 @@ XTring_bell ()
     }
 }
 \f
-/* Insert and delete character are not supposed to be used
-   because we are supposed to turn off the feature of using them.  */
+/* Insert and delete character.
+   These are not supposed to be used because we are supposed to turn
+   off the feature of using them.  */
 
 static 
 XTinsert_glyphs (start, len)
@@ -792,17 +833,17 @@ static
 XTset_terminal_window (n)
      register int n;
 {
-  if (updating_screen == 0)
+  if (updating_frame == 0)
     abort ();
 
-  if ((n <= 0) || (n > updating_screen->height))
-    flexlines = updating_screen->height;
+  if ((n <= 0) || (n > updating_frame->height))
+    flexlines = updating_frame->height;
   else
     flexlines = n;
 }
 \f
-/* Perform an insert-lines operation, inserting N lines
-   at a vertical position curs_y.  */
+/* Perform an insert-lines operation.
+   Insert N lines at a vertical position curs_y.  */
 
 static void
 stufflines (n)
@@ -810,8 +851,8 @@ stufflines (n)
 {
   register int topregion, bottomregion;
   register int length, newtop, mask;
-  register struct screen *s = updating_screen;
-  int intborder = s->display.x->internal_border_width;
+  register struct frame *f = updating_frame;
+  int intborder = f->display.x->internal_border_width;
 
   if (curs_y >= flexlines)
     return;
@@ -823,29 +864,29 @@ stufflines (n)
 
 #ifndef HAVE_X11
   dumpqueue ();
-#endif
+#endif /* HAVE_X11 */
 
   if ((length > 0) && (newtop <= flexlines))
     {
 #ifdef HAVE_X11
-      XCopyArea (x_current_display, s->display.x->window_desc,
-                s->display.x->window_desc, s->display.x->normal_gc,
-                intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder,
-                s->width * FONT_WIDTH (s->display.x->font),
-                length * FONT_HEIGHT (s->display.x->font), intborder,
-                newtop * FONT_HEIGHT (s->display.x->font) + intborder);
-#else
-      XMoveArea (s->display.x->window_desc,
-                intborder, topregion * FONT_HEIGHT (s->display.x->font) + intborder,
-                intborder, newtop * FONT_HEIGHT (s->display.x->font) + intborder,
-                s->width * FONT_WIDTH (s->display.x->font),
-                length * FONT_HEIGHT (s->display.x->font));
+      XCopyArea (x_current_display, FRAME_X_WINDOW (f),
+                FRAME_X_WINDOW (f), f->display.x->normal_gc,
+                intborder, CHAR_TO_PIXEL_ROW (f, topregion),
+                f->width * FONT_WIDTH (f->display.x->font),
+                length * FONT_HEIGHT (f->display.x->font), intborder,
+                CHAR_TO_PIXEL_ROW (f, newtop));
+#else /* ! defined (HAVE_X11) */
+      XMoveArea (FRAME_X_WINDOW (f),
+                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
         if the area being copied from is obscured.
         We can't let it wait because further i/d operations
         may want to copy this area to another area.  */
       x_read_exposes ();
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
     }
 
   newtop = min (newtop, (flexlines - 1));
@@ -853,18 +894,18 @@ stufflines (n)
   if (length > 0)
     {
 #ifdef HAVE_X11
-      XClearArea (x_current_display, s->display.x->window_desc, intborder, 
-                 topregion * FONT_HEIGHT (s->display.x->font) + intborder,
-                 s->width * FONT_WIDTH (s->display.x->font),
-                 n * FONT_HEIGHT (s->display.x->font), False);
-#else
-      XPixSet (s->display.x->window_desc,
+      XClearArea (x_current_display, FRAME_X_WINDOW (f), 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 (s->display.x->font) + intborder,
-              s->width * FONT_WIDTH (s->display.x->font),
-              n * FONT_HEIGHT (s->display.x->font),
-              s->display.x->background_pixel);
-#endif /* HAVE_X11 */
+              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);
+#endif /* ! defined (HAVE_X11) */
     }
 }
 
@@ -876,66 +917,66 @@ scraplines (n)
      register int n;
 {
   int mask;
-  register struct screen *s = updating_screen;
-  int intborder = s->display.x->internal_border_width;
+  register struct frame *f = updating_frame;
+  int intborder = f->display.x->internal_border_width;
 
   if (curs_y >= flexlines)
     return;
 
 #ifndef HAVE_X11
   dumpqueue ();
-#endif
+#endif /* HAVE_X11 */
 
   if ((curs_y + n) >= flexlines)
     {
       if (flexlines >= (curs_y + 1))
        {
 #ifdef HAVE_X11
-         XClearArea (x_current_display, s->display.x->window_desc, intborder,
-                     curs_y * FONT_HEIGHT (s->display.x->font) + intborder,
-                     s->width * FONT_WIDTH (s->display.x->font),
-                     (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font), False);
-#else
-         XPixSet (s->display.x->window_desc,
-                  intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder,
-                  s->width * FONT_WIDTH (s->display.x->font),
-                  (flexlines - curs_y) * FONT_HEIGHT (s->display.x->font),
-                  s->display.x->background_pixel);
-#endif /* HAVE_X11 */
+         XClearArea (x_current_display, FRAME_X_WINDOW (f), 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, 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);
+#endif /* ! defined (HAVE_X11) */
        }
     }
   else
     {
 #ifdef HAVE_X11
-      XCopyArea (x_current_display, s->display.x->window_desc,
-                s->display.x->window_desc, s->display.x->normal_gc,
+      XCopyArea (x_current_display, FRAME_X_WINDOW (f),
+                FRAME_X_WINDOW (f), f->display.x->normal_gc,
                 intborder,
-                (curs_y + n) * FONT_HEIGHT (s->display.x->font) + intborder,
-                s->width * FONT_WIDTH (s->display.x->font),
-                (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font),
-                intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder);
-      XClearArea (x_current_display, s->display.x->window_desc,
+                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, CHAR_TO_PIXEL_ROW (f, curs_y));
+      XClearArea (x_current_display, FRAME_X_WINDOW (f),
                  intborder,
-                 (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder,
-                 s->width * FONT_WIDTH (s->display.x->font),
-                 n * FONT_HEIGHT (s->display.x->font), False);
-#else
-      XMoveArea (s->display.x->window_desc,
+                 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 (s->display.x->font) + intborder,
-                intborder, curs_y * FONT_HEIGHT (s->display.x->font) + intborder,
-                s->width * FONT_WIDTH (s->display.x->font),
-                (flexlines - (curs_y + n)) * FONT_HEIGHT (s->display.x->font));
+                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
         if the area being copied from is obscured.
         We can't let it wait because further i/d operations
         may want to copy this area to another area.  */
       x_read_exposes ();
-      XPixSet (s->display.x->window_desc, intborder,
-              (flexlines - n) * FONT_HEIGHT (s->display.x->font) + intborder,
-              s->width * FONT_WIDTH (s->display.x->font),
-              n * FONT_HEIGHT (s->display.x->font), s->display.x->background_pixel);
-#endif /* HAVE_X11 */
+      XPixSet (FRAME_X_WINDOW (f), 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) */
     }
 }
 
@@ -945,11 +986,11 @@ scraplines (n)
 XTins_del_lines (vpos, n)
      int vpos, n;
 {
-  if (updating_screen == 0)
+  if (updating_frame == 0)
     abort ();
 
   /* Hide the cursor.  */
-  x_display_cursor (updating_screen, 0);
+  x_display_cursor (updating_frame, 0);
 
   XTcursor_to (vpos, 0);
 
@@ -962,60 +1003,62 @@ XTins_del_lines (vpos, n)
   UNBLOCK_INPUT;
 }
 \f
+/* Support routines for exposure events.  */
 static void clear_cursor ();
 
-/* Output into a rectangle of an X-window (for screen S)
-   the characters in s->phys_lines that overlap that rectangle.
+/* Output into a rectangle of an X-window (for frame F)
+   the characters in f->phys_lines that overlap that rectangle.
    TOP and LEFT are the position of the upper left corner of the rectangle.
    ROWS and COLS are the size of the rectangle.  */
 
 static void
-dumprectangle (s, left, top, cols, rows)
-     struct screen *s;
+dumprectangle (f, left, top, cols, rows)
+     struct frame *f;
      register int left, top, cols, rows;
 {
-  register struct screen_glyphs *active_screen = SCREEN_CURRENT_GLYPHS (s);
+  register struct frame_glyphs *active_frame = FRAME_CURRENT_GLYPHS (f);
   int cursor_cleared = 0;
   int bottom, right;
   register int y;
 
-  if (SCREEN_GARBAGED_P (s))
+  if (FRAME_GARBAGED_P (f))
     return;
 
-  top -= s->display.x->internal_border_width;
-  left -= s->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 > s->height * FONT_HEIGHT (s->display.x->font)
-      || right > s->width * FONT_WIDTH (s->display.x->font))
-    dumpborder (s, 0);
-#endif /* HAVE_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 (s->display.x->font);
-  left /= FONT_WIDTH (s->display.x->font);
-  bottom += (FONT_HEIGHT (s->display.x->font) - 1);
-  right += (FONT_WIDTH (s->display.x->font) - 1);
-  bottom /= FONT_HEIGHT (s->display.x->font);
-  right /= FONT_WIDTH (s->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 = PIXEL_TO_CHAR_ROW (f, bottom);
+  right = PIXEL_TO_CHAR_COL (f, right);
 
   /* Clip the rectangle to what can be visible.  */
   if (left < 0)
     left = 0;
   if (top < 0)
     top = 0;
-  if (right > s->width)
-    right = s->width;
-  if (bottom > s->height)
-    bottom = s->height;
+  if (right > f->width)
+    right = f->width;
+  if (bottom > f->height)
+    bottom = f->height;
 
   /* Get size in chars of the rectangle.  */
   cols = right - left;
@@ -1027,10 +1070,10 @@ dumprectangle (s, left, top, cols, rows)
 
   /* Turn off the cursor if it is in the rectangle.
      We will turn it back on afterward.  */
-  if ((s->phys_cursor_x >= left) && (s->phys_cursor_x < right)
-      && (s->phys_cursor_y >= top) && (s->phys_cursor_y < bottom))
+  if ((f->phys_cursor_x >= left) && (f->phys_cursor_x < right)
+      && (f->phys_cursor_y >= top) && (f->phys_cursor_y < bottom))
     {
-      clear_cursor (s);
+      clear_cursor (f);
       cursor_cleared = 1;
     }
 
@@ -1038,24 +1081,22 @@ dumprectangle (s, left, top, cols, rows)
 
   for (y = top; y < bottom; y++)
     {
-      GLYPH *line = &active_screen->glyphs[y][left];
+      GLYPH *line = &active_frame->glyphs[y][left];
 
-      if (! active_screen->enable[y] || left > active_screen->used[y])
+      if (! active_frame->enable[y] || left > active_frame->used[y])
        continue;
 
-      dumpglyphs (s,
-                (left * FONT_WIDTH (s->display.x->font)
-                 + s->display.x->internal_border_width),
-                (y * FONT_HEIGHT (s->display.x->font)
-                 + s->display.x->internal_border_width),
-                line, min (cols, active_screen->used[y] - left),
-                active_screen->highlight[y], s->display.x->font);
+      dumpglyphs (f,
+                 CHAR_TO_PIXEL_COL (f, left),
+                 CHAR_TO_PIXEL_ROW (f, y),
+                 line, min (cols, active_frame->used[y] - left),
+                 active_frame->highlight[y], f->display.x->font);
     }
 
   /* Turn the cursor on if we turned it off.  */
 
   if (cursor_cleared)
-    x_display_cursor (s, 1);
+    x_display_cursor (f, 1);
 }
 
 #ifndef HAVE_X11
@@ -1069,71 +1110,72 @@ dumpqueue ()
 
   while (dequeue_event (&r, &x_expose_queue))
     {
-      struct screen *s = x_window_to_screen (r.window);
-      if (s->display.x->icon_desc == r.window)
-       refreshicon (s);
+      struct frame *f = x_window_to_frame (r.window);
+      if (f->display.x->icon_desc == r.window)
+       refreshicon (f);
       else
-       dumprectangle (s, r.x, r.y, r.width, r.height);
+       dumprectangle (f, r.x, r.y, r.width, r.height);
     }
   XFlushQueue ();
 }
-#endif
+#endif /* HAVE_X11 */
 \f
-/* Process all expose events that are pending.
-   Redraws the cursor if necessary on any screen that
-   is not in the process of being updated with update_screen.  */
+/* Process all expose events that are pending, for X10.
+   Redraws the cursor if necessary on any frame that
+   is not in the process of being updated with update_frame.  */
 
+#ifndef HAVE_X11
 static void
 x_do_pending_expose ()
 {
   int mask;
-  struct screen *s;
-  Lisp_Object tail, screen;
+  struct frame *f;
+  Lisp_Object tail, frame;
 
   if (expose_all_windows)
     {
       expose_all_windows = 0;
-      for (tail = Vscreen_list; CONSP (tail); tail = XCONS (tail)->cdr)
+      for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
        {
          register int temp_width, temp_height;
          int intborder;
 
-         screen = XCONS (tail)->car;
-         if (XTYPE (screen) != Lisp_Screen)
+         frame = XCONS (tail)->car;
+         if (XGCTYPE (frame) != Lisp_Frame)
            continue;
-         s = XSCREEN (screen);
-         if (! SCREEN_IS_X (s))
+         f = XFRAME (frame);
+         if (! FRAME_X_P (f))
            continue;
-         if (!s->visible)
+         if (!f->async_visible)
            continue;
-         if (!s->display.x->needs_exposure)
+         if (!f->display.x->needs_exposure)
            continue;
 
-         intborder = s->display.x->internal_border_width;
+         intborder = f->display.x->internal_border_width;
 
-         clear_cursor (s);
-         XGetWindowInfo (s->display.x->window_desc, &windowinfo);
+         clear_cursor (f);
+         XGetWindowInfo (FRAME_X_WINDOW (f), &windowinfo);
          temp_width = ((windowinfo.width - 2 * intborder
-                        - s->display.x->v_scrollbar_width)
-                       / FONT_WIDTH (s->display.x->font));
+                        - f->display.x->v_scroll_bar_width)
+                       / FONT_WIDTH (f->display.x->font));
          temp_height = ((windowinfo.height- 2 * intborder
-                         - s->display.x->h_scrollbar_height)
-                        / FONT_HEIGHT (s->display.x->font));
-         if (temp_width != s->width || temp_height != s->height)
+                         - f->display.x->h_scroll_bar_height)
+                        / FONT_HEIGHT (f->display.x->font));
+         if (temp_width != f->width || temp_height != f->height)
            {
-             change_screen_size (s, max (1, temp_height),
-                                 max (1, temp_width), 0);
-             x_resize_scrollbars (s);
+             change_frame_size (f, max (1, temp_height),
+                                 max (1, temp_width), 0, 1);
+             x_resize_scroll_bars (f);
            }
-         s->display.x->left_pos = windowinfo.x;
-         s->display.x->top_pos = windowinfo.y;
-         dumprectangle (s, 0, 0, PIXEL_WIDTH (s), PIXEL_HEIGHT (s));
+         f->display.x->left_pos = windowinfo.x;
+         f->display.x->top_pos = windowinfo.y;
+         dumprectangle (f, 0, 0, PIXEL_WIDTH (f), PIXEL_HEIGHT (f));
 #if 0
-         dumpborder (s, 0);
-#endif
-         s->display.x->needs_exposure = 0;
-         if (updating_screen != s)
-           x_display_cursor (s, 1);
+         dumpborder (f, 0);
+#endif /* ! 0 */
+         f->display.x->needs_exposure = 0;
+         if (updating_frame != f)
+           x_display_cursor (f, 1);
          XFlushQueue ();
        }
     }
@@ -1142,348 +1184,330 @@ x_do_pending_expose ()
        for various windows.  */
 #ifdef HAVE_X11
     ;
-#else
+#else /* ! defined (HAVE_X11) */
     dumpqueue ();
-#endif
+#endif /* ! defined (HAVE_X11) */
 }
+#endif
 
 #ifdef HAVE_X11
 static void
-screen_highlight (screen)
-     struct screen *screen;
+frame_highlight (frame)
+     struct frame *frame;
 {
   if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorder (x_current_display, screen->display.x->window_desc,
-                     screen->display.x->border_pixel);
-  x_display_cursor (screen, 1);
+    XSetWindowBorder (x_current_display, FRAME_X_WINDOW (frame),
+                     frame->display.x->border_pixel);
+  x_display_cursor (frame, 1);
 }
 
 static void
-screen_unhighlight (screen)
-     struct screen *screen;
+frame_unhighlight (frame)
+     struct frame *frame;
 {
   if (! EQ (Vx_no_window_manager, Qnil))
-    XSetWindowBorderPixmap (x_current_display, screen->display.x->window_desc,
-                           screen->display.x->border_tile);
-  x_display_cursor (screen, 1);
+    XSetWindowBorderPixmap (x_current_display, FRAME_X_WINDOW (frame),
+                           frame->display.x->border_tile);
+  x_display_cursor (frame, 1);
 }
-#else  /* X10 */
-/* Dump the border-emphasis of screen S.
-   If S is selected, this is a lining of the same color as the border,
+#else /* ! defined (HAVE_X11) */
+/* Dump the border-emphasis of frame F.
+   If F is selected, this is a lining of the same color as the border,
    just within the border, occupying a portion of the internal border.
-   If S is not selected, it is background in the same place.
+   If F is not selected, it is background in the same place.
    If ALWAYS is 0, don't bother explicitly drawing if it's background.
 
-   ALWAYS = 1 is used when a screen becomes selected or deselected.
+   ALWAYS = 1 is used when a frame becomes selected or deselected.
    In that case, we also turn the cursor off and on again
    so it will appear in the proper shape (solid if selected; else hollow.)  */
 
 static void
-dumpborder (s, always)
-     struct screen *s;
+dumpborder (f, always)
+     struct frame *f;
      int always;
 {
-  int thickness = s->display.x->internal_border_width / 2;
-  int width = PIXEL_WIDTH (s);
-  int height = PIXEL_HEIGHT (s);
+  int thickness = f->display.x->internal_border_width / 2;
+  int width = PIXEL_WIDTH (f);
+  int height = PIXEL_HEIGHT (f);
   int pixel;
 
-  if (s != selected_screen)
+  if (f != selected_frame)
     {
       if (!always)
        return;
 
-      pixel = s->display.x->background_pixel;
+      pixel = f->display.x->background_pixel;
     }
   else
     {
-      pixel = s->display.x->border_pixel;
+      pixel = f->display.x->border_pixel;
     }
 
-  XPixSet (s->display.x->window_desc, 0, 0, width, thickness, pixel);
-  XPixSet (s->display.x->window_desc, 0, 0, thickness, height, pixel);
-  XPixSet (s->display.x->window_desc, 0, height - thickness, width,
+  XPixSet (FRAME_X_WINDOW (f), 0, 0, width, thickness, pixel);
+  XPixSet (FRAME_X_WINDOW (f), 0, 0, thickness, height, pixel);
+  XPixSet (FRAME_X_WINDOW (f), 0, height - thickness, width,
           thickness, pixel);
-  XPixSet (s->display.x->window_desc, width - thickness, 0, thickness,
+  XPixSet (FRAME_X_WINDOW (f), width - thickness, 0, thickness,
           height, pixel);
 
   if (always)
-    x_display_cursor (s, 1);
+    x_display_cursor (f, 1);
 }
-#endif /* X10 */
+#endif /* ! defined (HAVE_X11) */
 
-static void XTscreen_rehighlight ();
+static void XTframe_rehighlight ();
 
-/* The focus has changed.  Update the screens as necessary to reflect
-   the new situation.  Note that we can't change the selected screen
+/* 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 screen in which it occured, so the
+   Each event gets marked with the frame in which it occured, so the
    lisp code can tell when the switch took place by examining the events.  */
 
 static void
-x_new_focus_screen (screen)
-     struct screen *screen;
+x_new_focus_frame (frame)
+     struct frame *frame;
 {
-  struct screen *old_focus = x_focus_screen;
+  struct frame *old_focus = x_focus_frame;
   int events_enqueued = 0;
 
-  if (screen != x_focus_screen)
+  if (frame != x_focus_frame)
     {
       /* Set this before calling other routines, so that they see 
-        the correct value of x_focus_screen.  */
-      x_focus_screen = screen;
+        the correct value of x_focus_frame.  */
+      x_focus_frame = frame;
 
       if (old_focus && old_focus->auto_lower)
-       x_lower_screen (old_focus);
+       x_lower_frame (old_focus);
 
 #if 0
-      selected_screen = screen;
-      XSET (XWINDOW (selected_screen->selected_window)->screen,
-           Lisp_Screen, selected_screen);
-      Fselect_window (selected_screen->selected_window);
-      choose_minibuf_screen ();
-#endif
-
-      if (x_focus_screen && x_focus_screen->auto_raise)
-       x_raise_screen (x_focus_screen);
+      selected_frame = frame;
+      XSET (XWINDOW (selected_frame->selected_window)->frame,
+           Lisp_Frame, selected_frame);
+      Fselect_window (selected_frame->selected_window);
+      choose_minibuf_frame ();
+#endif /* ! 0 */
+
+      if (x_focus_frame && x_focus_frame->auto_raise)
+       x_raise_frame (x_focus_frame);
     }
 
-  XTscreen_rehighlight ();
+  XTframe_rehighlight ();
 }
 
 
-/* The focus has changed, or we have make a screen's selected window
-   point to a window on a different screen (this happens with global
-   minibuffer screens).  Shift the highlight as appropriate.  */
+/* The focus has changed, or we have redirected a frame's focus to
+   another frame (this happens when a frame uses a surrogate
+   minibuffer frame).  Shift the highlight as appropriate.  */
 static void
-XTscreen_rehighlight ()
+XTframe_rehighlight ()
 {
-  struct screen *old_highlight = x_highlight_screen;
+  struct frame *old_highlight = x_highlight_frame;
 
-  if (x_focus_screen)
+  if (x_focus_frame)
     {
-      x_highlight_screen = XSCREEN (SCREEN_FOCUS_SCREEN (x_focus_screen));
-      if (x_highlight_screen->display.nothing == 0)
-       XSET (SCREEN_FOCUS_SCREEN (x_focus_screen), Lisp_Screen,
-             (x_highlight_screen = x_focus_screen));
+      x_highlight_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))
+       {
+         FRAME_FOCUS_FRAME (x_focus_frame) = Qnil;
+         x_highlight_frame = x_focus_frame;
+       }
     }
   else
-    x_highlight_screen = 0;
+    x_highlight_frame = 0;
 
-  if (x_highlight_screen != old_highlight)
+  if (x_highlight_frame != old_highlight)
     {
       if (old_highlight)
-       screen_unhighlight (old_highlight);
-      if (x_highlight_screen)
-       screen_highlight (x_highlight_screen);
+       frame_unhighlight (old_highlight);
+      if (x_highlight_frame)
+       frame_highlight (x_highlight_frame);
     }
 }
 \f
-enum window_type
-{
-  no_window,
-  scrollbar_window,
-  text_window,
-};
-
-/* Symbol returned in input stream to indicate mouse movement. */
-Lisp_Object Qmouse_moved;
-
-/* Position of the mouse in characters */
-unsigned int x_mouse_x, x_mouse_y;
-
-/* Emacs window the mouse is in, if any. */
-extern Lisp_Object Vmouse_window;
-
-/* Offset in buffer of character under the pointer, or 0. */
-extern int mouse_buffer_offset;
+/* Mouse clicks and mouse movement.  Rah.  */
+#ifdef HAVE_X11
 
-/* Part of the screen the mouse is in. */
-extern Lisp_Object Vmouse_screen_part;
+/* 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);
 
-extern int buffer_posn_from_coords ();
+  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);
+    }
 
-/* Symbols from xfns.c to denote the different parts of a window.  */
-extern Lisp_Object Qmodeline_part, Qtext_part;
+  if (pix_x < 0) pix_x = 0;
+  else if (pix_x > f->width) pix_x = f->width;
 
-#if 0
-/* Set *RESULT to an emacs input_event corresponding to MOTION_EVENT.
-   S is the screen in which the event occurred.
+  if (pix_y < 0) pix_y = 0;
+  else if (pix_y > f->height) pix_y = f->height;
 
-   WINDOW_TYPE says whether the event happened in a scrollbar window
-   or a text window, affecting the format of the event created.
+  *x = pix_x;
+  *y = pix_y;
+}
 
-   PART specifies which part of the scrollbar the event happened in,
-   if WINDOW_TYPE == scrollbar_window.
+/* Any buttons grabbed. */
+unsigned int x_mouse_grabbed;
 
-   If the mouse is over the same character as the last time we checked,
-   don't return an event; set result->kind to no_event.  */
+/* Which modifier keys are on which modifier bits?
 
+   With each keystroke, X returns eight bits indicating which modifier
+   keys were held down when the key was pressed.  The interpretation
+   of the top five modifier bits depends on what keys are attached
+   to them.  If the Meta_L and Meta_R keysyms are on mod5, then mod5
+   is the meta bit.
+   
+   x_meta_mod_mask is a mask containing the bits used for the meta key.
+   It may have more than one bit set, if more than one modifier bit
+   has meta keys on it.  Basically, if EVENT is a KeyPress event,
+   the meta key is pressed if (EVENT.state & x_meta_mod_mask) != 0.  
+
+   x_shift_lock_mask is LockMask if the XK_Shift_Lock keysym is on the
+   lock modifier bit, or zero otherwise.  Non-alphabetic keys should
+   only be affected by the lock modifier bit if XK_Shift_Lock is in
+   use; XK_Caps_Lock should only affect alphabetic keys.  With this
+   arrangement, the lock modifier should shift the character if
+   (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
-notice_mouse_movement (result, motion_event, s, window_type, part)
-     struct input_event *result;
-     XMotionEvent motion_event;
-     struct screen *s;
-     int window_type;
-     Lisp_Object part;
+x_find_modifier_meanings ()
 {
-  int x, y, root_x, root_y, pix_x, pix_y;
-  unsigned int keys_and_buttons;
-  Window w, root_window;
-
-  /* Unless we decide otherwise below, return a non-event.  */
-  result->kind = no_event;
+  int min_code, max_code;
+  KeySym *syms;
+  int syms_per_code;
+  XModifierKeymap *mods;
+
+  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;
   
-  if (XQueryPointer (x_current_display,
-                    s->display.x->window_desc,
-                    &root_window, &w,
-                    &root_x, &root_y, &pix_x, &pix_y,
-                    &keys_and_buttons)
-      == False)
-    return;
-
-#if 0
-  if (w == None)   /* Mouse no longer in window. */
-    return Qnil;
-#endif
-
-  pixel_to_glyph_translation (s, pix_x, pix_y, &x, &y);
-  if (x == x_mouse_x && y == x_mouse_y)
-    return;
-
-  x_mouse_x = x;
-  x_mouse_y = y;
-
-  /* What sort of window are we in now?  */
-  if (window_type == text_window)            /* Text part */
-    {
-      int modeline_p;
-
-      Vmouse_window = window_from_coordinates (s, x, y, &modeline_p);
-
-      if (XTYPE (Vmouse_window) == Lisp_Window)
-       mouse_buffer_offset
-         = buffer_posn_from_coords (XWINDOW (Vmouse_window), x, y);
-      else
-       mouse_buffer_offset = 0;
-
-      if (EQ (Vmouse_window, Qnil))
-       Vmouse_screen_part = Qnil;
-      else if (modeline_p)
-       Vmouse_screen_part = Qmodeline_part;
-      else
-       Vmouse_screen_part = Qtext_part;
-      
-      result->kind = window_sys_event;
-      result->code = Qmouse_moved;
-
-      return;
-    }
-  else if (window_type == scrollbar_window)  /* Scrollbar */
-    {
-      Vmouse_window = s->selected_window;
-      mouse_buffer_offset = 0;
-      Vmouse_screen_part = part;
+  XDisplayKeycodes (x_current_display, &min_code, &max_code);
+  syms = XGetKeyboardMapping (x_current_display,
+                             min_code, max_code - min_code + 1,
+                             &syms_per_code);
+  mods = XGetModifierMapping (x_current_display);
+
+  /* Scan the modifier table to see which modifier bits the Meta and 
+     Alt keysyms are on.  */
+  {
+    int row, col;      /* The row and column in the modifier table. */
 
-      result->kind = window_sys_event;
-      result->code = Qmouse_moved;
+    for (row = 3; row < 8; row++)
+      for (col = 0; col < mods->max_keypermod; col++)
+       {
+         KeyCode code =
+           mods->modifiermap[(row * mods->max_keypermod) + col];
 
-      return;
-    }
+         /* Are any of this keycode's keysyms a meta key?  */
+         {
+           int code_col;
 
-  return;
-}
-#endif
+           for (code_col = 0; code_col < syms_per_code; code_col++)
+             {
+               int sym = syms[((code - min_code) * syms_per_code) + code_col];
 
-\f
-/* Mouse clicks and mouse movement.  Rah.  */
-#ifdef HAVE_X11
+               switch (sym)
+                 {
+                 case XK_Meta_L:
+                 case XK_Meta_R:
+                   x_meta_mod_mask |= (1 << row);
+                   break;
 
-/* Given a pixel position (PIX_X, PIX_Y) on the screen S, 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 (s, pix_x, pix_y, x, y, bounds)
-     SCREEN_PTR s;
-     register unsigned int pix_x, pix_y;
-     register int *x, *y;
-     XRectangle *bounds;
-{
-  int ibw = s->display.x->internal_border_width;
-  int width, height;
-  FONT_TYPE *font = s->display.x->font;
+                 case XK_Alt_L:
+                 case XK_Alt_R:
+                   x_alt_mod_mask |= (1 << row);
+                   break;
 
-  width = FONT_WIDTH (font);
-  height = FONT_HEIGHT (font);
+                 case XK_Hyper_L:
+                 case XK_Hyper_R:
+                   x_hyper_mod_mask |= (1 << row);
+                   break;
 
-  /* What line is it on?  */
-  if (pix_y < ibw)
-    *y = 0;
-  else if (pix_y > s->display.x->pixel_height - ibw)
-    *y = SCREEN_HEIGHT (s) - 1;
-  else
-    *y = (pix_y - ibw) / height;
+                 case XK_Super_L:
+                 case XK_Super_R:
+                   x_super_mod_mask |= (1 << row);
+                   break;
 
-  /* And what column?  */
-  if (pix_x < ibw)
-    *x = 0;
-  else if (pix_x > s->display.x->pixel_width - ibw)
-    *x = SCREEN_WIDTH (s) - 1;
-  else
-    *x = (pix_x - ibw) / width;
+                 case XK_Shift_Lock:
+                   /* Ignore this if it's not on the lock modifier.  */
+                   if ((1 << row) == LockMask)
+                     x_shift_lock_mask = LockMask;
+                   break;
+                 }
+             }
+         }
+       }
+  }
 
-  if (bounds)
+  /* If we couldn't find any meta keys, accept any alt keys as meta keys.  */
+  if (! x_meta_mod_mask)
     {
-      bounds->width = width;
-      bounds->height = height;
-      bounds->x = ibw + (*x * width);
-      bounds->y = ibw + (*y * height);
+      x_meta_mod_mask = x_alt_mod_mask;
+      x_alt_mod_mask = 0;
     }
+
+  XFree ((char *) syms);
+  XFreeModifiermap (mods);
 }
 
-/* Any buttons grabbed. */
-unsigned int x_mouse_grabbed;
 
 /* Convert a set of X modifier bits to the proper form for a
    struct input_event modifiers value.  */
 
-static Lisp_Object
+static unsigned int
 x_convert_modifiers (state)
      unsigned int state;
 {
-  return (  ((state & (ShiftMask | LockMask)) ? shift_modifier : 0)
-         | ((state & ControlMask)            ? ctrl_modifier  : 0)
-         | ((state & Mod1Mask)               ? meta_modifier  : 0));
+  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_alt_mod_mask)                  ? alt_modifier  : 0)
+         | ((state & x_super_mod_mask)                ? super_modifier  : 0)
+         | ((state & x_hyper_mod_mask)                ? hyper_modifier  : 0));
 }
 
-extern struct screen *x_window_to_scrollbar ();
-extern Lisp_Object Vmouse_event;
-
 /* 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
-   the mouse.
-
-   If PART and PREFIX are 0, then the event occurred in the text part;
-   otherwise it happened in a scrollbar. */
+   the mouse.  */
 
 static Lisp_Object
-construct_mouse_click (result, event, s, part, prefix)
+construct_mouse_click (result, event, f)
      struct input_event *result;
      XButtonEvent *event;
-     struct screen *s;
-     int prefix;
-     Lisp_Object part;
+     struct frame *f;
 {
-  /* Initialize those fields text and scrollbar clicks hold in common.
-     Make the event type no_event; we'll change that when we decide
+  /* Make the event type no_event; we'll change that when we decide
      otherwise.  */
-  result->kind = no_event;
-  XSET (result->code, Lisp_Int, event->button);
-  XSET (result->timestamp, Lisp_Int, event->time);
+  result->kind = mouse_click;
+  XSET (result->code, Lisp_Int, event->button - Button1);
+  result->timestamp = event->time;
   result->modifiers = (x_convert_modifiers (event->state)
-                      | (event->type == ButtonRelease ? up_modifier : 0));
-  XSET (result->timestamp, Lisp_Int, (event->time & 0x7fffff));
+                      | (event->type == ButtonRelease
+                         ? up_modifier 
+                         : down_modifier));
 
   /* Notice if the mouse is still grabbed.  */
   if (event->type == ButtonPress)
@@ -1499,33 +1523,14 @@ construct_mouse_click (result, event, s, part, prefix)
        Vmouse_depressed = Qnil;
     }
 
-  if (part)                    /* Scrollbar event */
-    {
-      int pos, len;
-
-      pos = event->y - (s->display.x->v_scrollbar_width - 2);
-      XSET (x_mouse_x, Lisp_Int, pos);
-      len = ((FONT_HEIGHT (s->display.x->font) * s->height)
-            + s->display.x->internal_border_width
-            - (2 * (s->display.x->v_scrollbar_width - 2)));
-      XSET (x_mouse_y, Lisp_Int, len);
-
-      result->kind = scrollbar_click;
-      result->part = part;
-      XSET (result->x, Lisp_Int, (s->display.x->top_pos - event->y));
-      XSET (result->y, Lisp_Int, s->display.x->pixel_height);
-      result->screen = s;
-    }
-  else                         /* Text Window Event */
-    {
-      int row, column;
+  {
+    int row, column;
 
-      pixel_to_glyph_coords (s, event->x, event->y, &column, &row, NULL);
-      result->kind = mouse_click;
-      result->x = column;
-      result->y = row;
-      result->screen = s;
-    }
+    pixel_to_glyph_coords (f, event->x, event->y, &column, &row, NULL);
+    XFASTINT (result->x) = column;
+    XFASTINT (result->y) = row;
+    XSET (result->frame_or_window, Lisp_Frame, f);
+  }
 }
 
 
@@ -1538,7 +1543,7 @@ construct_mouse_click (result, event, s, part, prefix)
    other kinds of events (focus changes and button clicks, for
    example), or by XQueryPointer calls; when one of these happens, we
    get another MotionNotify event the next time the mouse moves.  This
-   is at least as efficient than getting motion events when mouse
+   is at least as efficient as getting motion events when mouse
    tracking is on, and I suspect only negligibly worse when tracking
    is off.
 
@@ -1549,9 +1554,27 @@ construct_mouse_click (result, event, s, part, prefix)
    the server, which is very important.  */
 
 /* Where the mouse was last time we reported a mouse event.  */
-static SCREEN_PTR last_mouse_screen;
+static FRAME_PTR last_mouse_frame;
 static XRectangle last_mouse_glyph;
 
+/* The scroll bar in which the last X motion event occurred.
+
+   If the last X motion event occured 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
+   doesn't seem to be any way to wrest the timestamp from the server
+   along with the position query.  So, we just keep track of the time
+   of the last movement we received, and return that in hopes that
+   it's somewhat accurate.  */
+static Time last_mouse_movement_time;
+
 /* Function to report a mouse movement to the mainstream Emacs code.
    The input handler calls this.
 
@@ -1560,17 +1583,22 @@ static XRectangle last_mouse_glyph;
    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 (screen, event)
-     SCREEN_PTR screen;
+note_mouse_movement (frame, event)
+     FRAME_PTR frame;
      XMotionEvent *event;
 
 {
+  last_mouse_movement_time = event->time;
+
   /* Has the mouse moved off the glyph it was on at the last sighting?  */
   if (event->x < last_mouse_glyph.x
       || 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
@@ -1585,157 +1613,854 @@ note_mouse_position (screen, 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.
+
    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 (s, x, y, time)
-     SCREEN_PTR *s;
+XTmouse_position (f, bar_window, part, x, y, time)
+     FRAME_PTR *f;
+     Lisp_Object *bar_window;
+     enum scroll_bar_part *part;
      Lisp_Object *x, *y;
-     Lisp_Object *time;
+     unsigned long *time;
 {
-  int ix, iy, dummy;
-  Display *d = x_current_display;
-  Window guess, root, child;
-
   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 screen 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 screen'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 = selected_screen->display.x->window_desc;
-  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 screen we should
-         try instead.  */
-      guess = root;
-
-  *s = last_mouse_screen = x_window_to_screen (guess);
-  if (! *s)
-    *x = *y = Qnil;
+  if (! NILP (last_mouse_scroll_bar))
+    x_scroll_bar_report_motion (f, bar_window, part, x, y, time);
   else
     {
-      pixel_to_glyph_coords (*s, 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;
+      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.  */
-  *time = Qnil;
+      mouse_moved = 0;
+      last_mouse_scroll_bar = Qnil;
 
-  UNBLOCK_INPUT;
-}
+      /* Figure out which root window we're on.  */
+      XQueryPointer (x_current_display,
+                    DefaultRootWindow (x_current_display),
 
-\f
-static char *events[] =
-{
-  "0: ERROR!",
-  "1: REPLY",
-  "KeyPress",
-  "KeyRelease",
-  "ButtonPress",
-  "ButtonRelease",
-  "MotionNotify",
-  "EnterNotify",
-  "LeaveNotify",
-  "FocusIn",
-  "FocusOut",
-  "KeymapNotify",
-  "Expose",
-  "GraphicsExpose",
-  "NoExpose",
-  "VisibilityNotify",
-  "CreateNotify",
-  "DestroyNotify",
-  "UnmapNotify",
-  "MapNotify",
-  "MapRequest",
-  "ReparentNotify",
-  "ConfigureNotify",
-  "ConfigureRequest",
-  "GravityNotify",
-  "ResizeRequest",
-  "CirculateNotify",
-  "CirculateRequest",
-  "PropertyNotify",
-  "SelectionClear",
-  "SelectionRequest",
-  "SelectionNotify",
-  "ColormapNotify",
-  "ClientMessage",
-  "MappingNotify",
-  "LASTEvent"
-};
-#else  /* X10 */
-#define XEvent XKeyPressedEvent
-#endif /* HAVE_X11 */ 
+                    /* The root window which contains the pointer.  */
+                    &root,
 
-/* Symbols returned in the input stream to indicate various X events.  */
-Lisp_Object Qmouse_click;
-Lisp_Object Qscrollbar_click;
+                    /* Trash which we can't trust if the pointer is on
+                       a different screen.  */
+                    &dummy_window,
 
-/* Timestamp of enter window event.  This is only used by XTread_socket,
-   but we have to put it out here, since static variables within functions
-   sometimes don't work.  */
-static Time enter_timestamp;
+                    /* The position on that root window.  */
+                    &root_x, &root_y, 
 
-/* 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.
+                    /* More trash we can't trust.  */
+                    &dummy, &dummy,
 
-   Events representing keys are stored in buffer BUFP,
-   which can hold up to NUMCHARS characters.
-   We return the number of characters stored into the buffer,
-   thus pretending to be `read'.
+                    /* Modifier keys and pointer buttons, about which
+                       we don't care.  */
+                    (unsigned int *) &dummy);
 
-   WAITP is nonzero if we should block until input arrives.
-   EXPECTED is nonzero if the caller knows input is available.  */
+      /* 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;
 
-Lisp_Object
-XTread_socket (sd, bufp, numchars, waitp, expected)
-     register int sd;
-     register struct input_event *bufp;
-     register int numchars;
-     int waitp;
-     int expected;
-{
-  int count = 0;
-  int nbytes = 0;
+       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?  */
+       *f = x_window_to_frame (win);
+      
+       /* If not, is it one of our scroll bars?  */
+       if (! *f)
+         {
+           struct scroll_bar *bar = x_window_to_scroll_bar (win);
+
+           if (bar)
+             {
+               *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+               win_x = parent_x;
+               win_y = parent_y;
+             }
+         }
+
+       if (*f)
+         {
+           pixel_to_glyph_coords (*f, win_x, win_y, &win_x, &win_y,
+                                  &last_mouse_glyph);
+
+           *bar_window = Qnil;
+           *part = 0;
+           XSET (*x, Lisp_Int, win_x);
+           XSET (*y, Lisp_Int, win_y);
+           *time = last_mouse_movement_time;
+         }
+      }
+    }
+
+  UNBLOCK_INPUT;
+}
+
+#else /* ! defined (HAVE_X11) */
+#define XEvent XKeyPressedEvent
+#endif /* ! defined (HAVE_X11) */
+\f
+/* Scroll bar support.  */
+
+/* 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;
+
+  for (tail = Vframe_list;
+       XGCTYPE (tail) == Lisp_Cons;
+       tail = XCONS (tail)->cdr)
+    {
+      Lisp_Object frame = XCONS (tail)->car;
+      Lisp_Object bar, condemned;
+
+      /* All elements of Vframe_list should be frames.  */
+      if (XGCTYPE (frame) != Lisp_Frame)
+       abort ();
+
+      /* Scan this frame's scroll bar list for a scroll bar with the
+         right window ID.  */
+      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 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;
+{
+  FRAME_PTR frame = XFRAME (WINDOW_FRAME (window));
+  struct scroll_bar *bar =
+    XSCROLL_BAR (Fmake_vector (make_number (SCROLL_BAR_VEC_SIZE), Qnil));
+
+  BLOCK_INPUT;
+
+  {
+    XSetWindowAttributes a;
+    unsigned long mask;
+
+    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 | CWEventMask | CWCursor);
+
+    SET_SCROLL_BAR_X_WINDOW
+      (bar, 
+       XCreateWindow (x_current_display, FRAME_X_WINDOW (frame),
+
+                     /* Position and size of scroll bar.  */
+                     left, top, width, height,
+
+                     /* Border width, depth, class, and visual.  */
+                     0, CopyFromParent, CopyFromParent, CopyFromParent,
+
+                     /* Attributes.  */
+                     mask, &a));
+  }
+
+  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 = 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, SCROLL_BAR_X_WINDOW (bar));
+
+  UNBLOCK_INPUT;
+
+  return bar;
+}
+
+/* Draw BAR's handle in the proper position.
+   If the handle is already drawn from START to END, don't bother
+   redrawing it, unless REBUILD is non-zero; in that case, always
+   redraw it.  (REBUILD is handy for drawing the handle after expose
+   events.)  
+
+   Normally, we want to constrain the start and end of the handle to
+   fit inside its rectangle, but if the user is dragging the scroll bar
+   handle, we want to let them drag it down all the way, so that the
+   bar's top is as far down as it goes; otherwise, there's no way to
+   move to the very end of the buffer.  */
+static void
+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 = 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.  */
+    {
+      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;
+    }
+
+    /* Store the adjusted setting in the scroll bar.  */
+    XSET (bar->start, Lisp_Int, start);
+    XSET (bar->end, Lisp_Int, end);
+
+    /* 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, w, gc,
+
+                   /* x, y, width, height */
+                   VERTICAL_SCROLL_BAR_LEFT_BORDER,
+                   VERTICAL_SCROLL_BAR_TOP_BORDER + start,
+                   inside_width, end - start);
+
+
+    /* 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_SCROLL_BAR_LEFT_BORDER,
+                 VERTICAL_SCROLL_BAR_TOP_BORDER + end,
+                 inside_width, inside_height - end,
+                 False);
+
+  }
+
+  UNBLOCK_INPUT;
+}
+
+/* Move a scroll bar around on the screen, to accomodate changing
+   window configurations.  */
+static void
+x_scroll_bar_move (bar, top, left, width, height)
+     struct scroll_bar *bar;
+     int top, left, width, height;
+{
+  BLOCK_INPUT;
+
+  {
+    XWindowChanges wc;
+    unsigned int mask = 0;
+
+    wc.x = left;
+    wc.y = top;
+    wc.width = width;
+    wc.height = height;
+
+    if (left != XINT (bar->left))      mask |= CWX;
+    if (top != XINT (bar->top))                mask |= CWY;
+    if (width != XINT (bar->width))    mask |= CWWidth;
+    if (height != XINT (bar->height))  mask |= CWHeight;
+    
+    if (mask)
+      XConfigureWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar),
+                       mask, &wc);
+  }
+
+  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_scroll_bar_remove (bar)
+     struct scroll_bar *bar;
+{
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+
+  BLOCK_INPUT;
+
+  /* Destroy the window.  */
+  XDestroyWindow (x_current_display, SCROLL_BAR_X_WINDOW (bar));
+
+  /* Disassociate this scroll bar from its window.  */
+  XWINDOW (bar->window)->vertical_scroll_bar = Qnil;
+
+  UNBLOCK_INPUT;
+}
+
+/* Set the handle of the vertical scroll bar for WINDOW to indicate
+   that we are displaying PORTION characters out of a total of WHOLE
+   characters, starting at POSITION.  If WINDOW has no scroll bar,
+   create one.  */
+static void
+XTset_vertical_scroll_bar (window, portion, whole, position)
+     struct window *window;
+     int portion, whole, position;
+{
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (window));
+  int top = XINT (window->top);
+  int left = WINDOW_VERTICAL_SCROLL_BAR_COLUMN (window);
+  int height = WINDOW_VERTICAL_SCROLL_BAR_HEIGHT (window);
+
+  /* Where should this scroll bar be, pixelwise?  */
+  int pixel_top  = CHAR_TO_PIXEL_ROW (f, top);
+  int pixel_left = CHAR_TO_PIXEL_COL (f, left);
+  int pixel_width = 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.  */
+      bar = XSCROLL_BAR (window->vertical_scroll_bar);
+      x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
+    }
+
+  /* Set the scroll bar's current state, unless we're currently being
+     dragged.  */
+  if (NILP (bar->dragging))
+    {
+      int top_range =
+       VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
+
+      if (whole == 0)
+       x_scroll_bar_set_handle (bar, 0, top_range, 0);
+      else
+       {
+         int start = (position * top_range) / whole;
+         int end = ((position + portion) * top_range) / whole;
+
+         x_scroll_bar_set_handle (bar, start, end, 0);
+       }
+    }
+
+  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 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, 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_scroll_bars (frame)
+     FRAME_PTR frame;
+{
+  /* 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 WINDOW's scroll bar for deletion in this judgement cycle.
+   Note that WINDOW isn't necessarily condemned at all.  */
+static void
+XTredeem_scroll_bar (window)
+     struct window *window;
+{
+  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 scroll bars on FRAME that haven't been saved since the
+   last call to `*condemn_scroll_bars_hook'.  */
+static void
+XTjudge_scroll_bars (f)
+     FRAME_PTR f;
+{
+  Lisp_Object bar, next;
+
+  bar = FRAME_CONDEMNED_SCROLL_BARS (f);
+
+  /* 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)
+    {
+      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 scroll bar.
+
+   This may be called from a signal handler, so we have to ignore GC
+   mark bits.  */
+static void
+x_scroll_bar_expose (bar, event)
+     struct scroll_bar *bar;
+     XEvent *event;
+{
+  Window w = SCROLL_BAR_X_WINDOW (bar);
+  GC gc = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)))->display.x->normal_gc;
+
+  BLOCK_INPUT;
+
+  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 another line to make the extra-thick border on the right.  */
+  XFillRectangle (x_current_display, w, gc,
+
+                 /* x, y, width, height */
+                 XINT (bar->width) - 2, 1, 1, XINT (bar->height) - 2);
+
+  UNBLOCK_INPUT;
+}
+
+/* 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_scroll_bar_handle_click (bar, event, emacs_event)
+     struct scroll_bar *bar;
+     XEvent *event;
+     struct input_event *emacs_event;
+{
+  if (XGCTYPE (bar->window) != Lisp_Window)
+    abort ();
+
+  emacs_event->kind = scroll_bar_click;
+  XSET (emacs_event->code, Lisp_Int, event->xbutton.button - Button1);
+  emacs_event->modifiers =
+    (x_convert_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;
+    
+    /* 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));
+
+    /* 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));
+
+       x_scroll_bar_set_handle (bar, new_start, new_end, 0);
+       bar->dragging = Qnil;
+      }
+
+    /* Clicks on the handle are always reported as occuring 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);
+
+    XSET (emacs_event->y, Lisp_Int, top_range);
+  }
+}
+
+/* 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_scroll_bar_note_movement (bar, event)
+     struct scroll_bar *bar;
+     XEvent *event;
+{
+  last_mouse_movement_time = event->xmotion.time;
+
+  mouse_moved = 1;
+  XSET (last_mouse_scroll_bar, Lisp_Vector, bar);
+
+  /* If we're dragging the bar, display it.  */
+  if (! GC_NILP (bar->dragging))
+    {
+      /* Where should the handle be now?  */
+      int new_start = event->xmotion.y - XINT (bar->dragging);
+
+      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);
+  }
+}
+
+/* Return information to the user about the current position of the mouse
+   on the scroll bar.  */
+static void
+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;
+{
+  struct scroll_bar *bar = XSCROLL_BAR (last_mouse_scroll_bar);
+  int win_x, win_y;
+
+  BLOCK_INPUT;
+
+  /* Get the mouse's position relative to the scroll bar window, and
+     report that.  */
+  {
+    Window dummy_window;
+    int dummy_coord;
+    unsigned int dummy_mask;
+
+    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;
+       goto done;
+      }
+  }
+
+  {
+    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);
+    *time = last_mouse_movement_time;
+  }
+
+  mouse_moved = 0;
+  last_mouse_scroll_bar = Qnil;
+
+ done:
+  UNBLOCK_INPUT;
+}
+
+
+/* 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.  */
+
+x_scroll_bar_clear (f)
+     FRAME_PTR f;
+{
+  Lisp_Object bar;
+
+  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);
+}
+
+
+\f
+/* The main X event-reading loop - XTread_socket.  */
+
+/* Timestamp of enter window event.  This is only used by XTread_socket,
+   but we have to put it out here, since static variables within functions
+   sometimes don't work.  */
+static Time enter_timestamp;
+
+/* This holds the state XLookupString needs to implement dead keys
+   and other tricks known as "compose processing".  _X Window System_ 
+   says that a portable program can't use this, but Stephen Gildea assures
+   me that letting the compiler initialize it to zeros will work okay.
+
+   This must be defined outside of XTread_socket, for the same reasons
+   given for enter_timestamp, above.  */
+static XComposeStatus compose_status;
+
+/* Communication with window managers. */
+Atom Xatom_wm_protocols;
+
+/* Kinds of protocol things we may receive. */
+Atom Xatom_wm_take_focus;
+Atom Xatom_wm_save_yourself;
+Atom Xatom_wm_delete_window;
+
+/* Other WM communication */
+Atom Xatom_wm_configure_denied;          /* When our config request is denied */
+Atom Xatom_wm_window_moved;      /* When the WM moves us. */
+
+/* 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.
+
+   Events representing keys are stored in buffer BUFP,
+   which can hold up to NUMCHARS characters.
+   We return the number of characters stored into the buffer,
+   thus pretending to be `read'.
+
+   WAITP is nonzero if we should block until input arrives.
+   EXPECTED is nonzero if the caller knows input is available.  */
+
+int
+XTread_socket (sd, bufp, numchars, waitp, expected)
+     register int sd;
+     register struct input_event *bufp;
+     register int numchars;
+     int waitp;
+     int expected;
+{
+  int count = 0;
+  int nbytes = 0;
   int mask;
   int items_pending;           /* How many items are in the X queue. */
   XEvent event;
-  struct screen *s;
+  struct frame *f;
   int event_found;
   int prefix;
   Lisp_Object part;
@@ -1758,7 +2483,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
      FIOSNBIO is ignored, and instead of signalling EWOULDBLOCK,
      a read returns 0, which Xlib interprets as equivalent to EPIPE. */
   fcntl (fileno (stdin), F_SETFL, 0);
-#endif
+#endif /* ! defined (FIOSNBIO) */
 
 #ifndef SIGIO
 #ifndef HAVE_SELECT
@@ -1769,8 +2494,8 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
       XPeekEvent (XDISPLAY &event);
       read_alarm_should_throw = 0;
     }
-#endif
-#endif
+#endif /* HAVE_SELECT */
+#endif /* SIGIO */
 
   while (XStuffPending () != 0)
     {
@@ -1780,6 +2505,51 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
       switch (event.type)
        {
 #ifdef HAVE_X11
+       case ClientMessage:
+         {
+           if (event.xclient.message_type == Xatom_wm_protocols
+               && event.xclient.format == 32)
+             {
+               if (event.xclient.data.l[0] == Xatom_wm_take_focus)
+                 {
+                   f = x_window_to_frame (event.xclient.window);
+                   if (f)
+                     x_focus_on_frame (f);
+                   /* Not certain about handling scroll bars here */
+                 }
+               else if (event.xclient.data.l[0] == Xatom_wm_save_yourself)
+                 {
+                   /* Save state modify the WM_COMMAND property to
+                      something which can reinstate us. This notifies
+                      the session manager, who's looking for such a
+                      PropertyNotify.  Can restart processing when
+                      a keyboard or mouse event arrives. */
+                   if (numchars > 0)
+                     {
+                     }
+                 }
+               else if (event.xclient.data.l[0] == Xatom_wm_delete_window)
+                 {
+                   struct frame *f = x_window_to_frame (event.xclient.window);
+
+                   if (f)
+                     if (numchars > 0)
+                       {
+                       }
+                 }
+             }
+           else if (event.xclient.message_type == Xatom_wm_configure_denied)
+             {
+             }
+           else if (event.xclient.message_type == Xatom_wm_window_moved)
+             {
+               int new_x, new_y;
+
+               new_x = event.xclient.data.s[0];
+               new_y = event.xclient.data.s[1];
+             }
+         }
+         break;
 
        case SelectionClear:    /* Someone has grabbed ownership. */
          x_disown_selection (event.xselectionclear.window,
@@ -1792,71 +2562,96 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          break;
 
        case PropertyNotify:
-         /* If we were to do this synchronously, there'd be no worry
-            about re-selecting. */
-         x_send_incremental (event);
+
+         /* If we're being told about a root window property, then it's
+            a cut buffer change.  */
+         if (event.xproperty.window == ROOT_WINDOW)
+           x_invalidate_cut_buffer_cache (&event.xproperty);
+
+         /* Otherwise, we're probably handling an incremental
+             selection transmission.  */
+         else
+           {
+             /* If we were to do this synchronously, there'd be no worry
+                about re-selecting. */
+             x_send_incremental (event);
+           }
          break;
 
        case Expose:
-         s = x_window_to_screen (event.xexpose.window);
-         if (s)
+         f = x_window_to_frame (event.xexpose.window);
+         if (f)
            {
-             if (s->visible == 0)
+             if (f->async_visible == 0)
                {
-                 s->visible = 1;
-                 s->iconified = 0;
-                 SET_SCREEN_GARBAGED (s);
+                 f->async_visible = 1;
+                 f->async_iconified = 0;
+                 SET_FRAME_GARBAGED (f);
                }
              else
-               dumprectangle (x_window_to_screen (event.xexpose.window),
-                              event.xexpose.x, event.xexpose.y,
-                              event.xexpose.width, event.xexpose.height);
+               {
+                 dumprectangle (x_window_to_frame (event.xexpose.window),
+                                event.xexpose.x, event.xexpose.y,
+                                event.xexpose.width, event.xexpose.height);
+               }
+           }
+         else
+           {
+             struct scroll_bar *bar
+               = x_window_to_scroll_bar (event.xexpose.window);
+
+             if (bar)
+               x_scroll_bar_expose (bar, &event);
            }
          break;
 
        case GraphicsExpose:    /* This occurs when an XCopyArea's
                                  source area was obscured or not
                                  available.*/
-         dumprectangle (x_window_to_screen (event.xgraphicsexpose.drawable),
-                        event.xgraphicsexpose.x, event.xgraphicsexpose.y,
-                        event.xgraphicsexpose.width,
-                        event.xgraphicsexpose.height);
+         f = x_window_to_frame (event.xgraphicsexpose.drawable);
+         if (f)
+           {
+             dumprectangle (f,
+                            event.xgraphicsexpose.x, event.xgraphicsexpose.y,
+                            event.xgraphicsexpose.width,
+                            event.xgraphicsexpose.height);
+           }
          break;
 
        case NoExpose:          /* This occurs when an XCopyArea's
                                  source area was completely
                                  available */
          break;
-#else /* not HAVE_X11 */
+#else /* ! defined (HAVE_X11) */
        case ExposeWindow:
          if (event.subwindow != 0)
            break;              /* duplicate event */
-         s = x_window_to_screen (event.window);
-         if (event.window == s->display.x->icon_desc)
+         f = x_window_to_frame (event.window);
+         if (event.window == f->display.x->icon_desc)
            {
-             refreshicon (s);
-             s->iconified = 1;
+             refreshicon (f);
+             f->async_iconified = 1;
            }
-         if (event.window == s->display.x->window_desc)
+         if (event.window == FRAME_X_WINDOW (f))
            {
              /* Say must check all windows' needs_exposure flags.  */
              expose_all_windows = 1;
-             s->display.x->needs_exposure = 1;
-             s->visible = 1;
+             f->display.x->needs_exposure = 1;
+             f->async_visible = 1;
            }
          break;
 
        case ExposeRegion:
          if (event.subwindow != 0)
            break;              /* duplicate event */
-         s = x_window_to_screen (event.window);
-         if (event.window == s->display.x->icon_desc)
+         f = x_window_to_frame (event.window);
+         if (event.window == f->display.x->icon_desc)
            {
-             refreshicon (s);
+             refreshicon (f);
              break;
            }
          /* If window already needs full redraw, ignore this rectangle.  */
-         if (expose_all_windows && s->display.x->needs_exposure)
+         if (expose_all_windows && f->display.x->needs_exposure)
            break;
          /* Put the event on the queue of rectangles to redraw.  */
          if (enqueue_event (&event, &x_expose_queue))
@@ -1865,7 +2660,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            {
              /* Say must check all windows' needs_exposure flags.  */
              expose_all_windows = 1;
-             s->display.x->needs_exposure = 1;
+             f->display.x->needs_exposure = 1;
            }
          break;
 
@@ -1873,37 +2668,31 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          /* This should happen only when we are expecting it,
             in x_read_exposes.  */
          abort ();
-#endif /* not HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 #ifdef HAVE_X11
        case UnmapNotify:
-         {
-           XWMHints *hints;
-
-           s = x_window_to_screen (event.xunmap.window);
-           if (s)              /* S may no longer exist if
-                                  the screen was deleted.  */
-             {
-               /* While a screen is unmapped, display generation is
-                  disabled; you don't want to spend time updating a
-                  display that won't ever be seen.  */
-               s->visible = 0;
-               Vmouse_window = Vmouse_screen_part = Qnil;
-               x_mouse_x = x_mouse_y = -1;
-             }
-         }
+         f = x_window_to_frame (event.xunmap.window);
+         if (f)                /* F may no longer exist if
+                                  the frame was deleted.  */
+           {
+             /* While a frame is unmapped, display generation is
+                disabled; you don't want to spend time updating a
+                display that won't ever be seen.  */
+             f->async_visible = 0;
+           }
          break;
 
        case MapNotify:
-         s = x_window_to_screen (event.xmap.window);
-         if (s)
+         f = x_window_to_frame (event.xmap.window);
+         if (f)
            {
-             s->visible = 1;
-             s->iconified = 0;
+             f->async_visible = 1;
+             f->async_iconified = 0;
 
              /* wait_reading_process_input will notice this and update
-                the screen's display structures.  */
-             SET_SCREEN_GARBAGED (s);
+                the frame's display structures.  */
+             SET_FRAME_GARBAGED (f);
            }
          break;
 
@@ -1911,31 +2700,40 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
        case VisibilityNotify:
          break;
 
-#else
+#else /* ! defined (HAVE_X11) */
        case UnmapWindow:
-         s = x_window_to_screen (event.window);
-         if (event.window == s->display.x->icon_desc)
-           s->iconified = 0;
-         if (event.window == s->display.x->window_desc)
-           s->visible = 0;
+         f = x_window_to_frame (event.window);
+         if (event.window == f->display.x->icon_desc)
+           f->async_iconified = 0;
+         if (event.window == FRAME_X_WINDOW (f))
+           f->async_visible = 0;
          break;
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 #ifdef HAVE_X11
        case KeyPress:
-         s = x_window_to_screen (event.xkey.window);
-         if (s != 0)
+         f = x_window_to_frame (event.xkey.window);
+
+         if (f != 0)
            {
              KeySym keysym;
-             XComposeStatus status;
              char copy_buffer[80];
+             int modifiers;
 
-             /* This will have to go some day... */
-             nbytes = XLookupString (&event.xkey,
-                                     copy_buffer,
-                                     80,
-                                     &keysym,
-                                     &status);
+             event.xkey.state |= extra_keyboard_modifiers;
+             modifiers = event.xkey.state;
+
+             /* 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;
+
+             /* This will have to go some day...  */
+             nbytes =
+               XLookupString (&event.xkey, copy_buffer, 80, &keysym,
+                              &compose_status);
 
              /* Strip off the vendor-specific keysym bit, and take a shot
                 at recognizing the codes.  HP servers have extra keysyms
@@ -1944,16 +2742,18 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 
              if (numchars > 1)
                {
-                 if (IsCursorKey (keysym)          /* 0xff50 <= x < 0xff60 */
+                 if ((keysym >= XK_BackSpace && keysym <= XK_Escape)
+                     || keysym == XK_Delete
+                     || IsCursorKey (keysym)       /* 0xff50 <= x < 0xff60 */
                      || IsMiscFunctionKey (keysym) /* 0xff60 <= x < 0xff80 */
                      || IsKeypadKey (keysym)       /* 0xff80 <= x < 0xffbe */
                      || IsFunctionKey (keysym))    /* 0xffbe <= x < 0xffe1 */
                    {
                      bufp->kind = non_ascii_keystroke;
-                     XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff50);
-                     bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
-                     bufp->modifiers = x_convert_modifiers (event.xkey.state);
-                     XSET (bufp->timestamp, Lisp_Int, event.xkey.time);
+                     XSET (bufp->code, Lisp_Int, (unsigned) keysym - 0xff00);
+                     XSET (bufp->frame_or_window, Lisp_Frame, f);
+                     bufp->modifiers = x_convert_modifiers (modifiers);
+                     bufp->timestamp = event.xkey.time;
                      bufp++;
                      count++;
                      numchars--;
@@ -1964,12 +2764,11 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 
                      if (nbytes == 1)
                        {
-                         if (event.xkey.state & Mod1Mask)
-                           *copy_buffer |= METABIT;
                          bufp->kind = ascii_keystroke;
-                         bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
                          XSET (bufp->code, Lisp_Int, *copy_buffer);
-                         XSET (bufp->timestamp, Lisp_Int, event.xkey.time);
+                         XSET (bufp->frame_or_window, Lisp_Frame, f);
+                         bufp->modifiers = x_convert_modifiers (modifiers);
+                         bufp->timestamp = event.xkey.time;
                          bufp++;
                        }
                      else
@@ -1977,8 +2776,9 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                          {
                            bufp->kind = ascii_keystroke;
                            XSET (bufp->code, Lisp_Int, copy_buffer[i]);
-                           XSET (bufp->timestamp, Lisp_Int, event.xkey.time);
-                           bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
+                           XSET (bufp->frame_or_window, Lisp_Frame, f);
+                           bufp->modifiers = x_convert_modifiers (modifiers);
+                           bufp->timestamp = event.xkey.time;
                            bufp++;
                          }
 
@@ -1988,14 +2788,14 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
                }
            }
          break;
-#else
+#else /* ! defined (HAVE_X11) */
        case KeyPressed:
          {
            register char *where_mapping;
 
-           s = x_window_to_screen (event.window);
+           f = x_window_to_frame (event.window);
            /* Ignore keys typed on icon windows.  */
-           if (s != 0 && event.window == s->display.x->icon_desc)
+           if (f != 0 && event.window == f->display.x->icon_desc)
              break;
            where_mapping = XLookupMapping (&event, &nbytes);
            /* Nasty fix for arrow keys */
@@ -2027,7 +2827,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->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
+                   XSET (bufp->frame_or_window, Lisp_Frame, f);
                    bufp++;
                  }
                count += nbytes;
@@ -2035,85 +2835,73 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
              }
          }
          break;
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 #ifdef HAVE_X11
+
+         /* Here's a possible interpretation of the whole
+            FocusIn-EnterNotify FocusOut-LeaveNotify mess.  If you get a
+            FocusIn event, you have to get a FocusOut event before you
+            relinquish the focus.  If you haven't received a FocusIn event,
+            then a mere LeaveNotify is enough to free you.  */
+
        case EnterNotify:
-         s = x_window_to_screen (event.xcrossing.window);
+         f = x_window_to_frame (event.xcrossing.window);
 
-         if (event.xcrossing.detail == NotifyInferior) /* Left Scrollbar */
-           ;
-         else if (event.xcrossing.focus)               /* Entered Window */
+         if (event.xcrossing.focus)            /* Entered Window */
            {
-             /* If we decide we want to generate an event to be seen
-                by the rest of Emacs, we put it here.  */
-             struct input_event emacs_event;
-             emacs_event.kind = no_event;
-
              /* Avoid nasty pop/raise loops. */
-             if (s && (!(s->auto_raise)
-                       || !(s->auto_lower)
+             if (f && (!(f->auto_raise)
+                       || !(f->auto_lower)
                        || (event.xcrossing.time - enter_timestamp) > 500))
                {
-                 x_new_focus_screen (s);
+                 x_new_focus_frame (f);
                  enter_timestamp = event.xcrossing.time;
                }
-#if 0
-             else if ((s = x_window_to_scrollbar (event.xcrossing.window,
-                                                  &part, &prefix)))
-               /* Fake a motion event */
-               notice_mouse_movement (&emacs_event,
-                                      event.xmotion, s, scrollbar_window,
-                                      part);
-#endif
-
-#if 0
-             if (! EQ (Vx_send_mouse_movement_events, Qnil)
-                 && numchars >= 1
-                 && emacs_event.kind != no_event)
-               {
-                 bcopy (&emacs_event, bufp, sizeof (struct input_event));
-                 bufp++;
-                 count++;
-                 numchars--;
-               }
-#endif
            }
-         else if (s == x_focus_screen)
-           x_new_focus_screen (0);
-#if 0
-         else if (s = x_window_to_screen (event.xcrossing.window))
-           x_mouse_screen = s;
-#endif
+         else if (f == x_focus_frame)
+           x_new_focus_frame (0);
 
          break;
 
        case FocusIn:
-         s = x_window_to_screen (event.xfocus.window);
-         if (s)
-           x_new_focus_screen (s);
+         f = x_window_to_frame (event.xfocus.window);
+         if (event.xfocus.detail != NotifyPointer) 
+           x_focus_event_frame = f;
+         if (f)
+           x_new_focus_frame (f);
          break;
 
+
        case LeaveNotify:
-         if (event.xcrossing.detail != NotifyInferior
-             && event.xcrossing.subwindow == None
-             && event.xcrossing.mode == NotifyNormal)
+         f = x_window_to_frame (event.xcrossing.window);
+
+         if (event.xcrossing.focus)
+           {
+             if (! x_focus_event_frame)
+               x_new_focus_frame (0);
+             else
+               x_new_focus_frame (f);
+           }
+         else 
            {
-             s = x_window_to_screen (event.xcrossing.window);
-             if (event.xcrossing.focus)
-               x_new_focus_screen (s);
-             else if (s == x_focus_screen)
-               x_new_focus_screen (0);
+             if (f == x_focus_event_frame)
+               x_focus_event_frame = 0;
+             if (f == x_focus_frame)
+               x_new_focus_frame (0);
            }
          break;
 
        case FocusOut:
-         s = x_window_to_screen (event.xfocus.window);
-         if (s && s == x_focus_screen)
-           x_new_focus_screen (0);
+         f = x_window_to_frame (event.xfocus.window);
+         if (event.xfocus.detail != NotifyPointer
+             && f == x_focus_event_frame)
+           x_focus_event_frame = 0;
+         if (f && f == x_focus_frame)
+           x_new_focus_frame (0);
          break;
 
-#else /* not HAVE_X11 */
+#else /* ! defined (HAVE_X11) */
 
        case EnterWindow:
          if ((event.detail & 0xFF) == 1)
@@ -2122,14 +2910,10 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            break;              /* Entering our own subwindow.  */
 
          {
-           extern int waiting_for_input;
-           struct screen *old_s = x_input_screen;
+           f = x_window_to_frame (event.window);
+           x_mouse_frame = f;
 
-           s = x_window_to_screen (event.window);
-           x_mouse_screen = s;
-
-           if (waiting_for_input && x_focus_screen == 0)
-             x_new_focus_screen (s);
+           x_new_focus_frame (f);
          }
          break;
 
@@ -2139,71 +2923,62 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          if (event.subwindow != 0)
            break;              /* Leaving our own subwindow.  */
 
-         x_mouse_screen = 0;
-         if (x_focus_screen == 0
-             && x_input_screen != 0
-             && x_input_screen == x_window_to_screen (event.window)
-             && event.window == x_input_screen->display.x->window_desc)
+         x_mouse_frame = 0;
+         if (x_focus_frame == 0
+             && x_input_frame != 0
+             && x_input_frame == x_window_to_frame (event.window)
+             && event.window == FRAME_X_WINDOW (x_input_frame))
            {
-             s = x_input_screen;
-             x_input_screen = 0;
-             if (s)
-               screen_unhighlight (s);
+             f = x_input_frame;
+             x_input_frame = 0;
+             if (f)
+               frame_unhighlight (f);
            }
          break;
-#endif /* not HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 #ifdef HAVE_X11
        case MotionNotify:
          {
-           s = x_window_to_screen (event.xmotion.window);
-           if (s)
-             note_mouse_position (s, &event.xmotion);
-#if 0
-           else if ((s = x_window_to_scrollbar (event.xmotion.window,
-                                                &part, &prefix)))
+           f = x_window_to_frame (event.xmotion.window);
+           if (f)
+             note_mouse_movement (f, &event.xmotion);
+           else
              {
-               What should go here?
+               struct scroll_bar *bar =
+                 x_window_to_scroll_bar (event.xmotion.window);
+
+               if (bar)
+                 x_scroll_bar_note_movement (bar, &event);
              }
-#endif
          }
          break;
 
        case ConfigureNotify:
-         {
-           int rows, columns;
-           s = x_window_to_screen (event.xconfigure.window);
-           if (!s)
-             break;
-
-           columns = ((event.xconfigure.width -
-                       (2 * s->display.x->internal_border_width)
-                       - s->display.x->v_scrollbar_width)
-                      / FONT_WIDTH (s->display.x->font));
-           rows = ((event.xconfigure.height -
-                    (2 * s->display.x->internal_border_width)
-                    - s->display.x->h_scrollbar_height)
-                   / FONT_HEIGHT (s->display.x->font));
-
-           /* 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 != s->width
-               || rows != s->height
-               || event.xconfigure.width != s->display.x->pixel_width
-               || event.xconfigure.height != s->display.x->pixel_height)
-             {
-               change_screen_size (s, rows, columns, 0);
-               x_resize_scrollbars (s);
-               SET_SCREEN_GARBAGED (s);
-             }
+         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);
+               }
 
-           s->display.x->pixel_width = event.xconfigure.width;
-           s->display.x->pixel_height = event.xconfigure.height;
-           s->display.x->left_pos = event.xconfigure.x;
-           s->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:
@@ -2213,23 +2988,21 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            struct input_event emacs_event;
            emacs_event.kind = no_event;
 
-           s = x_window_to_screen (event.xbutton.window);
-           if (s)
-             if (!x_focus_screen || (s == x_focus_screen))
-               construct_mouse_click (&emacs_event,
-                                      &event, s, 0, 0);
-             else
-               continue;
+           f = x_window_to_frame (event.xbutton.window);
+           if (f)
+             {
+               if (!x_focus_frame || (f == x_focus_frame))
+                 construct_mouse_click (&emacs_event,
+                                        &event, f);
+             }
            else
-             if ((s = x_window_to_scrollbar (event.xbutton.window,
-                                             &part, &prefix)))
-               {
-                 if (!x_focus_screen || (selected_screen == x_focus_screen))
-                   construct_mouse_click (&emacs_event,
-                                          &event, s, part, prefix);
-                 else
-                   continue;
-               }
+             {
+               struct scroll_bar *bar =
+                 x_window_to_scroll_bar (event.xbutton.window);
+
+               if (bar)
+                 x_scroll_bar_handle_click (bar, &event, &emacs_event);
+             }
 
            if (numchars >= 1 && emacs_event.kind != no_event)
              {
@@ -2241,24 +3014,24 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
          }
          break;
 
-#else /* not HAVE_X11 */
+#else /* ! defined (HAVE_X11) */
        case ButtonPressed:
        case ButtonReleased:
-         s = x_window_to_screen (event.window);
-         if (s)
+         f = x_window_to_frame (event.window);
+         if (f)
            {
-             if (event.window == s->display.x->icon_desc)
+             if (event.window == f->display.x->icon_desc)
                {
-                 x_make_screen_visible (s);
+                 x_make_frame_visible (f);
 
                  if (warp_mouse_on_deiconify)
-                   XWarpMouse (s->display.x->window_desc, 10, 10);
+                   XWarpMouse (FRAME_X_WINDOW (f), 10, 10);
                  break;
                }
-             if (event.window == s->display.x->window_desc)
+             if (event.window == FRAME_X_WINDOW (f))
                {
-                 if (s->auto_raise)
-                   x_raise_screen (s);
+                 if (f->auto_raise)
+                   x_raise_frame (f);
                }
            }
          enqueue_event (&event, &x_mouse_queue);
@@ -2266,13 +3039,13 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
            {
              bufp->kind = ascii_keystroke;
              bufp->code = (char) 'X' & 037; /* C-x */
-             bufp->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
+             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->screen = XSCREEN (SCREEN_FOCUS_SCREEN (s));
+             XSET (bufp->frame_or_window, Lisp_Frame, f);
              XSET (bufp->time, Lisp_Int, event.xkey.time);
              bufp++;
 
@@ -2280,7 +3053,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
              numchars -= 2;
            }
          break;
-#endif /* not HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
 #ifdef HAVE_X11
 
@@ -2289,13 +3062,19 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
        case CirculateRequest:
          break;
 
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
        case MappingNotify:
-         if (event.xmapping.request == MappingKeyboard)
-           /* Someone has changed the keyboard mapping - flush the
-              local cache.  */
-           XRefreshKeyboardMapping (&event.xmapping);
+         /* Someone has changed the keyboard mapping - update the
+            local cache.  */
+         switch (event.xmapping.request)
+           {
+           case MappingModifier:
+             x_find_modifier_meanings ();
+             /* This is meant to fall through.  */
+           case MappingKeyboard:
+             XRefreshKeyboardMapping (&event.xmapping);
+           }
          break;
 
        default:
@@ -2315,15 +3094,17 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
       int mask = 1 << fd;
 
       if (0 != select (fd + 1, &mask, (long *) 0, (long *) 0,
-                      (struct timeval *) 0)
+                      (EMACS_TIME) 0)
          && !XStuffPending ())
        kill (getpid (), SIGHUP);
     }
-#endif /* HAVE_SELECT */
-#endif
+#endif /* ! defined (HAVE_SELECT) */
+#endif /* ! 0 */
 
-  if (updating_screen == 0)
+#ifndef HAVE_X11
+  if (updating_frame == 0)
     x_do_pending_expose ();
+#endif
 
   UNBLOCK_INPUT;
   return count;
@@ -2338,7 +3119,7 @@ XTread_socket (sd, bufp, numchars, waitp, expected)
 static void
 x_read_exposes ()
 {
-  struct screen *s;
+  struct frame *f;
   XKeyPressedEvent event;
 
   while (1)
@@ -2350,16 +3131,16 @@ x_read_exposes ()
        case ExposeWindow:
          if (event.subwindow != 0)
            break;                      /* duplicate event */
-         s = x_window_to_screen (event.window);
-         if (event.window == s->display.x->icon_desc)
+         f = x_window_to_frame (event.window);
+         if (event.window == f->display.x->icon_desc)
            {
-             refreshicon (s);
+             refreshicon (f);
              break;
            }
-         if (event.window == s->display.x->window_desc)
+         if (event.window == FRAME_X_WINDOW (f))
            {
              expose_all_windows = 1;
-             s->display.x->needs_exposure = 1;
+             f->display.x->needs_exposure = 1;
              break;
            }
          break;
@@ -2367,14 +3148,14 @@ x_read_exposes ()
        case ExposeRegion:
          if (event.subwindow != 0)
            break;                      /* duplicate event */
-         s = x_window_to_screen (event.window);
-         if (event.window == s->display.x->icon_desc)
+         f = x_window_to_frame (event.window);
+         if (event.window == f->display.x->icon_desc)
            {
-             refreshicon (s);
+             refreshicon (f);
              break;
            }
          /* If window already needs full redraw, ignore this rectangle.  */
-         if (expose_all_windows && s->display.x->needs_exposure)
+         if (expose_all_windows && f->display.x->needs_exposure)
            break;
          /* Put the event on the queue of rectangles to redraw.  */
          if (enqueue_event (&event, &x_expose_queue))
@@ -2383,7 +3164,7 @@ x_read_exposes ()
            {
              /* Say must check all windows' needs_exposure flags.  */
              expose_all_windows = 1;
-             s->display.x->needs_exposure = 1;
+             f->display.x->needs_exposure = 1;
            }
          break;
 
@@ -2395,281 +3176,291 @@ x_read_exposes ()
 #endif /* HAVE_X11 */
 
 \f
+/* Drawing the cursor.  */
+
+
 /* Draw a hollow box cursor.  Don't change the inside of the box.  */
 
 static void
-x_draw_box (s)
-     struct screen *s;
+x_draw_box (f)
+     struct frame *f;
 {
-  int left = s->cursor_x * FONT_WIDTH (s->display.x->font)
-    + s->display.x->internal_border_width;
-  int top = s->cursor_y * FONT_HEIGHT (s->display.x->font)
-    + s->display.x->internal_border_width;
-  int width = FONT_WIDTH (s->display.x->font);
-  int height = FONT_HEIGHT (s->display.x->font);
+  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, s->display.x->window_desc,
-                 s->display.x->cursor_gc,
+  XDrawRectangle (x_current_display, FRAME_X_WINDOW (f),
+                 f->display.x->cursor_gc,
                  left, top, width - 1, height - 1);
-#else
-  XPixSet (s->display.x->window_desc,
+#else /* ! defined (HAVE_X11) */
+  XPixSet (FRAME_X_WINDOW (f),
           left, top, width, 1,
-          s->display.x->cursor_pixel);
+          f->display.x->cursor_pixel);
 
-  XPixSet (s->display.x->window_desc,
+  XPixSet (FRAME_X_WINDOW (f),
           left, top, 1, height,
-          s->display.x->cursor_pixel);
+          f->display.x->cursor_pixel);
 
-  XPixSet (s->display.x->window_desc,
+  XPixSet (FRAME_X_WINDOW (f),
           left+width-1, top, 1, height,
-          s->display.x->cursor_pixel);
+          f->display.x->cursor_pixel);
 
-  XPixSet (s->display.x->window_desc,
+  XPixSet (FRAME_X_WINDOW (f),
           left, top+height-1, width, 1,
-          s->display.x->cursor_pixel);
-#endif /* HAVE_X11 */
+          f->display.x->cursor_pixel);
+#endif /* ! defined (HAVE_X11) */
 }
 
-/* Clear the cursor of screen S to background color,
+/* Clear the cursor of frame F to background color,
    and mark the cursor as not shown.
    This is used when the text where the cursor is
    is about to be rewritten.  */
 
 static void
-clear_cursor (s)
-     struct screen *s;
+clear_cursor (f)
+     struct frame *f;
 {
   int mask;
 
-  if (! s->visible
-      || s->phys_cursor_x < 0)
+  if (! FRAME_VISIBLE_P (f)
+      || f->phys_cursor_x < 0)
     return;
 
 #ifdef HAVE_X11
-  x_display_cursor (s, 0);
-#if 0
-  XClearArea (x_current_display, s->display.x->window_desc,
-             s->phys_cursor_x * FONT_WIDTH (s->display.x->font)
-             + s->display.x->internal_border_width,
-             s->phys_cursor_y * FONT_HEIGHT (s->display.x->font)
-             + s->display.x->internal_border_width,
-             FONT_WIDTH (s->display.x->font) + 1, FONT_HEIGHT (s->display.x->font) + 1, False);
-#endif
-#else
-  XPixSet (s->display.x->window_desc,
-          s->phys_cursor_x * FONT_WIDTH (s->display.x->font) + s->display.x->internal_border_width,
-          s->phys_cursor_y * FONT_HEIGHT (s->display.x->font) + s->display.x->internal_border_width,
-          FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font),
-          s->display.x->background_pixel);
-#endif /* HAVE_X11 */
-  s->phys_cursor_x = -1;
+  x_display_cursor (f, 0);
+#else /* ! defined (HAVE_X11) */
+  XPixSet (FRAME_X_WINDOW (f),
+          CHAR_TO_PIXEL_COL (f, f->phys_cursor_x),
+          CHAR_TO_PIXEL_ROW (f, f->phys_cursor_y),
+          FONT_WIDTH (f->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, f->display.x->font);
 }
 
 static void
-x_display_bar_cursor (s, on)
-     struct screen *s;
+x_display_bar_cursor (f, on)
+     struct frame *f;
      int on;
 {
-  register int phys_x = s->phys_cursor_x;
-  register int phys_y = s->phys_cursor_y;
-  register int x1;
-  register int y1;
-  register int y2;
+  struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
 
-  if (! s->visible || (! on && s->phys_cursor_x < 0))
+  if (! FRAME_VISIBLE_P (f))
     return;
 
-#ifdef HAVE_X11
-  if (phys_x >= 0 &&
-      (!on || phys_x != s->cursor_x || phys_y != s->cursor_y))
-    {
-      x1 = phys_x * FONT_WIDTH (s->display.x->font)
-       + s->display.x->internal_border_width;
-      y1 = phys_y * FONT_HEIGHT (s->display.x->font)
-       + s->display.x->internal_border_width - 1;
-      y2 = y1 + FONT_HEIGHT (s->display.x->font) + 1;
+  if (! on && f->phys_cursor_x < 0)
+    return;
 
-      XDrawLine (x_current_display, s->display.x->window_desc,
-                s->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);
+    }
 
-      s->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 && s == x_highlight_screen)
+  /* 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 = s->cursor_x * FONT_WIDTH (s->display.x->font)
-       + s->display.x->internal_border_width;
-      y1 = s->cursor_y * FONT_HEIGHT (s->display.x->font)
-       + s->display.x->internal_border_width - 1;
-      y2 = y1 + FONT_HEIGHT (s->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, s->display.x->window_desc,
-                s->display.x->cursor_gc, x1, y1, x1, y2);
+      f->phys_cursor_x = curs_x;
+      f->phys_cursor_y = curs_y;
 
-      s->phys_cursor_x = s->cursor_x;
-      s->phys_cursor_y = s->cursor_y;
+      f->display.x->current_cursor = bar_cursor;
     }
-#else  /* X10 */
-  Give it up, dude.
-#endif /* X10 */
-}
 
-
-/* Redraw the glyph at ROW, COLUMN on screen S, in the style
-   HIGHLIGHT.  HIGHLIGHT is as defined for dumpglyphs.  Return the
-   glyph drawn.  */
-
-static void
-x_draw_single_glyph (s, row, column, glyph, highlight)
-     struct screen *s;
-     int row, column;
-     GLYPH glyph;
-     int highlight;
-{
-  dumpglyphs (s,
-             (column * FONT_WIDTH (s->display.x->font)
-              + s->display.x->internal_border_width),
-             (row * FONT_HEIGHT (s->display.x->font)
-              + s->display.x->internal_border_width),
-             &glyph, 1, highlight, s->display.x->font);
+  if (updating_frame != f)
+    XFlushQueue ();
 }
 
-/* Turn the displayed cursor of screen S on or off according to ON.
+
+/* 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 S->cursor_x and S->cursor_y.  */
+   by F->cursor_x and F->cursor_y.  */
 
 static void
-x_display_box_cursor (s, on)
-     struct screen *s;
+x_display_box_cursor (f, on)
+     struct frame *f;
      int on;
 {
-  struct screen_glyphs *current_glyphs = SCREEN_CURRENT_GLYPHS (s);
+  struct frame_glyphs *current_glyphs = FRAME_CURRENT_GLYPHS (f);
 
-  if (! s->visible)
+  if (! FRAME_VISIBLE_P (f))
     return;
 
   /* If cursor is off and we want it off, return quickly.  */
-  if (!on && s->phys_cursor_x < 0)
+  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)
+    {
+      curs_x = FRAME_CURSOR_X (f);
+      curs_y = FRAME_CURSOR_Y (f);
+    }
+
   /* If cursor is currently being shown and we don't want it to be
      or it is in the wrong place,
      or we want a hollow box and it's not so, (pout!)
      erase it.  */
-  if (s->phys_cursor_x >= 0
+  if (f->phys_cursor_x >= 0
       && (!on
-         || s->phys_cursor_x != s->cursor_x
-         || s->phys_cursor_y != s->cursor_y
-         || (s->display.x->text_cursor_kind != hollow_box_cursor
-             && (s != x_highlight_screen))))
+         || f->phys_cursor_x != curs_x
+         || f->phys_cursor_y != curs_y
+         || (f->display.x->current_cursor != hollow_box_cursor
+             && (f != x_highlight_frame))))
     {
       /* Erase the cursor by redrawing the character underneath it.  */
-      x_draw_single_glyph (s, s->phys_cursor_y, s->phys_cursor_x,
-                          s->phys_cursor_glyph,
-                          current_glyphs->highlight[s->phys_cursor_y]);
-      s->phys_cursor_x = -1;
+      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 we want to show a cursor,
      or we want a box cursor and it's not so,
      write it in the right place.  */
   if (on
-      && (s->phys_cursor_x < 0
-         || (s->display.x->text_cursor_kind != filled_box_cursor
-             && s == x_highlight_screen)))
+      && (f->phys_cursor_x < 0
+         || (f->display.x->current_cursor != filled_box_cursor
+             && f == x_highlight_frame)))
     {
-      s->phys_cursor_glyph
-       = ((current_glyphs->enable[s->cursor_y]
-           && s->cursor_x < current_glyphs->used[s->cursor_y])
-          ? current_glyphs->glyphs[s->cursor_y][s->cursor_x]
+      f->phys_cursor_glyph
+       = ((current_glyphs->enable[curs_y]
+           && curs_x < current_glyphs->used[curs_y])
+          ? current_glyphs->glyphs[curs_y][curs_x]
           : SPACEGLYPH);
-      if (s != x_highlight_screen)
+      if (f != x_highlight_frame)
        {
-         x_draw_box (s);
-         s->display.x->text_cursor_kind = hollow_box_cursor;
+         x_draw_box (f);
+         f->display.x->current_cursor = hollow_box_cursor;
        }
       else
        {
-         x_draw_single_glyph (s, s->cursor_y, s->cursor_x,
-                              s->phys_cursor_glyph, 2);
-         s->display.x->text_cursor_kind = filled_box_cursor;
+         x_draw_single_glyph (f, curs_y, curs_x,
+                              f->phys_cursor_glyph, 2);
+         f->display.x->current_cursor = filled_box_cursor;
        }
 
-      s->phys_cursor_x = s->cursor_x;
-      s->phys_cursor_y = s->cursor_y;
+      f->phys_cursor_x = curs_x;
+      f->phys_cursor_y = curs_y;
     }
 
-  if (updating_screen != s)
+  if (updating_frame != f)
     XFlushQueue ();
 }
 
-extern Lisp_Object Vbar_cursor;
-
-x_display_cursor (s, on)
-     struct screen *s;
+x_display_cursor (f, on)
+     struct frame *f;
      int on;
 {
-  if (EQ (Vbar_cursor, Qnil))
-    x_display_box_cursor (s, on);
+  if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
+    x_display_box_cursor (f, on);
+  else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
+    x_display_bar_cursor (f, on);
   else
-    x_display_bar_cursor (s, on);
+    /* Those are the only two we have implemented!  */
+    abort ();
 }
 \f
 /* Icons.  */
 
-/* Refresh bitmap kitchen sink icon for screen S
+/* Refresh bitmap kitchen sink icon for frame F
    when we get an expose event for it. */
 
-refreshicon (s)
-     struct screen *s;
+refreshicon (f)
+     struct frame *f;
 {
 #ifdef HAVE_X11
   /* Normally, the window manager handles this function. */
-#else
+#else /* ! defined (HAVE_X11) */
   int mask;
 
-  if (s->display.x->icon_bitmap_flag)
-    XBitmapBitsPut (s->display.x->icon_desc, 0,  0, sink_width, sink_height,
+  if (f->display.x->icon_bitmap_flag)
+    XBitmapBitsPut (f->display.x->icon_desc, 0,  0, sink_width, sink_height,
                    sink_bits, BlackPixel, WHITE_PIX_DEFAULT, 
                    icon_bitmap, GXcopy, AllPlanes);
   else
     {
-      extern struct screen *selected_screen;
+      extern struct frame *selected_frame;
       struct Lisp_String *str;
       unsigned char *string;
 
       string
-       = XSTRING (XBUFFER (XWINDOW (s->selected_window)->buffer)->name)->data;
+       = XSTRING (XBUFFER (XWINDOW (f->selected_window)->buffer)->name)->data;
 
-      if (s->display.x->icon_label != string)
+      if (f->display.x->icon_label != string)
        {
-         s->display.x->icon_label = string;
-         XChangeWindow (s->display.x->icon_desc,
+         f->display.x->icon_label = string;
+         XChangeWindow (f->display.x->icon_desc,
                         XQueryWidth (string, icon_font_info->id) + 10,
                         icon_font_info->height + 10);
        }
 
-      XText (s->display.x->icon_desc, 5, 5, string,
+      XText (f->display.x->icon_desc, 5, 5, string,
             str->size, icon_font_info->id,
             BLACK_PIX_DEFAULT, WHITE_PIX_DEFAULT);
     }
   XFlushQueue ();
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 }
 
-/* Make the x-window of screen S 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 (s)
-     struct screen *s;
+x_bitmap_icon (f)
+     struct frame *f;
 {
   int mask;
   Window icon_window;
 
-  if (s->display.x->window_desc == 0)
+  if (FRAME_X_WINDOW (f) == 0)
     return 1;
 
 #ifdef HAVE_X11
@@ -2677,44 +3468,44 @@ x_bitmap_icon (s)
     XFreePixmap (x_current_display, icon_bitmap);
   
   icon_bitmap =
-    XCreateBitmapFromData (x_current_display, s->display.x->window_desc,
+    XCreateBitmapFromData (x_current_display, FRAME_X_WINDOW (f),
                           gnu_bits, gnu_width, gnu_height);
-  x_wm_set_icon_pixmap (s, icon_bitmap);
-  s->display.x->icon_bitmap_flag = 1;
-#else
-  if (s->display.x->icon_desc)
+  x_wm_set_icon_pixmap (f, icon_bitmap);
+  f->display.x->icon_bitmap_flag = 1;
+#else /* ! defined (HAVE_X11) */
+  if (f->display.x->icon_desc)
     {
-      XClearIconWindow (s->display.x->window_desc);
-      XDestroyWindow (s->display.x->icon_desc);
+      XClearIconWindow (FRAME_X_WINDOW (f));
+      XDestroyWindow (f->display.x->icon_desc);
     }
 
-  icon_window = XCreateWindow (s->display.x->parent_desc,
+  icon_window = XCreateWindow (f->display.x->parent_desc,
                               0, 0, sink_width, sink_height,
                               2, WhitePixmap, (Pixmap) NULL);
 
   if (icon_window == 0)
     return 1;
 
-  XSetIconWindow (s->display.x->window_desc, icon_window);
+  XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
   XSelectInput (icon_window, ExposeWindow | UnmapWindow);
 
-  s->display.x->icon_desc = icon_window;
-  s->display.x->icon_bitmap_flag = 1;
+  f->display.x->icon_desc = icon_window;
+  f->display.x->icon_bitmap_flag = 1;
 
   if (icon_bitmap == 0)
     icon_bitmap
       = XStoreBitmap (sink_mask_width, sink_mask_height, sink_mask_bits);
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
 
   return 0;
 }
 
 
-/* Make the x-window of screen S use a rectangle with text.  */
+/* Make the x-window of frame F use a rectangle with text.  */
 
 int
-x_text_icon (s, icon_name)
-     struct screen *s;
+x_text_icon (f, icon_name)
+     struct frame *f;
      char *icon_name;
 {
 #ifndef HAVE_X11
@@ -2726,260 +3517,196 @@ x_text_icon (s, icon_name)
 
 #ifndef WhitePixel
 #define WhitePixel 1
-#endif
+#endif /* WhitePixel */
 
 #ifndef BlackPixel
 #define BlackPixel 0
-#endif
-#endif /* not HAVE_X11 */
+#endif /* BlackPixel */
+#endif /* HAVE_X11 */
   
-  if (s->display.x->window_desc == 0)
+  if (FRAME_X_WINDOW (f) == 0)
     return 1;
 
+#ifdef HAVE_X11
+  if (icon_name)
+    f->display.x->icon_label = icon_name;
+  else
+    if (! f->display.x->icon_label)
+      f->display.x->icon_label = " *emacs* ";
+  
+  XSetIconName (x_current_display, FRAME_X_WINDOW (f),
+               (char *) f->display.x->icon_label);
+  
+  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 (invocation_name)->data,
                               "BodyFont"));
 
-#ifdef HAVE_X11
-  if (icon_name)
-    s->display.x->icon_label = icon_name;
-  else
-    if (! s->display.x->icon_label)
-      s->display.x->icon_label = " *emacs* ";
-  
-  XSetIconName (x_current_display, s->display.x->window_desc,
-               (char *) s->display.x->icon_label);
-  
-  s->display.x->icon_bitmap_flag = 0;
-#else
-  if (s->display.x->icon_desc)
+  if (f->display.x->icon_desc)
     {
-      XClearIconWindow (XDISPLAY s->display.x->window_desc);
-      XDestroyWindow (XDISPLAY s->display.x->icon_desc);
+      XClearIconWindow (XDISPLAY FRAME_X_WINDOW (f));
+      XDestroyWindow (XDISPLAY f->display.x->icon_desc);
     }
 
   if (icon_name)
-    s->display.x->icon_label = (unsigned char *) icon_name;
+    f->display.x->icon_label = (unsigned char *) icon_name;
   else
-    if (! s->display.x->icon_label)
-      s->display.x->icon_label = XSTRING (s->name)->data;
+    if (! f->display.x->icon_label)
+      f->display.x->icon_label = XSTRING (f->name)->data;
 
-  width = XStringWidth (s->display.x->icon_label, icon_font_info, 0, 0);
-  icon_window = XCreateWindow (s->display.x->parent_desc,
-                              s->display.x->left_pos,
-                              s->display.x->top_pos,
+  width = XStringWidth (f->display.x->icon_label, icon_font_info, 0, 0);
+  icon_window = XCreateWindow (f->display.x->parent_desc,
+                              f->display.x->left_pos,
+                              f->display.x->top_pos,
                               width + 10, icon_font_info->height + 10,
                               2, BlackPixmap, WhitePixmap);
 
   if (icon_window == 0)
     return 1;
 
-  XSetIconWindow (s->display.x->window_desc, icon_window);
+  XSetIconWindow (FRAME_X_WINDOW (f), icon_window);
   XSelectInput (icon_window, ExposeWindow | ExposeRegion | UnmapWindow | ButtonPressed);
 
-  s->display.x->icon_desc = icon_window;
-  s->display.x->icon_bitmap_flag = 0;
-  s->display.x->icon_label = 0;
-#endif /* HAVE_X11 */
+  f->display.x->icon_desc = icon_window;
+  f->display.x->icon_bitmap_flag = 0;
+  f->display.x->icon_label = 0;
+#endif /* ! defined (HAVE_X11) */
 
   return 0;
 }
 \f
-static char *x_proto_requests[] =
-{
-  "CreateWindow",
-  "ChangeWindowAttributes",
-  "GetWindowAttributes",
-  "DestroyWindow",
-  "DestroySubwindows",
-  "ChangeSaveSet",
-  "ReparentWindow",
-  "MapWindow",
-  "MapSubwindows",
-  "UnmapWindow",
-  "UnmapSubwindows",
-  "ConfigureWindow",
-  "CirculateWindow",
-  "GetGeometry",
-  "QueryTree",
-  "InternAtom",
-  "GetAtomName",
-  "ChangeProperty",
-  "DeleteProperty",
-  "GetProperty",
-  "ListProperties",
-  "SetSelectionOwner",
-  "GetSelectionOwner",
-  "ConvertSelection",
-  "SendEvent",
-  "GrabPointer",
-  "UngrabPointer",
-  "GrabButton",
-  "UngrabButton",
-  "ChangeActivePointerGrab",
-  "GrabKeyboard",
-  "UngrabKeyboard",
-  "GrabKey",
-  "UngrabKey",
-  "AllowEvents",
-  "GrabServer",
-  "UngrabServer",
-  "QueryPointer",
-  "GetMotionEvents",
-  "TranslateCoords",
-  "WarpPointer",
-  "SetInputFocus",
-  "GetInputFocus",
-  "QueryKeymap",
-  "OpenFont",
-  "CloseFont",
-  "QueryFont",
-  "QueryTextExtents",
-  "ListFonts",
-  "ListFontsWithInfo",
-  "SetFontPath",
-  "GetFontPath",
-  "CreatePixmap",
-  "FreePixmap",
-  "CreateGC",
-  "ChangeGC",
-  "CopyGC",
-  "SetDashes",
-  "SetClipRectangles",
-  "FreeGC",
-  "ClearArea",
-  "CopyArea",
-  "CopyPlane",
-  "PolyPoint",
-  "PolyLine",
-  "PolySegment",
-  "PolyRectangle",
-  "PolyArc",
-  "FillPoly",
-  "PolyFillRectangle",
-  "PolyFillArc",
-  "PutImage",
-  "GetImage",
-  "PolyText",
-  "PolyText",
-  "ImageText",
-  "ImageText",
-  "CreateColormap",
-  "FreeColormap",
-  "CopyColormapAndFree",
-  "InstallColormap",
-  "UninstallColormap",
-  "ListInstalledColormaps",
-  "AllocColor",
-  "AllocNamedColor",
-  "AllocColorCells",
-  "AllocColorPlanes",
-  "FreeColors",
-  "StoreColors",
-  "StoreNamedColor",
-  "QueryColors",
-  "LookupColor",
-  "CreateCursor",
-  "CreateGlyphCursor",
-  "FreeCursor",
-  "RecolorCursor",
-  "QueryBestSize",
-  "QueryExtension",
-  "ListExtensions",
-  "ChangeKeyboardMapping",
-  "GetKeyboardMapping",
-  "ChangeKeyboardControl",
-  "GetKeyboardControl",
-  "Bell",
-  "ChangePointerControl",
-  "GetPointerControl",
-  "SetScreenSaver",
-  "GetScreenSaver",
-  "ChangeHosts",
-  "ListHosts",
-  "SetAccessControl",
-  "SetCloseDownMode",
-  "KillClient",
-  "RotateProperties",
-  "ForceScreenSaver",
-  "SetPointerMapping",
-  "GetPointerMapping",
-  "SetModifierMapping",
-  "GetModifierMapping",
-  "NoOperation"
-};
-
-#define acceptable_x_error_p(type) ((type) == 94)
-
-x_handle_error_gracefully (event)
-     XErrorEvent *event;
-{
-  char error_ptr[128];
-  char *proto_ptr = x_proto_requests[event->request_code];
-  char str[128];
-
-  XGetErrorText (x_current_display, event->error_code, error_ptr, 128);
-  sprintf (str, "X Protocol Error: %s on request: %s", error_ptr, proto_ptr);
-  TOTALLY_UNBLOCK_INPUT;
-  error (str);
+/* Handling X errors.  */
+
+/* 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 ();
+
+  shut_down_emacs (0);
+
+  exit (70);
 }
 
-#if 0
-extern int x_selection_alloc_error;
-extern int x_converting_selection;
-#endif
+/* 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;
+     XErrorEvent *error;
+{
+  char buf[256];
 
-/* Handle X Errors.  If the error is not traumatic,
-   just call error ().  Otherwise print a (hopefully) interesting
-   message and quit.
+  /* Note that there is no real way portable across R3/R4 to get the 
+     original error handler.  */
 
-   The arg to Fkill_emacs is an exit status value
-   and also prevents any questions.  */
+  XGetErrorText (display, error->error_code, buf, sizeof (buf));
+  fprintf (stderr, "X protocol error: %s on protocol request %d\n",
+          buf, error->request_code);
 
-x_error_handler (disp, event)
-     Display *disp;
-#ifdef HAVE_X11
-     XErrorEvent *event;
+  /* 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 ();
 
-#define XlibDisplayIOError     (1L << 0)
+  x_connection_closed ();
+}
 
-#else
-     struct _XErrorEvent *event;
-#endif
+/* 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;
 {
-  /* Here we use the standard X handlers. */
+  fprintf (stderr, "Connection to X server %s lost.\n",
+          XDisplayName (DisplayString (display)));
 
-  BLOCK_INPUT;
-  if (event && event->type == 0) /* 0 is the XError Event type. */
-    {
-#if 0
-#ifdef HAVE_X11
-      if (event->request_code == BadAlloc && x_converting_selection)
-       x_selection_alloc_error = 1;
-      else
-#endif
-#endif
-      if (acceptable_x_error_p (event->request_code))
-       x_handle_error_gracefully (event);
-      else
-       _XDefaultError (disp, event);
-    }
-  else
+  /* 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 ();
+
+  x_connection_closed ();
+}
+
+/* A buffer for storing X error messages.  */
+static char (*x_caught_error_message)[200];
+
+/* An X error handler which stores the error message in
+   x_caught_error_message.  This is what's installed when
+   x_catch_errors is in effect.  */
+static int
+x_error_catcher (display, error)
+     Display *display;
+     XErrorEvent *error;
+{
+  XGetErrorText (display, error->error_code,
+                *x_caught_error_message, sizeof (*x_caught_error_message));
+}
+
+
+/* Begin trapping X errors.
+
+   After calling this function, X protocol errors no longer cause
+   Emacs to exit; instead, they are recorded in x_cfc_error_message.
+
+   Calling x_check_errors signals an Emacs error if an X error has
+   occurred since the last call to x_catch_errors or x_check_errors.
+
+   Calling x_uncatch_errors resumes the normal error handling.  */
+
+void x_catch_errors(), x_check_errors (), x_uncatch_errors ();
+
+void
+x_catch_errors ()
+{
+  /* Make sure any errors from previous requests have been dealt with.  */
+  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';
+
+  /* Install our little error handler.  */
+  XHandleError (x_error_catcher);
+}
+
+/* If any X protocol errors have arrived since the last call to
+   x_catch_errors or x_check_errors, signal an Emacs error using
+   sprintf (a buffer, FORMAT, the x error message text) as the text.  */
+void
+x_check_errors (format)
+     char *format;
+{
+  /* Make sure to catch any errors incurred so far.  */
+  XSync (x_current_display, False);
+
+  if ((*x_caught_error_message)[0])
     {
-      disp->flags |= XlibDisplayIOError;
-      _XDefaultIOError (disp);
-    }
-  UNBLOCK_INPUT;
+      char buf[256];
 
-  if (_Xdebug)
-    abort ();
-  else
-    Fkill_emacs (make_number (70));
+      sprintf (buf, format, *x_caught_error_message);
+      free (x_caught_error_message);
+
+      x_uncatch_errors ();
+      error (buf);
+    }
 }
 
-/* Initialize communication with the X window server.  */
+void
+x_uncatch_errors ()
+{
+  free (x_caught_error_message);
+  XHandleError (x_error_quitter);
+}
 
 #if 0
 static unsigned int x_wire_count;
@@ -2987,12 +3714,14 @@ x_trace_wire ()
 {
   fprintf (stderr, "Lib call: %d\n", ++x_wire_count);
 }
-#endif
+#endif /* ! 0 */
 
 \f
-/* Set the font of the x-window specified by screen S
+/* Changing the font of the frame.  */
+
+/* Set the font of the x-window specified by frame F
    to the font named NEWNAME.  This is safe to use
-   even before S has an actual x-window.  */
+   even before F has an actual x-window.  */
 
 #ifdef HAVE_X11
 
@@ -3007,8 +3736,8 @@ static int x_font_table_size;
    0 <= n_fonts <= x_font_table_size.  */
 static int n_fonts;
 
-x_new_font (s, fontname)
-     struct screen *s;
+x_new_font (f, fontname)
+     struct frame *f;
      register char *fontname;
 {
   XFontStruct *temp;
@@ -3045,7 +3774,7 @@ x_new_font (s, fontname)
   
   /* If we have, just return it from the table.  */
   if (already_loaded)
-    s->display.x->font = x_font_table[already_loaded];
+    f->display.x->font = x_font_table[already_loaded];
   
   /* Otherwise, load the font and add it to the table.  */
   else
@@ -3074,31 +3803,31 @@ x_new_font (s, fontname)
                                          * sizeof (x_font_table[0])));
        }
 
-      s->display.x->font = x_font_table[n_fonts++] = font;
+      f->display.x->font = x_font_table[n_fonts++] = 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 screen display the given font.  */
-  if (s->display.x->window_desc != 0)
+  /* Now make the frame display the given font.  */
+  if (FRAME_X_WINDOW (f) != 0)
     {
-      XSetFont (x_current_display, s->display.x->normal_gc,
-               s->display.x->font->fid);
-      XSetFont (x_current_display, s->display.x->reverse_gc,
-               s->display.x->font->fid);
-      XSetFont (x_current_display, s->display.x->cursor_gc,
-               s->display.x->font->fid);
-
-      x_set_window_size (s, s->width, s->height);
+      XSetFont (x_current_display, f->display.x->normal_gc,
+               f->display.x->font->fid);
+      XSetFont (x_current_display, f->display.x->reverse_gc,
+               f->display.x->font->fid);
+      XSetFont (x_current_display, f->display.x->cursor_gc,
+               f->display.x->font->fid);
+
+      x_set_window_size (f, f->width, f->height);
     }
 
   return 0;
 }
-#else
-x_new_font (s, newname)
-     struct screen *s;
+#else /* ! defined (HAVE_X11) */
+x_new_font (f, newname)
+     struct frame *f;
      register char *newname;
 {
   FONT_TYPE *temp;
@@ -3108,222 +3837,247 @@ x_new_font (s, newname)
   if (temp == (FONT_TYPE *) 0)
     return 1;
 
-  if (s->display.x->font)
-    XLoseFont (s->display.x->font);
+  if (f->display.x->font)
+    XLoseFont (f->display.x->font);
 
-  s->display.x->font = temp;
+  f->display.x->font = temp;
 
-  if (s->display.x->window_desc != 0)
-    x_set_window_size (s, s->width, s->height);
+  if (FRAME_X_WINDOW (f) != 0)
+    x_set_window_size (f, f->width, f->height);
 
   return 0;
 }
-#endif
+#endif /* ! defined (HAVE_X11) */
 \f
-x_calc_absolute_position (s)
-     struct screen *s;
+/* X Window sizes and positions.  */
+
+x_calc_absolute_position (f)
+     struct frame *f;
 {
 #ifdef HAVE_X11
-  if (s->display.x->left_pos < 0)
-    s->display.x->left_pos
-      = XINT (x_screen_width) - PIXEL_WIDTH (s) + s->display.x->left_pos;
-
-  if (s->display.x->top_pos < 0)
-    s->display.x->top_pos
-      = XINT (x_screen_height) - PIXEL_HEIGHT (s) + s->display.x->top_pos;
-#else /* X10 */
+  if (f->display.x->left_pos < 0)
+    f->display.x->left_pos
+      = x_screen_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;
+#else /* ! defined (HAVE_X11) */
   WINDOWINFO_TYPE parentinfo;
 
-  XGetWindowInfo (s->display.x->window_desc, &parentinfo);
+  XGetWindowInfo (FRAME_X_WINDOW (f), &parentinfo);
 
-  if (s->display.x->left_pos < 0)
-    s->display.x->left_pos = parentinfo.width + (s->display.x->left_pos + 1)
-      - PIXEL_WIDTH (s) - 2 * s->display.x->internal_border_width;
+  if (f->display.x->left_pos < 0)
+    f->display.x->left_pos = parentinfo.width + (f->display.x->left_pos + 1)
+      - PIXEL_WIDTH (f) - 2 * f->display.x->internal_border_width;
 
-  if (s->display.x->top_pos < 0)
-    s->display.x->top_pos = parentinfo.height + (s->display.x->top_pos + 1)
-      - PIXEL_HEIGHT (s) - 2 * s->display.x->internal_border_width;
-#endif /* X10 */
+  if (f->display.x->top_pos < 0)
+    f->display.x->top_pos = parentinfo.height + (f->display.x->top_pos + 1)
+      - PIXEL_HEIGHT (f) - 2 * f->display.x->internal_border_width;
+#endif /* ! defined (HAVE_X11) */
 }
 
-x_set_offset (s, xoff, yoff)
-     struct screen *s;
+x_set_offset (f, xoff, yoff)
+     struct frame *f;
      register int xoff, yoff;
 {
-  s->display.x->top_pos = yoff;
-  s->display.x->left_pos = xoff;
-  x_calc_absolute_position (s);
+  f->display.x->top_pos = yoff;
+  f->display.x->left_pos = xoff;
+  x_calc_absolute_position (f);
 
   BLOCK_INPUT;
-  XMoveWindow (XDISPLAY s->display.x->window_desc,
-              s->display.x->left_pos, s->display.x->top_pos);
+  XMoveWindow (XDISPLAY FRAME_X_WINDOW (f),
+              f->display.x->left_pos, f->display.x->top_pos);
 #ifdef HAVE_X11
-  x_wm_set_size_hint (s, 0);
-#endif
+  x_wm_set_size_hint (f, 0);
+#endif /* ! defined (HAVE_X11) */
   UNBLOCK_INPUT;
 }
 
-/* Call this to change the size of screen S's x-window. */
+/* Call this to change the size of frame F's x-window. */
 
-x_set_window_size (s, cols, rows)
-     struct screen *s;
-     register int cols, rows;
+x_set_window_size (f, cols, rows)
+     struct frame *f;
+     int cols, rows;
 {
   int pixelwidth, pixelheight;
   int mask;
-  int ibw = s->display.x->internal_border_width;
 
   BLOCK_INPUT;
 
-  /* ??? Who DOES worry about minimum reasonable sizes?  */
-  pixelwidth =  (cols * FONT_WIDTH (s->display.x->font) + 2 * ibw
-                + s->display.x->v_scrollbar_width);
-  pixelheight = (rows * FONT_HEIGHT (s->display.x->font) + 2 * ibw
-                + s->display.x->h_scrollbar_height);
+  check_frame_size (f, &rows, &cols);
+  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);
 
 #ifdef HAVE_X11
-  x_wm_set_size_hint (s, 0);
-#endif /* HAVE_X11 */
-  XChangeWindowSize (s->display.x->window_desc, pixelwidth, pixelheight);
+  x_wm_set_size_hint (f, 0);
+#endif /* ! defined (HAVE_X11) */
+  XChangeWindowSize (FRAME_X_WINDOW (f), pixelwidth, pixelheight);
+
+  /* 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.
+
+     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;
 }
 
 #ifndef HAVE_X11
-x_set_resize_hint (s)
-     struct screen *s;
+x_set_resize_hint (f)
+     struct frame *f;
 {
-
-  XSetResizeHint (s->display.x->window_desc, 2 * s->display.x->internal_border_width,
-                 2 * s->display.x->internal_border_width,
-                 FONT_WIDTH (s->display.x->font), FONT_HEIGHT (s->display.x->font));
+  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));
 }
-#endif /* not HAVE_X11 */
+#endif /* HAVE_X11 */
 \f
+/* Mouse warping, focus shifting, raising and lowering.  */
 
-x_set_mouse_position (s, x, y)
-     struct screen *s;
+x_set_mouse_position (f, x, y)
+     struct frame *f;
      int x, y;
 {
   int pix_x, pix_y;
 
-  x_raise_screen (s);
+  x_raise_frame (f);
 
-  if (x < 0)
-    pix_x = (SCREEN_WIDTH (s)
-             * FONT_WIDTH (s->display.x->font)
-             + 2 * s->display.x->internal_border_width
-             + s->display.x->v_scrollbar_width) / 2;
-  else
-    pix_x = x * FONT_WIDTH (s->display.x->font) + 2; /* add 2 pixels to each
-                                                        dimension to move the
-                                                        mouse into the char
-                                                        cell */
-
-  if (y < 0)
-    pix_y = (SCREEN_HEIGHT (s)
-             * FONT_HEIGHT (s->display.x->font)
-             + 2 * s->display.x->internal_border_width
-             + s->display.x->h_scrollbar_height) / 2;
-  else
-    pix_y = y * FONT_HEIGHT (s->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);
+
+  if (pix_y < 0) pix_y = 0;
+  if (pix_y > PIXEL_HEIGHT (f)) pix_y = PIXEL_HEIGHT (f);
 
   BLOCK_INPUT;
-  x_mouse_x = x;
-  x_mouse_y = y;
 
-  XWarpMousePointer (s->display.x->window_desc, pix_x, pix_y);
+  XWarpMousePointer (FRAME_X_WINDOW (f), pix_x, pix_y);
   UNBLOCK_INPUT;
 }
 
 #ifdef HAVE_X11
-x_focus_on_screen (s)
-     struct screen *s;
+x_focus_on_frame (f)
+     struct frame *f;
 {
-  x_raise_screen (s);
+  x_raise_frame (f);
 #if 0
   /* I don't think that the ICCCM allows programs to do things like this
      without the interaction of the window manager.  Whatever you end up
-     doing with this code, do it to x_unfocus_screen too.  */
-  XSetInputFocus (x_current_display, s->display.x->window_desc,
+     doing with this code, do it to x_unfocus_frame too.  */
+  XSetInputFocus (x_current_display, FRAME_X_WINDOW (f),
                  RevertToPointerRoot, CurrentTime);
-#endif
+#endif /* ! 0 */
 }
 
-x_unfocus_screen (s)
-     struct screen *s;
+x_unfocus_frame (f)
+     struct frame *f;
 {
 #if 0
-  /* Look at the remarks in x_focus_on_screen.  */
-  if (x_focus_screen == s)
+  /* Look at the remarks in x_focus_on_frame.  */
+  if (x_focus_frame == f)
     XSetInputFocus (x_current_display, PointerRoot,
                    RevertToPointerRoot, CurrentTime);
-#endif
+#endif /* ! 0 */
 }
 
-#endif
+#endif /* ! defined (HAVE_X11) */
 
-/* Raise screen S.  */
+/* Raise frame F.  */
 
-x_raise_screen (s)
-     struct screen *s;
+x_raise_frame (f)
+     struct frame *f;
 {
-  if (s->visible)
+  if (f->async_visible)
     {
       BLOCK_INPUT;
-      XRaiseWindow (XDISPLAY s->display.x->window_desc);
+      XRaiseWindow (XDISPLAY FRAME_X_WINDOW (f));
       XFlushQueue ();
       UNBLOCK_INPUT;
     }
 }
 
-/* Lower screen S.  */
+/* Lower frame F.  */
 
-x_lower_screen (s)
-     struct screen *s;
+x_lower_frame (f)
+     struct frame *f;
 {
-  if (s->visible)
+  if (f->async_visible)
     {
       BLOCK_INPUT;
-      XLowerWindow (XDISPLAY s->display.x->window_desc);
+      XLowerWindow (XDISPLAY FRAME_X_WINDOW (f));
       XFlushQueue ();
       UNBLOCK_INPUT;
     }
 }
 
+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_screen_visible (s)
-     struct screen *s;
+x_make_frame_visible (f)
+     struct frame *f;
 {
   int mask;
 
   BLOCK_INPUT;
 
-  if (! SCREEN_VISIBLE_P (s))
+  if (! FRAME_VISIBLE_P (f))
     {
 #ifdef HAVE_X11
       if (! EQ (Vx_no_window_manager, Qt))
-       x_wm_set_window_state (s, NormalState);
+       x_wm_set_window_state (f, NormalState);
 
-      XMapWindow (XDISPLAY s->display.x->window_desc);
-      if (s->display.x->v_scrollbar != 0 || s->display.x->h_scrollbar != 0)
-       XMapSubwindows (x_current_display, s->display.x->window_desc);
-#else
-      XMapWindow (XDISPLAY s->display.x->window_desc);
-      if (s->display.x->icon_desc != 0)
-       XUnmapWindow (s->display.x->icon_desc);
+      XMapWindow (XDISPLAY FRAME_X_WINDOW (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));
+      if (f->display.x->icon_desc != 0)
+       XUnmapWindow (f->display.x->icon_desc);
 
       /* Handled by the MapNotify event for X11 */
-      s->visible = 1;
-      s->iconified = 0;
+      f->async_visible = 1;
+      f->async_iconified = 0;
 
-      /* NOTE: this may cause problems for the first screen. */
+      /* NOTE: this may cause problems for the first frame. */
       XTcursor_to (0, 0);
-#endif                         /* not HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
     }
 
-  XRaiseWindow (XDISPLAY s->display.x->window_desc);
   XFlushQueue ();
 
   UNBLOCK_INPUT;
@@ -3331,142 +4085,150 @@ x_make_screen_visible (s)
 
 /* Change from mapped state to withdrawn state. */
 
-x_make_screen_invisible (s)
-     struct screen *s;
+x_make_frame_invisible (f)
+     struct frame *f;
 {
   int mask;
 
-  if (! s->visible)
+  if (! f->async_visible)
     return;
 
   BLOCK_INPUT;
-#ifdef HAVE_X11
-#if 0
-  if (! EQ (Vx_no_window_manager, Qt))
-    {
-      XUnmapEvent unmap;
-
-      unmap.type = UnmapNotify;
-      unmap.window = s->display.x->window_desc;
-      unmap.event = DefaultRootWindow (x_current_display);
-      unmap.from_configure = False;
-      XSendEvent (x_current_display, DefaultRootWindow (x_current_display),
-                 False, SubstructureRedirectMask|SubstructureNotifyMask,
-                 &unmap);
-    }
 
-  /* The new function below does the same as the above code, plus unmapping
-     the window.  Sending the event without actually unmapping can make
-     the window manager start ignoring the window (i.e., no more title bar,
-     icon manager stuff.) */
-#endif
+#ifdef HAVE_X11R4
 
-  /* New function available with R4 */
-  if (! XWithdrawWindow (x_current_display, s->display.x->window_desc,
+  if (! XWithdrawWindow (x_current_display, FRAME_X_WINDOW (f),
                         DefaultScreen (x_current_display)))
     {
       UNBLOCK_INPUT_RESIGNAL;
-      error ("Can't notify window manager of iconification.");
+      error ("can't notify window manager of window withdrawl");
     }
 
-#else
-  XUnmapWindow (XDISPLAY s->display.x->window_desc);
+#else /* ! defined (HAVE_X11R4) */
+#ifdef HAVE_X11
+
+  /*  Tell the window manager what we're going to do.  */
+  if (! EQ (Vx_no_window_manager, Qt))
+    {
+      XEvent unmap;
+
+      unmap.xunmap.type = UnmapNotify;
+      unmap.xunmap.window = FRAME_X_WINDOW (f);
+      unmap.xunmap.event = DefaultRootWindow (x_current_display);
+      unmap.xunmap.from_configure = False;
+      if (! XSendEvent (x_current_display,
+                       DefaultRootWindow (x_current_display),
+                       False,
+                       SubstructureRedirectMask|SubstructureNotifyMask,
+                       &unmap))
+       {
+         UNBLOCK_INPUT_RESIGNAL;
+         error ("can't notify window manager of withdrawal");
+       }
+    }
 
-  s->visible = 0;              /* Handled by the UnMap event for X11 */
-  if (s->display.x->icon_desc != 0)
-    XUnmapWindow (XDISPLAY s->display.x->icon_desc);
-#endif /* not HAVE_X11 */
+  /* Unmap the window ourselves.  Cheeky!  */
+  XUnmapWindow (x_current_display, FRAME_X_WINDOW (f));
+
+#else /* ! defined (HAVE_X11) */
+
+  XUnmapWindow (FRAME_X_WINDOW (f));
+  f->async_visible = 0;                /* Handled by the UnMap event for X11 */
+  if (f->display.x->icon_desc != 0)
+    XUnmapWindow (f->display.x->icon_desc);
+
+#endif /* ! defined (HAVE_X11) */
+#endif /* ! defined (HAVE_X11R4) */
 
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
 
- /* Window manager communication.  Created in Fx_open_connection. */
+/* Window manager communication.  Created in Fx_open_connection. */
 extern Atom Xatom_wm_change_state;
 
 /* Change window state from mapped to iconified. */
 
-x_iconify_screen (s)
-     struct screen *s;
+x_iconify_frame (f)
+     struct frame *f;
 {
   int mask;
 
-  if (s->iconified)
+  if (f->async_iconified)
     return;
 
   BLOCK_INPUT;
 
 #ifdef HAVE_X11
-  if (! EQ (Vx_no_window_manager, Qt))
-    if (! XIconifyWindow (x_current_display, s->display.x->window_desc,
-                         DefaultScreen (x_current_display)))
+  /* Since we don't know which revision of X we're running, we'll use both
+     the X11R3 and X11R4 techniques.  I don't know if this is a good idea.  */
+
+  /* X11R4: send a ClientMessage to the window manager using the
+     WM_CHANGE_STATE type.  */
+  {
+    XEvent message;
+    
+    message.xclient.window = FRAME_X_WINDOW (f);
+    message.xclient.type = ClientMessage;
+    message.xclient.message_type = Xatom_wm_change_state;
+    message.xclient.format = 32;
+    message.xclient.data.l[0] = IconicState;
+
+    if (! XSendEvent (x_current_display,
+                     DefaultRootWindow (x_current_display),
+                     False,
+                     SubstructureRedirectMask | SubstructureNotifyMask,
+                     &message))
       {
        UNBLOCK_INPUT_RESIGNAL;
        error ("Can't notify window manager of iconification.");
       }
+  }
 
-  s->iconified = 1;
-  
-#if 0
-    {
-      XClientMessageEvent message;
-    
-      message.window = s->display.x->window_desc;
-      message.type = ClientMessage;
-      message.message_type = Xatom_wm_change_state;
-      message.format = 32;
-      message.data.l[0] = IconicState;
+  /* X11R3: set the initial_state field of the window manager hints to 
+     IconicState.  */
+  x_wm_set_window_state (f, IconicState);
 
-      if (! XSendEvent (x_current_display,
-                       DefaultRootWindow (x_current_display),
-                       False,
-                       SubstructureRedirectMask | SubstructureNotifyMask,
-                       &message))
-       {
-         UNBLOCK_INPUT_RESIGNAL;
-         error ("Can't notify window manager of iconification.");
-       }
-    }
-#endif
-#else /* X10 */
-  XUnmapWindow (XDISPLAY s->display.x->window_desc);
+  f->async_iconified = 1;
+#else /* ! defined (HAVE_X11) */
+  XUnmapWindow (XDISPLAY FRAME_X_WINDOW (f));
 
-  s->visible = 0;              /* Handled in the UnMap event for X11. */
-  if (s->display.x->icon_desc != 0)
+  f->async_visible = 0;                /* Handled in the UnMap event for X11. */
+  if (f->display.x->icon_desc != 0)
     {
-      XMapWindow (XDISPLAY s->display.x->icon_desc);
-      refreshicon (s);
+      XMapWindow (XDISPLAY f->display.x->icon_desc);
+      refreshicon (f);
     }
-#endif /* X10 */
+#endif /* ! defined (HAVE_X11) */
 
   XFlushQueue ();
   UNBLOCK_INPUT;
 }
 
-/* Destroy the X window of screen S.
-   DISPL is the former s->display (since s->display
-   has already been nulled out).  */
+/* Destroy the X window of frame F.  */
 
-x_destroy_window (s, displ)
-     struct screen *s;
-     union display displ;
+x_destroy_window (f)
+     struct frame *f;
 {
-  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);
   XFlushQueue ();
-  UNBLOCK_INPUT;
 
-  free (displ.x);
-  if (s == x_focus_screen)
-    x_focus_screen = 0;
-  if (s == x_highlight_screen)
-    x_highlight_screen = 0;
+  free (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.  */
+
 #ifndef HAVE_X11
 
 /* Manage event queues.
@@ -3537,39 +4299,65 @@ mouse_event_pending_p ()
 {
   return queue_event_count (&x_mouse_queue);
 }
-#endif
+#endif /* HAVE_X11 */
 \f
+/* Setting window manager hints.  */
+
 #ifdef HAVE_X11
 
-x_wm_set_size_hint (s, prompting)
-     struct screen *s;
+x_wm_set_size_hint (f, prompting)
+     struct frame *f;
      long prompting;
 {
   XSizeHints size_hints;
-  Window window = s->display.x->window_desc;
+  Window window = FRAME_X_WINDOW (f);
 
   size_hints.flags = PResizeInc | PMinSize | PMaxSize;
 
-  flexlines = s->height;
-
-  size_hints.x = s->display.x->left_pos;
-  size_hints.y = s->display.x->top_pos;
-  size_hints.height = PIXEL_HEIGHT (s);
-  size_hints.width = PIXEL_WIDTH (s);
-  size_hints.width_inc = FONT_WIDTH (s->display.x->font);
-  size_hints.height_inc = FONT_HEIGHT (s->display.x->font);
-  size_hints.base_width = (2 * s->display.x->internal_border_width)
-    + s->display.x->v_scrollbar_width;
-  size_hints.base_height = (2 * s->display.x->internal_border_width)
-    + s->display.x->h_scrollbar_height;
-  size_hints.min_width = size_hints.base_width + size_hints.width_inc;
-  size_hints.min_height = size_hints.base_height + size_hints.height_inc;
-  size_hints.max_width = x_screen_width
-    - ((2 * s->display.x->internal_border_width)
-       + s->display.x->v_scrollbar_width);
-  size_hints.max_height = x_screen_height
-    - ((2 * s->display.x->internal_border_width)
-       + s->display.x->h_scrollbar_height);
+  flexlines = f->height;
+
+  size_hints.x = f->display.x->left_pos;
+  size_hints.y = f->display.x->top_pos;
+  size_hints.height = PIXEL_HEIGHT (f);
+  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 = x_screen_width - CHAR_TO_PIXEL_WIDTH (f, 0);
+  size_hints.max_height = x_screen_height - CHAR_TO_PIXEL_HEIGHT (f, 0);
+    
+  {
+    int base_width, base_height;
+
+    base_width = CHAR_TO_PIXEL_WIDTH (f, 0);
+    base_height = CHAR_TO_PIXEL_HEIGHT (f, 0);
+
+    {
+      int min_rows = 0, min_cols = 0;
+      check_frame_size (f, &min_rows, &min_cols);
+
+      /* The window manager uses the base width hints to calculate the
+        current number of rows and columns in the frame while
+        resizing; min_width and min_height aren't useful for this
+        purpose, since they might not give the dimensions for a
+        zero-row, zero-column frame.
+
+        We use the base_width and base_height members if we have
+        them; otherwise, we set the min_width and min_height members
+        to the size for a zero x zero frame.  */
+
+#ifdef HAVE_X11R4
+      size_hints.flags |= PBaseSize;
+      size_hints.base_width = base_width;
+      size_hints.base_height = base_height;
+      size_hints.min_width  = base_width + min_cols * size_hints.width_inc;
+      size_hints.min_height = base_height + min_rows * size_hints.height_inc;
+#else
+      size_hints.min_width = base_width;
+      size_hints.min_height = base_height;
+#endif
+    }
+
+  }
 
   if (prompting)
     size_hints.flags |= prompting;
@@ -3587,63 +4375,71 @@ x_wm_set_size_hint (s, prompting)
       if (hints.flags & USSize)
        size_hints.flags |= USSize;
     }
-  
-#if 0                          /* R3 */
+
+#ifdef HAVE_X11R4
+  XSetWMNormalHints (x_current_display, window, &size_hints);
+#else
   XSetNormalHints (x_current_display, window, &size_hints);
 #endif
-  XSetWMNormalHints (x_current_display, window, &size_hints);
 }
 
 /* Used for IconicState or NormalState */
-x_wm_set_window_state (s, state)
-     struct screen *s;
+x_wm_set_window_state (f, state)
+     struct frame *f;
      int state;
 {
-  XWMHints wm_hints;
-  Window window = s->display.x->window_desc;
+  Window window = FRAME_X_WINDOW (f);
 
-  wm_hints.flags = StateHint;
-  wm_hints.initial_state = state;
-  XSetWMHints (x_current_display, window, &wm_hints);
+  f->display.x->wm_hints.flags |= StateHint;
+  f->display.x->wm_hints.initial_state = state;
+
+  XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
 }
 
-x_wm_set_icon_pixmap (s, icon_pixmap)
-     struct screen *s;
+x_wm_set_icon_pixmap (f, icon_pixmap)
+     struct frame *f;
      Pixmap icon_pixmap;
 {
-  XWMHints wm_hints;
-  Window window = s->display.x->window_desc;
+  Window window = FRAME_X_WINDOW (f);
+
+  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;
 
-  wm_hints.flags = IconPixmapHint;
-  wm_hints.icon_pixmap = icon_pixmap;
-  XSetWMHints (x_current_display, window, &wm_hints);
+  XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
 }
 
-x_wm_set_icon_position (s, icon_x, icon_y)
-     struct screen *s;
+x_wm_set_icon_position (f, icon_x, icon_y)
+     struct frame *f;
      int icon_x, icon_y;
 {
-  XWMHints wm_hints;
-  Window window = s->display.x->window_desc;
+  Window window = FRAME_X_WINDOW (f);
+
+  f->display.x->wm_hints.flags |= IconPositionHint;
+  f->display.x->wm_hints.icon_x = icon_x;
+  f->display.x->wm_hints.icon_y = icon_y;
 
-  wm_hints.flags = IconPositionHint;
-  wm_hints.icon_x = icon_x;
-  wm_hints.icon_y = icon_y;
-  XSetWMHints (x_current_display, window, &wm_hints);
+  XSetWMHints (x_current_display, window, &f->display.x->wm_hints);
 }
 
 \f
+/* Initialization.  */
+
 void
 x_term_init (display_name)
      char *display_name;
 {
-  Lisp_Object screen;
+  Lisp_Object frame;
   char *defaultvalue;
 #ifdef F_SETOWN
   extern int old_fcntl_owner;
-#endif
+#endif /* ! defined (F_SETOWN) */
   
-  x_focus_screen = x_highlight_screen = 0;
+  x_focus_frame = x_highlight_frame = 0;
 
   x_current_display = XOpenDisplay (display_name);
   if (x_current_display == 0)
@@ -3652,13 +4448,13 @@ x_term_init (display_name)
 
 #ifdef HAVE_X11
   {
-    int hostname_size = MAXHOSTNAMELEN + 1;
+    int hostname_size = 256;
 
     hostname = (char *) xmalloc (hostname_size);
 
 #if 0
     XSetAfterFunction (x_current_display, x_trace_wire);
-#endif
+#endif /* ! 0 */
 
     invocation_name = Ffile_name_nondirectory (Fcar (Vcommand_line_args));
 
@@ -3683,7 +4479,18 @@ x_term_init (display_name)
                                + 2);
     sprintf (x_id_name, "%s@%s", XSTRING (invocation_name)->data, hostname);
   }
-  
+
+  /* Figure out which modifier bits mean what.  */
+  x_find_modifier_meanings ();
+
+  /* Get the scroll bar cursor.  */
+  x_vertical_scroll_bar_cursor =
+    XCreateFontCursor (x_current_display, XC_sb_v_double_arrow);
+
+  /* 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 ();
+
   dup2 (ConnectionNumber (x_current_display), 0);
 
 #ifndef SYSV_STREAMS
@@ -3694,22 +4501,22 @@ x_term_init (display_name)
   ConnectionNumber (x_current_display) = 0;    /* Looks a little strange?
                                                 * check the def of the macro;
                                                 * it is a genuine lvalue */
-#endif /* not SYSV_STREAMS */
+#endif /* SYSV_STREAMS */
 
-#endif /* HAVE_X11 */
+#endif /* ! defined (HAVE_X11) */
   
 #ifdef F_SETOWN
   old_fcntl_owner = fcntl (0, F_GETOWN, 0);
 #ifdef F_SETOWN_SOCK_NEG
   fcntl (0, F_SETOWN, -getpid ());     /* stdin is a socket here */
-#else
+#else /* ! defined (F_SETOWN_SOCK_NEG) */
   fcntl (0, F_SETOWN, getpid ());
-#endif /* F_SETOWN_SOCK_NEG */
-#endif /* F_SETOWN */
+#endif /* ! defined (F_SETOWN_SOCK_NEG) */
+#endif /* ! defined (F_SETOWN) */
 
 #ifdef SIGIO
   init_sigio ();
-#endif
+#endif /* ! defined (SIGIO) */
 
   /* Must use interrupt input because we cannot otherwise
      arrange for C-g to be noticed immediately.
@@ -3718,7 +4525,7 @@ x_term_init (display_name)
 
   expose_all_windows = 0;
 
-  clear_screen_hook = XTclear_screen;
+  clear_frame_hook = XTclear_frame;
   clear_end_of_line_hook = XTclear_end_of_line;
   ins_del_lines_hook = XTins_del_lines;
   change_line_highlight_hook = XTchange_line_highlight;
@@ -3734,26 +4541,33 @@ x_term_init (display_name)
   read_socket_hook = XTread_socket;
   cursor_to_hook = XTcursor_to;
   reassert_line_highlight_hook = XTreassert_line_highlight;
-  screen_rehighlight_hook = XTscreen_rehighlight;
   mouse_position_hook = XTmouse_position;
+  frame_rehighlight_hook = XTframe_rehighlight;
+  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 screens */
+  scroll_region_ok = 1;                /* we'll scroll partial frames */
   char_ins_del_ok = 0;         /* just as fast to write the line */
   line_ins_del_ok = 1;         /* we'll just blt 'em */
   fast_clear_end_of_line = 1;  /* X does this well */
-  memory_below_screen = 0;     /* we don't remember what scrolls 
+  memory_below_frame = 0;      /* we don't remember what scrolls 
                                   off the bottom */
   baud_rate = 19200;
 
-  XHandleError (x_error_handler);
-  XHandleIOError (x_error_handler);
+  /* Note that there is no real way portable across R3/R4 to get the 
+     original error handler.  */
+  XHandleError (x_error_quitter);
+  XHandleIOError (x_io_error_quitter);
 
   /* Disable Window Change signals;  they are handled by X events. */
 #ifdef SIGWINCH
   signal (SIGWINCH, SIG_DFL);
-#endif /* SIGWINCH */
+#endif /* ! defined (SIGWINCH) */
 
-  signal (SIGPIPE, x_error_handler);
+  signal (SIGPIPE, x_connection_closed);
 }
 
 void
@@ -3762,9 +4576,7 @@ syms_of_xterm ()
   staticpro (&invocation_name);
   invocation_name = Qnil;
 
-  Qmouse_moved = intern ("mouse-moved");
-  Qmouse_click = intern ("mouse-click");
-  Qscrollbar_click = intern ("scrollbar-click");
+  staticpro (&last_mouse_scroll_bar);
 }
-#endif /* HAVE_X11 */
-#endif /* HAVE_X_WINDOWS */
+#endif /* ! defined (HAVE_X11) */
+#endif /* ! defined (HAVE_X_WINDOWS) */