]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
* nsterm.m (sendEvent:): Skip mouse moved if no dialog and no Emacs
[gnu-emacs] / src / xdisp.c
index 0a79e6fd891959b22d22a986db2aa2d5ce01b63a..1a7369d7a45ef68e3edec16363b9b6ee35856779 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
@@ -816,21 +813,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 +877,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 +895,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 +1213,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 +1411,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 +1430,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;
                    }
                }
            }
@@ -2629,6 +2709,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 +3184,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 +3551,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 +3566,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 +3614,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 +5102,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);
            }
        }
@@ -5388,6 +5481,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);
        }
     }
@@ -5691,6 +5785,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 +6418,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 +6496,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 +6528,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 +8580,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 +9100,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 +9637,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;
@@ -10037,7 +10145,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 +10170,6 @@ unwind_with_echo_area_buffer (Lisp_Object vector)
     }
 
   Vwith_echo_area_save_vector = vector;
-  return Qnil;
 }
 
 
@@ -10461,20 +10568,12 @@ restore_message (void)
 }
 
 
-/* Handler for record_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.  */
+/* Handler for unwind-protect calling pop_message.  */
 
-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);
 }
@@ -10870,7 +10969,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 +11012,6 @@ unwind_format_mode_line (Lisp_Object vector)
     }
 
   Vmode_line_unwind_vector = vector;
-  return Qnil;
 }
 
 
@@ -11362,7 +11460,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 +11468,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 +11987,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 +12087,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 +12198,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 +12227,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 +12238,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 +12312,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 +12575,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 +12594,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))
@@ -12817,7 +12930,6 @@ redisplay_internal (void)
   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 +12968,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;
@@ -13503,7 +13610,6 @@ redisplay_internal (void)
 #endif /* HAVE_WINDOW_SYSTEM */
 
  end_of_redisplay:
-  backtrace_list = backtrace.next;
   unbind_to (count, Qnil);
   RESUME_POLLING;
 }
@@ -13542,14 +13648,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;
 }
 
 
@@ -14462,6 +14566,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 +14579,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 +14591,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 +14618,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 +14630,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 +14657,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 +14755,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 +14771,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 +14991,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 +15003,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 +15346,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;
@@ -15250,6 +15361,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
 
  restart:
   reconsider_clip_changes (w, buffer);
+  frame_line_height = default_line_pixel_height (w);
 
   /* Has the mode line to be updated?  */
   update_mode_line = (w->update_mode_line
@@ -15485,8 +15597,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
@@ -15497,7 +15611,7 @@ redisplay_window (Lisp_Object window, int just_this_one_p)
            new_vpos
              = pixel_margin + (header_line
                                ? CURRENT_HEADER_LINE_HEIGHT (w)
-                               : 0) + FRAME_LINE_HEIGHT (f);
+                               : 0) + frame_line_height;
          else
            {
              int window_height = window_box_height (w);
@@ -15746,9 +15860,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 +15886,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 +15922,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 +16035,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 +16228,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 +16254,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 +17561,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 +19006,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 +19037,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 +20079,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 +20100,404 @@ 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 = NULL;
+  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 (BUFFERP (w->contents))
+    b = XBUFFER (w->contents);
+
+  /* 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
+      && w->last_modified >= BUF_MODIFF (b)
+      && w->last_overlay_modified >= BUF_OVERLAY_MODIFF (b)
+      && 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 +21329,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 +21353,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 +21468,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));
@@ -27377,7 +27907,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 +28045,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 +28068,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;
 
@@ -27733,6 +28264,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)
@@ -28619,9 +29156,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 +29218,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 +29323,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.