Ignore a static composition that starts before the current checking position in redis...
[bpt/emacs.git] / src / xdisp.c
index a416c8f..b8a8ea7 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, 2008, 2009, 2010
+                 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -229,7 +229,7 @@ extern Lisp_Object do_mouse_tracking;
 extern int minibuffer_auto_raise;
 extern Lisp_Object Vminibuffer_list;
 
-extern Lisp_Object Qface;
+extern Lisp_Object Qface, Qdefault;
 extern Lisp_Object Qmode_line, Qmode_line_inactive, Qheader_line;
 
 extern Lisp_Object Voverriding_local_map;
@@ -1454,11 +1454,10 @@ pos_visible_p (w, charpos, x, y, rtop, rbot, rowh, vpos)
 }
 
 
-/* Return the next character from STR which is MAXLEN bytes long.
-   Return in *LEN the length of the character.  This is like
-   STRING_CHAR_AND_LENGTH but never returns an invalid character.  If
-   we find one, we return a `?', but with the length of the invalid
-   character.  */
+/* Return the next character from STR.  Return in *LEN the length of
+   the character.  This is like STRING_CHAR_AND_LENGTH but never
+   returns an invalid character.  If we find one, we return a `?', but
+   with the length of the invalid character.  */
 
 static INLINE int
 string_char_and_length (str, len)
@@ -1492,15 +1491,13 @@ string_pos_nchars_ahead (pos, string, nchars)
 
   if (STRING_MULTIBYTE (string))
     {
-      int rest = SBYTES (string) - BYTEPOS (pos);
       const unsigned char *p = SDATA (string) + BYTEPOS (pos);
       int len;
 
       while (nchars--)
        {
          string_char_and_length (p, &len);
-         p += len, rest -= len;
-         xassert (rest >= 0);
+         p += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
        }
@@ -1545,14 +1542,13 @@ c_string_pos (charpos, s, multibyte_p)
 
   if (multibyte_p)
     {
-      int rest = strlen (s), len;
+      int len;
 
       SET_TEXT_POS (pos, 0, 0);
       while (charpos--)
        {
          string_char_and_length (s, &len);
-         s += len, rest -= len;
-         xassert (rest >= 0);
+         s += len;
          CHARPOS (pos) += 1;
          BYTEPOS (pos) += len;
        }
@@ -3341,6 +3337,8 @@ handle_fontified_prop (it)
       val = Vfontification_functions;
       specbind (Qfontification_functions, Qnil);
 
+      xassert (it->end_charpos == ZV);
+      
       if (!CONSP (val) || EQ (XCAR (val), Qlambda))
        safe_call1 (val, pos);
       else
@@ -3380,6 +3378,13 @@ handle_fontified_prop (it)
 
       unbind_to (count, Qnil);
 
+      /* The fontification code may have added/removed text.
+        It could do even a lot worse, but let's at least protect against
+        the most obvious case where only the text past `pos' gets changed',
+        as is/was done in grep.el where some escapes sequences are turned
+        into face properties (bug#7876).  */
+      it->end_charpos = ZV;
+      
       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
         something.  This avoids an endless loop if they failed to
         fontify the text for which reason ever.  */
@@ -3614,7 +3619,6 @@ face_before_or_after_it_pos (it, before_p)
       if (STRING_MULTIBYTE (it->string))
        {
          const unsigned char *p = SDATA (it->string) + BYTEPOS (pos);
-         int rest = SBYTES (it->string) - BYTEPOS (pos);
          int c, len;
          struct face *face = FACE_FROM_ID (it->f, face_id);
 
@@ -3861,7 +3865,7 @@ setup_for_ellipsis (it, len)
     {
       struct Lisp_Vector *v = XVECTOR (DISP_INVIS_VECTOR (it->dp));
       it->dpvec = v->contents;
-      it->dpend = v->contents + v->size;
+      it->dpend = v->contents + v->header.size;
     }
   else
     {
@@ -4637,6 +4641,11 @@ handle_composition_prop (it)
       && COMPOSITION_VALID_P (start, end, prop)
       && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
+      if (start < pos)
+       /* As we can't handle this situation (perhaps, font-lock added
+          a new composition), we just return here hoping that next
+          redisplay will detect this composition much earlier.  */
+       return HANDLED_NORMALLY;
       if (start != pos)
        {
          if (STRINGP (it->string))
@@ -4717,6 +4726,7 @@ next_overlay_string (it)
                   && it->stop_charpos <= it->end_charpos));
       it->current.overlay_string_index = -1;
       it->n_overlay_strings = 0;
+      it->overlay_strings_charpos = -1;
 
       /* If we're at the end of the buffer, record that we have
         processed the overlay strings there already, so that
@@ -4729,11 +4739,13 @@ next_overlay_string (it)
       /* There are more overlay strings to process.  If
         IT->current.overlay_string_index has advanced to a position
         where we must load IT->overlay_strings with more strings, do
-        it.  */
+        it.  We must load at the IT->overlay_strings_charpos where
+        IT->n_overlay_strings was originally computed; when invisible
+        text is present, this might not be IT_CHARPOS (Bug#7016).  */
       int i = it->current.overlay_string_index % OVERLAY_STRING_CHUNK_SIZE;
 
       if (it->current.overlay_string_index && i == 0)
-       load_overlay_strings (it, 0);
+       load_overlay_strings (it, it->overlay_strings_charpos);
 
       /* Initialize IT to deliver display elements from the overlay
          string.  */
@@ -4949,8 +4961,9 @@ load_overlay_strings (it, charpos)
   if (n > 1)
     qsort (entries, n, sizeof *entries, compare_overlay_entries);
 
-  /* Record the total number of strings to process.  */
+  /* Record number of overlay strings, and where we computed it.  */
   it->n_overlay_strings = n;
+  it->overlay_strings_charpos = charpos;
 
   /* IT->current.overlay_string_index is the number of overlay strings
      that have already been consumed by IT.  Copy some of the
@@ -5689,11 +5702,11 @@ get_next_display_element (it)
              /* Return the first character from the display table
                 entry, if not empty.  If empty, don't display the
                 current character.  */
-             if (v->size)
+             if (v->header.size)
                {
                  it->dpvec_char_len = it->len;
                  it->dpvec = v->contents;
-                 it->dpend = v->contents + v->size;
+                 it->dpend = v->contents + v->header.size;
                  it->current.dpvec_index = 0;
                  it->dpvec_face_id = -1;
                  it->saved_face_id = it->face_id;
@@ -5914,9 +5927,21 @@ get_next_display_element (it)
          int pos = (it->s ? -1
                     : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
                     : IT_CHARPOS (*it));
+         int c;
+
+         if (it->what == IT_CHARACTER)
+           c = it->char_to_display;
+         else
+           {
+             struct composition *cmp = composition_table[it->cmp_it.id];
+             int i;
 
-         it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display, pos,
-                                      it->string);
+             c = ' ';
+             for (i = 0; i < cmp->glyph_len; i++)
+               if ((c = COMPOSITION_GLYPH (cmp, i)) != '\t')
+                 break;
+           }
+         it->face_id = FACE_FOR_CHAR (it->f, face, c, pos, it->string);
        }
     }
 #endif
@@ -6260,7 +6285,6 @@ next_element_from_string (it)
        }
       else if (STRING_MULTIBYTE (it->string))
        {
-         int remaining = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
          it->c = string_char_and_length (s, &it->len);
@@ -6296,7 +6320,6 @@ next_element_from_string (it)
        }
       else if (STRING_MULTIBYTE (it->string))
        {
-         int maxlen = SBYTES (it->string) - IT_STRING_BYTEPOS (*it);
          const unsigned char *s = (SDATA (it->string)
                                    + IT_STRING_BYTEPOS (*it));
          it->c = string_char_and_length (s, &it->len);
@@ -6350,13 +6373,7 @@ next_element_from_c_string (it)
       BYTEPOS (it->position) = CHARPOS (it->position) = -1;
     }
   else if (it->multibyte_p)
-    {
-      /* Implementation note: The calls to strlen apparently aren't a
-        performance problem because there is no noticeable performance
-        difference between Emacs running in unibyte or multibyte mode.  */
-      int maxlen = strlen (it->s) - IT_BYTEPOS (*it);
-      it->c = string_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
-    }
+    it->c = string_char_and_length (it->s + IT_BYTEPOS (*it), &it->len);
   else
     it->c = it->s[IT_BYTEPOS (*it)], it->len = 1;
 
@@ -10760,7 +10777,7 @@ hscroll_window_tree (window)
              current_buffer = XBUFFER (w->buffer);
 
              if (w == XWINDOW (selected_window))
-               pt = BUF_PT (current_buffer);
+               pt = PT;
              else
                {
                  pt = marker_position (w->pointm);
@@ -11194,7 +11211,7 @@ reconsider_clip_changes (w, b)
       int pt;
 
       if (w == XWINDOW (selected_window))
-       pt = BUF_PT (current_buffer);
+       pt = PT;
       else
        pt = marker_position (w->pointm);
 
@@ -11261,6 +11278,7 @@ redisplay_internal (preserve_echo_area)
      int preserve_echo_area;
 {
   struct window *w = XWINDOW (selected_window);
+  struct window *sw;
   struct frame *f;
   int pause;
   int must_finish = 0;
@@ -11331,6 +11349,9 @@ redisplay_internal (preserve_echo_area)
   }
 
  retry:
+  /* Remember the currently selected window.  */
+  sw = w;
+
   if (!EQ (old_frame, selected_frame)
       && FRAME_LIVE_P (XFRAME (old_frame)))
     /* When running redisplay, we play a bit fast-and-loose and allow e.g.
@@ -11396,6 +11417,14 @@ redisplay_internal (preserve_echo_area)
   /* Notice any pending interrupt request to change frame size.  */
   do_pending_window_change (1);
 
+  /* do_pending_window_change could change the selected_window due to
+     frame resizing which makes the selected window too small.  */
+  if (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw)
+    {
+      sw = w;
+      reconsider_clip_changes (w, current_buffer);
+    }
+
   /* Clear frames marked as garbaged.  */
   if (frame_garbaged)
     clear_garbaged_frames ();
@@ -11665,6 +11694,10 @@ redisplay_internal (preserve_echo_area)
          if (!must_finish)
            {
              do_pending_window_change (1);
+             /* If selected_window changed, redisplay again.  */
+             if (WINDOWP (selected_window)
+                 && (w = XWINDOW (selected_window)) != sw)
+               goto retry;
 
              /* We used to always goto end_of_redisplay here, but this
                 isn't enough if we have a blinking cursor.  */
@@ -11959,8 +11992,9 @@ redisplay_internal (preserve_echo_area)
   do_pending_window_change (1);
 
   /* If we just did a pending size change, or have additional
-     visible frames, redisplay again.  */
-  if (windows_or_buffers_changed && !pause)
+     visible frames, or selected_window changed, redisplay again.  */
+  if ((windows_or_buffers_changed && !pause)
+      || (WINDOWP (selected_window) && (w = XWINDOW (selected_window)) != sw))
     goto retry;
 
   /* Clear the face cache eventually.  */
@@ -12759,7 +12793,11 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
 
       /* If cursor ends up on a partially visible line,
         treat that as being off the bottom of the screen.  */
-      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0))
+      if (! cursor_row_fully_visible_p (w, extra_scroll_margin_lines <= 1, 0)
+         /* It's possible that the cursor is on the first line of the
+            buffer, which is partially obscured due to a vscroll
+            (Bug#7537).  In that case, avoid looping forever . */
+         && extra_scroll_margin_lines < w->desired_matrix->nrows - 1)
        {
          clear_glyph_matrix (w->desired_matrix);
          ++extra_scroll_margin_lines;
@@ -14222,7 +14260,8 @@ try_window_reusing_current_matrix (w)
                row->visible_height -= min_y - row->y;
              if (row->y + row->height > max_y)
                row->visible_height -= row->y + row->height - max_y;
-             row->redraw_fringe_bitmaps_p = 1;
+             if (row->fringe_bitmap_periodic_p)
+               row->redraw_fringe_bitmaps_p = 1;
 
              it.current_y += row->height;
 
@@ -14384,7 +14423,8 @@ try_window_reusing_current_matrix (w)
            row->visible_height -= min_y - row->y;
          if (row->y + row->height > max_y)
            row->visible_height -= row->y + row->height - max_y;
-         row->redraw_fringe_bitmaps_p = 1;
+         if (row->fringe_bitmap_periodic_p)
+           row->redraw_fringe_bitmaps_p = 1;
        }
 
       /* Scroll the current matrix.  */
@@ -17066,7 +17106,7 @@ display_menu_bar (w)
 
   /* Display all items of the menu bar.  */
   items = FRAME_MENU_BAR_ITEMS (it.f);
-  for (i = 0; i < XVECTOR (items)->size; i += 4)
+  for (i = 0; i < XVECTOR_SIZE (items); i += 4)
     {
       Lisp_Object string;
 
@@ -17888,16 +17928,19 @@ DEFUN ("format-mode-line", Fformat_mode_line, Sformat_mode_line,
 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.
-The value t means whatever face the window's mode line currently uses
-\(either `mode-line' or `mode-line-inactive', depending).
-A value of nil means the default is no face property.
-If FACE is an integer, the value string has no text properties.
+By default, the format is evaluated for the currently selected window.
+
+Optional second arg FACE specifies the face property to put on all
+characters for which no face is specified.  The value nil means the
+default face.  The value t means whatever face the window's mode line
+currently uses (either `mode-line' or `mode-line-inactive',
+depending on whether the window is the selected window or not).
+An integer value means 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).  */)
+are the selected window and the WINDOW's buffer).  */)
      (format, face, window, buffer)
      Lisp_Object format, face, window, buffer;
 {
@@ -17905,7 +17948,7 @@ are the selected window and the window's buffer).  */)
   int len;
   struct window *w;
   struct buffer *old_buffer = NULL;
-  int face_id = -1;
+  int face_id;
   int no_props = INTEGERP (face);
   int count = SPECPDL_INDEX ();
   Lisp_Object str;
@@ -17928,15 +17971,14 @@ are the selected window and the window's buffer).  */)
   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);
-    }
-
-  if (face_id < 0)
-    face_id = DEFAULT_FACE_ID;
+  face_id = (NILP (face) || EQ (face, Qdefault)) ? DEFAULT_FACE_ID
+    : EQ (face, Qt) ? (EQ (window, selected_window)
+                      ? MODE_LINE_FACE_ID : MODE_LINE_INACTIVE_FACE_ID)
+    : EQ (face, Qmode_line) ? MODE_LINE_FACE_ID
+    : EQ (face, Qmode_line_inactive) ? MODE_LINE_INACTIVE_FACE_ID
+    : EQ (face, Qheader_line) ? HEADER_LINE_FACE_ID
+    : EQ (face, Qtool_bar) ? TOOL_BAR_FACE_ID
+    : DEFAULT_FACE_ID;
 
   if (XBUFFER (buffer) != current_buffer)
     old_buffer = current_buffer;
@@ -20909,11 +20951,7 @@ produce_stretch_glyph (it)
 
       it2 = *it;
       if (it->multibyte_p)
-       {
-         int maxlen = ((IT_BYTEPOS (*it) >= GPT ? ZV : GPT)
-                       - IT_BYTEPOS (*it));
-         it2.c = it2.char_to_display = STRING_CHAR_AND_LENGTH (p, it2.len);
-       }
+       it2.c = it2.char_to_display = STRING_CHAR_AND_LENGTH (p, it2.len);
       else
        {
          it2.c = it2.char_to_display = *p, it2.len = 1;
@@ -23067,7 +23105,7 @@ on_hot_spot_p (hot_spot, x, y)
        {
          struct Lisp_Vector *v = XVECTOR (XCDR (hot_spot));
          Lisp_Object *poly = v->contents;
-         int n = v->size;
+         int n = v->header.size;
          int i;
          int inside = 0;
          Lisp_Object lx, ly;
@@ -25120,6 +25158,7 @@ init_xdisp ()
 
   mini_w = XWINDOW (minibuf_window);
   root_window = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (mini_w)));
+  echo_area_window = minibuf_window;
 
   if (!noninteractive)
     {