Minor additional fix in the wake of bugs #13623 and 13626.
[bpt/emacs.git] / src / xdisp.c
index d663e56..ca3f968 100644 (file)
@@ -367,28 +367,6 @@ Lisp_Object Qcenter;
 static Lisp_Object Qmargin, Qpointer;
 static Lisp_Object Qline_height;
 
-/* These setters are used only in this file, so they can be private.  */
-static void
-wset_base_line_number (struct window *w, Lisp_Object val)
-{
-  w->base_line_number = val;
-}
-static void
-wset_base_line_pos (struct window *w, Lisp_Object val)
-{
-  w->base_line_pos = val;
-}
-static void
-wset_column_number_displayed (struct window *w, Lisp_Object val)
-{
-  w->column_number_displayed = val;
-}
-static void
-wset_region_showing (struct window *w, Lisp_Object val)
-{
-  w->region_showing = val;
-}
-
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Test if overflow newline into fringe.  Called with iterator IT
@@ -840,17 +818,17 @@ static void ensure_echo_area_buffers (void);
 static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object);
 static Lisp_Object with_echo_area_buffer_unwind_data (struct window *);
 static int with_echo_area_buffer (struct window *, int,
-                                  int (*) (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t),
-                                  ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
+                                  int (*) (ptrdiff_t, Lisp_Object),
+                                  ptrdiff_t, Lisp_Object);
 static void clear_garbaged_frames (void);
-static int current_message_1 (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
+static int current_message_1 (ptrdiff_t, Lisp_Object);
 static void pop_message (void);
-static int truncate_message_1 (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
-static void set_message (const char *, Lisp_Object, ptrdiff_t, int);
-static int set_message_1 (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
+static int truncate_message_1 (ptrdiff_t, Lisp_Object);
+static void set_message (Lisp_Object);
+static int set_message_1 (ptrdiff_t, Lisp_Object);
 static int display_echo_area (struct window *);
-static int display_echo_area_1 (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
-static int resize_mini_window_1 (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t);
+static int display_echo_area_1 (ptrdiff_t, Lisp_Object);
+static int resize_mini_window_1 (ptrdiff_t, Lisp_Object);
 static Lisp_Object unwind_redisplay (Lisp_Object);
 static int string_char_and_length (const unsigned char *, int *);
 static struct text_pos display_prop_end (struct it *, Lisp_Object,
@@ -1414,21 +1392,9 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
              Lisp_Object cpos = make_number (charpos);
              Lisp_Object spec = Fget_char_property (cpos, Qdisplay, Qnil);
              Lisp_Object string = string_from_display_spec (spec);
-             int newline_in_string = 0;
-
-             if (STRINGP (string))
-               {
-                 const char *s = SSDATA (string);
-                 const char *e = s + SBYTES (string);
-                 while (s < e)
-                   {
-                     if (*s++ == '\n')
-                       {
-                         newline_in_string = 1;
-                         break;
-                       }
-                   }
-               }
+             bool newline_in_string
+               = (STRINGP (string)
+                  && memchr (SDATA (string), '\n', SBYTES (string)));
              /* The tricky code below is needed because there's a
                 discrepancy between move_it_to and how we set cursor
                 when the display line ends in a newline from a
@@ -9014,6 +8980,9 @@ move_it_vertically_backward (struct it *it, int dy)
   struct it it2, it3;
   void *it2data = NULL, *it3data = NULL;
   ptrdiff_t start_pos;
+  int nchars_per_row
+    = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
+  ptrdiff_t pos_limit;
 
  move_further_back:
   eassert (dy >= 0);
@@ -9022,9 +8991,15 @@ move_it_vertically_backward (struct it *it, int dy)
 
   /* Estimate how many newlines we must move back.  */
   nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
+  if (it->line_wrap == TRUNCATE)
+    pos_limit = BEGV;
+  else
+    pos_limit = max (start_pos - nlines * nchars_per_row, BEGV);
 
-  /* Set the iterator's position that many lines back.  */
-  while (nlines-- && IT_CHARPOS (*it) > BEGV)
+  /* Set the iterator's position that many lines back.  But don't go
+     back more than NLINES full screen lines -- this wins a day with
+     buffers which have very long lines.  */
+  while (nlines-- && IT_CHARPOS (*it) > pos_limit)
     back_to_previous_visible_line_start (it);
 
   /* Reseat the iterator here.  When moving backward, we don't want
@@ -9255,6 +9230,9 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
       struct it it2;
       void *it2data = NULL;
       ptrdiff_t start_charpos, i;
+      int nchars_per_row
+       = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
+      ptrdiff_t pos_limit;
 
       /* Start at the beginning of the screen line containing IT's
         position.  This may actually move vertically backwards,
@@ -9263,9 +9241,14 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
       move_it_vertically_backward (it, 0);
       dvpos -= it->vpos;
 
-      /* Go back -DVPOS visible lines and reseat the iterator there.  */
+      /* Go back -DVPOS buffer lines, but no farther than -DVPOS full
+        screen lines, and reseat the iterator there.  */
       start_charpos = IT_CHARPOS (*it);
-      for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > BEGV; --i)
+      if (it->line_wrap == TRUNCATE)
+       pos_limit = BEGV;
+      else
+       pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
+      for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i)
        back_to_previous_visible_line_start (it);
       reseat (it, it->current.pos, 1);
 
@@ -9407,11 +9390,11 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
       bset_undo_list (current_buffer, Qt);
 
       oldpoint = message_dolog_marker1;
-      set_marker_restricted (oldpoint, make_number (PT), Qnil);
+      set_marker_restricted_both (oldpoint, Qnil, PT, PT_BYTE);
       oldbegv = message_dolog_marker2;
-      set_marker_restricted (oldbegv, make_number (BEGV), Qnil);
+      set_marker_restricted_both (oldbegv, Qnil, BEGV, BEGV_BYTE);
       oldzv = message_dolog_marker3;
-      set_marker_restricted (oldzv, make_number (ZV), Qnil);
+      set_marker_restricted_both (oldzv, Qnil, ZV, ZV_BYTE);
       GCPRO1 (old_deactivate_mark);
 
       if (PT == Z)
@@ -9462,13 +9445,14 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
            }
        }
       else if (nbytes)
-       insert_1 (m, nbytes, 1, 0, 0);
+       insert_1_both (m, chars_in_text (msg, nbytes), nbytes, 1, 0, 0);
 
       if (nlflag)
        {
          ptrdiff_t this_bol, this_bol_byte, prev_bol, prev_bol_byte;
          printmax_t dups;
-         insert_1 ("\n", 1, 1, 0, 0);
+
+         insert_1_both ("\n", 1, 1, 1, 0, 0);
 
          scan_newline (Z, Z_BYTE, BEG, BEG_BYTE, -2, 0);
          this_bol = PT;
@@ -9497,7 +9481,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, int nlflag, int multibyte)
                         change message_log_check_duplicate.  */
                      int duplen = sprintf (dupstr, " [%"pMd" times]", dups);
                      TEMP_SET_PT_BOTH (Z - 1, Z_BYTE - 1);
-                     insert_1 (dupstr, duplen, 1, 0, 1);
+                     insert_1_both (dupstr, duplen, duplen, 1, 0, 1);
                    }
                }
            }
@@ -9567,7 +9551,7 @@ message_log_check_duplicate (ptrdiff_t prev_bol_byte, ptrdiff_t this_bol_byte)
 
   for (i = 0; i < len; i++)
     {
-      if (i >= 3 && p1[i-3] == '.' && p1[i-2] == '.' && p1[i-1] == '.')
+      if (i >= 3 && p1[i - 3] == '.' && p1[i - 2] == '.' && p1[i - 1] == '.')
        seen_dots = 1;
       if (p1[i] != p2[i])
        return seen_dots;
@@ -9580,87 +9564,12 @@ message_log_check_duplicate (ptrdiff_t prev_bol_byte, ptrdiff_t this_bol_byte)
       char *pend;
       intmax_t n = strtoimax ((char *) p1, &pend, 10);
       if (0 < n && n < INTMAX_MAX && strncmp (pend, " times]\n", 8) == 0)
-       return n+1;
+       return n + 1;
     }
   return 0;
 }
 \f
 
-/* Display an echo area message M with a specified length of NBYTES
-   bytes.  The string may include null characters.  If M is 0, clear
-   out any existing message, and let the mini-buffer text show
-   through.
-
-   This may GC, so the buffer M must NOT point to a Lisp string.  */
-
-void
-message2 (const char *m, ptrdiff_t nbytes, int multibyte)
-{
-  /* First flush out any partial line written with print.  */
-  message_log_maybe_newline ();
-  if (m)
-    message_dolog (m, nbytes, 1, multibyte);
-  message2_nolog (m, nbytes, multibyte);
-}
-
-
-/* The non-logging counterpart of message2.  */
-
-void
-message2_nolog (const char *m, ptrdiff_t nbytes, int multibyte)
-{
-  struct frame *sf = SELECTED_FRAME ();
-  message_enable_multibyte = multibyte;
-
-  if (FRAME_INITIAL_P (sf))
-    {
-      if (noninteractive_need_newline)
-       putc ('\n', stderr);
-      noninteractive_need_newline = 0;
-      if (m)
-       fwrite (m, nbytes, 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
-          && sf->glyphs_initialized_p
-          && FRAME_MESSAGE_BUF (sf))
-    {
-      Lisp_Object mini_window;
-      struct frame *f;
-
-      /* Get the frame containing the mini-buffer
-        that the selected frame is using.  */
-      mini_window = FRAME_MINIBUF_WINDOW (sf);
-      f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
-
-      FRAME_SAMPLE_VISIBILITY (f);
-      if (FRAME_VISIBLE_P (sf)
-         && ! FRAME_VISIBLE_P (f))
-       Fmake_frame_visible (WINDOW_FRAME (XWINDOW (mini_window)));
-
-      if (m)
-       {
-         set_message (m, Qnil, nbytes, multibyte);
-         if (minibuffer_auto_raise)
-           Fraise_frame  (WINDOW_FRAME (XWINDOW (mini_window)));
-       }
-      else
-       clear_message (1, 1);
-
-      do_pending_window_change (0);
-      echo_area_display (1);
-      do_pending_window_change (0);
-      if (FRAME_TERMINAL (f)->frame_up_to_date_hook)
-       (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f);
-    }
-}
-
-
 /* Display an echo area message M with a specified length of NBYTES
    bytes.  The string may include null characters.  If M is not a
    string, clear out any existing message, and let the mini-buffer
@@ -9669,7 +9578,7 @@ message2_nolog (const char *m, ptrdiff_t nbytes, int multibyte)
    This function cancels echoing.  */
 
 void
-message3 (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
+message3 (Lisp_Object m)
 {
   struct gcpro gcpro1;
 
@@ -9681,13 +9590,15 @@ message3 (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
   message_log_maybe_newline ();
   if (STRINGP (m))
     {
+      ptrdiff_t nbytes = SBYTES (m);
+      int multibyte = STRING_MULTIBYTE (m);
       USE_SAFE_ALLOCA;
       char *buffer = SAFE_ALLOCA (nbytes);
       memcpy (buffer, SDATA (m), nbytes);
       message_dolog (buffer, nbytes, 1, multibyte);
       SAFE_FREE ();
     }
-  message3_nolog (m, nbytes, multibyte);
+  message3_nolog (m);
 
   UNGCPRO;
 }
@@ -9699,10 +9610,9 @@ message3 (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
    and make this cancel echoing.  */
 
 void
-message3_nolog (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
+message3_nolog (Lisp_Object m)
 {
   struct frame *sf = SELECTED_FRAME ();
-  message_enable_multibyte = multibyte;
 
   if (FRAME_INITIAL_P (sf))
     {
@@ -9710,36 +9620,28 @@ message3_nolog (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
        putc ('\n', stderr);
       noninteractive_need_newline = 0;
       if (STRINGP (m))
-       fwrite (SDATA (m), nbytes, 1, stderr);
+       fwrite (SDATA (m), SBYTES (m), 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
-          && sf->glyphs_initialized_p
-          && FRAME_MESSAGE_BUF (sf))
+  /* Error messages get reported properly by cmd_error, so this must be just an
+     informative message; if the frame hasn't really been initialized yet, just
+     toss it.  */
+  else if (INTERACTIVE && sf->glyphs_initialized_p)
     {
-      Lisp_Object mini_window;
-      Lisp_Object frame;
-      struct frame *f;
-
       /* Get the frame containing the mini-buffer
         that the selected frame is using.  */
-      mini_window = FRAME_MINIBUF_WINDOW (sf);
-      frame = XWINDOW (mini_window)->frame;
-      f = XFRAME (frame);
+      Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);
+      Lisp_Object frame = XWINDOW (mini_window)->frame;
+      struct frame *f = XFRAME (frame);
 
-      FRAME_SAMPLE_VISIBILITY (f);
-      if (FRAME_VISIBLE_P (sf)
-         && !FRAME_VISIBLE_P (f))
+      if (FRAME_VISIBLE_P (sf) && !FRAME_VISIBLE_P (f))
        Fmake_frame_visible (frame);
 
       if (STRINGP (m) && SCHARS (m) > 0)
        {
-         set_message (NULL, m, nbytes, multibyte);
+         set_message (m);
          if (minibuffer_auto_raise)
            Fraise_frame (frame);
          /* Assume we are not echoing.
@@ -9769,7 +9671,7 @@ message3_nolog (Lisp_Object m, ptrdiff_t nbytes, int multibyte)
 void
 message1 (const char *m)
 {
-  message2 (m, (m ? strlen (m) : 0), 0);
+  message3 (m ? make_unibyte_string (m, strlen (m)) : Qnil);
 }
 
 
@@ -9778,7 +9680,7 @@ message1 (const char *m)
 void
 message1_nolog (const char *m)
 {
-  message2_nolog (m, (m ? strlen (m) : 0), 0);
+  message3_nolog (m ? make_unibyte_string (m, strlen (m)) : Qnil);
 }
 
 /* Display a message M which contains a single %s
@@ -9815,10 +9717,10 @@ message_with_string (const char *m, Lisp_Object string, int log)
       mini_window = FRAME_MINIBUF_WINDOW (sf);
       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
-      /* 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 (FRAME_MESSAGE_BUF (f))
+      /* Error messages get reported properly by cmd_error, so this must be
+        just an informative message; if the frame hasn't really been
+        initialized yet, just toss it.  */
+      if (f->glyphs_initialized_p)
        {
          Lisp_Object args[2], msg;
          struct gcpro gcpro1, gcpro2;
@@ -9831,9 +9733,9 @@ message_with_string (const char *m, Lisp_Object string, int log)
          msg = Fformat (2, args);
 
          if (log)
-           message3 (msg, SBYTES (msg), STRING_MULTIBYTE (msg));
+           message3 (msg);
          else
-           message3_nolog (msg, SBYTES (msg), STRING_MULTIBYTE (msg));
+           message3_nolog (msg);
 
          UNGCPRO;
 
@@ -9877,20 +9779,20 @@ vmessage (const char *m, va_list ap)
       mini_window = FRAME_MINIBUF_WINDOW (sf);
       f = XFRAME (WINDOW_FRAME (XWINDOW (mini_window)));
 
-      /* 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 (FRAME_MESSAGE_BUF (f))
+      /* Error messages get reported properly by cmd_error, so this must be
+        just an informative message; if the frame hasn't really been
+        initialized yet, just toss it.  */
+      if (f->glyphs_initialized_p)
        {
          if (m)
            {
              ptrdiff_t len;
+             ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f);
+             char *message_buf = alloca (maxsize + 1);
 
-             len = doprnt (FRAME_MESSAGE_BUF (f),
-                           FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
+             len = doprnt (message_buf, maxsize, m, (char *)0, ap);
 
-             message2 (FRAME_MESSAGE_BUF (f), len, 1);
+             message3 (make_string (message_buf, len));
            }
          else
            message1 (0);
@@ -9941,8 +9843,7 @@ update_echo_area (void)
     {
       Lisp_Object string;
       string = Fcurrent_message ();
-      message3 (string, SBYTES (string),
-               !NILP (BVAR (current_buffer, enable_multibyte_characters)));
+      message3 (string);
     }
 }
 
@@ -9978,7 +9879,7 @@ ensure_echo_area_buffers (void)
 }
 
 
-/* Call FN with args A1..A4 with either the current or last displayed
+/* Call FN with args A1..A2 with either the current or last displayed
    echo_area_buffer as current buffer.
 
    WHICH zero means use the current message buffer
@@ -9996,8 +9897,8 @@ ensure_echo_area_buffers (void)
 
 static int
 with_echo_area_buffer (struct window *w, int which,
-                      int (*fn) (ptrdiff_t, Lisp_Object, ptrdiff_t, ptrdiff_t),
-                      ptrdiff_t a1, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
+                      int (*fn) (ptrdiff_t, Lisp_Object),
+                      ptrdiff_t a1, Lisp_Object a2)
 {
   Lisp_Object buffer;
   int this_one, the_other, clear_buffer_p, rc;
@@ -10070,7 +9971,7 @@ with_echo_area_buffer (struct window *w, int which,
   eassert (BEGV >= BEG);
   eassert (ZV <= Z && ZV >= BEGV);
 
-  rc = fn (a1, a2, a3, a4);
+  rc = fn (a1, a2);
 
   eassert (BEGV >= BEG);
   eassert (ZV <= Z && ZV >= BEGV);
@@ -10249,7 +10150,7 @@ display_echo_area (struct window *w)
   window_height_changed_p
     = with_echo_area_buffer (w, display_last_displayed_message_p,
                             display_echo_area_1,
-                            (intptr_t) w, Qnil, 0, 0);
+                            (intptr_t) w, Qnil);
 
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
@@ -10266,7 +10167,7 @@ display_echo_area (struct window *w)
    Value is non-zero if height of W was changed.  */
 
 static int
-display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
+display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2)
 {
   intptr_t i1 = a1;
   struct window *w = (struct window *) i1;
@@ -10311,8 +10212,7 @@ resize_echo_area_exactly (void)
        resize_exactly = Qnil;
 
       resized_p = with_echo_area_buffer (w, 0, resize_mini_window_1,
-                                        (intptr_t) w, resize_exactly,
-                                        0, 0);
+                                        (intptr_t) w, resize_exactly);
       if (resized_p)
        {
          ++windows_or_buffers_changed;
@@ -10330,7 +10230,7 @@ resize_echo_area_exactly (void)
    resize_mini_window returns.  */
 
 static int
-resize_mini_window_1 (ptrdiff_t a1, Lisp_Object exactly, ptrdiff_t a3, ptrdiff_t a4)
+resize_mini_window_1 (ptrdiff_t a1, Lisp_Object exactly)
 {
   intptr_t i1 = a1;
   return resize_mini_window ((struct window *) i1, !NILP (exactly));
@@ -10499,7 +10399,7 @@ current_message (void)
   else
     {
       with_echo_area_buffer (0, 0, current_message_1,
-                            (intptr_t) &msg, Qnil, 0, 0);
+                            (intptr_t) &msg, Qnil);
       if (NILP (msg))
        echo_area_buffer[0] = Qnil;
     }
@@ -10509,7 +10409,7 @@ current_message (void)
 
 
 static int
-current_message_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
+current_message_1 (ptrdiff_t a1, Lisp_Object a2)
 {
   intptr_t i1 = a1;
   Lisp_Object *msg = (Lisp_Object *) i1;
@@ -10541,14 +10441,8 @@ push_message (void)
 void
 restore_message (void)
 {
-  Lisp_Object msg;
-
   eassert (CONSP (Vmessage_stack));
-  msg = XCAR (Vmessage_stack);
-  if (STRINGP (msg))
-    message3_nolog (msg, SBYTES (msg), STRING_MULTIBYTE (msg));
-  else
-    message3_nolog (msg, 0, 0);
+  message3_nolog (XCAR (Vmessage_stack));
 }
 
 
@@ -10591,16 +10485,16 @@ truncate_echo_area (ptrdiff_t nchars)
 {
   if (nchars == 0)
     echo_area_buffer[0] = Qnil;
-  /* 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 (!noninteractive
           && INTERACTIVE
           && !NILP (echo_area_buffer[0]))
     {
       struct frame *sf = SELECTED_FRAME ();
-      if (FRAME_MESSAGE_BUF (sf))
-       with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil, 0, 0);
+      /* Error messages get reported properly by cmd_error, so this must be
+        just an informative message; if the frame hasn't really been
+        initialized yet, just toss it.  */
+      if (sf->glyphs_initialized_p)
+       with_echo_area_buffer (0, 0, truncate_message_1, nchars, Qnil);
     }
 }
 
@@ -10609,7 +10503,7 @@ truncate_echo_area (ptrdiff_t nchars)
    message to at most NCHARS characters.  */
 
 static int
-truncate_message_1 (ptrdiff_t nchars, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4)
+truncate_message_1 (ptrdiff_t nchars, Lisp_Object a2)
 {
   if (BEG + nchars < Z)
     del_range (BEG + nchars, Z);
@@ -10618,30 +10512,16 @@ truncate_message_1 (ptrdiff_t nchars, Lisp_Object a2, ptrdiff_t a3, ptrdiff_t a4
   return 0;
 }
 
-/* Set the current message to a substring of S or STRING.
-
-   If STRING is a Lisp string, set the message to the first NBYTES
-   bytes from STRING.  NBYTES zero means use the whole string.  If
-   STRING is multibyte, the message will be displayed multibyte.
-
-   If S is not null, set the message to the first LEN bytes of S.  LEN
-   zero means use the whole string.  MULTIBYTE_P non-zero means S is
-   multibyte.  Display the message multibyte in that case.
-
-   Doesn't GC, as with_echo_area_buffer binds Qinhibit_modification_hooks
-   to t before calling set_message_1 (which calls insert).
-  */
+/* Set the current message to STRING.  */
 
 static void
-set_message (const char *s, Lisp_Object string,
-            ptrdiff_t nbytes, int multibyte_p)
+set_message (Lisp_Object string)
 {
-  message_enable_multibyte
-    = ((s && multibyte_p)
-       || (STRINGP (string) && STRING_MULTIBYTE (string)));
+  eassert (STRINGP (string));
 
-  with_echo_area_buffer (0, -1, set_message_1,
-                        (intptr_t) s, string, nbytes, multibyte_p);
+  message_enable_multibyte = STRING_MULTIBYTE (string);
+
+  with_echo_area_buffer (0, -1, set_message_1, 0, string);
   message_buf_print = 0;
   help_echo_showing_p = 0;
 
@@ -10651,18 +10531,14 @@ set_message (const char *s, Lisp_Object string,
 }
 
 
-/* Helper function for set_message.  Arguments have the same meaning
-   as there, with A1 corresponding to S and A2 corresponding to STRING
-   This function is called with the echo area buffer being
-   current.  */
+/* Helper function for set_message.  First argument is ignored and second
+   argument has the same meaning as for set_message.
+   This function is called with the echo area buffer being current.  */
 
 static int
-set_message_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t nbytes, ptrdiff_t multibyte_p)
+set_message_1 (ptrdiff_t a1, Lisp_Object string)
 {
-  intptr_t i1 = a1;
-  const char *s = (const char *) i1;
-  const unsigned char *msg = (const unsigned char *) s;
-  Lisp_Object string = a2;
+  eassert (STRINGP (string));
 
   /* Change multibyteness of the echo buffer appropriately.  */
   if (message_enable_multibyte
@@ -10676,61 +10552,10 @@ set_message_1 (ptrdiff_t a1, Lisp_Object a2, ptrdiff_t nbytes, ptrdiff_t multiby
   /* Insert new message at BEG.  */
   TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
-  if (STRINGP (string))
-    {
-      ptrdiff_t nchars;
-
-      if (nbytes == 0)
-       nbytes = SBYTES (string);
-      nchars = string_byte_to_char (string, nbytes);
-
-      /* This function takes care of single/multibyte conversion.  We
-         just have to ensure that the echo area buffer has the right
-         setting of enable_multibyte_characters.  */
-      insert_from_string (string, 0, 0, nchars, nbytes, 1);
-    }
-  else if (s)
-    {
-      if (nbytes == 0)
-       nbytes = strlen (s);
-
-      if (multibyte_p && NILP (BVAR (current_buffer, enable_multibyte_characters)))
-       {
-         /* Convert from multi-byte to single-byte.  */
-         ptrdiff_t i;
-         int c, n;
-         char work[1];
-
-         /* Convert a multibyte string to single-byte.  */
-         for (i = 0; i < nbytes; i += n)
-           {
-             c = string_char_and_length (msg + i, &n);
-             work[0] = (ASCII_CHAR_P (c)
-                        ? c
-                        : multibyte_char_to_unibyte (c));
-             insert_1_both (work, 1, 1, 1, 0, 0);
-           }
-       }
-      else if (!multibyte_p
-              && !NILP (BVAR (current_buffer, enable_multibyte_characters)))
-       {
-         /* Convert from single-byte to multi-byte.  */
-         ptrdiff_t i;
-         int c, n;
-         unsigned char str[MAX_MULTIBYTE_LENGTH];
-
-         /* Convert a single-byte string to multibyte.  */
-         for (i = 0; i < nbytes; i++)
-           {
-             c = msg[i];
-             MAKE_CHAR_MULTIBYTE (c);
-             n = CHAR_STRING (c, str);
-             insert_1_both ((char *) str, 1, n, 1, 0, 0);
-           }
-       }
-      else
-       insert_1 (s, nbytes, 1, 0, 0);
-    }
+  /* This function takes care of single/multibyte conversion.
+     We just have to ensure that the echo area buffer has the right
+     setting of enable_multibyte_characters.  */
+  insert_from_string (string, 0, 0, SCHARS (string), SBYTES (string), 1);
 
   return 0;
 }
@@ -10933,7 +10758,7 @@ window_buffer_changed (struct window *w)
 
   return (((BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) != w->last_had_star)
          || ((!NILP (Vtransient_mark_mode) && !NILP (BVAR (b, mark_active)))
-             != !NILP (w->region_showing)));
+             != (w->region_showing != 0)));
 }
 
 /* Nonzero if W has %c in its mode line and mode line should be updated.  */
@@ -10941,9 +10766,9 @@ window_buffer_changed (struct window *w)
 static int
 mode_line_update_needed (struct window *w)
 {
-  return (!NILP (w->column_number_displayed)
+  return (w->column_number_displayed != -1
          && !(PT == w->last_point && !window_outdated (w))
-         && (XFASTINT (w->column_number_displayed) != current_column ()));
+         && (w->column_number_displayed != current_column ()));
 }
 
 /***********************************************************************
@@ -13080,7 +12905,6 @@ redisplay_internal (void)
     {
       struct frame *f = XFRAME (frame);
 
-      FRAME_SAMPLE_VISIBILITY (f);
       if (FRAME_VISIBLE_P (f))
        ++number_of_visible_frames;
       clear_desired_matrices (f);
@@ -13197,16 +13021,15 @@ redisplay_internal (void)
       clear_garbaged_frames ();
     }
 
-
   /* If showing the region, and mark has changed, we must redisplay
      the whole window.  The assignment to this_line_start_pos prevents
      the optimization directly below this if-statement.  */
   if (((!NILP (Vtransient_mark_mode)
        && !NILP (BVAR (XBUFFER (w->buffer), mark_active)))
-       != !NILP (w->region_showing))
-      || (!NILP (w->region_showing)
-         && !EQ (w->region_showing,
-                 Fmarker_position (BVAR (XBUFFER (w->buffer), mark)))))
+       != (w->region_showing > 0))
+      || (w->region_showing
+         && w->region_showing
+         != XINT (Fmarker_position (BVAR (XBUFFER (w->buffer), mark)))))
     CHARPOS (this_line_start_pos) = 0;
 
   /* Optimize the case that only the line containing the cursor in the
@@ -13372,7 +13195,7 @@ redisplay_internal (void)
               && (EQ (selected_window,
                       BVAR (current_buffer, last_selected_window))
                   || highlight_nonselected_windows)
-              && NILP (w->region_showing)
+              && !w->region_showing
               && NILP (Vshow_trailing_whitespace)
               && !cursor_in_echo_area)
        {
@@ -13626,9 +13449,6 @@ redisplay_internal (void)
        {
          int this_is_visible = 0;
 
-         if (XFRAME (frame)->visible)
-           this_is_visible = 1;
-         FRAME_SAMPLE_VISIBILITY (XFRAME (frame));
          if (XFRAME (frame)->visible)
            this_is_visible = 1;
 
@@ -14872,7 +14692,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
       if (!just_this_one_p
          || current_buffer->clip_changed
          || BEG_UNCHANGED < CHARPOS (startp))
-       wset_base_line_number (w, Qnil);
+       w->base_line_number = 0;
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
@@ -14925,7 +14745,7 @@ compute_window_start_on_continuation_line (struct window *w)
        SET_TEXT_POS (start_pos, ZV, ZV_BYTE);
 
       /* Find the start of the continued line.  This should be fast
-        because scan_buffer is fast (newline cache).  */
+        because find_newline is fast (newline cache).  */
       row = w->desired_matrix->rows + (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0);
       init_iterator (&it, w, CHARPOS (start_pos), BYTEPOS (start_pos),
                     row, DEFAULT_FACE_ID);
@@ -15021,7 +14841,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
          region exists, cursor movement has to do more than just
          set the cursor.  */
       && markpos_of_region () < 0
-      && NILP (w->region_showing)
+      && !w->region_showing
       && NILP (Vshow_trailing_whitespace)
       /* This code is not used for mini-buffer for the sake of the case
         of redisplaying to replace an echo area message; since in
@@ -15587,7 +15407,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
       /* Forget any recorded base line for line number display.  */
       if (!buffer_unchanged_p)
-       wset_base_line_number (w, Qnil);
+       w->base_line_number = 0;
 
       /* Redisplay the mode line.  Select the buffer properly for that.
         Also, run the hook window-scroll-functions
@@ -15827,7 +15647,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              || current_buffer->clip_changed
              || BEG_UNCHANGED < CHARPOS (startp))
            /* Forget any recorded base line for line number display.  */
-           wset_base_line_number (w, Qnil);
+           w->base_line_number = 0;
 
          if (!cursor_row_fully_visible_p (w, 1, 0))
            {
@@ -15894,11 +15714,9 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   debug_method_add (w, "recenter");
 #endif
 
-  /* w->vscroll = 0; */
-
   /* Forget any previously recorded base line for line number display.  */
   if (!buffer_unchanged_p)
-    wset_base_line_number (w, Qnil);
+    w->base_line_number = 0;
 
   /* Determine the window start relative to point.  */
   init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
@@ -16118,10 +15936,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
           && !FRAME_WINDOW_P (f)
           && !WINDOW_FULL_WIDTH_P (w))
        /* Line number to display.  */
-       || INTEGERP (w->base_line_pos)
+       || w->base_line_pos > 0
        /* Column number is displayed and different from the one displayed.  */
-       || (!NILP (w->column_number_displayed)
-          && (XFASTINT (w->column_number_displayed) != current_column ())))
+       || (w->column_number_displayed != -1
+          && (w->column_number_displayed != current_column ())))
       /* This means that the window has a mode line.  */
       && (WINDOW_WANTS_MODELINE_P (w)
          || WINDOW_WANTS_HEADER_LINE_P (w)))
@@ -16152,11 +15970,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
        goto need_larger_matrices;
     }
 
-  if (!line_number_displayed
-      && !BUFFERP (w->base_line_pos))
+  if (!line_number_displayed && w->base_line_pos != -1)
     {
-      wset_base_line_pos (w, Qnil);
-      wset_base_line_number (w, Qnil);
+      w->base_line_pos = 0;
+      w->base_line_number = 0;
     }
 
  finish_menu_bars:
@@ -16393,7 +16210,7 @@ try_window_reusing_current_matrix (struct window *w)
 
   /* Can't do this if region may have changed.  */
   if (0 <= markpos_of_region ()
-      || !NILP (w->region_showing)
+      || w->region_showing
       || !NILP (Vshow_trailing_whitespace))
     return 0;
 
@@ -17232,7 +17049,7 @@ try_window_id (struct window *w)
     GIVE_UP (11);
 
   /* Likewise if showing a region.  */
-  if (!NILP (w->region_showing))
+  if (w->region_showing)
     GIVE_UP (10);
 
   /* Can't use this if overlay arrow position and/or string have
@@ -19319,7 +19136,7 @@ display_line (struct it *it)
     }
 
   /* Is IT->w showing the region?  */
-  wset_region_showing (it->w, it->region_beg_charpos > 0 ? Qt : Qnil);
+  it->w->region_showing = it->region_beg_charpos > 0 ? it->region_beg_charpos : 0;
 
   /* Clear the result glyph row and enable it.  */
   prepare_desired_row (row);
@@ -20323,7 +20140,7 @@ display_mode_lines (struct window *w)
 
   /* These will be set while the mode line specs are processed.  */
   line_number_displayed = 0;
-  wset_column_number_displayed (w, Qnil);
+  w->column_number_displayed = -1;
 
   if (WINDOW_WANTS_MODELINE_P (w))
     {
@@ -21346,8 +21163,7 @@ decode_mode_spec_coding (Lisp_Object coding_system, register char *buf, int eol_
    returned with spaces to that value.  Return a Lisp string in
    *STRING if the resulting string is taken from that Lisp string.
 
-   Note we operate on the current buffer for most purposes,
-   the exception being w->base_line_pos.  */
+   Note we operate on the current buffer for most purposes.  */
 
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
@@ -21458,7 +21274,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
       else
        {
          ptrdiff_t col = current_column ();
-         wset_column_number_displayed (w, make_number (col));
+         w->column_number_displayed = col;
          pint2str (decode_mode_spec_buf, width, col);
          return decode_mode_spec_buf;
        }
@@ -21517,27 +21333,24 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
        /* If we decided that this buffer isn't suitable for line numbers,
           don't forget that too fast.  */
-       if (EQ (w->base_line_pos, w->buffer))
+       if (w->base_line_pos == -1)
          goto no_value;
-       /* But do forget it, if the window shows a different buffer now.  */
-       else if (BUFFERP (w->base_line_pos))
-         wset_base_line_pos (w, Qnil);
 
        /* If the buffer is very big, don't waste time.  */
        if (INTEGERP (Vline_number_display_limit)
            && BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit))
          {
-           wset_base_line_pos (w, Qnil);
-           wset_base_line_number (w, Qnil);
+           w->base_line_pos = 0;
+           w->base_line_number = 0;
            goto no_value;
          }
 
-       if (INTEGERP (w->base_line_number)
-           && INTEGERP (w->base_line_pos)
-           && XFASTINT (w->base_line_pos) <= startpos)
+       if (w->base_line_number > 0
+           && w->base_line_pos > 0
+           && w->base_line_pos <= startpos)
          {
-           line = XFASTINT (w->base_line_number);
-           linepos = XFASTINT (w->base_line_pos);
+           line = w->base_line_number;
+           linepos = w->base_line_pos;
            linepos_byte = buf_charpos_to_bytepos (b, linepos);
          }
        else
@@ -21560,8 +21373,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
           go back past it.  */
        if (startpos == BUF_BEGV (b))
          {
-           wset_base_line_number (w, make_number (topline));
-           wset_base_line_pos (w, make_number (BUF_BEGV (b)));
+           w->base_line_number = topline;
+           w->base_line_pos = BUF_BEGV (b);
          }
        else if (nlines < height + 25 || nlines > height * 3 + 50
                 || linepos == BUF_BEGV (b))
@@ -21587,13 +21400,13 @@ decode_mode_spec (struct window *w, register int c, int field_width,
               give up on line numbers for this window.  */
            if (position == limit_byte && limit == startpos - distance)
              {
-               wset_base_line_pos (w, w->buffer);
-               wset_base_line_number (w, Qnil);
+               w->base_line_pos = -1;
+               w->base_line_number = 0;
                goto no_value;
              }
 
-           wset_base_line_number (w, make_number (topline - nlines));
-           wset_base_line_pos (w, make_number (BYTE_TO_CHAR (position)));
+           w->base_line_number = topline - nlines;
+           w->base_line_pos = BYTE_TO_CHAR (position);
          }
 
        /* Now count lines from the start pos to point.  */
@@ -21715,9 +21528,6 @@ decode_mode_spec (struct window *w, register int c, int field_width,
          return "@";
       }
 
-    case 't':                  /* indicate TEXT or BINARY */
-      return "T";
-
     case 'z':
       /* coding-system (not including end-of-line format) */
     case 'Z':
@@ -21767,11 +21577,15 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 }
 
 
-/* Count up to COUNT lines starting from START_BYTE.
-   But don't go beyond LIMIT_BYTE.
-   Return the number of lines thus found (always nonnegative).
+/* Count up to COUNT lines starting from START_BYTE.  COUNT negative
+   means count lines back from START_BYTE.  But don't go beyond
+   LIMIT_BYTE.  Return the number of lines thus found (always
+   nonnegative).
 
-   Set *BYTE_POS_PTR to 1 if we found COUNT lines, 0 if we hit LIMIT.  */
+   Set *BYTE_POS_PTR to the byte position where we stopped.  This is
+   either the position COUNT lines after/before START_BYTE, if we
+   found COUNT lines, or LIMIT_BYTE if we hit the limit before finding
+   COUNT lines.  */
 
 static ptrdiff_t
 display_count_lines (ptrdiff_t start_byte,
@@ -21798,31 +21612,36 @@ display_count_lines (ptrdiff_t start_byte,
          ceiling = min (limit_byte - 1, ceiling);
          ceiling_addr = BYTE_POS_ADDR (ceiling) + 1;
          base = (cursor = BYTE_POS_ADDR (start_byte));
-         while (1)
+
+         do
            {
              if (selective_display)
-               while (*cursor != '\n' && *cursor != 015 && ++cursor != ceiling_addr)
-                 ;
+               {
+                 while (*cursor != '\n' && *cursor != 015
+                        && ++cursor != ceiling_addr)
+                   continue;
+                 if (cursor == ceiling_addr)
+                   break;
+               }
              else
-               while (*cursor != '\n' && ++cursor != ceiling_addr)
-                 ;
+               {
+                 cursor = memchr (cursor, '\n', ceiling_addr - cursor);
+                 if (! cursor)
+                   break;
+               }
 
-             if (cursor != ceiling_addr)
+             cursor++;
+
+             if (--count == 0)
                {
-                 if (--count == 0)
-                   {
-                     start_byte += cursor - base + 1;
-                     *byte_pos_ptr = start_byte;
-                     return orig_count;
-                   }
-                 else
-                   if (++cursor == ceiling_addr)
-                     break;
+                 start_byte += cursor - base;
+                 *byte_pos_ptr = start_byte;
+                 return orig_count;
                }
-             else
-               break;
            }
-         start_byte += cursor - base;
+         while (cursor < ceiling_addr);
+
+         start_byte += ceiling_addr - base;
        }
     }
   else
@@ -21831,35 +21650,35 @@ display_count_lines (ptrdiff_t start_byte,
        {
          ceiling = BUFFER_FLOOR_OF (start_byte - 1);
          ceiling = max (limit_byte, ceiling);
-         ceiling_addr = BYTE_POS_ADDR (ceiling) - 1;
+         ceiling_addr = BYTE_POS_ADDR (ceiling);
          base = (cursor = BYTE_POS_ADDR (start_byte - 1) + 1);
          while (1)
            {
              if (selective_display)
-               while (--cursor != ceiling_addr
-                      && *cursor != '\n' && *cursor != 015)
-                 ;
+               {
+                 while (--cursor >= ceiling_addr
+                        && *cursor != '\n' && *cursor != 015)
+                   continue;
+                 if (cursor < ceiling_addr)
+                   break;
+               }
              else
-               while (--cursor != ceiling_addr && *cursor != '\n')
-                 ;
+               {
+                 cursor = memrchr (ceiling_addr, '\n', cursor - ceiling_addr);
+                 if (! cursor)
+                   break;
+               }
 
-             if (cursor != ceiling_addr)
+             if (++count == 0)
                {
-                 if (++count == 0)
-                   {
-                     start_byte += cursor - base + 1;
-                     *byte_pos_ptr = start_byte;
-                     /* When scanning backwards, we should
-                        not count the newline posterior to which we stop.  */
-                     return - orig_count - 1;
-                   }
+                 start_byte += cursor - base + 1;
+                 *byte_pos_ptr = start_byte;
+                 /* When scanning backwards, we should
+                    not count the newline posterior to which we stop.  */
+                 return - orig_count - 1;
                }
-             else
-               break;
            }
-         /* Here we add 1 to compensate for the last decrement
-            of CURSOR, which took it past the valid range.  */
-         start_byte += cursor - base + 1;
+         start_byte += ceiling_addr - base;
        }
     }