]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(erase_phys_cursor): Clear hollow cursor inside TEXT_AREA.
[gnu-emacs] / src / xdisp.c
index 1c479aee4e8f61944cb0074ffeea2cf664e85d42..3b7b9d39f81e6e648097bd2b84c8416f6f3fa606 100644 (file)
@@ -264,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;
@@ -888,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 *));
@@ -1785,7 +1789,8 @@ 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);
     }
 
@@ -2075,6 +2080,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
                                  * 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
@@ -4555,7 +4561,8 @@ 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;
@@ -4586,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;
 {
@@ -4891,6 +4898,9 @@ 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
@@ -5767,6 +5777,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                                  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 */
                        }
@@ -6064,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));
 
@@ -6133,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)
@@ -6180,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,
@@ -6277,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);
@@ -6365,7 +6382,7 @@ add_to_log (format, arg1, arg2)
   bcopy (SDATA (msg), buffer, len);
 
   message_dolog (buffer, len - 1, 1, 0);
-  SAFE_FREE (len);
+  SAFE_FREE ();
 
   UNGCPRO;
 }
@@ -6688,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 ();
@@ -7420,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;
        }
 
@@ -7976,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++);
 
@@ -8414,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
@@ -8433,18 +8452,24 @@ 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;
 
@@ -8691,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;
@@ -9523,11 +9549,13 @@ update_overlay_arrows (up_to_date)
 }
 
 
-/* Return overlay arrow string at row, or nil.  */
+/* 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 (f, row, pbitmap)
-     struct frame *f;
+overlay_arrow_at_row (it, row, pbitmap)
+     struct it *it;
      struct glyph_row *row;
      int *pbitmap;
 {
@@ -9550,9 +9578,10 @@ overlay_arrow_at_row (f, row, pbitmap)
          && (MATRIX_ROW_START_CHARPOS (row) == marker_position (val)))
        {
          val = overlay_arrow_string_or_property (var, pbitmap);
-         if (FRAME_WINDOW_P (f))
+         if (FRAME_WINDOW_P (it->f)
+             && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
            return Qt;
-         else if (STRINGP (val))
+         if (STRINGP (val))
            return val;
          break;
        }
@@ -10407,6 +10436,9 @@ redisplay_preserve_echo_area (from_where)
     }
   else
     redisplay_internal (1);
+
+  if (rif != NULL && rif->flush_display_optional)
+    rif->flush_display_optional (NULL);
 }
 
 
@@ -10864,6 +10896,9 @@ make_cursor_line_fully_visible (w, force_p)
   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)
@@ -10873,7 +10908,7 @@ make_cursor_line_fully_visible (w, force_p)
   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,
@@ -11027,7 +11062,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
     {
       start_display (&it, w, scroll_margin_pos);
       if (this_scroll_margin)
-       move_it_vertically (&it, - 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;
@@ -11147,7 +11182,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
          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;
        }
     }
@@ -11451,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
@@ -12026,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;
     }
@@ -12214,7 +12250,8 @@ redisplay_window (window, just_this_one_p)
     }
 
 #ifdef HAVE_WINDOW_SYSTEM
-  if (update_window_fringes (w, 0)
+  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)
@@ -12374,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
@@ -12422,7 +12459,7 @@ try_window_reusing_current_matrix (w)
              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 (start_row)
+                 || w->vscroll || MATRIX_ROW_PARTIALLY_VISIBLE_P (w, start_row)
                  || CHARPOS (start) == ZV)
                {
                  clear_glyph_matrix (w->desired_matrix);
@@ -13491,7 +13528,9 @@ try_window_id (w)
         && CHARPOS (start) > BEGV)
        /* 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 + cursor_height + this_scroll_margin > it.last_visible_y)
+       || (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);
@@ -14069,8 +14108,8 @@ 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, overlay_arrow_string)
@@ -14216,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.  */
@@ -14259,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.  */
@@ -14595,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.  */
@@ -14660,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;
        }
@@ -14688,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;
        }
@@ -14741,6 +14787,8 @@ display_line (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 */
                        }
@@ -14839,6 +14887,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);
 
          /* End of this display line if row is continued.  */
          if (row->continued_p || row->ends_at_zv_p)
@@ -14909,12 +14959,10 @@ display_line (it)
                {
                  if (!get_next_display_element (it))
                    {
-#ifdef HAVE_WINDOW_SYSTEM
                      it->continuation_lines_width = 0;
                      row->ends_at_zv_p = 1;
                      row->exact_window_width_line_p = 1;
                      break;
-#endif /* HAVE_WINDOW_SYSTEM */
                    }
                  if (ITERATOR_AT_END_OF_LINE_P (it))
                    {
@@ -14951,11 +14999,11 @@ display_line (it)
      better to let it be displayed like cursors under X.  */
   if (! overlay_arrow_seen
       && (overlay_arrow_string
-           = overlay_arrow_at_row (it->f, row, &overlay_arrow_bitmap),
+           = 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, overlay_arrow_string);
@@ -14980,10 +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;
-      it->w->overlay_arrow_bitmap = overlay_arrow_bitmap;
-      row->overlay_arrow_p = 1;
     }
 
   /* Compute pixel dimensions of this line.  */
@@ -15448,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);
@@ -15463,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
@@ -15768,7 +15824,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
        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;
@@ -15793,7 +15849,7 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
          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
@@ -16018,27 +16074,31 @@ pint2hrstr (buf, width, d)
        {
          tenths = remainder / 100;
          if (50 <= remainder % 100)
-           if (tenths < 9)
-             tenths++;
-           else
-             {
-               quotient++;
-               if (quotient == 10)
-                 tenths = -1;
-               else
-                 tenths = 0;
-             }
+           {
+             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;
-           }
+         {
+           if (quotient < 999)
+             quotient++;
+           else
+             {
+               quotient = 1;
+               exponent++;
+               tenths = 0;
+             }
+         }
     }
 
   /* Calculate the LENGTH of QUOTIENT.TENTHS as a string. */
@@ -16740,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.  */
@@ -16799,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;
        }
@@ -17235,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;
@@ -18207,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.  */
@@ -18244,11 +18321,8 @@ append_glyph (it)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
-  else if (!fonts_changed_p)
-    {
-      it->w->ncols_scale_factor++;
-      fonts_changed_p = 1;
-    }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 /* Store one glyph for the composition IT->cmp_id in IT->glyph_row.
@@ -18286,11 +18360,8 @@ append_composite_glyph (it)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
-  else if (!fonts_changed_p)
-    {
-      it->w->ncols_scale_factor++;
-      fonts_changed_p = 1;
-    }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 
@@ -18325,7 +18396,7 @@ produce_image_glyph (it)
 {
   struct image *img;
   struct face *face;
-  int face_ascent, glyph_ascent;
+  int glyph_ascent;
   struct glyph_slice slice;
 
   xassert (it->what == IT_IMAGE);
@@ -18408,7 +18479,7 @@ produce_image_glyph (it)
 
 #if 0  /* this breaks image tiling */
   /* If this glyph is alone on the last line, adjust it.ascent to minimum row ascent.  */
-  face_ascent = face->font ? FONT_BASE (face->font) : FRAME_BASELINE_OFFSET (it->f);
+  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
@@ -18460,11 +18531,8 @@ produce_image_glyph (it)
          glyph->font_type = FONT_TYPE_UNKNOWN;
          ++it->glyph_row->used[area];
        }
-      else if (!fonts_changed_p)
-       {
-         it->w->ncols_scale_factor++;
-         fonts_changed_p = 1;
-       }
+      else
+       IT_EXPAND_MATRIX_WIDTH (it, area);
     }
 }
 
@@ -18508,11 +18576,8 @@ append_stretch_glyph (it, object, width, height, ascent)
       glyph->font_type = FONT_TYPE_UNKNOWN;
       ++it->glyph_row->used[area];
     }
-  else if (!fonts_changed_p)
-    {
-      it->w->ncols_scale_factor++;
-      fonts_changed_p = 1;
-    }
+  else
+    IT_EXPAND_MATRIX_WIDTH (it, area);
 }
 
 
@@ -18567,14 +18632,14 @@ produce_stretch_glyph (it)
   plist = XCDR (it->object);
 
   /* Compute the width of the stretch.  */
-  if ((prop = Fplist_get (plist, QCwidth), !NILP (prop))
+  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 = Fplist_get (plist, QCrelative_width),
+  else if (prop = Fsafe_plist_get (plist, QCrelative_width),
           NUMVAL (prop) > 0)
     {
       /* Relative width `:relative-width FACTOR' specified and valid.
@@ -18598,7 +18663,7 @@ produce_stretch_glyph (it)
       x_produce_glyphs (&it2);
       width = NUMVAL (prop) * it2.pixel_width;
     }
-  else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
+  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)
@@ -18618,13 +18683,13 @@ produce_stretch_glyph (it)
     width = 1;
 
   /* Compute height.  */
-  if ((prop = Fplist_get (plist, QCheight), !NILP (prop))
+  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 = Fplist_get (plist, QCrelative_height),
+  else if (prop = Fsafe_plist_get (plist, QCrelative_height),
           NUMVAL (prop) > 0)
     height = FONT_HEIGHT (font) * NUMVAL (prop);
   else
@@ -18636,7 +18701,7 @@ produce_stretch_glyph (it)
   /* 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 = height * NUMVAL (prop) / 100.0;
   else if (!NILP (prop)
@@ -18696,8 +18761,10 @@ calc_line_height_property (it, prop, font, boff, total)
 
   if (STRINGP (it->object))
     position = make_number (IT_STRING_CHARPOS (*it));
-  else
+  else if (BUFFERP (it->object))
     position = make_number (IT_CHARPOS (*it));
+  else
+    return Qnil;
 
   val = Fget_char_property (position, prop, it->object);
 
@@ -19419,7 +19486,11 @@ x_produce_glyphs (it)
     it->current_x += it->pixel_width;
 
   if (extra_line_spacing > 0)
-    it->descent += extra_line_spacing;
+    {
+      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);
@@ -20001,6 +20072,11 @@ 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.  */
@@ -20044,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)
@@ -20051,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.  */
@@ -20386,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 1;
-       }
-      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;
@@ -20833,7 +20912,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
   if (IMAGEP (object))
     {
       Lisp_Object image_map, hotspot;
-      if ((image_map = Fplist_get (XCDR (object), QCmap),
+      if ((image_map = Fsafe_plist_get (XCDR (object), QCmap),
           !NILP (image_map))
          && (hotspot = find_hot_spot (image_map, dx, dy),
              CONSP (hotspot))
@@ -20845,12 +20924,14 @@ note_mode_line_or_margin_highlight (w, x, y, area)
          /* 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...).  */
-         if ((plist = XCDR (hotspot), CONSP (plist)))
+         hotspot = XCDR (hotspot);
+         if (CONSP (hotspot)
+             && (plist = XCAR (hotspot), CONSP (plist)))
            {
-             pointer = Fplist_get (plist, Qpointer);
+             pointer = Fsafe_plist_get (plist, Qpointer);
              if (NILP (pointer))
                pointer = Qhand;
-             help = Fplist_get (plist, Qhelp_echo);
+             help = Fsafe_plist_get (plist, Qhelp_echo);
              if (!NILP (help))
                {
                  help_echo_string = help;
@@ -20861,7 +20942,7 @@ note_mode_line_or_margin_highlight (w, x, y, area)
                }
            }
          if (NILP (pointer))
-           pointer = Fplist_get (XCDR (object), QCpointer);
+           pointer = Fsafe_plist_get (XCDR (object), QCpointer);
        }
     }
 
@@ -20871,13 +20952,16 @@ note_mode_line_or_margin_highlight (w, x, y, area)
       /* 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))
@@ -20944,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.  */
@@ -21010,7 +21096,7 @@ note_mouse_highlight (f, x, y)
          if (img != NULL && IMAGEP (img->spec))
            {
              Lisp_Object image_map, hotspot;
-             if ((image_map = Fplist_get (XCDR (img->spec), QCmap),
+             if ((image_map = Fsafe_plist_get (XCDR (img->spec), QCmap),
                   !NILP (image_map))
                  && (hotspot = find_hot_spot (image_map,
                                               glyph->slice.x + dx,
@@ -21024,12 +21110,14 @@ note_mouse_highlight (f, x, y)
                  /* 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...).  */
-                 if ((plist = XCDR (hotspot), CONSP (plist)))
+                 hotspot = XCDR (hotspot);
+                 if (CONSP (hotspot)
+                     && (plist = XCAR (hotspot), CONSP (plist)))
                    {
-                     pointer = Fplist_get (plist, Qpointer);
+                     pointer = Fsafe_plist_get (plist, Qpointer);
                      if (NILP (pointer))
                        pointer = Qhand;
-                     help_echo_string = Fplist_get (plist, Qhelp_echo);
+                     help_echo_string = Fsafe_plist_get (plist, Qhelp_echo);
                      if (!NILP (help_echo_string))
                        {
                          help_echo_window = window;
@@ -21039,7 +21127,7 @@ note_mouse_highlight (f, x, y)
                    }
                }
              if (NILP (pointer))
-               pointer = Fplist_get (XCDR (img->spec), QCpointer);
+               pointer = Fsafe_plist_get (XCDR (img->spec), QCpointer);
            }
        }
 
@@ -22336,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.