]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(erase_phys_cursor): Clear hollow cursor inside TEXT_AREA.
[gnu-emacs] / src / xdisp.c
index 9b3fc088775ece9a25117b755020c2052883fdcf..3b7b9d39f81e6e648097bd2b84c8416f6f3fa606 100644 (file)
@@ -1,5 +1,5 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03
+   Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -198,8 +198,6 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #ifdef MAC_OS
 #include "macterm.h"
-
-Cursor No_Cursor;
 #endif
 
 #ifndef FRAME_X_OUTPUT
@@ -217,6 +215,8 @@ extern int pending_menu_activation;
 extern int interrupt_input;
 extern int command_loop_level;
 
+extern Lisp_Object do_mouse_tracking;
+
 extern int minibuffer_auto_raise;
 extern Lisp_Object Vminibuffer_list;
 
@@ -242,6 +242,9 @@ Lisp_Object Qbuffer_position, Qposition, Qobject;
 /* Cursor shapes */
 Lisp_Object Qbar, Qhbar, Qbox, Qhollow;
 
+/* Pointer shapes */
+Lisp_Object Qarrow, Qhand, Qtext;
+
 Lisp_Object Qrisky_local_variable;
 
 /* Holds the list (error).  */
@@ -261,6 +264,10 @@ int mouse_autoselect_window;
 
 int auto_raise_tool_bar_buttons_p;
 
+/* Non-zero means to reposition window if cursor line is only partially visible.  */
+
+int make_cursor_line_fully_visible_p;
+
 /* Margin around tool bar buttons in pixels.  */
 
 Lisp_Object Vtool_bar_button_margin;
@@ -290,21 +297,47 @@ int inhibit_eval_during_redisplay;
 
 /* Names of text properties relevant for redisplay.  */
 
-Lisp_Object Qdisplay, Qrelative_width, Qalign_to;
+Lisp_Object Qdisplay;
 extern Lisp_Object Qface, Qinvisible, Qwidth;
 
 /* Symbols used in text property values.  */
 
+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 Qmargin;
+Lisp_Object Qslice;
+Lisp_Object Qcenter;
+Lisp_Object Qmargin, Qpointer;
+Lisp_Object Qline_height, Qtotal;
 extern Lisp_Object Qheight;
 extern Lisp_Object QCwidth, QCheight, QCascent;
+extern Lisp_Object Qscroll_bar;
+extern Lisp_Object Qcursor;
 
 /* Non-nil means highlight trailing whitespace.  */
 
 Lisp_Object Vshow_trailing_whitespace;
 
+#ifdef HAVE_WINDOW_SYSTEM
+extern Lisp_Object Voverflow_newline_into_fringe;
+
+/* Test if overflow newline into fringe.  Called with iterator IT
+   at or past right window margin, and with IT->current_x set.  */
+
+#define IT_OVERFLOW_NEWLINE_INTO_FRINGE(it)    \
+  (!NILP (Voverflow_newline_into_fringe)       \
+   && FRAME_WINDOW_P (it->f)                   \
+   && 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.  */
+
+Lisp_Object Vvoid_text_area_pointer;
+
 /* Name of the face used to highlight trailing whitespace.  */
 
 Lisp_Object Qtrailing_whitespace;
@@ -314,6 +347,10 @@ Lisp_Object Qtrailing_whitespace;
 
 Lisp_Object Qimage;
 
+/* The image map types.  */
+Lisp_Object QCmap, QCpointer;
+Lisp_Object Qrect, Qcircle, Qpoly;
+
 /* Non-zero means print newline to stdout before next mini-buffer
    message.  */
 
@@ -374,6 +411,13 @@ int multiple_frames;
 
 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;
@@ -382,11 +426,17 @@ Lisp_Object Voverlay_arrow_position;
 
 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.  */
 
-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.  */
 
@@ -627,10 +677,6 @@ EMACS_INT hscroll_margin;
 /* How much to scroll horizontally when point is inside the above margin.  */
 Lisp_Object Vhscroll_step;
 
-/* A list of symbols, one for each supported image type.  */
-
-Lisp_Object Vimage_types;
-
 /* The variable `resize-mini-windows'.  If nil, don't resize
    mini-windows.  If t, always resize them to fit the text they
    display.  If `grow-only', let mini-windows grow only until they
@@ -754,6 +800,9 @@ int help_echo_pos;
 
 Lisp_Object previous_help_echo_string;
 
+/* Null glyph slice */
+
+static struct glyph_slice null_glyph_slice = { 0, 0, 0, 0 };
 
 \f
 /* Function prototypes.  */
@@ -772,6 +821,7 @@ static int invisible_text_between_p P_ ((struct it *, int, int));
 
 static int next_element_from_ellipsis P_ ((struct it *));
 static void pint2str P_ ((char *, int, int));
+static void pint2hrstr P_ ((char *, int, int));
 static struct text_pos run_window_scroll_functions P_ ((Lisp_Object,
                                                        struct text_pos));
 static void reconsider_clip_changes P_ ((struct window *, struct buffer *));
@@ -802,10 +852,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 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 int make_cursor_line_fully_visible P_ ((struct window *));
+static int append_space_for_newline P_ ((struct it *, int));
+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));
@@ -813,6 +864,7 @@ static int message_log_check_duplicate P_ ((int, int, int, int));
 static void push_it P_ ((struct it *));
 static void pop_it P_ ((struct it *));
 static void sync_frame_with_window_matrix_rows P_ ((struct window *));
+static void select_frame_for_redisplay P_ ((Lisp_Object));
 static void redisplay_internal P_ ((int));
 static int echo_area_display P_ ((int));
 static void redisplay_windows P_ ((Lisp_Object));
@@ -840,7 +892,7 @@ static void next_overlay_string P_ ((struct it *));
 static void reseat P_ ((struct it *, struct text_pos, int));
 static void reseat_1 P_ ((struct it *, struct text_pos, int));
 static void back_to_previous_visible_line_start P_ ((struct it *));
-static void reseat_at_previous_visible_line_start P_ ((struct it *));
+void reseat_at_previous_visible_line_start P_ ((struct it *));
 static void reseat_at_next_visible_line_start P_ ((struct it *, int));
 static int next_element_from_display_vector P_ ((struct it *));
 static int next_element_from_string P_ ((struct it *));
@@ -1189,9 +1241,9 @@ line_bottom_y (it)
    and header-lines heights.  */
 
 int
-pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
      struct window *w;
-     int charpos, *fully, exact_mode_line_heights_p;
+     int charpos, *fully, *x, *y, exact_mode_line_heights_p;
 {
   struct it it;
   struct text_pos top;
@@ -1239,14 +1291,27 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
          visible_p = 1;
          *fully = bottom_y <= it.last_visible_y;
        }
+      if (visible_p && x)
+       {
+         *x = it.current_x;
+         *y = max (top_y + it.max_ascent - it.ascent, window_top_y);
+       }
     }
   else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
     {
+      struct it it2;
+
+      it2 = it;
       move_it_by_lines (&it, 1, 0);
       if (charpos < IT_CHARPOS (it))
        {
          visible_p = 1;
-         *fully  = 0;
+         if (x)
+           {
+             move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
+             *x = it2.current_x;
+             *y = it2.current_y + it2.max_ascent - it2.ascent;
+           }
        }
     }
 
@@ -1254,6 +1319,7 @@ pos_visible_p (w, charpos, fully, exact_mode_line_heights_p)
     set_buffer_internal_1 (old_buffer);
 
   current_header_line_height = current_mode_line_height = -1;
+
   return visible_p;
 }
 
@@ -1537,6 +1603,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
              ++glyph;
            }
 
+         /* If first glyph is partially visible, its first visible position is still 0.  */
+         if (hpos < 0)
+           hpos = 0;
+
          success_p = 1;
        }
       else
@@ -1568,11 +1638,10 @@ glyph_to_pixel_coords (w, hpos, vpos, frame_x, frame_y)
    date.  */
 
 static struct glyph *
-x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
+x_y_to_hpos_vpos (w, x, y, hpos, vpos, dx, dy, area)
      struct window *w;
      int x, y;
-     int *hpos, *vpos, *area;
-     int buffer_only_p;
+     int *hpos, *vpos, *dx, *dy, *area;
 {
   struct glyph *glyph, *end;
   struct glyph_row *row = NULL;
@@ -1611,7 +1680,7 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
       else if (x < window_box_right_offset (w, TEXT_AREA))
        {
          *area = TEXT_AREA;
-         x0 = window_box_left_offset (w, TEXT_AREA);
+         x0 = window_box_left_offset (w, TEXT_AREA) + min (row->x, 0);
        }
       else
        {
@@ -1623,23 +1692,22 @@ x_y_to_hpos_vpos (w, x, y, hpos, vpos, area, buffer_only_p)
   /* Find glyph containing X.  */
   glyph = row->glyphs[*area];
   end = glyph + row->used[*area];
-  while (glyph < end)
+  x -= x0;
+  while (glyph < end && x >= glyph->pixel_width)
     {
-      if (x < x0 + glyph->pixel_width)
-       {
-         if (w->pseudo_window_p)
-           break;
-         else if (!buffer_only_p || BUFFERP (glyph->object))
-           break;
-       }
-
-      x0 += glyph->pixel_width;
+      x -= glyph->pixel_width;
       ++glyph;
     }
 
   if (glyph == end)
     return NULL;
 
+  if (dx)
+    {
+      *dx = x;
+      *dy = y - (row->y + row->ascent - glyph->ascent);
+    }
+
   *hpos = glyph - row->glyphs[*area];
   return glyph;
 }
@@ -1721,26 +1789,36 @@ get_glyph_string_clip_rect (s, nr)
 
       /* If drawing a tool-bar window, draw it over the internal border
         at the top of the window.  */
-      if (s->w == XWINDOW (s->f->tool_bar_window))
+      if (WINDOWP (s->f->tool_bar_window)
+         && s->w == XWINDOW (s->f->tool_bar_window))
        r.y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
     }
 
   r.y = WINDOW_TO_FRAME_PIXEL_Y (s->w, r.y);
 
-#ifdef HAVE_NTGUI
-  /* ++KFS: From W32 port, but it looks ok for all platforms to me.  */
   /* If drawing the cursor, don't let glyph draw outside its
      advertised boundaries. Cleartype does this under some circumstances.  */
   if (s->hl == DRAW_CURSOR)
     {
+      struct glyph *glyph = s->first_glyph;
+      int height;
+
       if (s->x > r.x)
        {
          r.width -= s->x - r.x;
          r.x = s->x;
        }
-      r.width = min (r.width, s->first_glyph->pixel_width);
+      r.width = min (r.width, glyph->pixel_width);
+
+      /* Don't draw cursor glyph taller than our actual glyph.  */
+      height = max (FRAME_LINE_HEIGHT (s->f), glyph->ascent + glyph->descent);
+      if (height < r.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);
+       }
     }
-#endif
 
 #ifdef CONVERT_FROM_XRECT
   CONVERT_FROM_XRECT (r, *nr);
@@ -1863,10 +1941,14 @@ check_it (it)
       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)
@@ -1979,6 +2061,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->string = Qnil;
+  IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
 
   /* The window in which we iterate over current_buffer:  */
   XSETWINDOW (it->window, w);
@@ -1991,8 +2075,12 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
     {
       if (NATNUMP (current_buffer->extra_line_spacing))
        it->extra_line_spacing = XFASTINT (current_buffer->extra_line_spacing);
+      else if (FLOATP (current_buffer->extra_line_spacing))
+       it->extra_line_spacing = (XFLOAT_DATA (current_buffer->extra_line_spacing)
+                                 * FRAME_LINE_HEIGHT (it->f));
       else if (it->f->extra_line_spacing > 0)
        it->extra_line_spacing = it->f->extra_line_spacing;
+      it->max_extra_line_spacing = 0;
     }
 
   /* If realized faces have been removed, e.g. because of face
@@ -2004,9 +2092,11 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
   if (FRAME_FACE_CACHE (it->f)->used == 0)
     recompute_basic_faces (it->f);
 
-  /* Current value of the `space-width', and 'height' properties.  */
+  /* Current value of the `slice', `space-width', and 'height' properties.  */
+  it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
   it->space_width = Qnil;
   it->font_height = Qnil;
+  it->override_ascent = -1;
 
   /* Are control characters displayed as `^C'?  */
   it->ctl_arrow_p = !NILP (current_buffer->ctl_arrow);
@@ -2178,6 +2268,8 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
       else
        IT_BYTEPOS (*it) = bytepos;
 
+      it->start = it->current;
+
       /* Compute faces etc.  */
       reseat (it, it->current.pos, 1);
     }
@@ -2199,6 +2291,7 @@ start_display (it, w, pos)
 
   row = w->desired_matrix->rows + first_vpos;
   init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
+  it->first_vpos = first_vpos;
 
   if (!it->truncate_lines_p)
     {
@@ -2440,6 +2533,7 @@ init_to_row_start (it, w, row)
      struct glyph_row *row;
 {
   init_from_display_pos (it, w, &row->start);
+  it->start = row->start;
   it->continuation_lines_width = row->continuation_lines_width;
   CHECK_IT (it);
 }
@@ -2643,19 +2737,10 @@ next_overlay_change (pos)
   int noverlays;
   int endpos;
   Lisp_Object *overlays;
-  int len;
   int i;
 
   /* Get all overlays at the given position.  */
-  len = 10;
-  overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-  noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-  if (noverlays > len)
-    {
-      len = noverlays;
-      overlays = (Lisp_Object *) alloca (len * sizeof *overlays);
-      noverlays = overlays_at (pos, 0, &overlays, &len, &endpos, NULL, 1);
-    }
+  GET_OVERLAYS_AT (pos, overlays, noverlays, &endpos, 1);
 
   /* If any of these overlays ends before endpos,
      use its ending point instead.  */
@@ -3208,8 +3293,9 @@ handle_display_prop (it)
     }
 
   /* Reset those iterator values set from display property values.  */
-  it->font_height = Qnil;
+  it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
   it->space_width = Qnil;
+  it->font_height = Qnil;
   it->voffset = 0;
 
   /* We don't support recursive `display' properties, i.e. string
@@ -3228,11 +3314,14 @@ handle_display_prop (it)
       && !EQ (XCAR (prop), Qimage)
       && !EQ (XCAR (prop), Qspace)
       && !EQ (XCAR (prop), Qwhen)
+      && !EQ (XCAR (prop), Qslice)
       && !EQ (XCAR (prop), Qspace_width)
       && !EQ (XCAR (prop), Qheight)
       && !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))
@@ -3421,6 +3510,30 @@ handle_single_display_prop (it, prop, object, position,
       if (NUMBERP (value) && XFLOATINT (value) > 0)
        it->space_width = value;
     }
+  else if (CONSP (prop)
+          && EQ (XCAR (prop), Qslice))
+    {
+      /* `(slice X Y WIDTH HEIGHT)'.  */
+      Lisp_Object tem;
+
+      if (FRAME_TERMCAP_P (it->f) || FRAME_MSDOS_P (it->f))
+       return 0;
+
+      if (tem = XCDR (prop), CONSP (tem))
+       {
+         it->slice.x = XCAR (tem);
+         if (tem = XCDR (tem), CONSP (tem))
+           {
+             it->slice.y = XCAR (tem);
+             if (tem = XCDR (tem), CONSP (tem))
+               {
+                 it->slice.width = XCAR (tem);
+                 if (tem = XCDR (tem), CONSP (tem))
+                   it->slice.height = XCAR (tem);
+               }
+           }
+       }
+    }
   else if (CONSP (prop)
           && EQ (XCAR (prop), Qraise)
           && CONSP (XCDR (prop)))
@@ -3457,6 +3570,65 @@ handle_single_display_prop (it, prop, object, position,
         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;
+         int fringe_bitmap;
+
+         /* 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 (!SYMBOLP (value)
+             || !(fringe_bitmap = lookup_fringe_bitmap (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 = fringe_bitmap;
+             it->left_user_fringe_face_id = face_id;
+           }
+         else
+           {
+             it->right_user_fringe_bitmap = fringe_bitmap;
+             it->right_user_fringe_face_id = face_id;
+           }
+#endif /* HAVE_WINDOW_SYSTEM */
+         return 1;
+       }
+
       location = Qunbound;
       if (CONSP (prop) && CONSP (XCAR (prop)))
        {
@@ -3482,16 +3654,11 @@ handle_single_display_prop (it, prop, object, position,
          value = prop;
        }
 
+      valid_p = (STRINGP (value)
 #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 */
+                || (CONSP (value) && EQ (XCAR (value), Qspace)));
 
       if ((EQ (location, Qleft_margin)
           || EQ (location, Qright_margin)
@@ -4209,6 +4376,7 @@ push_it (it)
   p->string_nchars = it->string_nchars;
   p->area = it->area;
   p->multibyte_p = it->multibyte_p;
+  p->slice = it->slice;
   p->space_width = it->space_width;
   p->font_height = it->font_height;
   p->voffset = it->voffset;
@@ -4241,6 +4409,7 @@ pop_it (it)
   it->string_nchars = p->string_nchars;
   it->area = p->area;
   it->multibyte_p = p->multibyte_p;
+  it->slice = p->slice;
   it->space_width = p->space_width;
   it->font_height = p->font_height;
   it->voffset = p->voffset;
@@ -4392,12 +4561,21 @@ back_to_previous_visible_line_start (it)
        {
          Lisp_Object prop;
 
-         prop = Fget_char_property (make_number (IT_CHARPOS (*it)),
+         /* Check the newline before point for invisibility.  */
+         prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
                                     Qinvisible, it->window);
          if (TEXT_PROP_MEANS_INVISIBLE (prop))
            visible_p = 0;
        }
 
+      if (visible_p)
+       {
+         struct it it2 = *it;
+
+         if (handle_display_prop (&it2) == HANDLED_RETURN)
+           visible_p = 0;
+       }
+
       /* Back one more newline if the current one is invisible.  */
       if (!visible_p)
        back_to_previous_line_start (it);
@@ -4415,7 +4593,7 @@ back_to_previous_visible_line_start (it)
    selective display.  At the end, update IT's overlay information,
    face information etc.  */
 
-static void
+void
 reseat_at_previous_visible_line_start (it)
      struct it *it;
 {
@@ -4720,13 +4898,17 @@ get_next_display_element (it)
             translated to octal form.  */
          else if ((it->c < ' '
                    && (it->area != TEXT_AREA
+                       /* In mode line, treat \n like other crl chars.  */
+                       || (it->c != '\n'
+                           && it->glyph_row && it->glyph_row->mode_line_p)
                        || (it->c != '\n' && it->c != '\t')))
                   || (it->multibyte_p
                       ? ((it->c >= 127
                           && it->len == 1)
                          || !CHAR_PRINTABLE_P (it->c))
                       : (it->c >= 127
-                         && it->c == unibyte_char_to_multibyte (it->c))))
+                         && (!unibyte_display_via_language_environment
+                             || it->c == unibyte_char_to_multibyte (it->c)))))
            {
              /* IT->c is a control character which must be displayed
                 either as '\003' or as `^C' where the '\\' and '^'
@@ -5473,15 +5655,22 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
   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.  */
+      /* Stop when ZV reached.
+         We used to stop here when TO_CHARPOS reached as well, but that is
+         too soon if this glyph does not fit on this line.  So we handle it
+         explicitly below.  */
       if (!get_next_display_element (it)
-         || ((op & MOVE_TO_POS) != 0
-             && BUFFERP (it->object)
-             && IT_CHARPOS (*it) >= to_charpos))
+         || (it->truncate_lines_p
+             && BUFFER_POS_REACHED_P ()))
        {
          result = MOVE_POS_MATCH_OR_ZV;
          break;
@@ -5541,6 +5730,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
              /* We want to leave anything reaching TO_X to the caller.  */
              if ((op & MOVE_TO_X) && new_x > to_x)
                {
+                 if (BUFFER_POS_REACHED_P ())
+                   goto buffer_pos_reached;
                  it->current_x = x;
                  result = MOVE_X_REACHED;
                  break;
@@ -5563,7 +5754,34 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                      ++it->hpos;
                      it->current_x = new_x;
                      if (i == it->nglyphs - 1)
-                       set_iterator_to_next (it, 1);
+                       {
+                         set_iterator_to_next (it, 1);
+#ifdef HAVE_WINDOW_SYSTEM
+                         if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+                           {
+                             if (!get_next_display_element (it))
+                               {
+                                 result = MOVE_POS_MATCH_OR_ZV;
+                                 break;
+                               }
+                             if (BUFFER_POS_REACHED_P ())
+                               {
+                                 if (ITERATOR_AT_END_OF_LINE_P (it))
+                                   result = MOVE_POS_MATCH_OR_ZV;
+                                 else
+                                   result = MOVE_LINE_CONTINUED;
+                                 break;
+                               }
+                             if (ITERATOR_AT_END_OF_LINE_P (it))
+                               {
+                                 result = MOVE_NEWLINE_OR_CR;
+                                 break;
+                               }
+                             if (it->method == next_element_from_display_vector)
+                               it->face_id = it->saved_face_id;
+                           }
+#endif /* HAVE_WINDOW_SYSTEM */
+                       }
                    }
                  else
                    {
@@ -5577,6 +5795,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                  result = MOVE_LINE_CONTINUED;
                  break;
                }
+             else if (BUFFER_POS_REACHED_P ())
+               goto buffer_pos_reached;
              else if (new_x > it->first_visible_x)
                {
                  /* Glyph is visible.  Increment number of glyphs that
@@ -5593,6 +5813,15 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
          if (result != MOVE_UNDEFINED)
            break;
        }
+      else if (BUFFER_POS_REACHED_P ())
+       {
+       buffer_pos_reached:
+         it->current_x = x;
+         it->max_ascent = ascent;
+         it->max_descent = descent;
+         result = MOVE_POS_MATCH_OR_ZV;
+         break;
+       }
       else if ((op & MOVE_TO_X) && it->current_x >= to_x)
        {
          /* Stop when TO_X specified and reached.  This check is
@@ -5620,11 +5849,29 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
       if (it->truncate_lines_p
          && it->current_x >= it->last_visible_x)
        {
+#ifdef HAVE_WINDOW_SYSTEM
+         if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (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;
+                 break;
+               }
+           }
+#endif /* HAVE_WINDOW_SYSTEM */
          result = MOVE_LINE_TRUNCATED;
          break;
        }
     }
 
+#undef BUFFER_POS_REACHED_P
+
   /* Restore the iterator settings altered at the beginning of this
      function.  */
   it->glyph_row = saved_glyph_row;
@@ -5829,10 +6076,13 @@ move_it_vertically_backward (it, dy)
 {
   int nlines, h;
   struct it it2, it3;
-  int start_pos = IT_CHARPOS (*it);
+  int start_pos;
 
+ move_further_back:
   xassert (dy >= 0);
 
+  start_pos = IT_CHARPOS (*it);
+
   /* Estimate how many newlines we must move back.  */
   nlines = max (1, dy / FRAME_LINE_HEIGHT (it->f));
 
@@ -5898,13 +6148,13 @@ move_it_vertically_backward (it, dy)
             a line height of 13 pixels each, recentering with point
             on the bottom line will try to move -39/2 = 19 pixels
             backward.  Try to avoid moving into the first line.  */
-         && it->current_y - target_y > line_height / 3 * 2
+         && it->current_y - target_y > line_height * 2 / 3
          && IT_CHARPOS (*it) > BEGV)
        {
          TRACE_MOVE ((stderr, "  not far enough -> move_vert %d\n",
                       target_y - it->current_y));
-         move_it_vertically (it, target_y - it->current_y);
-         xassert (IT_CHARPOS (*it) >= BEGV);
+         dy = it->current_y - target_y;
+         goto move_further_back;
        }
       else if (target_y >= it->current_y + line_height
               && IT_CHARPOS (*it) < ZV)
@@ -5945,7 +6195,7 @@ move_it_vertically (it, dy)
 {
   if (dy <= 0)
     move_it_vertically_backward (it, -dy);
-  else if (dy > 0)
+  else
     {
       TRACE_MOVE ((stderr, "move_it_v: from %d, %d\n", IT_CHARPOS (*it), dy));
       move_it_to (it, ZV, -1, it->current_y + dy, -1,
@@ -6042,6 +6292,8 @@ move_it_by_lines (it, dvpos, need_y_p)
       /* DVPOS == 0 means move to the start of the screen line.  */
       move_it_vertically_backward (it, 0);
       xassert (it->current_x == 0 && it->hpos == 0);
+      /* Let next call to line_bottom_y calculate real line height */
+      last_height = 0;
     }
   else if (dvpos > 0)
     move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
@@ -6109,6 +6361,7 @@ add_to_log (format, arg1, arg2)
   char *buffer;
   int len;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  USE_SAFE_ALLOCA;
 
   /* Do nothing if called asynchronously.  Inserting text into
      a buffer may call after-change-functions and alike and
@@ -6125,10 +6378,12 @@ add_to_log (format, arg1, arg2)
   msg = Fformat (3, args);
 
   len = SBYTES (msg) + 1;
-  buffer = (char *) alloca (len);
+  SAFE_ALLOCA (buffer, char *, len);
   bcopy (SDATA (msg), buffer, len);
 
   message_dolog (buffer, len - 1, 1, 0);
+  SAFE_FREE ();
+
   UNGCPRO;
 }
 
@@ -6450,6 +6705,7 @@ message3 (m, nbytes, multibyte)
   struct gcpro gcpro1;
 
   GCPRO1 (m);
+  clear_message (1,1);
 
   /* First flush out any partial line written with print.  */
   message_log_maybe_newline ();
@@ -7182,7 +7438,7 @@ resize_mini_window (w, exact_p)
            height = it.current_y + last_height;
          else
            height = it.current_y + it.max_ascent + it.max_descent;
-         height -= it.extra_line_spacing;
+         height -= min (it.extra_line_spacing, it.max_extra_line_spacing);
          height = (height + unit - 1) / unit;
        }
 
@@ -7548,7 +7804,10 @@ clear_garbaged_frames ()
          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;
@@ -7735,7 +7994,7 @@ store_frame_title (str, field_width, precision)
 
   /* Copy at most PRECISION chars from STR.  */
   nbytes = strlen (str);
-  n+= c_string_width (str, nbytes, precision, &dummy, &nbytes);
+  n += c_string_width (str, nbytes, precision, &dummy, &nbytes);
   while (nbytes--)
     store_frame_title_char (*str++);
 
@@ -8140,7 +8399,7 @@ update_tool_bar (f, save_match_data)
      int save_match_data;
 {
 #ifdef USE_GTK
-  int do_update = FRAME_EXTERNAL_TOOL_BAR(f);
+  int do_update = FRAME_EXTERNAL_TOOL_BAR (f);
 #else
   int do_update = WINDOWP (f->tool_bar_window)
     && WINDOW_TOTAL_LINES (XWINDOW (f->tool_bar_window)) > 0;
@@ -8173,7 +8432,8 @@ update_tool_bar (f, save_match_data)
        {
          struct buffer *prev = current_buffer;
          int count = SPECPDL_INDEX ();
-         Lisp_Object old_tool_bar;
+         Lisp_Object new_tool_bar;
+          int new_n_tool_bar;
          struct gcpro gcpro1;
 
          /* Set current_buffer to the buffer of the selected
@@ -8192,19 +8452,25 @@ update_tool_bar (f, save_match_data)
              specbind (Qoverriding_local_map, Qnil);
            }
 
-         old_tool_bar = f->tool_bar_items;
-         GCPRO1 (old_tool_bar);
+         GCPRO1 (new_tool_bar);
 
          /* Build desired tool-bar items from keymaps.  */
-          BLOCK_INPUT;
-         f->tool_bar_items
-           = tool_bar_items (f->tool_bar_items, &f->n_tool_bar_items);
-          UNBLOCK_INPUT;
+          new_tool_bar = tool_bar_items (Fcopy_sequence (f->tool_bar_items),
+                                         &new_n_tool_bar);
 
          /* Redisplay the tool-bar if we changed it.  */
-         if (! NILP (Fequal (old_tool_bar, f->tool_bar_items)))
-           w->update_mode_line = Qt;
-         
+         if (NILP (Fequal (new_tool_bar, f->tool_bar_items)))
+            {
+              /* Redisplay that happens asynchronously due to an expose event
+                 may access f->tool_bar_items.  Make sure we update both
+                 variables within BLOCK_INPUT so no such event interrupts.  */
+              BLOCK_INPUT;
+              f->tool_bar_items = new_tool_bar;
+              f->n_tool_bar_items = new_n_tool_bar;
+              w->update_mode_line = Qt;
+              UNBLOCK_INPUT;
+            }
+
          UNGCPRO;
 
          unbind_to (count, Qnil);
@@ -8261,7 +8527,7 @@ build_desired_tool_bar_string (f)
       int enabled_p = !NILP (PROP (TOOL_BAR_ITEM_ENABLED_P));
       int selected_p = !NILP (PROP (TOOL_BAR_ITEM_SELECTED_P));
       int hmargin, vmargin, relief, idx, end;
-      extern Lisp_Object QCrelief, QCmargin, QCconversion, Qimage;
+      extern Lisp_Object QCrelief, QCmargin, QCconversion;
 
       /* If image is a vector, choose the image according to the
         button state.  */
@@ -8450,6 +8716,7 @@ display_tool_bar_line (it)
     {
       row->height = row->phys_height = it->last_visible_y - row->y;
       row->ascent = row->phys_ascent = 0;
+      row->extra_line_spacing = 0;
     }
 
   row->full_width_p = 1;
@@ -8537,7 +8804,7 @@ redisplay_tool_bar (f)
   int change_height_p = 0;
 
 #ifdef USE_GTK
-  if (FRAME_EXTERNAL_TOOL_BAR(f))
+  if (FRAME_EXTERNAL_TOOL_BAR (f))
     update_frame_tool_bar (f);
   return 0;
 #endif
@@ -8678,7 +8945,7 @@ get_tool_bar_item (f, x, y, glyph, hpos, vpos, prop_idx)
   int area;
 
   /* Find the glyph under X/Y.  */
-  *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, &area, 0);
+  *glyph = x_y_to_hpos_vpos (w, x, y, hpos, vpos, 0, 0, &area);
   if (*glyph == NULL)
     return -1;
 
@@ -8861,283 +9128,6 @@ note_tool_bar_highlight (f, x, y)
 #endif /* HAVE_WINDOW_SYSTEM */
 
 
-\f
-/***********************************************************************
-                              Fringes
- ***********************************************************************/
-
-#ifdef HAVE_WINDOW_SYSTEM
-
-/* An arrow like this: `<-'.  */
-static unsigned char left_bits[] = {
-   0x18, 0x0c, 0x06, 0x3f, 0x3f, 0x06, 0x0c, 0x18};
-
-/* Right truncation arrow bitmap `->'.  */
-static unsigned char right_bits[] = {
-   0x18, 0x30, 0x60, 0xfc, 0xfc, 0x60, 0x30, 0x18};
-
-/* Marker for continued lines.  */
-static unsigned char continued_bits[] = {
-   0x3c, 0x7c, 0xc0, 0xe4, 0xfc, 0x7c, 0x3c, 0x7c};
-
-/* Marker for continuation lines.  */
-static unsigned char continuation_bits[] = {
-   0x3c, 0x3e, 0x03, 0x27, 0x3f, 0x3e, 0x3c, 0x3e};
-
-/* Overlay arrow bitmap.  A triangular arrow.  */
-static unsigned char ov_bits[] = {
-   0x03, 0x0f, 0x1f, 0x3f, 0x3f, 0x1f, 0x0f, 0x03};
-
-/* 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};
-
-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 (continued_bits), 0, continued_bits },
-  { 8, sizeof (continuation_bits), 0, continuation_bits },
-  { 8, sizeof (ov_bits), 0, ov_bits },
-  { 8, sizeof (zv_bits), 3, zv_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.  */
-
-static void
-draw_fringe_bitmap (w, row, which, left_p)
-     struct window *w;
-     struct glyph_row *row;
-     enum fringe_bitmap_type which;
-     int left_p;
-{
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-  struct draw_fringe_bitmap_params p;
-
-  /* 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 = (fringe_bitmaps[which].period
-         ? (p.y % fringe_bitmaps[which].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.  */
-  p.y += (row->height - p.h) / 2;
-
-  rif->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;
-{
-  enum fringe_bitmap_type bitmap;
-
-  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)
-    {
-      /* Decide which bitmap to draw in the left fringe.  */
-      if (row->overlay_arrow_p)
-       bitmap = OVERLAY_ARROW_BITMAP;
-      else if (row->truncated_on_left_p)
-       bitmap = LEFT_TRUNCATION_BITMAP;
-      else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
-       bitmap = CONTINUATION_LINE_BITMAP;
-      else if (row->indicate_empty_line_p)
-       bitmap = ZV_LINE_BITMAP;
-      else
-       bitmap = NO_FRINGE_BITMAP;
-
-      draw_fringe_bitmap (w, row, bitmap, 1);
-    }
-
-  if (WINDOW_RIGHT_FRINGE_WIDTH (w) != 0)
-    {
-      /* Decide which bitmap to draw in the right fringe.  */
-      if (row->truncated_on_right_p)
-       bitmap = RIGHT_TRUNCATION_BITMAP;
-      else if (row->continued_p)
-       bitmap = CONTINUED_LINE_BITMAP;
-      else if (row->indicate_empty_line_p && WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
-       bitmap = ZV_LINE_BITMAP;
-      else
-       bitmap = NO_FRINGE_BITMAP;
-
-      draw_fringe_bitmap (w, row, bitmap, 0);
-    }
-}
-
-
-/* Compute actual fringe widths */
-
-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
@@ -9239,7 +9229,10 @@ hscroll_window_tree (window)
 
              /* 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)
                {
@@ -9448,42 +9441,192 @@ 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.  */
-
-int
-check_point_in_composition (prev_buf, prev_pt, buf, pt)
-     struct buffer *prev_buf, *buf;
-     int prev_pt, pt;
+static Lisp_Object
+overlay_arrow_string_or_property (var, pbitmap)
+     Lisp_Object var;
+     int *pbitmap;
 {
-  int start, end;
-  Lisp_Object prop;
-  Lisp_Object buffer;
+  Lisp_Object pstr = Fget (var, Qoverlay_arrow_string);
+  Lisp_Object bitmap;
 
-  XSETBUFFER (buffer, buf);
-  /* Check a composition at the last point if point moved within the
-     same buffer.  */
-  if (prev_buf == buf)
+  if (pbitmap)
     {
-      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);
+      *pbitmap = 0;
+      if (bitmap  = Fget (var, Qoverlay_arrow_bitmap), INTEGERP (bitmap))
+       *pbitmap = XINT (bitmap);
     }
 
-  /* 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);
+  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 ()
+{
+  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)
+       return 1;
+    }
+  return 0;
+}
+
+
+/* Return 1 if any overlay_arrows have moved or overlay-arrow-string
+   has changed.  */
+
+static int
+overlay_arrows_changed_p ()
+{
+  Lisp_Object vlist;
+
+  for (vlist = Voverlay_arrow_variable_list;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
+    {
+      Lisp_Object var = XCAR (vlist);
+      Lisp_Object val, pstr;
+
+      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 to display at row.
+   Return t if display as bitmap in left fringe.
+   Return nil if no overlay arrow.  */
+
+static Lisp_Object
+overlay_arrow_at_row (it, row, pbitmap)
+     struct it *it;
+     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 (it->f)
+             && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
+           return Qt;
+         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);
 }
 
 
@@ -9526,6 +9669,44 @@ reconsider_clip_changes (w, b)
     }
 }
 \f
+
+/* Select FRAME to forward the values of frame-local variables into C
+   variables so that the redisplay routines can access those values
+   directly.  */
+
+static void
+select_frame_for_redisplay (frame)
+     Lisp_Object frame;
+{
+  Lisp_Object tail, sym, val;
+  Lisp_Object old = selected_frame;
+
+  selected_frame = frame;
+
+  for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
+    if (CONSP (XCAR (tail))
+       && (sym = XCAR (XCAR (tail)),
+           SYMBOLP (sym))
+       && (sym = indirect_variable (sym),
+           val = SYMBOL_VALUE (sym),
+           (BUFFER_LOCAL_VALUEP (val)
+            || SOME_BUFFER_LOCAL_VALUEP (val)))
+       && XBUFFER_LOCAL_VALUE (val)->check_frame)
+      Fsymbol_value (sym);
+
+  for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
+    if (CONSP (XCAR (tail))
+       && (sym = XCAR (XCAR (tail)),
+           SYMBOLP (sym))
+       && (sym = indirect_variable (sym),
+           val = SYMBOL_VALUE (sym),
+           (BUFFER_LOCAL_VALUEP (val)
+            || SOME_BUFFER_LOCAL_VALUEP (val)))
+       && XBUFFER_LOCAL_VALUE (val)->check_frame)
+      Fsymbol_value (sym);
+}
+
+
 #define STOP_POLLING                                   \
 do { if (! polling_stopped_here) stop_polling ();      \
        polling_stopped_here = 1; } while (0)
@@ -9591,7 +9772,8 @@ redisplay_internal (preserve_echo_area)
   /* Record a function that resets redisplaying_p to its old value
      when we leave this function.  */
   count = SPECPDL_INDEX ();
-  record_unwind_protect (unwind_redisplay, make_number (redisplaying_p));
+  record_unwind_protect (unwind_redisplay,
+                        Fcons (make_number (redisplaying_p), selected_frame));
   ++redisplaying_p;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
@@ -9688,8 +9870,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 (! 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
@@ -9900,6 +10081,9 @@ redisplay_internal (preserve_echo_area)
 #if GLYPH_DEBUG
              *w->desired_matrix->method = 0;
              debug_method_add (w, "optimization 1");
+#endif
+#ifdef HAVE_WINDOW_SYSTEM
+             update_window_fringes (w, 0);
 #endif
              goto update;
            }
@@ -10005,6 +10189,11 @@ redisplay_internal (preserve_echo_area)
 
          if (FRAME_WINDOW_P (f) || f == sf)
            {
+             if (! EQ (frame, selected_frame))
+               /* Select the frame, for the sake of frame-local
+                  variables.  */
+               select_frame_for_redisplay (frame);
+
 #ifdef HAVE_WINDOW_SYSTEM
              if (clear_face_cache_count % 50 == 0
                  && FRAME_WINDOW_P (f))
@@ -10141,11 +10330,7 @@ redisplay_internal (preserve_echo_area)
       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.  */
@@ -10161,8 +10346,8 @@ redisplay_internal (preserve_echo_area)
             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_up_to_date_hook != 0)
            frame_up_to_date_hook (sf);
@@ -10230,7 +10415,7 @@ redisplay_internal (preserve_echo_area)
    This is useful in situations where you need to redisplay but no
    user action has occurred, making it inappropriate for the message
    area to be cleared.  See tracking_off and
-   wait_reading_process_input for examples of these situations.
+   wait_reading_process_output for examples of these situations.
 
    FROM_WHERE is an integer saying from where this function was
    called.  This is useful for debugging.  */
@@ -10251,19 +10436,29 @@ redisplay_preserve_echo_area (from_where)
     }
   else
     redisplay_internal (1);
+
+  if (rif != NULL && rif->flush_display_optional)
+    rif->flush_display_optional (NULL);
 }
 
 
 /* Function registered with record_unwind_protect in
    redisplay_internal.  Reset redisplaying_p to the value it had
    before redisplay_internal was called, and clear
-   prevent_freeing_realized_faces_p.  */
+   prevent_freeing_realized_faces_p.  It also selects the previously
+   selected frame.  */
 
 static Lisp_Object
-unwind_redisplay (old_redisplaying_p)
-     Lisp_Object old_redisplaying_p;
+unwind_redisplay (val)
+     Lisp_Object val;
 {
+  Lisp_Object old_redisplaying_p, old_frame;
+
+  old_redisplaying_p = XCAR (val);
   redisplaying_p = XFASTINT (old_redisplaying_p);
+  old_frame = XCDR (val);
+  if (! EQ (old_frame, selected_frame))
+    select_frame_for_redisplay (old_frame);
   return Qnil;
 }
 
@@ -10351,16 +10546,14 @@ mark_window_display_accurate (window, 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_...  */
-      last_arrow_position = Qt;
-      last_arrow_string = Qt;
+      update_overlay_arrows (-1);
     }
 }
 
@@ -10491,6 +10684,7 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
 {
   struct glyph *glyph = row->glyphs[TEXT_AREA];
   struct glyph *end = glyph + row->used[TEXT_AREA];
+  struct glyph *cursor = NULL;
   /* The first glyph that starts a sequence of glyphs from string.  */
   struct glyph *string_start;
   /* The X coordinate of string_start.  */
@@ -10500,6 +10694,8 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
   /* The last known character position before string_start.  */
   int string_before_pos;
   int x = row->x;
+  int cursor_x = x;
+  int cursor_from_overlay_pos = 0;
   int pt_old = PT - delta;
 
   /* Skip over glyphs not having an object at the start of the row.
@@ -10525,6 +10721,12 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
          string_start = NULL;
          x += glyph->pixel_width;
          ++glyph;
+         if (cursor_from_overlay_pos
+             && last_pos > cursor_from_overlay_pos)
+           {
+             cursor_from_overlay_pos = 0;
+             cursor = 0;
+           }
        }
       else
        {
@@ -10532,12 +10734,40 @@ set_cursor_from_row (w, row, matrix, delta, delta_bytes, dy, dvpos)
          string_start = glyph;
          string_start_x = x;
          /* Skip all glyphs from string.  */
-         SKIP_GLYPHS (glyph, end, x, STRINGP (glyph->object));
+         do
+           {
+             int pos;
+             if ((cursor == NULL || glyph > cursor)
+                 && !NILP (Fget_char_property (make_number ((glyph)->charpos),
+                                               Qcursor, (glyph)->object))
+                 && (pos = string_buffer_position (w, glyph->object,
+                                                   string_before_pos),
+                     (pos == 0   /* From overlay */
+                      || pos == pt_old)))
+               {
+                 /* Estimate overlay buffer position from the buffer
+                    positions of the glyphs before and after the overlay.
+                    Add 1 to last_pos so that if point corresponds to the
+                    glyph right after the overlay, we still use a 'cursor'
+                    property found in that overlay.  */
+                 cursor_from_overlay_pos = pos == 0 ? last_pos+1 : 0;
+                 cursor = glyph;
+                 cursor_x = x;
+               }
+             x += glyph->pixel_width;
+             ++glyph;
+           }
+         while (glyph < end && STRINGP (glyph->object));
        }
     }
 
-  if (string_start
-      && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
+  if (cursor != NULL)
+    {
+      glyph = cursor;
+      x = cursor_x;
+    }
+  else if (string_start
+          && (glyph == end || !BUFFERP (glyph->object) || last_pos > pt_old))
     {
       /* We may have skipped over point because the previous glyphs
         are from string.  As there's no easy way to know the
@@ -10650,17 +10880,25 @@ 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.)
+
+   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
-make_cursor_line_fully_visible (w)
+make_cursor_line_fully_visible (w, force_p)
      struct window *w;
+     int force_p;
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
   int window_height;
 
+  if (!make_cursor_line_fully_visible_p)
+    return 1;
+
   /* It's not always possible to find the cursor, e.g, when a window
      is full of overlay strings.  Don't do anything in that case.  */
   if (w->cursor.vpos < 0)
@@ -10670,15 +10908,17 @@ make_cursor_line_fully_visible (w)
   row = MATRIX_ROW (matrix, w->cursor.vpos);
 
   /* If the cursor row is not partially visible, there's nothing to do.  */
-  if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+  if (!MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row))
     return 1;
 
   /* 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 (row->height >= window_height)
-    return 1;
-
+    {
+      if (!force_p || w->vscroll)
+       return 1;
+    }
   return 0;
 
 #if 0
@@ -10769,7 +11009,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   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");
@@ -10787,6 +11027,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
   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)
@@ -10812,11 +11058,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));
 
-  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);
-      move_it_vertically (&it, - end_scroll_margin);
+      if (this_scroll_margin)
+       move_it_vertically_backward (&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;
     }
 
@@ -10860,7 +11108,12 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          aggressive = current_buffer->scroll_up_aggressively;
          height = WINDOW_BOX_TEXT_HEIGHT (w);
          if (NUMBERP (aggressive))
-           amount_to_scroll = XFLOATINT (aggressive) * height;
+           {
+             double float_amount = XFLOATINT (aggressive) * height;
+             amount_to_scroll = float_amount;
+             if (amount_to_scroll == 0 && float_amount > 0)
+               amount_to_scroll = 1;
+           }
        }
 
       if (amount_to_scroll <= 0)
@@ -10909,8 +11162,8 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          start_display (&it, w, startp);
 
          if (scroll_conservatively)
-           amount_to_scroll =
-             max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step));
+           amount_to_scroll
+             max (dy, FRAME_LINE_HEIGHT (f) * max (scroll_step, temp_scroll_step));
          else if (scroll_step || temp_scroll_step)
            amount_to_scroll = scroll_max;
          else
@@ -10918,13 +11171,18 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
              aggressive = current_buffer->scroll_down_aggressively;
              height = WINDOW_BOX_TEXT_HEIGHT (w);
              if (NUMBERP (aggressive))
-               amount_to_scroll = XFLOATINT (aggressive) * height;
+               {
+                 double float_amount = XFLOATINT (aggressive) * height;
+                 amount_to_scroll = float_amount;
+                 if (amount_to_scroll == 0 && float_amount > 0)
+                   amount_to_scroll = 1;
+               }
            }
 
          if (amount_to_scroll <= 0)
            return SCROLLING_FAILED;
 
-         move_it_vertically (&it, - amount_to_scroll);
+         move_it_vertically_backward (&it, amount_to_scroll);
          startp = it.current.pos;
        }
     }
@@ -10951,10 +11209,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 (! make_cursor_line_fully_visible (w))
+      if (! make_cursor_line_fully_visible (w, extra_scroll_margin_lines <= 1))
        {
          clear_glyph_matrix (w->desired_matrix);
-         last_line_misfit = 1;
+         ++extra_scroll_margin_lines;
          goto too_near_end;
        }
       rc = SCROLLING_SUCCESS;
@@ -11111,10 +11369,9 @@ 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)
-         || !MARKERP (Voverlay_arrow_position)
-         || current_buffer != XMARKER (Voverlay_arrow_position)->buffer))
+         || !overlay_arrow_in_current_buffer_p ()))
     {
-      int this_scroll_margin;
+      int this_scroll_margin, top_scroll_margin;
       struct glyph_row *row = NULL;
 
 #if GLYPH_DEBUG
@@ -11127,6 +11384,10 @@ try_cursor_movement (window, startp, scroll_step)
       this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
       this_scroll_margin *= FRAME_LINE_HEIGHT (f);
 
+      top_scroll_margin = this_scroll_margin;
+      if (WINDOW_WANTS_HEADER_LINE_P (w))
+       top_scroll_margin += CURRENT_HEADER_LINE_HEIGHT (w);
+
       /* Start with the row the cursor was displayed during the last
         not paused redisplay.  Give up if that row is not valid.  */
       if (w->last_cursor.vpos < 0
@@ -11181,13 +11442,12 @@ try_cursor_movement (window, startp, scroll_step)
          else if (PT < XFASTINT (w->last_point))
            {
              /* Cursor has to be moved backward.  Note that PT >=
-                CHARPOS (startp) because of the outer
-                if-statement.  */
+                CHARPOS (startp) because of the outer if-statement.  */
              while (!row->mode_line_p
                     && (MATRIX_ROW_START_CHARPOS (row) > PT
                         || (MATRIX_ROW_START_CHARPOS (row) == PT
                             && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
-                    && (row->y > this_scroll_margin
+                    && (row->y > top_scroll_margin
                         || CHARPOS (startp) == BEGV))
                {
                  xassert (row->enabled_p);
@@ -11215,7 +11475,7 @@ try_cursor_movement (window, startp, scroll_step)
                ++row;
 
              /* If within the scroll margin, scroll.  */
-             if (row->y < this_scroll_margin
+             if (row->y < top_scroll_margin
                  && CHARPOS (startp) != BEGV)
                scroll_p = 1;
            }
@@ -11226,7 +11486,8 @@ try_cursor_movement (window, startp, scroll_step)
              /* if PT is not in the glyph row, give up.  */
              rc = CURSOR_MOVEMENT_MUST_SCROLL;
            }
-         else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (row))
+         else if (MATRIX_ROW_PARTIALLY_VISIBLE_P (w, row)
+                  && make_cursor_line_fully_visible_p)
            {
              if (PT == MATRIX_ROW_END_CHARPOS (row)
                  && !row->ends_at_zv_p
@@ -11244,7 +11505,7 @@ try_cursor_movement (window, startp, scroll_step)
              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;
@@ -11274,7 +11535,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.
-     
+
      Note that mini-buffers sometimes aren't displaying any text.  */
   if (!MINI_WINDOW_P (w)
       || (w == XWINDOW (minibuf_window)
@@ -11286,7 +11547,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);
-      
+
       if (end < start)
        end = start;
       if (whole < (end - start))
@@ -11299,6 +11560,7 @@ set_vertical_scroll_bar (w)
   set_vertical_scroll_bar_hook (w, end - start, whole, start);
 }
 
+
 /* Redisplay leaf window WINDOW.  JUST_THIS_ONE_P non-zero means only
    selected_window is redisplayed.
 
@@ -11321,6 +11583,7 @@ redisplay_window (window, just_this_one_p)
   struct it it;
   /* Record it now because it's overwritten.  */
   int current_matrix_up_to_date_p = 0;
+  int used_current_matrix_p = 0;
   /* This is less strict than current_matrix_up_to_date_p.
      It indictes that the buffer contents and narrowing are unchanged.  */
   int buffer_unchanged_p = 0;
@@ -11511,6 +11774,11 @@ redisplay_window (window, just_this_one_p)
                  MOVE_TO_POS | MOVE_TO_X | MOVE_TO_Y);
       if (IT_CHARPOS (it) == PT)
        w->force_start = Qt;
+      /* IT may overshoot PT if text at PT is invisible.  */
+      else if (IT_CHARPOS (it) > PT && CHARPOS (startp) <= PT)
+       w->force_start = Qt;
+
+
     }
 
   /* Handle case where place to start displaying has been specified,
@@ -11568,7 +11836,7 @@ redisplay_window (window, just_this_one_p)
          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.  */
@@ -11622,6 +11890,7 @@ redisplay_window (window, just_this_one_p)
       switch (rc)
        {
        case CURSOR_MOVEMENT_SUCCESS:
+         used_current_matrix_p = 1;
          goto done;
 
 #if 0  /* try_cursor_movement never returns this value.  */
@@ -11686,7 +11955,8 @@ redisplay_window (window, just_this_one_p)
             buffer.  */
          || !NILP (Vwindow_scroll_functions)
          || MINI_WINDOW_P (w)
-         || !try_window_reusing_current_matrix (w))
+         || !(used_current_matrix_p
+              = try_window_reusing_current_matrix (w)))
        {
          IF_DEBUG (debug_method_add (w, "1"));
          try_window (window, startp);
@@ -11703,7 +11973,7 @@ redisplay_window (window, just_this_one_p)
            /* 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;
@@ -11792,7 +12062,7 @@ redisplay_window (window, just_this_one_p)
   if (it.current_y <= 0)
     {
       init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
-      move_it_vertically (&it, 0);
+      move_it_vertically_backward (&it, 0);
       xassert (IT_CHARPOS (it) <= PT);
       it.current_y = 0;
     }
@@ -11815,7 +12085,8 @@ redisplay_window (window, just_this_one_p)
       || !NILP (Vwindow_scroll_functions)
       || !just_this_one_p
       || MINI_WINDOW_P (w)
-      || !try_window_reusing_current_matrix (w))
+      || !(used_current_matrix_p
+          = try_window_reusing_current_matrix (w)))
     try_window (window, startp);
 
   /* If new fonts have been loaded (due to fontsets), give up.  We
@@ -11862,7 +12133,7 @@ redisplay_window (window, just_this_one_p)
       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)
@@ -11875,6 +12146,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.  */
+      clear_glyph_matrix (w->desired_matrix);
       centering_position = 0;
       goto point_at_top;
     }
@@ -11977,6 +12249,22 @@ redisplay_window (window, just_this_one_p)
 #endif
     }
 
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (f)
+      && update_window_fringes (w, 0)
+      && !just_this_one_p
+      && (used_current_matrix_p || overlay_arrow_seen)
+      && !w->pseudo_window_p)
+    {
+      update_begin (f);
+      BLOCK_INPUT;
+      if (draw_window_fringes (w, 1))
+       x_draw_vertical_border (w);
+      UNBLOCK_INPUT;
+      update_end (f);
+    }
+#endif /* HAVE_WINDOW_SYSTEM */
+
   /* We go to this label, with fonts_changed_p nonzero,
      if it is necessary to try again using larger glyph matrices.
      We have to redeem the scroll bar even in this case,
@@ -12123,7 +12411,7 @@ try_window_reusing_current_matrix (w)
   /* Give up if old or new display is scrolled vertically.  We could
      make this function handle this, but right now it doesn't.  */
   start_row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
-  if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (start_row))
+  if (w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row))
     return 0;
 
   /* The variable new_start now holds the new window start.  The old
@@ -12158,10 +12446,36 @@ try_window_reusing_current_matrix (w)
       last_text_row = last_reused_text_row = NULL;
 
       while (it.current_y < it.last_visible_y
-            && IT_CHARPOS (it) < CHARPOS (start)
             && !fonts_changed_p)
-       if (display_line (&it))
-         last_text_row = it.glyph_row - 1;
+       {
+         /* If we have reached into the characters in the START row,
+            that means the line boundaries have changed.  So we
+            can't start copying with the row START.  Maybe it will
+            work to start copying with the following row.  */
+         while (IT_CHARPOS (it) > CHARPOS (start))
+           {
+             /* Advance to the next row as the "start".  */
+             start_row++;
+             start = start_row->start.pos;
+             /* If there are no more rows to try, or just one, give up.  */
+             if (start_row == MATRIX_MODE_LINE_ROW (w->current_matrix) - 1
+                 || w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)
+                 || CHARPOS (start) == ZV)
+               {
+                 clear_glyph_matrix (w->desired_matrix);
+                 return 0;
+               }
+
+             start_vpos = MATRIX_ROW_VPOS (start_row, w->current_matrix);
+           }
+         /* If we have reached alignment,
+            we can copy the rest of the rows.  */
+         if (IT_CHARPOS (it) == CHARPOS (start))
+           break;
+
+         if (display_line (&it))
+           last_text_row = it.glyph_row - 1;
+       }
 
       /* A value of current_y < last_visible_y means that we stopped
         at the previous window start, which in turn means that we
@@ -12169,12 +12483,12 @@ try_window_reusing_current_matrix (w)
       if (it.current_y < it.last_visible_y)
        {
          /* IT.vpos always starts from 0; it counts text lines.  */
-         nrows_scrolled = it.vpos;
+         nrows_scrolled = it.vpos - (start_row - MATRIX_FIRST_TEXT_ROW (w->current_matrix));
 
          /* Find PT if not already found in the lines displayed.  */
          if (w->cursor.vpos < 0)
            {
-             int dy = it.current_y - first_row_y;
+             int dy = it.current_y - start_row->y;
 
              row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
              row = row_containing_pos (w, PT, row, NULL, dy);
@@ -12194,7 +12508,7 @@ try_window_reusing_current_matrix (w)
             scroll_run_hook will clear the cursor, and use the
             current matrix to get the height of the row the cursor is
             in.  */
-         run.current_y = first_row_y;
+         run.current_y = start_row->y;
          run.desired_y = it.current_y;
          run.height = it.last_visible_y - it.current_y;
 
@@ -12233,6 +12547,7 @@ try_window_reusing_current_matrix (w)
                row->visible_height -= min_y - row->y;
              if (row->y + row->height > max_y)
                row->visible_height -= row->y + row->height - max_y;
+             row->redraw_fringe_bitmaps_p = 1;
 
              it.current_y += row->height;
 
@@ -12359,9 +12674,8 @@ try_window_reusing_current_matrix (w)
         position.  */
       if (pt_row)
        {
-         w->cursor.vpos -= MATRIX_ROW_VPOS (first_reusable_row,
-                                            w->current_matrix);
-         w->cursor.y -= first_reusable_row->y;
+         w->cursor.vpos -= nrows_scrolled;
+         w->cursor.y -= first_reusable_row->y - start_row->y;
        }
 
       /* Scroll the display.  */
@@ -12372,7 +12686,6 @@ try_window_reusing_current_matrix (w)
 
       if (run.height)
        {
-         struct frame *f = XFRAME (WINDOW_FRAME (w));
          update_begin (f);
          rif->update_window_begin_hook (w);
          rif->clear_window_mouse_face (w);
@@ -12393,6 +12706,7 @@ try_window_reusing_current_matrix (w)
            row->visible_height -= min_y - row->y;
          if (row->y + row->height > max_y)
            row->visible_height -= row->y + row->height - max_y;
+         row->redraw_fringe_bitmaps_p = 1;
        }
 
       /* Scroll the current matrix.  */
@@ -12406,6 +12720,29 @@ try_window_reusing_current_matrix (w)
       for (row -= nrows_scrolled; row < bottom_row; ++row)
        row->enabled_p = 0;
 
+      /* Point may have moved to a different line, so we cannot assume that
+        the previous cursor position is valid; locate the correct row.  */
+      if (pt_row)
+       {
+         for (row = MATRIX_ROW (w->current_matrix, w->cursor.vpos);
+              row < bottom_row && PT >= MATRIX_ROW_END_CHARPOS (row);
+              row++)
+           {
+             w->cursor.vpos++;
+             w->cursor.y = row->y;
+           }
+         if (row < bottom_row)
+           {
+             struct glyph *glyph = row->glyphs[TEXT_AREA] + w->cursor.hpos;
+             while (glyph->charpos < PT)
+               {
+                 w->cursor.hpos++;
+                 w->cursor.x += glyph->pixel_width;
+                 glyph++;
+               }
+           }
+       }
+
       /* Adjust window end.  A null value of last_text_row means that
         the window end is in reused rows which in turn means that
         only its vpos can have changed.  */
@@ -12515,7 +12852,8 @@ find_last_unchanged_at_beg_row (w)
             row is not unchanged because it may be no longer
             continued.  */
          && !(MATRIX_ROW_END_CHARPOS (row) == first_changed_pos
-              && row->continued_p))
+              && (row->continued_p
+                  || row->exact_window_width_line_p)))
        row_found = row;
 
       /* Stop if last visible row.  */
@@ -12835,8 +13173,7 @@ try_window_id (w)
     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);
 
 
@@ -13024,8 +13361,9 @@ try_window_id (w)
   else
     {
       /* There are no reusable lines at the start of the window.
-        Start displaying in the first line.  */
+        Start displaying in the first text line.  */
       start_display (&it, w, start);
+      it.vpos = it.first_vpos;
       start_pos = it.current.pos;
     }
 
@@ -13188,9 +13526,11 @@ try_window_id (w)
 
     if ((w->cursor.y < this_scroll_margin
         && CHARPOS (start) > BEGV)
-       /* Don't take scroll margin into account at the bottom because
-          old redisplay didn't do it either.  */
-       || w->cursor.y + cursor_height > it.last_visible_y)
+       /* Old redisplay didn't take scroll margin into account at the bottom,
+          but then global-hl-line-mode doesn't scroll.  KFS 2004-06-14 */
+       || (w->cursor.y + (make_cursor_line_fully_visible_p
+                          ? cursor_height + this_scroll_margin
+                          : 1)) > it.last_visible_y)
       {
        w->cursor.vpos = -1;
        clear_glyph_matrix (w->desired_matrix);
@@ -13768,18 +14108,19 @@ usage: (trace-to-stderr STRING &rest OBJECTS)  */)
                     Building Desired Matrix Rows
  ***********************************************************************/
 
-/* Return a temporary glyph row holding the glyphs of an overlay
-   arrow.  Only used for non-window-redisplay windows.  */
+/* Return a temporary glyph row holding the glyphs of an overlay arrow.
+   Used for non-window-redisplay windows, and for windows w/o left fringe.  */
 
 static struct glyph_row *
-get_overlay_arrow_glyph_row (w)
+get_overlay_arrow_glyph_row (w, overlay_arrow_string)
      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;
-  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;
@@ -13806,7 +14147,7 @@ get_overlay_arrow_glyph_row (w)
 
       /* 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.  */
@@ -13914,6 +14255,7 @@ compute_line_metrics (it)
          row->height = it->max_ascent + it->max_descent;
          row->phys_ascent = it->max_phys_ascent;
          row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+         row->extra_line_spacing = it->max_extra_line_spacing;
        }
 
       /* Compute the width of this line.  */
@@ -13957,6 +14299,7 @@ compute_line_metrics (it)
        row->pixel_width -= it->truncation_pixel_width;
       row->ascent = row->phys_ascent = 0;
       row->height = row->phys_height = row->visible_height = 1;
+      row->extra_line_spacing = 0;
     }
 
   /* Compute a hash code for this row.  */
@@ -13975,8 +14318,7 @@ compute_line_metrics (it)
 
 
 /* Append one space to the glyph row of iterator IT if doing a
-   window-based redisplay.  DEFAULT_FACE_P non-zero means let the
-   space have the default face, otherwise let it have the same face as
+   window-based redisplay.  The space has the same face as
    IT->face_id.  Value is non-zero if a space was added.
 
    This function is called to make sure that there is always one glyph
@@ -13988,7 +14330,7 @@ compute_line_metrics (it)
    end of the line if the row ends in italic text.  */
 
 static int
-append_space (it, default_face_p)
+append_space_for_newline (it, default_face_p)
      struct it *it;
      int default_face_p;
 {
@@ -14002,7 +14344,7 @@ append_space (it, default_face_p)
          /* Save some values that must not be changed.
             Must save IT->c and IT->len because otherwise
             ITERATOR_AT_END_P wouldn't work anymore after
-            append_space has been called.  */
+            append_space_for_newline has been called.  */
          enum display_element_type saved_what = it->what;
          int saved_c = it->c, saved_len = it->len;
          int saved_x = it->current_x;
@@ -14029,6 +14371,8 @@ append_space (it, default_face_p)
 
          PRODUCE_GLYPHS (it);
 
+         it->override_ascent = -1;
+         it->constrain_row_ascent_descent_p = 0;
          it->current_x = saved_x;
          it->object = saved_object;
          it->position = saved_pos;
@@ -14245,13 +14589,19 @@ display_line (it)
      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 must not display in a row that's not a text row.  */
-  xassert (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
-          < it->w->desired_matrix->nrows);
+  if (MATRIX_ROW_VPOS (row, it->w->desired_matrix)
+      >= it->w->desired_matrix->nrows)
+    {
+      it->w->nrows_scale_factor++;
+      fonts_changed_p = 1;
+      return 0;
+    }
 
   /* Is IT->w showing the region?  */
   it->w->region_showing = it->region_beg_charpos > 0 ? Qt : Qnil;
@@ -14260,7 +14610,7 @@ display_line (it)
   prepare_desired_row (row);
 
   row->y = it->current_y;
-  row->start = it->current;
+  row->start = it->start;
   row->continuation_lines_width = it->continuation_lines_width;
   row->displays_text_p = 1;
   row->starts_in_middle_of_char_p = it->starts_in_middle_of_char_p;
@@ -14286,6 +14636,7 @@ display_line (it)
   row->height = it->max_ascent + it->max_descent;
   row->phys_ascent = it->max_phys_ascent;
   row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+  row->extra_line_spacing = it->max_extra_line_spacing;
 
   /* Loop generating characters.  The loop is left with IT on the next
      character to display.  */
@@ -14303,7 +14654,12 @@ 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.  */
-         if ((append_space (it, 1) && row->used[TEXT_AREA] == 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_for_newline (it, 1) && row->used[TEXT_AREA] == 1)
              || row->used[TEXT_AREA] == 0)
            {
              row->glyphs[TEXT_AREA]->charpos = -1;
@@ -14346,6 +14702,8 @@ display_line (it)
          row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
          row->phys_height = max (row->phys_height,
                                  it->max_phys_ascent + it->max_phys_descent);
+         row->extra_line_spacing = max (row->extra_line_spacing,
+                                        it->max_extra_line_spacing);
          set_iterator_to_next (it, 1);
          continue;
        }
@@ -14374,6 +14732,8 @@ display_line (it)
          row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
          row->phys_height = max (row->phys_height,
                                  it->max_phys_ascent + it->max_phys_descent);
+         row->extra_line_spacing = max (row->extra_line_spacing,
+                                        it->max_extra_line_spacing);
          if (it->current_x - it->pixel_width < it->first_visible_x)
            row->x = x - it->first_visible_x;
        }
@@ -14410,7 +14770,28 @@ display_line (it)
                      it->continuation_lines_width += new_x;
                      ++it->hpos;
                      if (i == nglyphs - 1)
-                       set_iterator_to_next (it, 1);
+                       {
+                         set_iterator_to_next (it, 1);
+#ifdef HAVE_WINDOW_SYSTEM
+                         if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (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;
+                               }
+                             else if (it->method == next_element_from_display_vector)
+                               it->face_id = it->saved_face_id;
+                           }
+#endif /* HAVE_WINDOW_SYSTEM */
+                       }
                    }
                  else if (CHAR_GLYPH_PADDING_P (*glyph)
                           && !FRAME_WINDOW_P (it->f))
@@ -14506,12 +14887,15 @@ display_line (it)
          row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
          row->phys_height = max (row->phys_height,
                                  it->max_phys_ascent + it->max_phys_descent);
+         row->extra_line_spacing = max (row->extra_line_spacing,
+                                        it->max_extra_line_spacing);
 
          /* End of this display line if row is continued.  */
-         if (row->continued_p)
+         if (row->continued_p || row->ends_at_zv_p)
            break;
        }
 
+    at_end_of_line:
       /* Is this a line end?  If yes, we're also done, after making
         sure that a non-default face is extended up to the right
         margin of the window.  */
@@ -14521,9 +14905,12 @@ display_line (it)
 
          row->ends_in_newline_from_string_p = STRINGP (it->object);
 
+#ifdef HAVE_WINDOW_SYSTEM
          /* Add a space at the end of the line that is used to
             display the cursor there.  */
-         append_space (it, 0);
+         if (!IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+           append_space_for_newline (it, 0);
+#endif /* HAVE_WINDOW_SYSTEM */
 
          /* Extend the face to the end of the line.  */
          extend_face_to_end_of_line (it);
@@ -14564,6 +14951,27 @@ display_line (it)
                  produce_special_glyphs (it, IT_TRUNCATION);
                }
            }
+#ifdef HAVE_WINDOW_SYSTEM
+         else
+           {
+             /* Don't truncate if we can overflow newline into fringe.  */
+             if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
+               {
+                 if (!get_next_display_element (it))
+                   {
+                     it->continuation_lines_width = 0;
+                     row->ends_at_zv_p = 1;
+                     row->exact_window_width_line_p = 1;
+                     break;
+                   }
+                 if (ITERATOR_AT_END_OF_LINE_P (it))
+                   {
+                     row->exact_window_width_line_p = 1;
+                     goto at_end_of_line;
+                   }
+               }
+           }
+#endif /* HAVE_WINDOW_SYSTEM */
 
          row->truncated_on_right_p = 1;
          it->continuation_lines_width = 0;
@@ -14589,17 +14997,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.  */
-  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, row, &overlay_arrow_bitmap),
+         !NILP (overlay_arrow_string)))
     {
       /* Overlay arrow in window redisplay is a fringe bitmap.  */
-      if (!FRAME_WINDOW_P (it->f))
+      if (STRINGP (overlay_arrow_string))
        {
-         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];
@@ -14621,9 +15028,12 @@ display_line (it)
              row->used[TEXT_AREA] = p2 - row->glyphs[TEXT_AREA];
            }
        }
-
+      else
+       {
+         it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
+         row->overlay_arrow_p = 1;
+       }
       overlay_arrow_seen = 1;
-      row->overlay_arrow_p = 1;
     }
 
   /* Compute pixel dimensions of this line.  */
@@ -14632,6 +15042,17 @@ display_line (it)
   /* 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)
@@ -14651,6 +15072,7 @@ display_line (it)
   it->current_y += row->height;
   ++it->vpos;
   ++it->glyph_row;
+  it->start = it->current;
   return row->displays_text_p;
 }
 
@@ -14894,6 +15316,8 @@ display_mode_line (w, face_id, format)
   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;
@@ -14910,7 +15334,6 @@ display_mode_line (w, face_id, format)
 
   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;
@@ -14993,6 +15416,10 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
            Lisp_Object oprops, aelt;
            oprops = Ftext_properties_at (make_number (0), elt);
 
+           /* If the starting string's properties are not what
+              we want, translate the string.  Also, if the string
+              is risky, do that anyway.  */
+
            if (NILP (Fequal (props, oprops)) || risky)
              {
                /* If the starting string has properties,
@@ -15071,14 +15498,15 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
 
            if (this - 1 != last)
              {
+               int nchars, nbytes;
+
                /* Output to end of string or up to '%'.  Field width
                   is length of string.  Don't output more than
                   PRECISION allows us.  */
                --this;
 
-               prec = chars_in_text (last, this - last);
-               if (precision > 0 && prec > precision - n)
-                 prec = precision - n;
+               prec = c_string_width (last, this - last, precision - n,
+                                      &nchars, &nbytes);
 
                if (frame_title_ptr)
                  n += store_frame_title (last, 0, prec);
@@ -15086,9 +15514,14 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                  {
                    int bytepos = last - lisp_string;
                    int charpos = string_byte_to_char (elt, bytepos);
+                   int endpos = (precision <= 0
+                                 ? string_byte_to_char (elt,
+                                                        this - lisp_string)
+                                 : charpos + nchars);
+
                    n += store_mode_line_string (NULL,
                                                 Fsubstring (elt, make_number (charpos),
-                                                            make_number (charpos + prec)),
+                                                            make_number (endpos)),
                                                 0, 0, 0, Qnil);
                  }
                else
@@ -15369,7 +15802,8 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
    The mode_line_string_face face property is always added to the string.
  */
 
-static int store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props)
+static int
+store_mode_line_string (string, lisp_string, copy_string, field_width, precision, props)
      char *string;
      Lisp_Object lisp_string;
      int copy_string;
@@ -15390,7 +15824,7 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width
        props = mode_line_string_face_prop;
       else if (!NILP (mode_line_string_face))
        {
-         Lisp_Object face = Fplist_get (props, Qface);
+         Lisp_Object face = Fsafe_plist_get (props, Qface);
          props = Fcopy_sequence (props);
          if (NILP (face))
            face = mode_line_string_face;
@@ -15415,7 +15849,7 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width
          Lisp_Object face;
          if (NILP (props))
            props = Ftext_properties_at (make_number (0), lisp_string);
-         face = Fplist_get (props, Qface);
+         face = Fsafe_plist_get (props, Qface);
          if (NILP (face))
            face = mode_line_string_face;
          else
@@ -15451,15 +15885,16 @@ static int store_mode_line_string (string, lisp_string, copy_string, field_width
 
 
 DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
-       0, 3, 0,
+       0, 4, 0,
        doc: /* Return the mode-line of selected window as a string.
 First optional arg FORMAT specifies a different format string (see
 `mode-line-format' for details) to use.  If FORMAT is t, return
 the buffer's header-line.  Second optional arg WINDOW specifies a
 different window to use as the context for the formatting.
-If third optional arg NO-PROPS is non-nil, string is not propertized.  */)
-     (format, window, no_props)
-     Lisp_Object format, window, no_props;
+If third optional arg NO-PROPS is non-nil, string is not propertized.
+Fourth optional arg BUFFER specifies which buffer to use.  */)
+  (format, window, no_props, buffer)
+     Lisp_Object format, window, no_props, buffer;
 {
   struct it it;
   int len;
@@ -15471,42 +15906,46 @@ If third optional arg NO-PROPS is non-nil, string is not propertized.  */)
     window = selected_window;
   CHECK_WINDOW (window);
   w = XWINDOW (window);
-  CHECK_BUFFER (w->buffer);
 
-  if (XBUFFER (w->buffer) != current_buffer)
+  if (NILP (buffer))
+    buffer = w->buffer;
+
+  CHECK_BUFFER (buffer);
+
+  if (XBUFFER (buffer) != current_buffer)
     {
       old_buffer = current_buffer;
-      set_buffer_internal_1 (XBUFFER (w->buffer));
+      set_buffer_internal_1 (XBUFFER (buffer));
     }
 
   if (NILP (format) || EQ (format, Qt))
     {
-      face_id = NILP (format)
-       ? CURRENT_MODE_LINE_FACE_ID (w) :
-       HEADER_LINE_FACE_ID;
-      format = NILP (format)
-       ? current_buffer->mode_line_format
-       : current_buffer->header_line_format;
+      face_id = (NILP (format)
+                ? CURRENT_MODE_LINE_FACE_ID (w)
+                : HEADER_LINE_FACE_ID);
+      format = (NILP (format)
+               ? current_buffer->mode_line_format
+               : current_buffer->header_line_format);
     }
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
 
   if (NILP (no_props))
     {
-      mode_line_string_face =
-       (face_id == MODE_LINE_FACE_ID ? Qmode_line :
-        face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive :
-        face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
+      mode_line_string_face
+       = (face_id == MODE_LINE_FACE_ID ? Qmode_line
+          : face_id == MODE_LINE_INACTIVE_FACE_ID ? Qmode_line_inactive
+          : face_id == HEADER_LINE_FACE_ID ? Qheader_line : Qnil);
 
-      mode_line_string_face_prop =
-       NILP (mode_line_string_face) ? Qnil :
-       Fcons (Qface, Fcons (mode_line_string_face, Qnil));
+      mode_line_string_face_prop
+       = (NILP (mode_line_string_face) ? Qnil
+          : Fcons (Qface, Fcons (mode_line_string_face, Qnil)));
 
       /* We need a dummy last element in mode_line_string_list to
         indicate we are building the propertized mode-line string.
         Using mode_line_string_face_prop here GC protects it.  */
-      mode_line_string_list =
-       Fcons (mode_line_string_face_prop, Qnil);
+      mode_line_string_list
+       Fcons (mode_line_string_face_prop, Qnil);
       frame_title_ptr = NULL;
     }
   else
@@ -15582,37 +16021,152 @@ pint2str (buf, width, d)
     }
 }
 
-/* Set a mnemonic character for coding_system (Lisp symbol) in BUF.
-   If EOL_FLAG is 1, set also a mnemonic character for end-of-line
-   type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+/* Write a null-terminated, right justified decimal and "human
+   readable" representation of the nonnegative integer D to BUF using
+   a minimal field width WIDTH.         D should be smaller than 999.5e24. */
 
-static unsigned char invalid_eol_type[] = "(*invalid*)";
+static const char power_letter[] =
+  {
+    0,  /* not used */
+    'k', /* kilo */
+    'M', /* mega */
+    'G', /* giga */
+    'T', /* tera */
+    'P', /* peta */
+    'E', /* exa */
+    'Z', /* zetta */
+    'Y'         /* yotta */
+  };
 
-static char *
-decode_mode_spec_coding (coding_system, buf, eol_flag)
-     Lisp_Object coding_system;
-     register char *buf;
-     int eol_flag;
+static void
+pint2hrstr (buf, width, d)
+     char *buf;
+     int width;
+     int d;
 {
-  Lisp_Object val;
-  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
-  const unsigned char *eol_str;
-  int eol_str_len;
-  /* The EOL conversion we are using.  */
-  Lisp_Object eoltype;
+  /* We aim to represent the nonnegative integer D as
+     QUOTIENT.TENTHS * 10 ^ (3 * EXPONENT). */
+  int quotient = d;
+  int remainder = 0;
+  /* -1 means: do not use TENTHS. */
+  int tenths = -1;
+  int exponent = 0;
 
-  val = Fget (coding_system, Qcoding_system);
-  eoltype = Qnil;
+  /* Length of QUOTIENT.TENTHS as a string. */
+  int length;
 
-  if (!VECTORP (val))          /* Not yet decided.  */
+  char * psuffix;
+  char * p;
+
+  if (1000 <= quotient)
     {
-      if (multibyte)
-       *buf++ = '-';
-      if (eol_flag)
-       eoltype = eol_mnemonic_undecided;
-      /* Don't mention EOL conversion if it isn't decided.  */
-    }
-  else
+      /* Scale to the appropriate EXPONENT. */
+      do
+       {
+         remainder = quotient % 1000;
+         quotient /= 1000;
+         exponent++;
+       }
+      while (1000 <= quotient);
+
+      /* Round to nearest and decide whether to use TENTHS or not. */
+      if (quotient <= 9)
+       {
+         tenths = remainder / 100;
+         if (50 <= remainder % 100)
+           {
+             if (tenths < 9)
+               tenths++;
+             else
+               {
+                 quotient++;
+                 if (quotient == 10)
+                   tenths = -1;
+                 else
+                   tenths = 0;
+               }
+           }
+       }
+      else
+       if (500 <= remainder)
+         {
+           if (quotient < 999)
+             quotient++;
+           else
+             {
+               quotient = 1;
+               exponent++;
+               tenths = 0;
+             }
+         }
+    }
+
+  /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */
+  if (tenths == -1 && quotient <= 99)
+    if (quotient <= 9)
+      length = 1;
+    else
+      length = 2;
+  else
+    length = 3;
+  p = psuffix = buf + max (width, length);
+
+  /* Print EXPONENT. */
+  if (exponent)
+    *psuffix++ = power_letter[exponent];
+  *psuffix = '\0';
+
+  /* Print TENTHS. */
+  if (tenths >= 0)
+    {
+      *--p = '0' + tenths;
+      *--p = '.';
+    }
+
+  /* Print QUOTIENT. */
+  do
+    {
+      int digit = quotient % 10;
+      *--p =  '0' + digit;
+    }
+  while ((quotient /= 10) != 0);
+
+  /* Print leading spaces. */
+  while (buf < p)
+    *--p = ' ';
+}
+
+/* Set a mnemonic character for coding_system (Lisp symbol) in BUF.
+   If EOL_FLAG is 1, set also a mnemonic character for end-of-line
+   type of CODING_SYSTEM.  Return updated pointer into BUF.  */
+
+static unsigned char invalid_eol_type[] = "(*invalid*)";
+
+static char *
+decode_mode_spec_coding (coding_system, buf, eol_flag)
+     Lisp_Object coding_system;
+     register char *buf;
+     int eol_flag;
+{
+  Lisp_Object val;
+  int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+  const unsigned char *eol_str;
+  int eol_str_len;
+  /* The EOL conversion we are using.  */
+  Lisp_Object eoltype;
+
+  val = Fget (coding_system, Qcoding_system);
+  eoltype = Qnil;
+
+  if (!VECTORP (val))          /* Not yet decided.  */
+    {
+      if (multibyte)
+       *buf++ = '-';
+      if (eol_flag)
+       eoltype = eol_mnemonic_undecided;
+      /* Don't mention EOL conversion if it isn't decided.  */
+    }
+  else
     {
       Lisp_Object eolvalue;
 
@@ -15668,7 +16222,10 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
    generated by character C.  PRECISION >= 0 means don't return a
    string longer than that value.  FIELD_WIDTH > 0 means pad the
    string returned with spaces to that value.  Return 1 in *MULTIBYTE
-   if the result is multibyte text.  */
+   if the result is multibyte text.
+
+   Note we operate on the current buffer for most purposes,
+   the exception being w->base_line_pos.  */
 
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
@@ -15682,7 +16239,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
-  struct buffer *b = XBUFFER (w->buffer);
+  struct buffer *b = current_buffer;
 
   obj = Qnil;
   *multibyte = 0;
@@ -15784,6 +16341,20 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
       obj = b->filename;
       break;
 
+    case 'i':
+      {
+       int size = ZV - BEGV;
+       pint2str (decode_mode_spec_buf, field_width, size);
+       return decode_mode_spec_buf;
+      }
+
+    case 'I':
+      {
+       int size = ZV - BEGV;
+       pint2hrstr (decode_mode_spec_buf, field_width, size);
+       return decode_mode_spec_buf;
+      }
+
     case 'l':
       {
        int startpos = XMARKER (w->start)->charpos;
@@ -15970,7 +16541,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
 
     case 's':
       /* status of process */
-      obj = Fget_buffer_process (w->buffer);
+      obj = Fget_buffer_process (Fcurrent_buffer ());
       if (NILP (obj))
        return "no process";
 #ifdef subprocesses
@@ -16229,6 +16800,7 @@ display_string (string, lisp_string, face_string, face_string_pos,
   row->height = it->max_ascent + it->max_descent;
   row->phys_ascent = it->max_phys_ascent;
   row->phys_height = it->max_phys_ascent + it->max_phys_descent;
+  row->extra_line_spacing = it->max_extra_line_spacing;
 
   /* This condition is for the case that we are called with current_x
      past last_visible_x.  */
@@ -16288,6 +16860,8 @@ display_string (string, lisp_string, face_string, face_string_pos,
          row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
          row->phys_height = max (row->phys_height,
                                  it->max_phys_ascent + it->max_phys_descent);
+         row->extra_line_spacing = max (row->extra_line_spacing,
+                                        it->max_extra_line_spacing);
          x += glyph->pixel_width;
          ++i;
        }
@@ -16399,6 +16973,252 @@ invisible_p (propval, list)
   return 0;
 }
 
+/* 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
+     right-fringe         - right fringe width in pixels
+
+     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
@@ -16478,7 +17298,8 @@ init_glyph_string (s, OPTIONAL_HDC (hdc) char2b, w, row, area, start, hl)
   s->y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
 
   /* Display the internal border below the tool-bar window.  */
-  if (s->w == XWINDOW (s->f->tool_bar_window))
+  if (WINDOWP (s->f->tool_bar_window)
+      && s->w == XWINDOW (s->f->tool_bar_window))
     s->y -= FRAME_INTERNAL_BORDER_WIDTH (s->f);
 
   s->ybase = s->y + row->ascent;
@@ -16738,6 +17559,7 @@ fill_image_glyph_string (s)
   xassert (s->first_glyph->type == IMAGE_GLYPH);
   s->img = IMAGE_FROM_ID (s->f, s->first_glyph->u.img_id);
   xassert (s->img);
+  s->slice = s->first_glyph->slice;
   s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
   s->font = s->face->font;
   s->width = s->first_glyph->pixel_width;
@@ -17449,6 +18271,19 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
   return x_reached;
 }
 
+/* Expand row matrix if too narrow.  Don't expand if area
+   is not present.  */
+
+#define IT_EXPAND_MATRIX_WIDTH(it, area)               \
+  {                                                    \
+    if (!fonts_changed_p                               \
+       && (it->glyph_row->glyphs[area]                 \
+           < it->glyph_row->glyphs[area + 1]))         \
+      {                                                        \
+       it->w->ncols_scale_factor++;                    \
+       fonts_changed_p = 1;                            \
+      }                                                        \
+  }
 
 /* Store one glyph for IT->char_to_display in IT->glyph_row.
    Called from x_produce_glyphs when IT->glyph_row is non-null.  */
@@ -17469,6 +18304,8 @@ append_glyph (it)
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
       glyph->pixel_width = it->pixel_width;
+      glyph->ascent = it->ascent;
+      glyph->descent = it->descent;
       glyph->voffset = it->voffset;
       glyph->type = CHAR_GLYPH;
       glyph->multibyte_p = it->multibyte_p;
@@ -17480,9 +18317,12 @@ append_glyph (it)
       glyph->glyph_not_available_p = it->glyph_not_available_p;
       glyph->face_id = it->face_id;
       glyph->u.ch = it->char_to_display;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 /* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
@@ -17503,6 +18343,8 @@ append_composite_glyph (it)
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
       glyph->pixel_width = it->pixel_width;
+      glyph->ascent = it->ascent;
+      glyph->descent = it->descent;
       glyph->voffset = it->voffset;
       glyph->type = COMPOSITE_GLYPH;
       glyph->multibyte_p = it->multibyte_p;
@@ -17514,9 +18356,12 @@ append_composite_glyph (it)
       glyph->glyph_not_available_p = 0;
       glyph->face_id = it->face_id;
       glyph->u.cmp_id = it->cmp_id;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 
@@ -17532,7 +18377,7 @@ take_vertical_position_into_account (it)
       if (it->voffset < 0)
        /* Increase the ascent so that we can display the text higher
           in the line.  */
-       it->ascent += abs (it->voffset);
+       it->ascent -= it->voffset;
       else
        /* Increase the descent so that we can display the text lower
           in the line.  */
@@ -17551,20 +18396,93 @@ produce_image_glyph (it)
 {
   struct image *img;
   struct face *face;
+  int glyph_ascent;
+  struct glyph_slice slice;
 
   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);
-
-  /* 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 = image_ascent (img, face);
-  it->descent = it->phys_descent = img->height + 2 * img->vmargin - it->ascent;
-  it->pixel_width = img->width + 2 * img->hmargin;
+  slice.x = slice.y = 0;
+  slice.width = img->width;
+  slice.height = img->height;
+
+  if (INTEGERP (it->slice.x))
+    slice.x = XINT (it->slice.x);
+  else if (FLOATP (it->slice.x))
+    slice.x = XFLOAT_DATA (it->slice.x) * img->width;
+
+  if (INTEGERP (it->slice.y))
+    slice.y = XINT (it->slice.y);
+  else if (FLOATP (it->slice.y))
+    slice.y = XFLOAT_DATA (it->slice.y) * img->height;
+
+  if (INTEGERP (it->slice.width))
+    slice.width = XINT (it->slice.width);
+  else if (FLOATP (it->slice.width))
+    slice.width = XFLOAT_DATA (it->slice.width) * img->width;
+
+  if (INTEGERP (it->slice.height))
+    slice.height = XINT (it->slice.height);
+  else if (FLOATP (it->slice.height))
+    slice.height = XFLOAT_DATA (it->slice.height) * img->height;
+
+  if (slice.x >= img->width)
+    slice.x = img->width;
+  if (slice.y >= img->height)
+    slice.y = img->height;
+  if (slice.x + slice.width >= img->width)
+    slice.width = img->width - slice.x;
+  if (slice.y + slice.height > img->height)
+    slice.height = img->height - slice.y;
+
+  if (slice.width == 0 || slice.height == 0)
+    return;
+
+  it->ascent = it->phys_ascent = glyph_ascent = image_ascent (img, face, &slice);
+
+  it->descent = slice.height - glyph_ascent;
+  if (slice.y == 0)
+    it->descent += img->vmargin;
+  if (slice.y + slice.height == img->height)
+    it->descent += img->vmargin;
+  it->phys_descent = it->descent;
+
+  it->pixel_width = slice.width;
+  if (slice.x == 0)
+    it->pixel_width += img->hmargin;
+  if (slice.x + slice.width == img->width)
+    it->pixel_width += 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 0  /* this breaks image tiling */
+  /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent.  */
+  int face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
+  if (face_ascent > it->ascent)
+    it->ascent = it->phys_ascent = face_ascent;
+#endif
 
   it->nglyphs = 1;
 
@@ -17572,13 +18490,15 @@ produce_image_glyph (it)
     {
       if (face->box_line_width > 0)
        {
-         it->ascent += face->box_line_width;
-         it->descent += face->box_line_width;
+         if (slice.y == 0)
+           it->ascent += face->box_line_width;
+         if (slice.y + slice.height == img->height)
+           it->descent += face->box_line_width;
        }
 
-      if (it->start_of_box_run_p)
+      if (it->start_of_box_run_p && slice.x == 0)
        it->pixel_width += abs (face->box_line_width);
-      if (it->end_of_box_run_p)
+      if (it->end_of_box_run_p && slice.x + slice.width == img->width)
        it->pixel_width += abs (face->box_line_width);
     }
 
@@ -17595,6 +18515,8 @@ produce_image_glyph (it)
          glyph->charpos = CHARPOS (it->position);
          glyph->object = it->object;
          glyph->pixel_width = it->pixel_width;
+         glyph->ascent = glyph_ascent;
+         glyph->descent = it->descent;
          glyph->voffset = it->voffset;
          glyph->type = IMAGE_GLYPH;
          glyph->multibyte_p = it->multibyte_p;
@@ -17605,29 +18527,31 @@ produce_image_glyph (it)
          glyph->glyph_not_available_p = 0;
          glyph->face_id = it->face_id;
          glyph->u.img_id = img->id;
+         glyph->slice = slice;
          glyph->font_type = FONT_TYPE_UNKNOWN;
          ++it->glyph_row->used[area];
        }
+      else
+       IT_EXPAND_MATRIX_WIDTH (it, area);
     }
 }
 
 
 /* Append a stretch glyph to IT->glyph_row.  OBJECT is the source
    of the glyph, WIDTH and HEIGHT are the width and height of the
-   stretch.  ASCENT is the percentage/100 of HEIGHT to use for the
-   ascent of the glyph (0 <= ASCENT <= 1).  */
+   stretch.  ASCENT is the ascent of the glyph (0 <= ASCENT <= HEIGHT).  */
 
 static void
 append_stretch_glyph (it, object, width, height, ascent)
      struct it *it;
      Lisp_Object object;
      int width, height;
-     double ascent;
+     int ascent;
 {
   struct glyph *glyph;
   enum glyph_row_area area = it->area;
 
-  xassert (ascent >= 0 && ascent <= 1);
+  xassert (ascent >= 0 && ascent <= height);
 
   glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
   if (glyph < it->glyph_row->glyphs[area + 1])
@@ -17635,6 +18559,8 @@ append_stretch_glyph (it, object, width, height, ascent)
       glyph->charpos = CHARPOS (it->position);
       glyph->object = object;
       glyph->pixel_width = width;
+      glyph->ascent = ascent;
+      glyph->descent = height - ascent;
       glyph->voffset = it->voffset;
       glyph->type = STRETCH_GLYPH;
       glyph->multibyte_p = it->multibyte_p;
@@ -17644,11 +18570,14 @@ append_stretch_glyph (it, object, width, height, ascent)
       glyph->padding_p = 0;
       glyph->glyph_not_available_p = 0;
       glyph->face_id = it->face_id;
-      glyph->u.stretch.ascent = height * ascent;
+      glyph->u.stretch.ascent = ascent;
       glyph->u.stretch.height = height;
+      glyph->slice = null_glyph_slice;
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 
@@ -17683,20 +18612,16 @@ append_stretch_glyph (it, object, width, height, ascent)
    of the stretch should be used for the ascent of the stretch.
    ASCENT must be in the range 0 <= ASCENT <= 100.  */
 
-#define NUMVAL(X)                              \
-     ((INTEGERP (X) || FLOATP (X))             \
-      ? XFLOATINT (X)                          \
-      : - 1)
-
-
 static void
 produce_stretch_glyph (it)
      struct it *it;
 {
-  /* (space :width WIDTH :height HEIGHT.  */
+  /* (space :width WIDTH :height HEIGHT ...)  */
   Lisp_Object prop, plist;
-  int width = 0, height = 0;
-  double ascent = 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;
   struct face *face = FACE_FROM_ID (it->f, it->face_id);
   XFontStruct *font = face->font ? face->font : FRAME_FONT (it->f);
 
@@ -17707,11 +18632,14 @@ produce_stretch_glyph (it)
   plist = XCDR (it->object);
 
   /* Compute the width of the stretch.  */
-  if (prop = Fplist_get (plist, QCwidth),
-      NUMVAL (prop) > 0)
-    /* Absolute width `:width WIDTH' specified and valid.  */
-    width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f);
-  else if (prop = Fplist_get (plist, QCrelative_width),
+  if ((prop = Fsafe_plist_get (plist, QCwidth), !NILP (prop))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 1, 0))
+    {
+      /* Absolute width `:width WIDTH' specified and valid.  */
+      zero_width_ok_p = 1;
+      width = (int)tem;
+    }
+  else if (prop = Fsafe_plist_get (plist, QCrelative_width),
           NUMVAL (prop) > 0)
     {
       /* Relative width `:relative-width FACTOR' specified and valid.
@@ -17735,38 +18663,54 @@ produce_stretch_glyph (it)
       x_produce_glyphs (&it2);
       width = NUMVAL (prop) * it2.pixel_width;
     }
-  else if (prop = Fplist_get (plist, QCalign_to),
-          NUMVAL (prop) > 0)
-    width = NUMVAL (prop) * FRAME_COLUMN_WIDTH (it->f) - it->current_x;
+  else if ((prop = Fsafe_plist_get (plist, QCalign_to), !NILP (prop))
+          && 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
     /* Nothing specified -> width defaults to canonical char width.  */
     width = FRAME_COLUMN_WIDTH (it->f);
 
+  if (width <= 0 && (width < 0 || !zero_width_ok_p))
+    width = 1;
+
   /* Compute height.  */
-  if (prop = Fplist_get (plist, QCheight),
-      NUMVAL (prop) > 0)
-    height = NUMVAL (prop) * FRAME_LINE_HEIGHT (it->f);
-  else if (prop = Fplist_get (plist, QCrelative_height),
+  if ((prop = Fsafe_plist_get (plist, QCheight), !NILP (prop))
+      && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
+    {
+      height = (int)tem;
+      zero_height_ok_p = 1;
+    }
+  else if (prop = Fsafe_plist_get (plist, QCrelative_height),
           NUMVAL (prop) > 0)
     height = FONT_HEIGHT (font) * NUMVAL (prop);
   else
     height = FONT_HEIGHT (font);
 
+  if (height <= 0 && (height < 0 || !zero_height_ok_p))
+    height = 1;
+
   /* Compute percentage of height used for ascent.  If
      `:ascent ASCENT' is present and valid, use that.  Otherwise,
      derive the ascent from the font in use.  */
-  if (prop = Fplist_get (plist, QCascent),
+  if (prop = Fsafe_plist_get (plist, QCascent),
       NUMVAL (prop) > 0 && NUMVAL (prop) <= 100)
-    ascent = NUMVAL (prop) / 100.0;
+    ascent = height * NUMVAL (prop) / 100.0;
+  else if (!NILP (prop)
+          && calc_pixel_width_or_height (&tem, it, prop, font, 0, 0))
+    ascent = min (max (0, (int)tem), height);
   else
-    ascent = (double) FONT_BASE (font) / FONT_HEIGHT (font);
+    ascent = (height * FONT_BASE (font)) / FONT_HEIGHT (font);
 
-  if (width <= 0)
-    width = 1;
-  if (height <= 0)
-    height = 1;
-
-  if (it->glyph_row)
+  if (width > 0 && height > 0 && it->glyph_row)
     {
       Lisp_Object object = it->stack[it->sp - 1].string;
       if (!STRINGP (object))
@@ -17775,11 +18719,11 @@ produce_stretch_glyph (it)
     }
 
   it->pixel_width = width;
-  it->ascent = it->phys_ascent = height * ascent;
+  it->ascent = it->phys_ascent = ascent;
   it->descent = it->phys_descent = height - it->ascent;
-  it->nglyphs = 1;
+  it->nglyphs = width > 0 && height > 0 ? 1 : 0;
 
-  if (face->box != FACE_NO_BOX)
+  if (width > 0 && height > 0 && face->box != FACE_NO_BOX)
     {
       if (face->box_line_width > 0)
        {
@@ -17796,6 +18740,109 @@ produce_stretch_glyph (it)
   take_vertical_position_into_account (it);
 }
 
+/* Calculate line-height and line-spacing properties.
+   An integer value specifies explicit pixel value.
+   A float value specifies relative value to current face height.
+   A cons (float . face-name) specifies relative value to
+   height of specified face font.
+
+   Returns height in pixels, or nil.  */
+
+static Lisp_Object
+calc_line_height_property (it, prop, font, boff, total)
+     struct it *it;
+     Lisp_Object prop;
+     XFontStruct *font;
+     int boff, *total;
+{
+  Lisp_Object position, val;
+  Lisp_Object face_name = Qnil;
+  int ascent, descent, height, override;
+
+  if (STRINGP (it->object))
+    position = make_number (IT_STRING_CHARPOS (*it));
+  else if (BUFFERP (it->object))
+    position = make_number (IT_CHARPOS (*it));
+  else
+    return Qnil;
+
+  val = Fget_char_property (position, prop, it->object);
+
+  if (NILP (val))
+    return val;
+
+  if (total && CONSP (val) && EQ (XCAR (val), Qtotal))
+    {
+      *total = 1;
+      val = XCDR (val);
+    }
+
+  if (INTEGERP (val))
+    return val;
+
+  if (CONSP (val))
+    {
+      face_name = XCDR (val);
+      val = XCAR (val);
+    }
+  else if (SYMBOLP (val))
+    {
+      face_name = val;
+      val = Qnil;
+    }
+
+  override = EQ (prop, Qline_height);
+
+  if (NILP (face_name))
+    {
+      font = FRAME_FONT (it->f);
+      boff = FRAME_BASELINE_OFFSET (it->f);
+    }
+  else if (EQ (face_name, Qt))
+    {
+      override = 0;
+    }
+  else
+    {
+      int face_id;
+      struct face *face;
+      struct font_info *font_info;
+
+      face_id = lookup_named_face (it->f, face_name, ' ');
+      if (face_id < 0)
+       return make_number (-1);
+
+      face = FACE_FROM_ID (it->f, face_id);
+      font = face->font;
+      if (font == NULL)
+       return make_number (-1);
+
+      font_info = FONT_INFO_FROM_ID (it->f, face->font_info_id);
+      boff = font_info->baseline_offset;
+      if (font_info->vertical_centering)
+       boff = VCENTER_BASELINE_OFFSET (font, it->f) - boff;
+    }
+
+  ascent = FONT_BASE (font) + boff;
+  descent = FONT_DESCENT (font) - boff;
+
+  if (override)
+    {
+      it->override_ascent = ascent;
+      it->override_descent = descent;
+      it->override_boff = boff;
+    }
+
+  height = ascent + descent;
+  if (FLOATP (val))
+    height = (int)(XFLOAT_DATA (val) * height);
+  else if (INTEGERP (val))
+    height *= XINT (val);
+
+  return make_number (height);
+}
+
+
 /* RIF:
    Produce glyphs/get display metrics for the display element IT is
    loaded with.  See the description of struct display_iterator in
@@ -17805,6 +18852,8 @@ void
 x_produce_glyphs (it)
      struct it *it;
 {
+  int extra_line_spacing = it->extra_line_spacing;
+
   it->glyph_not_available_p = 0;
 
   if (it->what == IT_CHARACTER)
@@ -17882,8 +18931,18 @@ x_produce_glyphs (it)
 
          pcm = rif->per_char_metric (font, &char2b,
                                      FONT_TYPE_FOR_UNIBYTE (font, it->char_to_display));
-         it->ascent = FONT_BASE (font) + boff;
-         it->descent = FONT_DESCENT (font) - boff;
+
+         if (it->override_ascent >= 0)
+           {
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
+           }
 
          if (pcm)
            {
@@ -17894,11 +18953,28 @@ x_produce_glyphs (it)
          else
            {
              it->glyph_not_available_p = 1;
-              it->phys_ascent = FONT_BASE (font) + boff;
-              it->phys_descent = FONT_DESCENT (font) - boff;
+             it->phys_ascent = it->ascent;
+             it->phys_descent = it->descent;
              it->pixel_width = FONT_WIDTH (font);
            }
 
+         if (it->constrain_row_ascent_descent_p)
+           {
+             if (it->descent > it->max_descent)
+               {
+                 it->ascent += it->descent - it->max_descent;
+                 it->descent = it->max_descent;
+               }
+             if (it->ascent > it->max_ascent)
+               {
+                 it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+                 it->ascent = it->max_ascent;
+               }
+             it->phys_ascent = min (it->phys_ascent, it->ascent);
+             it->phys_descent = min (it->phys_descent, it->descent);
+             extra_line_spacing = 0;
+           }
+
          /* If this is a space inside a region of text with
             `space-width' property, change its width.  */
          stretched_p = it->char_to_display == ' ' && !NILP (it->space_width);
@@ -17931,6 +19007,14 @@ x_produce_glyphs (it)
          if (face->overline_p)
            it->ascent += 2;
 
+         if (it->constrain_row_ascent_descent_p)
+           {
+             if (it->ascent > it->max_ascent)
+               it->ascent = it->max_ascent;
+             if (it->descent > it->max_descent)
+               it->descent = it->max_descent;
+           }
+
          take_vertical_position_into_account (it);
 
          /* If we have to actually produce glyphs, do it.  */
@@ -17940,8 +19024,8 @@ x_produce_glyphs (it)
                {
                  /* Translate a space with a `space-width' property
                     into a stretch glyph.  */
-                 double ascent = (double) FONT_BASE (font)
-                                / FONT_HEIGHT (font);
+                 int ascent = (((it->ascent + it->descent) * FONT_BASE (font))
+                               / FONT_HEIGHT (font));
                  append_stretch_glyph (it, it->object, it->pixel_width,
                                        it->ascent + it->descent, ascent);
                }
@@ -17957,17 +19041,73 @@ x_produce_glyphs (it)
        }
       else if (it->char_to_display == '\n')
        {
-         /* A newline has no width but we need the height of the line.  */
+         /* A newline has no width but we need the height of the line.
+            But if previous part of the line set a height, don't
+            increase that height */
+
+         Lisp_Object height;
+
+         it->override_ascent = -1;
          it->pixel_width = 0;
          it->nglyphs = 0;
-         it->ascent = it->phys_ascent = FONT_BASE (font) + boff;
-         it->descent = it->phys_descent = FONT_DESCENT (font) - boff;
 
-         if (face->box != FACE_NO_BOX
-             && face->box_line_width > 0)
+         height = calc_line_height_property(it, Qline_height, font, boff, 0);
+
+         if (it->override_ascent >= 0)
+           {
+             it->ascent = it->override_ascent;
+             it->descent = it->override_descent;
+             boff = it->override_boff;
+           }
+         else
+           {
+             it->ascent = FONT_BASE (font) + boff;
+             it->descent = FONT_DESCENT (font) - boff;
+           }
+
+         if (EQ (height, make_number(0)))
+           {
+             if (it->descent > it->max_descent)
+               {
+                 it->ascent += it->descent - it->max_descent;
+                 it->descent = it->max_descent;
+               }
+             if (it->ascent > it->max_ascent)
+               {
+                 it->descent = min (it->max_descent, it->descent + it->ascent - it->max_ascent);
+                 it->ascent = it->max_ascent;
+               }
+             it->phys_ascent = min (it->phys_ascent, it->ascent);
+             it->phys_descent = min (it->phys_descent, it->descent);
+             it->constrain_row_ascent_descent_p = 1;
+             extra_line_spacing = 0;
+           }
+         else
            {
-             it->ascent += face->box_line_width;
-             it->descent += face->box_line_width;
+             Lisp_Object spacing;
+             int total = 0;
+
+             it->phys_ascent = it->ascent;
+             it->phys_descent = it->descent;
+
+             if ((it->max_ascent > 0 || it->max_descent > 0)
+                 && face->box != FACE_NO_BOX
+                 && face->box_line_width > 0)
+               {
+                 it->ascent += face->box_line_width;
+                 it->descent += face->box_line_width;
+               }
+             if (!NILP (height)
+                 && XINT (height) > it->ascent + it->descent)
+               it->ascent = XINT (height) - it->descent;
+
+             spacing = calc_line_height_property(it, Qline_spacing, font, boff, &total);
+             if (INTEGERP (spacing))
+               {
+                 extra_line_spacing = XINT (spacing);
+                 if (total)
+                   extra_line_spacing -= (it->phys_ascent + it->phys_descent);
+               }
            }
        }
       else if (it->char_to_display == '\t')
@@ -17989,9 +19129,8 @@ x_produce_glyphs (it)
 
          if (it->glyph_row)
            {
-             double ascent = (double) it->ascent / (it->ascent + it->descent);
              append_stretch_glyph (it, it->object, it->pixel_width,
-                                   it->ascent + it->descent, ascent);
+                                   it->ascent + it->descent, it->ascent);
            }
        }
       else
@@ -18346,7 +19485,12 @@ x_produce_glyphs (it)
   if (it->area == TEXT_AREA)
     it->current_x += it->pixel_width;
 
-  it->descent += it->extra_line_spacing;
+  if (extra_line_spacing > 0)
+    {
+      it->descent += extra_line_spacing;
+      if (extra_line_spacing > it->max_extra_line_spacing)
+       it->max_extra_line_spacing = extra_line_spacing;
+    }
 
   it->max_ascent = max (it->max_ascent, it->ascent);
   it->max_descent = max (it->max_descent, it->descent);
@@ -18534,7 +19678,7 @@ x_clear_end_of_line (to_x)
    ARG.  If type is BAR_CURSOR, return in *WIDTH the specified width
    of the bar cursor.  */
 
-enum text_cursor_kinds
+static enum text_cursor_kinds
 get_specified_cursor_type (arg, width)
      Lisp_Object arg;
      int *width;
@@ -18625,9 +19769,10 @@ set_frame_cursor_types (f, arg)
    setting of cursor-type.  If explicitly marked off, draw no cursor.
    In all other cases, we want a hollow box cursor.  */
 
-enum text_cursor_kinds
-get_window_cursor_type (w, width, active_cursor)
+static enum text_cursor_kinds
+get_window_cursor_type (w, glyph, width, active_cursor)
      struct window *w;
+     struct glyph *glyph;
      int *width;
      int *active_cursor;
 {
@@ -18691,7 +19836,13 @@ get_window_cursor_type (w, width, active_cursor)
 
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
-    return cursor_type;
+    {
+      if (glyph != NULL && glyph->type == IMAGE_GLYPH) {
+       if (cursor_type == FILLED_BOX_CURSOR)
+         cursor_type = HOLLOW_BOX_CURSOR;
+      }
+      return cursor_type;
+    }
 
   /* Cursor is blinked off, so determine how to "toggle" it.  */
 
@@ -18706,6 +19857,11 @@ get_window_cursor_type (w, width, active_cursor)
       return FRAME_BLINK_OFF_CURSOR (f);
     }
 
+#if 0
+  /* Some people liked having a permanently visible blinking cursor,
+     while others had very strong opinions against it.  So it was
+     decided to remove it.  KFS 2003-09-03 */
+
   /* Finally perform built-in cursor blinking:
        filled box      <->   hollow box
        wide [h]bar     <->   narrow [h]bar
@@ -18720,6 +19876,7 @@ get_window_cursor_type (w, width, active_cursor)
       *width = 1;
       return cursor_type;
     }
+#endif
 
   return NO_CURSOR;
 }
@@ -18740,36 +19897,53 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1)
      enum glyph_row_area area;
      int x0, y0, x1, y1;
 {
-  if (area == TEXT_AREA && w->phys_cursor_on_p)
-    {
-      int cx0 = w->phys_cursor.x;
-      int cx1 = cx0 + w->phys_cursor_width;
-      int cy0 = w->phys_cursor.y;
-      int cy1 = cy0 + w->phys_cursor_height;
+  int cx0, cx1, cy0, cy1;
+  struct glyph_row *row;
 
-      if (x0 <= cx0 && (x1 < 0 || x1 >= cx1))
-       {
-         /* The cursor image will be completely removed from the
-            screen if the output area intersects the cursor area in
-            y-direction.  When we draw in [y0 y1[, and some part of
-            the cursor is at y < y0, that part must have been drawn
-            before.  When scrolling, the cursor is erased before
-            actually scrolling, so we don't come here.  When not
-            scrolling, the rows above the old cursor row must have
-            changed, and in this case these rows must have written
-            over the cursor image.
+  if (!w->phys_cursor_on_p)
+    return;
+  if (area != TEXT_AREA)
+    return;
 
-            Likewise if part of the cursor is below y1, with the
-            exception of the cursor being in the first blank row at
-            the buffer and window end because update_text_area
-            doesn't draw that row.  (Except when it does, but
-            that's handled in update_text_area.)  */
+  row = w->current_matrix->rows + w->phys_cursor.vpos;
+  if (!row->displays_text_p)
+    return;
 
-         if (((y0 >= cy0 && y0 < cy1) || (y1 > cy0 && y1 < cy1))
-             && w->current_matrix->rows[w->phys_cursor.vpos].displays_text_p)
-           w->phys_cursor_on_p = 0;
-       }
+  if (row->cursor_in_fringe_p)
+    {
+      row->cursor_in_fringe_p = 0;
+      draw_fringe_bitmap (w, row, 0);
+      w->phys_cursor_on_p = 0;
+      return;
     }
+
+  cx0 = w->phys_cursor.x;
+  cx1 = cx0 + w->phys_cursor_width;
+  if (x0 > cx0 || (x1 >= 0 && x1 < cx1))
+    return;
+
+  /* The cursor image will be completely removed from the
+     screen if the output area intersects the cursor area in
+     y-direction.  When we draw in [y0 y1[, and some part of
+     the cursor is at y < y0, that part must have been drawn
+     before.  When scrolling, the cursor is erased before
+     actually scrolling, so we don't come here.  When not
+     scrolling, the rows above the old cursor row must have
+     changed, and in this case these rows must have written
+     over the cursor image.
+
+     Likewise if part of the cursor is below y1, with the
+     exception of the cursor being in the first blank row at
+     the buffer and window end because update_text_area
+     doesn't draw that row.  (Except when it does, but
+     that's handled in update_text_area.)  */
+
+  cy0 = w->phys_cursor.y;
+  cy1 = cy0 + w->phys_cursor_height;
+  if ((y0 < cy0 || y0 >= cy1) && (y1 <= cy0 || y1 >= cy1))
+    return;
+
+  w->phys_cursor_on_p = 0;
 }
 
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -18898,12 +20072,25 @@ erase_phys_cursor (w)
   if (!cursor_row->enabled_p)
     goto mark_cursor_off;
 
+  /* If line spacing is > 0, old cursor may only be partially visible in
+     window after split-window.  So adjust visible height.  */
+  cursor_row->visible_height = min (cursor_row->visible_height,
+                                   window_text_bottom_y (w) - cursor_row->y);
+
   /* If row is completely invisible, don't attempt to delete a cursor which
      isn't there.  This can happen if cursor is at top of a window, and
      we switch to a buffer with a header line in that window.  */
   if (cursor_row->visible_height <= 0)
     goto mark_cursor_off;
 
+  /* If cursor is in the fringe, erase by drawing actual bitmap there.  */
+  if (cursor_row->cursor_in_fringe_p)
+    {
+      cursor_row->cursor_in_fringe_p = 0;
+      draw_fringe_bitmap (w, cursor_row, 0);
+      goto mark_cursor_off;
+    }
+
   /* This can happen when the new row is shorter than the old one.
      In this case, either draw_glyphs or clear_end_of_line
      should have cleared the cursor.  Note that we wouldn't be
@@ -18933,6 +20120,7 @@ erase_phys_cursor (w)
     {
       int x, y;
       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+      int width;
 
       cursor_glyph = get_phys_cursor_glyph (w);
       if (cursor_glyph == NULL)
@@ -18940,9 +20128,10 @@ erase_phys_cursor (w)
 
       x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
       y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
+      width = min (cursor_glyph->pixel_width,
+                  window_box_width (w, TEXT_AREA) - w->phys_cursor.x);
 
-      rif->clear_frame_area (f, x, y,
-                            cursor_glyph->pixel_width, cursor_row->visible_height);
+      rif->clear_frame_area (f, x, y, width, cursor_row->visible_height);
     }
 
   /* Erase the cursor by redrawing the character underneath it.  */
@@ -18972,7 +20161,6 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
   int new_cursor_type;
   int new_cursor_width;
   int active_cursor;
-  struct glyph_matrix *current_glyphs;
   struct glyph_row *glyph_row;
   struct glyph *glyph;
 
@@ -18990,10 +20178,7 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
   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)
@@ -19002,10 +20187,16 @@ display_and_set_cursor (w, on, hpos, vpos, x, y)
       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.  */
-  new_cursor_type = get_window_cursor_type (w, &new_cursor_width, &active_cursor);
+  new_cursor_type = get_window_cursor_type (w, glyph,
+                                           &new_cursor_width, &active_cursor);
 
   /* If cursor is currently being shown and we don't want it to be or
      it is in the wrong place, or the cursor type is not what we want,
@@ -19202,7 +20393,7 @@ clear_mouse_face (dpyinfo)
 {
   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;
@@ -19273,19 +20464,20 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
   int past_end = 0;
 
   first = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  if (charpos < MATRIX_ROW_START_CHARPOS (first))
+    {
+      *x = first->x;
+      *y = first->y;
+      *hpos = 0;
+      *vpos = MATRIX_ROW_VPOS (first, w->current_matrix);
+      return 1;
+    }
+
   row = row_containing_pos (w, charpos, first, NULL, 0);
   if (row == NULL)
     {
-      if (charpos < MATRIX_ROW_START_CHARPOS (first))
-       {
-         *x = *y = *hpos = *vpos = 0;
-         return 0;
-       }
-      else
-       {
-         row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
-         past_end = 1;
-       }
+      row = MATRIX_ROW (w->current_matrix, XFASTINT (w->window_end_vpos));
+      past_end = 1;
     }
 
   *x = row->x;
@@ -19319,7 +20511,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
     }
 
   *hpos = glyph - row->glyphs[TEXT_AREA];
-  return past_end;
+  return !past_end;
 }
 
 #else /* not 1 */
@@ -19505,6 +20697,186 @@ fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
 }
 
 
+/* See if position X, Y is within a hot-spot of an image.  */
+
+static int
+on_hot_spot_p (hot_spot, x, y)
+     Lisp_Object hot_spot;
+     int x, y;
+{
+  if (!CONSP (hot_spot))
+    return 0;
+
+  if (EQ (XCAR (hot_spot), Qrect))
+    {
+      /* CDR is (Top-Left . Bottom-Right) = ((x0 . y0) . (x1 . y1))  */
+      Lisp_Object rect = XCDR (hot_spot);
+      Lisp_Object tem;
+      if (!CONSP (rect))
+       return 0;
+      if (!CONSP (XCAR (rect)))
+       return 0;
+      if (!CONSP (XCDR (rect)))
+       return 0;
+      if (!(tem = XCAR (XCAR (rect)), INTEGERP (tem) && x >= XINT (tem)))
+       return 0;
+      if (!(tem = XCDR (XCAR (rect)), INTEGERP (tem) && y >= XINT (tem)))
+       return 0;
+      if (!(tem = XCAR (XCDR (rect)), INTEGERP (tem) && x <= XINT (tem)))
+       return 0;
+      if (!(tem = XCDR (XCDR (rect)), INTEGERP (tem) && y <= XINT (tem)))
+       return 0;
+      return 1;
+    }
+  else if (EQ (XCAR (hot_spot), Qcircle))
+    {
+      /* CDR is (Center . Radius) = ((x0 . y0) . r) */
+      Lisp_Object circ = XCDR (hot_spot);
+      Lisp_Object lr, lx0, ly0;
+      if (CONSP (circ)
+         && CONSP (XCAR (circ))
+         && (lr = XCDR (circ), INTEGERP (lr) || FLOATP (lr))
+         && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0))
+         && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0)))
+       {
+         double r = XFLOATINT (lr);
+         double dx = XINT (lx0) - x;
+         double dy = XINT (ly0) - y;
+         return (dx * dx + dy * dy <= r * r);
+       }
+    }
+  else if (EQ (XCAR (hot_spot), Qpoly))
+    {
+      /* CDR is [x0 y0 x1 y1 x2 y2 ...x(n-1) y(n-1)] */
+      if (VECTORP (XCDR (hot_spot)))
+       {
+         struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
+         Lisp_Object *poly = v->contents;
+         int n = v->size;
+         int i;
+         int inside = 0;
+         Lisp_Object lx, ly;
+         int x0, y0;
+
+         /* Need an even number of coordinates, and at least 3 edges.  */
+         if (n < 6 || n & 1)
+           return 0;
+
+         /* Count edge segments intersecting line from (X,Y) to (X,infinity).
+            If count is odd, we are inside polygon.  Pixels on edges
+            may or may not be included depending on actual geometry of the
+            polygon.  */
+         if ((lx = poly[n-2], !INTEGERP (lx))
+             || (ly = poly[n-1], !INTEGERP (lx)))
+           return 0;
+         x0 = XINT (lx), y0 = XINT (ly);
+         for (i = 0; i < n; i += 2)
+           {
+             int x1 = x0, y1 = y0;
+             if ((lx = poly[i], !INTEGERP (lx))
+                 || (ly = poly[i+1], !INTEGERP (ly)))
+               return 0;
+             x0 = XINT (lx), y0 = XINT (ly);
+
+             /* Does this segment cross the X line?  */
+             if (x0 >= x)
+               {
+                 if (x1 >= x)
+                   continue;
+               }
+             else if (x1 < x)
+               continue;
+             if (y > y0 && y > y1)
+               continue;
+             if (y < y0 + ((y1 - y0) * (x - x0)) / (x1 - x0))
+               inside = !inside;
+           }
+         return inside;
+       }
+    }
+  /* If we don't understand the format, pretend we're not in the hot-spot.  */
+  return 0;
+}
+
+Lisp_Object
+find_hot_spot (map, x, y)
+     Lisp_Object map;
+     int x, y;
+{
+  while (CONSP (map))
+    {
+      if (CONSP (XCAR (map))
+         && on_hot_spot_p (XCAR (XCAR (map)), x, y))
+       return XCAR (map);
+      map = XCDR (map);
+    }
+
+  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.
+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
+pixel coordinates of the upper left and bottom right corners.
+A circle is a cons (circle . ((x0 . y0) . r)) specifying the center
+and the radius of the circle; r may be a float or integer.
+A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the
+vector describes one corner in the polygon.
+Returns the alist element for the first matching AREA in MAP.  */)
+  (map, x, y)
+     Lisp_Object map;
+     Lisp_Object x, y;
+{
+  if (NILP (map))
+    return Qnil;
+
+  CHECK_NUMBER (x);
+  CHECK_NUMBER (y);
+
+  return find_hot_spot (map, XINT (x), XINT (y));
+}
+
+
+/* Display frame CURSOR, optionally using shape defined by POINTER.  */
+static void
+define_frame_cursor1 (f, cursor, pointer)
+     struct frame *f;
+     Cursor cursor;
+     Lisp_Object pointer;
+{
+  /* Do not change cursor shape while dragging mouse.  */
+  if (!NILP (do_mouse_tracking))
+    return;
+
+  if (!NILP (pointer))
+    {
+      if (EQ (pointer, Qarrow))
+       cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+      else if (EQ (pointer, Qhand))
+       cursor = FRAME_X_OUTPUT (f)->hand_cursor;
+      else if (EQ (pointer, Qtext))
+       cursor = FRAME_X_OUTPUT (f)->text_cursor;
+      else if (EQ (pointer, intern ("hdrag")))
+       cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+#ifdef HAVE_X_WINDOWS
+      else if (EQ (pointer, intern ("vdrag")))
+       cursor = FRAME_X_DISPLAY_INFO (f)->vertical_scroll_bar_cursor;
+#endif
+      else if (EQ (pointer, intern ("hourglass")))
+       cursor = FRAME_X_OUTPUT (f)->hourglass_cursor;
+      else if (EQ (pointer, Qmodeline))
+       cursor = FRAME_X_OUTPUT (f)->modeline_cursor;
+      else
+       cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+    }
+
+  if (cursor != No_Cursor)
+    rif->define_frame_cursor (f, cursor);
+}
+
 /* Take proper action when mouse has moved to the mode or header line
    or marginal area AREA of window W, x-position X and y-position Y.
    X is relative to the start of the text display area of W, so the
@@ -19519,40 +20891,95 @@ note_mode_line_or_margin_highlight (w, x, y, area)
 {
   struct frame *f = XFRAME (w->frame);
   Display_Info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
-  Cursor cursor = dpyinfo->vertical_scroll_bar_cursor;
-  int charpos;
-  Lisp_Object string, help, map, pos;
+  Cursor cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+  Lisp_Object pointer = Qnil;
+  int charpos, dx, dy, width, height;
+  Lisp_Object string, object = Qnil;
+  Lisp_Object pos, help;
 
   if (area == ON_MODE_LINE || area == ON_HEADER_LINE)
-    string = mode_line_string (w, x, y, area, &charpos);
+    string = mode_line_string (w, area, &x, &y, &charpos,
+                              &object, &dx, &dy, &width, &height);
   else
-    string = marginal_area_string (w, x, y, area, &charpos);
+    {
+      x -= WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w);
+      string = marginal_area_string (w, area, &x, &y, &charpos,
+                                    &object, &dx, &dy, &width, &height);
+    }
+
+  help = Qnil;
+
+  if (IMAGEP (object))
+    {
+      Lisp_Object image_map, hotspot;
+      if ((image_map = Fsafe_plist_get (XCDR (object), QCmap),
+          !NILP (image_map))
+         && (hotspot = find_hot_spot (image_map, dx, dy),
+             CONSP (hotspot))
+         && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+       {
+         Lisp_Object area_id, plist;
+
+         area_id = XCAR (hotspot);
+         /* Could check AREA_ID to see if we enter/leave this hot-spot.
+            If so, we could look for mouse-enter, mouse-leave
+            properties in PLIST (and do something...).  */
+         hotspot = XCDR (hotspot);
+         if (CONSP (hotspot)
+             && (plist = XCAR (hotspot), CONSP (plist)))
+           {
+             pointer = Fsafe_plist_get (plist, Qpointer);
+             if (NILP (pointer))
+               pointer = Qhand;
+             help = Fsafe_plist_get (plist, Qhelp_echo);
+             if (!NILP (help))
+               {
+                 help_echo_string = help;
+                 /* Is this correct?  ++kfs */
+                 XSETWINDOW (help_echo_window, w);
+                 help_echo_object = w->buffer;
+                 help_echo_pos = charpos;
+               }
+           }
+         if (NILP (pointer))
+           pointer = Fsafe_plist_get (XCDR (object), QCpointer);
+       }
+    }
 
   if (STRINGP (string))
     {
       pos = make_number (charpos);
-
       /* If we're on a string with `help-echo' text property, arrange
         for the help to be displayed.  This is done by setting the
         global variable help_echo_string to the help string.  */
-      help = Fget_text_property (pos, Qhelp_echo, string);
-      if (!NILP (help))
+      if (NILP (help))
        {
-         help_echo_string = help;
-         XSETWINDOW (help_echo_window, w);
-         help_echo_object = string;
-         help_echo_pos = charpos;
+         help = Fget_text_property (pos, Qhelp_echo, string);
+         if (!NILP (help))
+           {
+             help_echo_string = help;
+             XSETWINDOW (help_echo_window, w);
+             help_echo_object = string;
+             help_echo_pos = charpos;
+           }
        }
 
+      if (NILP (pointer))
+       pointer = Fget_text_property (pos, Qpointer, string);
+
      /* Change the mouse pointer according to what is under X/Y.  */
-      map = Fget_text_property (pos, Qlocal_map, string);
-      if (!KEYMAPP (map))
-       map = Fget_text_property (pos, Qkeymap, string);
-      if (KEYMAPP (map))
-       cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+      if (NILP (pointer) && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE)))
+       {
+         Lisp_Object map;
+         map = Fget_text_property (pos, Qlocal_map, string);
+         if (!KEYMAPP (map))
+           map = Fget_text_property (pos, Qkeymap, string);
+         if (!KEYMAPP (map))
+           cursor = dpyinfo->vertical_scroll_bar_cursor;
+       }
     }
 
-  rif->define_frame_cursor (f, cursor);
+  define_frame_cursor1 (f, cursor, pointer);
 }
 
 
@@ -19572,6 +20999,7 @@ note_mouse_highlight (f, x, y)
   Lisp_Object window;
   struct window *w;
   Cursor cursor = No_Cursor;
+  Lisp_Object pointer = Qnil;  /* Takes precedence over cursor!  */
   struct buffer *b;
 
   /* When a menu is active, don't highlight because this looks odd.  */
@@ -19600,8 +21028,10 @@ note_mouse_highlight (f, x, y)
   /* Which window is that in?  */
   window = window_from_coordinates (f, x, y, &part, 0, 0, 1);
 
-  /* If we were displaying active text in another window, clear that.  */
-  if (! EQ (window, dpyinfo->mouse_face_window))
+  /* If we were displaying active text in another window, clear that.
+     Also clear if we move out of text area in same window.  */
+  if (! EQ (window, dpyinfo->mouse_face_window)
+      || (part != ON_TEXT && !NILP (dpyinfo->mouse_face_window)))
     clear_mouse_face (dpyinfo);
 
   /* Not on a window -> return.  */
@@ -19609,7 +21039,6 @@ note_mouse_highlight (f, x, y)
     return;
 
   /* Reset help_echo_string. It will get recomputed below.  */
-  /* ++KFS: X version didn't do this, but it looks harmless.  */
   help_echo_string = Qnil;
 
   /* Convert to window-relative pixel coordinates.  */
@@ -19634,6 +21063,9 @@ note_mouse_highlight (f, x, y)
 
   if (part == ON_VERTICAL_BORDER)
     cursor = FRAME_X_OUTPUT (f)->horizontal_drag_cursor;
+  else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE
+          || part == ON_SCROLL_BAR)
+    cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
   else
     cursor = FRAME_X_OUTPUT (f)->text_cursor;
 
@@ -19645,31 +21077,74 @@ note_mouse_highlight (f, x, y)
       && XFASTINT (w->last_modified) == BUF_MODIFF (b)
       && XFASTINT (w->last_overlay_modified) == BUF_OVERLAY_MODIFF (b))
     {
-      int hpos, vpos, pos, i, area;
+      int hpos, vpos, pos, i, dx, dy, area;
       struct glyph *glyph;
       Lisp_Object object;
       Lisp_Object mouse_face = Qnil, overlay = Qnil, position;
       Lisp_Object *overlay_vec = NULL;
-      int len, noverlays;
+      int noverlays;
       struct buffer *obuf;
       int obegv, ozv, same_region;
 
       /* Find the glyph under X/Y.  */
-      glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &area, 0);
+      glyph = x_y_to_hpos_vpos (w, x, y, &hpos, &vpos, &dx, &dy, &area);
+
+      /* Look for :pointer property on image.  */
+      if (glyph != NULL && glyph->type == IMAGE_GLYPH)
+       {
+         struct image *img = IMAGE_FROM_ID (f, glyph->u.img_id);
+         if (img != NULL && IMAGEP (img->spec))
+           {
+             Lisp_Object image_map, hotspot;
+             if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap),
+                  !NILP (image_map))
+                 && (hotspot = find_hot_spot (image_map,
+                                              glyph->slice.x + dx,
+                                              glyph->slice.y + dy),
+                     CONSP (hotspot))
+                 && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+               {
+                 Lisp_Object area_id, plist;
+
+                 area_id = XCAR (hotspot);
+                 /* Could check AREA_ID to see if we enter/leave this hot-spot.
+                    If so, we could look for mouse-enter, mouse-leave
+                    properties in PLIST (and do something...).  */
+                 hotspot = XCDR (hotspot);
+                 if (CONSP (hotspot)
+                     && (plist = XCAR (hotspot), CONSP (plist)))
+                   {
+                     pointer = Fsafe_plist_get (plist, Qpointer);
+                     if (NILP (pointer))
+                       pointer = Qhand;
+                     help_echo_string = Fsafe_plist_get (plist, Qhelp_echo);
+                     if (!NILP (help_echo_string))
+                       {
+                         help_echo_window = window;
+                         help_echo_object = glyph->object;
+                         help_echo_pos = glyph->charpos;
+                       }
+                   }
+               }
+             if (NILP (pointer))
+               pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer);
+           }
+       }
 
       /* Clear mouse face if X/Y not over text.  */
       if (glyph == NULL
          || area != TEXT_AREA
          || !MATRIX_ROW (w->current_matrix, vpos)->displays_text_p)
        {
-#if defined (HAVE_NTGUI)
-         /* ++KFS: Why is this necessary on W32 ?  */
-         clear_mouse_face (dpyinfo);
-         cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
-#else
          if (clear_mouse_face (dpyinfo))
            cursor = No_Cursor;
-#endif
+         if (NILP (pointer))
+           {
+             if (area != TEXT_AREA)
+               cursor = FRAME_X_OUTPUT (f)->nontext_cursor;
+             else
+               pointer = Vvoid_text_area_pointer;
+           }
          goto set_cursor;
        }
 
@@ -19696,19 +21171,8 @@ note_mouse_highlight (f, x, y)
 
       if (BUFFERP (object))
        {
-         /* Put all the overlays we want in a vector in overlay_vec.
-            Store the length in len.  If there are more than 10, make
-            enough space for all, and try again.  */
-         len = 10;
-         overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-         noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL, 0);
-         if (noverlays > len)
-           {
-             len = noverlays;
-             overlay_vec = (Lisp_Object *) alloca (len * sizeof (Lisp_Object));
-             noverlays = overlays_at (pos, 0, &overlay_vec, &len, NULL, NULL,0);
-           }
-
+         /* Put all the overlays we want in a vector in overlay_vec.  */
+         GET_OVERLAYS_AT (pos, overlay_vec, noverlays, NULL, 0);
          /* Sort overlays into increasing priority order.  */
          noverlays = sort_overlays (overlay_vec, noverlays, w);
        }
@@ -19925,7 +21389,7 @@ note_mouse_highlight (f, x, y)
     check_help_echo:
 
       /* Look for a `help-echo' property.  */
-      {
+      if (NILP (help_echo_string)) {
        Lisp_Object help, overlay;
 
        /* Check overlays first.  */
@@ -19991,6 +21455,46 @@ note_mouse_highlight (f, x, y)
          }
       }
 
+      /* Look for a `pointer' property.  */
+      if (NILP (pointer))
+       {
+         /* Check overlays first.  */
+         for (i = noverlays - 1; i >= 0 && NILP (pointer); --i)
+           pointer = Foverlay_get (overlay_vec[i], Qpointer);
+
+         if (NILP (pointer))
+           {
+             Lisp_Object object = glyph->object;
+             int charpos = glyph->charpos;
+
+             /* Try text properties.  */
+             if (STRINGP (object)
+                 && charpos >= 0
+                 && charpos < SCHARS (object))
+               {
+                 pointer = Fget_text_property (make_number (charpos),
+                                               Qpointer, object);
+                 if (NILP (pointer))
+                   {
+                     /* If the string itself doesn't specify a pointer,
+                        see if the buffer text ``under'' it does.  */
+                     struct glyph_row *r
+                       = MATRIX_ROW (w->current_matrix, vpos);
+                     int start = MATRIX_ROW_START_CHARPOS (r);
+                     int pos = string_buffer_position (w, object, start);
+                     if (pos > 0)
+                       pointer = Fget_char_property (make_number (pos),
+                                                     Qpointer, w->buffer);
+                   }
+               }
+             else if (BUFFERP (object)
+                      && charpos >= BEGV
+                      && charpos < ZV)
+               pointer = Fget_text_property (make_number (charpos),
+                                             Qpointer, object);
+           }
+       }
+
       BEGV = obegv;
       ZV = ozv;
       current_buffer = obuf;
@@ -19998,12 +21502,7 @@ note_mouse_highlight (f, x, y)
 
  set_cursor:
 
-#ifndef HAVE_CARBON
-  if (cursor != No_Cursor)
-#else
-  if (bcmp (&cursor, &No_Cursor, sizeof (Cursor)))
-#endif
-    rif->define_frame_cursor (f, cursor);
+  define_frame_cursor1 (f, cursor, pointer);
 }
 
 
@@ -20083,9 +21582,9 @@ expose_area (w, row, r, area)
         AREA.  The first glyph of the text area can be partially visible.
         The first glyphs of other areas cannot.  */
       start_x = window_box_left_offset (w, area);
-      if (area == TEXT_AREA)
-       start_x += row->x;
       x = start_x;
+      if (area == TEXT_AREA)
+       x += row->x;
 
       /* Find the first glyph that must be redrawn.  */
       while (first < end
@@ -20191,13 +21690,13 @@ phys_cursor_in_rect_p (w, r)
   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;
-      /* ++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);
     }
@@ -20215,13 +21714,16 @@ x_draw_vertical_border (w)
      struct window *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
      do it for frames with vertical scroll bars because either the
      right scroll bar of a window, or the left scroll bar of its
      neighbor will suffice as a border.  */
+  if (FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (w->frame)))
+    return;
+
   if (!WINDOW_RIGHTMOST_P (w)
       && !WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w))
     {
@@ -20599,6 +22101,7 @@ syms_of_xdisp ()
 #endif
 #ifdef HAVE_WINDOW_SYSTEM
   defsubr (&Stool_bar_lines_needed);
+  defsubr (&Slookup_image_map);
 #endif
   defsubr (&Sformat_mode_line);
 
@@ -20628,20 +22131,26 @@ syms_of_xdisp ()
   staticpro (&Qspace_width);
   Qraise = intern ("raise");
   staticpro (&Qraise);
+  Qslice = intern ("slice");
+  staticpro (&Qslice);
   Qspace = intern ("space");
   staticpro (&Qspace);
   Qmargin = intern ("margin");
   staticpro (&Qmargin);
+  Qpointer = intern ("pointer");
+  staticpro (&Qpointer);
   Qleft_margin = intern ("left-margin");
   staticpro (&Qleft_margin);
   Qright_margin = intern ("right-margin");
   staticpro (&Qright_margin);
-  Qalign_to = intern ("align-to");
-  staticpro (&Qalign_to);
+  Qcenter = intern ("center");
+  staticpro (&Qcenter);
+  Qline_height = intern ("line-height");
+  staticpro (&Qline_height);
+  Qtotal = intern ("total");
+  staticpro (&Qtotal);
   QCalign_to = intern (":align-to");
   staticpro (&QCalign_to);
-  Qrelative_width = intern ("relative-width");
-  staticpro (&Qrelative_width);
   QCrelative_width = intern (":relative-width");
   staticpro (&QCrelative_width);
   QCrelative_height = intern (":relative-height");
@@ -20660,6 +22169,16 @@ syms_of_xdisp ()
   staticpro (&Qtrailing_whitespace);
   Qimage = intern ("image");
   staticpro (&Qimage);
+  QCmap = intern (":map");
+  staticpro (&QCmap);
+  QCpointer = intern (":pointer");
+  staticpro (&QCpointer);
+  Qrect = intern ("rect");
+  staticpro (&Qrect);
+  Qcircle = intern ("circle");
+  staticpro (&Qcircle);
+  Qpoly = intern ("poly");
+  staticpro (&Qpoly);
   Qmessage_truncate_lines = intern ("message-truncate-lines");
   staticpro (&Qmessage_truncate_lines);
   Qcursor_in_non_selected_windows = intern ("cursor-in-non-selected-windows");
@@ -20684,18 +22203,31 @@ syms_of_xdisp ()
   staticpro (&Qbox);
   Qhollow = intern ("hollow");
   staticpro (&Qhollow);
+  Qhand = intern ("hand");
+  staticpro (&Qhand);
+  Qarrow = intern ("arrow");
+  staticpro (&Qarrow);
+  Qtext = intern ("text");
+  staticpro (&Qtext);
   Qrisky_local_variable = intern ("risky-local-variable");
   staticpro (&Qrisky_local_variable);
   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);
 
-  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]);
@@ -20733,10 +22265,16 @@ wide as that tab on the display.  */);
 #endif
 
   DEFVAR_LISP ("show-trailing-whitespace", &Vshow_trailing_whitespace,
-    doc: /* Non-nil means highlight trailing whitespace.
+    doc: /* *Non-nil means highlight trailing whitespace.
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
+  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'.  */);
+  Vvoid_text_area_pointer = Qarrow;
+
   DEFVAR_LISP ("inhibit-redisplay", &Vinhibit_redisplay,
     doc: /* Non-nil means don't actually do any redisplay.
 This is used for internal purposes.  */);
@@ -20753,9 +22291,17 @@ See also `overlay-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;
 
+  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.
@@ -20775,6 +22321,11 @@ Recenter the window whenever point gets within this many lines
 of the top or bottom of the window.  */);
   scroll_margin = 0;
 
+  DEFVAR_LISP ("display-pixels-per-inch",  &Vdisplay_pixels_per_inch,
+    doc: /* Pixels per inch on current display.
+Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI).  */);
+  Vdisplay_pixels_per_inch = make_float (72.0);
+
 #if GLYPH_DEBUG
   DEFVAR_INT ("debug-end-pos", &debug_end_pos, doc: /* Don't ask.  */);
 #endif
@@ -20819,6 +22370,7 @@ This variable is not guaranteed to be accurate except while processing
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
 \(see `modify-frame-parameters').  */);
+
   DEFVAR_LISP ("icon-title-format", &Vicon_title_format,
     doc: /* Template for displaying the title bar of an iconified frame.
 \(Assuming the window manager supports this feature.)
@@ -20851,7 +22403,7 @@ all the functions in the list are called, with the frame as argument.  */);
   Vwindow_size_change_functions = Qnil;
 
   DEFVAR_LISP ("window-scroll-functions", &Vwindow_scroll_functions,
-    doc: /* List of Functions to call before redisplaying a window with scrolling.
+    doc: /* List of functions to call before redisplaying a window with scrolling.
 Each function is called with two arguments, the window
 and its new display-start position.  Note that the value of `window-end'
 is not valid when these functions are called.  */);
@@ -20872,6 +22424,10 @@ otherwise.  */);
     doc: /* *Non-nil means raise tool-bar buttons when the mouse moves over them.  */);
   auto_raise_tool_bar_buttons_p = 1;
 
+  DEFVAR_BOOL ("make-cursor-line-fully-visible", &make_cursor_line_fully_visible_p,
+    doc: /* *Non-nil means to scroll (recenter) cursor line if it is not fully visible.  */);
+  make_cursor_line_fully_visible_p = 1;
+
   DEFVAR_LISP ("tool-bar-button-margin", &Vtool_bar_button_margin,
     doc: /* *Margin around tool-bar buttons in pixels.
 If an integer, use that for both horizontal and vertical margins.
@@ -20957,11 +22513,6 @@ Note that the lower bound for automatic hscrolling specified by `scroll-left'
 and `scroll-right' overrides this variable's effect.  */);
   Vhscroll_step = make_number (0);
 
-  DEFVAR_LISP ("image-types", &Vimage_types,
-    doc: /* List of supported image types.
-Each element of the list is a symbol for a supported image type.  */);
-  Vimage_types = Qnil;
-
   DEFVAR_BOOL ("message-truncate-lines", &message_truncate_lines,
     doc: /* If non-nil, messages are truncated instead of resizing the echo area.
 Bind this around calls to `message' to let it take effect.  */);
@@ -21052,3 +22603,5 @@ init_xdisp ()
 }
 
 
+/* arch-tag: eacc864d-bb6a-4b74-894a-1a4399a1358b
+   (do not change this comment) */