dynwind fixes
[bpt/emacs.git] / src / xdisp.c
index 6291543..774903b 100644 (file)
@@ -98,7 +98,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
       This function attempts to redisplay a window by reusing parts of
       its existing display.  It finds and reuses the part that was not
 
       This function attempts to redisplay a window by reusing parts of
       its existing display.  It finds and reuses the part that was not
-      changed, and redraws the rest.
+      changed, and redraws the rest.  (The "id" part in the function's
+      name stands for "insert/delete", not for "identification" or
+      somesuch.)
 
     . try_window
 
 
     . try_window
 
@@ -113,6 +115,19 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    optimizations were successful, redisplay calls redisplay_windows,
    which performs a full redisplay of all windows.
 
    optimizations were successful, redisplay calls redisplay_windows,
    which performs a full redisplay of all windows.
 
+   Note that there's one more important optimization up Emacs's
+   sleeve, but it is related to actually redrawing the potentially
+   changed portions of the window/frame, not to reproducing the
+   desired matrices of those potentially changed portions.  Namely,
+   the function update_frame and its subroutines, which you will find
+   in dispnew.c, compare the desired matrices with the current
+   matrices, and only redraw the portions that changed.  So it could
+   happen that the functions in this file for some reason decide that
+   the entire desired matrix needs to be regenerated from scratch, and
+   still only parts of the Emacs display, or even nothing at all, will
+   be actually delivered to the glass, because update_frame has found
+   that the new and the old screen contents are similar or identical.
+
    Desired matrices.
 
    Desired matrices are always built per Emacs window.  The function
    Desired matrices.
 
    Desired matrices are always built per Emacs window.  The function
@@ -622,7 +637,7 @@ void
 wset_redisplay (struct window *w)
 {
   /* Beware: selected_window can be nil during early stages.  */
 wset_redisplay (struct window *w)
 {
   /* Beware: selected_window can be nil during early stages.  */
-  if (!EQ (make_lisp_ptr (w, Lisp_Vectorlike), selected_window))
+  if (!EQ (w->header.self, selected_window))
     redisplay_other_windows ();
   w->redisplay = true;
 }
     redisplay_other_windows ();
   w->redisplay = true;
 }
@@ -1262,12 +1277,23 @@ Value is the height in pixels of the line at point.  */)
   struct it it;
   struct text_pos pt;
   struct window *w = XWINDOW (selected_window);
   struct it it;
   struct text_pos pt;
   struct window *w = XWINDOW (selected_window);
+  struct buffer *old_buffer = NULL;
+  Lisp_Object result;
 
 
+  if (XBUFFER (w->contents) != current_buffer)
+    {
+      old_buffer = current_buffer;
+      set_buffer_internal_1 (XBUFFER (w->contents));
+    }
   SET_TEXT_POS (pt, PT, PT_BYTE);
   start_display (&it, w, pt);
   it.vpos = it.current_y = 0;
   last_height = 0;
   SET_TEXT_POS (pt, PT, PT_BYTE);
   start_display (&it, w, pt);
   it.vpos = it.current_y = 0;
   last_height = 0;
-  return make_number (line_bottom_y (&it));
+  result = make_number (line_bottom_y (&it));
+  if (old_buffer)
+    set_buffer_internal_1 (old_buffer);
+
+  return result;
 }
 
 /* Return the default pixel height of text lines in window W.  The
 }
 
 /* Return the default pixel height of text lines in window W.  The
@@ -2580,8 +2606,8 @@ safe_eval_handler (Lisp_Object arg, ptrdiff_t nargs, Lisp_Object *args)
    following.  Return the result, or nil if something went
    wrong.  Prevent redisplay during the evaluation.  */
 
    following.  Return the result, or nil if something went
    wrong.  Prevent redisplay during the evaluation.  */
 
-Lisp_Object
-safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+static Lisp_Object
+safe__call (bool inhibit_quit, ptrdiff_t nargs, Lisp_Object func, va_list ap)
 {
   Lisp_Object val;
 
 {
   Lisp_Object val;
 
@@ -2589,32 +2615,42 @@ safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
     val = Qnil;
   else
     {
     val = Qnil;
   else
     {
-      va_list ap;
       ptrdiff_t i;
       ptrdiff_t i;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       struct gcpro gcpro1;
       Lisp_Object *args = alloca (nargs * word_size);
 
       args[0] = func;
       struct gcpro gcpro1;
       Lisp_Object *args = alloca (nargs * word_size);
 
       args[0] = func;
-      va_start (ap, func);
       for (i = 1; i < nargs; i++)
        args[i] = va_arg (ap, Lisp_Object);
       for (i = 1; i < nargs; i++)
        args[i] = va_arg (ap, Lisp_Object);
-      va_end (ap);
 
       GCPRO1 (args[0]);
       gcpro1.nvars = nargs;
       specbind (Qinhibit_redisplay, Qt);
 
       GCPRO1 (args[0]);
       gcpro1.nvars = nargs;
       specbind (Qinhibit_redisplay, Qt);
+      if (inhibit_quit)
+       specbind (Qinhibit_quit, Qt);
       /* Use Qt to ensure debugger does not run,
         so there is no possibility of wanting to redisplay.  */
       val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
                                       safe_eval_handler);
       UNGCPRO;
       /* Use Qt to ensure debugger does not run,
         so there is no possibility of wanting to redisplay.  */
       val = internal_condition_case_n (Ffuncall, nargs, args, Qt,
                                       safe_eval_handler);
       UNGCPRO;
-      val = unbind_to (count, val);
+      dynwind_end ();
     }
 
   return val;
 }
 
     }
 
   return val;
 }
 
+Lisp_Object
+safe_call (ptrdiff_t nargs, Lisp_Object func, ...)
+{
+  Lisp_Object retval;
+  va_list ap;
+
+  va_start (ap, func);
+  retval = safe__call (false, nargs, func, ap);
+  va_end (ap);
+  return retval;
+}
 
 /* Call function FN with one argument ARG.
    Return the result, or nil if something went wrong.  */
 
 /* Call function FN with one argument ARG.
    Return the result, or nil if something went wrong.  */
@@ -2625,12 +2661,30 @@ safe_call1 (Lisp_Object fn, Lisp_Object arg)
   return safe_call (2, fn, arg);
 }
 
   return safe_call (2, fn, arg);
 }
 
+static Lisp_Object
+safe__call1 (bool inhibit_quit, Lisp_Object fn, ...)
+{
+  Lisp_Object retval;
+  va_list ap;
+
+  va_start (ap, fn);
+  retval = safe__call (inhibit_quit, 2, fn, ap);
+  va_end (ap);
+  return retval;
+}
+
 static Lisp_Object Qeval;
 
 Lisp_Object
 safe_eval (Lisp_Object sexpr)
 {
 static Lisp_Object Qeval;
 
 Lisp_Object
 safe_eval (Lisp_Object sexpr)
 {
-  return safe_call1 (Qeval, sexpr);
+  return safe__call1 (false, Qeval, sexpr);
+}
+
+static Lisp_Object
+safe__eval (bool inhibit_quit, Lisp_Object sexpr)
+{
+  return safe__call1 (inhibit_quit, Qeval, sexpr);
 }
 
 /* Call function FN with two arguments ARG1 and ARG2.
 }
 
 /* Call function FN with two arguments ARG1 and ARG2.
@@ -3757,7 +3811,7 @@ handle_fontified_prop (struct it *it)
             no amount of fontifying will be able to change it.  */
          NILP (prop) && IT_CHARPOS (*it) < Z))
     {
             no amount of fontifying will be able to change it.  */
          NILP (prop) && IT_CHARPOS (*it) < Z))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       Lisp_Object val;
       struct buffer *obuf = current_buffer;
       ptrdiff_t begv = BEGV, zv = ZV;
       Lisp_Object val;
       struct buffer *obuf = current_buffer;
       ptrdiff_t begv = BEGV, zv = ZV;
@@ -3805,7 +3859,7 @@ handle_fontified_prop (struct it *it)
          UNGCPRO;
        }
 
          UNGCPRO;
        }
 
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       /* Fontification functions routinely call `save-restriction'.
         Normally, this tags clip_changed, which can confuse redisplay
 
       /* Fontification functions routinely call `save-restriction'.
         Normally, this tags clip_changed, which can confuse redisplay
@@ -4769,7 +4823,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
 
   if (!NILP (form) && !EQ (form, Qt))
     {
 
   if (!NILP (form) && !EQ (form, Qt))
     {
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       struct gcpro gcpro1;
 
       /* Bind `object' to the object having the `display' property, a
       struct gcpro gcpro1;
 
       /* Bind `object' to the object having the `display' property, a
@@ -4785,7 +4839,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
       GCPRO1 (form);
       form = safe_eval (form);
       UNGCPRO;
       GCPRO1 (form);
       form = safe_eval (form);
       UNGCPRO;
-      unbind_to (count, Qnil);
+      dynwind_end ();
     }
 
   if (NILP (form))
     }
 
   if (NILP (form))
@@ -4843,11 +4897,11 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                {
                  /* Evaluate IT->font_height with `height' bound to the
                     current specified height to get the new height.  */
                {
                  /* Evaluate IT->font_height with `height' bound to the
                     current specified height to get the new height.  */
-                 ptrdiff_t count = SPECPDL_INDEX ();
+                 dynwind_begin ();
 
                  specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
                  value = safe_eval (it->font_height);
 
                  specbind (Qheight, face->lface[LFACE_HEIGHT_INDEX]);
                  value = safe_eval (it->font_height);
-                 unbind_to (count, Qnil);
+                 dynwind_end ();
 
                  if (NUMBERP (value))
                    new_height = XFLOATINT (value);
 
                  if (NUMBERP (value))
                    new_height = XFLOATINT (value);
@@ -8215,7 +8269,7 @@ next_element_from_buffer (struct it *it)
 
       /* Get the next character, maybe multibyte.  */
       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
 
       /* Get the next character, maybe multibyte.  */
       p = BYTE_POS_ADDR (IT_BYTEPOS (*it));
-      if (it->multibyte_p && !ASCII_BYTE_P (*p))
+      if (it->multibyte_p && !ASCII_CHAR_P (*p))
        it->c = STRING_CHAR_AND_LENGTH (p, it->len);
       else
        it->c = *p, it->len = 1;
        it->c = STRING_CHAR_AND_LENGTH (p, it->len);
       else
        it->c = *p, it->len = 1;
@@ -8517,7 +8571,7 @@ move_it_in_display_line_to (struct it *it,
        }
       else
        {
        }
       else
        {
-         if (it->line_wrap == WORD_WRAP)
+         if (it->line_wrap == WORD_WRAP && it->area == TEXT_AREA)
            {
              if (IT_DISPLAYING_WHITESPACE (it))
                may_wrap = 1;
            {
              if (IT_DISPLAYING_WHITESPACE (it))
                may_wrap = 1;
@@ -8801,8 +8855,11 @@ move_it_in_display_line_to (struct it *it,
                  if (closest_pos < ZV)
                    {
                      RESTORE_IT (it, &ppos_it, ppos_data);
                  if (closest_pos < ZV)
                    {
                      RESTORE_IT (it, &ppos_it, ppos_data);
-                     move_it_in_display_line_to (it, closest_pos, -1,
-                                                 MOVE_TO_POS);
+                     /* Don't recurse if closest_pos is equal to
+                        to_charpos, since we have just tried that.  */
+                     if (closest_pos != to_charpos)
+                       move_it_in_display_line_to (it, closest_pos, -1,
+                                                   MOVE_TO_POS);
                      result = MOVE_POS_MATCH_OR_ZV;
                    }
                  else
                      result = MOVE_POS_MATCH_OR_ZV;
                    }
                  else
@@ -8863,8 +8920,9 @@ move_it_in_display_line_to (struct it *it,
                      && !at_eob_p && closest_pos < ZV)
                    {
                      RESTORE_IT (it, &ppos_it, ppos_data);
                      && !at_eob_p && closest_pos < ZV)
                    {
                      RESTORE_IT (it, &ppos_it, ppos_data);
-                     move_it_in_display_line_to (it, closest_pos, -1,
-                                                 MOVE_TO_POS);
+                     if (closest_pos != to_charpos)
+                       move_it_in_display_line_to (it, closest_pos, -1,
+                                                   MOVE_TO_POS);
                    }
                  result = MOVE_POS_MATCH_OR_ZV;
                  break;
                    }
                  result = MOVE_POS_MATCH_OR_ZV;
                  break;
@@ -8882,7 +8940,9 @@ move_it_in_display_line_to (struct it *it,
              if (closest_pos < ZV)
                {
                  RESTORE_IT (it, &ppos_it, ppos_data);
              if (closest_pos < ZV)
                {
                  RESTORE_IT (it, &ppos_it, ppos_data);
-                 move_it_in_display_line_to (it, closest_pos, -1, MOVE_TO_POS);
+                 if (closest_pos != to_charpos)
+                   move_it_in_display_line_to (it, closest_pos, -1,
+                                               MOVE_TO_POS);
                }
              result = MOVE_POS_MATCH_OR_ZV;
              break;
                }
              result = MOVE_POS_MATCH_OR_ZV;
              break;
@@ -9511,6 +9571,7 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
       ptrdiff_t start_charpos, i;
       int nchars_per_row
        = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
       ptrdiff_t start_charpos, i;
       int nchars_per_row
        = (it->last_visible_x - it->first_visible_x) / FRAME_COLUMN_WIDTH (it->f);
+      bool hit_pos_limit = false;
       ptrdiff_t pos_limit;
 
       /* Start at the beginning of the screen line containing IT's
       ptrdiff_t pos_limit;
 
       /* Start at the beginning of the screen line containing IT's
@@ -9527,8 +9588,11 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
        pos_limit = BEGV;
       else
        pos_limit = max (start_charpos + dvpos * nchars_per_row, BEGV);
        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);
       for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > pos_limit; --i)
        back_to_previous_visible_line_start (it);
+      if (i > 0 && IT_CHARPOS (*it) <= pos_limit)
+       hit_pos_limit = true;
       reseat (it, it->current.pos, 1);
 
       /* Move further back if we end up in a string or an image.  */
       reseat (it, it->current.pos, 1);
 
       /* Move further back if we end up in a string or an image.  */
@@ -9572,6 +9636,25 @@ move_it_by_lines (struct it *it, ptrdiff_t dvpos)
          else
            bidi_unshelve_cache (it2data, 1);
        }
          else
            bidi_unshelve_cache (it2data, 1);
        }
+      else if (hit_pos_limit && pos_limit > BEGV
+              && dvpos < 0 && it2.vpos < -dvpos)
+       {
+         /* If we hit the limit, but still didn't make it far enough
+            back, that means there's a display string with a newline
+            covering a large chunk of text, and that caused
+            back_to_previous_visible_line_start try to go too far.
+            Punish those who commit such atrocities by going back
+            until we've reached DVPOS, after lifting the limit, which
+            could make it slow for very long lines.  "If it hurts,
+            don't do that!"  */
+         dvpos += it2.vpos;
+         RESTORE_IT (it, it, it2data);
+         for (i = -dvpos; i > 0; --i)
+           {
+             back_to_previous_visible_line_start (it);
+             it->vpos--;
+           }
+       }
       else
        RESTORE_IT (it, it, it2data);
     }
       else
        RESTORE_IT (it, it, it2data);
     }
@@ -9600,19 +9683,23 @@ character.  TO, if non-nil, specifies the last text position and
 defaults to the maximum accessible position of the buffer.  If TO is t,
 use the maximum accessible position that is not a newline character.
 
 defaults to the maximum accessible position of the buffer.  If TO is t,
 use the maximum accessible position that is not a newline character.
 
-The optional argument X_LIMIT, if non-nil, specifies the maximum text
-width that can be returned.  X_LIMIT nil or omitted, means to use the
+The optional argument X-LIMIT, if non-nil, specifies the maximum text
+width that can be returned.  X-LIMIT nil or omitted, means to use the
 pixel-width of WINDOW's body; use this if you do not intend to change
 the width of WINDOW.  Use the maximum width WINDOW may assume if you
 pixel-width of WINDOW's body; use this if you do not intend to change
 the width of WINDOW.  Use the maximum width WINDOW may assume if you
-intend to change WINDOW's width.
+intend to change WINDOW's width.  In any case, text whose x-coordinate
+is beyond X-LIMIT is ignored.  Since calculating the width of long lines
+can take some time, it's always a good idea to make this argument as
+small as possible; in particular, if the buffer contains long lines that
+shall be truncated anyway.
 
 
-The optional argument Y_LIMIT, if non-nil, specifies the maximum text
+The optional argument Y-LIMIT, if non-nil, specifies the maximum text
 height that can be returned.  Text lines whose y-coordinate is beyond
 height that can be returned.  Text lines whose y-coordinate is beyond
-Y_LIMIT are ignored.  Since calculating the text height of a large
+Y-LIMIT are ignored.  Since calculating the text height of a large
 buffer can take some time, it makes sense to specify this argument if
 the size of the buffer is unknown.
 
 buffer can take some time, it makes sense to specify this argument if
 the size of the buffer is unknown.
 
-Optional argument MODE_AND_HEADER_LINE nil or omitted means do not
+Optional argument MODE-AND-HEADER-LINE nil or omitted means do not
 include the height of the mode- or header-line of WINDOW in the return
 value.  If it is either the symbol `mode-line' or `header-line', include
 only the height of that line, if present, in the return value.  If t,
 include the height of the mode- or header-line of WINDOW in the return
 value.  If it is either the symbol `mode-line' or `header-line', include
 only the height of that line, if present, in the return value.  If t,
@@ -9845,9 +9932,7 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
          for (i = 0; i < nbytes; i += char_bytes)
            {
              c = string_char_and_length (msg + i, &char_bytes);
          for (i = 0; i < nbytes; i += char_bytes)
            {
              c = string_char_and_length (msg + i, &char_bytes);
-             work[0] = (ASCII_CHAR_P (c)
-                        ? c
-                        : multibyte_char_to_unibyte (c));
+             work[0] = CHAR_TO_BYTE8 (c);
              insert_1_both (work, 1, 1, 1, 0, 0);
            }
        }
              insert_1_both (work, 1, 1, 1, 0, 0);
            }
        }
@@ -10129,19 +10214,17 @@ message_with_string (const char *m, Lisp_Object string, int log)
     {
       if (m)
        {
     {
       if (m)
        {
-         /* ENCODE_SYSTEM below can GC and/or relocate the Lisp
-            String whose data pointer might be passed to us in M.  So
-            we use a local copy.  */
-         char *fmt = xstrdup (m);
+         /* ENCODE_SYSTEM below can GC and/or relocate the
+            Lisp data, so make sure we don't use it here.  */
+         eassert (relocatable_string_data_p (m) != 1);
 
          if (noninteractive_need_newline)
            putc ('\n', stderr);
          noninteractive_need_newline = 0;
 
          if (noninteractive_need_newline)
            putc ('\n', stderr);
          noninteractive_need_newline = 0;
-         fprintf (stderr, fmt, SDATA (ENCODE_SYSTEM (string)));
+         fprintf (stderr, m, SDATA (ENCODE_SYSTEM (string)));
          if (!cursor_in_echo_area)
            fprintf (stderr, "\n");
          fflush (stderr);
          if (!cursor_in_echo_area)
            fprintf (stderr, "\n");
          fflush (stderr);
-         xfree (fmt);
        }
     }
   else if (INTERACTIVE)
        }
     }
   else if (INTERACTIVE)
@@ -10342,7 +10425,7 @@ with_echo_area_buffer (struct window *w, int which,
 {
   Lisp_Object buffer;
   int this_one, the_other, clear_buffer_p, rc;
 {
   Lisp_Object buffer;
   int this_one, the_other, clear_buffer_p, rc;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   /* If buffers aren't live, make new ones.  */
   ensure_echo_area_buffers ();
 
   /* If buffers aren't live, make new ones.  */
   ensure_echo_area_buffers ();
@@ -10416,7 +10499,7 @@ with_echo_area_buffer (struct window *w, int which,
   eassert (BEGV >= BEG);
   eassert (ZV <= Z && ZV >= BEGV);
 
   eassert (BEGV >= BEG);
   eassert (ZV <= Z && ZV >= BEGV);
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return rc;
 }
 
   return rc;
 }
 
@@ -10521,11 +10604,11 @@ setup_echo_area_for_printing (int multibyte_p)
 
       if (Z > BEG)
        {
 
       if (Z > BEG)
        {
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
          specbind (Qinhibit_read_only, Qt);
          /* Note that undo recording is always disabled.  */
          del_range (BEG, Z);
          specbind (Qinhibit_read_only, Qt);
          /* Note that undo recording is always disabled.  */
          del_range (BEG, Z);
-         unbind_to (count, Qnil);
+         dynwind_end ();
        }
       TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
        }
       TEMP_SET_PT_BOTH (BEG, BEG_BYTE);
 
@@ -10576,13 +10659,6 @@ display_echo_area (struct window *w)
 {
   int i, no_message_p, window_height_changed_p;
 
 {
   int i, no_message_p, window_height_changed_p;
 
-  /* Temporarily disable garbage collections while displaying the echo
-     area.  This is done because a GC can print a message itself.
-     That message would modify the echo area buffer's contents while a
-     redisplay of the buffer is going on, and seriously confuse
-     redisplay.  */
-  ptrdiff_t count = inhibit_garbage_collection ();
-
   /* If there is no message, we must call display_echo_area_1
      nevertheless because it resizes the window.  But we will have to
      reset the echo_area_buffer in question to nil at the end because
   /* If there is no message, we must call display_echo_area_1
      nevertheless because it resizes the window.  But we will have to
      reset the echo_area_buffer in question to nil at the end because
@@ -10598,7 +10674,6 @@ display_echo_area (struct window *w)
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
 
   if (no_message_p)
     echo_area_buffer[i] = Qnil;
 
-  unbind_to (count, Qnil);
   return window_height_changed_p;
 }
 
   return window_height_changed_p;
 }
 
@@ -11110,11 +11185,11 @@ echo_area_display (int update_frame_p)
              /* Must update other windows.  Likewise as in other
                 cases, don't let this update be interrupted by
                 pending input.  */
              /* Must update other windows.  Likewise as in other
                 cases, don't let this update be interrupted by
                 pending input.  */
-             ptrdiff_t count = SPECPDL_INDEX ();
+             dynwind_begin ();
              specbind (Qredisplay_dont_pause, Qt);
              windows_or_buffers_changed = 44;
              redisplay_internal ();
              specbind (Qredisplay_dont_pause, Qt);
              windows_or_buffers_changed = 44;
              redisplay_internal ();
-             unbind_to (count, Qnil);
+             dynwind_end ();
            }
          else if (FRAME_WINDOW_P (f) && n == 0)
            {
            }
          else if (FRAME_WINDOW_P (f) && n == 0)
            {
@@ -11406,7 +11481,7 @@ x_consider_frame_title (Lisp_Object frame)
       char *title;
       ptrdiff_t len;
       struct it it;
       char *title;
       ptrdiff_t len;
       struct it it;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
 
       FOR_EACH_FRAME (tail, other_frame)
        {
 
       FOR_EACH_FRAME (tail, other_frame)
        {
@@ -11442,7 +11517,7 @@ x_consider_frame_title (Lisp_Object frame)
       display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
       len = MODE_LINE_NOPROP_LEN (title_start);
       title = mode_line_noprop_buf + title_start;
       display_mode_element (&it, 0, -1, -1, fmt, Qnil, 0);
       len = MODE_LINE_NOPROP_LEN (title_start);
       title = mode_line_noprop_buf + title_start;
-      unbind_to (count, Qnil);
+      dynwind_end ();
 
       /* Set the title only if it's changed.  This avoids consing in
         the common case where it hasn't.  (If it turns out that we've
 
       /* Set the title only if it's changed.  This avoids consing in
         the common case where it hasn't.  (If it turns out that we've
@@ -11505,7 +11580,7 @@ prepare_menu_bars (void)
                }
            }
        }
                }
            }
        }
-      safe_call1 (Vpre_redisplay_function, windows);
+      safe__call1 (true, Vpre_redisplay_function, windows);
     }
 
   /* Update all frame titles based on their buffer names, etc.  We do
     }
 
   /* Update all frame titles based on their buffer names, etc.  We do
@@ -11550,7 +11625,7 @@ prepare_menu_bars (void)
   if (all_windows)
     {
       Lisp_Object tail, frame;
   if (all_windows)
     {
       Lisp_Object tail, frame;
-      ptrdiff_t count = SPECPDL_INDEX ();
+      dynwind_begin ();
       /* 1 means that update_menu_bar has run its hooks
         so any further calls to update_menu_bar shouldn't do so again.  */
       int menu_bar_hooks_run = 0;
       /* 1 means that update_menu_bar has run its hooks
         so any further calls to update_menu_bar shouldn't do so again.  */
       int menu_bar_hooks_run = 0;
@@ -11606,7 +11681,7 @@ prepare_menu_bars (void)
          UNGCPRO;
        }
 
          UNGCPRO;
        }
 
-      unbind_to (count, Qnil);
+      dynwind_end ();
     }
   else
     {
     }
   else
     {
@@ -11669,7 +11744,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
 
          specbind (Qinhibit_menubar_update, Qt);
 
 
          specbind (Qinhibit_menubar_update, Qt);
 
@@ -11722,7 +11797,7 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
          w->update_mode_line = 1;
 #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || HAVE_NS || USE_GTK) */
 
          w->update_mode_line = 1;
 #endif /* ! (USE_X_TOOLKIT || HAVE_NTGUI || HAVE_NS || USE_GTK) */
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
          set_buffer_internal_1 (prev);
        }
     }
          set_buffer_internal_1 (prev);
        }
     }
@@ -11736,11 +11811,6 @@ update_menu_bar (struct frame *f, int save_match_data, int hooks_run)
 
 #ifdef HAVE_WINDOW_SYSTEM
 
 
 #ifdef HAVE_WINDOW_SYSTEM
 
-/* Tool-bar item index of the item on which a mouse button was pressed
-   or -1.  */
-
-int last_tool_bar_item;
-
 /* Select `frame' temporarily without running all the code in
    do_switch_frame.
    FIXME: Maybe do_switch_frame should be trimmed down similarly
 /* Select `frame' temporarily without running all the code in
    do_switch_frame.
    FIXME: Maybe do_switch_frame should be trimmed down similarly
@@ -11791,7 +11861,7 @@ update_tool_bar (struct frame *f, int save_match_data)
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
          || window_buffer_changed (w))
        {
          struct buffer *prev = current_buffer;
-         ptrdiff_t count = SPECPDL_INDEX ();
+         dynwind_begin ();
          Lisp_Object frame, new_tool_bar;
           int new_n_tool_bar;
          struct gcpro gcpro1;
          Lisp_Object frame, new_tool_bar;
           int new_n_tool_bar;
          struct gcpro gcpro1;
@@ -11847,7 +11917,7 @@ update_tool_bar (struct frame *f, int save_match_data)
 
          UNGCPRO;
 
 
          UNGCPRO;
 
-         unbind_to (count, Qnil);
+         dynwind_end ();
          set_buffer_internal_1 (prev);
        }
     }
          set_buffer_internal_1 (prev);
        }
     }
@@ -12199,11 +12269,6 @@ tool_bar_height (struct frame *f, int *n_rows, bool pixelwise)
 
 #endif /* !USE_GTK && !HAVE_NS */
 
 
 #endif /* !USE_GTK && !HAVE_NS */
 
-#if defined USE_GTK || defined HAVE_NS
-EXFUN (Ftool_bar_height, 2) ATTRIBUTE_CONST;
-EXFUN (Ftool_bar_lines_needed, 1) ATTRIBUTE_CONST;
-#endif
-
 DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height,
        0, 2, 0,
        doc: /* Return the number of lines occupied by the tool bar of FRAME.
 DEFUN ("tool-bar-height", Ftool_bar_height, Stool_bar_height,
        0, 2, 0,
        doc: /* Return the number of lines occupied by the tool bar of FRAME.
@@ -12542,7 +12607,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
      where the button was pressed, disregarding where it was
      released.  */
   if (NILP (Vmouse_highlight) && !down_p)
      where the button was pressed, disregarding where it was
      released.  */
   if (NILP (Vmouse_highlight) && !down_p)
-    prop_idx = last_tool_bar_item;
+    prop_idx = f->last_tool_bar_item;
 
   /* If item is disabled, do nothing.  */
   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
 
   /* If item is disabled, do nothing.  */
   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
@@ -12554,7 +12619,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       /* Show item in pressed state.  */
       if (!NILP (Vmouse_highlight))
        show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
       /* Show item in pressed state.  */
       if (!NILP (Vmouse_highlight))
        show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
-      last_tool_bar_item = prop_idx;
+      f->last_tool_bar_item = prop_idx;
     }
   else
     {
     }
   else
     {
@@ -12579,7 +12644,7 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       event.arg = key;
       event.modifiers = modifiers;
       kbd_buffer_store_event (&event);
       event.arg = key;
       event.modifiers = modifiers;
       kbd_buffer_store_event (&event);
-      last_tool_bar_item = -1;
+      f->last_tool_bar_item = -1;
     }
 }
 
     }
 }
 
@@ -12629,8 +12694,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
   mouse_down_p = (x_mouse_grabbed (dpyinfo)
                  && f == dpyinfo->last_mouse_frame);
 
   mouse_down_p = (x_mouse_grabbed (dpyinfo)
                  && f == dpyinfo->last_mouse_frame);
 
-  if (mouse_down_p
-      && last_tool_bar_item != prop_idx)
+  if (mouse_down_p && f->last_tool_bar_item != prop_idx)
     return;
 
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
     return;
 
   draw = mouse_down_p ? DRAW_IMAGE_SUNKEN : DRAW_IMAGE_RAISED;
@@ -13254,15 +13318,6 @@ propagate_buffer_redisplay (void)
     }
 }
 
     }
 }
 
-#define STOP_POLLING                                   \
-do { if (! polling_stopped_here) stop_polling ();      \
-       polling_stopped_here = 1; } while (0)
-
-#define RESUME_POLLING                                 \
-do { if (polling_stopped_here) start_polling ();       \
-       polling_stopped_here = 0; } while (0)
-
-
 /* Perhaps in the future avoid recentering windows if it
    is not necessary; currently that causes some problems.  */
 
 /* Perhaps in the future avoid recentering windows if it
    is not necessary; currently that causes some problems.  */
 
@@ -13317,13 +13372,13 @@ redisplay_internal (void)
 
   /* Record a function that clears redisplaying_p
      when we leave this function.  */
 
   /* Record a function that clears redisplaying_p
      when we leave this function.  */
-  count = SPECPDL_INDEX ();
+  dynwind_begin ();
   record_unwind_protect_void (unwind_redisplay);
   redisplaying_p = 1;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
   /* Record this function, so it appears on the profiler's backtraces.  */
   record_unwind_protect_void (unwind_redisplay);
   redisplaying_p = 1;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
   /* Record this function, so it appears on the profiler's backtraces.  */
-  record_in_backtrace (Qredisplay_internal, &Qnil, 0);
+  /*record_in_backtrace (Qredisplay_internal, &Qnil, 0);*/
 
   FOR_EACH_FRAME (tail, frame)
     XFRAME (frame)->already_hscrolled_p = 0;
 
   FOR_EACH_FRAME (tail, frame)
     XFRAME (frame)->already_hscrolled_p = 0;
@@ -13762,13 +13817,6 @@ redisplay_internal (void)
                        goto retry_frame;
                    }
 
                        goto retry_frame;
                    }
 
-                 /* Prevent various kinds of signals during display
-                    update.  stdio is not robust about handling
-                    signals, which can cause an apparent I/O error.  */
-                 if (interrupt_input)
-                   unrequest_sigio ();
-                 STOP_POLLING;
-
                  pending |= update_frame (f, 0, 0);
                  f->cursor_type_changed = 0;
                  f->updated_p = 1;
                  pending |= update_frame (f, 0, 0);
                  f->cursor_type_changed = 0;
                  f->updated_p = 1;
@@ -13819,13 +13867,6 @@ redisplay_internal (void)
       if (sf->fonts_changed)
        goto retry;
 
       if (sf->fonts_changed)
        goto retry;
 
-      /* Prevent various kinds of signals during display update.
-        stdio is not robust about handling signals,
-        which can cause an apparent I/O error.  */
-      if (interrupt_input)
-       unrequest_sigio ();
-      STOP_POLLING;
-
       if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
        {
          if (hscroll_windows (selected_window))
       if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf))
        {
          if (hscroll_windows (selected_window))
@@ -13896,14 +13937,6 @@ redisplay_internal (void)
       windows_or_buffers_changed = 0;
     }
 
       windows_or_buffers_changed = 0;
     }
 
-  /* Start SIGIO interrupts coming again.  Having them off during the
-     code above makes it less likely one will discard output, but not
-     impossible, since there might be stuff in the system buffer here.
-     But it is much hairier to try to do anything about that.  */
-  if (interrupt_input)
-    request_sigio ();
-  RESUME_POLLING;
-
   /* If a frame has become visible which was not before, redisplay
      again, so that we display it.  Expose events for such a frame
      (which it gets when becoming visible) don't call the parts of
   /* If a frame has become visible which was not before, redisplay
      again, so that we display it.  Expose events for such a frame
      (which it gets when becoming visible) don't call the parts of
@@ -13954,11 +13987,7 @@ redisplay_internal (void)
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
-  if (interrupt_input && interrupts_deferred)
-    request_sigio ();
-
-  unbind_to (count, Qnil);
-  RESUME_POLLING;
+  dynwind_end ();
 }
 
 
 }
 
 
@@ -14349,7 +14378,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
-                 bpos_max = prop_pos - 1;
+                 bpos_max = prop_pos;
              }
            if (INTEGERP (chprop))
              {
              }
            if (INTEGERP (chprop))
              {
@@ -14423,7 +14452,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
                                              pos_after, 0);
 
                if (prop_pos >= pos_before)
-                 bpos_max = prop_pos - 1;
+                 bpos_max = prop_pos;
              }
            if (INTEGERP (chprop))
              {
              }
            if (INTEGERP (chprop))
              {
@@ -14453,7 +14482,7 @@ set_cursor_from_row (struct window *w, struct glyph_row *row,
      GLYPH_BEFORE and GLYPH_AFTER.  */
   if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
        && BUFFERP (glyph->object) && glyph->charpos == pt_old)
      GLYPH_BEFORE and GLYPH_AFTER.  */
   if (!((row->reversed_p ? glyph > glyphs_end : glyph < glyphs_end)
        && BUFFERP (glyph->object) && glyph->charpos == pt_old)
-      && !(bpos_max < pt_old && pt_old <= bpos_covered))
+      && !(bpos_max <= pt_old && pt_old <= bpos_covered))
     {
       /* An empty line has a single glyph whose OBJECT is zero and
         whose CHARPOS is the position of a newline on that line.
     {
       /* An empty line has a single glyph whose OBJECT is zero and
         whose CHARPOS is the position of a newline on that line.
@@ -15640,9 +15669,6 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
   return rc;
 }
 
   return rc;
 }
 
-#if !defined USE_TOOLKIT_SCROLL_BARS || defined USE_GTK
-static
-#endif
 void
 set_vertical_scroll_bar (struct window *w)
 {
 void
 set_vertical_scroll_bar (struct window *w)
 {
@@ -15685,7 +15711,51 @@ set_vertical_scroll_bar (struct window *w)
    selected_window is redisplayed.
 
    We can return without actually redisplaying the window if fonts has been
    selected_window is redisplayed.
 
    We can return without actually redisplaying the window if fonts has been
-   changed on window's frame.  In that case, redisplay_internal will retry.  */
+   changed on window's frame.  In that case, redisplay_internal will retry.
+
+   As one of the important parts of redisplaying a window, we need to
+   decide whether the previous window-start position (stored in the
+   window's w->start marker position) is still valid, and if it isn't,
+   recompute it.  Some details about that:
+
+    . The previous window-start could be in a continuation line, in
+      which case we need to recompute it when the window width
+      changes.  See compute_window_start_on_continuation_line and its
+      call below.
+
+    . The text that changed since last redisplay could include the
+      previous window-start position.  In that case, we try to salvage
+      what we can from the current glyph matrix by calling
+      try_scrolling, which see.
+
+    . Some Emacs command could force us to use a specific window-start
+      position by setting the window's force_start flag, or gently
+      propose doing that by setting the window's optional_new_start
+      flag.  In these cases, we try using the specified start point if
+      that succeeds (i.e. the window desired matrix is successfully
+      recomputed, and point location is within the window).  In case
+      of optional_new_start, we first check if the specified start
+      position is feasible, i.e. if it will allow point to be
+      displayed in the window.  If using the specified start point
+      fails, e.g., if new fonts are needed to be loaded, we abort the
+      redisplay cycle and leave it up to the next cycle to figure out
+      things.
+
+    . Note that the window's force_start flag is sometimes set by
+      redisplay itself, when it decides that the previous window start
+      point is fine and should be kept.  Search for "goto force_start"
+      below to see the details.  Like the values of window-start
+      specified outside of redisplay, these internally-deduced values
+      are tested for feasibility, and ignored if found to be
+      unfeasible.
+
+    . Note that the function try_window, used to completely redisplay
+      a window, accepts the window's start point as its argument.
+      This is used several times in the redisplay code to control
+      where the window start will be, according to user options such
+      as scroll-conservatively, and also to ensure the screen line
+      showing point will be fully (as opposed to partially) visible on
+      display.  */
 
 static void
 redisplay_window (Lisp_Object window, bool just_this_one_p)
 
 static void
 redisplay_window (Lisp_Object window, bool just_this_one_p)
@@ -15705,7 +15775,6 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
      It indicates that the buffer contents and narrowing are unchanged.  */
   bool buffer_unchanged_p = false;
   int temp_scroll_step = 0;
      It indicates that the buffer contents and narrowing are unchanged.  */
   bool buffer_unchanged_p = false;
   int temp_scroll_step = 0;
-  ptrdiff_t count = SPECPDL_INDEX ();
   int rc;
   int centering_position = -1;
   int last_line_misfit = 0;
   int rc;
   int centering_position = -1;
   int last_line_misfit = 0;
@@ -15731,6 +15800,10 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   eassert (XMARKER (w->start)->buffer == buffer);
   eassert (XMARKER (w->pointm)->buffer == buffer);
 
   eassert (XMARKER (w->start)->buffer == buffer);
   eassert (XMARKER (w->pointm)->buffer == buffer);
 
+  dynwind_begin ();
+
+  /* We come here again if we need to run window-text-change-functions
+     below.  */
  restart:
   reconsider_clip_changes (w);
   frame_line_height = default_line_pixel_height (w);
  restart:
   reconsider_clip_changes (w);
   frame_line_height = default_line_pixel_height (w);
@@ -15795,7 +15868,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
        && !current_buffer->prevent_redisplay_optimizations_p
        && !window_outdated (w));
 
        && !current_buffer->prevent_redisplay_optimizations_p
        && !window_outdated (w));
 
-  /* Run the window-bottom-change-functions
+  /* Run the window-text-change-functions
      if it is possible that the text on the screen has changed
      (either due to modification of the text, or any other reason).  */
   if (!current_matrix_up_to_date_p
      if it is possible that the text on the screen has changed
      (either due to modification of the text, or any other reason).  */
   if (!current_matrix_up_to_date_p
@@ -16396,12 +16469,50 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   /* Consider the following case: Window starts at BEGV, there is
      invisible, intangible text at BEGV, so that display starts at
      some point START > BEGV.  It can happen that we are called with
   /* Consider the following case: Window starts at BEGV, there is
      invisible, intangible text at BEGV, so that display starts at
      some point START > BEGV.  It can happen that we are called with
-     PT somewhere between BEGV and START.  Try to handle that case.  */
+     PT somewhere between BEGV and START.  Try to handle that case,
+     and similar ones.  */
   if (w->cursor.vpos < 0)
     {
   if (w->cursor.vpos < 0)
     {
-      struct glyph_row *row = w->current_matrix->rows;
-      if (row->mode_line_p)
-       ++row;
+      /* First, try locating the proper glyph row for PT.  */
+      struct glyph_row *row =
+       row_containing_pos (w, PT, w->current_matrix->rows, NULL, 0);
+
+      /* Sometimes point is at the beginning of invisible text that is
+        before the 1st character displayed in the row.  In that case,
+        row_containing_pos fails to find the row, because no glyphs
+        with appropriate buffer positions are present in the row.
+        Therefore, we next try to find the row which shows the 1st
+        position after the invisible text.  */
+      if (!row)
+       {
+         Lisp_Object val =
+           get_char_property_and_overlay (make_number (PT), Qinvisible,
+                                          Qnil, NULL);
+
+         if (TEXT_PROP_MEANS_INVISIBLE (val))
+           {
+             ptrdiff_t alt_pos;
+             Lisp_Object invis_end =
+               Fnext_single_char_property_change (make_number (PT), Qinvisible,
+                                                  Qnil, Qnil);
+
+             if (NATNUMP (invis_end))
+               alt_pos = XFASTINT (invis_end);
+             else
+               alt_pos = ZV;
+             row = row_containing_pos (w, alt_pos, w->current_matrix->rows,
+                                       NULL, 0);
+           }
+       }
+      /* Finally, fall back on the first row of the window after the
+        header line (if any).  This is slightly better than not
+        displaying the cursor at all.  */
+      if (!row)
+       {
+         row = w->current_matrix->rows;
+         if (row->mode_line_p)
+           ++row;
+       }
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
@@ -16604,7 +16715,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   if (CHARPOS (lpoint) <= ZV)
     TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
 
   if (CHARPOS (lpoint) <= ZV)
     TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 }
 
 
 }
 
 
@@ -18612,6 +18723,7 @@ insert_left_trunc_glyphs (struct it *it)
   truncate_it.current_x = 0;
   truncate_it.face_id = DEFAULT_FACE_ID;
   truncate_it.glyph_row = &scratch_glyph_row;
   truncate_it.current_x = 0;
   truncate_it.face_id = DEFAULT_FACE_ID;
   truncate_it.glyph_row = &scratch_glyph_row;
+  truncate_it.area = TEXT_AREA;
   truncate_it.glyph_row->used[TEXT_AREA] = 0;
   CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
   truncate_it.object = make_number (0);
   truncate_it.glyph_row->used[TEXT_AREA] = 0;
   CHARPOS (truncate_it.position) = BYTEPOS (truncate_it.position) = -1;
   truncate_it.object = make_number (0);
@@ -20590,6 +20702,10 @@ Value is the new character position of point.  */)
       && !b->clip_changed
       && !b->prevent_redisplay_optimizations_p
       && !window_outdated (w)
       && !b->clip_changed
       && !b->prevent_redisplay_optimizations_p
       && !window_outdated (w)
+      /* We rely below on the cursor coordinates to be up to date, but
+        we cannot trust them if some command moved point since the
+        last complete redisplay.  */
+      && w->last_point == BUF_PT (b)
       && w->cursor.vpos >= 0
       && w->cursor.vpos < w->current_matrix->nrows
       && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
       && w->cursor.vpos >= 0
       && w->cursor.vpos < w->current_matrix->nrows
       && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
@@ -20880,7 +20996,10 @@ Value is the new character position of point.  */)
                  SAVE_IT (it2, it, it_data);
                  move_it_in_display_line_to (&it, ZV, target_x,
                                              MOVE_TO_POS | MOVE_TO_X);
                  SAVE_IT (it2, it, it_data);
                  move_it_in_display_line_to (&it, ZV, target_x,
                                              MOVE_TO_POS | MOVE_TO_X);
-                 target_x = it.current_x - 1;
+                 /* If we arrived at target_x, that _is_ the last
+                    character on the previous line.  */
+                 if (it.current_x != target_x)
+                   target_x = it.current_x - 1;
                  RESTORE_IT (&it, &it2, it_data);
                }
            }
                  RESTORE_IT (&it, &it2, it_data);
                }
            }
@@ -21350,7 +21469,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
 {
   struct it it;
   struct face *face;
 {
   struct it it;
   struct face *face;
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
   /* Don't extend on a previously drawn mode-line.
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
   /* Don't extend on a previously drawn mode-line.
@@ -21378,7 +21497,7 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
   pop_kboard ();
 
   display_mode_element (&it, 0, 0, 0, format, Qnil, 0);
   pop_kboard ();
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
 
   /* Fill up with spaces.  */
   display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
 
   /* Fill up with spaces.  */
   display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0);
@@ -21777,7 +21896,7 @@ display_mode_element (struct it *it, int depth, int field_width, int precision,
            if (CONSP (XCDR (elt)))
              {
                Lisp_Object spec;
            if (CONSP (XCDR (elt)))
              {
                Lisp_Object spec;
-               spec = safe_eval (XCAR (XCDR (elt)));
+               spec = safe__eval (true, XCAR (XCDR (elt)));
                n += display_mode_element (it, depth, field_width - n,
                                           precision - n, spec, props,
                                           risky);
                n += display_mode_element (it, depth, field_width - n,
                                           precision - n, spec, props,
                                           risky);
@@ -22030,7 +22149,7 @@ are the selected window and the WINDOW's buffer).  */)
   struct buffer *old_buffer = NULL;
   int face_id;
   int no_props = INTEGERP (face);
   struct buffer *old_buffer = NULL;
   int face_id;
   int no_props = INTEGERP (face);
-  ptrdiff_t count = SPECPDL_INDEX ();
+  dynwind_begin ();
   Lisp_Object str;
   int string_start = 0;
 
   Lisp_Object str;
   int string_start = 0;
 
@@ -22043,8 +22162,10 @@ are the selected window and the WINDOW's buffer).  */)
 
   /* Make formatting the modeline a non-op when noninteractive, otherwise
      there will be problems later caused by a partially initialized frame.  */
 
   /* Make formatting the modeline a non-op when noninteractive, otherwise
      there will be problems later caused by a partially initialized frame.  */
-  if (NILP (format) || noninteractive)
+  if (NILP (format) || noninteractive) {
+    dynwind_end ();
     return empty_unibyte_string;
     return empty_unibyte_string;
+  }
 
   if (no_props)
     face = Qnil;
 
   if (no_props)
     face = Qnil;
@@ -22105,7 +22226,7 @@ are the selected window and the WINDOW's buffer).  */)
                        empty_unibyte_string);
     }
 
                        empty_unibyte_string);
     }
 
-  unbind_to (count, Qnil);
+  dynwind_end ();
   return str;
 }
 
   return str;
 }
 
@@ -22594,7 +22715,7 @@ decode_mode_spec (struct window *w, register int c, int field_width,
        return decode_mode_spec_buf;
     no_value:
         {
        return decode_mode_spec_buf;
     no_value:
         {
-         charp = decode_mode_spec_buf;
+         char *p = decode_mode_spec_buf;
          int pad = width - 2;
          while (pad-- > 0)
            *p++ = ' ';
          int pad = width - 2;
          while (pad-- > 0)
            *p++ = ' ';
@@ -22690,10 +22811,8 @@ decode_mode_spec (struct window *w, register int c, int field_width,
 
     case '@':
       {
 
     case '@':
       {
-       ptrdiff_t count = inhibit_garbage_collection ();
        Lisp_Object val = call1 (intern ("file-remote-p"),
                                 BVAR (current_buffer, directory));
        Lisp_Object val = call1 (intern ("file-remote-p"),
                                 BVAR (current_buffer, directory));
-       unbind_to (count, Qnil);
 
        if (NILP (val))
          return "-";
 
        if (NILP (val))
          return "-";
@@ -23342,7 +23461,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
            return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
        }
 
            return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
        }
 
-      prop = buffer_local_value_1 (prop, it->w->contents);
+      prop = buffer_local_value (prop, it->w->contents);
       if (EQ (prop, Qunbound))
        prop = Qnil;
     }
       if (EQ (prop, Qunbound))
        prop = Qnil;
     }
@@ -23394,7 +23513,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
              return OK_PIXELS (pixels);
            }
 
              return OK_PIXELS (pixels);
            }
 
-         car = buffer_local_value_1 (car, it->w->contents);
+         car = buffer_local_value (car, it->w->contents);
          if (EQ (car, Qunbound))
            car = Qnil;
        }
          if (EQ (car, Qunbound))
            car = Qnil;
        }
@@ -23571,7 +23690,7 @@ get_char_face_and_encoding (struct frame *f, int c, int face_id,
 #endif
     {
       eassert (face != NULL);
 #endif
     {
       eassert (face != NULL);
-      PREPARE_FACE_FOR_DISPLAY (f, face);
+      prepare_face_for_display (f, face);
     }
 
   return face;
     }
 
   return face;
@@ -23594,7 +23713,7 @@ get_glyph_face_and_encoding (struct frame *f, struct glyph *glyph,
 
   /* Make sure X resources of the face are allocated.  */
   eassert (face != NULL);
 
   /* Make sure X resources of the face are allocated.  */
   eassert (face != NULL);
-  PREPARE_FACE_FOR_DISPLAY (f, face);
+  prepare_face_for_display (f, face);
 
   if (two_byte_p)
     *two_byte_p = 0;
 
   if (two_byte_p)
     *two_byte_p = 0;
@@ -23911,7 +24030,7 @@ fill_stretch_glyph_string (struct glyph_string *s, int start, int end)
   s->ybase += voffset;
 
   /* The case that face->gc == 0 is handled when drawing the glyph
   s->ybase += voffset;
 
   /* The case that face->gc == 0 is handled when drawing the glyph
-     string by calling PREPARE_FACE_FOR_DISPLAY.  */
+     string by calling prepare_face_for_display.  */
   eassert (s->face);
   return glyph - s->row->glyphs[s->area];
 }
   eassert (s->face);
   return glyph - s->row->glyphs[s->area];
 }
@@ -24509,13 +24628,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
+         if (hl != overlap_hl)
+           clip_head = head;
          j = i;
          BUILD_GLYPH_STRINGS (j, start, h, t,
                               overlap_hl, dummy_x, last_x);
          start = i;
          compute_overhangs_and_x (t, head->x, 1);
          prepend_glyph_string_lists (&head, &tail, h, t);
          j = i;
          BUILD_GLYPH_STRINGS (j, start, h, t,
                               overlap_hl, dummy_x, last_x);
          start = i;
          compute_overhangs_and_x (t, head->x, 1);
          prepend_glyph_string_lists (&head, &tail, h, t);
-         clip_head = head;
+         if (clip_head == NULL)
+           clip_head = head;
        }
 
       /* Prepend glyph strings for glyphs in front of the first glyph
        }
 
       /* Prepend glyph strings for glyphs in front of the first glyph
@@ -24536,7 +24658,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
-         clip_head = head;
+         if (hl == overlap_hl || clip_head == NULL)
+           clip_head = head;
          BUILD_GLYPH_STRINGS (i, start, h, t,
                               overlap_hl, dummy_x, last_x);
          for (s = h; s; s = s->next)
          BUILD_GLYPH_STRINGS (i, start, h, t,
                               overlap_hl, dummy_x, last_x);
          for (s = h; s; s = s->next)
@@ -24560,13 +24683,16 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
+         if (hl != overlap_hl)
+           clip_tail = tail;
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
          /* Because BUILD_GLYPH_STRINGS updates the first argument,
             we don't have `end = i;' here.  */
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
          /* Because BUILD_GLYPH_STRINGS updates the first argument,
             we don't have `end = i;' here.  */
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
-         clip_tail = tail;
+         if (clip_tail == NULL)
+           clip_tail = tail;
        }
 
       /* Append glyph strings for glyphs following the last glyph
        }
 
       /* Append glyph strings for glyphs following the last glyph
@@ -24584,7 +24710,8 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
          else
            overlap_hl = DRAW_NORMAL_TEXT;
 
-         clip_tail = tail;
+         if (hl == overlap_hl || clip_tail == NULL)
+           clip_tail = tail;
          i++;                  /* We must include the Ith glyph.  */
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
          i++;                  /* We must include the Ith glyph.  */
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               overlap_hl, x, last_x);
@@ -24852,7 +24979,7 @@ produce_image_glyph (struct it *it)
   face = FACE_FROM_ID (it->f, it->face_id);
   eassert (face);
   /* Make sure X resources of the face is loaded.  */
   face = FACE_FROM_ID (it->f, it->face_id);
   eassert (face);
   /* Make sure X resources of the face is loaded.  */
-  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+  prepare_face_for_display (it->f, face);
 
   if (it->image_id < 0)
     {
 
   if (it->image_id < 0)
     {
@@ -25130,7 +25257,7 @@ produce_stretch_glyph (struct it *it)
     {
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
     {
       struct face *face = FACE_FROM_ID (it->f, it->face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
-      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+      prepare_face_for_display (it->f, face);
     }
 #endif
 
     }
 #endif
 
@@ -25594,7 +25721,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
 
       face = FACE_FROM_ID (it->f, face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
 
       face = FACE_FROM_ID (it->f, face_id);
       font = face->font ? face->font : FRAME_FONT (it->f);
-      PREPARE_FACE_FOR_DISPLAY (it->f, face);
+      prepare_face_for_display (it->f, face);
 
       if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
        {
 
       if (it->glyphless_method == GLYPHLESS_DISPLAY_ACRONYM)
        {
@@ -25610,7 +25737,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
          sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
          str = buf;
        }
          sprintf (buf, "%0*X", it->c < 0x10000 ? 4 : 6, it->c);
          str = buf;
        }
-      for (len = 0; str[len] && ASCII_BYTE_P (str[len]) && len < 6; len++)
+      for (len = 0; str[len] && ASCII_CHAR_P (str[len]) && len < 6; len++)
        code[len] = font->driver->encode_char (font, str[len]);
       upper_len = (len + 1) / 2;
       font->driver->text_extents (font, code, upper_len,
        code[len] = font->driver->encode_char (font, str[len]);
       upper_len = (len + 1) / 2;
       font->driver->text_extents (font, code, upper_len,
@@ -26935,9 +27062,6 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
 
 /* Erase the image of a cursor of window W from the screen.  */
 
 
 /* Erase the image of a cursor of window W from the screen.  */
 
-#ifndef HAVE_NTGUI
-static
-#endif
 void
 erase_phys_cursor (struct window *w)
 {
 void
 erase_phys_cursor (struct window *w)
 {
@@ -27246,7 +27370,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
   if (/* If window is in the process of being destroyed, don't bother
         to do anything.  */
       w->current_matrix != NULL
   if (/* If window is in the process of being destroyed, don't bother
         to do anything.  */
       w->current_matrix != NULL
-      /* Don't update mouse highlight if hidden */
+      /* Don't update mouse highlight if hidden */
       && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
       /* Recognize when we are called to operate on rows that don't exist
         anymore.  This can happen when a window is split.  */
       && (draw != DRAW_MOUSE_FACE || !hlinfo->mouse_face_hidden)
       /* Recognize when we are called to operate on rows that don't exist
         anymore.  This can happen when a window is split.  */
@@ -28463,8 +28587,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
          else if (area == ON_MODE_LINE)
            {
              Lisp_Object default_help
          else if (area == ON_MODE_LINE)
            {
              Lisp_Object default_help
-               = buffer_local_value_1 (Qmode_line_default_help_echo,
-                                       w->contents);
+               = buffer_local_value (Qmode_line_default_help_echo,
+                                     w->contents);
 
              if (STRINGP (default_help))
                {
 
              if (STRINGP (default_help))
                {
@@ -29799,6 +29923,8 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result)
 void
 syms_of_xdisp (void)
 {
 void
 syms_of_xdisp (void)
 {
+#include "xdisp.x"
+
   Vwith_echo_area_save_vector = Qnil;
   staticpro (&Vwith_echo_area_save_vector);
 
   Vwith_echo_area_save_vector = Qnil;
   staticpro (&Vwith_echo_area_save_vector);
 
@@ -29815,25 +29941,6 @@ syms_of_xdisp (void)
   message_dolog_marker3 = Fmake_marker ();
   staticpro (&message_dolog_marker3);
 
   message_dolog_marker3 = Fmake_marker ();
   staticpro (&message_dolog_marker3);
 
-#ifdef GLYPH_DEBUG
-  defsubr (&Sdump_frame_glyph_matrix);
-  defsubr (&Sdump_glyph_matrix);
-  defsubr (&Sdump_glyph_row);
-  defsubr (&Sdump_tool_bar_row);
-  defsubr (&Strace_redisplay);
-  defsubr (&Strace_to_stderr);
-#endif
-#ifdef HAVE_WINDOW_SYSTEM
-  defsubr (&Stool_bar_height);
-  defsubr (&Slookup_image_map);
-#endif
-  defsubr (&Sline_pixel_height);
-  defsubr (&Sformat_mode_line);
-  defsubr (&Sinvisible_p);
-  defsubr (&Scurrent_bidi_paragraph_direction);
-  defsubr (&Swindow_text_pixel_size);
-  defsubr (&Smove_point_visually);
-
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
   DEFSYM (Qoverriding_local_map, "overriding-local-map");
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
   DEFSYM (Qoverriding_local_map, "overriding-local-map");
@@ -30485,7 +30592,7 @@ init_xdisp (void)
     /* Allocate the buffer for frame titles.
        Also used for `format-mode-line'.  */
     int size = 100;
     /* Allocate the buffer for frame titles.
        Also used for `format-mode-line'.  */
     int size = 100;
-    mode_line_noprop_buf = xmalloc (size);
+    mode_line_noprop_buf = xmalloc_atomic (size);
     mode_line_noprop_buf_end = mode_line_noprop_buf + size;
     mode_line_noprop_ptr = mode_line_noprop_buf;
     mode_line_target = MODE_LINE_DISPLAY;
     mode_line_noprop_buf_end = mode_line_noprop_buf + size;
     mode_line_noprop_ptr = mode_line_noprop_buf;
     mode_line_target = MODE_LINE_DISPLAY;