]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
(hack_wm_protocols): Use correct type for last parameter
[gnu-emacs] / src / xdisp.c
index 9bf37e21776bb52fa4322d2bd93aaa5dc9443e6e..f7a3b6dc914c463bdca5185292e8ac979b7f1c64 100644 (file)
@@ -1,6 +1,6 @@
 /* Display generation from window structure and buffer text.
-   Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04
-   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.
 
@@ -827,7 +827,6 @@ static char *decode_mode_spec_coding P_ ((Lisp_Object, char *, int));
 static int invisible_text_between_p P_ ((struct it *, int, int));
 #endif
 
-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,
@@ -902,6 +901,7 @@ static void reseat_1 P_ ((struct it *, struct text_pos, int));
 static void back_to_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_ellipsis P_ ((struct it *));
 static int next_element_from_display_vector P_ ((struct it *));
 static int next_element_from_string P_ ((struct it *));
 static int next_element_from_c_string P_ ((struct it *));
@@ -1243,28 +1243,31 @@ line_bottom_y (it)
 }
 
 
-/* Return 1 if position CHARPOS is visible in window W.  Set *FULLY to
-   1 if POS is visible and the line containing POS is fully visible.
+/* Return 1 if position CHARPOS is visible in window W.
+   If visible, set *X and *Y to pixel coordinates of top left corner.
+   Set *RTOP and *RBOT to pixel height of an invisible area of glyph at POS.
    EXACT_MODE_LINE_HEIGHTS_P non-zero means compute exact mode-line
    and header-lines heights.  */
 
 int
-pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
+pos_visible_p (w, charpos, x, y, rtop, rbot, exact_mode_line_heights_p)
      struct window *w;
-     int charpos, *fully, *x, *y, exact_mode_line_heights_p;
+     int charpos, *x, *y, *rtop, *rbot, exact_mode_line_heights_p;
 {
   struct it it;
   struct text_pos top;
-  int visible_p;
+  int visible_p = 0;
   struct buffer *old_buffer = NULL;
 
+  if (noninteractive)
+    return visible_p;
+
   if (XBUFFER (w->buffer) != current_buffer)
     {
       old_buffer = current_buffer;
       set_buffer_internal_1 (XBUFFER (w->buffer));
     }
 
-  *fully = visible_p = 0;
   SET_TEXT_POS_FROM_MARKER (top, w->start);
 
   /* Compute exact mode line heights, if requested.  */
@@ -1289,20 +1292,22 @@ pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
   if (IT_CHARPOS (it) >= charpos)
     {
       int top_y = it.current_y;
-      int bottom_y = line_bottom_y (&it);
+      int bottom_y = (last_height = 0, line_bottom_y (&it));
       int window_top_y = WINDOW_HEADER_LINE_HEIGHT (w);
 
       if (top_y < window_top_y)
        visible_p = bottom_y > window_top_y;
       else if (top_y < it.last_visible_y)
-       {
          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);
+         *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
+         if (rtop)
+           {
+             *rtop = max (0, window_top_y - top_y);
+             *rbot = max (0, bottom_y - it.last_visible_y);
+           }
        }
     }
   else if (it.current_y + it.max_ascent + it.max_descent > it.last_visible_y)
@@ -1319,6 +1324,11 @@ pos_visible_p (w, charpos, fully, x, y, exact_mode_line_heights_p)
              move_it_to (&it2, charpos, -1, -1, -1, MOVE_TO_POS);
              *x = it2.current_x;
              *y = it2.current_y + it2.max_ascent - it2.ascent;
+             if (rtop)
+               {
+                 *rtop = 0;
+                 *rbot = max (0, (it2.current_y + it2.max_ascent + it2.max_descent) - it.last_visible_y);
+               }
            }
        }
     }
@@ -1776,6 +1786,24 @@ get_glyph_string_clip_rect (s, nr)
       r.height = s->row->visible_height;
     }
 
+  if (s->clip_head)
+    if (r.x < s->clip_head->x)
+      {
+       if (r.width >= s->clip_head->x - r.x)
+         r.width -= s->clip_head->x - r.x;
+       else
+         r.width = 0;
+       r.x = s->clip_head->x;
+      }
+  if (s->clip_tail)
+    if (r.x + r.width > s->clip_tail->x + s->clip_tail->background_width)
+      {
+       if (s->clip_tail->x + s->clip_tail->background_width >= r.x)
+         r.width = s->clip_tail->x + s->clip_tail->background_width - r.x;
+       else
+         r.width = 0;
+      }
+
   /* 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.  */
@@ -1809,7 +1837,7 @@ get_glyph_string_clip_rect (s, nr)
   if (s->hl == DRAW_CURSOR)
     {
       struct glyph *glyph = s->first_glyph;
-      int height;
+      int height, max_y;
 
       if (s->x > r.x)
        {
@@ -1818,13 +1846,26 @@ get_glyph_string_clip_rect (s, nr)
        }
       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)
+      /* If r.y is below window bottom, ensure that we still see a cursor.  */
+      height = min (glyph->ascent + glyph->descent,
+                   min (FRAME_LINE_HEIGHT (s->f), s->row->visible_height));
+      max_y = window_text_bottom_y (s->w) - height;
+      max_y = WINDOW_TO_FRAME_PIXEL_Y (s->w, max_y);
+      if (s->ybase - glyph->ascent > max_y)
+       {
+         r.y = max_y;
+         r.height = height;
+       }
+      else
        {
-         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);
+         /* 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)
+           {
+             max_y = r.y + r.height;
+             r.y = min (max_y, max (r.y, s->ybase + glyph->descent - height));
+             r.height = min (max_y - r.y, height);
+           }
        }
     }
 
@@ -1835,6 +1876,64 @@ get_glyph_string_clip_rect (s, nr)
 #endif
 }
 
+
+/* EXPORT:
+   Return the position and height of the phys cursor in window W.
+   Set w->phys_cursor_width to width of phys cursor.
+*/
+
+int
+get_phys_cursor_geometry (w, row, glyph, heightp)
+     struct window *w;
+     struct glyph_row *row;
+     struct glyph *glyph;
+     int *heightp;
+{
+  struct frame *f = XFRAME (WINDOW_FRAME (w));
+  int x, y, wd, h, h0, y0;
+
+  /* Compute the width of the rectangle to draw.  If on a stretch
+     glyph, and `x-stretch-block-cursor' is nil, don't draw a
+     rectangle as wide as the glyph, but use a canonical character
+     width instead.  */
+  wd = glyph->pixel_width - 1;
+#ifdef HAVE_NTGUI
+  wd++; /* Why? */
+#endif
+  if (glyph->type == STRETCH_GLYPH
+      && !x_stretch_cursor_p)
+    wd = min (FRAME_COLUMN_WIDTH (f), wd);
+  w->phys_cursor_width = wd;
+
+  y = w->phys_cursor.y + row->ascent - glyph->ascent;
+
+  /* If y is below window bottom, ensure that we still see a cursor.  */
+  h0 = min (FRAME_LINE_HEIGHT (f), row->visible_height);
+
+  h = max (h0, glyph->ascent + glyph->descent);
+  h0 = min (h0, glyph->ascent + glyph->descent);
+
+  y0 = WINDOW_HEADER_LINE_HEIGHT (w);
+  if (y < y0)
+    {
+      h = max (h - (y0 - y) + 1, h0);
+      y = y0 - 1;
+    }
+  else
+    {
+      y0 = window_text_bottom_y (w) - h0;
+      if (y > y0)
+       {
+         h += y - y0;
+         y = y0;
+       }
+    }
+
+  *heightp = h - 1;
+  return WINDOW_TO_FRAME_PIXEL_Y (w, y);
+}
+
+
 #endif /* HAVE_WINDOW_SYSTEM */
 
 \f
@@ -1944,7 +2043,7 @@ static void
 check_it (it)
      struct it *it;
 {
-  if (it->method == next_element_from_string)
+  if (it->method == GET_FROM_STRING)
     {
       xassert (STRINGP (it->string));
       xassert (IT_STRING_CHARPOS (*it) >= 0);
@@ -1952,7 +2051,7 @@ check_it (it)
   else
     {
       xassert (IT_STRING_CHARPOS (*it) < 0);
-      if (it->method == next_element_from_buffer)
+      if (it->method == GET_FROM_BUFFER)
        {
          /* Check that character and byte positions agree.  */
          xassert (IT_CHARPOS (*it) == BYTE_TO_CHAR (IT_BYTEPOS (*it)));
@@ -2462,7 +2561,7 @@ init_from_display_pos (it, w, pos)
         property for an image, the iterator will be set up for that
         image, and we have to undo that setup first before we can
         correct the overlay string index.  */
-      if (it->method == next_element_from_image)
+      if (it->method == GET_FROM_IMAGE)
        pop_it (it);
 
       /* We already have the first chunk of overlay strings in
@@ -2485,7 +2584,7 @@ init_from_display_pos (it, w, pos)
       it->string = it->overlay_strings[relative_index];
       xassert (STRINGP (it->string));
       it->current.string_pos = pos->string_pos;
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
     }
 
 #if 0 /* This is bogus because POS not having an overlay string
@@ -2501,7 +2600,7 @@ init_from_display_pos (it, w, pos)
       while (it->sp)
        pop_it (it);
       it->current.overlay_string_index = -1;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
       if (CHARPOS (pos->pos) == ZV)
        it->overlay_strings_at_end_processed_p = 1;
     }
@@ -2615,7 +2714,7 @@ handle_stop (it)
        {
          /* Don't check for overlay strings below when set to deliver
             characters from a display vector.  */
-         if (it->method == next_element_from_display_vector)
+         if (it->method == GET_FROM_DISPLAY_VECTOR)
            handle_overlay_change_p = 0;
 
          /* Handle overlay changes.  */
@@ -3273,7 +3372,7 @@ setup_for_ellipsis (it, len)
   /* Remember the current face id in case glyphs specify faces.
      IT's face is restored in set_iterator_to_next.  */
   it->saved_face_id = it->face_id;
-  it->method = next_element_from_display_vector;
+  it->method = GET_FROM_DISPLAY_VECTOR;
   it->ellipsis_p = 1;
 }
 
@@ -3638,7 +3737,7 @@ handle_single_display_spec (it, spec, object, position,
       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->method = GET_FROM_IMAGE;
       it->face_id = face_id;
 
       /* Say that we haven't consumed the characters with
@@ -3721,7 +3820,7 @@ handle_single_display_spec (it, spec, object, position,
          it->current.overlay_string_index = -1;
          IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
          it->end_charpos = it->string_nchars = SCHARS (it->string);
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          it->stop_charpos = 0;
          it->string_from_display_prop_p = 1;
          /* Say that we haven't consumed the characters with
@@ -3731,7 +3830,7 @@ handle_single_display_spec (it, spec, object, position,
        }
       else if (CONSP (value) && EQ (XCAR (value), Qspace))
        {
-         it->method = next_element_from_stretch;
+         it->method = GET_FROM_STRETCH;
          it->object = value;
          it->current.pos = it->position = start_pos;
        }
@@ -3742,7 +3841,7 @@ handle_single_display_spec (it, spec, object, position,
          it->image_id = lookup_image (it->f, value);
          it->position = start_pos;
          it->object = NILP (object) ? it->w->buffer : object;
-         it->method = next_element_from_image;
+         it->method = GET_FROM_IMAGE;
 
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
@@ -3998,7 +4097,7 @@ handle_composition_prop (it)
 
       if (id >= 0)
        {
-         it->method = next_element_from_composition;
+         it->method = GET_FROM_COMPOSITION;
          it->cmp_id = id;
          it->cmp_len = COMPOSITION_LENGTH (prop);
          /* For a terminal, draw only the first character of the
@@ -4073,7 +4172,7 @@ next_overlay_string (it)
       it->current.overlay_string_index = -1;
       SET_TEXT_POS (it->current.string_pos, -1, -1);
       it->n_overlay_strings = 0;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
 
       /* If we're at the end of the buffer, record that we have
         processed the overlay strings there already, so that
@@ -4102,7 +4201,7 @@ next_overlay_string (it)
       it->string = it->overlay_strings[i];
       it->multibyte_p = STRING_MULTIBYTE (it->string);
       SET_TEXT_POS (it->current.string_pos, 0, 0);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
       it->stop_charpos = 0;
     }
 
@@ -4367,13 +4466,13 @@ get_overlay_strings (it, charpos)
       xassert (STRINGP (it->string));
       it->end_charpos = SCHARS (it->string);
       it->multibyte_p = STRING_MULTIBYTE (it->string);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
     }
   else
     {
       it->string = Qnil;
       it->current.overlay_string_index = -1;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
     }
 
   CHECK_IT (it);
@@ -4573,51 +4672,53 @@ static void
 back_to_previous_visible_line_start (it)
      struct it *it;
 {
-  int visible_p = 0;
-
-  /* Go back one newline if not on BEGV already.  */
-  if (IT_CHARPOS (*it) > BEGV)
-    back_to_previous_line_start (it);
-
-  /* Move over lines that are invisible because of selective display
-     or text properties.  */
-  while (IT_CHARPOS (*it) > BEGV
-        && !visible_p)
+  while (IT_CHARPOS (*it) > BEGV)
     {
-      visible_p = 1;
+      back_to_previous_line_start (it);
+      if (IT_CHARPOS (*it) <= BEGV)
+       break;
 
       /* If selective > 0, then lines indented more than that values
         are invisible.  */
       if (it->selective > 0
          && indented_beyond_p (IT_CHARPOS (*it), IT_BYTEPOS (*it),
                                (double) it->selective)) /* iftc */
-       visible_p = 0;
-      else
-       {
-         Lisp_Object prop;
+       continue;
 
-         /* Check the newline before point for invisibility.  */
-         prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
+      /* Check the newline before point for invisibility.  */
+      {
+       Lisp_Object prop;
+       prop = Fget_char_property (make_number (IT_CHARPOS (*it) - 1),
                                     Qinvisible, it->window);
-         if (TEXT_PROP_MEANS_INVISIBLE (prop))
-           visible_p = 0;
-       }
-
-#if 0
-      /* Commenting this out fixes the bug described in
-        http://www.math.ku.dk/~larsh/emacs/emacs-loops-on-large-images/test-case.txt.  */
-      if (visible_p)
-       {
-         struct it it2 = *it;
-
-         if (handle_display_prop (&it2) == HANDLED_RETURN)
-           visible_p = 0;
-       }
-#endif
+       if (TEXT_PROP_MEANS_INVISIBLE (prop))
+         continue;
+      }
 
-      /* Back one more newline if the current one is invisible.  */
-      if (!visible_p)
-       back_to_previous_line_start (it);
+      /* If newline has a display property that replaces the newline with something
+        else (image or text), find start of overlay or interval and continue search
+        from that point.  */
+      {
+       struct it it2 = *it;
+       int pos = IT_CHARPOS (*it);
+       int beg, end;
+       Lisp_Object val, overlay;
+
+       it2.sp = 0;
+       if (handle_display_prop (&it2) == HANDLED_RETURN
+           && !NILP (val = get_char_property_and_overlay
+                     (make_number (pos), Qdisplay, Qnil, &overlay))
+           && (OVERLAYP (overlay)
+               ? (beg = OVERLAY_POSITION (OVERLAY_START (overlay)))
+               : get_property_and_range (pos, Qdisplay, &val, &beg, &end, Qnil)))
+         {
+           if (beg < BEGV)
+             beg = BEGV;
+           IT_CHARPOS (*it) = beg;
+           IT_BYTEPOS (*it) = buf_charpos_to_bytepos (current_buffer, beg);
+           continue;
+         }
+      }
+      break;
     }
 
   xassert (IT_CHARPOS (*it) >= BEGV);
@@ -4749,7 +4850,7 @@ reseat_1 (it, pos, set_stop_p)
   IT_STRING_CHARPOS (*it) = -1;
   IT_STRING_BYTEPOS (*it) = -1;
   it->string = Qnil;
-  it->method = next_element_from_buffer;
+  it->method = GET_FROM_BUFFER;
   /* RMS: I added this to fix a bug in move_it_vertically_backward
      where it->area continued to relate to the starting point
      for the backward motion.  Bug report from
@@ -4815,7 +4916,7 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
       it->string = string;
       it->s = NULL;
       it->end_charpos = it->string_nchars = SCHARS (string);
-      it->method = next_element_from_string;
+      it->method = GET_FROM_STRING;
       it->current.string_pos = string_pos (charpos, string);
     }
   else
@@ -4837,7 +4938,7 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
          it->end_charpos = it->string_nchars = strlen (s);
        }
 
-      it->method = next_element_from_c_string;
+      it->method = GET_FROM_C_STRING;
     }
 
   /* PRECISION > 0 means don't return more than PRECISION characters
@@ -4868,6 +4969,20 @@ reseat_to_string (it, s, string, charpos, precision, field_width, multibyte)
                              Iteration
  ***********************************************************************/
 
+/* Map enum it_method value to corresponding next_element_from_* function.  */
+
+static int (* get_next_element[NUM_IT_METHODS]) P_ ((struct it *it)) =
+{
+  next_element_from_buffer,
+  next_element_from_display_vector,
+  next_element_from_composition,
+  next_element_from_string,
+  next_element_from_c_string,
+  next_element_from_image,
+  next_element_from_stretch
+};
+
+
 /* Load IT's display element fields with information about the next
    display element from the current position of IT.  Value is zero if
    end of buffer (or C string) is reached.  */
@@ -4883,7 +4998,7 @@ get_next_display_element (it)
   int success_p;
 
  get_next:
-  success_p = (*it->method) (it);
+  success_p = (*get_next_element[it->method]) (it);
 
   if (it->what == IT_CHARACTER)
     {
@@ -4917,7 +5032,7 @@ get_next_display_element (it)
                  it->current.dpvec_index = 0;
                  it->dpvec_face_id = -1;
                  it->saved_face_id = it->face_id;
-                 it->method = next_element_from_display_vector;
+                 it->method = GET_FROM_DISPLAY_VECTOR;
                  it->ellipsis_p = 0;
                }
              else
@@ -4943,7 +5058,7 @@ get_next_display_element (it)
          else if ((it->c < ' '
                    && (it->area != TEXT_AREA
                        /* In mode line, treat \n like other crl chars.  */
-                       || (it->c != '\n'
+                       || (it->c != '\t'
                            && it->glyph_row && it->glyph_row->mode_line_p)
                        || (it->c != '\n' && it->c != '\t')))
                   || (it->multibyte_p
@@ -4978,18 +5093,15 @@ get_next_display_element (it)
                      if (lface_id)
                        {
                          g = FAST_GLYPH_CHAR (g);
-                         /* The function returns -1 if lface_id is invalid.  */
-                         face_id = ascii_face_of_lisp_face (it->f, lface_id);
-                         if (face_id >= 0)
-                           face_id = merge_into_realized_face (it->f, Qnil,
-                                                               face_id, it->face_id);
+                         face_id = merge_faces (it->f, Qt, lface_id,
+                                                it->face_id);
                        }
                    }
                  else
                    {
                      /* Merge the escape-glyph face into the current face.  */
-                     face_id = merge_into_realized_face (it->f, Qescape_glyph,
-                                                         0, it->face_id);
+                     face_id = merge_faces (it->f, Qescape_glyph, 0,
+                                            it->face_id);
                      g = '^';
                    }
 
@@ -5009,18 +5121,15 @@ get_next_display_element (it)
                  if (lface_id)
                    {
                      escape_glyph = FAST_GLYPH_CHAR (escape_glyph);
-                     /* The function returns -1 if lface_id is invalid.  */
-                     face_id = ascii_face_of_lisp_face (it->f, lface_id);
-                     if (face_id >= 0)
-                       face_id = merge_into_realized_face (it->f, Qnil,
-                                                           face_id, it->face_id);
+                     face_id = merge_faces (it->f, Qt, lface_id,
+                                            it->face_id);
                    }
                }
              else
                {
                  /* Merge the escape-glyph face into the current face.  */
-                 face_id = merge_into_realized_face (it->f, Qescape_glyph,
-                                                     0, it->face_id);
+                 face_id = merge_faces (it->f, Qescape_glyph, 0,
+                                        it->face_id);
                  escape_glyph = '\\';
                }
 
@@ -5081,7 +5190,7 @@ get_next_display_element (it)
              it->current.dpvec_index = 0;
              it->dpvec_face_id = face_id;
              it->saved_face_id = it->face_id;
-             it->method = next_element_from_display_vector;
+             it->method = GET_FROM_DISPLAY_VECTOR;
              it->ellipsis_p = 0;
              goto get_next;
            }
@@ -5143,8 +5252,9 @@ set_iterator_to_next (it, reseat_p)
      moving the iterator to a new position might set them.  */
   it->start_of_box_run_p = it->end_of_box_run_p = 0;
 
-  if (it->method == next_element_from_buffer)
+  switch (it->method)
     {
+    case GET_FROM_BUFFER:
       /* The current display element of IT is a character from
         current_buffer.  Advance in the buffer, and maybe skip over
         invisible lines that are so because of selective display.  */
@@ -5157,32 +5267,32 @@ set_iterator_to_next (it, reseat_p)
          IT_CHARPOS (*it) += 1;
          xassert (IT_BYTEPOS (*it) == CHAR_TO_BYTE (IT_CHARPOS (*it)));
        }
-    }
-  else if (it->method == next_element_from_composition)
-    {
-      xassert (it->cmp_id >= 0 && it ->cmp_id < n_compositions);
+      break;
+
+    case GET_FROM_COMPOSITION:
+      xassert (it->cmp_id >= 0 && it->cmp_id < n_compositions);
       if (STRINGP (it->string))
        {
          IT_STRING_BYTEPOS (*it) += it->len;
          IT_STRING_CHARPOS (*it) += it->cmp_len;
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          goto consider_string_end;
        }
       else
        {
          IT_BYTEPOS (*it) += it->len;
          IT_CHARPOS (*it) += it->cmp_len;
-         it->method = next_element_from_buffer;
+         it->method = GET_FROM_BUFFER;
        }
-    }
-  else if (it->method == next_element_from_c_string)
-    {
+      break;
+
+    case GET_FROM_C_STRING:
       /* Current display element of IT is from a C string.  */
       IT_BYTEPOS (*it) += it->len;
       IT_CHARPOS (*it) += 1;
-    }
-  else if (it->method == next_element_from_display_vector)
-    {
+      break;
+
+    case GET_FROM_DISPLAY_VECTOR:
       /* Current display element of IT is from a display table entry.
         Advance in the display table definition.  Reset it to null if
         end reached, and continue with characters from buffers/
@@ -5196,11 +5306,11 @@ set_iterator_to_next (it, reseat_p)
       if (it->dpvec + it->current.dpvec_index == it->dpend)
        {
          if (it->s)
-           it->method = next_element_from_c_string;
+           it->method = GET_FROM_C_STRING;
          else if (STRINGP (it->string))
-           it->method = next_element_from_string;
+           it->method = GET_FROM_STRING;
          else
-           it->method = next_element_from_buffer;
+           it->method = GET_FROM_BUFFER;
 
          it->dpvec = NULL;
          it->current.dpvec_index = -1;
@@ -5217,9 +5327,9 @@ set_iterator_to_next (it, reseat_p)
          /* Recheck faces after display vector */
          it->stop_charpos = IT_CHARPOS (*it);
        }
-    }
-  else if (it->method == next_element_from_string)
-    {
+      break;
+
+    case GET_FROM_STRING:
       /* Current display element is a character from a Lisp string.  */
       xassert (it->s == NULL && STRINGP (it->string));
       IT_STRING_BYTEPOS (*it) += it->len;
@@ -5244,34 +5354,35 @@ set_iterator_to_next (it, reseat_p)
              && it->sp > 0)
            {
              pop_it (it);
-             if (!STRINGP (it->string))
-               it->method = next_element_from_buffer;
-             else
+             if (STRINGP (it->string))
                goto consider_string_end;
+             it->method = GET_FROM_BUFFER;
            }
        }
-    }
-  else if (it->method == next_element_from_image
-          || it->method == next_element_from_stretch)
-    {
+      break;
+
+    case GET_FROM_IMAGE:
+    case GET_FROM_STRETCH:
       /* The position etc with which we have to proceed are on
         the stack.  The position may be at the end of a string,
          if the `display' property takes up the whole string.  */
+      xassert (it->sp > 0);
       pop_it (it);
       it->image_id = 0;
       if (STRINGP (it->string))
        {
-         it->method = next_element_from_string;
+         it->method = GET_FROM_STRING;
          goto consider_string_end;
        }
-      else
-       it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
+      break;
+
+    default:
+      /* There are no other methods defined, so this should be a bug.  */
+      abort ();
     }
-  else
-    /* There are no other methods defined, so this should be a bug.  */
-    abort ();
 
-  xassert (it->method != next_element_from_string
+  xassert (it->method != GET_FROM_STRING
           || (STRINGP (it->string)
               && IT_STRING_CHARPOS (*it) >= 0));
 }
@@ -5309,13 +5420,9 @@ next_element_from_display_vector (it)
       else
        {
          int lface_id = FAST_GLYPH_FACE (g);
-         if (lface_id)
-           {
-             /* The function returns -1 if lface_id is invalid.  */
-             int face_id = ascii_face_of_lisp_face (it->f, lface_id);
-             if (face_id >= 0)
-               it->face_id = face_id;
-           }
+         if (lface_id > 0)
+           it->face_id = merge_faces (it->f, Qt, lface_id,
+                                      it->saved_face_id);
        }
     }
   else
@@ -5487,7 +5594,7 @@ next_element_from_ellipsis (it)
         was in IT->saved_face_id, and signal that it's there by
         setting face_before_selective_p.  */
       it->saved_face_id = it->face_id;
-      it->method = next_element_from_buffer;
+      it->method = GET_FROM_BUFFER;
       reseat_at_next_visible_line_start (it, 1);
       it->face_before_selective_p = 1;
     }
@@ -5728,11 +5835,14 @@ 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           \
-   && it->method == next_element_from_buffer)
+#define BUFFER_POS_REACHED_P()                                 \
+  ((op & MOVE_TO_POS) != 0                                     \
+   && BUFFERP (it->object)                                     \
+   && IT_CHARPOS (*it) >= to_charpos                           \
+   && (it->method == GET_FROM_BUFFER ||                                \
+       (it->method == GET_FROM_DISPLAY_VECTOR &&               \
+       it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
+
 
   while (1)
     {
@@ -6394,11 +6504,15 @@ move_it_by_lines (it, dvpos, need_y_p)
       it->current_y -= it2.current_y;
       it->current_x = it->hpos = 0;
 
-      /* If we moved too far, move IT some lines forward.  */
+      /* If we moved too far back, move IT some lines forward.  */
       if (it2.vpos > -dvpos)
        {
          int delta = it2.vpos + dvpos;
+         it2 = *it;
          move_it_to (it, -1, -1, -1, it->vpos + delta, MOVE_TO_VPOS);
+         /* Move back again if we got too far ahead.  */
+         if (IT_CHARPOS (*it) >= start_charpos)
+           *it = it2;
        }
     }
 }
@@ -6409,7 +6523,7 @@ int
 in_display_vector_p (it)
      struct it *it;
 {
-  return (it->method == next_element_from_display_vector
+  return (it->method == GET_FROM_DISPLAY_VECTOR
          && it->current.dpvec_index > 0
          && it->dpvec + it->current.dpvec_index != it->dpend);
 }
@@ -7991,6 +8105,8 @@ echo_area_display (update_frame_p)
 
   /* Last displayed message is now the current message.  */
   echo_area_buffer[1] = echo_area_buffer[0];
+  /* Inform read_char that we're not echoing.  */
+  echo_message_buffer = Qnil;
 
   /* Prevent redisplay optimization in redisplay_internal by resetting
      this_line_start_pos.  This is done because the mini-buffer now
@@ -12230,6 +12346,8 @@ redisplay_window (window, just_this_one_p)
       /* If centering point failed to make the whole line visible,
         put point at the top instead.  That has to make the whole line
         visible, if it can be done.  */
+      if (centering_position == 0)
+       goto done;
       clear_glyph_matrix (w->desired_matrix);
       centering_position = 0;
       goto point_at_top;
@@ -13725,7 +13843,12 @@ try_window_id (w)
                        bottom_vpos, dy);
 
   if (first_unchanged_at_end_row)
-    first_unchanged_at_end_row += dvpos;
+    {
+      first_unchanged_at_end_row += dvpos;
+      if (first_unchanged_at_end_row->y >= it.last_visible_y
+         || !MATRIX_ROW_DISPLAYS_TEXT_P (first_unchanged_at_end_row))
+       first_unchanged_at_end_row = NULL;
+    }
 
   /* If scrolling up, there may be some lines to display at the end of
      the window.  */
@@ -13782,7 +13905,6 @@ try_window_id (w)
 
   /* Update window_end_pos and window_end_vpos.  */
   if (first_unchanged_at_end_row
-      && first_unchanged_at_end_row->y < it.last_visible_y
       && !last_text_row_at_end)
     {
       /* Window end line if one of the preserved rows from the current
@@ -15142,7 +15264,7 @@ display_line (it)
 
   /* Record whether this row ends inside an ellipsis.  */
   row->ends_in_ellipsis_p
-    = (it->method == next_element_from_display_vector
+    = (it->method == GET_FROM_DISPLAY_VECTOR
        && it->ellipsis_p);
 
   /* Save fringe bitmaps in this row.  */
@@ -15989,20 +16111,29 @@ store_mode_line_string (string, lisp_string, copy_string, field_width, precision
 
 DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
        1, 4, 0,
-       doc: /* Return the mode-line of selected window as a string.
-First arg FORMAT specifies the mode line format (see `mode-line-format' for
-details) to use.  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.  Fourth optional arg BUFFER specifies
-which buffer to use.  */)
-  (format, window, no_props, buffer)
-     Lisp_Object format, window, no_props, buffer;
+       doc: /* Format a string out of a mode line format specification.
+First arg FORMAT specifies the mode line format (see `mode-line-format'
+for details) to use.
+
+Optional second arg FACE specifies the face property to put
+on all characters for which no face is specified.
+t means whatever face the window's mode line currently uses
+\(either `mode-line' or `mode-line-inactive', depending).
+nil means the default is no face property.
+If FACE is an integer, the value string has no text properties.
+
+Optional third and fourth args WINDOW and BUFFER specify the window
+and buffer to use as the context for the formatting (defaults
+are the selected window and the window's buffer).  */)
+  (format, face, window, buffer)
+     Lisp_Object format, face, window, buffer;
 {
   struct it it;
   int len;
   struct window *w;
   struct buffer *old_buffer = NULL;
-  enum face_id face_id = DEFAULT_FACE_ID;
+  int face_id = -1;
+  int no_props = INTEGERP (face);
 
   if (NILP (window))
     window = selected_window;
@@ -16011,9 +16142,24 @@ which buffer to use.  */)
 
   if (NILP (buffer))
     buffer = w->buffer;
-
   CHECK_BUFFER (buffer);
 
+  if (NILP (format))
+    return build_string ("");
+
+  if (no_props)
+    face = Qnil;
+
+  if (!NILP (face))
+    {
+      if (EQ (face, Qt))
+       face = (EQ (window, selected_window) ? Qmode_line : Qmode_line_inactive);
+      face_id = lookup_named_face (XFRAME (WINDOW_FRAME (w)), face, 0, 0);
+    }
+
+  if (face_id < 0)
+    face_id = DEFAULT_FACE_ID;
+
   if (XBUFFER (buffer) != current_buffer)
     {
       old_buffer = current_buffer;
@@ -16022,16 +16168,11 @@ which buffer to use.  */)
 
   init_iterator (&it, w, -1, -1, NULL, face_id);
 
-  if (NILP (no_props))
+  if (!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;
       mode_line_string_face_prop
-       = (NILP (mode_line_string_face) ? Qnil
-          : Fcons (Qface, Fcons (mode_line_string_face, Qnil)));
+       = (NILP (face) ? Qnil : Fcons (Qface, Fcons (face, Qnil)));
 
       /* We need a dummy last element in mode_line_string_list to
         indicate we are building the propertized mode-line string.
@@ -16054,7 +16195,7 @@ which buffer to use.  */)
   if (old_buffer)
     set_buffer_internal_1 (old_buffer);
 
-  if (NILP (no_props))
+  if (!no_props)
     {
       Lisp_Object str;
       mode_line_string_list = Fnreverse (mode_line_string_list);
@@ -18211,6 +18352,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
 {
   struct glyph_string *head, *tail;
   struct glyph_string *s;
+  struct glyph_string *clip_head = NULL, *clip_tail = NULL;
   int last_x, area_width;
   int x_reached;
   int i, j;
@@ -18279,6 +18421,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
          start = i;
          compute_overhangs_and_x (t, head->x, 1);
          prepend_glyph_string_lists (&head, &tail, h, t);
+         clip_head = head;
        }
 
       /* Prepend glyph strings for glyphs in front of the first glyph
@@ -18291,6 +18434,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
       i = left_overwriting (head);
       if (i >= 0)
        {
+         clip_head = head;
          BUILD_GLYPH_STRINGS (i, start, h, t,
                               DRAW_NORMAL_TEXT, dummy_x, last_x);
          for (s = h; s; s = s->next)
@@ -18310,6 +18454,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
                               DRAW_NORMAL_TEXT, x, last_x);
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
+         clip_tail = tail;
        }
 
       /* Append glyph strings for glyphs following the last glyph
@@ -18320,6 +18465,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
       i = right_overwriting (tail);
       if (i >= 0)
        {
+         clip_tail = tail;
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               DRAW_NORMAL_TEXT, x, last_x);
          for (s = h; s; s = s->next)
@@ -18327,6 +18473,12 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
          compute_overhangs_and_x (h, tail->x + tail->width, 0);
          append_glyph_string_lists (&head, &tail, h, t);
        }
+      if (clip_head || clip_tail)
+       for (s = head; s; s = s->next)
+         {
+           s->clip_head = clip_head;
+           s->clip_tail = clip_tail;
+         }
     }
 
   /* Draw all strings.  */
@@ -18340,8 +18492,9 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps_p)
         completely. */
       && !overlaps_p)
     {
-      int x0 = head ? head->x : x;
-      int x1 = tail ? tail->x + tail->background_width : x;
+      int x0 = clip_head ? clip_head->x : (head ? head->x : x);
+      int x1 = (clip_tail ? clip_tail->x + clip_tail->background_width
+               : (tail ? tail->x + tail->background_width : x));
 
       int text_left = window_box_left (w, TEXT_AREA);
       x0 -= text_left;
@@ -20593,6 +20746,28 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
       past_end = 1;
     }
 
+  /* If whole rows or last part of a row came from a display overlay,
+     row_containing_pos will skip over such rows because their end pos
+     equals the start pos of the overlay or interval.  Backtrack if we
+     have a STOP object and previous row's end glyph came from STOP.  */
+  if (!NILP (stop))
+    {
+      struct glyph_row *prev = row-1;
+      while ((prev = row - 1, prev >= first)
+            && MATRIX_ROW_END_CHARPOS (prev) == charpos
+            && prev->used[TEXT_AREA] > 0)
+       {
+         end = prev->glyphs[TEXT_AREA];
+         glyph = end + prev->used[TEXT_AREA];
+         while (--glyph >= end
+                && INTEGERP (glyph->object));
+         if (glyph >= end
+             && !EQ (stop, glyph->object))
+           break;
+         row = prev;
+       }
+    }
+
   *x = row->x;
   *y = row->y;
   *vpos = MATRIX_ROW_VPOS (row, w->current_matrix);
@@ -21054,9 +21229,9 @@ note_mode_line_or_margin_highlight (w, x, y, area)
                  help_echo_pos = charpos;
                }
            }
-         if (NILP (pointer))
-           pointer = Fsafe_plist_get (XCDR (object), QCpointer);
        }
+      if (NILP (pointer))
+       pointer = Fsafe_plist_get (XCDR (object), QCpointer);
     }
 
   if (STRINGP (string))
@@ -21934,7 +22109,9 @@ expose_window (w, fr)
              || (r.y >= y0 && r.y < y1)
              || (r.y + r.height > y0 && r.y + r.height < y1))
            {
-             if (row->overlapping_p)
+             /* A header line may be overlapping, but there is no need
+                to fix overlapping areas for them.  KFS 2005-02-12 */
+             if (row->overlapping_p && !row->mode_line_p)
                {
                  if (first_overlapping_row == NULL)
                    first_overlapping_row = row;