Now part of GNU Emacs. Update FSF's address.
[bpt/emacs.git] / src / xdisp.c
index d7de7db..f7f7898 100644 (file)
@@ -1,6 +1,7 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, 1998, 1999,
-     2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
+                 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+                 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -1346,6 +1347,9 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
 
   current_header_line_height = current_mode_line_height = -1;
 
+  if (visible_p && XFASTINT (w->hscroll) > 0)
+    *x -= XFASTINT (w->hscroll) * WINDOW_FRAME_COLUMN_WIDTH (w);
+
   return visible_p;
 }
 
@@ -1764,15 +1768,20 @@ frame_to_window_pixel_xy (w, x, y)
 }
 
 /* EXPORT:
-   Return in *R the clipping rectangle for glyph string S.  */
+   Return in RECTS[] at most N clipping rectangles for glyph string S.
+   Return the number of stored rectangles.  */
 
-void
-get_glyph_string_clip_rect (s, nr)
+int
+get_glyph_string_clip_rects (s, rects, n)
      struct glyph_string *s;
-     NativeRectangle *nr;
+     NativeRectangle *rects;
+     int n;
 {
   XRectangle r;
 
+  if (n <= 0)
+    return 0;
+
   if (s->row->full_width_p)
     {
       /* Draw full-width.  X coordinates are relative to S->w->left_col.  */
@@ -1815,10 +1824,27 @@ get_glyph_string_clip_rect (s, nr)
   /* If S draws overlapping rows, it's sufficient to use the top and
      bottom of the window for clipping because this glyph string
      intentionally draws over other lines.  */
-  if (s->for_overlaps_p)
+  if (s->for_overlaps)
     {
       r.y = WINDOW_HEADER_LINE_HEIGHT (s->w);
       r.height = window_text_bottom_y (s->w) - r.y;
+
+      /* Alas, the above simple strategy does not work for the
+        environments with anti-aliased text: if the same text is
+        drawn onto the same place multiple times, it gets thicker.
+        If the overlap we are processing is for the erased cursor, we
+        take the intersection with the rectagle of the cursor.  */
+      if (s->for_overlaps & OVERLAPS_ERASED_CURSOR)
+       {
+         XRectangle rc, r_save = r;
+
+         rc.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (s->w, s->w->phys_cursor.x);
+         rc.y = s->w->phys_cursor.y;
+         rc.width = s->w->phys_cursor_width;
+         rc.height = s->w->phys_cursor_height;
+
+         x_intersect_rectangles (&r_save, &rc, &r);
+       }
     }
   else
     {
@@ -1877,11 +1903,71 @@ get_glyph_string_clip_rect (s, nr)
        }
     }
 
+  if ((s->for_overlaps & OVERLAPS_BOTH) == 0
+      || (s->for_overlaps & OVERLAPS_BOTH) == OVERLAPS_BOTH && n == 1)
+    {
 #ifdef CONVERT_FROM_XRECT
-  CONVERT_FROM_XRECT (r, *nr);
+      CONVERT_FROM_XRECT (r, *rects);
 #else
-  *nr = r;
+      *rects = r;
 #endif
+      return 1;
+    }
+  else
+    {
+      /* If we are processing overlapping and allowed to return
+        multiple clipping rectangles, we exclude the row of the glyph
+        string from the clipping rectangle.  This is to avoid drawing
+        the same text on the environment with anti-aliasing.  */
+#ifdef CONVERT_FROM_XRECT
+      XRectangle rs[2];
+#else
+      XRectangle *rs = rects;
+#endif
+      int i = 0, row_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, s->row->y);
+
+      if (s->for_overlaps & OVERLAPS_PRED)
+       {
+         rs[i] = r;
+         if (r.y + r.height > row_y)
+           if (r.y < row_y)
+             rs[i].height = row_y - r.y;
+           else
+             rs[i].height = 0;
+         i++;
+       }
+      if (s->for_overlaps & OVERLAPS_SUCC)
+       {
+         rs[i] = r;
+         if (r.y < row_y + s->row->visible_height)
+           if (r.y + r.height > row_y + s->row->visible_height)
+             {
+               rs[i].y = row_y + s->row->visible_height;
+               rs[i].height = r.y + r.height - rs[i].y;
+             }
+           else
+             rs[i].height = 0;
+         i++;
+       }
+
+      n = i;
+#ifdef CONVERT_FROM_XRECT
+      for (i = 0; i < n; i++)
+       CONVERT_FROM_XRECT (rs[i], rects[i]);
+#endif
+      return n;
+    }
+}
+
+/* EXPORT:
+   Return in *NR the clipping rectangle for glyph string S.  */
+
+void
+get_glyph_string_clip_rect (s, nr)
+     struct glyph_string *s;
+     NativeRectangle *nr;
+{
+  get_glyph_string_clip_rects (s, nr, 1);
 }
 
 
@@ -1941,6 +2027,198 @@ get_phys_cursor_geometry (w, row, glyph, heightp)
   return WINDOW_TO_FRAME_PIXEL_Y (w, y);
 }
 
+/*
+ * Remember which glyph the mouse is over.
+ */
+
+void
+remember_mouse_glyph (f, gx, gy, rect)
+     struct frame *f;
+     int gx, gy;
+     NativeRectangle *rect;
+{
+  Lisp_Object window;
+  struct window *w;
+  struct glyph_row *r, *gr, *end_row;
+  enum window_part part;
+  enum glyph_row_area area;
+  int x, y, width, height;
+
+  /* Try to determine frame pixel position and size of the glyph under
+     frame pixel coordinates X/Y on frame F.  */
+
+  window = window_from_coordinates (f, gx, gy, &part, &x, &y, 0);
+  if (NILP (window))
+    {
+      width = FRAME_SMALLEST_CHAR_WIDTH (f);
+      height = FRAME_SMALLEST_FONT_HEIGHT (f);
+      goto virtual_glyph;
+    }
+
+  w = XWINDOW (window);
+  width = WINDOW_FRAME_COLUMN_WIDTH (w);
+  height = WINDOW_FRAME_LINE_HEIGHT (w);
+
+  r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+  end_row = MATRIX_BOTTOM_TEXT_ROW (w->current_matrix, w);
+
+  if (w->pseudo_window_p)
+    {
+      area = TEXT_AREA;
+      part = ON_MODE_LINE; /* Don't adjust margin. */
+      goto text_glyph;
+    }
+
+  switch (part)
+    {
+    case ON_LEFT_MARGIN:
+      area = LEFT_MARGIN_AREA;
+      goto text_glyph;
+
+    case ON_RIGHT_MARGIN:
+      area = RIGHT_MARGIN_AREA;
+      goto text_glyph;
+
+    case ON_HEADER_LINE:
+    case ON_MODE_LINE:
+      gr = (part == ON_HEADER_LINE
+           ? MATRIX_HEADER_LINE_ROW (w->current_matrix)
+           : MATRIX_MODE_LINE_ROW (w->current_matrix));
+      gy = gr->y;
+      area = TEXT_AREA;
+      goto text_glyph_row_found;
+
+    case ON_TEXT:
+      area = TEXT_AREA;
+
+    text_glyph:
+      gr = 0; gy = 0;
+      for (; r <= end_row && r->enabled_p; ++r)
+       if (r->y + r->height > y)
+         {
+           gr = r; gy = r->y;
+           break;
+         }
+
+    text_glyph_row_found:
+      if (gr && gy <= y)
+       {
+         struct glyph *g = gr->glyphs[area];
+         struct glyph *end = g + gr->used[area];
+
+         height = gr->height;
+         for (gx = gr->x; g < end; gx += g->pixel_width, ++g)
+           if (gx + g->pixel_width > x)
+             break;
+
+         if (g < end)
+           {
+             if (g->type == IMAGE_GLYPH)
+               {
+                 /* Don't remember when mouse is over image, as
+                    image may have hot-spots.  */
+                 STORE_NATIVE_RECT (*rect, 0, 0, 0, 0);
+                 return;
+               }
+             width = g->pixel_width;
+           }
+         else
+           {
+             /* Use nominal char spacing at end of line.  */
+             x -= gx;
+             gx += (x / width) * width;
+           }
+
+         if (part != ON_MODE_LINE && part != ON_HEADER_LINE)
+           gx += window_box_left_offset (w, area);
+       }
+      else
+       {
+         /* Use nominal line height at end of window.  */
+         gx = (x / width) * width;
+         y -= gy;
+         gy += (y / height) * height;
+       }
+      break;
+
+    case ON_LEFT_FRINGE:
+      gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+           ? WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (w)
+           : window_box_right_offset (w, LEFT_MARGIN_AREA));
+      width = WINDOW_LEFT_FRINGE_WIDTH (w);
+      goto row_glyph;
+
+    case ON_RIGHT_FRINGE:
+      gx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+           ? window_box_right_offset (w, RIGHT_MARGIN_AREA)
+           : window_box_right_offset (w, TEXT_AREA));
+      width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+      goto row_glyph;
+
+    case ON_SCROLL_BAR:
+      gx = (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w)
+           ? 0
+           : (window_box_right_offset (w, RIGHT_MARGIN_AREA)
+              + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                 ? WINDOW_RIGHT_FRINGE_WIDTH (w)
+                 : 0)));
+      width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+
+    row_glyph:
+      gr = 0, gy = 0;
+      for (; r <= end_row && r->enabled_p; ++r)
+       if (r->y + r->height > y)
+         {
+           gr = r; gy = r->y;
+           break;
+         }
+
+      if (gr && gy <= y)
+       height = gr->height;
+      else
+       {
+         /* Use nominal line height at end of window.  */
+         y -= gy;
+         gy += (y / height) * height;
+       }
+      break;
+
+    default:
+      ;
+    virtual_glyph:
+      /* If there is no glyph under the mouse, then we divide the screen
+        into a grid of the smallest glyph in the frame, and use that
+        as our "glyph".  */
+
+      /* Arrange for the division in FRAME_PIXEL_X_TO_COL etc. to
+        round down even for negative values.  */
+      if (gx < 0)
+       gx -= width - 1;
+      if (gy < 0)
+       gy -= height - 1;
+
+      gx = (gx / width) * width;
+      gy = (gy / height) * height;
+
+      goto store_rect;
+    }
+
+  gx += WINDOW_LEFT_EDGE_X (w);
+  gy += WINDOW_TOP_EDGE_Y (w);
+
+ store_rect:
+  STORE_NATIVE_RECT (*rect, gx, gy, width, height);
+
+  /* Visible feedback for debugging.  */
+#if 0
+#if HAVE_X_WINDOWS
+  XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                 f->output_data.x->normal_gc,
+                 gx, gy, width, height);
+#endif
+#endif
+}
+
 
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -3424,7 +3702,7 @@ handle_display_prop (it)
     }
   else
     {
-      object = it->w->buffer;
+      XSETWINDOW (object, it->w);
       position = &it->current.pos;
     }
 
@@ -3445,6 +3723,9 @@ handle_display_prop (it)
   if (NILP (prop))
     return HANDLED_NORMALLY;
 
+  if (!STRINGP (it->string))
+    object = it->w->buffer;
+
   if (CONSP (prop)
       /* Simple properties.  */
       && !EQ (XCAR (prop), Qimage)
@@ -4800,7 +5081,8 @@ reseat_at_next_visible_line_start (it, on_newline_p)
           && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
                                 (double) it->selective)) /* iftc */
       {
-       xassert (FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
+       xassert (IT_BYTEPOS (*it) == BEGV
+                || FETCH_BYTE (IT_BYTEPOS (*it) - 1) == '\n');
        newline_found_p = forward_to_next_line_start (it, &skipped_p);
       }
 
@@ -6008,6 +6290,8 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
             glyphs have the same width.  */
          int single_glyph_width = it->pixel_width / it->nglyphs;
          int new_x;
+         int x_before_this_char = x;
+         int hpos_before_this_char = it->hpos;
 
          for (i = 0; i < it->nglyphs; ++i, x = new_x)
            {
@@ -6039,8 +6323,22 @@ move_it_in_display_line_to (it, to_charpos, to_x, op)
                    {
                      ++it->hpos;
                      it->current_x = new_x;
+
+                     /* The character's last glyph just barely fits
+                        in this row.  */
                      if (i == it->nglyphs - 1)
                        {
+                         /* If this is the destination position,
+                            return a position *before* it in this row,
+                            now that we know it fits in this row.  */
+                         if (BUFFER_POS_REACHED_P ())
+                           {
+                             it->hpos = hpos_before_this_char;
+                             it->current_x = x_before_this_char;
+                             result = MOVE_POS_MATCH_OR_ZV;
+                             break;
+                           }
+
                          set_iterator_to_next (it, 1);
 #ifdef HAVE_WINDOW_SYSTEM
                          if (IT_OVERFLOW_NEWLINE_INTO_FRINGE (it))
@@ -6502,6 +6800,7 @@ move_it_vertically (it, dy)
       /* If buffer ends in ZV without a newline, move to the start of
         the line to satisfy the post-condition.  */
       if (IT_CHARPOS (*it) == ZV
+         && ZV > BEGV
          && FETCH_BYTE (IT_BYTEPOS (*it) - 1) != '\n')
        move_it_by_lines (it, 0, 0);
     }
@@ -6727,7 +7026,10 @@ message_log_maybe_newline ()
    terminated with a newline when NLFLAG is non-zero.  MULTIBYTE, if
    nonzero, means interpret the contents of M as multibyte.  This
    function calls low-level routines in order to bypass text property
-   hooks, etc. which might not be safe to run.  */
+   hooks, etc. which might not be safe to run.
+
+   This may GC (insert may run before/after change hooks),
+   so the buffer M must NOT point to a Lisp string.  */
 
 void
 message_dolog (m, nbytes, nlflag, multibyte)
@@ -6938,10 +7240,7 @@ message_log_check_duplicate (prev_bol, prev_bol_byte, this_bol, this_bol_byte)
    out any existing message, and let the mini-buffer text show
    through.
 
-   The buffer M must continue to exist until after the echo area gets
-   cleared or some other message gets displayed there.  This means do
-   not pass text that is stored in a Lisp string; do not pass text in
-   a buffer that was alloca'd.  */
+   This may GC, so the buffer M must NOT point to a Lisp string.  */
 
 void
 message2 (m, nbytes, multibyte)
@@ -7038,7 +7337,15 @@ message3 (m, nbytes, multibyte)
   /* First flush out any partial line written with print.  */
   message_log_maybe_newline ();
   if (STRINGP (m))
-    message_dolog (SDATA (m), nbytes, 1, multibyte);
+    {
+      char *buffer;
+      USE_SAFE_ALLOCA;
+
+      SAFE_ALLOCA (buffer, char *, nbytes);
+      bcopy (SDATA (m), buffer, nbytes);
+      message_dolog (buffer, nbytes, 1, multibyte);
+      SAFE_FREE ();
+    }
   message3_nolog (m, nbytes, multibyte);
 
   UNGCPRO;
@@ -7096,6 +7403,9 @@ message3_nolog (m, nbytes, multibyte)
          set_message (NULL, m, nbytes, multibyte);
          if (minibuffer_auto_raise)
            Fraise_frame (frame);
+         /* Assume we are not echoing.
+            (If we are, echo_now will override this.)  */
+         echo_message_buffer = Qnil;
        }
       else
        clear_message (1, 1);
@@ -7624,13 +7934,16 @@ display_echo_area_1 (a1, a2, a3, a4)
   int window_height_changed_p = 0;
 
   /* Do this before displaying, so that we have a large enough glyph
-     matrix for the display.  */
+     matrix for the display.  If we can't get enough space for the
+     whole text, display the last N lines.  That works by setting w->start.  */
   window_height_changed_p = resize_mini_window (w, 0);
 
+  /* Use the starting position chosen by resize_mini_window.  */
+  SET_TEXT_POS_FROM_MARKER (start, w->start);
+
   /* Display.  */
   clear_glyph_matrix (w->desired_matrix);
   XSETWINDOW (window, w);
-  SET_TEXT_POS (start, BEG, BEG_BYTE);
   try_window (window, start, 0);
 
   return window_height_changed_p;
@@ -7686,8 +7999,14 @@ resize_mini_window_1 (a1, exactly, a3, a4)
 
 /* Resize mini-window W to fit the size of its contents.  EXACT:P
    means size the window exactly to the size needed.  Otherwise, it's
-   only enlarged until W's buffer is empty.  Value is non-zero if
-   the window height has been changed.  */
+   only enlarged until W's buffer is empty.
+
+   Set W->start to the right place to begin display.  If the whole
+   contents fit, start at the beginning.  Otherwise, start so as
+   to make the end of the contents appear.  This is particularly
+   important for y-or-n-p, but seems desirable generally.
+
+   Value is non-zero if the window height has been changed.  */
 
 int
 resize_mini_window (w, exact_p)
@@ -7699,6 +8018,11 @@ resize_mini_window (w, exact_p)
 
   xassert (MINI_WINDOW_P (w));
 
+  /* By default, start display at the beginning.  */
+  set_marker_both (w->start, w->buffer,
+                  BUF_BEGV (XBUFFER (w->buffer)),
+                  BUF_BEGV_BYTE (XBUFFER (w->buffer)));
+
   /* Don't resize windows while redisplaying a window; it would
      confuse redisplay functions when the size of the window they are
      displaying changes from under them.  Such a resizing can happen,
@@ -7762,7 +8086,7 @@ resize_mini_window (w, exact_p)
       if (height > max_height)
        {
          height = max_height;
-         init_iterator (&it, w, PT, PT_BYTE, NULL, DEFAULT_FACE_ID);
+         init_iterator (&it, w, ZV, ZV_BYTE, NULL, DEFAULT_FACE_ID);
          move_it_vertically_backward (&it, (height - 1) * unit);
          start = it.current.pos;
        }
@@ -7973,7 +8297,11 @@ truncate_message_1 (nchars, a2, a3, a4)
 
    If S is not null, set the message to the first LEN bytes of S.  LEN
    zero means use the whole string.  MULTIBYTE_P non-zero means S is
-   multibyte.  Display the message multibyte in that case.  */
+   multibyte.  Display the message multibyte in that case.
+
+   Doesn't GC, as with_echo_area_buffer binds Qinhibit_modification_hooks
+   to t before calling set_message_1 (which calls insert).
+  */
 
 void
 set_message (s, string, nbytes, multibyte_p)
@@ -9969,12 +10297,14 @@ overlay_arrow_at_row (it, row)
          if (FRAME_WINDOW_P (it->f)
              && WINDOW_LEFT_FRINGE_WIDTH (it->w) > 0)
            {
+#ifdef HAVE_WINDOW_SYSTEM
              if (val = Fget (var, Qoverlay_arrow_bitmap), SYMBOLP (val))
                {
                  int fringe_bitmap;
                  if ((fringe_bitmap = lookup_fringe_bitmap (val)) != 0)
                    return make_number (fringe_bitmap);
                }
+#endif
              return make_number (-1); /* Use default arrow bitmap */
            }
          return overlay_arrow_string_or_property (var);
@@ -10575,9 +10905,9 @@ redisplay_internal (preserve_echo_area)
   if (consider_all_windows_p)
     {
       Lisp_Object tail, frame;
-      int i, n = 0, size = 50;
-      struct frame **updated
-       = (struct frame **) alloca (size * sizeof *updated);
+
+      FOR_EACH_FRAME (tail, frame)
+       XFRAME (frame)->updated_p = 0;
 
       /* Recompute # windows showing selected buffer.  This will be
         incremented each time such a window is displayed.  */
@@ -10639,15 +10969,7 @@ redisplay_internal (preserve_echo_area)
                    break;
 #endif
 
-                 if (n == size)
-                   {
-                     int nbytes = size * sizeof *updated;
-                     struct frame **p = (struct frame **) alloca (2 * nbytes);
-                     bcopy (updated, p, nbytes);
-                     size *= 2;
-                   }
-
-                 updated[n++] = f;
+                 f->updated_p = 1;
                }
            }
        }
@@ -10657,12 +10979,15 @@ redisplay_internal (preserve_echo_area)
          /* Do the mark_window_display_accurate after all windows have
             been redisplayed because this call resets flags in buffers
             which are needed for proper redisplay.  */
-         for (i = 0; i < n; ++i)
+         FOR_EACH_FRAME (tail, frame)
            {
-             struct frame *f = updated[i];
-             mark_window_display_accurate (f->root_window, 1);
-             if (frame_up_to_date_hook)
-               frame_up_to_date_hook (f);
+             struct frame *f = XFRAME (frame);
+             if (f->updated_p)
+               {
+                 mark_window_display_accurate (f->root_window, 1);
+                 if (frame_up_to_date_hook)
+                   frame_up_to_date_hook (f);
+               }
            }
        }
     }
@@ -11324,6 +11649,7 @@ static int
 cursor_row_fully_visible_p (w, force_p, current_matrix_p)
      struct window *w;
      int force_p;
+     int current_matrix_p;
 {
   struct glyph_matrix *matrix;
   struct glyph_row *row;
@@ -12708,10 +13034,9 @@ redisplay_window (window, just_this_one_p)
 
 #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_window_fringes (w, (just_this_one_p
+                                   || (!used_current_matrix_p && !overlay_arrow_seen)
+                                   || w->pseudo_window_p)))
     {
       update_begin (f);
       BLOCK_INPUT;
@@ -12790,15 +13115,15 @@ try_window (window, pos, check_margins)
   if (check_margins
       && !MINI_WINDOW_P (w))
     {
-      int this_scroll_margin, cursor_height;
+      int this_scroll_margin;
 
       this_scroll_margin = max (0, scroll_margin);
       this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
       this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
-      cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
 
       if ((w->cursor.y < this_scroll_margin
-          && CHARPOS (pos) > BEGV)
+          && CHARPOS (pos) > BEGV
+          && IT_CHARPOS (it) < ZV)
          /* rms: considering make_cursor_line_fully_visible_p here
             seems to give wrong results.  We don't want to recenter
             when the last line is partly visible, we want to allow
@@ -13046,7 +13371,7 @@ try_window_reusing_current_matrix (w)
          /* Disable lines in the current matrix which are now
             below the window.  */
          for (++row; row < bottom_row; ++row)
-           row->enabled_p = 0;
+           row->enabled_p = row->mode_line_p = 0;
        }
 
       /* Update window_end_pos etc.; last_reused_text_row is the last
@@ -15916,7 +16241,7 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
       {
        /* A string: output it and check for %-constructs within it.  */
        unsigned char c;
-       const unsigned char *this, *lisp_string;
+       int offset = 0;
 
        if (!NILP (props) || risky)
          {
@@ -15974,8 +16299,7 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
              }
          }
 
-       this = SDATA (elt);
-       lisp_string = this;
+       offset = 0;
 
        if (literal)
          {
@@ -15998,42 +16322,44 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
            break;
          }
 
+       /* Handle the non-literal case.  */
+
        while ((precision <= 0 || n < precision)
-              && *this
+              && SREF (elt, offset) != 0
               && (mode_line_target != MODE_LINE_DISPLAY
                   || it->current_x < it->last_visible_x))
          {
-           const unsigned char *last = this;
+           int last_offset = offset;
 
            /* Advance to end of string or next format specifier.  */
-           while ((c = *this++) != '\0' && c != '%')
+           while ((c = SREF (elt, offset++)) != '\0' && c != '%')
              ;
 
-           if (this - 1 != last)
+           if (offset - 1 != last_offset)
              {
                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;
+               offset--;
 
-               prec = c_string_width (last, this - last, precision - n,
+               prec = c_string_width (SDATA (elt) + last_offset,
+                                      offset - last_offset, precision - n,
                                       &nchars, &nbytes);
 
                switch (mode_line_target)
                  {
                  case MODE_LINE_NOPROP:
                  case MODE_LINE_TITLE:
-                   n += store_mode_line_noprop (last, 0, prec);
+                   n += store_mode_line_noprop (SDATA (elt) + last_offset, 0, prec);
                    break;
                  case MODE_LINE_STRING:
                    {
-                     int bytepos = last - lisp_string;
+                     int bytepos = last_offset;
                      int charpos = string_byte_to_char (elt, bytepos);
                      int endpos = (precision <= 0
-                                   ? string_byte_to_char (elt,
-                                                          this - lisp_string)
+                                   ? string_byte_to_char (elt, offset)
                                    : charpos + nchars);
 
                      n += store_mode_line_string (NULL,
@@ -16044,7 +16370,7 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                    break;
                  case MODE_LINE_DISPLAY:
                    {
-                     int bytepos = last - lisp_string;
+                     int bytepos = last_offset;
                      int charpos = string_byte_to_char (elt, bytepos);
                      n += display_string (NULL, elt, Qnil, 0, charpos,
                                           it, 0, prec, 0,
@@ -16055,12 +16381,12 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
              }
            else /* c == '%' */
              {
-               const unsigned char *percent_position = this;
+               int percent_position = offset;
 
                /* Get the specified minimum width.  Zero means
                   don't pad.  */
                field = 0;
-               while ((c = *this++) >= '0' && c <= '9')
+               while ((c = SREF (elt, offset++)) >= '0' && c <= '9')
                  field = field * 10 + c - '0';
 
                /* Don't pad beyond the total padding allowed.  */
@@ -16080,7 +16406,7 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                    int bytepos, charpos;
                    unsigned char *spec;
 
-                   bytepos = percent_position - lisp_string;
+                   bytepos = percent_position;
                    charpos = (STRING_MULTIBYTE (elt)
                               ? string_byte_to_char (elt, bytepos)
                               : bytepos);
@@ -17615,6 +17941,15 @@ calc_pixel_width_or_height (res, it, prop, font, width_p, align_to)
          if (pixels > 0)
            {
              double ppi;
+#ifdef HAVE_WINDOW_SYSTEM
+             if (FRAME_WINDOW_P (it->f)
+                 && (ppi = (width_p
+                            ? FRAME_X_DISPLAY_INFO (it->f)->resx
+                            : FRAME_X_DISPLAY_INFO (it->f)->resy),
+                     ppi > 0))
+               return OK_PIXELS (ppi / pixels);
+#endif
+
              if ((ppi = NUMVAL (Vdisplay_pixels_per_inch), ppi > 0)
                  || (CONSP (Vdisplay_pixels_per_inch)
                      && (ppi = (width_p
@@ -17962,22 +18297,23 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
 
    FACES is an array of faces for all components of this composition.
    S->gidx is the index of the first component for S.
-   OVERLAPS_P non-zero means S should draw the foreground only, and
-   use its physical height for clipping.
+
+   OVERLAPS non-zero means S should draw the foreground only, and use
+   its physical height for clipping.  See also draw_glyphs.
 
    Value is the index of a component not in S.  */
 
 static int
-fill_composite_glyph_string (s, faces, overlaps_p)
+fill_composite_glyph_string (s, faces, overlaps)
      struct glyph_string *s;
      struct face **faces;
-     int overlaps_p;
+     int overlaps;
 {
   int i;
 
   xassert (s);
 
-  s->for_overlaps_p = overlaps_p;
+  s->for_overlaps = overlaps;
 
   s->face = faces[s->gidx];
   s->font = s->face->font;
@@ -18021,16 +18357,16 @@ fill_composite_glyph_string (s, faces, overlaps_p)
 
    FACE_ID is the face id of the string.  START is the index of the
    first glyph to consider, END is the index of the last + 1.
-   OVERLAPS_P non-zero means S should draw the foreground only, and
-   use its physical height for clipping.
+   OVERLAPS non-zero means S should draw the foreground only, and use
+   its physical height for clipping.  See also draw_glyphs.
 
    Value is the index of the first glyph not in S.  */
 
 static int
-fill_glyph_string (s, face_id, start, end, overlaps_p)
+fill_glyph_string (s, face_id, start, end, overlaps)
      struct glyph_string *s;
      int face_id;
-     int start, end, overlaps_p;
+     int start, end, overlaps;
 {
   struct glyph *glyph, *last;
   int voffset;
@@ -18040,7 +18376,7 @@ fill_glyph_string (s, face_id, start, end, overlaps_p)
   xassert (s->nchars == 0);
   xassert (start >= 0 && end > start);
 
-  s->for_overlaps_p = overlaps_p,
+  s->for_overlaps = overlaps,
   glyph = s->row->glyphs[s->area] + start;
   last = s->row->glyphs[s->area] + end;
   voffset = glyph->voffset;
@@ -18517,7 +18853,7 @@ compute_overhangs_and_x (s, x, backward_p)
         INIT_GLYPH_STRING (s, char2b, w, row, area, START, HL);           \
         append_glyph_string (&HEAD, &TAIL, s);                            \
         s->x = (X);                                                       \
-        START = fill_glyph_string (s, face_id, START, END, overlaps_p);   \
+        START = fill_glyph_string (s, face_id, START, END, overlaps);   \
        }                                                                  \
      while (0)
 
@@ -18570,7 +18906,7 @@ compute_overhangs_and_x (s, x, backward_p)
        if (n == 0)                                                       \
          first_s = s;                                                    \
                                                                          \
-       n = fill_composite_glyph_string (s, faces, overlaps_p);           \
+       n = fill_composite_glyph_string (s, faces, overlaps);             \
       }                                                                          \
                                                                          \
     ++START;                                                             \
@@ -18639,20 +18975,26 @@ compute_overhangs_and_x (s, x, backward_p)
    DRAW_IMAGE_SUNKEN   draw an image with a sunken relief around it
    DRAW_IMAGE_RAISED   draw an image with a raised relief around it
 
-   If OVERLAPS_P is non-zero, draw only the foreground of characters
-   and clip to the physical height of ROW.
+   If OVERLAPS is non-zero, draw only the foreground of characters and
+   clip to the physical height of ROW.  Non-zero value also defines
+   the overlapping part to be drawn:
+
+   OVERLAPS_PRED               overlap with preceding rows
+   OVERLAPS_SUCC               overlap with succeeding rows
+   OVERLAPS_BOTH               overlap with both preceding/succeeding rows
+   OVERLAPS_ERASED_CURSOR      overlap with erased cursor area
 
    Value is the x-position reached, relative to AREA of W.  */
 
 static int
-draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
+draw_glyphs (w, x, row, area, start, end, hl, overlaps)
      struct window *w;
      int x;
      struct glyph_row *row;
      enum glyph_row_area area;
      int start, end;
      enum draw_glyphs_face hl;
-     int overlaps_p;
+     int overlaps;
 {
   struct glyph_string *head, *tail;
   struct glyph_string *s;
@@ -18701,7 +19043,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
   /* If there are any glyphs with lbearing < 0 or rbearing > width in
      the row, redraw some glyphs in front or following the glyph
      strings built above.  */
-  if (head && !overlaps_p && row->contains_overlapping_glyphs_p)
+  if (head && !overlaps && row->contains_overlapping_glyphs_p)
     {
       int dummy_x = 0;
       struct glyph_string *h, *t;
@@ -18794,7 +19136,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
       /* When drawing overlapping rows, only the glyph strings'
         foreground is drawn, which doesn't erase a cursor
         completely. */
-      && !overlaps_p)
+      && !overlaps)
     {
       int x0 = clip_head ? clip_head->x : (head ? head->x : x);
       int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
@@ -20527,13 +20869,15 @@ notice_overwritten_cursor (w, area, x0, x1, y0, y1)
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* EXPORT for RIF:
-   Fix the display of area AREA of overlapping row ROW in window W.  */
+   Fix the display of area AREA of overlapping row ROW in window W
+   with respect to the overlapping part OVERLAPS.  */
 
 void
-x_fix_overlapping_area (w, row, area)
+x_fix_overlapping_area (w, row, area, overlaps)
      struct window *w;
      struct glyph_row *row;
      enum glyph_row_area area;
+     int overlaps;
 {
   int i, x;
 
@@ -20556,7 +20900,7 @@ x_fix_overlapping_area (w, row, area)
 
          draw_glyphs (w, start_x, row, area,
                       start, i,
-                      DRAW_NORMAL_TEXT, 1);
+                      DRAW_NORMAL_TEXT, overlaps);
        }
       else
        {
@@ -20598,13 +20942,17 @@ draw_phys_cursor_glyph (w, row, hl)
         are redrawn.  */
       else if (hl == DRAW_NORMAL_TEXT && row->overlapped_p)
        {
+         w->phys_cursor_width = x1 - w->phys_cursor.x;
+
          if (row > w->current_matrix->rows
              && MATRIX_ROW_OVERLAPS_SUCC_P (row - 1))
-           x_fix_overlapping_area (w, row - 1, TEXT_AREA);
+           x_fix_overlapping_area (w, row - 1, TEXT_AREA,
+                                   OVERLAPS_ERASED_CURSOR);
 
          if (MATRIX_ROW_BOTTOM_Y (row) < window_text_bottom_y (w)
              && MATRIX_ROW_OVERLAPS_PRED_P (row + 1))
-           x_fix_overlapping_area (w, row + 1, TEXT_AREA);
+           x_fix_overlapping_area (w, row + 1, TEXT_AREA,
+                                   OVERLAPS_ERASED_CURSOR);
        }
     }
 }
@@ -22395,13 +22743,13 @@ expose_overlaps (w, first_overlapping_row, last_overlapping_row)
        xassert (row->enabled_p && !row->mode_line_p);
 
        if (row->used[LEFT_MARGIN_AREA])
-         x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA);
+         x_fix_overlapping_area (w, row, LEFT_MARGIN_AREA, OVERLAPS_BOTH);
 
        if (row->used[TEXT_AREA])
-         x_fix_overlapping_area (w, row, TEXT_AREA);
+         x_fix_overlapping_area (w, row, TEXT_AREA, OVERLAPS_BOTH);
 
        if (row->used[RIGHT_MARGIN_AREA])
-         x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA);
+         x_fix_overlapping_area (w, row, RIGHT_MARGIN_AREA, OVERLAPS_BOTH);
       }
 }
 
@@ -23049,7 +23397,7 @@ 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.
+    doc: /* Pixels per inch value for non-window system displays.
 Value is a number or a cons (WIDTH-DPI . HEIGHT-DPI).  */);
   Vdisplay_pixels_per_inch = make_float (72.0);