]> code.delx.au - gnu-emacs/blobdiff - src/dispnew.c
(direct_output_for_insert, direct_output_forward_char): Fix Lisp_Object
[gnu-emacs] / src / dispnew.c
index 3aec0bd61d241b51f0e5391b4d3ba95b8f302504..0faabda929867940fe5a55a44ed269a583b0cf7c 100644 (file)
@@ -1,12 +1,11 @@
 /* Updating of data structures for redisplay.
 /* Updating of data structures for redisplay.
-   Copyright (C) 1985, 1986, 1987, 1988, 1990,
-   1992 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94 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
 
 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,
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -21,14 +20,16 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <signal.h>
 
 
 #include <signal.h>
 
-#include "config.h"
+#include <config.h>
+
 #include <stdio.h>
 #include <ctype.h>
 
 #include <stdio.h>
 #include <ctype.h>
 
+#include "lisp.h"
 #include "termchar.h"
 #include "termopts.h"
 #include "termchar.h"
 #include "termopts.h"
+#include "termhooks.h"
 #include "cm.h"
 #include "cm.h"
-#include "lisp.h"
 #include "dispextern.h"
 #include "buffer.h"
 #include "frame.h"
 #include "dispextern.h"
 #include "buffer.h"
 #include "frame.h"
@@ -36,23 +37,40 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "commands.h"
 #include "disptab.h"
 #include "indent.h"
 #include "commands.h"
 #include "disptab.h"
 #include "indent.h"
+#include "intervals.h"
 
 #include "systty.h"
 
 #include "systty.h"
-#include "systime.h"
 
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #endif /* HAVE_X_WINDOWS */
 
 
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #endif /* HAVE_X_WINDOWS */
 
+/* Include systime.h after xterm.h to avoid double inclusion of time.h. */
+#include "systime.h"
+
+#include <errno.h>
+
 #define max(a, b) ((a) > (b) ? (a) : (b))
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
 #define max(a, b) ((a) > (b) ? (a) : (b))
 #define min(a, b) ((a) < (b) ? (a) : (b))
 
-#ifndef PENDING_OUTPUT_COUNT
 /* Get number of chars of output now in the buffer of a stdio stream.
    This ought to be built in in stdio, but it isn't.
    Some s- files override this because their stdio internals differ.  */
 /* Get number of chars of output now in the buffer of a stdio stream.
    This ought to be built in in stdio, but it isn't.
    Some s- files override this because their stdio internals differ.  */
+#ifdef __GNU_LIBRARY__
+/* The s- file might have overridden the definition with one that works for
+   the system's C library.  But we are using the GNU C library, so this is
+   the right definition for every system.  */
+#ifdef GNU_LIBRARY_PENDING_OUTPUT_COUNT
+#define PENDING_OUTPUT_COUNT GNU_LIBRARY_PENDING_OUTPUT_COUNT
+#else
+#undef PENDING_OUTPUT_COUNT
+#define        PENDING_OUTPUT_COUNT(FILE) ((FILE)->__bufp - (FILE)->__buffer)
+#endif
+#else /* not __GNU_LIBRARY__ */
+#ifndef PENDING_OUTPUT_COUNT
 #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
 #endif
 #define PENDING_OUTPUT_COUNT(FILE) ((FILE)->_ptr - (FILE)->_base)
 #endif
+#endif
 
 /* Nonzero upon entry to redisplay means do not assume anything about
    current contents of actual terminal frame; clear and redraw it.  */
 
 /* Nonzero upon entry to redisplay means do not assume anything about
    current contents of actual terminal frame; clear and redraw it.  */
@@ -116,7 +134,7 @@ FRAME_PTR last_nonminibuf_frame;
    exist inside frame objects lives in the following structure instead.
 
    NOTE: the_only_frame is not checked for garbage collection; don't
    exist inside frame objects lives in the following structure instead.
 
    NOTE: the_only_frame is not checked for garbage collection; don't
-   store collectable objects in any of its fields!
+   store collectible objects in any of its fields!
 
    You're not/The only frame in town/...  */
 
 
    You're not/The only frame in town/...  */
 
@@ -164,21 +182,6 @@ DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
   return Qnil;
 }
 
   return Qnil;
 }
 
-DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
-  "Redraw all frames marked as having their images garbled.")
-  ()
-{
-  Lisp_Object frame, tail;
-
-  for (tail = Vframe_list; CONSP (tail); tail = XCONS (tail)->cdr)
-    {
-      frame = XCONS (tail)->car;
-      if (XFRAME (frame)->garbaged && XFRAME (frame)->visible)
-       Fredraw_frame (frame);
-    }
-  return Qnil;
-}
-
 redraw_frame (f)
      FRAME_PTR f;
 {
 redraw_frame (f)
      FRAME_PTR f;
 {
@@ -187,11 +190,12 @@ redraw_frame (f)
   Fredraw_frame (frame);
 }
 
   Fredraw_frame (frame);
 }
 
-#else /* not MULTI_FRAME */
+#else
 
 
-DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, 0,
-  "Clear screen and output again what is supposed to appear on it.")
-  ()
+DEFUN ("redraw-frame", Fredraw_frame, Sredraw_frame, 1, 1, 0,
+  "Clear frame FRAME and output again what is supposed to appear on it.")
+  (frame)
+     Lisp_Object frame;
 {
   update_begin (0);
   set_terminal_modes ();
 {
   update_begin (0);
   set_terminal_modes ();
@@ -202,11 +206,39 @@ DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, 0,
   windows_or_buffers_changed++;
   /* Mark all windows as INaccurate,
      so that every window will have its redisplay done.  */
   windows_or_buffers_changed++;
   /* Mark all windows as INaccurate,
      so that every window will have its redisplay done.  */
-  mark_window_display_accurate (FRAME_ROOT_WINDOW (0));
+  mark_window_display_accurate (FRAME_ROOT_WINDOW (0), 0);
   return Qnil;
 }
 
   return Qnil;
 }
 
-#endif /* not MULTI_FRAME */
+#endif
+
+DEFUN ("redraw-display", Fredraw_display, Sredraw_display, 0, 0, "",
+  "Clear and redisplay all visible frames.")
+  ()
+{
+  Lisp_Object tail, frame;
+
+  FOR_EACH_FRAME (tail, frame)
+    if (FRAME_VISIBLE_P (XFRAME (frame)))
+      Fredraw_frame (frame);
+
+  return Qnil;
+}
+
+/* This is used when frame_garbaged is set.
+   Redraw the individual frames marked as garbaged.  */
+
+void
+redraw_garbaged_frames ()
+{
+  Lisp_Object tail, frame;
+
+  FOR_EACH_FRAME (tail, frame)
+    if (FRAME_VISIBLE_P (XFRAME (frame))
+       && FRAME_GARBAGED_P (XFRAME (frame)))
+      Fredraw_frame (frame);
+}
+
 \f
 static struct frame_glyphs *
 make_frame_glyphs (frame, empty)
 \f
 static struct frame_glyphs *
 make_frame_glyphs (frame, empty)
@@ -216,14 +248,15 @@ make_frame_glyphs (frame, empty)
   register int i;
   register width = FRAME_WIDTH (frame);
   register height = FRAME_HEIGHT (frame);
   register int i;
   register width = FRAME_WIDTH (frame);
   register height = FRAME_HEIGHT (frame);
-  register struct frame_glyphs *new =
-    (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs));
+  register struct frame_glyphs *new
+    (struct frame_glyphs *) xmalloc (sizeof (struct frame_glyphs));
 
   SET_GLYPHS_FRAME (new, frame);
   new->height = height;
   new->width = width;
   new->used = (int *) xmalloc (height * sizeof (int));
   new->glyphs = (GLYPH **) xmalloc (height * sizeof (GLYPH *));
 
   SET_GLYPHS_FRAME (new, frame);
   new->height = height;
   new->width = width;
   new->used = (int *) xmalloc (height * sizeof (int));
   new->glyphs = (GLYPH **) xmalloc (height * sizeof (GLYPH *));
+  new->charstarts = (int **) xmalloc (height * sizeof (int *));
   new->highlight = (char *) xmalloc (height * sizeof (char));
   new->enable = (char *) xmalloc (height * sizeof (char));
   bzero (new->enable, height * sizeof (char));
   new->highlight = (char *) xmalloc (height * sizeof (char));
   new->enable = (char *) xmalloc (height * sizeof (char));
   bzero (new->enable, height * sizeof (char));
@@ -245,9 +278,13 @@ make_frame_glyphs (frame, empty)
       /* Make the buffer used by decode_mode_spec.  This buffer is also
          used as temporary storage when updating the frame.  See scroll.c. */
       unsigned int total_glyphs = (width + 2) * sizeof (GLYPH);
       /* Make the buffer used by decode_mode_spec.  This buffer is also
          used as temporary storage when updating the frame.  See scroll.c. */
       unsigned int total_glyphs = (width + 2) * sizeof (GLYPH);
+      unsigned int total_charstarts = (width + 2) * sizeof (int);
 
       new->total_contents = (GLYPH *) xmalloc (total_glyphs);
       bzero (new->total_contents, total_glyphs);
 
       new->total_contents = (GLYPH *) xmalloc (total_glyphs);
       bzero (new->total_contents, total_glyphs);
+
+      new->total_charstarts = (int *) xmalloc (total_charstarts);
+      bzero (new->total_charstarts, total_glyphs);
     }
   else
     {
     }
   else
     {
@@ -257,37 +294,60 @@ make_frame_glyphs (frame, empty)
       bzero (new->total_contents, total_glyphs);
       for (i = 0; i < height; i++)
        new->glyphs[i] = new->total_contents + i * (width + 2) + 1;
       bzero (new->total_contents, total_glyphs);
       for (i = 0; i < height; i++)
        new->glyphs[i] = new->total_contents + i * (width + 2) + 1;
+
+      if (!FRAME_TERMCAP_P (frame))
+       {
+         unsigned int total_charstarts = height * (width + 2) * sizeof (int);
+
+         new->total_charstarts = (int *) xmalloc (total_charstarts);
+         bzero (new->total_charstarts, total_charstarts);
+         for (i = 0; i < height; i++)
+           new->charstarts[i] = new->total_charstarts + i * (width + 2) + 1;
+       }
+      else
+       {
+         /* Without a window system, we don't really need charstarts.
+            So use a small amount of space to make enough data structure
+            to prevent crashes in display_text_line.  */
+         new->total_charstarts = (int *) xmalloc ((width + 2) * sizeof (int));
+         for (i = 0; i < height; i++)
+           new->charstarts[i] = new->total_charstarts;
+       }
     }
 
   return new;
 }
 
     }
 
   return new;
 }
 
-static void
+void
 free_frame_glyphs (frame, glyphs)
      FRAME_PTR frame;
      struct frame_glyphs *glyphs;
 {
   if (glyphs->total_contents)
 free_frame_glyphs (frame, glyphs)
      FRAME_PTR frame;
      struct frame_glyphs *glyphs;
 {
   if (glyphs->total_contents)
-    free (glyphs->total_contents);
-
-  free (glyphs->used);
-  free (glyphs->glyphs);
-  free (glyphs->highlight);
-  free (glyphs->enable);
-  free (glyphs->bufp);
+    xfree (glyphs->total_contents);
+  if (glyphs->total_charstarts)
+    xfree (glyphs->total_charstarts);
+
+  xfree (glyphs->used);
+  xfree (glyphs->glyphs);
+  xfree (glyphs->highlight);
+  xfree (glyphs->enable);
+  xfree (glyphs->bufp);
+  if (glyphs->charstarts)
+    xfree (glyphs->charstarts);
 
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (frame))
     {
 
 #ifdef HAVE_X_WINDOWS
   if (FRAME_X_P (frame))
     {
-      free (glyphs->top_left_x);
-      free (glyphs->top_left_y);
-      free (glyphs->pix_width);
-      free (glyphs->pix_height);
-      free (glyphs->max_ascent);
+      xfree (glyphs->top_left_x);
+      xfree (glyphs->top_left_y);
+      xfree (glyphs->pix_width);
+      xfree (glyphs->pix_height);
+      xfree (glyphs->max_ascent);
     }
 #endif
 
     }
 #endif
 
-  free (glyphs);
+  xfree (glyphs);
 }
 
 static void
 }
 
 static void
@@ -302,9 +362,20 @@ remake_frame_glyphs (frame)
     free_frame_glyphs (frame, FRAME_TEMP_GLYPHS (frame));
 
   if (FRAME_MESSAGE_BUF (frame))
     free_frame_glyphs (frame, FRAME_TEMP_GLYPHS (frame));
 
   if (FRAME_MESSAGE_BUF (frame))
-    FRAME_MESSAGE_BUF (frame)
-      = (char *) xrealloc (FRAME_MESSAGE_BUF (frame),
-                          FRAME_WIDTH (frame) + 1);
+    {
+      /* Reallocate the frame's message buffer; remember that
+        echo_area_glyphs may be pointing here.  */
+      char *old_message_buf = FRAME_MESSAGE_BUF (frame);
+
+      FRAME_MESSAGE_BUF (frame)
+       = (char *) xrealloc (FRAME_MESSAGE_BUF (frame),
+                            FRAME_WIDTH (frame) + 1);
+
+      if (echo_area_glyphs == old_message_buf)
+       echo_area_glyphs = FRAME_MESSAGE_BUF (frame);
+      if (previous_echo_glyphs == old_message_buf)
+       previous_echo_glyphs = FRAME_MESSAGE_BUF (frame);
+    }
   else
     FRAME_MESSAGE_BUF (frame)
       = (char *) xmalloc (FRAME_WIDTH (frame) + 1);
   else
     FRAME_MESSAGE_BUF (frame)
       = (char *) xmalloc (FRAME_WIDTH (frame) + 1);
@@ -469,25 +540,27 @@ safe_bcopy (from, to, size)
      char *from, *to;
      int size;
 {
      char *from, *to;
      int size;
 {
-  register char *endf;
-  register char *endt;
-
-  if (size == 0)
+  if (size <= 0 || from == to)
     return;
 
     return;
 
-  /* If destination is higher in memory, and overlaps source zone,
-     copy from the end.  */
-  if (from < to && from + size > to)
+  /* If the source and destination don't overlap, then bcopy can
+     handle it.  If they do overlap, but the destination is lower in
+     memory than the source, we'll assume bcopy can handle that.  */
+  if (to < from || from + size <= to)
+    bcopy (from, to, size);
+
+  /* Otherwise, we'll copy from the end.  */
+  else
     {
     {
-      endf = from + size;
-      endt = to + size;
+      register char *endf = from + size;
+      register char *endt = to + size;
 
       /* If TO - FROM is large, then we should break the copy into
         nonoverlapping chunks of TO - FROM bytes each.  However, if
         TO - FROM is small, then the bcopy function call overhead
         makes this not worth it.  The crossover point could be about
 
       /* If TO - FROM is large, then we should break the copy into
         nonoverlapping chunks of TO - FROM bytes each.  However, if
         TO - FROM is small, then the bcopy function call overhead
         makes this not worth it.  The crossover point could be about
-        anywhere.  Since I don't think the obvious copy loop is ever
-        too bad, I'm trying to err in its favor.  */
+        anywhere.  Since I don't think the obvious copy loop is too
+        bad, I'm trying to err in its favor.  */
       if (to - from < 64)
        {
          do
       if (to - from < 64)
        {
          do
@@ -496,56 +569,25 @@ safe_bcopy (from, to, size)
        }
       else
        {
        }
       else
        {
-         /* Since TO - FROM >= 64, the overlap is less than SIZE,
-            so we can always safely do this loop once.  */
-         while (endt > to)
+         for (;;)
            {
              endt -= (to - from);
              endf -= (to - from);
 
            {
              endt -= (to - from);
              endf -= (to - from);
 
+             if (endt < to)
+               break;
+
              bcopy (endf, endt, to - from);
            }
              bcopy (endf, endt, to - from);
            }
-         
-         /* If TO - FROM wasn't a multiple of SIZE, there will be a
+
+         /* If SIZE wasn't a multiple of TO - FROM, there will be a
             little left over.  The amount left over is
             (endt + (to - from)) - to, which is endt - from.  */
          bcopy (from, to, endt - from);
        }
     }
             little left over.  The amount left over is
             (endt + (to - from)) - to, which is endt - from.  */
          bcopy (from, to, endt - from);
        }
     }
-  else
-    bcopy (from, to, size);
 }     
 
 }     
 
-#if 0
-void
-safe_bcopy (from, to, size)
-     char *from, *to;
-     int size;
-{
-  register char *endf;
-  register char *endt;
-
-  if (size == 0)
-    return;
-
-  /* If destination is higher in memory, and overlaps source zone,
-     copy from the end. */
-  if (from < to && from + size > to)
-    {
-      endf = from + size;
-      endt = to + size;
-
-      do
-       *--endt = *--endf;
-      while (endf != from);
-
-      return;
-    }
-
-  bcopy (from, to, size);
-}
-#endif
-
 /* Rotate a vector of SIZE bytes right, by DISTANCE bytes.
    DISTANCE may be negative.  */
 
 /* Rotate a vector of SIZE bytes right, by DISTANCE bytes.
    DISTANCE may be negative.  */
 
@@ -570,13 +612,15 @@ rotate_vector (vector, size, distance)
    Returns nonzero if done, zero if terminal cannot scroll them.  */
 
 int
    Returns nonzero if done, zero if terminal cannot scroll them.  */
 
 int
-scroll_frame_lines (frame, from, end, amount)
+scroll_frame_lines (frame, from, end, amount, newpos)
      register FRAME_PTR frame;
      register FRAME_PTR frame;
-     int from, end, amount;
+     int from, end, amount, newpos;
 {
   register int i;
   register struct frame_glyphs *current_frame
     = FRAME_CURRENT_GLYPHS (frame);
 {
   register int i;
   register struct frame_glyphs *current_frame
     = FRAME_CURRENT_GLYPHS (frame);
+  int pos_adjust;
+  int width = FRAME_WIDTH (frame);
 
   if (!line_ins_del_ok)
     return 0;
 
   if (!line_ins_del_ok)
     return 0;
@@ -597,6 +641,10 @@ scroll_frame_lines (frame, from, end, amount)
                     sizeof (GLYPH *) * (end + amount - from),
                     amount * sizeof (GLYPH *));
 
                     sizeof (GLYPH *) * (end + amount - from),
                     amount * sizeof (GLYPH *));
 
+      rotate_vector (current_frame->charstarts + from,
+                    sizeof (int *) * (end + amount - from),
+                    amount * sizeof (int *));
+
       safe_bcopy (current_frame->used + from,
                  current_frame->used + from + amount,
                  (end - from) * sizeof current_frame->used[0]);
       safe_bcopy (current_frame->used + from,
                  current_frame->used + from + amount,
                  (end - from) * sizeof current_frame->used[0]);
@@ -609,6 +657,29 @@ scroll_frame_lines (frame, from, end, amount)
                  current_frame->enable + from + amount,
                  (end - from) * sizeof current_frame->enable[0]);
 
                  current_frame->enable + from + amount,
                  (end - from) * sizeof current_frame->enable[0]);
 
+      /* Adjust the lines by an amount
+        that puts the first of them at NEWPOS.  */
+      pos_adjust = newpos - current_frame->charstarts[from + amount][0];
+
+      /* Offset each char position in the charstarts lines we moved
+        by pos_adjust.  */
+      for (i = from + amount; i < end + amount; i++)
+       {
+         int *line = current_frame->charstarts[i];
+         int col;
+         for (col = 0; col < width; col++)
+           if (line[col] > 0)
+             line[col] += pos_adjust;
+       }
+      for (i = from; i < from + amount; i++)
+       {
+         int *line = current_frame->charstarts[i];
+         int col;
+         line[0] = -1;
+         for (col = 0; col < width; col++)
+           line[col] = 0;
+       }
+
       /* Mark the lines made empty by scrolling as enabled, empty and
         normal video.  */
       bzero (current_frame->used + from,
       /* Mark the lines made empty by scrolling as enabled, empty and
         normal video.  */
       bzero (current_frame->used + from,
@@ -618,6 +689,7 @@ scroll_frame_lines (frame, from, end, amount)
       for (i = from; i < from + amount; i++)
        {
          current_frame->glyphs[i][0] = '\0';
       for (i = from; i < from + amount; i++)
        {
          current_frame->glyphs[i][0] = '\0';
+         current_frame->charstarts[i][0] = -1;
          current_frame->enable[i] = 1;
        }
 
          current_frame->enable[i] = 1;
        }
 
@@ -665,6 +737,10 @@ scroll_frame_lines (frame, from, end, amount)
                     sizeof (GLYPH *) * (end - from - amount),
                     amount * sizeof (GLYPH *));
 
                     sizeof (GLYPH *) * (end - from - amount),
                     amount * sizeof (GLYPH *));
 
+      rotate_vector (current_frame->charstarts + from + amount,
+                    sizeof (int *) * (end - from - amount),
+                    amount * sizeof (int *));
+
       safe_bcopy (current_frame->used + from,
                  current_frame->used + from + amount,
                  (end - from) * sizeof current_frame->used[0]);
       safe_bcopy (current_frame->used + from,
                  current_frame->used + from + amount,
                  (end - from) * sizeof current_frame->used[0]);
@@ -677,6 +753,29 @@ scroll_frame_lines (frame, from, end, amount)
                  current_frame->enable + from + amount,
                  (end - from) * sizeof current_frame->enable[0]);
 
                  current_frame->enable + from + amount,
                  (end - from) * sizeof current_frame->enable[0]);
 
+      /* Adjust the lines by an amount
+        that puts the first of them at NEWPOS.  */
+      pos_adjust = newpos - current_frame->charstarts[from + amount][0];
+
+      /* Offset each char position in the charstarts lines we moved
+        by pos_adjust.  */
+      for (i = from + amount; i < end + amount; i++)
+       {
+         int *line = current_frame->charstarts[i];
+         int col;
+         for (col = 0; col < width; col++)
+           if (line[col] > 0)
+             line[col] += pos_adjust;
+       }
+      for (i = end + amount; i < end; i++)
+       {
+         int *line = current_frame->charstarts[i];
+         int col;
+         line[0] = -1;
+         for (col = 0; col < width; col++)
+           line[col] = 0;
+       }
+
       /* Mark the lines made empty by scrolling as enabled, empty and
         normal video.  */
       bzero (current_frame->used + end + amount,
       /* Mark the lines made empty by scrolling as enabled, empty and
         normal video.  */
       bzero (current_frame->used + end + amount,
@@ -686,6 +785,7 @@ scroll_frame_lines (frame, from, end, amount)
       for (i = end + amount; i < end; i++)
        {
          current_frame->glyphs[i][0] = '\0';
       for (i = end + amount; i < end; i++)
        {
          current_frame->glyphs[i][0] = '\0';
+         current_frame->charstarts[i][0] = 0;
          current_frame->enable[i] = 1;
        }
 
          current_frame->enable[i] = 1;
        }
 
@@ -750,7 +850,11 @@ preserve_other_columns (w)
              int len;
 
              bcopy (current_frame->glyphs[vpos],
              int len;
 
              bcopy (current_frame->glyphs[vpos],
-                    desired_frame->glyphs[vpos], start);
+                    desired_frame->glyphs[vpos],
+                    start * sizeof (current_frame->glyphs[vpos][0]));
+             bcopy (current_frame->charstarts[vpos],
+                    desired_frame->charstarts[vpos],
+                    start * sizeof (current_frame->charstarts[vpos][0]));
              len = min (start, current_frame->used[vpos]);
              if (desired_frame->used[vpos] < len)
                desired_frame->used[vpos] = len;
              len = min (start, current_frame->used[vpos]);
              if (desired_frame->used[vpos] < len)
                desired_frame->used[vpos] = len;
@@ -759,11 +863,19 @@ preserve_other_columns (w)
              && desired_frame->used[vpos] < current_frame->used[vpos])
            {
              while (desired_frame->used[vpos] < end)
              && desired_frame->used[vpos] < current_frame->used[vpos])
            {
              while (desired_frame->used[vpos] < end)
-               desired_frame->glyphs[vpos][desired_frame->used[vpos]++]
-                 = SPACEGLYPH;
+               {
+                 int used = desired_frame->used[vpos]++;
+                 desired_frame->glyphs[vpos][used] = SPACEGLYPH;
+                 desired_frame->glyphs[vpos][used] = 0;
+               }
              bcopy (current_frame->glyphs[vpos] + end,
                     desired_frame->glyphs[vpos] + end,
              bcopy (current_frame->glyphs[vpos] + end,
                     desired_frame->glyphs[vpos] + end,
-                    current_frame->used[vpos] - end);
+                    ((current_frame->used[vpos] - end)
+                     * sizeof (current_frame->glyphs[vpos][0])));
+             bcopy (current_frame->charstarts[vpos] + end,
+                    desired_frame->charstarts[vpos] + end,
+                    ((current_frame->used[vpos] - end)
+                     * sizeof (current_frame->charstarts[vpos][0])));
              desired_frame->used[vpos] = current_frame->used[vpos];
            }
        }
              desired_frame->used[vpos] = current_frame->used[vpos];
            }
        }
@@ -809,6 +921,89 @@ preserve_my_columns (w)
 
 #endif
 \f
 
 #endif
 \f
+/* Adjust by ADJUST the charstart values in window W
+   after vpos VPOS, which counts relative to the frame
+   (not relative to W itself).  */
+
+void
+adjust_window_charstarts (w, vpos, adjust)
+     struct window *w;
+     int vpos;
+     int adjust;
+{
+  int left = XFASTINT (w->left);
+  int top = XFASTINT (w->top);
+  int right = left + window_internal_width (w);
+  int bottom = top + window_internal_height (w);
+  int i;
+
+  for (i = vpos + 1; i < bottom; i++)
+    {
+      int *charstart
+       = FRAME_CURRENT_GLYPHS (XFRAME (WINDOW_FRAME (w)))->charstarts[i];
+      int j;
+      for (j = left; j < right; j++)
+       if (charstart[j] > 0)
+         charstart[j] += adjust;
+    }
+}
+
+/* Check the charstarts values in the area of window W
+   for internal consistency.  We cannot check that they are "right";
+   we can only look for something nonsensical.  */
+
+verify_charstarts (w)
+     struct window *w;
+{
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+  int i;
+  int top = XFASTINT (w->top);
+  int bottom = top + window_internal_height (w);
+  int left = XFASTINT (w->left);
+  int right = left + window_internal_width (w);
+  int next_line;
+  int truncate = (XINT (w->hscroll)
+                 || (truncate_partial_width_windows
+                     && (XFASTINT (w->width) < FRAME_WIDTH (f)))
+                 || !NILP (XBUFFER (w->buffer)->truncate_lines));
+
+  for (i = top; i < bottom; i++)
+    {
+      int j;
+      int last;
+      int *charstart = FRAME_CURRENT_GLYPHS (f)->charstarts[i];
+
+      if (i != top)
+       {
+         if (truncate)
+           {
+             /* If we are truncating lines, allow a jump
+                in charstarts from one line to the next.  */
+             if (charstart[left] < next_line)
+               abort ();
+           }
+         else
+           {
+             if (charstart[left] != next_line)
+               abort ();
+           }
+       }
+
+      for (j = left; j < right; j++)
+       if (charstart[j] > 0)
+         last = charstart[j];
+      /* Record where the next line should start.  */
+      next_line = last;
+      if (BUF_ZV (XBUFFER (w->buffer)) != last)
+       {
+         /* If there's a newline between the two lines, count that.  */
+         int endchar = *BUF_CHAR_ADDRESS (XBUFFER (w->buffer), last);
+         if (endchar == '\n')
+           next_line++;
+       }
+    }
+}
+\f
 /* On discovering that the redisplay for a window was no good,
    cancel the columns of that window, so that when the window is
    displayed over again get_display_line will not complain.  */
 /* On discovering that the redisplay for a window was no good,
    cancel the columns of that window, so that when the window is
    displayed over again get_display_line will not complain.  */
@@ -817,8 +1012,8 @@ cancel_my_columns (w)
      struct window *w;
 {
   register int vpos;
      struct window *w;
 {
   register int vpos;
-  register struct frame_glyphs *desired_glyphs =
-    FRAME_DESIRED_GLYPHS (XFRAME (w->frame));
+  register struct frame_glyphs *desired_glyphs
+    FRAME_DESIRED_GLYPHS (XFRAME (w->frame));
   register int start = XFASTINT (w->left);
   register int bot = XFASTINT (w->top) + XFASTINT (w->height);
 
   register int start = XFASTINT (w->left);
   register int bot = XFASTINT (w->top) + XFASTINT (w->height);
 
@@ -857,9 +1052,9 @@ direct_output_for_insert (g)
 #endif /* COMPILER_REGISTER_BUG */
     int vpos = FRAME_CURSOR_Y (frame);
 
 #endif /* COMPILER_REGISTER_BUG */
     int vpos = FRAME_CURSOR_Y (frame);
 
-  /* Give up if about to continue line */
-  if (hpos - XFASTINT (w->left) + 1 + 1 >= XFASTINT (w->width)
-
+  /* Give up if about to continue line */
+  if (hpos >= XFASTINT (w->left) + window_internal_width (w) - 1
+    
   /* Avoid losing if cursor is in invisible text off left margin */
       || (XINT (w->hscroll) && hpos == XFASTINT (w->left))
     
   /* Avoid losing if cursor is in invisible text off left margin */
       || (XINT (w->hscroll) && hpos == XFASTINT (w->left))
     
@@ -874,11 +1069,35 @@ direct_output_for_insert (g)
   /* Give up if buffer appears in two places.  */
       || buffer_shared > 1
 
   /* Give up if buffer appears in two places.  */
       || buffer_shared > 1
 
+#ifdef USE_TEXT_PROPERTIES
+  /* Intervals have already been adjusted, point is after the
+     character that was just inserted. */
+  /* Give up if character is invisible. */
+  /* Give up if character has a face property.
+     At the moment we only lose at end of line or end of buffer
+     and only with faces that have some background */
+  /* Instead of wasting time, give up if character has any text properties */
+      || ! NILP (Ftext_properties_at (make_number (point - 1), Qnil))
+#endif
+
   /* Give up if w is minibuffer and a message is being displayed there */
       || (MINI_WINDOW_P (w) && echo_area_glyphs))
     return 0;
 
   /* Give up if w is minibuffer and a message is being displayed there */
       || (MINI_WINDOW_P (w) && echo_area_glyphs))
     return 0;
 
-  current_frame->glyphs[vpos][hpos] = g;
+  {
+    int face = 0;
+#ifdef HAVE_X_WINDOWS
+    int dummy;
+
+    if (FRAME_X_P (frame))
+      face = compute_char_face (frame, w, point - 1, -1, -1, &dummy, point, 0);
+#endif
+    current_frame->glyphs[vpos][hpos] = MAKE_GLYPH (frame, g, face);
+    current_frame->charstarts[vpos][hpos] = point - 1;
+    /* Record the entry for after the newly inserted character.  */
+    current_frame->charstarts[vpos][hpos + 1] = point;
+    adjust_window_charstarts (w, vpos, 1);
+  }
   unchanged_modified = MODIFF;
   beg_unchanged = GPT - BEG;
   XFASTINT (w->last_point) = point;
   unchanged_modified = MODIFF;
   beg_unchanged = GPT - BEG;
   XFASTINT (w->last_point) = point;
@@ -904,24 +1123,51 @@ direct_output_forward_char (n)
 {
   register FRAME_PTR frame = selected_frame;
   register struct window *w = XWINDOW (selected_window);
 {
   register FRAME_PTR frame = selected_frame;
   register struct window *w = XWINDOW (selected_window);
+  Lisp_Object position;
+  int hpos = FRAME_CURSOR_X (frame);
+
+  /* Give up if in truncated text at end of line.  */
+  if (hpos >= XFASTINT (w->left) + window_internal_width (w) - 1)
+    return 0;
 
   /* Avoid losing if cursor is in invisible text off left margin
      or about to go off either side of window.  */
   if ((FRAME_CURSOR_X (frame) == XFASTINT (w->left)
        && (XINT (w->hscroll) || n < 0))
       || (n > 0
 
   /* Avoid losing if cursor is in invisible text off left margin
      or about to go off either side of window.  */
   if ((FRAME_CURSOR_X (frame) == XFASTINT (w->left)
        && (XINT (w->hscroll) || n < 0))
       || (n > 0
-         && (FRAME_CURSOR_X (frame) + 1
-             >= (XFASTINT (w->left) + XFASTINT (w->width)
-                 - (XFASTINT (w->width) < FRAME_WIDTH (frame))
-                 - 1)))
+         && (FRAME_CURSOR_X (frame) + 1 >= window_internal_width (w) - 1))
       || cursor_in_echo_area)
     return 0;
       || cursor_in_echo_area)
     return 0;
+  
+  /* Can't use direct output if highlighting a region.  */
+  if (!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
+    return 0;
+
+#ifdef USE_TEXT_PROPERTIES
+  /* Don't use direct output next to an invisible character
+     since we might need to do something special.  */
+
+  XFASTINT (position) = point;
+  if (XFASTINT (position) < ZV
+      && ! NILP (Fget_char_property (position,
+                                    Qinvisible,
+                                    selected_window)))
+    return 0;
+
+  XFASTINT (position) = point - 1;
+  if (XFASTINT (position) >= BEGV
+      && ! NILP (Fget_char_property (position,
+                                    Qinvisible,
+                                    selected_window)))
+    return 0;
+#endif
 
   FRAME_CURSOR_X (frame) += n;
   XFASTINT (w->last_point_x) = FRAME_CURSOR_X (frame);
   XFASTINT (w->last_point) = point;
   cursor_to (FRAME_CURSOR_Y (frame), FRAME_CURSOR_X (frame));
   fflush (stdout);
 
   FRAME_CURSOR_X (frame) += n;
   XFASTINT (w->last_point_x) = FRAME_CURSOR_X (frame);
   XFASTINT (w->last_point) = point;
   cursor_to (FRAME_CURSOR_Y (frame), FRAME_CURSOR_X (frame));
   fflush (stdout);
+
   return 1;
 }
 \f
   return 1;
 }
 \f
@@ -937,8 +1183,8 @@ update_frame (f, force, inhibit_hairy_id)
      int force;
      int inhibit_hairy_id;
 {
      int force;
      int inhibit_hairy_id;
 {
-  register struct frame_glyphs *current_frame = FRAME_CURRENT_GLYPHS (f);
-  register struct frame_glyphs *desired_frame = FRAME_DESIRED_GLYPHS (f);
+  register struct frame_glyphs *current_frame;
+  register struct frame_glyphs *desired_frame = 0;
   register int i;
   int pause;
   int preempt_count = baud_rate / 2400 + 1;
   register int i;
   int pause;
   int preempt_count = baud_rate / 2400 + 1;
@@ -947,6 +1193,9 @@ update_frame (f, force, inhibit_hairy_id)
   register int downto, leftmost;
 #endif
 
   register int downto, leftmost;
 #endif
 
+  if (preempt_count <= 0)
+    preempt_count = 1;
+
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
   detect_input_pending ();
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
 
   detect_input_pending ();
@@ -961,6 +1210,10 @@ update_frame (f, force, inhibit_hairy_id)
   if (!line_ins_del_ok)
     inhibit_hairy_id = 1;
 
   if (!line_ins_del_ok)
     inhibit_hairy_id = 1;
 
+  /* These are separate to avoid a possible bug in the AIX C compiler.  */
+  current_frame = FRAME_CURRENT_GLYPHS (f);
+  desired_frame = FRAME_DESIRED_GLYPHS (f);
+
   /* See if any of the desired lines are enabled; don't compute for
      i/d line if just want cursor motion. */
   for (i = 0; i < FRAME_HEIGHT (f); i++)
   /* See if any of the desired lines are enabled; don't compute for
      i/d line if just want cursor motion. */
   for (i = 0; i < FRAME_HEIGHT (f); i++)
@@ -1017,7 +1270,8 @@ update_frame (f, force, inhibit_hairy_id)
                        outq = PENDING_OUTPUT_COUNT (stdout);
 #endif
                      outq *= 10;
                        outq = PENDING_OUTPUT_COUNT (stdout);
 #endif
                      outq *= 10;
-                     sleep (outq / baud_rate);
+                     if (baud_rate <= outq && baud_rate > 0)
+                       sleep (outq / baud_rate);
                    }
                }
              if ((i - 1) % preempt_count == 0)
                    }
                }
              if ((i - 1) % preempt_count == 0)
@@ -1097,7 +1351,7 @@ update_frame (f, force, inhibit_hairy_id)
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
   display_completed = !pause;
 
   if (FRAME_HEIGHT (f) == 0) abort (); /* Some bug zeros some core */
   display_completed = !pause;
 
-  bzero (desired_frame->enable, FRAME_HEIGHT (f));
+  bzero (FRAME_DESIRED_GLYPHS (f)->enable, FRAME_HEIGHT (f));
   return pause;
 }
 
   return pause;
 }
 
@@ -1200,14 +1454,13 @@ buffer_posn_from_coords (window, col, line)
      struct window *window;
      int col, line;
 {
      struct window *window;
      int col, line;
 {
+  int hscroll = XINT (window->hscroll);
   int window_left = XFASTINT (window->left);
 
   /* The actual width of the window is window->width less one for the
      DISP_CONTINUE_GLYPH, and less one if it's not the rightmost
      window.  */
   int window_left = XFASTINT (window->left);
 
   /* The actual width of the window is window->width less one for the
      DISP_CONTINUE_GLYPH, and less one if it's not the rightmost
      window.  */
-  int window_width = (XFASTINT (window->width) - 1
-                     - (XFASTINT (window->width) + window_left
-                        != FRAME_WIDTH (XFRAME (window->frame))));
+  int window_width = window_internal_width (window) - 1;
 
   int startp = marker_position (window->start);
 
 
   int startp = marker_position (window->start);
 
@@ -1224,9 +1477,10 @@ buffer_posn_from_coords (window, col, line)
      sure I will keep it.  */
   posn = compute_motion (startp, 0,
                         (window == XWINDOW (minibuf_window) && startp == 1
      sure I will keep it.  */
   posn = compute_motion (startp, 0,
                         (window == XWINDOW (minibuf_window) && startp == 1
-                         ? minibuf_prompt_width : 0),
-                        ZV, line, col - window_left,
-                        window_width, XINT (window->hscroll), 0);
+                         ? minibuf_prompt_width : 0)
+                        + (hscroll ? 1 - hscroll : 0),
+                        ZV, line, col,
+                        window_width, hscroll, 0, window);
 
   current_buffer = old_current_buffer;
 
 
   current_buffer = old_current_buffer;
 
@@ -1262,7 +1516,7 @@ count_match (str1, str2)
 /* Char insertion/deletion cost vector, from term.c */
 extern int *char_ins_del_vector;
 
 /* Char insertion/deletion cost vector, from term.c */
 extern int *char_ins_del_vector;
 
-#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_HEIGHT((f))])
+#define char_ins_del_cost(f) (&char_ins_del_vector[FRAME_WIDTH((f))])
 
 static void
 update_line (frame, vpos)
 
 static void
 update_line (frame, vpos)
@@ -1270,6 +1524,7 @@ update_line (frame, vpos)
      int vpos;
 {
   register GLYPH *obody, *nbody, *op1, *op2, *np1, *temp;
      int vpos;
 {
   register GLYPH *obody, *nbody, *op1, *op2, *np1, *temp;
+  int *temp1;
   int tem;
   int osp, nsp, begmatch, endmatch, olen, nlen;
   int save;
   int tem;
   int osp, nsp, begmatch, endmatch, olen, nlen;
   int save;
@@ -1327,7 +1582,7 @@ update_line (frame, vpos)
        = current_frame->used[vpos]
          * FONT_WIDTH (frame->display.x->font);
       current_frame->pix_height[vpos]
        = current_frame->used[vpos]
          * FONT_WIDTH (frame->display.x->font);
       current_frame->pix_height[vpos]
-       = FONT_HEIGHT (frame->display.x->font);
+       = frame->display.x->line_height;
     }
 #endif /* HAVE_X_WINDOWS */
 
     }
 #endif /* HAVE_X_WINDOWS */
 
@@ -1364,6 +1619,25 @@ update_line (frame, vpos)
     {
       int i,j;
 
     {
       int i,j;
 
+#if 0
+      if (FRAME_X_P (frame))
+       {
+         /* Under X, erase everything we are going to rewrite,
+            and rewrite everything from the first char that's changed.
+            This is part of supporting fonts like Courier
+            whose chars can overlap outside the char width.  */
+         for (i = 0; i < nlen; i++)
+           if (i >= olen || nbody[i] != obody[i])
+             break;
+
+         cursor_to (vpos, i);
+         if (i != olen)
+           clear_end_of_line (olen);
+         write_glyphs (nbody + i, nlen - i);
+       }
+      else
+       {}
+#endif /* 0 */
       for (i = 0; i < nlen; i++)
        {
          if (i >= olen || nbody[i] != obody[i])    /* A non-matching char. */
       for (i = 0; i < nlen; i++)
        {
          if (i >= olen || nbody[i] != obody[i])    /* A non-matching char. */
@@ -1393,6 +1667,11 @@ update_line (frame, vpos)
       desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
       current_frame->glyphs[vpos] = temp;
 
       desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
       current_frame->glyphs[vpos] = temp;
 
+      /* Exchange charstarts between current_frame and new_frame.  */
+      temp1 = desired_frame->charstarts[vpos];
+      desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
+      current_frame->charstarts[vpos] = temp1;
+
       return;
     }
 
       return;
     }
 
@@ -1411,6 +1690,11 @@ update_line (frame, vpos)
       desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
       current_frame->glyphs[vpos] = temp;
 
       desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
       current_frame->glyphs[vpos] = temp;
 
+      /* Exchange charstarts between current_frame and new_frame.  */
+      temp1 = desired_frame->charstarts[vpos];
+      desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
+      current_frame->charstarts[vpos] = temp1;
+
       return;
     }
 
       return;
     }
 
@@ -1571,6 +1855,70 @@ update_line (frame, vpos)
   temp = desired_frame->glyphs[vpos];
   desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
   current_frame->glyphs[vpos] = temp;
   temp = desired_frame->glyphs[vpos];
   desired_frame->glyphs[vpos] = current_frame->glyphs[vpos];
   current_frame->glyphs[vpos] = temp;
+
+  /* Exchange charstarts between current_frame and new_frame.  */
+  temp1 = desired_frame->charstarts[vpos];
+  desired_frame->charstarts[vpos] = current_frame->charstarts[vpos];
+  current_frame->charstarts[vpos] = temp1;
+}
+\f
+/* A vector of size >= NFRAMES + 3 * NBUFFERS + 1, containing the session's
+   frames, buffers, buffer-read-only flags, and buffer-modified-flags,
+   and a trailing sentinel (so we don't need to add length checks).  */
+static Lisp_Object frame_and_buffer_state;
+
+DEFUN ("frame-or-buffer-changed-p", Fframe_or_buffer_changed_p,
+  Sframe_or_buffer_changed_p, 0, 0, 0,
+  "Return non-nil if the frame and buffer state appears to have changed.\n\
+The state variable is an internal vector containing all frames and buffers,\n\
+along with the buffers' read-only and modified flags, which allows a fast\n\
+check to see whether the menu bars might need to be recomputed.\n\
+If this function returns non-nil, it updates the internal vector to reflect\n\
+the current state.\n")
+  ()
+{
+  Lisp_Object tail, frame, buf;
+  Lisp_Object *vecp;
+  int n;
+  vecp = XVECTOR (frame_and_buffer_state)->contents;
+  FOR_EACH_FRAME (tail, frame)
+    if (!EQ (*vecp++, frame))
+      goto changed;
+  for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      buf = XCONS (XCONS (tail)->car)->cdr;
+      if (!EQ (*vecp++, buf))
+       goto changed;
+      if (!EQ (*vecp++, XBUFFER (buf)->read_only))
+       goto changed;
+      if (!EQ (*vecp++, Fbuffer_modified_p (buf)))
+       goto changed;
+    }
+  return Qnil;
+ changed:
+  n = 1;
+  FOR_EACH_FRAME (tail, frame)
+    n++;
+  for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
+    n += 3;
+  /* Reallocate the vector if it's grown, or if it's shrunk a lot.  */
+  if (n > XVECTOR (frame_and_buffer_state)->size
+      || n < XVECTOR (frame_and_buffer_state)->size / 2)
+    frame_and_buffer_state = Fmake_vector (make_number (n), Qlambda);
+  vecp = XVECTOR (frame_and_buffer_state)->contents;
+  FOR_EACH_FRAME (tail, frame)
+    *vecp++ = frame;
+  for (tail = Vbuffer_alist; CONSP (tail); tail = XCONS (tail)->cdr)
+    {
+      buf = XCONS (XCONS (tail)->car)->cdr;
+      *vecp++ = buf;
+      *vecp++ = XBUFFER (buf)->read_only;
+      *vecp++ = Fbuffer_modified_p (buf);
+    }
+  /* If we left any slack in the vector, fill it up now.  */
+  for (; n < XVECTOR (frame_and_buffer_state)->size; ++n)
+    *vecp++ = Qlambda;
+  return Qt;
 }
 \f
 DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
 }
 \f
 DEFUN ("open-termscript", Fopen_termscript, Sopen_termscript,
@@ -1612,14 +1960,13 @@ window_change_signal ()
      later outside of the signal handler.  */
 
   {
      later outside of the signal handler.  */
 
   {
-    Lisp_Object tail;
-    FRAME_PTR f;
+    Lisp_Object tail, frame;
 
 
-    FOR_EACH_FRAME (tail, f)
+    FOR_EACH_FRAME (tail, frame)
       {
       {
-       if (FRAME_TERMCAP_P (f))
+       if (FRAME_TERMCAP_P (XFRAME (frame)))
          {
          {
-           change_frame_size (f, height, width, 0, 1);
+           change_frame_size (XFRAME (frame), height, width, 0, 1);
            break;
          }
       }
            break;
          }
       }
@@ -1638,20 +1985,18 @@ do_pending_window_change ()
   /* If window_change_signal should have run before, run it now.  */
   while (delayed_size_change)
     {
   /* If window_change_signal should have run before, run it now.  */
   while (delayed_size_change)
     {
-      Lisp_Object tail;
-      FRAME_PTR f;
+      Lisp_Object tail, frame;
 
       delayed_size_change = 0;
 
 
       delayed_size_change = 0;
 
-      FOR_EACH_FRAME (tail, f)
+      FOR_EACH_FRAME (tail, frame)
        {
        {
+         FRAME_PTR f = XFRAME (frame);
+
          int height = FRAME_NEW_HEIGHT (f);
          int width = FRAME_NEW_WIDTH (f);
          int height = FRAME_NEW_HEIGHT (f);
          int width = FRAME_NEW_WIDTH (f);
-           
-         FRAME_NEW_HEIGHT (f) = 0;
-         FRAME_NEW_WIDTH (f) = 0;
 
 
-         if (height != 0)
+         if (height != 0 || width != 0)
            change_frame_size (f, height, width, 0, 0);
        }
     }
            change_frame_size (f, height, width, 0, 0);
        }
     }
@@ -1683,7 +2028,7 @@ change_frame_size (frame, newheight, newwidth, pretend, delay)
   FRAME_NEW_HEIGHT (frame) = 0;
   FRAME_NEW_WIDTH  (frame) = 0;
 
   FRAME_NEW_HEIGHT (frame) = 0;
   FRAME_NEW_WIDTH  (frame) = 0;
 
-  /* If an arguments is zero, set it to the current value.  */
+  /* If an argument is zero, set it to the current value.  */
   newheight || (newheight = FRAME_HEIGHT (frame));
   newwidth  || (newwidth  = FRAME_WIDTH  (frame));
 
   newheight || (newheight = FRAME_HEIGHT (frame));
   newwidth  || (newwidth  = FRAME_WIDTH  (frame));
 
@@ -1702,14 +2047,15 @@ change_frame_size (frame, newheight, newwidth, pretend, delay)
        {
          /* Frame has both root and minibuffer.  */
          set_window_height (FRAME_ROOT_WINDOW (frame),
        {
          /* Frame has both root and minibuffer.  */
          set_window_height (FRAME_ROOT_WINDOW (frame),
-                            newheight - 1, 0);
+                            newheight - 1 - FRAME_MENU_BAR_LINES (frame), 0);
          XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (frame))->top)
            = newheight - 1;
          set_window_height (FRAME_MINIBUF_WINDOW (frame), 1, 0);
        }
       else
        /* Frame has just one top-level window.  */
          XFASTINT (XWINDOW (FRAME_MINIBUF_WINDOW (frame))->top)
            = newheight - 1;
          set_window_height (FRAME_MINIBUF_WINDOW (frame), 1, 0);
        }
       else
        /* Frame has just one top-level window.  */
-       set_window_height (FRAME_ROOT_WINDOW (frame), newheight, 0);
+       set_window_height (FRAME_ROOT_WINDOW (frame),
+                          newheight - FRAME_MENU_BAR_LINES (frame), 0);
 
       if (FRAME_TERMCAP_P (frame) && !pretend)
        FrameRows = newheight;
 
       if (FRAME_TERMCAP_P (frame) && !pretend)
        FrameRows = newheight;
@@ -1744,7 +2090,12 @@ change_frame_size (frame, newheight, newwidth, pretend, delay)
 
   FRAME_HEIGHT (frame) = newheight;
   FRAME_WIDTH (frame)  = newwidth;
 
   FRAME_HEIGHT (frame) = newheight;
   FRAME_WIDTH (frame)  = newwidth;
-       
+
+  if (FRAME_CURSOR_X (frame) >= FRAME_WIDTH (frame))
+    FRAME_CURSOR_X (frame) = FRAME_WIDTH (frame) - 1;
+  if (FRAME_CURSOR_Y (frame) >= FRAME_HEIGHT (frame))
+    FRAME_CURSOR_Y (frame) = FRAME_HEIGHT (frame) - 1;
+
   remake_frame_glyphs (frame);
   calculate_costs (frame);
 }
   remake_frame_glyphs (frame);
   calculate_costs (frame);
 }
@@ -1800,29 +2151,53 @@ bitch_at_user ()
 }
 
 DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0,
 }
 
 DEFUN ("sleep-for", Fsleep_for, Ssleep_for, 1, 2, 0,
-  "Pause, without updating display, for ARG seconds.\n\
-Optional second arg non-nil means ARG is measured in milliseconds.\n\
-\(Not all operating systems support milliseconds.)")
-  (arg, millisec)
-     Lisp_Object arg, millisec;
+  "Pause, without updating display, for SECONDS seconds.\n\
+SECONDS may be a floating-point value, meaning that you can wait for a\n\
+fraction of a second.  Optional second arg MILLISECONDS specifies an\n\
+additional wait period, in milliseconds; this may be useful if your\n\
+Emacs was built without floating point support.\n\
+\(Not all operating systems support waiting for a fraction of a second.)")
+  (seconds, milliseconds)
+     Lisp_Object seconds, milliseconds;
 {
 {
-  int usec = 0;
-  int sec;
+  int sec, usec;
 
 
-  CHECK_NUMBER (arg, 0);
-  sec = XINT (arg);
-  if (sec <= 0)
-    return Qnil;
+  if (NILP (milliseconds))
+    XSET (milliseconds, Lisp_Int, 0);
+  else
+    CHECK_NUMBER (milliseconds, 1);
+  usec = XINT (milliseconds) * 1000;
 
 
-  if (!NILP (millisec))
-    {
-#ifndef EMACS_HAS_USECS
-      error ("millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
+#ifdef LISP_FLOAT_TYPE
+  {
+    double duration = extract_float (seconds);
+    sec = (int) duration;
+    usec += (duration - sec) * 1000000;
+  }
 #else
 #else
-      usec = sec % 1000 * 1000;
-      sec /= 1000;
+  CHECK_NUMBER (seconds, 0);
+  sec = XINT (seconds);
 #endif
 #endif
+
+#ifndef EMACS_HAS_USECS
+  if (sec == 0 && usec != 0)
+    error ("millisecond `sleep-for' not supported on %s", SYSTEM_TYPE);
+#endif
+
+  /* Assure that 0 <= usec < 1000000.  */
+  if (usec < 0)
+    {
+      /* We can't rely on the rounding being correct if user is negative.  */
+      if (-1000000 < usec)
+       sec--, usec += 1000000;
+      else
+       sec -= -usec / 1000000, usec = 1000000 - (-usec % 1000000);
     }
     }
+  else
+    sec += usec / 1000000, usec %= 1000000;
+
+  if (sec <= 0)
+    return Qnil;
 
   {
     Lisp_Object zero;
 
   {
     Lisp_Object zero;
@@ -1831,7 +2206,10 @@ Optional second arg non-nil means ARG is measured in milliseconds.\n\
     wait_reading_process_input (sec, usec, zero, 0);
   }
 
     wait_reading_process_input (sec, usec, zero, 0);
   }
 
-#if 0 /* No wait_reading_process_input */
+  /* We should always have wait_reading_process_input; we have a dummy
+     implementation for systems which don't support subprocesses.  */
+#if 0
+  /* No wait_reading_process_input */
   immediate_quit = 1;
   QUIT;
 
   immediate_quit = 1;
   QUIT;
 
@@ -1868,8 +2246,9 @@ Optional second arg non-nil means ARG is measured in milliseconds.\n\
 /* This is just like wait_reading_process_input, except that
    it does the redisplay.
 
 /* This is just like wait_reading_process_input, except that
    it does the redisplay.
 
-   It's also just like Fsit_for, except that it can be used for
-   waiting for input as well.  */
+   It's also much like Fsit_for, except that it can be used for
+   waiting for input as well.  One differnce is that sit_for
+   does not call prepare_menu_bars; Fsit_for does call that.  */
 
 Lisp_Object
 sit_for (sec, usec, reading, display)
 
 Lisp_Object
 sit_for (sec, usec, reading, display)
@@ -1887,14 +2266,18 @@ sit_for (sec, usec, reading, display)
     return Qt;
 
 #ifdef SIGIO
     return Qt;
 
 #ifdef SIGIO
-  gobble_input ();
+  gobble_input (0);
 #endif
 
   XSET (read_kbd, Lisp_Int, reading ? -1 : 1);
   wait_reading_process_input (sec, usec, read_kbd, display);
 
 
 #endif
 
   XSET (read_kbd, Lisp_Int, reading ? -1 : 1);
   wait_reading_process_input (sec, usec, read_kbd, display);
 
 
-#if 0 /* No wait_reading_process_input available.  */
+  /* wait_reading_process_input should always be available now; it is
+     simulated in a simple way on systems that don't support
+     subprocesses.  */
+#if 0
+  /* No wait_reading_process_input available.  */
   immediate_quit = 1;
   QUIT;
 
   immediate_quit = 1;
   QUIT;
 
@@ -1919,52 +2302,46 @@ sit_for (sec, usec, reading, display)
 }
 
 DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0,
 }
 
 DEFUN ("sit-for", Fsit_for, Ssit_for, 1, 3, 0,
-  "Perform redisplay, then wait for ARG seconds or until input is available.\n\
-Optional second arg non-nil means ARG counts in milliseconds.\n\
+  "Perform redisplay, then wait for SECONDS seconds or until input is available.\n\
+SECONDS may be a floating-point value, meaning that you can wait for a\n\
+fraction of a second.  Optional second arg MILLISECONDS specifies an\n\
+additional wait period, in milliseconds; this may be useful if your\n\
+Emacs was built without floating point support.\n\
+\(Not all operating systems support waiting for a fraction of a second.)\n\
 Optional third arg non-nil means don't redisplay, just wait for input.\n\
 Redisplay is preempted as always if input arrives, and does not happen\n\
 if input is available before it starts.\n\
 Value is t if waited the full time with no input arriving.")
 Optional third arg non-nil means don't redisplay, just wait for input.\n\
 Redisplay is preempted as always if input arrives, and does not happen\n\
 if input is available before it starts.\n\
 Value is t if waited the full time with no input arriving.")
-  (arg, millisec, nodisp)
-     Lisp_Object arg, millisec, nodisp;
+  (seconds, milliseconds, nodisp)
+     Lisp_Object seconds, milliseconds, nodisp;
 {
 {
-  int usec = 0;
-  int sec;
+  int sec, usec;
 
 
-  CHECK_NUMBER (arg, 0);
-  sec = XINT (arg);
+  if (NILP (milliseconds))
+    XSET (milliseconds, Lisp_Int, 0);
+  else
+    CHECK_NUMBER (milliseconds, 1);
+  usec = XINT (milliseconds) * 1000;
 
 
-  if (!NILP (millisec))
-    {
-#ifndef EMACS_HAS_USECS
-      error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
+#ifdef LISP_FLOAT_TYPE
+  {
+    double duration = extract_float (seconds);
+    sec = (int) duration;
+    usec += (duration - sec) * 1000000;
+  }
 #else
 #else
-      usec = (sec % 1000) * 1000;
-      sec /= 1000;
+  CHECK_NUMBER (seconds, 0);
+  sec = XINT (seconds);
 #endif
 #endif
-    }
-
-  return sit_for (sec, usec, 0, NILP (nodisp));
-}
-
-DEFUN ("sleep-for-millisecs", Fsleep_for_millisecs, Ssleep_for_millisecs,
-  1, 1, 0,
-  "Pause, without updating display, for ARG milliseconds.")
-  (arg)
-     Lisp_Object arg;
-{
-  Lisp_Object zero;
 
 #ifndef EMACS_HAS_USECS
 
 #ifndef EMACS_HAS_USECS
-  error ("sleep-for-millisecs not supported on %s", SYSTEM_TYPE);
-#else
-  CHECK_NUMBER (arg, 0);
+  if (usec != 0 && sec == 0)
+    error ("millisecond `sit-for' not supported on %s", SYSTEM_TYPE);
+#endif
 
 
-  XFASTINT (zero) = 0;
-  wait_reading_process_input (XINT (arg) / 1000, XINT (arg) % 1000 * 1000,
-                             zero, 0);
-  return Qnil;
-#endif /* EMACS_HAS_USECS */
+  if (NILP (nodisp))
+    prepare_menu_bars ();
+  return sit_for (sec, usec, 0, NILP (nodisp));
 }
 \f
 char *terminal_type;
 }
 \f
 char *terminal_type;
@@ -1985,20 +2362,29 @@ init_display ()
   cursor_in_echo_area = 0;
   terminal_type = (char *) 0;
 
   cursor_in_echo_area = 0;
   terminal_type = (char *) 0;
 
-  /* If the DISPLAY environment variable is set, try to use X, and
-     die with an error message if that doesn't work.  */
+  /* Now is the time to initialize this; it's used by init_sys_modes
+     during startup.  */
+  Vwindow_system = Qnil;
 
 
-  /* Check if we're using a window system here before trying to
-     initialize the terminal.  If we check the terminal first,
+  /* If the user wants to use a window system, we shouldn't bother
+     initializing the terminal.  This is especially important when the
+     terminal is so dumb that emacs gives up before and doesn't bother
+     using the window system.
 
 
-     If someone has indicated that they want
-     to use a window system, we shouldn't bother initializing the
-     terminal.  This is especially important when the terminal is so
-     dumb that emacs gives up before  and doesn't bother using the window
-     system.  */
+     If the DISPLAY environment variable is set, try to use X, and die
+     with an error message if that doesn't work.  */
 
 #ifdef HAVE_X_WINDOWS
 
 #ifdef HAVE_X_WINDOWS
-  if (!inhibit_window_system && (display_arg || getenv ("DISPLAY")))
+  if (! display_arg)
+    {
+#ifdef VMS
+      display_arg = (getenv ("DECW$DISPLAY") != 0);
+#else
+      display_arg = (getenv ("DISPLAY") != 0);
+#endif
+    }
+
+  if (!inhibit_window_system && display_arg)
     {
       Vwindow_system = intern ("x");
 #ifdef HAVE_X11
     {
       Vwindow_system = intern ("x");
 #ifdef HAVE_X11
@@ -2072,14 +2458,18 @@ syms_of_display ()
   defsubr (&Sredraw_frame);
 #endif
   defsubr (&Sredraw_display);
   defsubr (&Sredraw_frame);
 #endif
   defsubr (&Sredraw_display);
+  defsubr (&Sframe_or_buffer_changed_p);
   defsubr (&Sopen_termscript);
   defsubr (&Sding);
   defsubr (&Ssit_for);
   defsubr (&Ssleep_for);
   defsubr (&Ssend_string_to_terminal);
 
   defsubr (&Sopen_termscript);
   defsubr (&Sding);
   defsubr (&Ssit_for);
   defsubr (&Ssleep_for);
   defsubr (&Ssend_string_to_terminal);
 
+  frame_and_buffer_state = Fmake_vector (make_number (1), Qlambda);
+  staticpro (&frame_and_buffer_state);
+
   DEFVAR_INT ("baud-rate", &baud_rate,
   DEFVAR_INT ("baud-rate", &baud_rate,
-    "The output baud rate of the terminal.\n\
+    "*The output baud rate of the terminal.\n\
 On most systems, changing this value will affect the amount of padding\n\
 and the other strategic decisions made during redisplay.");
   DEFVAR_BOOL ("inverse-video", &inverse_video,
 On most systems, changing this value will affect the amount of padding\n\
 and the other strategic decisions made during redisplay.");
   DEFVAR_BOOL ("inverse-video", &inverse_video,
@@ -2107,7 +2497,7 @@ Each element can be:\n\
  integer: a glyph code which this glyph is an alias for.\n\
  string: output this glyph using that string (not impl. in X windows).\n\
  nil: this glyph mod 256 is char code to output,\n\
  integer: a glyph code which this glyph is an alias for.\n\
  string: output this glyph using that string (not impl. in X windows).\n\
  nil: this glyph mod 256 is char code to output,\n\
-    and this glyph / 256 is face code for X windows (see `x-set-face').");
+    and this glyph / 256 is face code for X windows (see `face-id').");
   Vglyph_table = Qnil;
 
   DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
   Vglyph_table = Qnil;
 
   DEFVAR_LISP ("standard-display-table", &Vstandard_display_table,
@@ -2124,4 +2514,3 @@ See `buffer-display-table' for more information.");
       Vwindow_system_version = Qnil;
     }
 }
       Vwindow_system_version = Qnil;
     }
 }
-