Mention `tla replay' in README.multi-tty (Gaute Strokkenes).
[bpt/emacs.git] / src / xdisp.c
index 4b49472..3c144f4 100644 (file)
@@ -301,6 +301,7 @@ extern Lisp_Object Qface, Qinvisible, Qwidth;
 Lisp_Object Vdisplay_pixels_per_inch;
 Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
 Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
 Lisp_Object Vdisplay_pixels_per_inch;
 Lisp_Object Qspace, QCalign_to, QCrelative_width, QCrelative_height;
 Lisp_Object Qleft_margin, Qright_margin, Qspace_width, Qraise;
+Lisp_Object Qcenter;
 Lisp_Object Qmargin, Qpointer;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
 Lisp_Object Qmargin, Qpointer;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
@@ -311,13 +312,10 @@ extern Lisp_Object Qscroll_bar;
 Lisp_Object Vshow_trailing_whitespace;
 
 #ifdef HAVE_WINDOW_SYSTEM
 Lisp_Object Vshow_trailing_whitespace;
 
 #ifdef HAVE_WINDOW_SYSTEM
-/* Non-nil means that newline may flow into the right fringe.  */
-
-Lisp_Object Voverflow_newline_into_fringe;
-#endif /* HAVE_WINDOW_SYSTEM */
+extern Lisp_Object Voverflow_newline_into_fringe;
 
 /* Test if overflow newline into fringe.  Called with iterator IT
 
 /* Test if overflow newline into fringe.  Called with iterator IT
-   at or past right window margin, and with IT->current_x set.  */ 
+   at or past right window margin, and with IT->current_x set.  */
 
 #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it)    \
   (!NILP (Voverflow_newline_into_fringe)       \
 
 #define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it)    \
   (!NILP (Voverflow_newline_into_fringe)       \
@@ -325,6 +323,8 @@ Lisp_Object Voverflow_newline_into_fringe;
    && WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0    \
    && it->current_x == it->last_visible_x)
 
    && WINDOW_RIGHT_FRINGE_WIDTH (it->w) > 0    \
    && it->current_x == it->last_visible_x)
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 /* Non-nil means show the text cursor in void text areas
    i.e. in blank areas after eol and eob.  This used to be
    the default in 21.3.  */
 /* Non-nil means show the text cursor in void text areas
    i.e. in blank areas after eol and eob.  This used to be
    the default in 21.3.  */
@@ -404,6 +404,13 @@ int multiple_frames;
 
 Lisp_Object Vglobal_mode_string;
 
 
 Lisp_Object Vglobal_mode_string;
 
+
+/* List of variables (symbols) which hold markers for overlay arrows.
+   The symbols on this list are examined during redisplay to determine
+   where to display overlay arrows.  */
+
+Lisp_Object Voverlay_arrow_variable_list;
+
 /* Marker for where to display an arrow on top of the buffer text.  */
 
 Lisp_Object Voverlay_arrow_position;
 /* Marker for where to display an arrow on top of the buffer text.  */
 
 Lisp_Object Voverlay_arrow_position;
@@ -412,11 +419,17 @@ Lisp_Object Voverlay_arrow_position;
 
 Lisp_Object Voverlay_arrow_string;
 
 
 Lisp_Object Voverlay_arrow_string;
 
-/* Values of those variables at last redisplay.  However, if
-   Voverlay_arrow_position is a marker, last_arrow_position is its
+/* Values of those variables at last redisplay are stored as
+   properties on `overlay-arrow-position' symbol.  However, if
+   Voverlay_arrow_position is a marker, last-arrow-position is its
    numerical position.  */
 
    numerical position.  */
 
-static Lisp_Object last_arrow_position, last_arrow_string;
+Lisp_Object Qlast_arrow_position, Qlast_arrow_string;
+
+/* Alternative overlay-arrow-string and overlay-arrow-bitmap
+   properties on a symbol in overlay-arrow-variable-list.  */
+
+Lisp_Object Qoverlay_arrow_string, Qoverlay_arrow_bitmap;
 
 /* Like mode-line-format, but for the title bar on a visible frame.  */
 
 
 /* Like mode-line-format, but for the title bar on a visible frame.  */
 
@@ -829,10 +842,11 @@ static struct text_pos display_prop_end P_ ((struct it *, Lisp_Object,
 static int compute_window_start_on_continuation_line P_ ((struct window *));
 static Lisp_Object safe_eval_handler P_ ((Lisp_Object));
 static void insert_left_trunc_glyphs P_ ((struct it *));
 static int compute_window_start_on_continuation_line P_ ((struct window *));
 static Lisp_Object safe_eval_handler P_ ((Lisp_Object));
 static void insert_left_trunc_glyphs P_ ((struct it *));
-static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *));
+static struct glyph_row *get_overlay_arrow_glyph_row P_ ((struct window *,
+                                                         Lisp_Object));
 static void extend_face_to_end_of_line P_ ((struct it *));
 static int append_space P_ ((struct it *, int));
 static void extend_face_to_end_of_line P_ ((struct it *));
 static int append_space P_ ((struct it *, int));
-static int make_cursor_line_fully_visible P_ ((struct window *));
+static int make_cursor_line_fully_visible P_ ((struct window *, int));
 static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
 static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
 static int try_scrolling P_ ((Lisp_Object, int, EMACS_INT, EMACS_INT, int, int));
 static int try_cursor_movement P_ ((Lisp_Object, struct text_pos, int *));
 static int trailing_whitespace_p P_ ((int));
@@ -1775,8 +1789,9 @@ get_glyph_string_clip_rect (s, nr)
       height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
       if (height < r.height)
        {
       height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
       if (height < r.height)
        {
-         r.y = s->ybase + glyph->descent - height;
-         r.height = height;
+         int max_y = r.y + r.height;
+         r.y = min (max_y, s->ybase + glyph->descent - height);
+         r.height = min (max_y - r.y, height);
        }
     }
 
        }
     }
 
@@ -1901,10 +1916,14 @@ check_it (it)
       xassert (STRINGP (it->string));
       xassert (IT_STRING_CHARPOS (*it) >= 0);
     }
       xassert (STRINGP (it->string));
       xassert (IT_STRING_CHARPOS (*it) >= 0);
     }
-  else if (it->method == next_element_from_buffer)
+  else
     {
     {
-      /* Check that character and byte positions agree.  */
-      xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
+      xassert (IT_STRING_CHARPOS (*it) < 0);
+      if (it->method == next_element_from_buffer)
+       {
+         /* Check that character and byte positions agree.  */
+         xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
+       }
     }
 
   if (it->dpvec)
     }
 
   if (it->dpvec)
@@ -2017,6 +2036,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
   it->current.overlay_string_index = -1;
   it->current.dpvec_index = -1;
   it->base_face_id = base_face_id;
   it->current.overlay_string_index = -1;
   it->current.dpvec_index = -1;
   it->base_face_id = base_face_id;
+  it->string = Qnil;
+  IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
 
   /* The window in which we iterate over current_buffer:  */
   XSETWINDOW (it->window, w);
 
   /* The window in which we iterate over current_buffer:  */
   XSETWINDOW (it->window, w);
@@ -3275,6 +3296,8 @@ handle_display_prop (it)
       && !EQ (XCAR (prop), Qraise)
       /* Marginal area specifications.  */
       && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
       && !EQ (XCAR (prop), Qraise)
       /* Marginal area specifications.  */
       && !(CONSP (XCAR (prop)) && EQ (XCAR (XCAR (prop)), Qmargin))
+      && !EQ (XCAR (prop), Qleft_fringe)
+      && !EQ (XCAR (prop), Qright_fringe)
       && !NILP (XCAR (prop)))
     {
       for (; CONSP (prop); prop = XCDR (prop))
       && !NILP (XCAR (prop)))
     {
       for (; CONSP (prop); prop = XCDR (prop))
@@ -3499,6 +3522,64 @@ handle_single_display_prop (it, prop, object, position,
         text properties change there.  */
       it->stop_charpos = position->charpos;
 
         text properties change there.  */
       it->stop_charpos = position->charpos;
 
+      if (CONSP (prop)
+         && (EQ (XCAR (prop), Qleft_fringe)
+             || EQ (XCAR (prop), Qright_fringe))
+         && CONSP (XCDR (prop)))
+       {
+         unsigned face_id = DEFAULT_FACE_ID;
+
+         /* Save current settings of IT so that we can restore them
+            when we are finished with the glyph property value.  */
+
+         /* `(left-fringe BITMAP FACE)'.  */
+         if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+           return 0;
+
+#ifdef HAVE_WINDOW_SYSTEM
+         value = XCAR (XCDR (prop));
+         if (!NUMBERP (value)
+             || !valid_fringe_bitmap_id_p (XINT (value)))
+           return 0;
+
+         if (CONSP (XCDR (XCDR (prop))))
+           {
+             Lisp_Object face_name = XCAR (XCDR (XCDR (prop)));
+
+             face_id = lookup_named_face (it->f, face_name, 'A');
+             if (face_id < 0)
+               return 0;
+           }
+
+         push_it (it);
+
+         it->area = TEXT_AREA;
+         it->what = IT_IMAGE;
+         it->image_id = -1; /* no image */
+         it->position = start_pos;
+         it->object = NILP (object) ? it->w->buffer : object;
+         it->method = next_element_from_image;
+         it->face_id = face_id;
+
+         /* Say that we haven't consumed the characters with
+            `display' property yet.  The call to pop_it in
+            set_iterator_to_next will clean this up.  */
+         *position = start_pos;
+
+         if (EQ (XCAR (prop), Qleft_fringe))
+           {
+             it->left_user_fringe_bitmap = XINT (value);
+             it->left_user_fringe_face_id = face_id;
+           }
+         else
+           {
+             it->right_user_fringe_bitmap = XINT (value);
+             it->right_user_fringe_face_id = face_id;
+           }
+#endif /* HAVE_WINDOW_SYSTEM */
+         return 1;
+       }
+
       location = Qunbound;
       if (CONSP (prop) && CONSP (XCAR (prop)))
        {
       location = Qunbound;
       if (CONSP (prop) && CONSP (XCAR (prop)))
        {
@@ -3524,16 +3605,11 @@ handle_single_display_prop (it, prop, object, position,
          value = prop;
        }
 
          value = prop;
        }
 
+      valid_p = (STRINGP (value)
 #ifdef HAVE_WINDOW_SYSTEM
 #ifdef HAVE_WINDOW_SYSTEM
-      if (FRAME_TERMCAP_P (it->f))
-       valid_p = STRINGP (value);
-      else
-       valid_p = (STRINGP (value)
-                  || (CONSP (value) && EQ (XCAR (value), Qspace))
-                  || valid_image_p (value));
-#else /* not HAVE_WINDOW_SYSTEM */
-      valid_p = STRINGP (value);
+                || (!FRAME_TERMCAP_P (it->f) && valid_image_p (value))
 #endif /* not HAVE_WINDOW_SYSTEM */
 #endif /* not HAVE_WINDOW_SYSTEM */
+                || (CONSP (value) && EQ (XCAR (value), Qspace)));
 
       if ((EQ (location, Qleft_margin)
           || EQ (location, Qright_margin)
 
       if ((EQ (location, Qleft_margin)
           || EQ (location, Qright_margin)
@@ -5515,15 +5591,18 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
   saved_glyph_row = it->glyph_row;
   it->glyph_row = NULL;
 
   saved_glyph_row = it->glyph_row;
   it->glyph_row = NULL;
 
+#define BUFFER_POS_REACHED_P()                     \
+  ((op & MOVE_TO_POS) != 0                         \
+   && BUFFERP (it->object)                         \
+   && IT_CHARPOS (*it) >= to_charpos)
+
   while (1)
     {
       int x, i, ascent = 0, descent = 0;
 
       /* Stop when ZV or TO_CHARPOS reached.  */
       if (!get_next_display_element (it)
   while (1)
     {
       int x, i, ascent = 0, descent = 0;
 
       /* Stop when ZV or TO_CHARPOS reached.  */
       if (!get_next_display_element (it)
-         || ((op & MOVE_TO_POS) != 0
-             && BUFFERP (it->object)
-             && IT_CHARPOS (*it) >= to_charpos))
+         || BUFFER_POS_REACHED_P ())
        {
          result = MOVE_POS_MATCH_OR_ZV;
          break;
        {
          result = MOVE_POS_MATCH_OR_ZV;
          break;
@@ -5610,7 +5689,12 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
-                             get_next_display_element (it);
+                             if (!get_next_display_element (it)
+                                 || BUFFER_POS_REACHED_P ())
+                               {
+                                 result = MOVE_POS_MATCH_OR_ZV;
+                                 break;
+                               }
                              if (ITERATOR_AT_END_OF_LINE_P (it))
                                {
                                  result = MOVE_NEWLINE_OR_CR;
                              if (ITERATOR_AT_END_OF_LINE_P (it))
                                {
                                  result = MOVE_NEWLINE_OR_CR;
@@ -5678,7 +5762,12 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
 #ifdef HAVE_WINDOW_SYSTEM
          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
            {
 #ifdef HAVE_WINDOW_SYSTEM
          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
            {
-             get_next_display_element (it);
+             if (!get_next_display_element (it)
+                 || BUFFER_POS_REACHED_P ())
+               {
+                 result = MOVE_POS_MATCH_OR_ZV;
+                 break;
+               }
              if (ITERATOR_AT_END_OF_LINE_P (it))
                {
                  result = MOVE_NEWLINE_OR_CR;
              if (ITERATOR_AT_END_OF_LINE_P (it))
                {
                  result = MOVE_NEWLINE_OR_CR;
@@ -5691,6 +5780,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
        }
     }
 
        }
     }
 
+#undef BUFFER_POS_REACHED_P
+
   /* Restore the iterator settings altered at the beginning of this
      function.  */
   it->glyph_row = saved_glyph_row;
   /* Restore the iterator settings altered at the beginning of this
      function.  */
   it->glyph_row = saved_glyph_row;
@@ -7614,7 +7705,10 @@ clear_garbaged_frames ()
          if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
            {
              if (f->resized_p)
          if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
            {
              if (f->resized_p)
-               Fredraw_frame (frame);
+               {
+                 Fredraw_frame (frame);
+                 f->force_flush_display_p = 1;
+               }
              clear_current_matrices (f);
              changed_count++;
              f->garbaged = 0;
              clear_current_matrices (f);
              changed_count++;
              f->garbaged = 0;
@@ -8270,7 +8364,7 @@ update_tool_bar (f, save_match_data)
          /* Redisplay the tool-bar if we changed it.  */
          if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
            w->update_mode_line = Qt;
          /* Redisplay the tool-bar if we changed it.  */
          if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
            w->update_mode_line = Qt;
-         
+
          UNGCPRO;
 
          unbind_to (count, Qnil);
          UNGCPRO;
 
          unbind_to (count, Qnil);
@@ -8928,536 +9022,6 @@ note_tool_bar_highlight (f, x, y)
 
 
 \f
 
 
 \f
-/***********************************************************************
-                              Fringes
- ***********************************************************************/
-
-#ifdef HAVE_WINDOW_SYSTEM
-
-/* Notice that all bitmaps bits are "mirrored".  */
-
-/* An arrow like this: `<-'.  */
-/*
-  ...xx...
-  ....xx..
-  .....xx.
-  ..xxxxxx
-  ..xxxxxx
-  .....xx.
-  ....xx..
-  ...xx...
-*/
-static unsigned char left_bits[] = {
-   0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
-
-
-/* Right truncation arrow bitmap `->'.  */
-/*
-  ...xx...
-  ..xx....
-  .xx.....
-  xxxxxx..
-  xxxxxx..
-  .xx.....
-  ..xx....
-  ...xx...
-*/
-static unsigned char right_bits[] = {
-   0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
-
-
-/* Up arrow bitmap.  */
-/*
-  ...xx...
-  ..xxxx..
-  .xxxxxx.
-  xxxxxxxx
-  ...xx...
-  ...xx...
-  ...xx...
-  ...xx...
-*/
-static unsigned char up_arrow_bits[] = {
-   0x18, 0x3c, 0x7e, 0xff, 0x18, 0x18, 0x18, 0x18};
-
-
-/* Down arrow bitmap.  */
-/*
-  ...xx...
-  ...xx...
-  ...xx...
-  ...xx...
-  xxxxxxxx
-  .xxxxxx.
-  ..xxxx..
-  ...xx...
-*/
-static unsigned char down_arrow_bits[] = {
-   0x18, 0x18, 0x18, 0x18, 0xff, 0x7e, 0x3c, 0x18};
-
-/* Marker for continued lines.  */
-/*
-  ..xxxx..
-  .xxxxx..
-  xx......
-  xxx..x..
-  xxxxxx..
-  .xxxxx..
-  ..xxxx..
-  .xxxxx..
-*/
-static unsigned char continued_bits[] = {
-   0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
-
-/* Marker for continuation lines.  */
-/*
-  ..xxxx..
-  ..xxxxx.
-  ......xx
-  ..x..xxx
-  ..xxxxxx
-  ..xxxxx.
-  ..xxxx..
-  ..xxxxx.
-*/
-static unsigned char continuation_bits[] = {
-   0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
-
-/* Overlay arrow bitmap.  A triangular arrow.  */
-/*
-  ......xx
-  ....xxxx
-  ...xxxxx
-  ..xxxxxx
-  ..xxxxxx
-  ...xxxxx
-  ....xxxx
-  ......xx
-*/
-static unsigned char ov_bits[] = {
-   0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
-
-
-/* First line bitmap.  An left-up angle.  */
-/*
-  ..xxxxxx
-  ..xxxxxx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ........
-*/
-static unsigned char first_line_bits[] = {
-   0x3f, 0x3f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00};
-
-
-/* Last line bitmap.  An left-down angle.  */
-/*
-  ........
-  xx......
-  xx......
-  xx......
-  xx......
-  xx......
-  xxxxxx..
-  xxxxxx..
-*/
-static unsigned char last_line_bits[] = {
-   0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xfc};
-
-/* Filled box cursor bitmap.  A filled box; max 13 pixels high.  */
-/*
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-  .xxxxxxx
-*/
-static unsigned char filled_box_cursor_bits[] = {
-   0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f};
-
-/* Hollow box cursor bitmap.  A hollow box; max 13 pixels high.  */
-/*
-  .xxxxxxx
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .x.....x
-  .xxxxxxx
-*/
-static unsigned char hollow_box_cursor_bits[] = {
-   0x7f, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x7f};
-
-/* Bar cursor bitmap.  A vertical bar; max 13 pixels high.  */
-/*
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-  ......xx
-*/
-static unsigned char bar_cursor_bits[] = {
-   0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03};
-
-/* HBar cursor bitmap.  A horisontal bar; 2 pixels high.  */
-/*
-  .xxxxxxx
-  .xxxxxxx
-*/
-static unsigned char hbar_cursor_bits[] = {
-  0x7f, 0x7f};
-
-
-/* Bitmap drawn to indicate lines not displaying text if
-   `indicate-empty-lines' is non-nil.  */
-static unsigned char zv_bits[] = {
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00,
-  0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3c, 0x00};
-
-/* Hollow square bitmap.  */
-/*
-  .xxxxxx.
-  .x....x.
-  .x....x.
-  .x....x.
-  .x....x.
-  .xxxxxx.
-*/
-static unsigned char hollow_square_bits[] = {
-   0x7e, 0x42, 0x42, 0x42, 0x42, 0x7e};
-
-
-struct fringe_bitmap fringe_bitmaps[MAX_FRINGE_BITMAPS] =
-{
-  { 0, 0, 0, NULL /* NO_FRINGE_BITMAP */ },
-  { 8, sizeof (left_bits), 0, left_bits },
-  { 8, sizeof (right_bits), 0, right_bits },
-  { 8, sizeof (up_arrow_bits), -1, up_arrow_bits },
-  { 8, sizeof (down_arrow_bits), -2, down_arrow_bits },
-  { 8, sizeof (continued_bits), 0, continued_bits },
-  { 8, sizeof (continuation_bits), 0, continuation_bits },
-  { 8, sizeof (ov_bits), 0, ov_bits },
-  { 8, sizeof (first_line_bits), -1, first_line_bits },
-  { 8, sizeof (last_line_bits), -2, last_line_bits },
-  { 8, sizeof (filled_box_cursor_bits), 0, filled_box_cursor_bits },
-  { 8, sizeof (hollow_box_cursor_bits), 0, hollow_box_cursor_bits },
-  { 8, sizeof (bar_cursor_bits), 0, bar_cursor_bits },
-  { 8, sizeof (hbar_cursor_bits), -2, hbar_cursor_bits },
-  { 8, sizeof (zv_bits), 3, zv_bits },
-  { 8, sizeof (hollow_square_bits), 0, hollow_square_bits },
-};
-
-
-/* Draw the bitmap WHICH in one of the left or right fringes of
-   window W.  ROW is the glyph row for which to display the bitmap; it
-   determines the vertical position at which the bitmap has to be
-   drawn.
-   LEFT_P is 1 for left fringe, 0 for right fringe.
-*/
-
-void
-draw_fringe_bitmap (w, row, left_p)
-     struct window *w;
-     struct glyph_row *row;
-     int left_p;
-{
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-  struct draw_fringe_bitmap_params p;
-  enum fringe_bitmap_type which;
-  int period;
-
-  if (left_p)
-    which = row->left_fringe_bitmap;
-  else if (!row->cursor_in_fringe_p)
-    which = row->right_fringe_bitmap;
-  else
-    switch (w->phys_cursor_type)
-      {
-      case HOLLOW_BOX_CURSOR:
-       if (row->visible_height >= sizeof(hollow_box_cursor_bits))
-         which = HOLLOW_BOX_CURSOR_BITMAP;
-       else
-         which = HOLLOW_SQUARE_BITMAP;
-       break;
-      case FILLED_BOX_CURSOR:
-       which = FILLED_BOX_CURSOR_BITMAP;
-       break;
-      case BAR_CURSOR:
-       which = BAR_CURSOR_BITMAP;
-       break;
-      case HBAR_CURSOR:
-       which = HBAR_CURSOR_BITMAP;
-       break;
-      case NO_CURSOR:
-      default:
-       w->phys_cursor_on_p = 0;
-       row->cursor_in_fringe_p = 0;
-       which = row->right_fringe_bitmap;
-       break;
-      }
-
-  period = fringe_bitmaps[which].period;
-
-  /* Convert row to frame coordinates.  */
-  p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
-
-  p.which = which;
-  p.wd = fringe_bitmaps[which].width;
-
-  p.h = fringe_bitmaps[which].height;
-  p.dh = (period > 0 ? (p.y % period) : 0);
-  p.h -= p.dh;
-  /* Clip bitmap if too high.  */
-  if (p.h > row->height)
-    p.h = row->height;
-
-  p.face = FACE_FROM_ID (f, FRINGE_FACE_ID);
-  PREPARE_FACE_FOR_DISPLAY (f, p.face);
-
-  /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
-     the fringe.  */
-  p.bx = -1;
-  if (left_p)
-    {
-      int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
-      int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-                                  ? LEFT_MARGIN_AREA
-                                  : TEXT_AREA));
-      if (p.wd > wd)
-       p.wd = wd;
-      p.x = x - p.wd - (wd - p.wd) / 2;
-
-      if (p.wd < wd || row->height > p.h)
-       {
-         /* If W has a vertical border to its left, don't draw over it.  */
-         wd -= ((!WINDOW_LEFTMOST_P (w)
-                 && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
-                ? 1 : 0);
-         p.bx = x - wd;
-         p.nx = wd;
-       }
-    }
-  else
-    {
-      int x = window_box_right (w,
-                               (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
-                                ? RIGHT_MARGIN_AREA
-                                : TEXT_AREA));
-      int wd = WINDOW_RIGHT_FRINGE_WIDTH (w);
-      if (p.wd > wd)
-       p.wd = wd;
-      p.x = x + (wd - p.wd) / 2;
-      /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
-        the fringe.  */
-      if (p.wd < wd || row->height > p.h)
-       {
-         p.bx = x;
-         p.nx = wd;
-       }
-    }
-
-  if (p.bx >= 0)
-    {
-      int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
-
-      p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
-      p.ny = row->visible_height;
-    }
-
-  /* Adjust y to the offset in the row to start drawing the bitmap.  */
-  if (period == 0)
-    p.y += (row->height - p.h) / 2;
-  else if (period == -2)
-    {
-      p.h = fringe_bitmaps[which].height;
-      p.y += (row->visible_height - p.h);
-    }
-
-  FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p);
-}
-
-/* Draw fringe bitmaps for glyph row ROW on window W.  Call this
-   function with input blocked.  */
-
-void
-draw_row_fringe_bitmaps (w, row)
-     struct window *w;
-     struct glyph_row *row;
-{
-  xassert (interrupt_input_blocked);
-
-  /* If row is completely invisible, because of vscrolling, we
-     don't have to draw anything.  */
-  if (row->visible_height <= 0)
-    return;
-
-  if (WINDOW_LEFT_FRINGE_WIDTH (w) != 0)
-    draw_fringe_bitmap (w, row, 1);
-
-  if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0)
-    draw_fringe_bitmap (w, row, 0);
-}
-
-/* Draw the fringes of window W.  Only fringes for rows marked for
-   update in redraw_fringe_bitmaps_p are drawn.  */
-
-void
-draw_window_fringes (w)
-     struct window *w;
-{
-  struct glyph_row *row;
-  int yb = window_text_bottom_y (w);
-  int nrows = w->current_matrix->nrows;
-  int y = 0, rn;
-
-  if (w->pseudo_window_p)
-    return;
-
-  for (y = 0, rn = 0, row = w->current_matrix->rows;
-       y < yb && rn < nrows;
-       y += row->height, ++row, ++rn)
-    {
-      if (!row->redraw_fringe_bitmaps_p)
-       continue;
-      draw_row_fringe_bitmaps (w, row);
-      row->redraw_fringe_bitmaps_p = 0;
-    }
-}
-
-
-/* Compute actual fringe widths for frame F.  
-
-   If REDRAW is 1, redraw F if the fringe settings was actually
-   modified and F is visible.
-
-   Since the combined left and right fringe must occupy an integral
-   number of columns, we may need to add some pixels to each fringe.
-   Typically, we add an equal amount (+/- 1 pixel) to each fringe,
-   but a negative width value is taken literally (after negating it).
-
-   We never make the fringes narrower than specified.  It is planned
-   to make fringe bitmaps customizable and expandable, and at that
-   time, the user will typically specify the minimum number of pixels
-   needed for his bitmaps, so we shouldn't select anything less than
-   what is specified.
-*/
-
-void
-compute_fringe_widths (f, redraw)
-     struct frame *f;
-     int redraw;
-{
-  int o_left = FRAME_LEFT_FRINGE_WIDTH (f);
-  int o_right = FRAME_RIGHT_FRINGE_WIDTH (f);
-  int o_cols = FRAME_FRINGE_COLS (f);
-
-  Lisp_Object left_fringe = Fassq (Qleft_fringe, f->param_alist);
-  Lisp_Object right_fringe = Fassq (Qright_fringe, f->param_alist);
-  int left_fringe_width, right_fringe_width;
-
-  if (!NILP (left_fringe))
-    left_fringe = Fcdr (left_fringe);
-  if (!NILP (right_fringe))
-    right_fringe = Fcdr (right_fringe);
-
-  left_fringe_width = ((NILP (left_fringe) || !INTEGERP (left_fringe)) ? 8 :
-                      XINT (left_fringe));
-  right_fringe_width = ((NILP (right_fringe) || !INTEGERP (right_fringe)) ? 8 :
-                       XINT (right_fringe));
-
-  if (left_fringe_width || right_fringe_width)
-    {
-      int left_wid = left_fringe_width >= 0 ? left_fringe_width : -left_fringe_width;
-      int right_wid = right_fringe_width >= 0 ? right_fringe_width : -right_fringe_width;
-      int conf_wid = left_wid + right_wid;
-      int font_wid = FRAME_COLUMN_WIDTH (f);
-      int cols = (left_wid + right_wid + font_wid-1) / font_wid;
-      int real_wid = cols * font_wid;
-      if (left_wid && right_wid)
-       {
-         if (left_fringe_width < 0)
-           {
-             /* Left fringe width is fixed, adjust right fringe if necessary */
-             FRAME_LEFT_FRINGE_WIDTH (f) = left_wid;
-             FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid - left_wid;
-           }
-         else if (right_fringe_width < 0)
-           {
-             /* Right fringe width is fixed, adjust left fringe if necessary */
-             FRAME_LEFT_FRINGE_WIDTH (f) = real_wid - right_wid;
-             FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid;
-           }
-         else
-           {
-             /* Adjust both fringes with an equal amount.
-                Note that we are doing integer arithmetic here, so don't
-                lose a pixel if the total width is an odd number.  */
-             int fill = real_wid - conf_wid;
-             FRAME_LEFT_FRINGE_WIDTH (f) = left_wid + fill/2;
-             FRAME_RIGHT_FRINGE_WIDTH (f) = right_wid + fill - fill/2;
-           }
-       }
-      else if (left_fringe_width)
-       {
-         FRAME_LEFT_FRINGE_WIDTH (f) = real_wid;
-         FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
-       }
-      else
-       {
-         FRAME_LEFT_FRINGE_WIDTH (f) = 0;
-         FRAME_RIGHT_FRINGE_WIDTH (f) = real_wid;
-       }
-      FRAME_FRINGE_COLS (f) = cols;
-    }
-  else
-    {
-      FRAME_LEFT_FRINGE_WIDTH (f) = 0;
-      FRAME_RIGHT_FRINGE_WIDTH (f) = 0;
-      FRAME_FRINGE_COLS (f) = 0;
-    }
-
-  if (redraw && FRAME_VISIBLE_P (f))
-    if (o_left != FRAME_LEFT_FRINGE_WIDTH (f) ||
-       o_right != FRAME_RIGHT_FRINGE_WIDTH (f) ||
-       o_cols != FRAME_FRINGE_COLS (f))
-      redraw_frame (f);
-}
-
-#endif /* HAVE_WINDOW_SYSTEM */
-
-
-\f
 /************************************************************************
                         Horizontal scrolling
  ************************************************************************/
 /************************************************************************
                         Horizontal scrolling
  ************************************************************************/
@@ -9558,7 +9122,10 @@ hscroll_window_tree (window)
 
              /* Position cursor in window.  */
              if (!hscroll_relative_p && hscroll_step_abs == 0)
 
              /* Position cursor in window.  */
              if (!hscroll_relative_p && hscroll_step_abs == 0)
-               hscroll = max (0, it.current_x - text_area_width / 2)
+               hscroll = max (0, (it.current_x
+                                  - (ITERATOR_AT_END_OF_LINE_P (&it)
+                                     ? (text_area_width - 4 * FRAME_COLUMN_WIDTH (it.f))
+                                     : (text_area_width / 2))))
                          / FRAME_COLUMN_WIDTH (it.f);
              else if (w->cursor.x >= text_area_width - h_margin)
                {
                          / FRAME_COLUMN_WIDTH (it.f);
              else if (w->cursor.x >= text_area_width - h_margin)
                {
@@ -9767,76 +9334,223 @@ redisplay ()
 }
 
 
 }
 
 
-/* Return 1 if point moved out of or into a composition.  Otherwise
-   return 0.  PREV_BUF and PREV_PT are the last point buffer and
-   position.  BUF and PT are the current point buffer and position.  */
+static Lisp_Object
+overlay_arrow_string_or_property (var, pbitmap)
+     Lisp_Object var;
+     int *pbitmap;
+{
+  Lisp_Object pstr = Fget (var, Qoverlay_arrow_string);
+  Lisp_Object bitmap;
 
 
-int
-check_point_in_composition (prev_buf, prev_pt, buf, pt)
-     struct buffer *prev_buf, *buf;
-     int prev_pt, pt;
+  if (pbitmap)
+    {
+      *pbitmap = 0;
+      if (bitmap  = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap))
+       *pbitmap = XINT (bitmap);
+    }
+
+  if (!NILP (pstr))
+    return pstr;
+  return Voverlay_arrow_string;
+}
+
+/* Return 1 if there are any overlay-arrows in current_buffer.  */
+static int
+overlay_arrow_in_current_buffer_p ()
 {
 {
-  int start, end;
-  Lisp_Object prop;
-  Lisp_Object buffer;
+  Lisp_Object vlist;
 
 
-  XSETBUFFER (buffer, buf);
-  /* Check a composition at the last point if point moved within the
-     same buffer.  */
-  if (prev_buf == buf)
+  for (vlist = Voverlay_arrow_variable_list;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
     {
     {
-      if (prev_pt == pt)
-       /* Point didn't move.  */
-       return 0;
+      Lisp_Object var = XCAR (vlist);
+      Lisp_Object val;
 
 
-      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)
-         && start < prev_pt && end > prev_pt)
-       /* The last point was within the composition.  Return 1 iff
-            point moved out of the composition.  */
-       return (pt <= start || pt >= end);
+      if (!SYMBOLP (var))
+       continue;
+      val = find_symbol_value (var);
+      if (MARKERP (val)
+         && current_buffer == XMARKER (val)->buffer)
+       return 1;
     }
     }
-
-  /* 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)
-         && start < pt && end > pt);
+  return 0;
 }
 
 
 }
 
 
-/* Reconsider the setting of B->clip_changed which is displayed
-   in window W.  */
+/* Return 1 if any overlay_arrows have moved or overlay-arrow-string
+   has changed.  */
 
 
-static INLINE void
-reconsider_clip_changes (w, b)
-     struct window *w;
-     struct buffer *b;
+static int
+overlay_arrows_changed_p ()
 {
 {
-  if (b->clip_changed
-          && !NILP (w->window_end_valid)
-          && w->current_matrix->buffer == b
-          && w->current_matrix->zv == BUF_ZV (b)
-          && w->current_matrix->begv == BUF_BEGV (b))
-    b->clip_changed = 0;
+  Lisp_Object vlist;
 
 
-  /* If display wasn't paused, and W is not a tool bar window, see if
-     point has been moved into or out of a composition.  In that case,
-     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->buffer) && !NILP (w->window_end_valid))
+  for (vlist = Voverlay_arrow_variable_list;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
     {
     {
-      int pt;
-
-      if (w == XWINDOW (selected_window))
-       pt = BUF_PT (current_buffer);
-      else
-       pt = marker_position (w->pointm);
+      Lisp_Object var = XCAR (vlist);
+      Lisp_Object val, pstr;
 
 
-      if ((w->current_matrix->buffer != XBUFFER (w->buffer)
+      if (!SYMBOLP (var))
+       continue;
+      val = find_symbol_value (var);
+      if (!MARKERP (val))
+       continue;
+      if (! EQ (COERCE_MARKER (val),
+               Fget (var, Qlast_arrow_position))
+         || ! (pstr = overlay_arrow_string_or_property (var, 0),
+               EQ (pstr, Fget (var, Qlast_arrow_string))))
+       return 1;
+    }
+  return 0;
+}
+
+/* Mark overlay arrows to be updated on next redisplay.  */
+
+static void
+update_overlay_arrows (up_to_date)
+     int up_to_date;
+{
+  Lisp_Object vlist;
+
+  for (vlist = Voverlay_arrow_variable_list;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
+    {
+      Lisp_Object var = XCAR (vlist);
+
+      if (!SYMBOLP (var))
+       continue;
+
+      if (up_to_date > 0)
+       {
+         Lisp_Object val = find_symbol_value (var);
+         Fput (var, Qlast_arrow_position,
+               COERCE_MARKER (val));
+         Fput (var, Qlast_arrow_string,
+               overlay_arrow_string_or_property (var, 0));
+       }
+      else if (up_to_date < 0
+              || !NILP (Fget (var, Qlast_arrow_position)))
+       {
+         Fput (var, Qlast_arrow_position, Qt);
+         Fput (var, Qlast_arrow_string, Qt);
+       }
+    }
+}
+
+
+/* Return overlay arrow string at row, or nil.  */
+
+static Lisp_Object
+overlay_arrow_at_row (f, row, pbitmap)
+     struct frame *f;
+     struct glyph_row *row;
+     int *pbitmap;
+{
+  Lisp_Object vlist;
+
+  for (vlist = Voverlay_arrow_variable_list;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
+    {
+      Lisp_Object var = XCAR (vlist);
+      Lisp_Object val;
+
+      if (!SYMBOLP (var))
+       continue;
+
+      val = find_symbol_value (var);
+
+      if (MARKERP (val)
+         && current_buffer == XMARKER (val)->buffer
+         && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
+       {
+         val = overlay_arrow_string_or_property (var, pbitmap);
+         if (FRAME_WINDOW_P (f))
+           return Qt;
+         else if (STRINGP (val))
+           return val;
+         break;
+       }
+    }
+
+  *pbitmap = 0;
+  return Qnil;
+}
+
+/* Return 1 if point moved out of or into a composition.  Otherwise
+   return 0.  PREV_BUF and PREV_PT are the last point buffer and
+   position.  BUF and PT are the current point buffer and position.  */
+
+int
+check_point_in_composition (prev_buf, prev_pt, buf, pt)
+     struct buffer *prev_buf, *buf;
+     int prev_pt, pt;
+{
+  int start, end;
+  Lisp_Object prop;
+  Lisp_Object buffer;
+
+  XSETBUFFER (buffer, buf);
+  /* Check a composition at the last point if point moved within the
+     same buffer.  */
+  if (prev_buf == buf)
+    {
+      if (prev_pt == pt)
+       /* Point didn't move.  */
+       return 0;
+
+      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)
+         && start < prev_pt && end > prev_pt)
+       /* The last point was within the composition.  Return 1 iff
+            point moved out of the composition.  */
+       return (pt <= start || pt >= end);
+    }
+
+  /* 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)
+         && start < pt && end > pt);
+}
+
+
+/* Reconsider the setting of B->clip_changed which is displayed
+   in window W.  */
+
+static INLINE void
+reconsider_clip_changes (w, b)
+     struct window *w;
+     struct buffer *b;
+{
+  if (b->clip_changed
+          && !NILP (w->window_end_valid)
+          && w->current_matrix->buffer == b
+          && w->current_matrix->zv == BUF_ZV (b)
+          && w->current_matrix->begv == BUF_BEGV (b))
+    b->clip_changed = 0;
+
+  /* If display wasn't paused, and W is not a tool bar window, see if
+     point has been moved into or out of a composition.  In that case,
+     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->buffer) && !NILP (w->window_end_valid))
+    {
+      int pt;
+
+      if (w == XWINDOW (selected_window))
+       pt = BUF_PT (current_buffer);
+      else
+       pt = marker_position (w->pointm);
+
+      if ((w->current_matrix->buffer != XBUFFER (w->buffer)
           || pt != XINT (w->last_point))
          && check_point_in_composition (w->current_matrix->buffer,
                                         XINT (w->last_point),
           || pt != XINT (w->last_point))
          && check_point_in_composition (w->current_matrix->buffer,
                                         XINT (w->last_point),
@@ -10046,8 +9760,7 @@ redisplay_internal (preserve_echo_area)
 
   /* If specs for an arrow have changed, do thorough redisplay
      to ensure we remove any arrow that should no longer exist.  */
 
   /* If specs for an arrow have changed, do thorough redisplay
      to ensure we remove any arrow that should no longer exist.  */
-  if (! EQ (COERCE_MARKER (Voverlay_arrow_position), last_arrow_position)
-      || ! EQ (Voverlay_arrow_string, last_arrow_string))
+  if (overlay_arrows_changed_p ())
     consider_all_windows_p = windows_or_buffers_changed = 1;
 
   /* Normally the message* functions will have already displayed and
     consider_all_windows_p = windows_or_buffers_changed = 1;
 
   /* Normally the message* functions will have already displayed and
@@ -10507,11 +10220,7 @@ redisplay_internal (preserve_echo_area)
       CHARPOS (this_line_start_pos) = 0;
 
       /* Let the overlay arrow be updated the next time.  */
       CHARPOS (this_line_start_pos) = 0;
 
       /* Let the overlay arrow be updated the next time.  */
-      if (!NILP (last_arrow_position))
-       {
-         last_arrow_position = Qt;
-         last_arrow_string = Qt;
-       }
+      update_overlay_arrows (0);
 
       /* If we pause after scrolling, some rows in the current
         matrices of some windows are not valid.  */
 
       /* If we pause after scrolling, some rows in the current
         matrices of some windows are not valid.  */
@@ -10527,8 +10236,8 @@ redisplay_internal (preserve_echo_area)
             consider_all_windows_p is set.  */
          mark_window_display_accurate_1 (w, 1);
 
             consider_all_windows_p is set.  */
          mark_window_display_accurate_1 (w, 1);
 
-         last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
-         last_arrow_string = Voverlay_arrow_string;
+         /* Say overlay arrows are up to date.  */
+         update_overlay_arrows (1);
 
          if (FRAME_DISPLAY (sf)->frame_up_to_date_hook != 0)
            FRAME_DISPLAY (sf)->frame_up_to_date_hook (sf);
 
          if (FRAME_DISPLAY (sf)->frame_up_to_date_hook != 0)
            FRAME_DISPLAY (sf)->frame_up_to_date_hook (sf);
@@ -10724,16 +10433,14 @@ mark_window_display_accurate (window, accurate_p)
 
   if (accurate_p)
     {
 
   if (accurate_p)
     {
-      last_arrow_position = COERCE_MARKER (Voverlay_arrow_position);
-      last_arrow_string = Voverlay_arrow_string;
+      update_overlay_arrows (1);
     }
   else
     {
       /* Force a thorough redisplay the next time by setting
         last_arrow_position and last_arrow_string to t, which is
         unequal to any useful value of Voverlay_arrow_...  */
     }
   else
     {
       /* Force a thorough redisplay the next time by setting
         last_arrow_position and last_arrow_string to t, which is
         unequal to any useful value of Voverlay_arrow_...  */
-      last_arrow_position = Qt;
-      last_arrow_string = Qt;
+      update_overlay_arrows (-1);
     }
 }
 
     }
 }
 
@@ -11023,12 +10730,17 @@ run_window_scroll_functions (window, startp)
    A value of 1 means there is nothing to be done.
    (Either the line is fully visible, or it cannot be made so,
    or we cannot tell.)
    A value of 1 means there is nothing to be done.
    (Either the line is fully visible, or it cannot be made so,
    or we cannot tell.)
+
+   If FORCE_P is non-zero, return 0 even if partial visible cursor row
+   is higher than window.
+
    A value of 0 means the caller should do scrolling
    as if point had gone off the screen.  */
 
 static int
    A value of 0 means the caller should do scrolling
    as if point had gone off the screen.  */
 
 static int
-make_cursor_line_fully_visible (w)
+make_cursor_line_fully_visible (w, force_p)
      struct window *w;
      struct window *w;
+     int force_p;
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
@@ -11046,6 +10758,9 @@ make_cursor_line_fully_visible (w)
   if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
     return 1;
 
   if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
     return 1;
 
+  if (force_p)
+    return 0;
+
   /* If the row the cursor is in is taller than the window's height,
      it's not clear what to do, so do nothing.  */
   window_height = window_box_height (w);
   /* If the row the cursor is in is taller than the window's height,
      it's not clear what to do, so do nothing.  */
   window_height = window_box_height (w);
@@ -11142,7 +10857,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   int amount_to_scroll = 0;
   Lisp_Object aggressive;
   int height;
   int amount_to_scroll = 0;
   Lisp_Object aggressive;
   int height;
-  int end_scroll_margin;
+  int extra_scroll_margin_lines = last_line_misfit ? 1 : 0;
 
 #if GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
 
 #if GLYPH_DEBUG
   debug_method_add (w, "try_scrolling");
@@ -11160,6 +10875,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   else
     this_scroll_margin = 0;
 
   else
     this_scroll_margin = 0;
 
+  /* Force scroll_conservatively to have a reasonable value so it doesn't
+     cause an overflow while computing how much to scroll.  */
+  if (scroll_conservatively)
+    scroll_conservatively = min (scroll_conservatively,
+                                 MOST_POSITIVE_FIXNUM / FRAME_LINE_HEIGHT (f));
+
   /* Compute how much we should try to scroll maximally to bring point
      into view.  */
   if (scroll_step || scroll_conservatively || temp_scroll_step)
   /* Compute how much we should try to scroll maximally to bring point
      into view.  */
   if (scroll_step || scroll_conservatively || temp_scroll_step)
@@ -11185,11 +10906,13 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   CHARPOS (scroll_margin_pos) = XINT (window_end);
   BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
 
   CHARPOS (scroll_margin_pos) = XINT (window_end);
   BYTEPOS (scroll_margin_pos) = CHAR_TO_BYTE (CHARPOS (scroll_margin_pos));
 
-  end_scroll_margin = this_scroll_margin + !!last_line_misfit;
-  if (end_scroll_margin)
+  if (this_scroll_margin || extra_scroll_margin_lines)
     {
       start_display (&it, w, scroll_margin_pos);
     {
       start_display (&it, w, scroll_margin_pos);
-      move_it_vertically (&it, - end_scroll_margin);
+      if (this_scroll_margin)
+       move_it_vertically (&it, - this_scroll_margin);
+      if (extra_scroll_margin_lines)
+       move_it_by_lines (&it, - extra_scroll_margin_lines, 0);
       scroll_margin_pos = it.current.pos;
     }
 
       scroll_margin_pos = it.current.pos;
     }
 
@@ -11324,10 +11047,10 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
-      if (! make_cursor_line_fully_visible (w))
+      if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
        {
          clear_glyph_matrix (w->desired_matrix);
        {
          clear_glyph_matrix (w->desired_matrix);
-         last_line_misfit = 1;
+         ++extra_scroll_margin_lines;
          goto too_near_end;
        }
       rc = SCROLLING_SUCCESS;
          goto too_near_end;
        }
       rc = SCROLLING_SUCCESS;
@@ -11484,8 +11207,7 @@ try_cursor_movement (window, startp, scroll_step)
       && INTEGERP (w->window_end_vpos)
       && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
       && (FRAME_WINDOW_P (f)
       && INTEGERP (w->window_end_vpos)
       && XFASTINT (w->window_end_vpos) < w->current_matrix->nrows
       && (FRAME_WINDOW_P (f)
-         || !MARKERP (Voverlay_arrow_position)
-         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+         || !overlay_arrow_in_current_buffer_p ()))
     {
       int this_scroll_margin;
       struct glyph_row *row = NULL;
     {
       int this_scroll_margin;
       struct glyph_row *row = NULL;
@@ -11617,7 +11339,7 @@ try_cursor_movement (window, startp, scroll_step)
              else
                {
                  set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
              else
                {
                  set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
-                 if (!make_cursor_line_fully_visible (w))
+                 if (!make_cursor_line_fully_visible (w, 0))
                    rc = CURSOR_MOVEMENT_MUST_SCROLL;
                  else
                    rc = CURSOR_MOVEMENT_SUCCESS;
                    rc = CURSOR_MOVEMENT_MUST_SCROLL;
                  else
                    rc = CURSOR_MOVEMENT_SUCCESS;
@@ -11647,7 +11369,7 @@ set_vertical_scroll_bar (w)
      which reflect the whole buffer size, with special markers
      indicating narrowing, and scrollbars which reflect only the
      visible region.
      which reflect the whole buffer size, with special markers
      indicating narrowing, and scrollbars which reflect only the
      visible region.
-     
+
      Note that mini-buffers sometimes aren't displaying any text.  */
   if (!MINI_WINDOW_P (w)
       || (w == XWINDOW (minibuf_window)
      Note that mini-buffers sometimes aren't displaying any text.  */
   if (!MINI_WINDOW_P (w)
       || (w == XWINDOW (minibuf_window)
@@ -11659,7 +11381,7 @@ set_vertical_scroll_bar (w)
       /* I don't think this is guaranteed to be right.  For the
         moment, we'll pretend it is.  */
       end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
       /* I don't think this is guaranteed to be right.  For the
         moment, we'll pretend it is.  */
       end = BUF_Z (buf) - XFASTINT (w->window_end_pos) - BUF_BEGV (buf);
-      
+
       if (end < start)
        end = start;
       if (whole < (end - start))
       if (end < start)
        end = start;
       if (whole < (end - start))
@@ -11674,136 +11396,6 @@ set_vertical_scroll_bar (w)
       (w, end - start, whole, start);
 }
 
       (w, end - start, whole, start);
 }
 
-#ifdef HAVE_WINDOW_SYSTEM
-
-/* Recalculate the bitmaps to show in the fringes of window W.
-   If FORCE_P is 0, only mark rows with modified bitmaps for update in
-   redraw_fringe_bitmaps_p; else mark all rows for update.  */
-
-int
-update_window_fringes (w, force_p)
-     struct window *w;
-     int force_p;
-{
-  struct glyph_row *row, *cur = 0;
-  int yb = window_text_bottom_y (w);
-  int rn, nrows = w->current_matrix->nrows;
-  int y;
-  int redraw_p = 0;
-  Lisp_Object ind;
-
-  if (w->pseudo_window_p)
-    return 0;
-
-  if (!MINI_WINDOW_P (w)
-      && (ind = XBUFFER (w->buffer)->indicate_buffer_boundaries, !NILP (ind)))
-    {
-      int do_eob = 1, do_bob = 1;
-
-      for (y = 0, rn = 0;
-          y < yb && rn < nrows;
-          y += row->height, ++rn)
-       {
-         unsigned indicate_bob_p, indicate_top_line_p;
-         unsigned indicate_eob_p, indicate_bottom_line_p;
-         
-         row = w->desired_matrix->rows + rn;
-         if (!row->enabled_p)
-           row = w->current_matrix->rows + rn;
-
-         indicate_bob_p = row->indicate_bob_p;
-         indicate_top_line_p = row->indicate_top_line_p;
-         indicate_eob_p = row->indicate_eob_p;
-         indicate_bottom_line_p = row->indicate_bottom_line_p;
-         
-         row->indicate_bob_p = row->indicate_top_line_p = 0;
-         row->indicate_eob_p = row->indicate_bottom_line_p = 0;
-
-         if (MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer)))
-           row->indicate_bob_p = do_bob, do_bob = 0;
-         else if (EQ (ind, Qt)
-                  && (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0) == rn)
-           row->indicate_top_line_p = 1;
-
-         if (MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer)))
-           row->indicate_eob_p = do_eob, do_eob = 0;
-         else if (EQ (ind, Qt)
-                  && y + row->height >= yb)
-           row->indicate_bottom_line_p = 1;
-
-         if (indicate_bob_p != row->indicate_bob_p
-             || indicate_top_line_p != row->indicate_top_line_p
-             || indicate_eob_p != row->indicate_eob_p
-             || indicate_bottom_line_p != row->indicate_bottom_line_p)
-           row->redraw_fringe_bitmaps_p = 1;
-       }
-    }
-
-  for (y = 0, rn = 0;
-       y < yb && rn < nrows;
-       y += row->height, rn++)
-    {
-      enum fringe_bitmap_type left, right;
-
-      row = w->desired_matrix->rows + rn;
-      cur = w->current_matrix->rows + rn;
-      if (!row->enabled_p)
-       row = cur;
-
-      /* Decide which bitmap to draw in the left fringe.  */
-      if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
-       left = NO_FRINGE_BITMAP;
-      else if (row->overlay_arrow_p)
-       left = OVERLAY_ARROW_BITMAP;
-      else if (row->truncated_on_left_p)
-       left = LEFT_TRUNCATION_BITMAP;
-      else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
-       left = CONTINUATION_LINE_BITMAP;
-      else if (row->indicate_empty_line_p)
-       left = ZV_LINE_BITMAP;
-      else if (row->indicate_bob_p)
-       left = FIRST_LINE_BITMAP;
-      else
-       left = NO_FRINGE_BITMAP;
-
-      /* Decide which bitmap to draw in the right fringe.  */
-      if (WINDOW_RIGHT_FRINGE_WIDTH (w) == 0)
-       right = NO_FRINGE_BITMAP;
-      else if (row->truncated_on_right_p)
-       right = RIGHT_TRUNCATION_BITMAP;
-      else if (row->continued_p)
-       right = CONTINUED_LINE_BITMAP;
-      else if (row->indicate_eob_p)
-       right = LAST_LINE_BITMAP;
-      else if (row->indicate_top_line_p) 
-       right = UP_ARROW_BITMAP;
-      else if (row->indicate_bottom_line_p)
-       right = DOWN_ARROW_BITMAP;
-      else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
-       right = ZV_LINE_BITMAP;
-      else
-       right = NO_FRINGE_BITMAP;
-
-      if (force_p
-         || row->y != cur->y
-         || row->visible_height != cur->visible_height
-         || left != cur->left_fringe_bitmap
-         || right != cur->right_fringe_bitmap
-         || cur->redraw_fringe_bitmaps_p)
-       {
-         redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1;
-         cur->left_fringe_bitmap = left;
-         cur->right_fringe_bitmap = right;
-       }
-
-      row->left_fringe_bitmap = left;
-      row->right_fringe_bitmap = right;
-    }
-
-  return redraw_p;
-}
-
-#endif /* HAVE_WINDOW_SYSTEM */
 
 /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P non-zero means only
    selected_window is redisplayed.
 
 /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P non-zero means only
    selected_window is redisplayed.
@@ -12080,7 +11672,7 @@ redisplay_window (window, just_this_one_p)
          new_vpos = window_box_height (w) / 2;
        }
 
          new_vpos = window_box_height (w) / 2;
        }
 
-      if (!make_cursor_line_fully_visible (w))
+      if (!make_cursor_line_fully_visible (w, 0))
        {
          /* Point does appear, but on a line partly visible at end of window.
             Move it back to a fully-visible line.  */
        {
          /* Point does appear, but on a line partly visible at end of window.
             Move it back to a fully-visible line.  */
@@ -12217,7 +11809,7 @@ redisplay_window (window, just_this_one_p)
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
 
            /* Forget any recorded base line for line number display.  */
            w->base_line_number = Qnil;
 
-         if (!make_cursor_line_fully_visible (w))
+         if (!make_cursor_line_fully_visible (w, 1))
            {
              clear_glyph_matrix (w->desired_matrix);
              last_line_misfit = 1;
            {
              clear_glyph_matrix (w->desired_matrix);
              last_line_misfit = 1;
@@ -12377,7 +11969,7 @@ redisplay_window (window, just_this_one_p)
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
       set_cursor_from_row (w, row, w->current_matrix, 0, 0, 0, 0);
     }
 
-  if (!make_cursor_line_fully_visible (w))
+  if (!make_cursor_line_fully_visible (w, centering_position > 0))
     {
       /* If vscroll is enabled, disable it and try again.  */
       if (w->vscroll)
     {
       /* If vscroll is enabled, disable it and try again.  */
       if (w->vscroll)
@@ -12390,6 +11982,7 @@ redisplay_window (window, just_this_one_p)
       /* If centering point failed to make the whole line visible,
         put point at the top instead.  That has to make the whole line
         visible, if it can be done.  */
       /* If centering point failed to make the whole line visible,
         put point at the top instead.  That has to make the whole line
         visible, if it can be done.  */
+      clear_glyph_matrix (w->desired_matrix);
       centering_position = 0;
       goto point_at_top;
     }
       centering_position = 0;
       goto point_at_top;
     }
@@ -12494,6 +12087,7 @@ redisplay_window (window, just_this_one_p)
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (update_window_fringes (w, 0)
 
 #ifdef HAVE_WINDOW_SYSTEM
   if (update_window_fringes (w, 0)
+      && !just_this_one_p
       && (used_current_matrix_p || overlay_arrow_seen)
       && !w->pseudo_window_p)
     {
       && (used_current_matrix_p || overlay_arrow_seen)
       && !w->pseudo_window_p)
     {
@@ -13366,8 +12960,7 @@ try_window_id (w)
     GIVE_UP (10);
 
   /* Can use this if overlay arrow position and or string have changed.  */
     GIVE_UP (10);
 
   /* Can use this if overlay arrow position and or string have changed.  */
-  if (!EQ (last_arrow_position, COERCE_MARKER (Voverlay_arrow_position))
-      || !EQ (last_arrow_string, Voverlay_arrow_string))
+  if (overlay_arrows_changed_p ())
     GIVE_UP (12);
 
 
     GIVE_UP (12);
 
 
@@ -13760,36 +13353,36 @@ try_window_id (w)
            {
              /* Scroll last_unchanged_at_beg_row to the end of the
                 window down dvpos lines.  */
            {
              /* Scroll last_unchanged_at_beg_row to the end of the
                 window down dvpos lines.  */
-             set_terminal_window (end);
+             set_terminal_window (f, end);
 
              /* On dumb terminals delete dvpos lines at the end
                 before inserting dvpos empty lines.  */
              if (!FRAME_SCROLL_REGION_OK (f))
 
              /* On dumb terminals delete dvpos lines at the end
                 before inserting dvpos empty lines.  */
              if (!FRAME_SCROLL_REGION_OK (f))
-               ins_del_lines (end - dvpos, -dvpos);
+               ins_del_lines (f, end - dvpos, -dvpos);
 
              /* Insert dvpos empty lines in front of
                  last_unchanged_at_beg_row.  */
 
              /* Insert dvpos empty lines in front of
                  last_unchanged_at_beg_row.  */
-             ins_del_lines (from, dvpos);
+             ins_del_lines (f, from, dvpos);
            }
          else if (dvpos < 0)
            {
              /* Scroll up last_unchanged_at_beg_vpos to the end of
                 the window to last_unchanged_at_beg_vpos - |dvpos|.  */
            }
          else if (dvpos < 0)
            {
              /* Scroll up last_unchanged_at_beg_vpos to the end of
                 the window to last_unchanged_at_beg_vpos - |dvpos|.  */
-             set_terminal_window (end);
+             set_terminal_window (f, end);
 
              /* Delete dvpos lines in front of
                 last_unchanged_at_beg_vpos.  ins_del_lines will set
                 the cursor to the given vpos and emit |dvpos| delete
                 line sequences.  */
 
              /* Delete dvpos lines in front of
                 last_unchanged_at_beg_vpos.  ins_del_lines will set
                 the cursor to the given vpos and emit |dvpos| delete
                 line sequences.  */
-             ins_del_lines (from + dvpos, dvpos);
+             ins_del_lines (f, from + dvpos, dvpos);
 
              /* On a dumb terminal insert dvpos empty lines at the
                  end.  */
              if (!FRAME_SCROLL_REGION_OK (f))
 
              /* On a dumb terminal insert dvpos empty lines at the
                  end.  */
              if (!FRAME_SCROLL_REGION_OK (f))
-               ins_del_lines (end + dvpos, -dvpos);
+               ins_del_lines (f, end + dvpos, -dvpos);
            }
 
            }
 
-         set_terminal_window (0);
+         set_terminal_window (f, 0);
        }
 
       update_end (f);
        }
 
       update_end (f);
@@ -14304,14 +13897,15 @@ usage: (trace-to-stderr STRING &rest OBJECTS)  */)
    arrow.  Only used for non-window-redisplay windows.  */
 
 static struct glyph_row *
    arrow.  Only used for non-window-redisplay windows.  */
 
 static struct glyph_row *
-get_overlay_arrow_glyph_row (w)
+get_overlay_arrow_glyph_row (w, overlay_arrow_string)
      struct window *w;
      struct window *w;
+     Lisp_Object overlay_arrow_string;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   struct buffer *buffer = XBUFFER (w->buffer);
   struct buffer *old = current_buffer;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   struct buffer *buffer = XBUFFER (w->buffer);
   struct buffer *old = current_buffer;
-  const unsigned char *arrow_string = SDATA (Voverlay_arrow_string);
-  int arrow_len = SCHARS (Voverlay_arrow_string);
+  const unsigned char *arrow_string = SDATA (overlay_arrow_string);
+  int arrow_len = SCHARS (overlay_arrow_string);
   const unsigned char *arrow_end = arrow_string + arrow_len;
   const unsigned char *p;
   struct it it;
   const unsigned char *arrow_end = arrow_string + arrow_len;
   const unsigned char *p;
   struct it it;
@@ -14338,7 +13932,7 @@ get_overlay_arrow_glyph_row (w)
 
       /* Get its face.  */
       ilisp = make_number (p - arrow_string);
 
       /* Get its face.  */
       ilisp = make_number (p - arrow_string);
-      face = Fget_text_property (ilisp, Qface, Voverlay_arrow_string);
+      face = Fget_text_property (ilisp, Qface, overlay_arrow_string);
       it.face_id = compute_char_face (f, it.c, face);
 
       /* Compute its width, get its glyphs.  */
       it.face_id = compute_char_face (f, it.c, face);
 
       /* Compute its width, get its glyphs.  */
@@ -14777,6 +14371,8 @@ display_line (it)
      struct it *it;
 {
   struct glyph_row *row = it->glyph_row;
      struct it *it;
 {
   struct glyph_row *row = it->glyph_row;
+  int overlay_arrow_bitmap;
+  Lisp_Object overlay_arrow_string;
 
   /* We always start displaying at hpos zero even if hscrolled.  */
   xassert (it->hpos == 0 && it->current_x == 0);
 
   /* We always start displaying at hpos zero even if hscrolled.  */
   xassert (it->hpos == 0 && it->current_x == 0);
@@ -14835,6 +14431,11 @@ display_line (it)
             display the cursor there under X.  Set the charpos of the
             first glyph of blank lines not corresponding to any text
             to -1.  */
             display the cursor there under X.  Set the charpos of the
             first glyph of blank lines not corresponding to any text
             to -1.  */
+#ifdef HAVE_WINDOW_SYSTEM
+         if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+           row->exact_window_width_line_p = 1;
+         else
+#endif /* HAVE_WINDOW_SYSTEM */
          if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
              || row->used[TEXT_AREA] == 0)
            {
          if ((append_space (it, 1) && row->used[TEXT_AREA] == 1)
              || row->used[TEXT_AREA] == 0)
            {
@@ -14947,8 +14548,14 @@ display_line (it)
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                            {
-                             get_next_display_element (it);
-                             if (ITERATOR_AT_END_OF_LINE_P (it))
+                             if (!get_next_display_element (it))
+                               {
+                                 row->exact_window_width_line_p = 1;
+                                 it->continuation_lines_width = 0;
+                                 row->continued_p = 0;
+                                 row->ends_at_zv_p = 1;
+                               }
+                             else if (ITERATOR_AT_END_OF_LINE_P (it))
                                {
                                  row->continued_p = 0;
                                  row->exact_window_width_line_p = 1;
                                {
                                  row->continued_p = 0;
                                  row->exact_window_width_line_p = 1;
@@ -15053,7 +14660,7 @@ display_line (it)
                                  it->max_phys_ascent + it->max_phys_descent);
 
          /* End of this display line if row is continued.  */
                                  it->max_phys_ascent + it->max_phys_descent);
 
          /* End of this display line if row is continued.  */
-         if (row->continued_p)
+         if (row->continued_p || row->ends_at_zv_p)
            break;
        }
 
            break;
        }
 
@@ -15119,7 +14726,15 @@ display_line (it)
              /* Don't truncate if we can overflow newline into fringe.  */
              if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                {
              /* Don't truncate if we can overflow newline into fringe.  */
              if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
                {
-                 get_next_display_element (it);
+                 if (!get_next_display_element (it))
+                   {
+#ifdef HAVE_WINDOW_SYSTEM
+                     it->continuation_lines_width = 0;
+                     row->ends_at_zv_p = 1;
+                     row->exact_window_width_line_p = 1;
+                     break;
+#endif /* HAVE_WINDOW_SYSTEM */
+                   }
                  if (ITERATOR_AT_END_OF_LINE_P (it))
                    {
                      row->exact_window_width_line_p = 1;
                  if (ITERATOR_AT_END_OF_LINE_P (it))
                    {
                      row->exact_window_width_line_p = 1;
@@ -15153,17 +14768,16 @@ display_line (it)
      mark this glyph row as the one containing the overlay arrow.
      This is clearly a mess with variable size fonts.  It would be
      better to let it be displayed like cursors under X.  */
      mark this glyph row as the one containing the overlay arrow.
      This is clearly a mess with variable size fonts.  It would be
      better to let it be displayed like cursors under X.  */
-  if (MARKERP (Voverlay_arrow_position)
-      && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
-      && (MATRIX_ROW_START_CHARPOS (row)
-         == marker_position (Voverlay_arrow_position))
-      && STRINGP (Voverlay_arrow_string)
-      && ! overlay_arrow_seen)
+  if (! overlay_arrow_seen
+      && (overlay_arrow_string
+           = overlay_arrow_at_row (it->f, row, &overlay_arrow_bitmap),
+         !NILP (overlay_arrow_string)))
     {
       /* Overlay arrow in window redisplay is a fringe bitmap.  */
       if (!FRAME_WINDOW_P (it->f))
        {
     {
       /* Overlay arrow in window redisplay is a fringe bitmap.  */
       if (!FRAME_WINDOW_P (it->f))
        {
-         struct glyph_row *arrow_row = get_overlay_arrow_glyph_row (it->w);
+         struct glyph_row *arrow_row
+           = get_overlay_arrow_glyph_row (it->w, overlay_arrow_string);
          struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
          struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
          struct glyph *p = row->glyphs[TEXT_AREA];
          struct glyph *glyph = arrow_row->glyphs[TEXT_AREA];
          struct glyph *arrow_end = glyph + arrow_row->used[TEXT_AREA];
          struct glyph *p = row->glyphs[TEXT_AREA];
@@ -15187,6 +14801,7 @@ display_line (it)
        }
 
       overlay_arrow_seen = 1;
        }
 
       overlay_arrow_seen = 1;
+      it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
       row->overlay_arrow_p = 1;
     }
 
       row->overlay_arrow_p = 1;
     }
 
@@ -15196,6 +14811,17 @@ display_line (it)
   /* Remember the position at which this line ends.  */
   row->end = it->current;
 
   /* Remember the position at which this line ends.  */
   row->end = it->current;
 
+  /* Save fringe bitmaps in this row.  */
+  row->left_user_fringe_bitmap = it->left_user_fringe_bitmap;
+  row->left_user_fringe_face_id = it->left_user_fringe_face_id;
+  row->right_user_fringe_bitmap = it->right_user_fringe_bitmap;
+  row->right_user_fringe_face_id = it->right_user_fringe_face_id;
+
+  it->left_user_fringe_bitmap = 0;
+  it->left_user_fringe_face_id = 0;
+  it->right_user_fringe_bitmap = 0;
+  it->right_user_fringe_face_id = 0;
+
   /* Maybe set the cursor.  */
   if (it->w->cursor.vpos < 0
       && PT >= MATRIX_ROW_START_CHARPOS (row)
   /* Maybe set the cursor.  */
   if (it->w->cursor.vpos < 0
       && PT >= MATRIX_ROW_START_CHARPOS (row)
@@ -15459,6 +15085,8 @@ display_mode_line (w, face_id, format)
   init_iterator (&it, w, -1, -1, NULL, face_id);
   prepare_desired_row (it.glyph_row);
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
   prepare_desired_row (it.glyph_row);
 
+  it.glyph_row->mode_line_p = 1;
+
   if (! mode_line_inverse_video)
     /* Force the mode-line to be displayed in the default face.  */
     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
   if (! mode_line_inverse_video)
     /* Force the mode-line to be displayed in the default face.  */
     it.base_face_id = it.face_id = DEFAULT_FACE_ID;
@@ -15475,7 +15103,6 @@ display_mode_line (w, face_id, format)
 
   compute_line_metrics (&it);
   it.glyph_row->full_width_p = 1;
 
   compute_line_metrics (&it);
   it.glyph_row->full_width_p = 1;
-  it.glyph_row->mode_line_p = 1;
   it.glyph_row->continued_p = 0;
   it.glyph_row->truncated_on_left_p = 0;
   it.glyph_row->truncated_on_right_p = 0;
   it.glyph_row->continued_p = 0;
   it.glyph_row->truncated_on_left_p = 0;
   it.glyph_row->truncated_on_right_p = 0;
@@ -16675,14 +16302,6 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
       return "T";
 #endif
 
       return "T";
 #endif
 
-    case 'T':
-      /* %T is the frame name on a termcap frame, the empty string otherwise. */
-      if (! FRAME_TERMCAP_P (f))
-        return "";
-      if (!NILP (f->title))
-       return (char *) SDATA (f->title);
-      return (char *) SDATA (f->name);
-
     case 'z':
       /* coding-system (not including end-of-line format) */
     case 'Z':
     case 'z':
       /* coding-system (not including end-of-line format) */
     case 'Z':
@@ -17097,56 +16716,302 @@ invisible_p (propval, list)
   return 0;
 }
 
   return 0;
 }
 
-\f
-/***********************************************************************
-                            Glyph Display
- ***********************************************************************/
+/* Calculate a width or height in pixels from a specification using
+   the following elements:
 
 
-#ifdef HAVE_WINDOW_SYSTEM
+   SPEC ::=
+     NUM      - a (fractional) multiple of the default font width/height
+     (NUM)    - specifies exactly NUM pixels
+     UNIT     - a fixed number of pixels, see below.
+     ELEMENT  - size of a display element in pixels, see below.
+     (NUM . SPEC) - equals NUM * SPEC
+     (+ SPEC SPEC ...)  - add pixel values
+     (- SPEC SPEC ...)  - subtract pixel values
+     (- SPEC)           - negate pixel value
 
 
-#if GLYPH_DEBUG
+   NUM ::=
+     INT or FLOAT   - a number constant
+     SYMBOL         - use symbol's (buffer local) variable binding.
 
 
-void
-dump_glyph_string (s)
-     struct glyph_string *s;
-{
-  fprintf (stderr, "glyph string\n");
-  fprintf (stderr, "  x, y, w, h = %d, %d, %d, %d\n",
-          s->x, s->y, s->width, s->height);
-  fprintf (stderr, "  ybase = %d\n", s->ybase);
-  fprintf (stderr, "  hl = %d\n", s->hl);
-  fprintf (stderr, "  left overhang = %d, right = %d\n",
-          s->left_overhang, s->right_overhang);
-  fprintf (stderr, "  nchars = %d\n", s->nchars);
-  fprintf (stderr, "  extends to end of line = %d\n",
-          s->extends_to_end_of_line_p);
-  fprintf (stderr, "  font height = %d\n", FONT_HEIGHT (s->font));
-  fprintf (stderr, "  bg width = %d\n", s->background_width);
-}
+   UNIT ::=
+     in       - pixels per inch  *)
+     mm       - pixels per 1/1000 meter  *)
+     cm       - pixels per 1/100 meter   *)
+     width    - width of current font in pixels.
+     height   - height of current font in pixels.
 
 
-#endif /* GLYPH_DEBUG */
+     *) using the ratio(s) defined in display-pixels-per-inch.
 
 
-/* Initialize glyph string S.  CHAR2B is a suitably allocated vector
-   of XChar2b structures for S; it can't be allocated in
-   init_glyph_string because it must be allocated via `alloca'.  W
-   is the window on which S is drawn.  ROW and AREA are the glyph row
-   and area within the row from which S is constructed.  START is the
-   index of the first glyph structure covered by S.  HL is a
-   face-override for drawing S.  */
+   ELEMENT ::=
 
 
-#ifdef HAVE_NTGUI
-#define OPTIONAL_HDC(hdc)  hdc,
-#define DECLARE_HDC(hdc)   HDC hdc;
-#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
-#define RELEASE_HDC(hdc, f)  release_frame_dc ((f), (hdc))
-#endif
+     left-fringe          - left fringe width in pixels
+     right-fringe         - right fringe width in pixels
 
 
-#ifndef OPTIONAL_HDC
-#define OPTIONAL_HDC(hdc)
-#define DECLARE_HDC(hdc)
-#define ALLOCATE_HDC(hdc, f)
-#define RELEASE_HDC(hdc, f)
-#endif
+     left-margin          - left margin width in pixels
+     right-margin         - right margin width in pixels
+
+     scroll-bar           - scroll-bar area width in pixels
+
+   Examples:
+
+   Pixels corresponding to 5 inches:
+     (5 . in)
+
+   Total width of non-text areas on left side of window (if scroll-bar is on left):
+     '(space :width (+ left-fringe left-margin scroll-bar))
+
+   Align to first text column (in header line):
+     '(space :align-to 0)
+
+   Align to middle of text area minus half the width of variable `my-image'
+   containing a loaded image:
+     '(space :align-to (0.5 . (- text my-image)))
+
+   Width of left margin minus width of 1 character in the default font:
+     '(space :width (- left-margin 1))
+
+   Width of left margin minus width of 2 characters in the current font:
+     '(space :width (- left-margin (2 . width)))
+
+   Center 1 character over left-margin (in header line):
+     '(space :align-to (+ left-margin (0.5 . left-margin) -0.5))
+
+   Different ways to express width of left fringe plus left margin minus one pixel:
+     '(space :width (- (+ left-fringe left-margin) (1)))
+     '(space :width (+ left-fringe left-margin (- (1))))
+     '(space :width (+ left-fringe left-margin (-1)))
+
+*/
+
+#define NUMVAL(X)                              \
+     ((INTEGERP (X) || FLOATP (X))             \
+      ? XFLOATINT (X)                          \
+      : - 1)
+
+int
+calc_pixel_width_or_height (res, it, prop, font, width_p, align_to)
+     double *res;
+     struct it *it;
+     Lisp_Object prop;
+     void *font;
+     int width_p, *align_to;
+{
+  double pixels;
+
+#define OK_PIXELS(val) ((*res = (double)(val)), 1)
+#define OK_ALIGN_TO(val) ((*align_to = (int)(val)), 1)
+
+  if (NILP (prop))
+    return OK_PIXELS (0);
+
+  if (SYMBOLP (prop))
+    {
+      if (SCHARS (SYMBOL_NAME (prop)) == 2)
+       {
+         char *unit =  SDATA (SYMBOL_NAME (prop));
+
+         if (unit[0] == 'i' && unit[1] == 'n')
+           pixels = 1.0;
+         else if (unit[0] == 'm' && unit[1] == 'm')
+           pixels = 25.4;
+         else if (unit[0] == 'c' && unit[1] == 'm')
+           pixels = 2.54;
+         else
+           pixels = 0;
+         if (pixels > 0)
+           {
+             double ppi;
+             if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
+                 || (CONSP (Vdisplay_pixels_per_inch)
+                     && (ppi = (width_p
+                                ? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
+                                : NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
+                         ppi > 0)))
+               return OK_PIXELS (ppi / pixels);
+
+             return 0;
+           }
+       }
+
+#ifdef HAVE_WINDOW_SYSTEM
+      if (EQ (prop, Qheight))
+       return OK_PIXELS (font ? FONT_HEIGHT ((XFontStruct *)font) : FRAME_LINE_HEIGHT (it->f));
+      if (EQ (prop, Qwidth))
+       return OK_PIXELS (font ? FONT_WIDTH ((XFontStruct *)font) : FRAME_COLUMN_WIDTH (it->f));
+#else
+      if (EQ (prop, Qheight) || EQ (prop, Qwidth))
+       return OK_PIXELS (1);
+#endif
+
+      if (EQ (prop, Qtext))
+         return OK_PIXELS (width_p
+                           ? window_box_width (it->w, TEXT_AREA)
+                           : WINDOW_BOX_HEIGHT_NO_MODE_LINE (it->w));
+
+      if (align_to && *align_to < 0)
+       {
+         *res = 0;
+         if (EQ (prop, Qleft))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qright))
+           return OK_ALIGN_TO (window_box_right_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qcenter))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, TEXT_AREA)
+                               + window_box_width (it->w, TEXT_AREA) / 2);
+         if (EQ (prop, Qleft_fringe))
+           return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                               ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (it->w)
+                               : window_box_right_offset (it->w, LEFT_MARGIN_AREA));
+         if (EQ (prop, Qright_fringe))
+           return OK_ALIGN_TO (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                               ? window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+                               : window_box_right_offset (it->w, TEXT_AREA));
+         if (EQ (prop, Qleft_margin))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, LEFT_MARGIN_AREA));
+         if (EQ (prop, Qright_margin))
+           return OK_ALIGN_TO (window_box_left_offset (it->w, RIGHT_MARGIN_AREA));
+         if (EQ (prop, Qscroll_bar))
+           return OK_ALIGN_TO (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
+                               ? 0
+                               : (window_box_right_offset (it->w, RIGHT_MARGIN_AREA)
+                                  + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
+                                     ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
+                                     : 0)));
+       }
+      else
+       {
+         if (EQ (prop, Qleft_fringe))
+           return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
+         if (EQ (prop, Qright_fringe))
+           return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
+         if (EQ (prop, Qleft_margin))
+           return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
+         if (EQ (prop, Qright_margin))
+           return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
+         if (EQ (prop, Qscroll_bar))
+           return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
+       }
+
+      prop = Fbuffer_local_value (prop, it->w->buffer);
+    }
+
+  if (INTEGERP (prop) || FLOATP (prop))
+    {
+      int base_unit = (width_p
+                      ? FRAME_COLUMN_WIDTH (it->f)
+                      : FRAME_LINE_HEIGHT (it->f));
+      return OK_PIXELS (XFLOATINT (prop) * base_unit);
+    }
+
+  if (CONSP (prop))
+    {
+      Lisp_Object car = XCAR (prop);
+      Lisp_Object cdr = XCDR (prop);
+
+      if (SYMBOLP (car))
+       {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (valid_image_p (prop))
+           {
+             int id = lookup_image (it->f, prop);
+             struct image *img = IMAGE_FROM_ID (it->f, id);
+
+             return OK_PIXELS (width_p ? img->width : img->height);
+           }
+#endif
+         if (EQ (car, Qplus) || EQ (car, Qminus))
+           {
+             int first = 1;
+             double px;
+
+             pixels = 0;
+             while (CONSP (cdr))
+               {
+                 if (!calc_pixel_width_or_height (&px, it, XCAR (cdr),
+                                                  font, width_p, align_to))
+                   return 0;
+                 if (first)
+                   pixels = (EQ (car, Qplus) ? px : -px), first = 0;
+                 else
+                   pixels += px;
+                 cdr = XCDR (cdr);
+               }
+             if (EQ (car, Qminus))
+               pixels = -pixels;
+             return OK_PIXELS (pixels);
+           }
+
+         car = Fbuffer_local_value (car, it->w->buffer);
+       }
+
+      if (INTEGERP (car) || FLOATP (car))
+       {
+         double fact;
+         pixels = XFLOATINT (car);
+         if (NILP (cdr))
+           return OK_PIXELS (pixels);
+         if (calc_pixel_width_or_height (&fact, it, cdr,
+                                         font, width_p, align_to))
+           return OK_PIXELS (pixels * fact);
+         return 0;
+       }
+
+      return 0;
+    }
+
+  return 0;
+}
+
+\f
+/***********************************************************************
+                            Glyph Display
+ ***********************************************************************/
+
+#ifdef HAVE_WINDOW_SYSTEM
+
+#if GLYPH_DEBUG
+
+void
+dump_glyph_string (s)
+     struct glyph_string *s;
+{
+  fprintf (stderr, "glyph string\n");
+  fprintf (stderr, "  x, y, w, h = %d, %d, %d, %d\n",
+          s->x, s->y, s->width, s->height);
+  fprintf (stderr, "  ybase = %d\n", s->ybase);
+  fprintf (stderr, "  hl = %d\n", s->hl);
+  fprintf (stderr, "  left overhang = %d, right = %d\n",
+          s->left_overhang, s->right_overhang);
+  fprintf (stderr, "  nchars = %d\n", s->nchars);
+  fprintf (stderr, "  extends to end of line = %d\n",
+          s->extends_to_end_of_line_p);
+  fprintf (stderr, "  font height = %d\n", FONT_HEIGHT (s->font));
+  fprintf (stderr, "  bg width = %d\n", s->background_width);
+}
+
+#endif /* GLYPH_DEBUG */
+
+/* Initialize glyph string S.  CHAR2B is a suitably allocated vector
+   of XChar2b structures for S; it can't be allocated in
+   init_glyph_string because it must be allocated via `alloca'.  W
+   is the window on which S is drawn.  ROW and AREA are the glyph row
+   and area within the row from which S is constructed.  START is the
+   index of the first glyph structure covered by S.  HL is a
+   face-override for drawing S.  */
+
+#ifdef HAVE_NTGUI
+#define OPTIONAL_HDC(hdc)  hdc,
+#define DECLARE_HDC(hdc)   HDC hdc;
+#define ALLOCATE_HDC(hdc, f) hdc = get_frame_dc ((f))
+#define RELEASE_HDC(hdc, f)  release_frame_dc ((f), (hdc))
+#endif
+
+#ifndef OPTIONAL_HDC
+#define OPTIONAL_HDC(hdc)
+#define DECLARE_HDC(hdc)
+#define ALLOCATE_HDC(hdc, f)
+#define RELEASE_HDC(hdc, f)
+#endif
 
 static void
 init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
 
 static void
 init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
@@ -18258,17 +18123,34 @@ produce_image_glyph (it)
   xassert (it->what == IT_IMAGE);
 
   face = FACE_FROM_ID (it->f, it->face_id);
   xassert (it->what == IT_IMAGE);
 
   face = FACE_FROM_ID (it->f, it->face_id);
+  xassert (face);
+  /* Make sure X resources of the face is loaded.  */
+  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+  if (it->image_id < 0)
+    {
+      /* Fringe bitmap.  */
+      it->ascent = it->phys_ascent = 0;
+      it->descent = it->phys_descent = 0;
+      it->pixel_width = 0;
+      it->nglyphs = 0;
+      return;
+    }
+
   img = IMAGE_FROM_ID (it->f, it->image_id);
   xassert (img);
   img = IMAGE_FROM_ID (it->f, it->image_id);
   xassert (img);
-
-  /* Make sure X resources of the face and image are loaded.  */
-  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+  /* Make sure X resources of the image is loaded.  */
   prepare_image_for_display (it->f, img);
 
   it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face);
   it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
   it->pixel_width = img->width + 2 * img->hmargin;
 
   prepare_image_for_display (it->f, img);
 
   it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face);
   it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
   it->pixel_width = img->width + 2 * img->hmargin;
 
+  /* It's quite possible for images to have an ascent greater than
+     their height, so don't get confused in that case.  */
+  if (it->descent < 0)
+    it->descent = 0;
+
   /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent.  */
   face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
   if (face_ascent > it->ascent)
   /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent.  */
   face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
   if (face_ascent > it->ascent)
@@ -18363,209 +18245,6 @@ append_stretch_glyph (it, object, width, height, ascent)
 }
 
 
 }
 
 
-/* Calculate a width or height in pixels from a specification using
-   the following elements:
-
-   SPEC ::= 
-     NUM      - a (fractional) multiple of the default font width/height
-     (NUM)    - specifies exactly NUM pixels
-     UNIT     - a fixed number of pixels, see below.
-     ELEMENT  - size of a display element in pixels, see below.
-     (NUM . SPEC) - equals NUM * SPEC
-     (+ SPEC SPEC ...)  - add pixel values
-     (- SPEC SPEC ...)  - subtract pixel values
-     (- SPEC)           - negate pixel value
-
-   NUM ::= 
-     INT or FLOAT   - a number constant
-     SYMBOL         - use symbol's (buffer local) variable binding.
-
-   UNIT ::=
-     in       - pixels per inch  *)
-     mm       - pixels per 1/1000 meter  *)
-     cm       - pixels per 1/100 meter   *)
-     width    - width of current font in pixels.
-     height   - height of current font in pixels.
-
-     *) using the ratio(s) defined in display-pixels-per-inch.
-
-   ELEMENT ::=
-
-     left-fringe         - left fringe width in pixels
-     (left-fringe . nil) - left fringe width if inside margins, else 0
-     (left-fringe . t)   - left fringe width if outside margins, else 0
-
-     right-fringe         - right fringe width in pixels
-     (right-fringe . nil) - right fringe width if inside margins, else 0
-     (right-fringe . t)   - right fringe width if outside margins, else 0
-
-     left-margin          - left margin width in pixels
-     right-margin         - right margin width in pixels
-
-     scroll-bar           - scroll-bar area width in pixels
-     (scroll-bar . left)  - scroll-bar width if on left, else 0
-     (scroll-bar . right) - scroll-bar width if on right, else 0
-
-   Examples:
-
-   Pixels corresponding to 5 inches:
-     (5 . in)     
-               
-   Total width of non-text areas on left side of window:
-     (+ left-fringe left-margin (scroll-bar . left))
-
-   Total width of fringes if inside display margins:
-     (+ (left-fringe) (right-fringe))
-
-   Width of left margin minus width of 1 character in the default font:
-     (- left-margin 1)
-
-   Width of left margin minus width of 2 characters in the current font:
-     (- left-margin (2 . width))
-
-   Width of left fringe plus left margin minus one pixel:
-     (- (+ left-fringe left-margin) (1))
-     (+ left-fringe left-margin (- (1)))
-     (+ left-fringe left-margin (-1))
-
-*/
-
-#define NUMVAL(X)                              \
-     ((INTEGERP (X) || FLOATP (X))             \
-      ? XFLOATINT (X)                          \
-      : - 1)
-
-static int
-calc_pixel_width_or_height (res, it, prop, font, width_p)
-     double *res;
-     struct it *it;
-     Lisp_Object prop;
-     XFontStruct *font;
-     int width_p;
-{
-  double pixels;
-
-#define OK_PIXELS(val) ((*res = (val)), 1)
-
-  if (SYMBOLP (prop))
-    {
-      if (SCHARS (SYMBOL_NAME (prop)) == 2)
-       {
-         char *unit =  SDATA (SYMBOL_NAME (prop));
-
-         if (unit[0] == 'i' && unit[1] == 'n')
-           pixels = 1.0;
-         else if (unit[0] == 'm' && unit[1] == 'm')
-           pixels = 25.4;
-         else if (unit[0] == 'c' && unit[1] == 'm')
-           pixels = 2.54;
-         else
-           pixels = 0;
-         if (pixels > 0)
-           {
-             double ppi;
-             if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
-                 || (CONSP (Vdisplay_pixels_per_inch)
-                     && (ppi = (width_p
-                                ? NUMVAL (XCAR (Vdisplay_pixels_per_inch))
-                                : NUMVAL (XCDR (Vdisplay_pixels_per_inch))),
-                         ppi > 0)))
-               return OK_PIXELS (ppi / pixels);
-
-             return 0;
-           }
-       }
-
-      if (EQ (prop, Qheight))
-       return OK_PIXELS (font ? FONT_HEIGHT (font) : FRAME_LINE_HEIGHT (it->f));
-      if (EQ (prop, Qwidth))
-       return OK_PIXELS (font ? FONT_WIDTH (font) : FRAME_COLUMN_WIDTH (it->f));
-      if (EQ (prop, Qleft_fringe))
-       return OK_PIXELS (WINDOW_LEFT_FRINGE_WIDTH (it->w));
-      if (EQ (prop, Qright_fringe))
-       return OK_PIXELS (WINDOW_RIGHT_FRINGE_WIDTH (it->w));
-      if (EQ (prop, Qleft_margin))
-       return OK_PIXELS (WINDOW_LEFT_MARGIN_WIDTH (it->w));
-      if (EQ (prop, Qright_margin))
-       return OK_PIXELS (WINDOW_RIGHT_MARGIN_WIDTH (it->w));
-      if (EQ (prop, Qscroll_bar))
-       return OK_PIXELS (WINDOW_SCROLL_BAR_AREA_WIDTH (it->w));
-
-      prop = Fbuffer_local_value (prop, it->w->buffer);
-    }
-
-  if (INTEGERP (prop) || FLOATP (prop))
-    {
-      int base_unit = (width_p
-                      ? FRAME_COLUMN_WIDTH (it->f)
-                      : FRAME_LINE_HEIGHT (it->f));
-      return OK_PIXELS (XFLOATINT (prop) * base_unit);
-    }
-
-  if (CONSP (prop))
-    {
-      Lisp_Object car = XCAR (prop);
-      Lisp_Object cdr = XCDR (prop);
-
-      if (SYMBOLP (car))
-       {
-         if (EQ (car, Qplus) || EQ (car, Qminus))
-           {
-             int first = 1;
-             double px;
-
-             pixels = 0;
-             while (CONSP (cdr))
-               {
-                 if (!calc_pixel_width_or_height (&px, it, XCAR (cdr), font, width_p))
-                   return 0;
-                 if (first)
-                   pixels = (EQ (car, Qplus) ? px : -px), first = 0;
-                 else
-                   pixels += px;
-                 cdr = XCDR (cdr);
-               }
-             if (EQ (car, Qminus))
-               pixels = -pixels;
-             return OK_PIXELS (pixels);
-           }
-
-         if (EQ (car, Qleft_fringe))
-           return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
-                              == !NILP (cdr))
-                             ? WINDOW_LEFT_FRINGE_WIDTH (it->w)
-                             : 0);
-         if (EQ (car, Qright_fringe))
-           return OK_PIXELS ((WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (it->w)
-                              == !NILP (cdr))
-                             ? WINDOW_RIGHT_FRINGE_WIDTH (it->w)
-                             : 0);
-         if (EQ (car, Qscroll_bar))
-           return OK_PIXELS ((WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (it->w)
-                               == EQ (cdr, Qleft))
-                              ? WINDOW_SCROLL_BAR_AREA_WIDTH (it->w)
-                              : 0);
-
-         car = Fbuffer_local_value (car, it->w->buffer);
-       }
-
-      if (INTEGERP (car) || FLOATP (car))
-       {
-         double fact;
-         pixels = XFLOATINT (car);
-         if (NILP (cdr))
-           return OK_PIXELS (pixels);
-         if (calc_pixel_width_or_height (&fact, it, cdr, font, width_p))
-           return OK_PIXELS (pixels * fact);
-         return 0;
-       }
-
-      return 0;
-    }
-
-  return 0;
-}
-
 /* Produce a stretch glyph for iterator IT.  IT->object is the value
    of the glyph property displayed.  The value must be a list
    `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
 /* Produce a stretch glyph for iterator IT.  IT->object is the value
    of the glyph property displayed.  The value must be a list
    `(space KEYWORD VALUE ...)' with the following KEYWORD/VALUE pairs
@@ -18603,7 +18282,7 @@ produce_stretch_glyph (it)
 {
   /* (space :width WIDTH :height HEIGHT ...)  */
   Lisp_Object prop, plist;
 {
   /* (space :width WIDTH :height HEIGHT ...)  */
   Lisp_Object prop, plist;
-  int width = 0, height = 0;
+  int width = 0, height = 0, align_to = -1;
   int zero_width_ok_p = 0, zero_height_ok_p = 0;
   int ascent = 0;
   double tem;
   int zero_width_ok_p = 0, zero_height_ok_p = 0;
   int ascent = 0;
   double tem;
@@ -18618,7 +18297,7 @@ produce_stretch_glyph (it)
 
   /* Compute the width of the stretch.  */
   if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
 
   /* Compute the width of the stretch.  */
   if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
-      && calc_pixel_width_or_height (&tem, it, prop, font, 1))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
     {
       /* Absolute width `:width WIDTH' specified and valid.  */
       zero_width_ok_p = 1;
     {
       /* Absolute width `:width WIDTH' specified and valid.  */
       zero_width_ok_p = 1;
@@ -18649,9 +18328,15 @@ produce_stretch_glyph (it)
       width = NUMVAL (prop) * it2.pixel_width;
     }
   else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
       width = NUMVAL (prop) * it2.pixel_width;
     }
   else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
-          && calc_pixel_width_or_height (&tem, it, prop, font, 1))
-    {
-      width = max (0, (int)tem - it->current_x);
+          && calc_pixel_width_or_height (&tem, it, prop, font, 1, &align_to))
+    {
+      if (it->glyph_row == NULL || !it->glyph_row->mode_line_p)
+       align_to = (align_to < 0
+                   ? 0
+                   : align_to - window_box_left_offset (it->w, TEXT_AREA));
+      else if (align_to < 0)
+       align_to = window_box_left_offset (it->w, TEXT_AREA);
+      width = max (0, (int)tem + align_to - it->current_x);
       zero_width_ok_p = 1;
     }
   else
       zero_width_ok_p = 1;
     }
   else
@@ -18663,7 +18348,7 @@ produce_stretch_glyph (it)
 
   /* Compute height.  */
   if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
 
   /* Compute height.  */
   if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
-      && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
     {
       height = (int)tem;
       zero_height_ok_p = 1;
     {
       height = (int)tem;
       zero_height_ok_p = 1;
@@ -18684,7 +18369,7 @@ produce_stretch_glyph (it)
       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
     ascent = height * NUMVAL (prop) / 100.0;
   else if (!NILP (prop)
       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
     ascent = height * NUMVAL (prop) / 100.0;
   else if (!NILP (prop)
-          && calc_pixel_width_or_height (&tem, it, prop, font, 0))
+          && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
     ascent = min (max (0, (int)tem), height);
   else
     ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
     ascent = min (max (0, (int)tem), height);
   else
     ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
@@ -19615,7 +19300,7 @@ get_window_cursor_type (w, glyph, width, active_cursor)
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
-      if (glyph->type == IMAGE_GLYPH) {
+      if (glyph != NULL && glyph->type == IMAGE_GLYPH) {
        if (cursor_type == FILLED_BOX_CURSOR)
          cursor_type = HOLLOW_BOX_CURSOR;
       }
        if (cursor_type == FILLED_BOX_CURSOR)
          cursor_type = HOLLOW_BOX_CURSOR;
       }
@@ -19932,7 +19617,6 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
   int new_cursor_type;
   int new_cursor_width;
   int active_cursor;
   int new_cursor_type;
   int new_cursor_width;
   int active_cursor;
-  struct glyph_matrix *current_glyphs;
   struct glyph_row *glyph_row;
   struct glyph *glyph;
 
   struct glyph_row *glyph_row;
   struct glyph *glyph;
 
@@ -19950,10 +19634,7 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
   if (!on && !w->phys_cursor_on_p)
     return;
 
   if (!on && !w->phys_cursor_on_p)
     return;
 
-  current_glyphs = w->current_matrix;
-  glyph_row = MATRIX_ROW (current_glyphs, vpos);
-  glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
-
+  glyph_row = MATRIX_ROW (w->current_matrix, vpos);
   /* If cursor row is not enabled, we don't really know where to
      display the cursor.  */
   if (!glyph_row->enabled_p)
   /* If cursor row is not enabled, we don't really know where to
      display the cursor.  */
   if (!glyph_row->enabled_p)
@@ -19962,6 +19643,11 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
       return;
     }
 
       return;
     }
 
+  glyph = NULL;
+  if (!glyph_row->exact_window_width_line_p
+      || hpos < glyph_row->used[TEXT_AREA])
+    glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+
   xassert (interrupt_input_blocked);
 
   /* Set new_cursor_type to the cursor we want to be displayed.  */
   xassert (interrupt_input_blocked);
 
   /* Set new_cursor_type to the cursor we want to be displayed.  */
@@ -20163,7 +19849,7 @@ clear_mouse_face (dpyinfo)
 {
   int cleared = 0;
 
 {
   int cleared = 0;
 
-  if (!NILP (dpyinfo->mouse_face_window))
+  if (!dpyinfo->mouse_face_hidden && !NILP (dpyinfo->mouse_face_window))
     {
       show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
       cleared = 1;
     {
       show_mouse_face (dpyinfo, DRAW_NORMAL_TEXT);
       cleared = 1;
@@ -20240,7 +19926,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
       if (charpos < MATRIX_ROW_START_CHARPOS (first))
        {
          *x = *y = *hpos = *vpos = 0;
       if (charpos < MATRIX_ROW_START_CHARPOS (first))
        {
          *x = *y = *hpos = *vpos = 0;
-         return 0;
+         return 1;
        }
       else
        {
        }
       else
        {
@@ -20280,7 +19966,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
     }
 
   *hpos = glyph - row->glyphs[TEXT_AREA];
     }
 
   *hpos = glyph - row->glyphs[TEXT_AREA];
-  return past_end;
+  return !past_end;
 }
 
 #else /* not 1 */
 }
 
 #else /* not 1 */
@@ -20528,7 +20214,7 @@ on_hot_spot_p (hot_spot, x, y)
          int x0, y0;
 
          /* Need an even number of coordinates, and at least 3 edges.  */
          int x0, y0;
 
          /* Need an even number of coordinates, and at least 3 edges.  */
-         if (n < 6 || n & 1) 
+         if (n < 6 || n & 1)
            return 0;
 
          /* Count edge segments intersecting line from (X,Y) to (X,infinity).
            return 0;
 
          /* Count edge segments intersecting line from (X,Y) to (X,infinity).
@@ -20563,8 +20249,7 @@ on_hot_spot_p (hot_spot, x, y)
          return inside;
        }
     }
          return inside;
        }
     }
-  else
-    return 0;
+  return 0;
 }
 
 Lisp_Object
 }
 
 Lisp_Object
@@ -20579,13 +20264,13 @@ find_hot_spot (map, x, y)
        return XCAR (map);
       map = XCDR (map);
     }
        return XCAR (map);
       map = XCDR (map);
     }
-  
+
   return Qnil;
 }
 
 DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map,
        3, 3, 0,
   return Qnil;
 }
 
 DEFUN ("lookup-image-map", Flookup_image_map, Slookup_image_map,
        3, 3, 0,
-       doc: /* Lookup in image map MAP coordinates X and Y.  
+       doc: /* Lookup in image map MAP coordinates X and Y.
 An image map is an alist where each element has the format (AREA ID PLIST).
 An AREA is specified as either a rectangle, a circle, or a polygon:
 A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the
 An image map is an alist where each element has the format (AREA ID PLIST).
 An AREA is specified as either a rectangle, a circle, or a polygon:
 A rectangle is a cons (rect . ((x0 . y0) . (x1 . y1))) specifying the
@@ -20599,14 +20284,11 @@ Returns the alist element for the first matching AREA in MAP.  */)
      Lisp_Object map;
      Lisp_Object x, y;
 {
      Lisp_Object map;
      Lisp_Object x, y;
 {
-  int ix, iy;
   if (NILP (map))
     return Qnil;
 
   if (NILP (map))
     return Qnil;
 
-  if (!INTEGERP (x))
-    wrong_type_argument (Qintegerp, x);
-  if (!INTEGERP (y))
-    wrong_type_argument (Qintegerp, y);
+  CHECK_NUMBER (x);
+  CHECK_NUMBER (y);
 
   return find_hot_spot (map, XINT (x), XINT (y));
 }
 
   return find_hot_spot (map, XINT (x), XINT (y));
 }
@@ -20667,7 +20349,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
   Lisp_Object pointer = Qnil;
   int charpos, dx, dy, width, height;
   Lisp_Object string, object = Qnil;
   Lisp_Object pointer = Qnil;
   int charpos, dx, dy, width, height;
   Lisp_Object string, object = Qnil;
-  Lisp_Object pos, help, image;
+  Lisp_Object pos, help;
 
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
     string = mode_line_string (w, area, &x, &y, &charpos,
 
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
     string = mode_line_string (w, area, &x, &y, &charpos,
@@ -20735,7 +20417,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
        pointer = Fget_text_property (pos, Qpointer, string);
 
      /* Change the mouse pointer according to what is under X/Y.  */
        pointer = Fget_text_property (pos, Qpointer, string);
 
      /* Change the mouse pointer according to what is under X/Y.  */
-      if (NILP (pointer) && area == ON_MODE_LINE)
+      if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
        {
          Lisp_Object map;
          map = Fget_text_property (pos, Qlocal_map, string);
        {
          Lisp_Object map;
          map = Fget_text_property (pos, Qlocal_map, string);
@@ -21461,13 +21143,13 @@ phys_cursor_in_rect_p (w, r)
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph)
     {
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph)
     {
-      /* r is relative to W's box, but w->phys_cursor.x is relative 
+      /* r is relative to W's box, but w->phys_cursor.x is relative
         to left edge of W's TEXT area.  Adjust it.  */
       cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
       cr.y = w->phys_cursor.y;
       cr.width = cursor_glyph->pixel_width;
       cr.height = w->phys_cursor_height;
         to left edge of W's TEXT area.  Adjust it.  */
       cr.x = window_box_left_offset (w, TEXT_AREA) + w->phys_cursor.x;
       cr.y = w->phys_cursor.y;
       cr.width = cursor_glyph->pixel_width;
       cr.height = w->phys_cursor_height;
-      /* ++KFS: W32 version used W32-specific IntersectRect here, but 
+      /* ++KFS: W32 version used W32-specific IntersectRect here, but
         I assume the effect is the same -- and this is portable.  */
       return x_intersect_rectangles (&cr, r, &result);
     }
         I assume the effect is the same -- and this is portable.  */
       return x_intersect_rectangles (&cr, r, &result);
     }
@@ -21487,7 +21169,7 @@ x_draw_vertical_border (w)
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   
   /* We could do better, if we knew what type of scroll-bar the adjacent
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   
   /* We could do better, if we knew what type of scroll-bar the adjacent
-     windows (on either side) have...  But we don't :-( 
+     windows (on either side) have...  But we don't :-(
      However, I think this works ok.  ++KFS 2003-04-25 */
 
   /* Redraw borders between horizontally adjacent windows.  Don't
      However, I think this works ok.  ++KFS 2003-04-25 */
 
   /* Redraw borders between horizontally adjacent windows.  Don't
@@ -21911,6 +21593,8 @@ syms_of_xdisp ()
   staticpro (&Qleft_margin);
   Qright_margin = intern ("right-margin");
   staticpro (&Qright_margin);
   staticpro (&Qleft_margin);
   Qright_margin = intern ("right-margin");
   staticpro (&Qright_margin);
+  Qcenter = intern ("center");
+  staticpro (&Qcenter);
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
   QCrelative_width = intern (":relative-width");
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
   QCrelative_width = intern (":relative-width");
@@ -21976,13 +21660,20 @@ syms_of_xdisp ()
   Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
   staticpro (&Qinhibit_free_realized_faces);
 
   Qinhibit_free_realized_faces = intern ("inhibit-free-realized-faces");
   staticpro (&Qinhibit_free_realized_faces);
 
-  list_of_error = Fcons (intern ("error"), Qnil);
+  list_of_error = Fcons (Fcons (intern ("error"),
+                               Fcons (intern ("void-variable"), Qnil)),
+                        Qnil);
   staticpro (&list_of_error);
 
   staticpro (&list_of_error);
 
-  last_arrow_position = Qnil;
-  last_arrow_string = Qnil;
-  staticpro (&last_arrow_position);
-  staticpro (&last_arrow_string);
+  Qlast_arrow_position = intern ("last-arrow-position");
+  staticpro (&Qlast_arrow_position);
+  Qlast_arrow_string = intern ("last-arrow-string");
+  staticpro (&Qlast_arrow_string);
+
+  Qoverlay_arrow_string = intern ("overlay-arrow-string");
+  staticpro (&Qoverlay_arrow_string);
+  Qoverlay_arrow_bitmap = intern ("overlay-arrow-bitmap");
+  staticpro (&Qoverlay_arrow_bitmap);
 
   echo_buffer[0] = echo_buffer[1] = Qnil;
   staticpro (&echo_buffer[0]);
 
   echo_buffer[0] = echo_buffer[1] = Qnil;
   staticpro (&echo_buffer[0]);
@@ -22024,21 +21715,10 @@ wide as that tab on the display.  */);
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
-#ifdef HAVE_WINDOW_SYSTEM
-  DEFVAR_LISP ("overflow-newline-into-fringe", &Voverflow_newline_into_fringe,
-    doc: /* *Non-nil means that newline may flow into the right fringe.
-This means that display lines which are exactly as wide as the window
-(not counting the final newline) will only occupy one screen line, by
-showing (or hiding) the final newline in the right fringe; when point
-is at the final newline, the cursor is shown in the right fringe.
-If nil, also continue lines which are exactly as wide as the window.  */);
-  Voverflow_newline_into_fringe = Qt;
-#endif
-
   DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
     doc: /* *The pointer shape to show in void text areas.
 Nil means to show the text pointer.  Other options are `arrow', `text',
   DEFVAR_LISP ("void-text-area-pointer", &Vvoid_text_area_pointer,
     doc: /* *The pointer shape to show in void text areas.
 Nil means to show the text pointer.  Other options are `arrow', `text',
-`hand', `vdrag', `hdrag', `modeline', and `hourglass'.  */); 
+`hand', `vdrag', `hdrag', `modeline', and `hourglass'.  */);
   Vvoid_text_area_pointer = Qarrow;
 
   DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
   Vvoid_text_area_pointer = Qarrow;
 
   DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
@@ -22057,9 +21737,17 @@ See also `overlay-arrow-string'.  */);
   Voverlay_arrow_position = Qnil;
 
   DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
   Voverlay_arrow_position = Qnil;
 
   DEFVAR_LISP ("overlay-arrow-string", &Voverlay_arrow_string,
-    doc: /* String to display as an arrow.  See also `overlay-arrow-position'.  */);
+    doc: /* String to display as an arrow in non-window frames.
+See also `overlay-arrow-position'.  */);
   Voverlay_arrow_string = Qnil;
 
   Voverlay_arrow_string = Qnil;
 
+  DEFVAR_LISP ("overlay-arrow-variable-list", &Voverlay_arrow_variable_list,
+    doc: /* List of variables (symbols) which hold markers for overlay arrows.
+The symbols on this list are examined during redisplay to determine
+where to display overlay arrows.  */);
+  Voverlay_arrow_variable_list
+    = Fcons (intern ("overlay-arrow-position"), Qnil);
+
   DEFVAR_INT ("scroll-step", &scroll_step,
     doc: /* *The number of lines to try scrolling a window by when point moves out.
 If that fails to bring point back on frame, point is centered instead.
   DEFVAR_INT ("scroll-step", &scroll_step,
     doc: /* *The number of lines to try scrolling a window by when point moves out.
 If that fails to bring point back on frame, point is centered instead.