* dispextern.h (face_at_buffer_position, face_for_overlay_string)
[bpt/emacs.git] / src / xdisp.c
index 9624487..6876f16 100644 (file)
@@ -1,7 +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, 2006, 2007 Free Software Foundation, Inc.
+                 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -239,6 +239,7 @@ extern Lisp_Object Qhelp_echo;
 
 Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map;
 Lisp_Object Qwindow_scroll_functions, Vwindow_scroll_functions;
+Lisp_Object Qwindow_text_change_functions, Vwindow_text_change_functions;
 Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
 Lisp_Object Qinhibit_point_motion_hooks;
 Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
@@ -696,6 +697,7 @@ int trace_move;
    point visible.  */
 
 int automatic_hscrolling_p;
+Lisp_Object Qauto_hscroll_mode;
 
 /* How close to the margin can point get before the window is scrolled
    horizontally.  */
@@ -915,11 +917,12 @@ static int display_mode_lines P_ ((struct window *));
 static int display_mode_line P_ ((struct window *, enum face_id, Lisp_Object));
 static int display_mode_element P_ ((struct it *, int, int, int, Lisp_Object, Lisp_Object, int));
 static int store_mode_line_string P_ ((char *, Lisp_Object, int, int, int, Lisp_Object));
-static char *decode_mode_spec P_ ((struct window *, int, int, int, int *));
+static char *decode_mode_spec P_ ((struct window *, int, int, int, int *,
+                                  Lisp_Object *));
 static void display_menu_bar P_ ((struct window *));
 static int display_count_lines P_ ((int, int, int, int, int *));
 static int display_string P_ ((unsigned char *, Lisp_Object, Lisp_Object,
-                              int, int, struct it *, int, int, int, int));
+                              EMACS_INT, EMACS_INT, struct it *, int, int, int, int));
 static void compute_line_metrics P_ ((struct it *));
 static void run_redisplay_end_trigger_hook P_ ((struct it *));
 static int get_overlay_strings P_ ((struct it *, int));
@@ -961,7 +964,7 @@ static void compute_stop_pos P_ ((struct it *));
 static void compute_string_pos P_ ((struct text_pos *, struct text_pos,
                                    Lisp_Object));
 static int face_before_or_after_it_pos P_ ((struct it *, int));
-static int next_overlay_change P_ ((int));
+static EMACS_INT next_overlay_change P_ ((EMACS_INT));
 static int handle_single_display_spec P_ ((struct it *, Lisp_Object,
                                           Lisp_Object, Lisp_Object,
                                           struct text_pos *, int));
@@ -1328,6 +1331,28 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, rowh, vpos)
          visible_p = 1;
       if (visible_p)
        {
+         Lisp_Object window, prop;
+
+         XSETWINDOW (window, w);
+         prop = Fget_char_property (make_number (it.position.charpos),
+                                    Qinvisible, window);
+
+         /* If charpos coincides with invisible text covered with an
+            ellipsis, use the first glyph of the ellipsis to compute
+            the pixel positions.  */
+         if (TEXT_PROP_MEANS_INVISIBLE (prop) == 2)
+           {
+             struct glyph_row *row = it.glyph_row;
+             struct glyph *glyph = row->glyphs[TEXT_AREA];
+             struct glyph *end = glyph + row->used[TEXT_AREA];
+             int x = row->x;
+
+             for (; glyph < end && glyph->charpos < charpos; glyph++)
+               x += glyph->pixel_width;
+
+             top_x = x;
+           }
+
          *x = top_x;
          *y = max (top_y + max (0, it.max_ascent - it.ascent), window_top_y);
          *rtop = max (0, window_top_y - top_y);
@@ -2512,7 +2537,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id)
   XSETWINDOW (it->window, w);
   it->w = w;
   it->f = XFRAME (w->frame);
-  
+
   /* Extra space between lines (on window systems only).  */
   if (base_face_id == DEFAULT_FACE_ID
       && FRAME_WINDOW_P (it->f))
@@ -3199,12 +3224,12 @@ compute_stop_pos (it)
    follows.  This is like `next-overlay-change' but doesn't use
    xmalloc.  */
 
-static int
+static EMACS_INT
 next_overlay_change (pos)
-     int pos;
+     EMACS_INT pos;
 {
   int noverlays;
-  int endpos;
+  EMACS_INT endpos;
   Lisp_Object *overlays;
   int i;
 
@@ -3216,7 +3241,7 @@ next_overlay_change (pos)
   for (i = 0; i < noverlays; ++i)
     {
       Lisp_Object oend;
-      int oendpos;
+      EMACS_INT oendpos;
 
       oend = OVERLAY_END (overlays[i]);
       oendpos = OVERLAY_POSITION (oend);
@@ -3328,7 +3353,8 @@ static enum prop_handled
 handle_face_prop (it)
      struct it *it;
 {
-  int new_face_id, next_stop;
+  int new_face_id;
+  EMACS_INT next_stop;
 
   if (!STRINGP (it->string))
     {
@@ -3496,7 +3522,7 @@ face_before_or_after_it_pos (it, before_p)
      int before_p;
 {
   int face_id, limit;
-  int next_check_charpos;
+  EMACS_INT next_check_charpos;
   struct text_pos pos;
 
   xassert (it->s == NULL);
@@ -4553,103 +4579,86 @@ handle_auto_composed_prop (it)
 
   if (FUNCTIONP (Vauto_composition_function))
     {
-      Lisp_Object val;
-      EMACS_INT pos, this_pos;
+      Lisp_Object val = Qnil;
+      EMACS_INT pos, limit = -1;
 
       if (STRINGP (it->string))
        pos = IT_STRING_CHARPOS (*it);
       else
        pos = IT_CHARPOS (*it);
-      this_pos = pos;
 
-      val =Fget_char_property (make_number (pos), Qauto_composed, it->string);
+      val = Fget_text_property (make_number (pos), Qauto_composed, it->string);
       if (! NILP (val))
        {
-         Lisp_Object limit = Qnil, next;
-         
-         /* As Fnext_single_char_property_change is very slow, we
-            limit the search to the current line.  */
-         if (STRINGP (it->string))
-           limit = make_number (SCHARS (it->string));
-         else
-           limit = make_number (find_next_newline_no_quit (pos, 1));
+         Lisp_Object cmp_prop;
+         EMACS_INT cmp_start, cmp_end;
 
-         next = (Fnext_single_property_change
-                 (make_number (pos), Qauto_composed, it->string, limit));
-         if (XINT (next) < XINT (limit))
+#ifdef USE_FONT_BACKEND
+         if (enable_font_backend
+             && get_property_and_range (pos, Qcomposition, &cmp_prop,
+                                        &cmp_start, &cmp_end, it->string)
+             && cmp_start == pos
+             && COMPOSITION_METHOD (cmp_prop) == COMPOSITION_WITH_GLYPH_STRING)
            {
-             /* The current point is auto-composed, but there exist
-                characters not yet composed beyond the auto-composed
-                region.  There's a possiblity that the last
-                characters in the region may be newly composed.  */
-             int charpos = XINT (next) - 1, bytepos, c;
+             Lisp_Object gstring = COMPOSITION_COMPONENTS (cmp_prop);
+             Lisp_Object font_object = LGSTRING_FONT (gstring);
+
+             if (! EQ (font_object,
+                       font_at (-1, pos, FACE_FROM_ID (it->f, it->face_id),
+                                it->w, it->string)))
+               /* We must re-compute the composition for the
+                  different font.  */
+               val = Qnil;
+           }
+#endif
+         if (! NILP (val))
+           {
+             Lisp_Object end;
 
+             /* As Fnext_single_char_property_change is very slow, we
+                limit the search to the current line.  */
              if (STRINGP (it->string))
-               {
-                 bytepos = string_char_to_byte (it->string, charpos);
-                 c = SDATA (it->string)[bytepos];
-               }
+               limit = SCHARS (it->string);
              else
-               {
-                 bytepos = CHAR_TO_BYTE (charpos);
-                 c = FETCH_BYTE (bytepos);
-               }
-             if (c != '\n')
-               /* If the last character is not newline, it may be
-                  composed with the following characters.  */
-               val = Qnil, pos = charpos + 1;
+               limit = find_next_newline_no_quit (pos, 1);
+             end = Fnext_single_char_property_change (make_number (pos),
+                                                      Qauto_composed,
+                                                      it->string,
+                                                      make_number (limit));
+
+             if (XINT (end) < limit)
+               /* The current point is auto-composed, but there exist
+                  characters not yet composed beyond the
+                  auto-composed region.  There's a possiblity that
+                  the last characters in the region may be newly
+                  composed.  */
+               val = Qnil;
            }
        }
       if (NILP (val))
        {
-         int count = SPECPDL_INDEX ();
-         Lisp_Object args[4];
-
-         args[0] = Vauto_composition_function;
-         specbind (Qauto_composition_function, Qnil);
-         args[1] = make_number (pos);
-         args[2] = it->string;
-#ifdef USE_FONT_BACKEND
-         if (enable_font_backend)
+         if (limit < 0)
+           limit = (STRINGP (it->string) ? SCHARS (it->string)
+                    : find_next_newline_no_quit (pos, 1));
+         if (pos < limit)
            {
-             struct face *face = FACE_FROM_ID (it->f, it->face_id);
-             int c;
-
-             if (STRINGP (it->string))
-               {
-                 EMACS_INT pos_byte = IT_STRING_BYTEPOS (*it);
-                 const unsigned char *s = SDATA (it->string) + pos_byte;
+             int count = SPECPDL_INDEX ();
+             Lisp_Object args[5];
 
-                 if (STRING_MULTIBYTE (it->string))
-                   it->c = STRING_CHAR (s, 0);
-                 else
-                   it->c = *s;
-               }
+             args[0] = Vauto_composition_function;
+             specbind (Qauto_composition_function, Qnil);
+             args[1] = make_number (pos);
+             args[2] = make_number (limit);
+#ifdef USE_FONT_BACKEND
+             if (enable_font_backend)
+               args[3] = it->window;
              else
-               {
-                 EMACS_INT pos_byte = IT_BYTEPOS (*it);
-
-                 it->c = FETCH_CHAR (pos_byte);
-               }
-             args[3] = font_at (it->c, this_pos, face, it->w, it->string);
-           }
-         else
 #endif /* USE_FONT_BACKEND */
-           args[3] = Qnil;
-         safe_call (4, args);
-         unbind_to (count, Qnil);
-
-         if (this_pos == pos)
-           {
-             val = Fget_char_property (args[1], Qauto_composed, it->string);
-             /* Return HANDLED_RECOMPUTE_PROPS only if function composed
-                something.  This avoids an endless loop if they failed to
-                fontify the text for which reason ever.  */
-             if (! NILP (val))
-               handled = HANDLED_RECOMPUTE_PROPS;
+               args[3] = Qnil;
+             args[4] = it->string;
+             safe_call (5, args);
+             unbind_to (count, Qnil);
            }
-         else
-           handled = HANDLED_RECOMPUTE_PROPS;
        }
     }
 
@@ -4669,15 +4678,20 @@ handle_composition_prop (it)
 
   if (STRINGP (it->string))
     {
+      unsigned char *s;
+
       pos = IT_STRING_CHARPOS (*it);
       pos_byte = IT_STRING_BYTEPOS (*it);
       string = it->string;
+      s = SDATA (string) + pos_byte;
+      it->c = STRING_CHAR (s, 0);
     }
   else
     {
       pos = IT_CHARPOS (*it);
       pos_byte = IT_BYTEPOS (*it);
       string = Qnil;
+      it->c = FETCH_CHAR (pos_byte);
     }
 
   /* If there's a valid composition and point is not inside of the
@@ -4730,11 +4744,10 @@ handle_composition_prop (it)
 #ifdef USE_FONT_BACKEND
          if (composition_table[id]->method == COMPOSITION_WITH_GLYPH_STRING)
            {
+             /* FIXME: This doesn't do anything!?! */
              Lisp_Object lgstring = AREF (XHASH_TABLE (composition_hash_table)
                                           ->key_and_value,
                                           cmp->hash_index * 2);
-
-             it->c = XINT (LGLYPH_CHAR (LGSTRING_GLYPH (lgstring, 0)));
            }
          else
 #endif /* USE_FONT_BACKEND */
@@ -5408,7 +5421,7 @@ back_to_previous_visible_line_start (it)
       {
        struct it it2;
        int pos;
-       int beg, end;
+       EMACS_INT beg, end;
        Lisp_Object val, overlay;
 
        /* If newline is part of a composition, continue from start of composition */
@@ -5987,7 +6000,7 @@ get_next_display_element (it)
       int pos = (it->s ? -1
                 : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
                 : IT_CHARPOS (*it));
-         
+
       it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
     }
 
@@ -8207,7 +8220,7 @@ with_echo_area_buffer_unwind_data (w)
      struct window *w;
 {
   int i = 0;
-  Lisp_Object vector;
+  Lisp_Object vector, tmp;
 
   /* Reduce consing by keeping one vector in
      Vwith_echo_area_save_vector.  */
@@ -8217,22 +8230,22 @@ with_echo_area_buffer_unwind_data (w)
   if (NILP (vector))
     vector = Fmake_vector (make_number (7), Qnil);
 
-  XSETBUFFER (AREF (vector, i), current_buffer); ++i;
-  AREF (vector, i) = Vdeactivate_mark, ++i;
-  AREF (vector, i) = make_number (windows_or_buffers_changed), ++i;
+  XSETBUFFER (tmp, current_buffer); ASET (vector, i, tmp); ++i;
+  ASET (vector, i, Vdeactivate_mark); ++i;
+  ASET (vector, i, make_number (windows_or_buffers_changed)); ++i;
 
   if (w)
     {
-      XSETWINDOW (AREF (vector, i), w); ++i;
-      AREF (vector, i) = w->buffer; ++i;
-      AREF (vector, i) = make_number (XMARKER (w->pointm)->charpos); ++i;
-      AREF (vector, i) = make_number (XMARKER (w->pointm)->bytepos); ++i;
+      XSETWINDOW (tmp, w); ASET (vector, i, tmp); ++i;
+      ASET (vector, i, w->buffer); ++i;
+      ASET (vector, i, make_number (XMARKER (w->pointm)->charpos)); ++i;
+      ASET (vector, i, make_number (XMARKER (w->pointm)->bytepos)); ++i;
     }
   else
     {
       int end = i + 4;
       for (; i < end; ++i)
-       AREF (vector, i) = Qnil;
+       ASET (vector, i, Qnil);
     }
 
   xassert (i == ASIZE (vector));
@@ -8463,7 +8476,7 @@ resize_mini_window_1 (a1, exactly, a3, a4)
 }
 
 
-/* Resize mini-window W to fit the size of its contents.  EXACT:P
+/* 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.
 
@@ -8905,11 +8918,11 @@ clear_garbaged_frames ()
     {
       Lisp_Object tail, frame;
       int changed_count = 0;
-      
+
       FOR_EACH_FRAME (tail, frame)
        {
          struct frame *f = XFRAME (frame);
-         
+
          if (FRAME_VISIBLE_P (f) && FRAME_GARBAGED_P (f))
            {
              if (f->resized_p)
@@ -8923,7 +8936,7 @@ clear_garbaged_frames ()
              f->resized_p = 0;
            }
        }
-      
+
       frame_garbaged = 0;
       if (changed_count)
        ++windows_or_buffers_changed;
@@ -8953,8 +8966,6 @@ echo_area_display (update_frame_p)
   if (!FRAME_VISIBLE_P (f) || !f->glyphs_initialized_p)
     return 0;
 
-/* The terminal frame is used as the first Emacs frame on the Mac OS.  */
-#ifndef MAC_OS8
 #ifdef HAVE_WINDOW_SYSTEM
   /* When Emacs starts, selected_frame may be the initial terminal
      frame.  If we let this through, a message would be displayed on
@@ -8962,7 +8973,6 @@ echo_area_display (update_frame_p)
   if (FRAME_INITIAL_P (XFRAME (selected_frame)))
     return 0;
 #endif /* HAVE_WINDOW_SYSTEM */
-#endif
 
   /* Redraw garbaged frames.  */
   if (frame_garbaged)
@@ -9086,7 +9096,7 @@ static Lisp_Object
 format_mode_line_unwind_data (obuf, save_proptrans)
      struct buffer *obuf;
 {
-  Lisp_Object vector;
+  Lisp_Object vector, tmp;
 
   /* Reduce consing by keeping one vector in
      Vwith_echo_area_save_vector.  */
@@ -9096,17 +9106,18 @@ format_mode_line_unwind_data (obuf, save_proptrans)
   if (NILP (vector))
     vector = Fmake_vector (make_number (7), Qnil);
 
-  AREF (vector, 0) = make_number (mode_line_target);
-  AREF (vector, 1) = make_number (MODE_LINE_NOPROP_LEN (0));
-  AREF (vector, 2) = mode_line_string_list;
-  AREF (vector, 3) = (save_proptrans ? mode_line_proptrans_alist : Qt);
-  AREF (vector, 4) = mode_line_string_face;
-  AREF (vector, 5) = mode_line_string_face_prop;
+  ASET (vector, 0, make_number (mode_line_target));
+  ASET (vector, 1, make_number (MODE_LINE_NOPROP_LEN (0)));
+  ASET (vector, 2, mode_line_string_list);
+  ASET (vector, 3, save_proptrans ? mode_line_proptrans_alist : Qt);
+  ASET (vector, 4, mode_line_string_face);
+  ASET (vector, 5, mode_line_string_face_prop);
 
   if (obuf)
-    XSETBUFFER (AREF (vector, 6), obuf);
+    XSETBUFFER (tmp, obuf);
   else
-    AREF (vector, 6) = Qnil;
+    tmp = Qnil;
+  ASET (vector, 6, tmp);
 
   return vector;
 }
@@ -9126,7 +9137,7 @@ unwind_format_mode_line (vector)
   if (!NILP (AREF (vector, 6)))
     {
       set_buffer_internal_1 (XBUFFER (AREF (vector, 6)));
-      AREF (vector, 6) = Qnil;
+      ASET (vector, 6, Qnil);
     }
 
   Vmode_line_unwind_vector = vector;
@@ -10552,11 +10563,12 @@ hscroll_window_tree (window)
          /* Scroll when cursor is inside this scroll margin.  */
          h_margin = hscroll_margin * WINDOW_FRAME_COLUMN_WIDTH (w);
 
-         if ((XFASTINT (w->hscroll)
-              && w->cursor.x <= h_margin)
-             || (cursor_row->enabled_p
-                 && cursor_row->truncated_on_right_p
-                 && (w->cursor.x >= text_area_width - h_margin)))
+         if (!NILP (Fbuffer_local_value (Qauto_hscroll_mode, w->buffer))
+             && ((XFASTINT (w->hscroll)
+                  && w->cursor.x <= h_margin)
+                 || (cursor_row->enabled_p
+                     && cursor_row->truncated_on_right_p
+                     && (w->cursor.x >= text_area_width - h_margin))))
            {
              struct it it;
              int hscroll;
@@ -10646,16 +10658,9 @@ static int
 hscroll_windows (window)
      Lisp_Object window;
 {
-  int hscrolled_p;
-
-  if (automatic_hscrolling_p)
-    {
-      hscrolled_p = hscroll_window_tree (window);
-      if (hscrolled_p)
-       clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
-    }
-  else
-    hscrolled_p = 0;
+  int hscrolled_p = hscroll_window_tree (window);
+  if (hscrolled_p)
+    clear_desired_matrices (XFRAME (WINDOW_FRAME (XWINDOW (window))));
   return hscrolled_p;
 }
 
@@ -11039,27 +11044,20 @@ select_frame_for_redisplay (frame)
 
   selected_frame = frame;
 
-  for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
-    if (CONSP (XCAR (tail))
-       && (sym = XCAR (XCAR (tail)),
-           SYMBOLP (sym))
-       && (sym = indirect_variable (sym),
-           val = SYMBOL_VALUE (sym),
-           (BUFFER_LOCAL_VALUEP (val)))
-       && XBUFFER_LOCAL_VALUE (val)->check_frame)
-      /* Use find_symbol_value rather than Fsymbol_value
-        to avoid an error if it is void.  */
-      find_symbol_value (sym);
-
-  for (tail = XFRAME (old)->param_alist; CONSP (tail); tail = XCDR (tail))
-    if (CONSP (XCAR (tail))
-       && (sym = XCAR (XCAR (tail)),
-           SYMBOLP (sym))
-       && (sym = indirect_variable (sym),
-           val = SYMBOL_VALUE (sym),
-           (BUFFER_LOCAL_VALUEP (val)))
-       && XBUFFER_LOCAL_VALUE (val)->check_frame)
-      find_symbol_value (sym);
+  do
+    {
+      for (tail = XFRAME (frame)->param_alist; CONSP (tail); tail = XCDR (tail))
+       if (CONSP (XCAR (tail))
+           && (sym = XCAR (XCAR (tail)),
+               SYMBOLP (sym))
+           && (sym = indirect_variable (sym),
+               val = SYMBOL_VALUE (sym),
+               (BUFFER_LOCAL_VALUEP (val)))
+           && XBUFFER_LOCAL_VALUE (val)->check_frame)
+         /* Use find_symbol_value rather than Fsymbol_value
+            to avoid an error if it is void.  */
+         find_symbol_value (sym);
+    } while (!EQ (frame, old) && (frame = old, 1));
 }
 
 
@@ -11212,7 +11210,7 @@ redisplay_internal (preserve_echo_area)
       }
   }
 
-  
+
   /* Notice any pending interrupt request to change frame size.  */
   do_pending_window_change (1);
 
@@ -11794,13 +11792,7 @@ redisplay_internal (preserve_echo_area)
 #ifdef HAVE_WINDOW_SYSTEM
       if (clear_image_cache_count > CLEAR_IMAGE_CACHE_COUNT)
        {
-         Lisp_Object tail, frame;
-         FOR_EACH_FRAME (tail, frame)
-           {
-             struct frame *f = XFRAME (frame);
-             if (FRAME_WINDOW_P (f))
-               clear_image_cache (f, 0);
-           }
+         clear_image_caches (Qnil);
          clear_image_cache_count = 0;
        }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -13049,8 +13041,7 @@ redisplay_window (window, just_this_one_p)
   *w->desired_matrix->method = 0;
 #endif
 
-  specbind (Qinhibit_point_motion_hooks, Qt);
-
+ restart:
   reconsider_clip_changes (w, buffer);
 
   /* Has the mode line to be updated?  */
@@ -13101,10 +13092,6 @@ redisplay_window (window, just_this_one_p)
   /* Really select the buffer, for the sake of buffer-local
      variables.  */
   set_buffer_internal_1 (XBUFFER (w->buffer));
-  SET_TEXT_POS (opoint, PT, PT_BYTE);
-
-  beg_unchanged = BEG_UNCHANGED;
-  end_unchanged = END_UNCHANGED;
 
   current_matrix_up_to_date_p
     = (!NILP (w->window_end_valid)
@@ -13113,6 +13100,23 @@ redisplay_window (window, just_this_one_p)
        && XFASTINT (w->last_modified) >= MODIFF
        && XFASTINT (w->last_overlay_modified) >= OVERLAY_MODIFF);
 
+  /* Run the window-bottom-change-functions
+     if it is possible that the text on the screen has changed
+     (either due to modification of the text, or any other reason).  */
+  if (!current_matrix_up_to_date_p
+      && !NILP (Vwindow_text_change_functions))
+    {
+      safe_run_hooks (Qwindow_text_change_functions);
+      goto restart;
+    }
+
+  beg_unchanged = BEG_UNCHANGED;
+  end_unchanged = END_UNCHANGED;
+
+  SET_TEXT_POS (opoint, PT, PT_BYTE);
+
+  specbind (Qinhibit_point_motion_hooks, Qt);
+
   buffer_unchanged_p
     = (!NILP (w->window_end_valid)
        && !current_buffer->clip_changed
@@ -14417,8 +14421,7 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes)
 
   /* Display must not have been paused, otherwise the current matrix
      is not up to date.  */
-  if (NILP (w->window_end_valid))
-    abort ();
+  eassert (!NILP (w->window_end_valid));
 
   /* A value of window_end_pos >= END_UNCHANGED means that the window
      end is in the range of changed text.  If so, there is no
@@ -14469,8 +14472,7 @@ find_first_unchanged_at_end_row (w, delta, delta_bytes)
        }
     }
 
-  if (row_found && !MATRIX_ROW_DISPLAYS_TEXT_P (row_found))
-    abort ();
+  eassert (!row_found || MATRIX_ROW_DISPLAYS_TEXT_P (row_found));
 
   return row_found;
 }
@@ -16765,7 +16767,7 @@ display_menu_bar (w)
        break;
 
       /* Remember where item was displayed.  */
-      AREF (items, i + 3) = make_number (it.hpos);
+      ASET (items, i + 3, make_number (it.hpos));
 
       /* Display the item, pad with one space.  */
       if (it.current_x < it.last_visible_x)
@@ -17220,14 +17222,14 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                    int multibyte;
                    int bytepos, charpos;
                    unsigned char *spec;
+                   Lisp_Object string;
 
                    bytepos = percent_position;
                    charpos = (STRING_MULTIBYTE (elt)
                               ? string_byte_to_char (elt, bytepos)
                               : bytepos);
-
-                   spec
-                     = decode_mode_spec (it->w, c, field, prec, &multibyte);
+                   spec = decode_mode_spec (it->w, c, field, prec, &multibyte,
+                                            &string);
 
                    switch (mode_line_target)
                      {
@@ -17237,19 +17239,24 @@ display_mode_element (it, depth, field_width, precision, elt, props, risky)
                        break;
                      case MODE_LINE_STRING:
                        {
-                         int len = strlen (spec);
-                         Lisp_Object tem = make_string (spec, len);
+                         if (NILP (string))
+                           {
+                             int len = strlen (spec);
+                             string = make_string (spec, len);
+                           }
                          props = Ftext_properties_at (make_number (charpos), elt);
                          /* Should only keep face property in props */
-                         n += store_mode_line_string (NULL, tem, 0, field, prec, props);
+                         n += store_mode_line_string (NULL, string, 0, field, prec, props);
                        }
                        break;
                      case MODE_LINE_DISPLAY:
                        {
                          int nglyphs_before, nwritten;
 
+                         if (STRINGP (string))
+                           spec = NULL;
                          nglyphs_before = it->glyph_row->used[TEXT_AREA];
-                         nwritten = display_string (spec, Qnil, elt,
+                         nwritten = display_string (spec, string, elt,
                                                     charpos, 0, it,
                                                     field, prec, 0,
                                                     multibyte);
@@ -17913,18 +17920,19 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
 static char lots_of_dashes[] = "--------------------------------------------------------------------------------------------------------------------------------------------";
 
 static char *
-decode_mode_spec (w, c, field_width, precision, multibyte)
+decode_mode_spec (w, c, field_width, precision, multibyte, string)
      struct window *w;
      register int c;
      int field_width, precision;
      int *multibyte;
+     Lisp_Object *string;
 {
   Lisp_Object obj;
   struct frame *f = XFRAME (WINDOW_FRAME (w));
   char *decode_mode_spec_buf = f->decode_mode_spec_buffer;
   struct buffer *b = current_buffer;
 
-  obj = Qnil;
+  *string = obj = Qnil;
   *multibyte = 0;
 
   switch (c)
@@ -18089,8 +18097,8 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
            goto no_value;
          }
 
-       if (!NILP (w->base_line_number)
-           && !NILP (w->base_line_pos)
+       if (INTEGERP (w->base_line_number)
+           && INTEGERP (w->base_line_pos)
            && XFASTINT (w->base_line_pos) <= startpos)
          {
            line = XFASTINT (w->base_line_number);
@@ -18317,6 +18325,7 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
   if (STRINGP (obj))
     {
       *multibyte = STRING_MULTIBYTE (obj);
+      *string = obj;
       return (char *) SDATA (obj);
     }
   else
@@ -18475,8 +18484,8 @@ display_string (string, lisp_string, face_string, face_string_pos,
      unsigned char *string;
      Lisp_Object lisp_string;
      Lisp_Object face_string;
-     int face_string_pos;
-     int start;
+     EMACS_INT face_string_pos;
+     EMACS_INT start;
      struct it *it;
      int field_width, precision, max_x;
      int multibyte;
@@ -18494,7 +18503,7 @@ display_string (string, lisp_string, face_string, face_string_pos,
      from LISP_STRING, if that's given.  */
   if (STRINGP (face_string))
     {
-      int endptr;
+      EMACS_INT endptr;
       struct face *face;
 
       it->face_id
@@ -19298,16 +19307,16 @@ fill_composite_glyph_string (s, base_face, overlaps)
                s->cmp->hash_index * 2);
 
       s->face = base_face;
-      s->font_info = s->cmp->font;
+      s->font_info = base_face->font_info;
       s->font = s->font_info->font;
       for (i = 0, s->nchars = 0; i < s->cmp->glyph_len; i++, s->nchars++)
        {
          Lisp_Object g = LGSTRING_GLYPH (gstring, i);
          unsigned code;
           XChar2b * store_pos;
-         if (NILP (LGLYPH_FROM (g)))
+         if (NILP (g))
            break;
-         code = XUINT (LGLYPH_CODE (g));
+         code = LGLYPH_CODE (g);
           store_pos = s->char2b + i;
          STORE_XCHAR2B (store_pos, code >> 8, code & 0xFF);
        }
@@ -19330,7 +19339,8 @@ fill_composite_glyph_string (s, base_face, overlaps)
 
          if (c != '\t')
            {
-             int face_id = FACE_FOR_CHAR (s->f, base_face, c, -1, Qnil);
+             int face_id = FACE_FOR_CHAR (s->f, base_face->ascii_face, c,
+                                          -1, Qnil);
 
              face = get_char_face_and_encoding (s->f, c, face_id,
                                                 s->char2b + i, 1, 1);
@@ -19401,7 +19411,7 @@ fill_glyph_string (s, face_id, start, end, overlaps)
   glyph = s->row->glyphs[s->area] + start;
   last = s->row->glyphs[s->area] + end;
   voffset = glyph->voffset;
-
+  s->padding_p = glyph->padding_p;
   glyph_not_available_p = glyph->glyph_not_available_p;
 
   while (glyph < last
@@ -19420,7 +19430,8 @@ fill_glyph_string (s, face_id, start, end, overlaps)
       ++s->nchars;
       xassert (s->nchars <= end - start);
       s->width += glyph->pixel_width;
-      ++glyph;
+      if (glyph++->padding_p != s->padding_p)
+       break;
     }
 
   s->font = s->face->font;
@@ -19868,7 +19879,6 @@ compute_overhangs_and_x (s, x, backward_p)
     int n;                                                                 \
                                                                            \
     char2b = (XChar2b *) alloca ((sizeof *char2b) * cmp->glyph_len);       \
-    base_face = base_face->ascii_face;                                     \
                                                                            \
     /* Make glyph_strings for each glyph sequence that is drawable by      \
        the same face, and append them to HEAD/TAIL.  */                            \
@@ -20174,7 +20184,18 @@ append_glyph (it)
     {
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
-      glyph->pixel_width = it->pixel_width;
+      if (it->pixel_width > 0)
+       {
+         glyph->pixel_width = it->pixel_width;
+         glyph->padding_p = 0;
+       }
+      else
+       {
+         /* Assure at least 1-pixel width.  Otherwise, cursor can't
+            be displayed correctly.  */
+         glyph->pixel_width = 1;
+         glyph->padding_p = 1;
+       }
       glyph->ascent = it->ascent;
       glyph->descent = it->descent;
       glyph->voffset = it->voffset;
@@ -20184,7 +20205,6 @@ append_glyph (it)
       glyph->right_box_line_p = it->end_of_box_run_p;
       glyph->overlaps_vertically_p = (it->phys_ascent > it->ascent
                                      || it->phys_descent > it->descent);
-      glyph->padding_p = 0;
       glyph->glyph_not_available_p = it->glyph_not_available_p;
       glyph->face_id = it->face_id;
       glyph->u.ch = it->char_to_display;
@@ -20907,6 +20927,10 @@ x_produce_glyphs (it)
              if (pcm && (pcm->lbearing < 0 || pcm->rbearing > pcm->width))
                it->glyph_row->contains_overlapping_glyphs_p = 1;
            }
+         if (! stretched_p && it->pixel_width == 0)
+           /* We assure that all visible glyphs have at least 1-pixel
+              width.  */
+           it->pixel_width = 1;
        }
       else if (it->char_to_display == '\n')
        {
@@ -21084,8 +21108,17 @@ x_produce_glyphs (it)
 
          take_vertical_position_into_account (it);
 
+         if (it->ascent < 0)
+           it->ascent = 0;
+         if (it->descent < 0)
+           it->descent = 0;
+
          if (it->glyph_row)
            append_glyph (it);
+         if (it->pixel_width == 0)
+           /* We assure that all visible glyphs have at least 1-pixel
+              width.  */
+           it->pixel_width = 1;
        }
       it->multibyte_p = saved_multibyte_p;
     }
@@ -21108,8 +21141,8 @@ x_produce_glyphs (it)
 #ifdef USE_FONT_BACKEND
       if (cmp->method == COMPOSITION_WITH_GLYPH_STRING)
        {
-         if (! cmp->font || cmp->font != font)
-           font_prepare_composition (cmp);
+         PREPARE_FACE_FOR_DISPLAY (it->f, face);
+         font_prepare_composition (cmp, it->f);
        }
       else
 #endif /* USE_FONT_BACKEND */
@@ -21310,7 +21343,7 @@ x_produce_glyphs (it)
                              + grefx * (rightmost - leftmost) / 2
                              - nrefx * width / 2
                              + xoff);
-                 
+
                      btm = ((grefy == 0 ? highest
                              : grefy == 1 ? 0
                              : grefy == 2 ? lowest
@@ -21389,7 +21422,6 @@ x_produce_glyphs (it)
       it->pixel_width = cmp->pixel_width;
       it->ascent = it->phys_ascent = cmp->ascent;
       it->descent = it->phys_descent = cmp->descent;
-
       if (face->box != FACE_NO_BOX)
        {
          int thick = face->box_line_width;
@@ -21414,6 +21446,10 @@ x_produce_glyphs (it)
        it->ascent += overline_margin;
 
       take_vertical_position_into_account (it);
+      if (it->ascent < 0)
+       it->ascent = 0;
+      if (it->descent < 0)
+       it->descent = 0;
 
       if (it->glyph_row)
        append_composite_glyph (it);
@@ -23044,7 +23080,7 @@ note_mode_line_or_margin_highlight (window, x, y, area)
          int gpos;
          int gseq_length;
          int total_pixel_width;
-         int ignore;
+         EMACS_INT ignore;
 
          int vpos, hpos;
 
@@ -23396,7 +23432,7 @@ note_mouse_highlight (f, x, y)
              /* Find the range of text around this char that
                 should be active.  */
              Lisp_Object before, after;
-             int ignore;
+             EMACS_INT ignore;
 
              before = Foverlay_start (overlay);
              after = Foverlay_end (overlay);
@@ -23430,7 +23466,7 @@ note_mouse_highlight (f, x, y)
              /* Find the range of text around this char that
                 should be active.  */
              Lisp_Object before, after, beginning, end;
-             int ignore;
+             EMACS_INT ignore;
 
              beginning = Fmarker_position (w->start);
              end = make_number (BUF_Z (XBUFFER (object))
@@ -23470,7 +23506,7 @@ note_mouse_highlight (f, x, y)
          else if (!NILP (mouse_face) && STRINGP (object))
            {
              Lisp_Object b, e;
-             int ignore;
+             EMACS_INT ignore;
 
              b = Fprevious_single_property_change (make_number (pos + 1),
                                                    Qmouse_face,
@@ -23517,7 +23553,7 @@ note_mouse_highlight (f, x, y)
                {
                  Lisp_Object before = Foverlay_start (overlay);
                  Lisp_Object after = Foverlay_end (overlay);
-                 int ignore;
+                 EMACS_INT ignore;
 
                  /* Note that we might not be able to find position
                     BEFORE in the glyph matrix if the overlay is
@@ -23854,6 +23890,24 @@ phys_cursor_in_rect_p (w, r)
 {
   XRectangle cr, result;
   struct glyph *cursor_glyph;
+  struct glyph_row *row;
+
+  if (w->phys_cursor.vpos >= 0
+      && w->phys_cursor.vpos < w->current_matrix->nrows
+      && (row = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos),
+         row->enabled_p)
+      && row->cursor_in_fringe_p)
+    {
+      /* Cursor is in the fringe.  */
+      cr.x = window_box_right_offset (w,
+                                     (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
+                                      ? RIGHT_MARGIN_AREA
+                                      : TEXT_AREA));
+      cr.y = row->y;
+      cr.width = WINDOW_RIGHT_FRINGE_WIDTH (w);
+      cr.height = row->height;
+      return x_intersect_rectangles (&cr, r, &result);
+    }
 
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph)
@@ -23882,7 +23936,7 @@ x_draw_vertical_border (w)
      struct window *w;
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
-  
+
   /* We could do better, if we knew what type of scroll-bar the adjacent
      windows (on either side) have...  But we don't :-(
      However, I think this works ok.  ++KFS 2003-04-25 */
@@ -24287,6 +24341,9 @@ syms_of_xdisp ()
   staticpro (&Qwindow_scroll_functions);
   Qwindow_scroll_functions = intern ("window-scroll-functions");
 
+  staticpro (&Qwindow_text_change_functions);
+  Qwindow_text_change_functions = intern ("window-text-change-functions");
+
   staticpro (&Qredisplay_end_trigger_functions);
   Qredisplay_end_trigger_functions = intern ("redisplay-end-trigger-functions");
 
@@ -24495,8 +24552,12 @@ If you want scrolling to always be a line at a time, you should set
 
   DEFVAR_INT ("scroll-conservatively", &scroll_conservatively,
     doc: /* *Scroll up to this many lines, to bring point back on screen.
-A value of zero means to scroll the text to center point vertically
-in the window.  */);
+If point moves off-screen, redisplay will scroll by up to
+`scroll-conservatively' lines in order to bring point just barely
+onto the screen again.   If that cannot be done, then redisplay
+recenters point as usual.
+
+A value of zero means always recenter point if it moves off screen.  */);
   scroll_conservatively = 0;
 
   DEFVAR_INT ("scroll-margin", &scroll_margin,
@@ -24594,6 +24655,11 @@ and its new display-start position.  Note that the value of `window-end'
 is not valid when these functions are called.  */);
   Vwindow_scroll_functions = Qnil;
 
+  DEFVAR_LISP ("window-text-change-functions",
+              &Vwindow_text_change_functions,
+    doc: /* Functions to call in redisplay when text in the window might change.  */);
+  Vwindow_text_change_functions = Qnil;
+
   DEFVAR_LISP ("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions,
     doc: /* Functions called when redisplay of a window reaches the end trigger.
 Each function is called with two arguments, the window and the end trigger value.
@@ -24703,6 +24769,8 @@ the frame's other specifications determine how to blink the cursor off.  */);
   DEFVAR_BOOL ("auto-hscroll-mode", &automatic_hscrolling_p,
     doc: /* *Non-nil means scroll the display automatically to make point visible.  */);
   automatic_hscrolling_p = 1;
+  Qauto_hscroll_mode = intern ("auto-hscroll-mode");
+  staticpro (&Qauto_hscroll_mode);
 
   DEFVAR_INT ("hscroll-margin", &hscroll_margin,
     doc: /* *How many columns away from the window edge point is allowed to get