]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(merge_properties_sticky): Preserve original order of properties.
[gnu-emacs] / src / xdisp.c
index 2b93311023df0df1d3cf677d37c145d12d2f4314..2fd2e6ee629059f77fa272bc41d7e85b8b421150 100644 (file)
@@ -1,5 +1,5 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985, 86, 87, 88, 93, 94 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -18,7 +18,7 @@ along with GNU Emacs; see the file COPYING.  If not, write to
 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 
-#include "config.h"
+#include <config.h>
 #include <stdio.h>
 /*#include <ctype.h>*/
 #undef NULL
@@ -33,6 +33,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "macros.h"
 #include "disptab.h"
 #include "termhooks.h"
+#include "intervals.h"
+
+#ifdef USE_X_TOOLKIT
+extern void set_frame_menubar ();
+#endif
 
 extern int interrupt_input;
 extern int command_loop_level;
@@ -92,6 +97,9 @@ static Lisp_Object last_arrow_position, last_arrow_string;
 /* Nonzero if overlay arrow has been displayed once in this window.  */
 static int overlay_arrow_seen;
 
+/* Nonzero means highlight the region even in nonselected windows.  */
+static int highlight_nonselected_windows;
+
 /* If cursor motion alone moves point off frame,
    Try scrolling this many lines up or down if that will bring it back.  */
 int scroll_step;
@@ -120,6 +128,8 @@ static void echo_area_display ();
 void mark_window_display_accurate ();
 static void redisplay_windows ();
 static void redisplay_window ();
+static void update_menu_bars ();
+static void update_menu_bar ();
 static void try_window ();
 static int try_window_id ();
 static struct position *display_text_line ();
@@ -143,6 +153,9 @@ int minibuf_prompt_width;
    It overrides the minibuf_prompt as well as the buffer.  */
 char *echo_area_glyphs;
 
+/* This is the length of the message in echo_area_glyphs.  */
+int echo_area_glyphs_length;
+
 /* true iff we should redraw the mode lines on the next redisplay */
 int update_mode_lines;
 
@@ -178,6 +191,7 @@ int line_number_display_limit;
 \f
 /* Specify m, a string, as a message in the minibuf.  If m is 0, clear out
    any existing message, and let the minibuffer text show through.  */
+
 void
 message1 (m)
      char *m;
@@ -210,7 +224,10 @@ message1 (m)
 #endif
 
       if (m)
-       echo_area_glyphs = m;
+       {
+         echo_area_glyphs = m;
+         echo_area_glyphs_length = strlen (m);
+       }
       else
        echo_area_glyphs = previous_echo_glyphs = 0;
 
@@ -221,6 +238,69 @@ message1 (m)
     }
 }
 
+/* Display an echo area message M with a specified length of LEN chars.
+   This way, null characters can be included.  */
+
+void
+message2 (m, len)
+     char *m;
+     int len;
+{
+  if (noninteractive)
+    {
+      if (noninteractive_need_newline)
+       putc ('\n', stderr);
+      noninteractive_need_newline = 0;
+      fwrite (m, len, 1, stderr);
+      if (cursor_in_echo_area == 0)
+       fprintf (stderr, "\n");
+      fflush (stderr);
+    }
+  /* A null message buffer means that the frame hasn't really been
+     initialized yet.  Error messages get reported properly by
+     cmd_error, so this must be just an informative message; toss it.  */
+  else if (INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
+    {
+#ifdef MULTI_FRAME
+      Lisp_Object minibuf_frame;
+
+      choose_minibuf_frame ();
+      minibuf_frame = WINDOW_FRAME (XWINDOW (minibuf_window));
+      FRAME_SAMPLE_VISIBILITY (XFRAME (minibuf_frame));
+      if (FRAME_VISIBLE_P (selected_frame)
+         && ! FRAME_VISIBLE_P (XFRAME (minibuf_frame)))
+       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (minibuf_window)));
+#endif
+
+      if (m)
+       {
+         echo_area_glyphs = m;
+         echo_area_glyphs_length = len;
+       }
+      else
+       echo_area_glyphs = previous_echo_glyphs = 0;
+
+      do_pending_window_change ();
+      echo_area_display ();
+      update_frame (XFRAME (XWINDOW (minibuf_window)->frame), 1, 1);
+      do_pending_window_change ();
+    }
+}
+
+/* Truncate what will be displayed in the echo area
+   the next time we display it--but don't redisplay it now.  */
+
+void
+truncate_echo_area (len)
+     int len;
+{
+  /* A null message buffer means that the frame hasn't really been
+     initialized yet.  Error messages get reported properly by
+     cmd_error, so this must be just an informative message; toss it.  */
+  if (!noninteractive && INTERACTIVE && FRAME_MESSAGE_BUF (selected_frame))
+    echo_area_glyphs_length = len;
+}
+
 /* Nonzero if FRAME_MESSAGE_BUF (selected_frame) is being used by print;
    zero if being used by message.  */
 int message_buf_print;
@@ -265,22 +345,21 @@ message (m, a1, a2, a3)
        {
          if (m)
            {
-             {
+             int len;
 #ifdef NO_ARG_ARRAY
-               int a[3];
-               a[0] = a1;
-               a[1] = a2;
-               a[2] = a3;
+             int a[3];
+             a[0] = a1;
+             a[1] = a2;
+             a[2] = a3;
 
-               doprnt (FRAME_MESSAGE_BUF (echo_frame),
-                       FRAME_WIDTH (echo_frame), m, 0, 3, a);
+             len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+                           FRAME_WIDTH (echo_frame), m, 0, 3, a);
 #else
-               doprnt (FRAME_MESSAGE_BUF (echo_frame),
-                       FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
+             len = doprnt (FRAME_MESSAGE_BUF (echo_frame),
+                           FRAME_WIDTH (echo_frame), m, 0, 3, &a1);
 #endif /* NO_ARG_ARRAY */
-             }
 
-             message1 (FRAME_MESSAGE_BUF (echo_frame));
+             message2 (FRAME_MESSAGE_BUF (echo_frame), len);
            }
          else
            message1 (0);
@@ -309,7 +388,7 @@ echo_area_display ()
 
   if (frame_garbaged)
     {
-      Fredraw_display ();
+      redraw_garbaged_frames ();
       frame_garbaged = 0;
     }
 
@@ -319,6 +398,7 @@ echo_area_display ()
       get_display_line (f, vpos, 0);
       display_string (XWINDOW (minibuf_window), vpos,
                      echo_area_glyphs ? echo_area_glyphs : "",
+                     echo_area_glyphs ? echo_area_glyphs_length : -1,
                      0, 0, 0, FRAME_WIDTH (f));
 
       /* If desired cursor location is on this line, put it at end of text */
@@ -329,11 +409,12 @@ echo_area_display ()
       {
        int i;
 
-       for (i = vpos + 1; i < vpos + XWINDOW (minibuf_window)->height; i++)
+       for (i = vpos + 1;
+            i < vpos + XFASTINT (XWINDOW (minibuf_window)->height); i++)
          {
            get_display_line (f, i, 0);
            display_string (XWINDOW (minibuf_window), vpos,
-                           "", 0, 0, 0, FRAME_WIDTH (f));
+                           "", 0, 0, 0, 0, FRAME_WIDTH (f));
          }
       }
     }
@@ -346,6 +427,77 @@ echo_area_display ()
   previous_echo_glyphs = echo_area_glyphs;
 }
 \f
+/* Prepare for redisplay by updating menu-bar item lists when appropriate.
+   This can't be done in `redisplay' itself because it can call eval.  */
+
+void
+prepare_menu_bars ()
+{
+  register struct window *w = XWINDOW (selected_window);
+  int all_windows;
+
+  if (noninteractive)
+    return;
+
+  /* Set the visible flags for all frames.
+     Do this before checking for resized or garbaged frames; they want
+     to know if their frames are visible.
+     See the comment in frame.h for FRAME_SAMPLE_VISIBILITY.  */
+  {
+    Lisp_Object tail, frame;
+
+    FOR_EACH_FRAME (tail, frame)
+      FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
+  }
+
+  /* Notice any pending interrupt request to change frame size.  */
+  do_pending_window_change ();
+
+  if (frame_garbaged)
+    {
+      redraw_garbaged_frames ();
+      frame_garbaged = 0;
+    }
+
+  if (clip_changed || windows_or_buffers_changed)
+    update_mode_lines++;
+
+  /* Detect case that we need to write a star in the mode line.  */
+  if (XFASTINT (w->last_modified) < MODIFF
+      && XFASTINT (w->last_modified) <= current_buffer->save_modified)
+    {
+      w->update_mode_line = Qt;
+      if (buffer_shared > 1)
+       update_mode_lines++;
+    }
+
+  all_windows = update_mode_lines || buffer_shared > 1;
+
+  /* If specs for an arrow have changed, do thorough redisplay
+     to ensure we remove any arrow that should no longer exist.  */
+  if (! EQ (Voverlay_arrow_position, last_arrow_position)
+      || ! EQ (Voverlay_arrow_string, last_arrow_string))
+    all_windows = 1, clip_changed = 1;
+
+  /* Update the menu bar item lists, if appropriate.
+     This has to be done before any actual redisplay
+     or generation of display lines.  */
+  if (all_windows)
+    {
+      Lisp_Object tail, frame;
+
+      FOR_EACH_FRAME (tail, frame)
+       {
+         FRAME_PTR f = XFRAME (frame);
+
+         if (FRAME_VISIBLE_P (f))
+           update_menu_bars (FRAME_ROOT_WINDOW (f));
+       }
+    }
+  else if (FRAME_VISIBLE_P (selected_frame))
+    update_menu_bar (selected_window);
+}
+\f
 /* Do a frame update, taking possible shortcuts into account.
    This is the main external entry point for redisplay.
 
@@ -353,11 +505,14 @@ echo_area_display ()
    message is no longer requested, we clear the echo area
    or bring back the minibuffer if that is in use.
 
-   Everyone would like to have a hook here to call eval,
-   but that cannot be done safely without a lot of changes elsewhere.
-   This can be called from signal handlers; with alarms set up;
+   Do not call eval from within this function.
+   Calls to eval after the call to echo_area_display would confuse
+   the display_line mechanism and would cause a crash.
+   Calls to eval before that point will work most of the time,
+   but can still lose, because  this function
+   can be called from signal handlers; with alarms set up;
    or with synchronous processes running.
-   See the function `echo' in keyboard.c.
+
    See Fcall_process; if you called it from here, it could be
    entered recursively.  */
 
@@ -391,20 +546,10 @@ redisplay ()
 
   if (frame_garbaged)
     {
-      Fredraw_display ();
+      redraw_garbaged_frames ();
       frame_garbaged = 0;
     }
 
-  /* Normally the message* functions will have already displayed and
-     updated the echo area, but the frame may have been trashed, or
-     the update may have been preempted, so display the echo area
-     again here.  */
-  if (echo_area_glyphs || previous_echo_glyphs)
-    {
-      echo_area_display ();
-      must_finish = 1;
-    }
-
   if (clip_changed || windows_or_buffers_changed)
     update_mode_lines++;
 
@@ -427,6 +572,25 @@ redisplay ()
       || ! EQ (Voverlay_arrow_string, last_arrow_string))
     all_windows = 1, clip_changed = 1;
 
+  /* Normally the message* functions will have already displayed and
+     updated the echo area, but the frame may have been trashed, or
+     the update may have been preempted, so display the echo area
+     again here.  */
+  if (echo_area_glyphs || previous_echo_glyphs)
+    {
+      echo_area_display ();
+      must_finish = 1;
+    }
+
+  /* If showing region, and mark has changed, must redisplay whole window.  */
+  if (((!NILP (Vtransient_mark_mode)
+       && !NILP (XBUFFER (w->buffer)->mark_active))
+       != !NILP (w->region_showing))
+      || (!NILP (w->region_showing)
+         && !EQ (w->region_showing,
+                 Fmarker_position (XBUFFER (w->buffer)->mark))))
+    this_line_bufpos = -1;
+
   tlbufpos = this_line_bufpos;
   tlendpos = this_line_endpos;
   if (!all_windows && tlbufpos > 0 && NILP (w->update_mode_line)
@@ -486,7 +650,10 @@ redisplay ()
            }
          goto update;
        }
-      else
+      /* If highlighting the region, we can't just move the cursor.  */
+      else if (! (!NILP (Vtransient_mark_mode)
+                 && !NILP (current_buffer->mark_active))
+              && NILP (w->region_showing))
        {
          pos = *compute_motion (tlbufpos, 0,
                                 XINT (w->hscroll) ? 1 - XINT (w->hscroll) : 0,
@@ -699,10 +866,20 @@ mark_window_display_accurate (window, flag)
       w = XWINDOW (window);
 
       if (!NILP (w->buffer))
-       XFASTINT (w->last_modified)
-         = !flag ? 0
-           : XBUFFER (w->buffer) == current_buffer
-             ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
+       {
+         XFASTINT (w->last_modified)
+           = !flag ? 0
+             : XBUFFER (w->buffer) == current_buffer
+               ? MODIFF : BUF_MODIFF (XBUFFER (w->buffer));
+
+         /* Record if we are showing a region, so can make sure to
+            update it fully at next redisplay.  */
+         w->region_showing = (!NILP (Vtransient_mark_mode)
+                              && !NILP (XBUFFER (w->buffer)->mark_active)
+                              ? Fmarker_position (XBUFFER (w->buffer)->mark)
+                              : Qnil);
+       }
+
       w->window_end_valid = Qt;
       w->update_mode_line = Qnil;
 
@@ -725,8 +902,85 @@ mark_window_display_accurate (window, flag)
     }
 }
 \f
+/* Update the menu bar item lists for WINDOW
+   and its subwindows and siblings.
+   This has to be done before we start to fill in any display lines,
+   because it can call eval.  */
+
+static void
+update_menu_bars (window)
+     Lisp_Object window;
+{
+  for (; !NILP (window); window = XWINDOW (window)->next)
+    update_menu_bar (window, 0);
+}
+
+/* Update the menu bar item list for window WINDOW and its subwindows.  */
+
+static void
+update_menu_bar (window, just_this_one)
+     Lisp_Object window;
+     int just_this_one;
+{
+  register struct window *w = XWINDOW (window);
+  struct buffer *old = current_buffer;
+  FRAME_PTR f = XFRAME (WINDOW_FRAME (w));
+
+  /* If this is a combination window, do its children; that's all.  */
+
+  if (!NILP (w->vchild))
+    {
+      update_menu_bars (w->vchild);
+      return;
+    }
+  if (!NILP (w->hchild))
+    {
+      update_menu_bars (w->hchild);
+      return;
+    }
+  if (NILP (w->buffer))
+    abort ();
+  
+  if (update_mode_lines)
+    w->update_mode_line = Qt;
+
+  /* When we reach a frame's selected window, redo the frame's menu bar.  */
+  if (!NILP (w->update_mode_line)
+#ifdef USE_X_TOOLKIT
+      && FRAME_EXTERNAL_MENU_BAR (f) 
+#else
+      && FRAME_MENU_BAR_LINES (f) > 0
+#endif
+      && EQ (FRAME_SELECTED_WINDOW (f), window))
+    {
+      /* If the user has switched buffers or windows, we need to
+        recompute to reflect the new bindings.  But we'll
+        recompute when update_mode_lines is set too; that means
+        that people can use force-mode-line-update to request
+        that the menu bar be recomputed.  The adverse effect on
+        the rest of the redisplay algorithm is about the same as
+        windows_or_buffers_changed anyway.  */
+      if (windows_or_buffers_changed
+         || update_mode_lines
+         || (XFASTINT (w->last_modified) < MODIFF
+             && (XFASTINT (w->last_modified)
+                 <= XBUFFER (w->buffer)->save_modified)))
+       {
+         struct buffer *prev = current_buffer;
+         current_buffer = XBUFFER (w->buffer);
+         FRAME_MENU_BAR_ITEMS (f) = menu_bar_items ();
+         current_buffer = prev;
+#ifdef USE_X_TOOLKIT
+         set_frame_menubar (f);
+#endif /* USE_X_TOOLKIT */
+       }
+    }
+}
+\f
 int do_id = 1;
 
+/* Redisplay WINDOW and its subwindows and siblings.  */
+
 static void
 redisplay_windows (window)
      Lisp_Object window;
@@ -735,6 +989,8 @@ redisplay_windows (window)
     redisplay_window (window, 0);
 }
 
+/* Redisplay window WINDOW and its subwindows.  */
+
 static void
 redisplay_window (window, just_this_one)
      Lisp_Object window;
@@ -790,7 +1046,7 @@ redisplay_window (window, just_this_one)
          for (i = 0; i < height; i++)
            {
              get_display_line (f, vpos + i, 0);
-             display_string (w, vpos + i, "", 0, 0, 0, width);
+             display_string (w, vpos + i, "", 0, 0, 0, 0, width);
            }
          
          goto finish_scroll_bars;
@@ -849,6 +1105,7 @@ redisplay_window (window, just_this_one)
       try_window (window, startp);
       if (cursor_vpos < 0)
        {
+         /* ??? What should happen here if highlighting a region?  */
          /* If point does not appear, move point so it does appear */
          pos = *compute_motion (startp, 0,
                                ((EQ (window, minibuf_window) && startp == 1)
@@ -859,11 +1116,12 @@ redisplay_window (window, just_this_one)
                                - (1 << (SHORTBITS - 1)),
                                width, hscroll, pos_tab_offset (w, startp));
          SET_PT (pos.bufpos);
-         if (w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
+         if (w != XWINDOW (selected_window))
            Fset_marker (w->pointm, make_number (point), Qnil);
          else
            {
-             lpoint = point;
+             if (current_buffer == old)
+               lpoint = point;
              FRAME_CURSOR_X (f) = max (0, pos.hpos) + XFASTINT (w->left);
              FRAME_CURSOR_Y (f) = pos.vpos + XFASTINT (w->top);
            }
@@ -884,6 +1142,9 @@ redisplay_window (window, just_this_one)
   if (XFASTINT (w->last_modified) >= MODIFF
       && point >= startp && !clip_changed
       && (just_this_one || XFASTINT (w->width) == FRAME_WIDTH (f))
+      /* Can't use this case if highlighting a region.  */
+      && !(!NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active))
+      && NILP (w->region_showing)
       && !EQ (window, minibuf_window))
     {
       pos = *compute_motion (startp, 0, (hscroll ? 1 - hscroll : 0),
@@ -922,10 +1183,16 @@ redisplay_window (window, just_this_one)
   else if (just_this_one && !MINI_WINDOW_P (w)
           && point >= startp
           && XFASTINT (w->last_modified)
+          /* or else vmotion on first line won't work.  */
+          && ! NILP (w->start_at_line_beg)
           && ! EQ (w->window_end_valid, Qnil)
           && do_id && !clip_changed
           && !blank_end_of_window
           && XFASTINT (w->width) == FRAME_WIDTH (f)
+          /* Can't use this case if highlighting a region.  */
+          && !(!NILP (Vtransient_mark_mode)
+               && !NILP (current_buffer->mark_active))
+          && NILP (w->region_showing)
           && EQ (last_arrow_position, Voverlay_arrow_position)
           && EQ (last_arrow_string, Voverlay_arrow_string)
           && (tem = try_window_id (FRAME_SELECTED_WINDOW (f)))
@@ -1021,7 +1288,11 @@ done:
 
   /* When we reach a frame's selected window, redo the frame's menu bar.  */
   if (!NILP (w->update_mode_line)
+#ifdef USE_X_TOOLKIT
+      && FRAME_EXTERNAL_MENU_BAR (f) 
+#else
       && FRAME_MENU_BAR_LINES (f) > 0
+#endif
       && EQ (FRAME_SELECTED_WINDOW (f), window))
     display_menu_bar (w);
 
@@ -1031,21 +1302,29 @@ done:
       int start, end, whole;
 
       /* Calculate the start and end positions for the current window.
+        At some point, it would be nice to choose between scrollbars
+        which reflect the whole buffer size, with special markers
+        indicating narrowing, and scrollbars which reflect only the
+        visible region.
+
         Note that minibuffers sometimes aren't displaying any text.  */
       if (! MINI_WINDOW_P (w)
          || (w == XWINDOW (minibuf_window) && ! echo_area_glyphs))
        {
-         start = startp;
+         whole = ZV - BEGV;
+         start = startp - BEGV;
          /* I don't think this is guaranteed to be right.  For the
             moment, we'll pretend it is.  */
-         end = Z - XINT (w->window_end_pos);
-         whole = Z - BEG;
+         end = (Z - XINT (w->window_end_pos)) - BEGV;
+
+         if (end < start) end = start;
+         if (whole < (end - start)) whole = end - start;
        }
       else
        start = end = whole = 0;
 
       /* Indicate what this scroll bar ought to be displaying now.  */
-      (*set_vertical_scroll_bar_hook) (w, end - start, whole, start - 1);
+      (*set_vertical_scroll_bar_hook) (w, end - start, whole, start);
 
       /* Note that we actually used the scroll bar attached to this window,
         so it shouldn't be deleted at the end of redisplay.  */
@@ -1087,7 +1366,10 @@ try_window (window, pos)
       if (pos != val.bufpos)
        last_text_vpos
          /* Next line, unless prev line ended in end of buffer with no cr */
-         = vpos - (val.vpos && FETCH_CHAR (val.bufpos - 1) != '\n');
+         = vpos - (val.vpos && (FETCH_CHAR (val.bufpos - 1) != '\n'
+                                || ! NILP (Fget_text_property (val.bufpos-1,
+                                                               Qinvisible,
+                                                               Fcurrent_buffer ()))));
       pos = val.bufpos;
     }
 
@@ -1143,13 +1425,13 @@ try_window_id (window)
   if (Z - GPT < end_unchanged)
     end_unchanged = Z - GPT;
 
-  if (beg_unchanged + 1 < start)
+  if (beg_unchanged + BEG < start)
     return 0;                  /* Give up if changes go above top of window */
 
   /* Find position before which nothing is changed.  */
   bp = *compute_motion (start, 0, lmargin,
-                       beg_unchanged + 1, height + 1, 0, width, hscroll,
-                       pos_tab_offset (w, start));
+                       min (ZV, beg_unchanged + BEG), height + 1, 0,
+                       width, hscroll, pos_tab_offset (w, start));
   if (bp.vpos >= height)
     {
       if (point < bp.bufpos && !bp.contin)
@@ -1557,9 +1839,11 @@ copy_rope (t, s, from, face)
 
   while (n--)
     {
-      if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (*f),
-                                  (GLYPH_FACE (*f)
-                                   ? GLYPH_FACE (*f)
+      int glyph = XFASTINT (*f);
+
+      if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph),
+                                  (GLYPH_FACE (glyph)
+                                   ? GLYPH_FACE (glyph)
                                    : face));
       ++t;
       ++f;
@@ -1583,9 +1867,11 @@ copy_part_of_rope (t, s, from, len, face)
 
   while (n--)
     {
-      if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (*f),
-                                  (GLYPH_FACE (*f)
-                                   ? GLYPH_FACE (*f)
+      int glyph = XFASTINT (*f);
+
+      if (t >= s) *t = MAKE_GLYPH (GLYPH_CHAR (glyph),
+                                  (GLYPH_FACE (glyph)
+                                   ? GLYPH_FACE (glyph)
                                    : face));
       ++t;
       ++f;
@@ -1625,7 +1911,7 @@ display_text_line (w, start, vpos, hpos, taboffset)
   register unsigned char *p;
   GLYPH *endp;
   register GLYPH *startp;
-  register GLYPH *p1prev;
+  register GLYPH *p1prev = 0;
   FRAME_PTR f = XFRAME (w->frame);
   int tab_width = XINT (current_buffer->tab_width);
   int ctl_arrow = !NILP (current_buffer->ctl_arrow);
@@ -1638,6 +1924,12 @@ display_text_line (w, start, vpos, hpos, taboffset)
     || (truncate_partial_width_windows
        && XFASTINT (w->width) < FRAME_WIDTH (f))
     || !NILP (current_buffer->truncate_lines);
+
+  /* 1 if we should highlight the region.  */
+  int highlight_region
+    = !NILP (Vtransient_mark_mode) && !NILP (current_buffer->mark_active);
+  int region_beg, region_end;
+
   int selective
     = XTYPE (current_buffer->selective_display) == Lisp_Int
       ? XINT (current_buffer->selective_display)
@@ -1669,6 +1961,11 @@ display_text_line (w, start, vpos, hpos, taboffset)
      to overlays or text property changes.  */
   int next_face_change;
 
+#ifdef USE_TEXT_PROPERTIES
+  /* The next location where the `invisible' property changes */
+  int next_invisible;
+#endif
+  
   /* The face we're currently using.  */
   int current_face = 0;
 
@@ -1679,11 +1976,30 @@ display_text_line (w, start, vpos, hpos, taboffset)
   get_display_line (f, vpos, XFASTINT (w->left));
   if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
 
+  /* Show where to highlight the region.  */
+  if (highlight_region && XMARKER (current_buffer->mark)->buffer != 0
+      /* Maybe highlight only in selected window.  */
+      && (highlight_nonselected_windows
+         || w == XWINDOW (selected_window)))
+    {
+      region_beg = marker_position (current_buffer->mark);
+      if (PT < region_beg)
+       {
+         region_end = region_beg;
+         region_beg = PT;
+       }
+      else
+       region_end = PT;
+      w->region_showing = Qt;
+    }
+  else
+    region_beg = region_end = -1;
+
   if (MINI_WINDOW_P (w) && start == 1
       && vpos == XFASTINT (w->top))
     {
       if (minibuf_prompt)
-       hpos = display_string (w, vpos, minibuf_prompt, hpos,
+       hpos = display_string (w, vpos, minibuf_prompt, -1, hpos,
                               (!truncate ? continuer : truncator),
                               -1, -1);
       minibuf_prompt_width = hpos;
@@ -1708,6 +2024,9 @@ display_text_line (w, start, vpos, hpos, taboffset)
      or at face change.  */
   pause = pos;
   next_face_change = pos;
+#ifdef USE_TEXT_PROPERTIES
+  next_invisible = pos;
+#endif
   while (p1 < endp)
     {
       p1prev = p1;
@@ -1725,16 +2044,55 @@ display_text_line (w, start, vpos, hpos, taboffset)
              cursor_hpos = p1 - startp;
            }
 
+#ifdef USE_TEXT_PROPERTIES
+         /* if the `invisible' property is set to t, we can skip to
+            the next property change */
+         while (pos == next_invisible && pos < end)
+           {
+             Lisp_Object position, limit, endpos, prop;
+             XFASTINT (position) = pos;
+             prop = Fget_text_property (position, Qinvisible,
+                                        Fcurrent_buffer ());
+             /* This is just an estimate to give reasonable
+                performance; nothing should go wrong if it is too small.  */
+             XFASTINT (limit) = pos + 50;
+             endpos
+               = Fnext_single_property_change (position, Qinvisible,
+                                               Fcurrent_buffer (), limit);
+             if (INTEGERP (endpos))
+               next_invisible = XINT (endpos);
+             else
+               next_invisible = end;
+             if (! NILP (prop))
+               {
+                 if (pos < point && next_invisible >= point)
+                   {
+                     cursor_vpos = vpos;
+                     cursor_hpos = p1 - startp;
+                   }
+                 pos = next_invisible;
+               }
+           }
+         if (pos >= end)
+           break;
+#endif
+
 #ifdef HAVE_X_WINDOWS
          /* Did we hit a face change?  Figure out what face we should
             use now.  We also hit this the first time through the
             loop, to see what face we should start with.  */
-         if (pos == next_face_change)
-           current_face = compute_char_face (f, w, pos, &next_face_change);
+         if (pos >= next_face_change && FRAME_X_P (f))
+           current_face = compute_char_face (f, w, pos,
+                                             region_beg, region_end,
+                                             &next_face_change, pos + 50);
 #endif
 
          pause = end;
 
+#ifdef USE_TEXT_PROPERTIES       
+         if (pos < next_invisible && next_invisible < pause)
+           pause = next_invisible;
+#endif
          if (pos < next_face_change && next_face_change < pause)
            pause = next_face_change;
 
@@ -1775,6 +2133,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
              copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
+#if 1
+         /* Draw the face of the newline character as extending all the 
+            way to the end of the frame line.  */
+         if (current_face)
+           while (p1 < endp)
+             *p1++ = MAKE_GLYPH (' ', current_face);
+#endif
          break;
        }
       else if (c == '\t')
@@ -1801,6 +2166,13 @@ display_text_line (w, start, vpos, hpos, taboffset)
              copy_part_of_rope (p1prev, p1prev, invis_vector_contents,
                                 (p1 - p1prev), current_face);
            }
+#if 1
+         /* Draw the face of the newline character as extending all the 
+            way to the end of the frame line.  */
+         if (current_face)
+           while (p1 < endp)
+             *p1++ = MAKE_GLYPH (' ', current_face);
+#endif
          break;
        }
       else if (dp != 0 && XTYPE (DISP_CHAR_VECTOR (dp, c)) == Lisp_Vector)
@@ -1851,10 +2223,16 @@ display_text_line (w, start, vpos, hpos, taboffset)
   /* by backing up over it */
   if (p1 > endp)
     {
-      /* Start the next line with that same character */
-      pos--;
-      /* but at a negative hpos, to skip the columns output on this line.  */
-      val.hpos += p1prev - endp;
+      /* Don't back up if we never actually displayed any text.
+        This occurs when the minibuffer prompt takes up the whole line.  */
+      if (p1prev)
+       {
+         /* Start the next line with that same character */
+         pos--;
+         /* but at negative hpos, to skip the columns output on this line.  */
+         val.hpos += p1prev - endp;
+       }
+
       /* Keep in this line everything up to the continuation column.  */
       p1 = endp;
     }
@@ -1968,14 +2346,17 @@ display_text_line (w, start, vpos, hpos, taboffset)
       unsigned char *p = XSTRING (Voverlay_arrow_string)->data;
       int i;
       int len = XSTRING (Voverlay_arrow_string)->size;
+      int arrow_end;
 
       if (len > width)
        len = width;
       for (i = 0; i < len; i++)
        startp[i] = p[i];
-      if (desired_glyphs->used[vpos] <
-         (len + startp - desired_glyphs->glyphs[vpos]))
-       desired_glyphs->used[vpos] = len + startp - desired_glyphs->glyphs[vpos];
+
+      /* Bug in SunOS 4.1.1 compiler requires this intermediate variable.  */
+      arrow_end = (startp - desired_glyphs->glyphs[vpos]) + len;
+      if (desired_glyphs->used[vpos] < arrow_end)
+       desired_glyphs->used[vpos] = arrow_end;
 
       overlay_arrow_seen = 1;
     }
@@ -1997,6 +2378,7 @@ display_menu_bar (w)
   int maxendcol = FRAME_WIDTH (f);
   int hpos = 0;
 
+#ifndef USE_X_TOOLKIT
   if (FRAME_MENU_BAR_LINES (f) <= 0)
     return;
 
@@ -2014,12 +2396,13 @@ display_menu_bar (w)
       if (hpos < maxendcol)
        hpos = display_string (XWINDOW (FRAME_ROOT_WINDOW (f)), vpos,
                               XSTRING (string)->data,
+                              XSTRING (string)->size,
                               hpos, 0, hpos, maxendcol);
       /* Put a gap of 3 spaces between items.  */
       if (hpos < maxendcol)
        {
          int hpos1 = hpos + 3;
-         hpos = display_string (w, vpos, "", hpos, 0,
+         hpos = display_string (w, vpos, "", 0, hpos, 0,
                                 min (hpos1, maxendcol), maxendcol);
        }
     }
@@ -2029,7 +2412,13 @@ display_menu_bar (w)
 
   /* Fill out the line with spaces.  */
   if (maxendcol > hpos)
-    hpos = display_string (w, vpos, "", hpos, 0, maxendcol, -1);
+    hpos = display_string (w, vpos, "", 0, hpos, 0, maxendcol, -1);
+
+  /* Clear the rest of the lines allocated to the menu bar.  */
+  vpos++;
+  while (vpos < FRAME_MENU_BAR_LINES (f))
+    get_display_line (f, vpos++, 0);
+#endif /* not USE_X_TOOLKIT */
 }
 \f
 /* Display the mode line for window w */
@@ -2140,7 +2529,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
            if (this - 1 != last)
              {
                register int lim = --this - last + hpos;
-               hpos = display_string (w, vpos, last, hpos, 0, hpos,
+               hpos = display_string (w, vpos, last, -1, hpos, 0, hpos,
                                       min (lim, maxendcol));
              }
            else /* c == '%' */
@@ -2169,6 +2558,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
                  hpos = display_string (w, vpos,
                                         decode_mode_spec (w, c,
                                                           maxendcol - hpos),
+                                        -1,
                                         hpos, 0, spec_width, maxendcol);
              }
          }
@@ -2190,6 +2580,7 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
               don't check for % within it.  */
            if (XTYPE (tem) == Lisp_String)
              hpos = display_string (w, vpos, XSTRING (tem)->data,
+                                    XSTRING (tem)->size,
                                     hpos, 0, minendcol, maxendcol);
            /* Give up right away for nil or t.  */
            else if (!EQ (tem, elt))
@@ -2279,13 +2670,13 @@ display_mode_element (w, vpos, hpos, depth, minendcol, maxendcol, elt)
 
     default:
     invalid:
-      return (display_string (w, vpos, "*invalid*", hpos, 0,
+      return (display_string (w, vpos, "*invalid*", -1, hpos, 0,
                              minendcol, maxendcol));
     }
 
  end:
   if (minendcol > hpos)
-    hpos = display_string (w, vpos, "", hpos, 0, minendcol, -1);
+    hpos = display_string (w, vpos, "", 0, hpos, 0, minendcol, -1);
   return hpos;
 }
 \f
@@ -2445,9 +2836,21 @@ decode_mode_spec (w, c, maxwidth)
       obj = Fget_buffer_process (Fcurrent_buffer ());
       if (NILP (obj))
        return "no process";
+#ifdef subprocesses
       obj = Fsymbol_name (Fprocess_status (obj));
+#endif
       break;
 
+    case 't':                  /* indicate TEXT or BINARY */
+#ifdef MSDOS
+      decode_mode_spec_buf[0]
+       = NILP (current_buffer->buffer_file_type) ? "T" : "B";
+      decode_mode_spec_buf[1] = 0;
+      return decode_mode_spec_buf;
+#else /* not MSDOS */
+      return "T";
+#endif /* not MSDOS */
+
     case 'p':
       {
        int pos = marker_position (w->start);
@@ -2562,6 +2965,7 @@ display_count_lines (from, limit, n, pos_ptr)
 /* Display STRING on one line of window W, starting at HPOS.
    Display at position VPOS.  Caller should have done get_display_line.
    If VPOS == -1, display it as the current frame's title.
+   LENGTH is the length of STRING, or -1 meaning STRING is null-terminated.
 
   TRUNCATE is GLYPH to display at end if truncated.  Zero for none.
 
@@ -2575,9 +2979,10 @@ display_count_lines (from, limit, n, pos_ptr)
   Returns ending hpos */
 
 static int
-display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
+display_string (w, vpos, string, length, hpos, truncate, mincol, maxcol)
      struct window *w;
      unsigned char *string;
+     int length;
      int vpos, hpos;
      GLYPH truncate;
      int mincol, maxcol;
@@ -2627,8 +3032,16 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
 
   while (p1 < end)
     {
+      if (length == 0)
+       break;
       c = *string++;
-      if (!c) break;
+      /* Specified length.  */
+      if (length >= 0)
+       length--;
+      /* Unspecified length (null-terminated string).  */
+      else if (c == 0)
+       break;
+
       if (c >= 040 && c < 0177
          && (dp == 0 || XTYPE (DISP_CHAR_VECTOR (dp, c)) != Lisp_Vector))
        {
@@ -2676,7 +3089,7 @@ display_string (w, vpos, string, hpos, truncate, mincol, maxcol)
        }
     }
 
-  if (c)
+  if (c && length > 0)
     {
       p1 = end;
       if (truncate) *p1++ = truncate;
@@ -2740,6 +3153,10 @@ If this is zero, point is always centered after it moves off frame.");
   DEFVAR_INT ("line-number-display-limit", &line_number_display_limit,
     "*Maximum buffer size for which line number should be displayed.");
   line_number_display_limit = 1000000;
+
+  DEFVAR_BOOL ("highlight-nonselected-windows", &highlight_nonselected_windows,
+    "*Non-nil means highlight region even in nonselected windows.");
+  highlight_nonselected_windows = 1;
 }
 
 /* initialize the window system */