Omit some unnecessary casts.
[bpt/emacs.git] / src / xdisp.c
index 0a79e6f..67f4720 100644 (file)
@@ -313,8 +313,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "gtkutil.h"
 #endif
 
-#include "font.h"
-
 #ifndef FRAME_X_OUTPUT
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
 #endif
@@ -378,8 +376,7 @@ static Lisp_Object Qline_height;
    && ((IT)->bidi_it.paragraph_dir == R2L              \
        ? (WINDOW_LEFT_FRINGE_WIDTH ((IT)->w) > 0)      \
        : (WINDOW_RIGHT_FRINGE_WIDTH ((IT)->w) > 0))    \
-   && (IT)->current_x == (IT)->last_visible_x          \
-   && (IT)->line_wrap != WORD_WRAP)
+   && (IT)->current_x == (IT)->last_visible_x)
 
 #else /* !HAVE_WINDOW_SYSTEM */
 #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it) 0
@@ -807,7 +804,6 @@ static void pint2str (char *, int, ptrdiff_t);
 static void pint2hrstr (char *, int, ptrdiff_t);
 static struct text_pos run_window_scroll_functions (Lisp_Object,
                                                     struct text_pos);
-static void reconsider_clip_changes (struct window *, struct buffer *);
 static int text_outside_line_unchanged_p (struct window *,
                                          ptrdiff_t, ptrdiff_t);
 static void store_mode_line_noprop_char (char);
@@ -816,21 +812,20 @@ static void handle_stop (struct it *);
 static void handle_stop_backwards (struct it *, ptrdiff_t);
 static void vmessage (const char *, va_list) ATTRIBUTE_FORMAT_PRINTF (1, 0);
 static void ensure_echo_area_buffers (void);
-static Lisp_Object unwind_with_echo_area_buffer (Lisp_Object);
+static void 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, Lisp_Object);
 static void clear_garbaged_frames (void);
 static int current_message_1 (ptrdiff_t, Lisp_Object);
-static void pop_message (void);
 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);
 static int resize_mini_window_1 (ptrdiff_t, Lisp_Object);
-static Lisp_Object unwind_redisplay (Lisp_Object);
+static void unwind_redisplay (void);
 static int string_char_and_length (const unsigned char *, int *);
 static struct text_pos display_prop_end (struct it *, Lisp_Object,
                                          struct text_pos);
@@ -881,7 +876,6 @@ static void next_overlay_string (struct it *);
 static void reseat (struct it *, struct text_pos, int);
 static void reseat_1 (struct it *, struct text_pos, int);
 static void back_to_previous_visible_line_start (struct it *);
-void reseat_at_previous_visible_line_start (struct it *);
 static void reseat_at_next_visible_line_start (struct it *, int);
 static int next_element_from_ellipsis (struct it *);
 static int next_element_from_display_vector (struct it *);
@@ -900,7 +894,6 @@ static int get_next_display_element (struct it *);
 static enum move_it_result
        move_it_in_display_line_to (struct it *, ptrdiff_t, int,
                                   enum move_operation_enum);
-void move_it_vertically_backward (struct it *, int);
 static void get_visually_first_element (struct it *);
 static void init_to_row_start (struct it *, struct window *,
                                struct glyph_row *);
@@ -1219,6 +1212,70 @@ line_bottom_y (struct it *it)
   return line_top_y + line_height;
 }
 
+DEFUN ("line-pixel-height", Fline_pixel_height,
+       Sline_pixel_height, 0, 0, 0,
+       doc: /* Return height in pixels of text line in the selected window.
+
+Value is the height in pixels of the line at point.  */)
+  (void)
+{
+  struct it it;
+  struct text_pos pt;
+  struct window *w = XWINDOW (selected_window);
+
+  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));
+}
+
+/* Return the default pixel height of text lines in window W.  The
+   value is the canonical height of the W frame's default font, plus
+   any extra space required by the line-spacing variable or frame
+   parameter.
+
+   Implementation note: this ignores any line-spacing text properties
+   put on the newline characters.  This is because those properties
+   only affect the _screen_ line ending in the newline (i.e., in a
+   continued line, only the last screen line will be affected), which
+   means only a small number of lines in a buffer can ever use this
+   feature.  Since this function is used to compute the default pixel
+   equivalent of text lines in a window, we can safely ignore those
+   few lines.  For the same reasons, we ignore the line-height
+   properties.  */
+int
+default_line_pixel_height (struct window *w)
+{
+  struct frame *f = WINDOW_XFRAME (w);
+  int height = FRAME_LINE_HEIGHT (f);
+
+  if (!FRAME_INITIAL_P (f) && BUFFERP (w->contents))
+    {
+      struct buffer *b = XBUFFER (w->contents);
+      Lisp_Object val = BVAR (b, extra_line_spacing);
+
+      if (NILP (val))
+       val = BVAR (&buffer_defaults, extra_line_spacing);
+      if (!NILP (val))
+       {
+         if (RANGED_INTEGERP (0, val, INT_MAX))
+           height += XFASTINT (val);
+         else if (FLOATP (val))
+           {
+             int addon = XFLOAT_DATA (val) * height + 0.5;
+
+             if (addon >= 0)
+               height += addon;
+           }
+       }
+      else
+       height += f->extra_line_spacing;
+    }
+
+  return height;
+}
+
 /* Subroutine of pos_visible_p below.  Extracts a display string, if
    any, from the display spec given as its argument.  */
 static Lisp_Object
@@ -1353,8 +1410,7 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
          struct it save_it = it;
          /* Why 10? because we don't know how many canonical lines
             will the height of the next line(s) be.  So we guess.  */
-         int ten_more_lines =
-           10 * FRAME_LINE_HEIGHT (XFRAME (WINDOW_FRAME (w)));
+         int ten_more_lines = 10 * default_line_pixel_height (w);
 
          move_it_to (&it, charpos, -1, bottom_y + ten_more_lines, -1,
                      MOVE_TO_POS | MOVE_TO_Y);
@@ -1373,18 +1429,41 @@ pos_visible_p (struct window *w, ptrdiff_t charpos, int *x, int *y,
                top_x = it.glyph_row->x;
              else
                {
-                 struct it it2;
+                 struct it it2, it2_prev;
+                 /* The idea is to get to the previous buffer
+                    position, consume the character there, and use
+                    the pixel coordinates we get after that.  But if
+                    the previous buffer position is also displayed
+                    from a display vector, we need to consume all of
+                    the glyphs from that display vector.  */
                  start_display (&it2, w, top);
                  move_it_to (&it2, charpos - 1, -1, -1, -1, MOVE_TO_POS);
-                 get_next_display_element (&it2);
-                 PRODUCE_GLYPHS (&it2);
-                 if (ITERATOR_AT_END_OF_LINE_P (&it2)
-                     || it2.current_x > it2.last_visible_x)
+                 /* If we didn't get to CHARPOS - 1, there's some
+                    replacing display property at that position, and
+                    we stopped after it.  That is exactly the place
+                    whose coordinates we want.  */
+                 if (IT_CHARPOS (it2) != charpos - 1)
+                   it2_prev = it2;
+                 else
+                   {
+                     /* Iterate until we get out of the display
+                        vector that displays the character at
+                        CHARPOS - 1.  */
+                     do {
+                       get_next_display_element (&it2);
+                       PRODUCE_GLYPHS (&it2);
+                       it2_prev = it2;
+                       set_iterator_to_next (&it2, 1);
+                     } while (it2.method == GET_FROM_DISPLAY_VECTOR
+                              && IT_CHARPOS (it2) < charpos);
+                   }
+                 if (ITERATOR_AT_END_OF_LINE_P (&it2_prev)
+                     || it2_prev.current_x > it2_prev.last_visible_x)
                    top_x = it.glyph_row->x;
                  else
                    {
-                     top_x = it2.current_x;
-                     top_y = it2.current_y;
+                     top_x = it2_prev.current_x;
+                     top_y = it2_prev.current_y;
                    }
                }
            }
@@ -1774,7 +1853,7 @@ estimate_mode_line_height (struct frame *f, enum face_id face_id)
    not force the value into range.  */
 
 void
-pixel_to_glyph_coords (FRAME_PTR f, register int pix_x, register int pix_y,
+pixel_to_glyph_coords (struct frame *f, register int pix_x, register int pix_y,
                       int *x, int *y, NativeRectangle *bounds, int noclip)
 {
 
@@ -2629,6 +2708,7 @@ init_iterator (struct it *it, struct window *w,
   it->bidi_it.string.lstring = Qnil;
   it->bidi_it.string.s = NULL;
   it->bidi_it.string.bufpos = 0;
+  it->bidi_it.w = w;
 
   /* The window in which we iterate over current_buffer:  */
   XSETWINDOW (it->window, w);
@@ -3103,6 +3183,7 @@ init_from_display_pos (struct it *it, struct window *w, struct display_pos *pos)
          it->bidi_it.string.bufpos = it->overlay_strings_charpos;
          it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (IT_STRING_CHARPOS (*it), IT_STRING_BYTEPOS (*it),
                        FRAME_WINDOW_P (it->f), &it->bidi_it);
 
@@ -3469,11 +3550,11 @@ next_overlay_change (ptrdiff_t pos)
 ptrdiff_t
 compute_display_string_pos (struct text_pos *position,
                            struct bidi_string_data *string,
+                           struct window *w,
                            int frame_window_p, int *disp_prop)
 {
   /* OBJECT = nil means current buffer.  */
-  Lisp_Object object =
-    (string && STRINGP (string->lstring)) ? string->lstring : Qnil;
+  Lisp_Object object, object1;
   Lisp_Object pos, spec, limpos;
   int string_p = (string && (STRINGP (string->lstring) || string->s));
   ptrdiff_t eob = string_p ? string->schars : ZV;
@@ -3484,6 +3565,16 @@ compute_display_string_pos (struct text_pos *position,
   struct text_pos tpos;
   int rv = 0;
 
+  if (string && STRINGP (string->lstring))
+    object1 = object = string->lstring;
+  else if (w && !string_p)
+    {
+      XSETWINDOW (object, w);
+      object1 = Qnil;
+    }
+  else
+    object1 = object = Qnil;
+
   *disp_prop = 1;
 
   if (charpos >= eob
@@ -3522,7 +3613,7 @@ compute_display_string_pos (struct text_pos *position,
      that will replace the underlying text when displayed.  */
   limpos = make_number (lim);
   do {
-    pos = Fnext_single_char_property_change (pos, Qdisplay, object, limpos);
+    pos = Fnext_single_char_property_change (pos, Qdisplay, object1, limpos);
     CHARPOS (tpos) = XFASTINT (pos);
     if (CHARPOS (tpos) >= lim)
       {
@@ -5010,6 +5101,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
              it->bidi_it.string.bufpos = bufpos;
              it->bidi_it.string.from_disp_str = 1;
              it->bidi_it.string.unibyte = !it->multibyte_p;
+             it->bidi_it.w = it->w;
              bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
            }
        }
@@ -5253,7 +5345,7 @@ handle_composition_prop (struct it *it)
      composition (in the case that the composition is from the current
      buffer), draw a glyph composed from the composition components.  */
   if (find_composition (pos, -1, &start, &end, &prop, string)
-      && COMPOSITION_VALID_P (start, end, prop)
+      && composition_valid_p (start, end, prop)
       && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
       if (start < pos)
@@ -5388,6 +5480,7 @@ next_overlay_string (struct it *it)
          it->bidi_it.string.bufpos = it->overlay_strings_charpos;
          it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
        }
     }
@@ -5415,8 +5508,8 @@ next_overlay_string (struct it *it)
 static int
 compare_overlay_entries (const void *e1, const void *e2)
 {
-  struct overlay_entry *entry1 = (struct overlay_entry *) e1;
-  struct overlay_entry *entry2 = (struct overlay_entry *) e2;
+  struct overlay_entry const *entry1 = e1;
+  struct overlay_entry const *entry2 = e2;
   int result;
 
   if (entry1->after_string_p != entry2->after_string_p)
@@ -5691,6 +5784,7 @@ get_overlay_strings_1 (struct it *it, ptrdiff_t charpos, int compute_stop_p)
          it->bidi_it.string.bufpos = pos;
          it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
        }
       return 1;
@@ -6323,6 +6417,7 @@ reseat_1 (struct it *it, struct text_pos pos, int set_stop_p)
       it->bidi_it.string.lstring = Qnil;
       it->bidi_it.string.bufpos = 0;
       it->bidi_it.string.unibyte = 0;
+      it->bidi_it.w = it->w;
     }
 
   if (set_stop_p)
@@ -6400,6 +6495,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
          it->bidi_it.string.bufpos = 0;
          it->bidi_it.string.from_disp_str = 0;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (charpos, IT_STRING_BYTEPOS (*it),
                        FRAME_WINDOW_P (it->f), &it->bidi_it);
        }
@@ -6431,6 +6527,7 @@ reseat_to_string (struct it *it, const char *s, Lisp_Object string,
          it->bidi_it.string.bufpos = 0;
          it->bidi_it.string.from_disp_str = 0;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (charpos, IT_BYTEPOS (*it), FRAME_WINDOW_P (it->f),
                        &it->bidi_it);
        }
@@ -8482,7 +8579,9 @@ move_it_in_display_line_to (struct it *it,
                                    result = MOVE_LINE_CONTINUED;
                                  break;
                                }
-                             if (ITERATOR_AT_END_OF_LINE_P (it))
+                             if (ITERATOR_AT_END_OF_LINE_P (it)
+                                 && (it->line_wrap != WORD_WRAP
+                                     || wrap_it.sp < 0))
                                {
                                  result = MOVE_NEWLINE_OR_CR;
                                  break;
@@ -9000,7 +9099,7 @@ move_it_vertically_backward (struct it *it, int dy)
   start_pos = IT_CHARPOS (*it);
 
   /* Estimate how many newlines we must move back.  */
-  nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
+  nlines = max (1, dy / default_line_pixel_height (it->w));
   if (it->line_wrap == TRUNCATE)
     pos_limit = BEGV;
   else
@@ -9537,7 +9636,15 @@ message_dolog (const char *m, ptrdiff_t nbytes, bool nlflag, bool multibyte)
 
       shown = buffer_window_count (current_buffer) > 0;
       set_buffer_internal (oldbuf);
-      if (!shown)
+      /* We called insert_1_both above with its 5th argument (PREPARE)
+        zero, which prevents insert_1_both from calling
+        prepare_to_modify_buffer, which in turns prevents us from
+        incrementing windows_or_buffers_changed even if *Messages* is
+        shown in some window.  So we must manually incrementing
+        windows_or_buffers_changed here to make up for that.  */
+      if (shown)
+       windows_or_buffers_changed++;
+      else
        windows_or_buffers_changed = old_windows_or_buffers_changed;
       message_log_need_newline = !nlflag;
       Vdeactivate_mark = old_deactivate_mark;
@@ -9682,7 +9789,7 @@ message3_nolog (Lisp_Object m)
 void
 message1 (const char *m)
 {
-  message3 (m ? make_unibyte_string (m, strlen (m)) : Qnil);
+  message3 (m ? build_unibyte_string (m) : Qnil);
 }
 
 
@@ -9691,7 +9798,7 @@ message1 (const char *m)
 void
 message1_nolog (const char *m)
 {
-  message3_nolog (m ? make_unibyte_string (m, strlen (m)) : Qnil);
+  message3_nolog (m ? build_unibyte_string (m) : Qnil);
 }
 
 /* Display a message M which contains a single %s
@@ -9801,7 +9908,7 @@ vmessage (const char *m, va_list ap)
              ptrdiff_t maxsize = FRAME_MESSAGE_BUF_SIZE (f);
              char *message_buf = alloca (maxsize + 1);
 
-             len = doprnt (message_buf, maxsize, m, (char *)0, ap);
+             len = doprnt (message_buf, maxsize, m, 0, ap);
 
              message3 (make_string (message_buf, len));
            }
@@ -10037,7 +10144,7 @@ with_echo_area_buffer_unwind_data (struct window *w)
 /* Restore global state from VECTOR which was created by
    with_echo_area_buffer_unwind_data.  */
 
-static Lisp_Object
+static void
 unwind_with_echo_area_buffer (Lisp_Object vector)
 {
   set_buffer_internal_1 (XBUFFER (AREF (vector, 0)));
@@ -10062,7 +10169,6 @@ unwind_with_echo_area_buffer (Lisp_Object vector)
     }
 
   Vwith_echo_area_save_vector = vector;
-  return Qnil;
 }
 
 
@@ -10461,20 +10567,12 @@ restore_message (void)
 }
 
 
-/* Handler for record_unwind_protect calling pop_message.  */
+/* Handler for unwind-protect calling pop_message.  */
 
-Lisp_Object
-pop_message_unwind (Lisp_Object dummy)
-{
-  pop_message ();
-  return Qnil;
-}
-
-/* Pop the top-most entry off Vmessage_stack.  */
-
-static void
-pop_message (void)
+void
+pop_message_unwind (void)
 {
+  /* Pop the top-most entry off Vmessage_stack.  */
   eassert (CONSP (Vmessage_stack));
   Vmessage_stack = XCDR (Vmessage_stack);
 }
@@ -10751,17 +10849,6 @@ buffer_shared_and_changed (void)
          && UNCHANGED_MODIFIED < MODIFF);
 }
 
-/* Nonzero if W doesn't reflect the actual state of current buffer due
-   to its text or overlays change.  FIXME: this may be called when
-   XBUFFER (w->contents) != current_buffer, which looks suspicious.  */
-
-static int
-window_outdated (struct window *w)
-{
-  return (w->last_modified < MODIFF
-         || w->last_overlay_modified < OVERLAY_MODIFF);
-}
-
 /* Nonzero if W's buffer was changed but not saved or Transient Mark mode
    is enabled and mark of W's buffer was changed since last W's update.  */
 
@@ -10870,7 +10957,7 @@ format_mode_line_unwind_data (struct frame *target_frame,
   return vector;
 }
 
-static Lisp_Object
+static void
 unwind_format_mode_line (Lisp_Object vector)
 {
   Lisp_Object old_window = AREF (vector, 7);
@@ -10913,7 +11000,6 @@ unwind_format_mode_line (Lisp_Object vector)
     }
 
   Vmode_line_unwind_vector = vector;
-  return Qnil;
 }
 
 
@@ -11083,7 +11169,18 @@ prepare_menu_bars (void)
        {
          f = XFRAME (frame);
          if (!EQ (frame, tooltip_frame)
-             && (FRAME_VISIBLE_P (f) || FRAME_ICONIFIED_P (f)))
+             && (FRAME_ICONIFIED_P (f)
+                 || FRAME_VISIBLE_P (f) == 1
+                 /* Exclude TTY frames that are obscured because they
+                    are not the top frame on their console.  This is
+                    because x_consider_frame_title actually switches
+                    to the frame, which for TTY frames means it is
+                    marked as garbaged, and will be completely
+                    redrawn on the next redisplay cycle.  This causes
+                    TTY frames to be completely redrawn, when there
+                    are more than one of them, even though nothing
+                    should be changed on display.  */
+                 || (FRAME_VISIBLE_P (f) == 2 && FRAME_WINDOW_P (f))))
            x_consider_frame_title (frame);
        }
     }
@@ -11288,7 +11385,7 @@ struct cursor_pos output_cursor;
 
 /* EXPORT:
    Set the global variable output_cursor to CURSOR.  All cursor
-   positions are relative to updated_window.  */
+   positions are relative to currently updated window.  */
 
 void
 set_output_cursor (struct cursor_pos *cursor)
@@ -11303,41 +11400,24 @@ set_output_cursor (struct cursor_pos *cursor)
 /* EXPORT for RIF:
    Set a nominal cursor position.
 
-   HPOS and VPOS are column/row positions in a window glyph matrix.  X
-   and Y are window text area relative pixel positions.
+   HPOS and VPOS are column/row positions in a window glyph matrix.
+   and Y are window text area relative pixel positions.
 
-   If this is done during an update, updated_window will contain the
-   window that is being updated and the position is the future output
-   cursor position for that window.  If updated_window is null, use
-   selected_window and display the cursor at the given position.  */
+   This is always done during window update, so the position is the
+   future output cursor position for currently updated window W.
+   NOTE: W is used only to check whether this function is called
+   in a consistent manner via the redisplay interface.  */
 
 void
-x_cursor_to (int vpos, int hpos, int y, int x)
+x_cursor_to (struct window *w, int vpos, int hpos, int y, int x)
 {
-  struct window *w;
-
-  /* If updated_window is not set, work on selected_window.  */
-  if (updated_window)
-    w = updated_window;
-  else
-    w = XWINDOW (selected_window);
+  eassert (w);
 
   /* Set the output cursor.  */
   output_cursor.hpos = hpos;
   output_cursor.vpos = vpos;
   output_cursor.x = x;
   output_cursor.y = y;
-
-  /* If not called as part of an update, really display the cursor.
-     This will also set the cursor position of W.  */
-  if (updated_window == NULL)
-    {
-      block_input ();
-      display_and_set_cursor (w, 1, hpos, vpos, x, y);
-      if (FRAME_RIF (SELECTED_FRAME ())->flush_display_optional)
-       FRAME_RIF (SELECTED_FRAME ())->flush_display_optional (SELECTED_FRAME ());
-      unblock_input ();
-    }
 }
 
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -11351,7 +11431,7 @@ x_cursor_to (int vpos, int hpos, int y, int x)
 
 /* Where the mouse was last time we reported a mouse event.  */
 
-FRAME_PTR last_mouse_frame;
+struct frame *last_mouse_frame;
 
 /* Tool-bar item index of the item on which a mouse button was pressed
    or -1.  */
@@ -11362,7 +11442,7 @@ int last_tool_bar_item;
    do_switch_frame.
    FIXME: Maybe do_switch_frame should be trimmed down similarly
    when `norecord' is set.  */
-static Lisp_Object
+static void
 fast_set_selected_frame (Lisp_Object frame)
 {
   if (!EQ (selected_frame, frame))
@@ -11370,7 +11450,6 @@ fast_set_selected_frame (Lisp_Object frame)
       selected_frame = frame;
       selected_window = XFRAME (frame)->selected_window;
     }
-  return Qnil;
 }
 
 /* Update the tool-bar item list for frame F.  This has to be done
@@ -11890,9 +11969,8 @@ redisplay_tool_bar (struct frame *f)
 
          XSETFRAME (frame, f);
          Fmodify_frame_parameters (frame,
-                                   Fcons (Fcons (Qtool_bar_lines,
-                                                 make_number (nlines)),
-                                          Qnil));
+                                   list1 (Fcons (Qtool_bar_lines,
+                                                 make_number (nlines))));
          if (WINDOW_TOTAL_LINES (w) != old_height)
            {
              clear_glyph_matrix (w->desired_matrix);
@@ -11991,9 +12069,8 @@ redisplay_tool_bar (struct frame *f)
            {
              XSETFRAME (frame, f);
              Fmodify_frame_parameters (frame,
-                                       Fcons (Fcons (Qtool_bar_lines,
-                                                     make_number (nlines)),
-                                              Qnil));
+                                       list1 (Fcons (Qtool_bar_lines,
+                                                     make_number (nlines))));
              if (WINDOW_TOTAL_LINES (w) != old_height)
                {
                  clear_glyph_matrix (w->desired_matrix);
@@ -12103,12 +12180,27 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
   int hpos, vpos, prop_idx;
   struct glyph *glyph;
   Lisp_Object enabled_p;
-
-  /* If not on the highlighted tool-bar item, return.  */
+  int ts;
+
+  /* If not on the highlighted tool-bar item, and mouse-highlight is
+     non-nil, return.  This is so we generate the tool-bar button
+     click only when the mouse button is released on the same item as
+     where it was pressed.  However, when mouse-highlight is disabled,
+     generate the click when the button is released regardless of the
+     highlight, since tool-bar items are not highlighted in that
+     case.  */
   frame_to_window_pixel_xy (w, &x, &y);
-  if (get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx) != 0)
+  ts = get_tool_bar_item (f, x, y, &glyph, &hpos, &vpos, &prop_idx);
+  if (ts == -1
+      || (ts != 0 && !NILP (Vmouse_highlight)))
     return;
 
+  /* When mouse-highlight is off, generate the click for the item
+     where the button was pressed, disregarding where it was
+     released.  */
+  if (NILP (Vmouse_highlight) && !down_p)
+    prop_idx = 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 (NILP (enabled_p))
@@ -12117,7 +12209,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
   if (down_p)
     {
       /* Show item in pressed state.  */
-      show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
+      if (!NILP (Vmouse_highlight))
+       show_mouse_face (hlinfo, DRAW_IMAGE_SUNKEN);
       last_tool_bar_item = prop_idx;
     }
   else
@@ -12127,7 +12220,8 @@ handle_tool_bar_click (struct frame *f, int x, int y, int down_p,
       EVENT_INIT (event);
 
       /* Show item in released state.  */
-      show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
+      if (!NILP (Vmouse_highlight))
+       show_mouse_face (hlinfo, DRAW_IMAGE_RAISED);
 
       key = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_KEY);
 
@@ -12200,7 +12294,7 @@ note_tool_bar_highlight (struct frame *f, int x, int y)
 
   /* If tool-bar item is not enabled, don't highlight it.  */
   enabled_p = AREF (f->tool_bar_items, prop_idx + TOOL_BAR_ITEM_ENABLED_P);
-  if (!NILP (enabled_p))
+  if (!NILP (enabled_p) && !NILP (Vmouse_highlight))
     {
       /* Compute the x-position of the glyph.  In front and past the
         image is a space.  We include this in the highlighted area.  */
@@ -12463,6 +12557,7 @@ static void debug_method_add (struct window *, char const *, ...)
 static void
 debug_method_add (struct window *w, char const *fmt, ...)
 {
+  void *ptr = w;
   char *method = w->desired_matrix->method;
   int len = strlen (method);
   int size = sizeof w->desired_matrix->method;
@@ -12481,7 +12576,7 @@ debug_method_add (struct window *w, char const *fmt, ...)
 
   if (trace_redisplay_p)
     fprintf (stderr, "%p (%s): %s\n",
-            w,
+            ptr,
             ((BUFFERP (w->contents)
               && STRINGP (BVAR (XBUFFER (w->contents), name)))
              ? SSDATA (BVAR (XBUFFER (w->contents), name))
@@ -12739,7 +12834,7 @@ check_point_in_composition (struct buffer *prev_buf, ptrdiff_t prev_pt,
 
       if (prev_pt > BUF_BEGV (buf) && prev_pt < BUF_ZV (buf)
          && find_composition (prev_pt, -1, &start, &end, &prop, buffer)
-         && COMPOSITION_VALID_P (start, end, prop)
+         && composition_valid_p (start, end, prop)
          && start < prev_pt && end > prev_pt)
        /* The last point was within the composition.  Return 1 iff
             point moved out of the composition.  */
@@ -12749,17 +12844,17 @@ check_point_in_composition (struct buffer *prev_buf, ptrdiff_t prev_pt,
   /* Check a composition at the current point.  */
   return (pt > BUF_BEGV (buf) && pt < BUF_ZV (buf)
          && find_composition (pt, -1, &start, &end, &prop, buffer)
-         && COMPOSITION_VALID_P (start, end, prop)
+         && composition_valid_p (start, end, prop)
          && start < pt && end > pt);
 }
 
-
-/* Reconsider the setting of B->clip_changed which is displayed
-   in window W.  */
+/* Reconsider the clip changes of buffer which is displayed in W.  */
 
 static void
-reconsider_clip_changes (struct window *w, struct buffer *b)
+reconsider_clip_changes (struct window *w)
 {
+  struct buffer *b = XBUFFER (w->contents);
+
   if (b->clip_changed
       && w->window_end_valid
       && w->current_matrix->buffer == b
@@ -12772,24 +12867,17 @@ reconsider_clip_changes (struct window *w, struct buffer *b)
      we set b->clip_changed to 1 to force updating the screen.  If
      b->clip_changed has already been set to 1, we can skip this
      check.  */
-  if (!b->clip_changed && BUFFERP (w->contents) && w->window_end_valid)
+  if (!b->clip_changed && w->window_end_valid)
     {
-      ptrdiff_t pt;
+      ptrdiff_t pt = (w == XWINDOW (selected_window)
+                     ? PT : marker_position (w->pointm));
 
-      if (w == XWINDOW (selected_window))
-       pt = PT;
-      else
-       pt = marker_position (w->pointm);
-
-      if ((w->current_matrix->buffer != XBUFFER (w->contents)
-          || pt != w->last_point)
+      if ((w->current_matrix->buffer != b || pt != w->last_point)
          && check_point_in_composition (w->current_matrix->buffer,
-                                        w->last_point,
-                                        XBUFFER (w->contents), pt))
+                                        w->last_point, b, pt))
        b->clip_changed = 1;
     }
 }
-\f
 
 #define STOP_POLLING                                   \
 do { if (! polling_stopped_here) stop_polling ();      \
@@ -12810,14 +12898,13 @@ redisplay_internal (void)
   struct window *sw;
   struct frame *fr;
   int pending;
-  int must_finish = 0;
+  bool must_finish = 0, match_p;
   struct text_pos tlbufpos, tlendpos;
   int number_of_visible_frames;
-  ptrdiff_t count, count1;
+  ptrdiff_t count;
   struct frame *sf;
   int polling_stopped_here = 0;
   Lisp_Object tail, frame;
-  struct backtrace backtrace;
 
   /* Non-zero means redisplay has to consider all windows on all
      frames.  Zero means, only selected_window is considered.  */
@@ -12856,17 +12943,12 @@ redisplay_internal (void)
   /* Record a function that clears redisplaying_p
      when we leave this function.  */
   count = SPECPDL_INDEX ();
-  record_unwind_protect (unwind_redisplay, selected_frame);
+  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.  */
-  backtrace.next = backtrace_list;
-  backtrace.function = Qredisplay_internal;
-  backtrace.args = &Qnil;
-  backtrace.nargs = 0;
-  backtrace.debug_on_exit = 0;
-  backtrace_list = &backtrace;
+  record_in_backtrace (Qredisplay_internal, &Qnil, 0);
 
   FOR_EACH_FRAME (tail, frame)
     XFRAME (frame)->already_hscrolled_p = 0;
@@ -12876,7 +12958,6 @@ redisplay_internal (void)
   sw = w;
 
   pending = 0;
-  reconsider_clip_changes (w, current_buffer);
   last_escape_glyph_frame = NULL;
   last_escape_glyph_face_id = (1 << FACE_ID_BITS);
   last_glyphless_glyph_frame = NULL;
@@ -12931,10 +13012,7 @@ redisplay_internal (void)
   /* do_pending_window_change could change the selected_window due to
      frame resizing which makes the selected window too small.  */
   if (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw)
-    {
-      sw = w;
-      reconsider_clip_changes (w, current_buffer);
-    }
+    sw = w;
 
   /* Clear frames marked as garbaged.  */
   clear_garbaged_frames ();
@@ -12946,22 +13024,31 @@ redisplay_internal (void)
   if (windows_or_buffers_changed)
     update_mode_lines++;
 
-  /* Detect case that we need to write or remove a star in the mode line.  */
-  if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
+  reconsider_clip_changes (w);
+
+  /* In most cases selected window displays current buffer.  */
+  match_p = XBUFFER (w->contents) == current_buffer;
+  if (match_p)
     {
-      w->update_mode_line = 1;
-      if (buffer_shared_and_changed ())
-       update_mode_lines++;
-    }
+      ptrdiff_t count1;
 
-  /* Avoid invocation of point motion hooks by `current_column' below.  */
-  count1 = SPECPDL_INDEX ();
-  specbind (Qinhibit_point_motion_hooks, Qt);
+      /* Detect case that we need to write or remove a star in the mode line.  */
+      if ((SAVE_MODIFF < MODIFF) != w->last_had_star)
+       {
+         w->update_mode_line = 1;
+         if (buffer_shared_and_changed ())
+           update_mode_lines++;
+       }
 
-  if (mode_line_update_needed (w))
-    w->update_mode_line = 1;
+      /* Avoid invocation of point motion hooks by `current_column' below.  */
+      count1 = SPECPDL_INDEX ();
+      specbind (Qinhibit_point_motion_hooks, Qt);
 
-  unbind_to (count1, Qnil);
+      if (mode_line_update_needed (w))
+       w->update_mode_line = 1;
+
+      unbind_to (count1, Qnil);
+    }
 
   consider_all_windows_p = (update_mode_lines
                            || buffer_shared_and_changed ()
@@ -13060,7 +13147,7 @@ redisplay_internal (void)
       && !FRAME_OBSCURED_P (XFRAME (w->frame))
       /* Make sure recorded data applies to current buffer, etc.  */
       && this_line_buffer == current_buffer
-      && current_buffer == XBUFFER (w->contents)
+      && match_p
       && !w->force_start
       && !w->optional_new_start
       /* Point must be on the line that we have info recorded about.  */
@@ -13503,7 +13590,6 @@ redisplay_internal (void)
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
-  backtrace_list = backtrace.next;
   unbind_to (count, Qnil);
   RESUME_POLLING;
 }
@@ -13542,14 +13628,12 @@ redisplay_preserve_echo_area (int from_where)
 }
 
 
-/* Function registered with record_unwind_protect in redisplay_internal.
-   Clear redisplaying_p.  Also select the previously selected frame.  */
+/* Function registered with record_unwind_protect in redisplay_internal.  */
 
-static Lisp_Object
-unwind_redisplay (Lisp_Object old_frame)
+static void
+unwind_redisplay (void)
 {
   redisplaying_p = 0;
-  return Qnil;
 }
 
 
@@ -14354,8 +14438,7 @@ run_window_scroll_functions (Lisp_Object window, struct text_pos startp)
   struct window *w = XWINDOW (window);
   SET_MARKER_FROM_TEXT_POS (w->start, startp);
 
-  if (current_buffer != XBUFFER (w->contents))
-    emacs_abort ();
+  eassert (current_buffer == XBUFFER (w->contents));
 
   if (!NILP (Vwindow_scroll_functions))
     {
@@ -14462,6 +14545,9 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   Lisp_Object aggressive;
   /* We will never try scrolling more than this number of lines.  */
   int scroll_limit = SCROLL_LIMIT;
+  int frame_line_height = default_line_pixel_height (w);
+  int window_total_lines
+    = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
 #ifdef GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
@@ -14472,8 +14558,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   /* Compute scroll margin height in pixels.  We scroll when point is
      within this distance from the top or bottom of the window.  */
   if (scroll_margin > 0)
-    this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
-      * FRAME_LINE_HEIGHT (f);
+    this_scroll_margin = min (scroll_margin, window_total_lines / 4)
+      * frame_line_height;
   else
     this_scroll_margin = 0;
 
@@ -14484,19 +14570,19 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
   if (arg_scroll_conservatively > scroll_limit)
     {
       arg_scroll_conservatively = scroll_limit + 1;
-      scroll_max = scroll_limit * FRAME_LINE_HEIGHT (f);
+      scroll_max = scroll_limit * frame_line_height;
     }
   else if (scroll_step || arg_scroll_conservatively || temp_scroll_step)
     /* Compute how much we should try to scroll maximally to bring
        point into view.  */
     scroll_max = (max (scroll_step,
                       max (arg_scroll_conservatively, temp_scroll_step))
-                 * FRAME_LINE_HEIGHT (f));
+                 * frame_line_height);
   else if (NUMBERP (BVAR (current_buffer, scroll_down_aggressively))
           || NUMBERP (BVAR (current_buffer, scroll_up_aggressively)))
     /* We're trying to scroll because of aggressive scrolling but no
        scroll_step is set.  Choose an arbitrary one.  */
-    scroll_max = 10 * FRAME_LINE_HEIGHT (f);
+    scroll_max = 10 * frame_line_height;
   else
     scroll_max = 0;
 
@@ -14511,7 +14597,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
         either that ypos or PT, whichever comes first.  */
       start_display (&it, w, startp);
       scroll_margin_y = it.last_visible_y - this_scroll_margin
-       - FRAME_LINE_HEIGHT (f) * extra_scroll_margin_lines;
+       - frame_line_height * extra_scroll_margin_lines;
       move_it_to (&it, PT, -1, scroll_margin_y - 1, -1,
                  (MOVE_TO_POS | MOVE_TO_Y));
 
@@ -14523,7 +14609,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
             the user limited scrolling by a small number of lines, but
             always finds PT if scroll_conservatively is set to a large
             number, such as most-positive-fixnum.  */
-         int slack = max (scroll_max, 10 * FRAME_LINE_HEIGHT (f));
+         int slack = max (scroll_max, 10 * frame_line_height);
          int y_to_move = it.last_visible_y + slack;
 
          /* Compute the distance from the scroll margin to PT or to
@@ -14550,8 +14636,8 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
         move it down by scroll_step.  */
       if (arg_scroll_conservatively)
        amount_to_scroll
-         = min (max (dy, FRAME_LINE_HEIGHT (f)),
-                FRAME_LINE_HEIGHT (f) * arg_scroll_conservatively);
+         = min (max (dy, frame_line_height),
+                frame_line_height * arg_scroll_conservatively);
       else if (scroll_step || temp_scroll_step)
        amount_to_scroll = scroll_max;
       else
@@ -14648,7 +14734,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          start_display (&it, w, pos);
          y0 = it.current_y;
          y_to_move = max (it.last_visible_y,
-                          max (scroll_max, 10 * FRAME_LINE_HEIGHT (f)));
+                          max (scroll_max, 10 * frame_line_height));
          move_it_to (&it, CHARPOS (scroll_margin_pos), 0,
                      y_to_move, -1,
                      MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
@@ -14664,7 +14750,7 @@ try_scrolling (Lisp_Object window, int just_this_one_p,
          start_display (&it, w, startp);
 
          if (arg_scroll_conservatively)
-           amount_to_scroll = max (dy, FRAME_LINE_HEIGHT (f) *
+           amount_to_scroll = max (dy, frame_line_height *
                                    max (scroll_step, temp_scroll_step));
          else if (scroll_step || temp_scroll_step)
            amount_to_scroll = scroll_max;
@@ -14884,6 +14970,9 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
     {
       int this_scroll_margin, top_scroll_margin;
       struct glyph_row *row = NULL;
+      int frame_line_height = default_line_pixel_height (w);
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
 #ifdef GLYPH_DEBUG
       debug_method_add (w, "cursor movement");
@@ -14893,8 +14982,8 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp, int *scroll_ste
         of the window.  This is a pixel value.  */
       if (scroll_margin > 0)
        {
-         this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         this_scroll_margin *= FRAME_LINE_HEIGHT (f);
+         this_scroll_margin = min (scroll_margin, window_total_lines / 4);
+         this_scroll_margin *= frame_line_height;
        }
       else
        this_scroll_margin = 0;
@@ -15236,6 +15325,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   int centering_position = -1;
   int last_line_misfit = 0;
   ptrdiff_t beg_unchanged, end_unchanged;
+  int frame_line_height;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -15249,7 +15339,8 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   eassert (XMARKER (w->pointm)->buffer == buffer);
 
  restart:
-  reconsider_clip_changes (w, buffer);
+  reconsider_clip_changes (w);
+  frame_line_height = default_line_pixel_height (w);
 
   /* Has the mode line to be updated?  */
   update_mode_line = (w->update_mode_line
@@ -15447,8 +15538,6 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          startp = run_window_scroll_functions (window, startp);
        }
 
-      w->last_modified = 0;
-      w->last_overlay_modified = 0;
       if (CHARPOS (startp) < BEGV)
        SET_TEXT_POS (startp, BEGV, BEGV_BYTE);
       else if (CHARPOS (startp) > ZV)
@@ -15485,8 +15574,10 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
          /* Some people insist on not letting point enter the scroll
             margin, even though this part handles windows that didn't
             scroll at all.  */
-         int margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         int pixel_margin = margin * FRAME_LINE_HEIGHT (f);
+         int window_total_lines
+           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
+         int margin = min (scroll_margin, window_total_lines / 4);
+         int pixel_margin = margin * frame_line_height;
          bool header_line = WINDOW_WANTS_HEADER_LINE_P (w);
 
          /* Note: We add an extra FRAME_LINE_HEIGHT, because the loop
@@ -15494,10 +15585,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
             the Y coordinate of the _next_ row, see the definition of
             MATRIX_ROW_BOTTOM_Y.  */
          if (w->cursor.vpos < margin + header_line)
-           new_vpos
-             = pixel_margin + (header_line
-                               ? CURRENT_HEADER_LINE_HEIGHT (w)
-                               : 0) + FRAME_LINE_HEIGHT (f);
+           {
+             w->cursor.vpos = -1;
+             clear_glyph_matrix (w->desired_matrix);
+             goto try_to_scroll;
+           }
          else
            {
              int window_height = window_box_height (w);
@@ -15505,7 +15597,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              if (header_line)
                window_height += CURRENT_HEADER_LINE_HEIGHT (w);
              if (w->cursor.y >= window_height - pixel_margin)
-               new_vpos = window_height - pixel_margin;
+               {
+                 w->cursor.vpos = -1;
+                 clear_glyph_matrix (w->desired_matrix);
+                 goto try_to_scroll;
+               }
            }
        }
 
@@ -15687,9 +15783,6 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
  try_to_scroll:
 
-  w->last_modified = 0;
-  w->last_overlay_modified = 0;
-
   /* Redisplay the mode line.  Select the buffer properly for that.  */
   if (!update_mode_line)
     {
@@ -15746,9 +15839,11 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
   it.current_y = it.last_visible_y;
   if (centering_position < 0)
     {
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
       int margin =
        scroll_margin > 0
-       ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+       ? min (scroll_margin, window_total_lines / 4)
        : 0;
       ptrdiff_t margin_pos = CHARPOS (startp);
       Lisp_Object aggressive;
@@ -15770,7 +15865,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
          SAVE_IT (it1, it, it1data);
          start_display (&it1, w, startp);
-         move_it_vertically (&it1, margin * FRAME_LINE_HEIGHT (f));
+         move_it_vertically (&it1, margin * frame_line_height);
          margin_pos = IT_CHARPOS (it1);
          RESTORE_IT (&it, &it, it1data);
        }
@@ -15806,15 +15901,15 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
              if (pt_offset)
                centering_position -= pt_offset;
              centering_position -=
-               FRAME_LINE_HEIGHT (f) * (1 + margin + (last_line_misfit != 0))
+               frame_line_height * (1 + margin + (last_line_misfit != 0))
                + WINDOW_HEADER_LINE_HEIGHT (w);
              /* Don't let point enter the scroll margin near top of
                 the window.  */
-             if (centering_position < margin * FRAME_LINE_HEIGHT (f))
-               centering_position = margin * FRAME_LINE_HEIGHT (f);
+             if (centering_position < margin * frame_line_height)
+               centering_position = margin * frame_line_height;
            }
          else
-           centering_position = margin * FRAME_LINE_HEIGHT (f) + pt_offset;
+           centering_position = margin * frame_line_height + pt_offset;
        }
       else
        /* Set the window start half the height of the window backward
@@ -15919,11 +16014,13 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
         make that row fully visible and out of the margin.  */
       if (scroll_conservatively > SCROLL_LIMIT)
        {
+         int window_total_lines
+           = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) * frame_line_height;
          int margin =
            scroll_margin > 0
-           ? min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4)
+           ? min (scroll_margin, window_total_lines / 4)
            : 0;
-         int move_down = w->cursor.vpos >= WINDOW_TOTAL_LINES (w) / 2;
+         int move_down = w->cursor.vpos >= window_total_lines / 2;
 
          move_it_by_lines (&it, move_down ? margin + 1 : -(margin + 1));
          clear_glyph_matrix (w->desired_matrix);
@@ -16110,6 +16207,7 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
   struct it it;
   struct glyph_row *last_text_row = NULL;
   struct frame *f = XFRAME (w->frame);
+  int frame_line_height = default_line_pixel_height (w);
 
   /* Make POS the new window start.  */
   set_marker_both (w->start, Qnil, CHARPOS (pos), BYTEPOS (pos));
@@ -16135,11 +16233,13 @@ try_window (Lisp_Object window, struct text_pos pos, int flags)
       && !MINI_WINDOW_P (w))
     {
       int this_scroll_margin;
+      int window_total_lines
+       = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (f) / frame_line_height;
 
       if (scroll_margin > 0)
        {
-         this_scroll_margin = min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
-         this_scroll_margin *= FRAME_LINE_HEIGHT (f);
+         this_scroll_margin = min (scroll_margin, window_total_lines / 4);
+         this_scroll_margin *= frame_line_height;
        }
       else
        this_scroll_margin = 0;
@@ -17440,10 +17540,13 @@ try_window_id (struct window *w)
   /* Don't let the cursor end in the scroll margins.  */
   {
     int this_scroll_margin, cursor_height;
+    int frame_line_height = default_line_pixel_height (w);
+    int window_total_lines
+      = WINDOW_TOTAL_LINES (w) * FRAME_LINE_HEIGHT (it.f) / frame_line_height;
 
     this_scroll_margin =
-      max (0, min (scroll_margin, WINDOW_TOTAL_LINES (w) / 4));
-    this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+      max (0, min (scroll_margin, window_total_lines / 4));
+    this_scroll_margin *= frame_line_height;
     cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
 
     if ((w->cursor.y < this_scroll_margin
@@ -18882,6 +18985,7 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
          it->bidi_it.string.bufpos = IT_CHARPOS (*it);
          it->bidi_it.string.from_disp_str = it->string_from_display_prop_p;
          it->bidi_it.string.unibyte = !it->multibyte_p;
+         it->bidi_it.w = it->w;
          bidi_init_it (0, 0, FRAME_WINDOW_P (it->f), &it->bidi_it);
        }
     }
@@ -18912,16 +19016,19 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
 static Lisp_Object
 get_it_property (struct it *it, Lisp_Object prop)
 {
-  Lisp_Object position;
+  Lisp_Object position, object = it->object;
 
-  if (STRINGP (it->object))
+  if (STRINGP (object))
     position = make_number (IT_STRING_CHARPOS (*it));
-  else if (BUFFERP (it->object))
-    position = make_number (IT_CHARPOS (*it));
+  else if (BUFFERP (object))
+    {
+      position = make_number (IT_CHARPOS (*it));
+      object = it->window;
+    }
   else
     return Qnil;
 
-  return Fget_char_property (position, prop, it->object);
+  return Fget_char_property (position, prop, object);
 }
 
 /* See if there's a line- or wrap-prefix, and if so, push it on IT.  */
@@ -19951,6 +20058,10 @@ See also `bidi-paragraph-direction'.  */)
       itb.string.lstring = Qnil;
       itb.string.bufpos = 0;
       itb.string.unibyte = 0;
+      /* We have no window to use here for ignoring window-specific
+        overlays.  Using NULL for window pointer will cause
+        compute_display_string_pos to use the current buffer.  */
+      itb.w = NULL;
       bidi_paragraph_init (NEUTRAL_DIR, &itb, 1);
       bidi_unshelve_cache (itb_data, 0);
       set_buffer_temp (old);
@@ -19968,6 +20079,400 @@ See also `bidi-paragraph-direction'.  */)
     }
 }
 
+DEFUN ("move-point-visually", Fmove_point_visually,
+       Smove_point_visually, 1, 1, 0,
+       doc: /* Move point in the visual order in the specified DIRECTION.
+DIRECTION can be 1, meaning move to the right, or -1, which moves to the
+left.
+
+Value is the new character position of point.  */)
+  (Lisp_Object direction)
+{
+  struct window *w = XWINDOW (selected_window);
+  struct buffer *b = XBUFFER (w->contents);
+  struct glyph_row *row;
+  int dir;
+  Lisp_Object paragraph_dir;
+
+#define ROW_GLYPH_NEWLINE_P(ROW,GLYPH)         \
+  (!(ROW)->continued_p                         \
+   && INTEGERP ((GLYPH)->object)               \
+   && (GLYPH)->type == CHAR_GLYPH              \
+   && (GLYPH)->u.ch == ' '                     \
+   && (GLYPH)->charpos >= 0                    \
+   && !(GLYPH)->avoid_cursor_p)
+
+  CHECK_NUMBER (direction);
+  dir = XINT (direction);
+  if (dir > 0)
+    dir = 1;
+  else
+    dir = -1;
+
+  /* If current matrix is up-to-date, we can use the information
+     recorded in the glyphs, at least as long as the goal is on the
+     screen.  */
+  if (w->window_end_valid
+      && !windows_or_buffers_changed
+      && b
+      && !b->clip_changed
+      && !b->prevent_redisplay_optimizations_p
+      && !window_outdated (w)
+      && w->cursor.vpos >= 0
+      && w->cursor.vpos < w->current_matrix->nrows
+      && (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos))->enabled_p)
+    {
+      struct glyph *g = row->glyphs[TEXT_AREA];
+      struct glyph *e = dir > 0 ? g + row->used[TEXT_AREA] : g - 1;
+      struct glyph *gpt = g + w->cursor.hpos;
+
+      for (g = gpt + dir; (dir > 0 ? g < e : g > e); g += dir)
+       {
+         if (BUFFERP (g->object) && g->charpos != PT)
+           {
+             SET_PT (g->charpos);
+             w->cursor.vpos = -1;
+             return make_number (PT);
+           }
+         else if (!INTEGERP (g->object) && !EQ (g->object, gpt->object))
+           {
+             ptrdiff_t new_pos;
+
+             if (BUFFERP (gpt->object))
+               {
+                 new_pos = PT;
+                 if ((gpt->resolved_level - row->reversed_p) % 2 == 0)
+                   new_pos += (row->reversed_p ? -dir : dir);
+                 else
+                   new_pos -= (row->reversed_p ? -dir : dir);;
+               }
+             else if (BUFFERP (g->object))
+               new_pos = g->charpos;
+             else
+               break;
+             SET_PT (new_pos);
+             w->cursor.vpos = -1;
+             return make_number (PT);
+           }
+         else if (ROW_GLYPH_NEWLINE_P (row, g))
+           {
+             /* Glyphs inserted at the end of a non-empty line for
+                positioning the cursor have zero charpos, so we must
+                deduce the value of point by other means.  */
+             if (g->charpos > 0)
+               SET_PT (g->charpos);
+             else if (row->ends_at_zv_p && PT != ZV)
+               SET_PT (ZV);
+             else if (PT != MATRIX_ROW_END_CHARPOS (row) - 1)
+               SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+             else
+               break;
+             w->cursor.vpos = -1;
+             return make_number (PT);
+           }
+       }
+      if (g == e || INTEGERP (g->object))
+       {
+         if (row->truncated_on_left_p || row->truncated_on_right_p)
+           goto simulate_display;
+         if (!row->reversed_p)
+           row += dir;
+         else
+           row -= dir;
+         if (row < MATRIX_FIRST_TEXT_ROW (w->current_matrix)
+             || row > MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w))
+           goto simulate_display;
+
+         if (dir > 0)
+           {
+             if (row->reversed_p && !row->continued_p)
+               {
+                 SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+                 w->cursor.vpos = -1;
+                 return make_number (PT);
+               }
+             g = row->glyphs[TEXT_AREA];
+             e = g + row->used[TEXT_AREA];
+             for ( ; g < e; g++)
+               {
+                 if (BUFFERP (g->object)
+                     /* Empty lines have only one glyph, which stands
+                        for the newline, and whose charpos is the
+                        buffer position of the newline.  */
+                     || ROW_GLYPH_NEWLINE_P (row, g)
+                     /* When the buffer ends in a newline, the line at
+                        EOB also has one glyph, but its charpos is -1.  */
+                     || (row->ends_at_zv_p
+                         && !row->reversed_p
+                         && INTEGERP (g->object)
+                         && g->type == CHAR_GLYPH
+                         && g->u.ch == ' '))
+                   {
+                     if (g->charpos > 0)
+                       SET_PT (g->charpos);
+                     else if (!row->reversed_p
+                              && row->ends_at_zv_p
+                              && PT != ZV)
+                       SET_PT (ZV);
+                     else
+                       continue;
+                     w->cursor.vpos = -1;
+                     return make_number (PT);
+                   }
+               }
+           }
+         else
+           {
+             if (!row->reversed_p && !row->continued_p)
+               {
+                 SET_PT (MATRIX_ROW_END_CHARPOS (row) - 1);
+                 w->cursor.vpos = -1;
+                 return make_number (PT);
+               }
+             e = row->glyphs[TEXT_AREA];
+             g = e + row->used[TEXT_AREA] - 1;
+             for ( ; g >= e; g--)
+               {
+                 if (BUFFERP (g->object)
+                     || (ROW_GLYPH_NEWLINE_P (row, g)
+                         && g->charpos > 0)
+                     /* Empty R2L lines on GUI frames have the buffer
+                        position of the newline stored in the stretch
+                        glyph.  */
+                     || g->type == STRETCH_GLYPH
+                     || (row->ends_at_zv_p
+                         && row->reversed_p
+                         && INTEGERP (g->object)
+                         && g->type == CHAR_GLYPH
+                         && g->u.ch == ' '))
+                   {
+                     if (g->charpos > 0)
+                       SET_PT (g->charpos);
+                     else if (row->reversed_p
+                              && row->ends_at_zv_p
+                              && PT != ZV)
+                       SET_PT (ZV);
+                     else
+                       continue;
+                     w->cursor.vpos = -1;
+                     return make_number (PT);
+                   }
+               }
+           }
+       }
+    }
+
+ simulate_display:
+
+  /* If we wind up here, we failed to move by using the glyphs, so we
+     need to simulate display instead.  */
+
+  if (b)
+    paragraph_dir = Fcurrent_bidi_paragraph_direction (w->contents);
+  else
+    paragraph_dir = Qleft_to_right;
+  if (EQ (paragraph_dir, Qright_to_left))
+    dir = -dir;
+  if (PT <= BEGV && dir < 0)
+    xsignal0 (Qbeginning_of_buffer);
+  else if (PT >= ZV && dir > 0)
+    xsignal0 (Qend_of_buffer);
+  else
+    {
+      struct text_pos pt;
+      struct it it;
+      int pt_x, target_x, pixel_width, pt_vpos;
+      bool at_eol_p;
+      bool overshoot_expected = false;
+      bool target_is_eol_p = false;
+
+      /* Setup the arena.  */
+      SET_TEXT_POS (pt, PT, PT_BYTE);
+      start_display (&it, w, pt);
+
+      if (it.cmp_it.id < 0
+         && it.method == GET_FROM_STRING
+         && it.area == TEXT_AREA
+         && it.string_from_display_prop_p
+         && (it.sp > 0 && it.stack[it.sp - 1].method == GET_FROM_BUFFER))
+       overshoot_expected = true;
+
+      /* Find the X coordinate of point.  We start from the beginning
+        of this or previous line to make sure we are before point in
+        the logical order (since the move_it_* functions can only
+        move forward).  */
+      reseat_at_previous_visible_line_start (&it);
+      it.current_x = it.hpos = it.current_y = it.vpos = 0;
+      if (IT_CHARPOS (it) != PT)
+       move_it_to (&it, overshoot_expected ? PT - 1 : PT,
+                   -1, -1, -1, MOVE_TO_POS);
+      pt_x = it.current_x;
+      pt_vpos = it.vpos;
+      if (dir > 0 || overshoot_expected)
+       {
+         struct glyph_row *row = it.glyph_row;
+
+         /* When point is at beginning of line, we don't have
+            information about the glyph there loaded into struct
+            it.  Calling get_next_display_element fixes that.  */
+         if (pt_x == 0)
+           get_next_display_element (&it);
+         at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it);
+         it.glyph_row = NULL;
+         PRODUCE_GLYPHS (&it); /* compute it.pixel_width */
+         it.glyph_row = row;
+         /* PRODUCE_GLYPHS advances it.current_x, so we must restore
+            it, lest it will become out of sync with it's buffer
+            position.  */
+         it.current_x = pt_x;
+       }
+      else
+       at_eol_p = ITERATOR_AT_END_OF_LINE_P (&it);
+      pixel_width = it.pixel_width;
+      if (overshoot_expected && at_eol_p)
+       pixel_width = 0;
+      else if (pixel_width <= 0)
+       pixel_width = 1;
+
+      /* If there's a display string at point, we are actually at the
+        glyph to the left of point, so we need to correct the X
+        coordinate.  */
+      if (overshoot_expected)
+       pt_x += pixel_width;
+
+      /* Compute target X coordinate, either to the left or to the
+        right of point.  On TTY frames, all characters have the same
+        pixel width of 1, so we can use that.  On GUI frames we don't
+        have an easy way of getting at the pixel width of the
+        character to the left of point, so we use a different method
+        of getting to that place.  */
+      if (dir > 0)
+       target_x = pt_x + pixel_width;
+      else
+       target_x = pt_x - (!FRAME_WINDOW_P (it.f)) * pixel_width;
+
+      /* Target X coordinate could be one line above or below the line
+        of point, in which case we need to adjust the target X
+        coordinate.  Also, if moving to the left, we need to begin at
+        the left edge of the point's screen line.  */
+      if (dir < 0)
+       {
+         if (pt_x > 0)
+           {
+             start_display (&it, w, pt);
+             reseat_at_previous_visible_line_start (&it);
+             it.current_x = it.current_y = it.hpos = 0;
+             if (pt_vpos != 0)
+               move_it_by_lines (&it, pt_vpos);
+           }
+         else
+           {
+             move_it_by_lines (&it, -1);
+             target_x = it.last_visible_x - !FRAME_WINDOW_P (it.f);
+             target_is_eol_p = true;
+           }
+       }
+      else
+       {
+         if (at_eol_p
+             || (target_x >= it.last_visible_x
+                 && it.line_wrap != TRUNCATE))
+           {
+             if (pt_x > 0)
+               move_it_by_lines (&it, 0);
+             move_it_by_lines (&it, 1);
+             target_x = 0;
+           }
+       }
+
+      /* Move to the target X coordinate.  */
+#ifdef HAVE_WINDOW_SYSTEM
+      /* On GUI frames, as we don't know the X coordinate of the
+        character to the left of point, moving point to the left
+        requires walking, one grapheme cluster at a time, until we
+        find ourself at a place immediately to the left of the
+        character at point.  */
+      if (FRAME_WINDOW_P (it.f) && dir < 0)
+       {
+         struct text_pos new_pos = it.current.pos;
+         enum move_it_result rc = MOVE_X_REACHED;
+
+         while (it.current_x + it.pixel_width <= target_x
+                && rc == MOVE_X_REACHED)
+           {
+             int new_x = it.current_x + it.pixel_width;
+
+             new_pos = it.current.pos;
+             if (new_x == it.current_x)
+               new_x++;
+             rc = move_it_in_display_line_to (&it, ZV, new_x,
+                                              MOVE_TO_POS | MOVE_TO_X);
+             if (ITERATOR_AT_END_OF_LINE_P (&it) && !target_is_eol_p)
+               break;
+           }
+         /* If we ended up on a composed character inside
+            bidi-reordered text (e.g., Hebrew text with diacritics),
+            the iterator gives us the buffer position of the last (in
+            logical order) character of the composed grapheme cluster,
+            which is not what we want.  So we cheat: we compute the
+            character position of the character that follows (in the
+            logical order) the one where the above loop stopped.  That
+            character will appear on display to the left of point.  */
+         if (it.bidi_p
+             && it.bidi_it.scan_dir == -1
+             && new_pos.charpos - IT_CHARPOS (it) > 1)
+           {
+             new_pos.charpos = IT_CHARPOS (it) + 1;
+             new_pos.bytepos = CHAR_TO_BYTE (new_pos.charpos);
+           }
+         it.current.pos = new_pos;
+       }
+      else
+#endif
+      if (it.current_x != target_x)
+       move_it_in_display_line_to (&it, ZV, target_x, MOVE_TO_POS | MOVE_TO_X);
+
+      /* When lines are truncated, the above loop will stop at the
+        window edge.  But we want to get to the end of line, even if
+        it is beyond the window edge; automatic hscroll will then
+        scroll the window to show point as appropriate.  */
+      if (target_is_eol_p && it.line_wrap == TRUNCATE
+         && get_next_display_element (&it))
+       {
+         struct text_pos new_pos = it.current.pos;
+
+         while (!ITERATOR_AT_END_OF_LINE_P (&it))
+           {
+             set_iterator_to_next (&it, 0);
+             if (it.method == GET_FROM_BUFFER)
+               new_pos = it.current.pos;
+             if (!get_next_display_element (&it))
+               break;
+           }
+
+         it.current.pos = new_pos;
+       }
+
+      /* If we ended up in a display string that covers point, move to
+        buffer position to the right in the visual order.  */
+      if (dir > 0)
+       {
+         while (IT_CHARPOS (it) == PT)
+           {
+             set_iterator_to_next (&it, 0);
+             if (!get_next_display_element (&it))
+               break;
+           }
+       }
+
+      /* Move point to that position.  */
+      SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+    }
+
+  return make_number (PT);
+
+#undef ROW_GLYPH_NEWLINE_P
+}
 
 \f
 /***********************************************************************
@@ -20799,7 +21304,7 @@ store_mode_line_string (const char *string, Lisp_Object lisp_string, int copy_st
          if (NILP (face))
            face = mode_line_string_face;
          else
-           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
+           face = list2 (face, mode_line_string_face);
          props = Fplist_put (props, Qface, face);
        }
       Fadd_text_properties (make_number (0), make_number (len),
@@ -20823,8 +21328,8 @@ store_mode_line_string (const char *string, Lisp_Object lisp_string, int copy_st
          if (NILP (face))
            face = mode_line_string_face;
          else
-           face = Fcons (face, Fcons (mode_line_string_face, Qnil));
-         props = Fcons (Qface, Fcons (face, Qnil));
+           face = list2 (face, mode_line_string_face);
+         props = list2 (Qface, face);
          if (copy_string)
            lisp_string = Fcopy_sequence (lisp_string);
        }
@@ -20938,7 +21443,7 @@ are the selected window and the WINDOW's buffer).  */)
       mode_line_string_list = Qnil;
       mode_line_string_face = face;
       mode_line_string_face_prop
-       = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
+       = NILP (face) ? Qnil : list2 (Qface, face);
     }
 
   push_kboard (FRAME_KBOARD (it.f));
@@ -23321,17 +23826,15 @@ draw_glyphs (struct window *w, int x, struct glyph_row *row,
          && hlinfo->mouse_face_beg_row >= 0
          && hlinfo->mouse_face_end_row >= 0)
        {
-         struct glyph_row *mouse_beg_row, *mouse_end_row;
-
-         mouse_beg_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_beg_row);
-         mouse_end_row = MATRIX_ROW (w->current_matrix, hlinfo->mouse_face_end_row);
+         ptrdiff_t row_vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
 
-         if (row >= mouse_beg_row && row <= mouse_end_row)
+         if (row_vpos >= hlinfo->mouse_face_beg_row
+             && row_vpos <= hlinfo->mouse_face_end_row)
            {
              check_mouse_face = 1;
-             mouse_beg_col = (row == mouse_beg_row)
+             mouse_beg_col = (row_vpos == hlinfo->mouse_face_beg_row)
                ? hlinfo->mouse_face_beg_col : 0;
-             mouse_end_col = (row == mouse_end_row)
+             mouse_end_col = (row_vpos == hlinfo->mouse_face_end_row)
                ? hlinfo->mouse_face_end_col
                : row->used[TEXT_AREA];
            }
@@ -25223,16 +25726,15 @@ x_produce_glyphs (struct it *it)
 /* EXPORT for RIF:
    Output LEN glyphs starting at START at the nominal cursor position.
    Advance the nominal cursor over the text.  The global variable
-   updated_window contains the window being updated, updated_row is
-   the glyph row being updated, and updated_area is the area of that
-   row being updated.  */
+   updated_row is the glyph row being updated, and updated_area is the
+   area of that row being updated.  */
 
 void
-x_write_glyphs (struct glyph *start, int len)
+x_write_glyphs (struct window *w, struct glyph *start, int len)
 {
-  int x, hpos, chpos = updated_window->phys_cursor.hpos;
+  int x, hpos, chpos = w->phys_cursor.hpos;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   /* When the window is hscrolled, cursor hpos can legitimately be out
      of bounds, but we draw the cursor at the corresponding window
      margin in that case.  */
@@ -25246,18 +25748,18 @@ x_write_glyphs (struct glyph *start, int len)
   /* Write glyphs.  */
 
   hpos = start - updated_row->glyphs[updated_area];
-  x = draw_glyphs (updated_window, output_cursor.x,
+  x = draw_glyphs (w, output_cursor.x,
                   updated_row, updated_area,
                   hpos, hpos + len,
                   DRAW_NORMAL_TEXT, 0);
 
   /* Invalidate old phys cursor if the glyph at its hpos is redrawn.  */
   if (updated_area == TEXT_AREA
-      && updated_window->phys_cursor_on_p
-      && updated_window->phys_cursor.vpos == output_cursor.vpos
+      && w->phys_cursor_on_p
+      && w->phys_cursor.vpos == output_cursor.vpos
       && chpos >= hpos
       && chpos < hpos + len)
-    updated_window->phys_cursor_on_p = 0;
+    w->phys_cursor_on_p = 0;
 
   unblock_input ();
 
@@ -25271,19 +25773,17 @@ x_write_glyphs (struct glyph *start, int len)
    Insert LEN glyphs from START at the nominal cursor position.  */
 
 void
-x_insert_glyphs (struct glyph *start, int len)
+x_insert_glyphs (struct window *w, struct glyph *start, int len)
 {
   struct frame *f;
-  struct window *w;
   int line_height, shift_by_width, shifted_region_width;
   struct glyph_row *row;
   struct glyph *glyph;
   int frame_x, frame_y;
   ptrdiff_t hpos;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   block_input ();
-  w = updated_window;
   f = XFRAME (WINDOW_FRAME (w));
 
   /* Get the height of the line we are in.  */
@@ -25325,18 +25825,17 @@ x_insert_glyphs (struct glyph *start, int len)
    (inclusive) to pixel column TO_X (exclusive).  The idea is that
    everything from TO_X onward is already erased.
 
-   TO_X is a pixel position relative to updated_area of
-   updated_window.  TO_X == -1 means clear to the end of this area.  */
+   TO_X is a pixel position relative to updated_area of currently
+   updated window W.  TO_X == -1 means clear to the end of this area.  */
 
 void
-x_clear_end_of_line (int to_x)
+x_clear_end_of_line (struct window *w, int to_x)
 {
   struct frame *f;
-  struct window *w = updated_window;
   int max_x, min_y, max_y;
   int from_x, from_y, to_y;
 
-  eassert (updated_window && updated_row);
+  eassert (updated_row);
   f = XFRAME (w->frame);
 
   if (updated_row->full_width_p)
@@ -27377,7 +27876,7 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
   if (STRINGP (string))
     {
       mouse_face = Fget_text_property (pos, Qmouse_face, string);
-      if (!NILP (mouse_face)
+      if (!NILP (Vmouse_highlight) && !NILP (mouse_face)
          && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))
          && glyph)
        {
@@ -27515,8 +28014,10 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y,
 
 /* EXPORT:
    Take proper action when the mouse has moved to position X, Y on
-   frame F as regards highlighting characters that have mouse-face
-   properties.  Also de-highlighting chars where the mouse was before.
+   frame F with regards to highlighting portions of display that have
+   mouse-face properties.  Also de-highlight portions of display where
+   the mouse was before, set the mouse pointer shape as appropriate
+   for the mouse coordinates, and activate help echo (tooltips).
    X and Y can be negative or out of range.  */
 
 void
@@ -27536,8 +28037,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
     return;
 #endif
 
-  if (NILP (Vmouse_highlight)
-      || !f->glyphs_initialized_p
+  if (!f->glyphs_initialized_p
       || f->pointer_invisible)
     return;
 
@@ -27606,10 +28106,7 @@ note_mouse_highlight (struct frame *f, int x, int y)
   /* Are we in a window whose display is up to date?
      And verify the buffer's text has not changed.  */
   b = XBUFFER (w->contents);
-  if (part == ON_TEXT
-      && w->window_end_valid
-      && w->last_modified == BUF_MODIFF (b)
-      && w->last_overlay_modified == BUF_OVERLAY_MODIFF (b))
+  if (part == ON_TEXT && w->window_end_valid && !window_outdated (w))
     {
       int hpos, vpos, dx, dy, area = LAST_AREA;
       ptrdiff_t pos;
@@ -27733,6 +28230,12 @@ note_mouse_highlight (struct frame *f, int x, int y)
       else
        noverlays = 0;
 
+      if (NILP (Vmouse_highlight))
+       {
+         clear_mouse_face (hlinfo);
+         goto check_help_echo;
+       }
+
       same_region = coords_in_mouse_face_p (w, hpos, vpos);
 
       if (same_region)
@@ -28294,7 +28797,7 @@ expose_window (struct window *w, XRectangle *fr)
   /* When we're currently updating the window, display and current
      matrix usually don't agree.  Arrange for a thorough display
      later.  */
-  if (w == updated_window)
+  if (w->must_be_updated_p)
     {
       SET_FRAME_GARBAGED (f);
       return 0;
@@ -28619,9 +29122,11 @@ syms_of_xdisp (void)
   defsubr (&Stool_bar_lines_needed);
   defsubr (&Slookup_image_map);
 #endif
+  defsubr (&Sline_pixel_height);
   defsubr (&Sformat_mode_line);
   defsubr (&Sinvisible_p);
   defsubr (&Scurrent_bidi_paragraph_direction);
+  defsubr (&Smove_point_visually);
 
   DEFSYM (Qmenu_bar_update_hook, "menu-bar-update-hook");
   DEFSYM (Qoverriding_terminal_local_map, "overriding-terminal-local-map");
@@ -28679,9 +29184,8 @@ syms_of_xdisp (void)
   DEFSYM (Qarrow, "arrow");
   DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
-  list_of_error = Fcons (Fcons (intern_c_string ("error"),
-                               Fcons (intern_c_string ("void-variable"), Qnil)),
-                        Qnil);
+  list_of_error = list1 (list2 (intern_c_string ("error"),
+                               intern_c_string ("void-variable")));
   staticpro (&list_of_error);
 
   DEFSYM (Qlast_arrow_position, "last-arrow-position");
@@ -28785,7 +29289,7 @@ See also `overlay-arrow-position'.  */);
 The symbols on this list are examined during redisplay to determine
 where to display overlay arrows.  */);
   Voverlay_arrow_variable_list
-    = Fcons (intern_c_string ("overlay-arrow-position"), Qnil);
+    = list1 (intern_c_string ("overlay-arrow-position"));
 
   DEFVAR_INT ("scroll-step", emacs_scroll_step,
     doc: /* The number of lines to try scrolling a window by when point moves out.