Add 2008 to copyright years.
[bpt/emacs.git] / src / xdisp.c
index 90977aa..fa53a98 100644 (file)
@@ -7,7 +7,7 @@ This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -967,8 +967,8 @@ static void compute_string_pos P_ ((struct text_pos *, struct text_pos,
 static int face_before_or_after_it_pos P_ ((struct it *, int));
 static int next_overlay_change P_ ((int));
 static int handle_single_display_spec P_ ((struct it *, Lisp_Object,
-                                          Lisp_Object, struct text_pos *,
-                                          int));
+                                          Lisp_Object, Lisp_Object,
+                                          struct text_pos *, int));
 static int underlying_face_id P_ ((struct it *));
 static int in_ellipses_for_invisible_text_p P_ ((struct display_pos *,
                                                 struct window *));
@@ -3073,16 +3073,18 @@ handle_stop (it)
          if (it->method == GET_FROM_DISPLAY_VECTOR)
            handle_overlay_change_p = 0;
 
-         /* Handle overlay changes.  */
+         /* Handle overlay changes.
+            This sets HANDLED to HANDLED_RECOMPUTE_PROPS
+            if it finds overlays.  */
          if (handle_overlay_change_p)
            handled = handle_overlay_change (it);
-
-         /* Determine where to stop next.  */
-         if (handled == HANDLED_NORMALLY)
-           compute_stop_pos (it);
        }
     }
   while (handled == HANDLED_RECOMPUTE_PROPS);
+
+  /* Determine where to stop next.  */
+  if (handled == HANDLED_NORMALLY)
+    compute_stop_pos (it);
 }
 
 
@@ -3363,18 +3365,58 @@ handle_face_prop (it)
   else
     {
       int base_face_id, bufpos;
+      int i;
+      Lisp_Object from_overlay
+       = (it->current.overlay_string_index >= 0
+          ? it->string_overlays[it->current.overlay_string_index]
+          : Qnil);
+
+      /* See if we got to this string directly or indirectly from
+        an overlay property.  That includes the before-string or
+        after-string of an overlay, strings in display properties
+        provided by an overlay, their text properties, etc.
+
+        FROM_OVERLAY is the overlay that brought us here, or nil if none.  */
+      if (! NILP (from_overlay))
+       for (i = it->sp - 1; i >= 0; i--)
+         {
+           if (it->stack[i].current.overlay_string_index >= 0)
+             from_overlay
+               = it->string_overlays[it->stack[i].current.overlay_string_index];
+           else if (! NILP (it->stack[i].from_overlay))
+             from_overlay = it->stack[i].from_overlay;
 
-      if (it->current.overlay_string_index >= 0)
-       bufpos = IT_CHARPOS (*it);
+           if (!NILP (from_overlay))
+             break;
+         }
+
+      if (! NILP (from_overlay))
+       {
+         bufpos = IT_CHARPOS (*it);
+         /* For a string from an overlay, the base face depends
+            only on text properties and ignores overlays.  */
+         base_face_id
+           = face_for_overlay_string (it->w,
+                                      IT_CHARPOS (*it),
+                                      it->region_beg_charpos,
+                                      it->region_end_charpos,
+                                      &next_stop,
+                                      (IT_CHARPOS (*it)
+                                       + TEXT_PROP_DISTANCE_LIMIT),
+                                      0,
+                                      from_overlay);
+       }
       else
-       bufpos = 0;
+       {
+         bufpos = 0;
 
-      /* For strings from a buffer, i.e. overlay strings or strings
-        from a `display' property, use the face at IT's current
-        buffer position as the base face to merge with, so that
-        overlay strings appear in the same face as surrounding
-        text, unless they specify their own faces.  */
-      base_face_id = underlying_face_id (it);
+         /* For strings from a `display' property, use the face at
+            IT's current buffer position as the base face to merge
+            with, so that overlay strings appear in the same face as
+            surrounding text, unless they specify their own
+            faces.  */
+         base_face_id = underlying_face_id (it);
+       }
 
       new_face_id = face_at_string_position (it->w,
                                             it->string,
@@ -3719,6 +3761,10 @@ handle_invisible_prop (it)
                  it->position.bytepos = CHAR_TO_BYTE (it->position.charpos);
                }
               setup_for_ellipsis (it, 0);
+             /* Let the ellipsis display before
+                considering any properties of the following char.
+                Fixes jasonr@gnu.org 01 Oct 07 bug.  */
+             handled = HANDLED_RETURN;
             }
        }
     }
@@ -3780,7 +3826,7 @@ static enum prop_handled
 handle_display_prop (it)
      struct it *it;
 {
-  Lisp_Object prop, object;
+  Lisp_Object prop, object, overlay;
   struct text_pos *position;
   /* Nonzero if some property replaces the display of the text itself.  */
   int display_replaced_p = 0;
@@ -3808,10 +3854,12 @@ handle_display_prop (it)
   if (!it->string_from_display_prop_p)
     it->area = TEXT_AREA;
 
-  prop = Fget_char_property (make_number (position->charpos),
-                            Qdisplay, object);
+  prop = get_char_property_and_overlay (make_number (position->charpos),
+                                       Qdisplay, object, &overlay);
   if (NILP (prop))
     return HANDLED_NORMALLY;
+  /* Now OVERLAY is the overlay that gave us this property, or nil
+     if it was a text property.  */
 
   if (!STRINGP (it->string))
     object = it->w->buffer;
@@ -3833,22 +3881,35 @@ handle_display_prop (it)
     {
       for (; CONSP (prop); prop = XCDR (prop))
        {
-         if (handle_single_display_spec (it, XCAR (prop), object,
+         if (handle_single_display_spec (it, XCAR (prop), object, overlay,
                                          position, display_replaced_p))
-           display_replaced_p = 1;
+           {
+             display_replaced_p = 1;
+             /* If some text in a string is replaced, `position' no
+                longer points to the position of `object'.  */
+             if (STRINGP (object))
+               break;
+           }
        }
     }
   else if (VECTORP (prop))
     {
       int i;
       for (i = 0; i < ASIZE (prop); ++i)
-       if (handle_single_display_spec (it, AREF (prop, i), object,
+       if (handle_single_display_spec (it, AREF (prop, i), object, overlay,
                                        position, display_replaced_p))
-         display_replaced_p = 1;
+         {
+           display_replaced_p = 1;
+           /* If some text in a string is replaced, `position' no
+              longer points to the position of `object'.  */
+           if (STRINGP (object))
+             break;
+         }
     }
   else
     {
-      int ret = handle_single_display_spec (it, prop, object, position, 0);
+      int ret = handle_single_display_spec (it, prop, object, overlay,
+                                           position, 0);
       if (ret < 0)  /* Replaced by "", i.e. nothing. */
        return HANDLED_RECOMPUTE_PROPS;
       if (ret)
@@ -3890,6 +3951,9 @@ display_prop_end (it, object, start_pos)
    replaced text display with something else, for example an image;
    we ignore such properties after the first one has been processed.
 
+   OVERLAY is the overlay this `display' property came from,
+   or nil if it was a text property.
+
    If PROP is a `space' or `image' specification, and in some other
    cases too, set *POSITION to the position where the `display'
    property ends.
@@ -3899,11 +3963,12 @@ display_prop_end (it, object, start_pos)
    "something" is "nothing". */
 
 static int
-handle_single_display_spec (it, spec, object, position,
+handle_single_display_spec (it, spec, object, overlay, position,
                            display_replaced_before_p)
      struct it *it;
      Lisp_Object spec;
      Lisp_Object object;
+     Lisp_Object overlay;
      struct text_pos *position;
      int display_replaced_before_p;
 {
@@ -4013,7 +4078,7 @@ handle_single_display_spec (it, spec, object, position,
       return 0;
     }
 
-  /* Handle `(space_width WIDTH)'.  */
+  /* Handle `(space-width WIDTH)'.  */
   if (CONSP (spec)
       && EQ (XCAR (spec), Qspace_width)
       && CONSP (XCDR (spec)))
@@ -4137,6 +4202,7 @@ handle_single_display_spec (it, spec, object, position,
       it->position = start_pos;
       it->object = NILP (object) ? it->w->buffer : object;
       it->method = GET_FROM_IMAGE;
+      it->from_overlay = Qnil;
       it->face_id = face_id;
 
       /* Say that we haven't consumed the characters with
@@ -4207,6 +4273,7 @@ handle_single_display_spec (it, spec, object, position,
       it->position = *position;
       push_it (it);
       it->position = save_pos;
+      it->from_overlay = overlay;
 
       if (NILP (location))
        it->area = TEXT_AREA;
@@ -4233,13 +4300,16 @@ handle_single_display_spec (it, spec, object, position,
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
             set_iterator_to_next will clean this up.  */
-         *position = start_pos;
+         if (BUFFERP (object))
+           it->current.pos = start_pos;
        }
       else if (CONSP (value) && EQ (XCAR (value), Qspace))
        {
          it->method = GET_FROM_STRETCH;
          it->object = value;
-         *position = it->position = start_pos;
+         it->position = start_pos;
+         if (BUFFERP (object))
+           it->current.pos = start_pos;
        }
 #ifdef HAVE_WINDOW_SYSTEM
       else
@@ -4253,7 +4323,8 @@ handle_single_display_spec (it, spec, object, position,
          /* Say that we haven't consumed the characters with
             `display' property yet.  The call to pop_it in
             set_iterator_to_next will clean this up.  */
-         *position = start_pos;
+         if (BUFFERP (object))
+           it->current.pos = start_pos;
        }
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -4846,7 +4917,10 @@ load_overlay_strings (it, charpos)
   i = 0;
   j = it->current.overlay_string_index;
   while (i < OVERLAY_STRING_CHUNK_SIZE && j < n)
-    it->overlay_strings[i++] = entries[j++].string;
+    {
+      it->overlay_strings[i] = entries[j].string;
+      it->string_overlays[i++] = entries[j++].overlay;
+    }
 
   CHECK_IT (it);
 }
@@ -4892,6 +4966,7 @@ get_overlay_strings_1 (it, charpos, compute_stop_p)
         string.  */
       IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = 0;
       it->string = it->overlay_strings[0];
+      it->from_overlay = Qnil;
       it->stop_charpos = 0;
       xassert (STRINGP (it->string));
       it->end_charpos = SCHARS (it->string);
@@ -4945,6 +5020,7 @@ push_it (it)
   p->face_id = it->face_id;
   p->string = it->string;
   p->method = it->method;
+  p->from_overlay = it->from_overlay;
   switch (p->method)
     {
     case GET_FROM_IMAGE:
@@ -4998,6 +5074,7 @@ pop_it (it)
   it->current = p->current;
   it->position = p->position;
   it->string = p->string;
+  it->from_overlay = p->from_overlay;
   if (NILP (it->string))
     SET_TEXT_POS (it->current.string_pos, -1, -1);
   it->method = p->method;
@@ -6269,7 +6346,7 @@ next_element_from_buffer (it)
        it->c = *p, it->len = 1;
 
       /* Record what we have and where it came from.  */
-      it->what = IT_CHARACTER;;
+      it->what = IT_CHARACTER;
       it->object = it->w->buffer;
       it->position = it->current.pos;
 
@@ -7087,18 +7164,22 @@ move_it_by_lines (it, dvpos, need_y_p)
 {
   struct position pos;
 
-  if (!FRAME_WINDOW_P (it->f))
+  /* The commented-out optimization uses vmotion on terminals.  This
+     gives bad results, because elements like it->what, on which
+     callers such as pos_visible_p rely, aren't updated. */
+  /*  if (!FRAME_WINDOW_P (it->f))
     {
       struct text_pos textpos;
 
-      /* We can use vmotion on frames without proportional fonts.  */
       pos = *vmotion (IT_CHARPOS (*it), dvpos, it->w);
       SET_TEXT_POS (textpos, pos.bufpos, pos.bytepos);
       reseat (it, textpos, 1);
       it->vpos += pos.vpos;
       it->current_y += pos.vpos;
     }
-  else if (dvpos == 0)
+    else */
+
+  if (dvpos == 0)
     {
       /* DVPOS == 0 means move to the start of the screen line.  */
       move_it_vertically_backward (it, 0);
@@ -10836,7 +10917,7 @@ redisplay_internal (preserve_echo_area)
   int must_finish = 0;
   struct text_pos tlbufpos, tlendpos;
   int number_of_visible_frames;
-  int count;
+  int count, count1;
   struct frame *sf;
   int polling_stopped_here = 0;
 
@@ -10974,6 +11055,10 @@ redisplay_internal (preserve_echo_area)
        update_mode_lines++;
     }
 
+  /* Avoid invocation of point motion hooks by `current_column' below.  */
+  count1 = SPECPDL_INDEX ();
+  specbind (Qinhibit_point_motion_hooks, Qt);
+
   /* If %c is in the mode line, update it if needed.  */
   if (!NILP (w->column_number_displayed)
       /* This alternative quickly identifies a common case
@@ -10985,6 +11070,8 @@ redisplay_internal (preserve_echo_area)
           != (int) current_column ()))  /* iftc */
     w->update_mode_line = Qt;
 
+  unbind_to (count1, Qnil);
+
   FRAME_SCROLL_BOTTOM_VPOS (XFRAME (w->frame)) = -1;
 
   /* The variable buffer_shared is set in redisplay_window and
@@ -12777,6 +12864,7 @@ redisplay_window (window, just_this_one_p)
   int rc;
   int centering_position = -1;
   int last_line_misfit = 0;
+  int save_beg_unchanged, save_end_unchanged;
 
   SET_TEXT_POS (lpoint, PT, PT_BYTE);
   opoint = lpoint;
@@ -12841,6 +12929,9 @@ redisplay_window (window, just_this_one_p)
   set_buffer_internal_1 (XBUFFER (w->buffer));
   SET_TEXT_POS (opoint, PT, PT_BYTE);
 
+  save_beg_unchanged = BEG_UNCHANGED;
+  save_end_unchanged = END_UNCHANGED;
+
   current_matrix_up_to_date_p
     = (!NILP (w->window_end_valid)
        && !current_buffer->clip_changed
@@ -12964,6 +13055,8 @@ redisplay_window (window, just_this_one_p)
        w->force_start = Qt;
     }
 
+ force_start:
+
   /* Handle case where place to start displaying has been specified,
      unless the specified location is outside the accessible range.  */
   if (!NILP (w->force_start)
@@ -13143,29 +13236,15 @@ redisplay_window (window, just_this_one_p)
         than a simple mouse-click.  */
       if (NILP (w->start_at_line_beg)
          && NILP (do_mouse_tracking)
-         && CHARPOS (startp) > BEGV)
-       {
-         /* Make sure beg_unchanged and end_unchanged are up to date.
-            Do it only if buffer has really changed.  This may or may
-            not have been done by try_window_id (see which) already. */
-         if (MODIFF > SAVE_MODIFF
-             /* This seems to happen sometimes after saving a buffer.  */
-             || BEG_UNCHANGED + END_UNCHANGED > Z_BYTE)
-           {
-             if (GPT - BEG < BEG_UNCHANGED)
-               BEG_UNCHANGED = GPT - BEG;
-             if (Z - GPT < END_UNCHANGED)
-               END_UNCHANGED = Z - GPT;
-           }
-
-         if (CHARPOS (startp) > BEG + BEG_UNCHANGED
-             && CHARPOS (startp) <= Z - END_UNCHANGED)
-           {
-             /* There doesn't seems to be a simple way to find a new
-                window start that is near the old window start, so
-                we just recenter.  */
-             goto recenter;
-           }
+         && CHARPOS (startp) > BEGV
+         && CHARPOS (startp) > BEG + save_beg_unchanged
+         && CHARPOS (startp) <= Z - save_end_unchanged)
+       {
+         w->force_start = Qt;
+         if (XMARKER (w->start)->buffer == current_buffer)
+           compute_window_start_on_continuation_line (w);
+         SET_TEXT_POS_FROM_MARKER (startp, w->start);
+         goto force_start;
        }
 
 #if GLYPH_DEBUG
@@ -13522,7 +13601,10 @@ redisplay_window (window, just_this_one_p)
   /* Restore current_buffer and value of point in it.  */
   TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
   set_buffer_internal_1 (old);
-  TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
+  /* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become
+     shorter.  This can be caused by log truncation in *Messages*. */
+  if (CHARPOS (lpoint) <= ZV)
+    TEMP_SET_PT_BOTH (CHARPOS (lpoint), BYTEPOS (lpoint));
 
   unbind_to (count, Qnil);
 }
@@ -13797,7 +13879,7 @@ try_window_reusing_current_matrix (w)
                         nrows_scrolled);
 
          /* Disable lines that must be updated.  */
-         for (i = 0; i < it.vpos; ++i)
+         for (i = 0; i < nrows_scrolled; ++i)
            (start_row + i)->enabled_p = 0;
 
          /* Re-compute Y positions.  */
@@ -15853,13 +15935,37 @@ cursor_row_p (w, row)
 
   if (PT == MATRIX_ROW_END_CHARPOS (row))
     {
-      /* If the row ends with a newline from a string, we don't want
-        the cursor there, but we still want it at the start of the
-        string if the string starts in this row.
-        If the row is continued it doesn't end in a newline.  */
+      /* Suppose the row ends on a string.
+        Unless the row is continued, that means it ends on a newline
+        in the string.  If it's anything other than a display string
+        (e.g. a before-string from an overlay), we don't want the
+        cursor there.  (This heuristic seems to give the optimal
+        behavior for the various types of multi-line strings.)  */
       if (CHARPOS (row->end.string_pos) >= 0)
-       cursor_row_p = (row->continued_p
-                       || PT >= MATRIX_ROW_START_CHARPOS (row));
+       {
+         if (row->continued_p)
+           cursor_row_p = 1;
+         else
+           {
+             /* Check for `display' property.  */
+             struct glyph *beg = row->glyphs[TEXT_AREA];
+             struct glyph *end = beg + row->used[TEXT_AREA] - 1;
+             struct glyph *glyph;
+
+             cursor_row_p = 0;
+             for (glyph = end; glyph >= beg; --glyph)
+               if (STRINGP (glyph->object))
+                 {
+                   Lisp_Object prop
+                     = Fget_char_property (make_number (PT),
+                                           Qdisplay, Qnil);
+                   cursor_row_p =
+                     (!NILP (prop)
+                      && display_prop_string_p (prop, glyph->object));
+                   break;
+                 }
+           }
+       }
       else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
        {
          /* If the row ends in middle of a real character,
@@ -17319,7 +17425,9 @@ are the selected window and the window's buffer).  */)
     buffer = w->buffer;
   CHECK_BUFFER (buffer);
 
-  if (NILP (format))
+  /* Make formatting the modeline a non-op when noninteractive, otherwise
+     there will be problems later caused by a partially initialized frame.  */
+  if (NILP (format) || noninteractive)
     return build_string ("");
 
   if (no_props)
@@ -21270,7 +21378,7 @@ get_window_cursor_type (w, glyph, width, active_cursor)
       non_selected = 1;
     }
 
-  /* Nonselected window or nonselected frame.  */
+  /* Detect a nonselected window or nonselected frame.  */
   else if (w != XWINDOW (f->selected_window)
 #ifdef HAVE_WINDOW_SYSTEM
           || f != FRAME_X_DISPLAY_INFO (f)->x_highlight_frame
@@ -21289,13 +21397,6 @@ get_window_cursor_type (w, glyph, width, active_cursor)
   if (NILP (b->cursor_type))
     return NO_CURSOR;
 
-  /* Use cursor-in-non-selected-windows for non-selected window or frame.  */
-  if (non_selected)
-    {
-      alt_cursor = b->cursor_in_non_selected_windows;
-      return get_specified_cursor_type (alt_cursor, width);
-    }
-
   /* Get the normal cursor type for this window.  */
   if (EQ (b->cursor_type, Qt))
     {
@@ -21305,6 +21406,21 @@ get_window_cursor_type (w, glyph, width, active_cursor)
   else
     cursor_type = get_specified_cursor_type (b->cursor_type, width);
 
+  /* Use cursor-in-non-selected-windows instead
+     for non-selected window or frame.  */
+  if (non_selected)
+    {
+      alt_cursor = b->cursor_in_non_selected_windows;
+      if (!EQ (Qt, alt_cursor))
+       return get_specified_cursor_type (alt_cursor, width);
+      /* t means modify the normal cursor type.  */
+      if (cursor_type == FILLED_BOX_CURSOR)
+       cursor_type = HOLLOW_BOX_CURSOR;
+      else if (cursor_type == BAR_CURSOR && *width > 1)
+       --*width;
+      return cursor_type;
+    }
+
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
@@ -23365,6 +23481,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)
@@ -23988,8 +24122,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,
@@ -24107,7 +24245,10 @@ Any other value means to autoselect window instantaneously when the
 mouse pointer enters it.
 
 Autoselection selects the minibuffer only if it is active, and never
-unselects the minibuffer if it is active.  */);
+unselects the minibuffer if it is active.
+
+When customizing this variable make sure that the actual value of
+`focus-follows-mouse' matches the behavior of your window manager.  */);
   Vmouse_autoselect_window = Qnil;
 
   DEFVAR_LISP ("auto-resize-tool-bars", &Vauto_resize_tool_bars,
@@ -24115,7 +24256,7 @@ unselects the minibuffer if it is active.  */);
 This dynamically changes the tool-bar's height to the minimum height
 that is needed to make all tool-bar items visible.
 If value is `grow-only', the tool-bar's height is only increased
-automatically; to decreace the tool-bar height, use \\[recenter].  */);
+automatically; to decrease the tool-bar height, use \\[recenter].  */);
   Vauto_resize_tool_bars = Qt;
 
   DEFVAR_BOOL ("auto-raise-tool-bar-buttons", &auto_raise_tool_bar_buttons_p,