]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
Munge comment associated w/ last change to describe intent; nfc.
[gnu-emacs] / src / xdisp.c
index 5bb157cae73e3c641c741212b8ff4880cca6e6ff..d7de7dbe8262baa8219cce6ea48a058371c3b923 100644 (file)
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* New redisplay written by Gerd Moellmann <gerd@gnu.org>.
 
@@ -231,7 +231,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 Qredisplay_end_trigger_functions;
+Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
 Lisp_Object Qinhibit_point_motion_hooks;
 Lisp_Object QCeval, QCfile, QCdata, QCpropertize;
 Lisp_Object Qfontified;
@@ -2408,7 +2408,9 @@ start_display (it, w, pos)
   init_iterator (it, w, CHARPOS (pos), BYTEPOS (pos), row, DEFAULT_FACE_ID);
   it->first_vpos = first_vpos;
 
-  if (!it->truncate_lines_p)
+  /* Don't reseat to previous visible line start if current start
+     position is in a string or image.  */
+  if (it->method == GET_FROM_BUFFER && !it->truncate_lines_p)
     {
       int start_at_line_beg_p;
       int first_y = it->current_y;
@@ -5871,6 +5873,15 @@ next_element_from_composition (it)
             Moving an iterator without producing glyphs
  ***********************************************************************/
 
+/* Check if iterator is at a position corresponding to a valid buffer
+   position after some move_it_ call.  */
+
+#define IT_POS_VALID_AFTER_MOVE_P(it)                  \
+  ((it)->method == GET_FROM_STRING                     \
+   ? IT_STRING_CHARPOS (*it) == 0                      \
+   : 1)
+
+
 /* Move iterator IT to a specified buffer or X position within one
    line on the display without producing glyphs.
 
@@ -6379,8 +6390,12 @@ move_it_vertically_backward (it, dy)
      y-distance.  */
   it2 = *it;
   it2.max_ascent = it2.max_descent = 0;
-  move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
-             MOVE_TO_POS | MOVE_TO_VPOS);
+  do
+    {
+      move_it_to (&it2, start_pos, -1, -1, it2.vpos + 1,
+                 MOVE_TO_POS | MOVE_TO_VPOS);
+    }
+  while (!IT_POS_VALID_AFTER_MOVE_P (&it2));
   xassert (IT_CHARPOS (*it) >= BEGV);
   it3 = it2;
 
@@ -6578,21 +6593,45 @@ move_it_by_lines (it, dvpos, need_y_p)
       last_height = 0;
     }
   else if (dvpos > 0)
-    move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+    {
+      move_it_to (it, -1, -1, -1, it->vpos + dvpos, MOVE_TO_VPOS);
+      if (!IT_POS_VALID_AFTER_MOVE_P (it))
+       move_it_to (it, IT_CHARPOS (*it) + 1, -1, -1, -1, MOVE_TO_POS);
+    }
   else
     {
       struct it it2;
       int start_charpos, i;
 
       /* Start at the beginning of the screen line containing IT's
-        position.  */
+        position.  This may actually move vertically backwards,
+         in case of overlays, so adjust dvpos accordingly.  */
+      dvpos += it->vpos;
       move_it_vertically_backward (it, 0);
+      dvpos -= it->vpos;
 
       /* Go back -DVPOS visible lines and reseat the iterator there.  */
       start_charpos = IT_CHARPOS (*it);
-      for (i = -dvpos; i && IT_CHARPOS (*it) > BEGV; --i)
+      for (i = -dvpos; i > 0 && IT_CHARPOS (*it) > BEGV; --i)
        back_to_previous_visible_line_start (it);
       reseat (it, it->current.pos, 1);
+
+      /* Move further back if we end up in a string or an image.  */
+      while (!IT_POS_VALID_AFTER_MOVE_P (it))
+       {
+         /* First try to move to start of display line.  */
+         dvpos += it->vpos;
+         move_it_vertically_backward (it, 0);
+         dvpos -= it->vpos;
+         if (IT_POS_VALID_AFTER_MOVE_P (it))
+           break;
+         /* If start of line is still in string or image,
+            move further back.  */
+         back_to_previous_visible_line_start (it);
+         reseat (it, it->current.pos, 1);
+         dvpos--;
+       }
+
       it->current_x = it->hpos = 0;
 
       /* Above call may have moved too far if continuation lines
@@ -7592,7 +7631,7 @@ display_echo_area_1 (a1, a2, a3, a4)
   clear_glyph_matrix (w->desired_matrix);
   XSETWINDOW (window, w);
   SET_TEXT_POS (start, BEG, BEG_BYTE);
-  try_window (window, start);
+  try_window (window, start, 0);
 
   return window_height_changed_p;
 }
@@ -10046,7 +10085,9 @@ select_frame_for_redisplay (frame)
            (BUFFER_LOCAL_VALUEP (val)
             || SOME_BUFFER_LOCAL_VALUEP (val)))
        && XBUFFER_LOCAL_VALUE (val)->check_frame)
-      Fsymbol_value (sym);
+      /* 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))
@@ -10057,7 +10098,7 @@ select_frame_for_redisplay (frame)
            (BUFFER_LOCAL_VALUEP (val)
             || SOME_BUFFER_LOCAL_VALUEP (val)))
        && XBUFFER_LOCAL_VALUE (val)->check_frame)
-      Fsymbol_value (sym);
+      find_symbol_value (sym);
 }
 
 
@@ -10131,6 +10172,16 @@ redisplay_internal (preserve_echo_area)
   ++redisplaying_p;
   specbind (Qinhibit_free_realized_faces, Qnil);
 
+  {
+    Lisp_Object tail, frame;
+
+    FOR_EACH_FRAME (tail, frame)
+      {
+       struct frame *f = XFRAME (frame);
+       f->already_hscrolled_p = 0;
+      }
+  }
+
  retry:
   pause = 0;
   reconsider_clip_changes (w, current_buffer);
@@ -10565,8 +10616,12 @@ redisplay_internal (preserve_echo_area)
              if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
                {
                  /* See if we have to hscroll.  */
-                 if (hscroll_windows (f->root_window))
-                   goto retry;
+                 if (!f->already_hscrolled_p)
+                   {
+                     f->already_hscrolled_p = 1;
+                     if (hscroll_windows (f->root_window))
+                       goto retry;
+                   }
 
                  /* Prevent various kinds of signals during display
                     update.  stdio is not robust about handling
@@ -11294,7 +11349,7 @@ cursor_row_fully_visible_p (w, force_p, current_matrix_p)
   window_height = window_box_height (w);
   if (row->height >= window_height)
     {
-      if (!force_p || w->vscroll)
+      if (!force_p || MINI_WINDOW_P (w) || w->vscroll)
        return 1;
     }
   return 0;
@@ -11570,7 +11625,7 @@ try_scrolling (window, just_this_one_p, scroll_conservatively,
 
   /* Display the window.  Give up if new fonts are loaded, or if point
      doesn't appear.  */
-  if (!try_window (window, startp))
+  if (!try_window (window, startp, 0))
     rc = SCROLLING_NEED_LARGER_MATRICES;
   else if (w->cursor.vpos < 0)
     {
@@ -11824,7 +11879,10 @@ try_cursor_movement (window, startp, scroll_step)
              while (!row->mode_line_p
                     && (MATRIX_ROW_START_CHARPOS (row) > PT
                         || (MATRIX_ROW_START_CHARPOS (row) == PT
-                            && MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)))
+                            && (MATRIX_ROW_STARTS_IN_MIDDLE_OF_CHAR_P (row)
+                                || (/* STARTS_IN_MIDDLE_OF_STRING_P (row) */
+                                    row > w->current_matrix->rows
+                                    && (row-1)->ends_in_newline_from_string_p))))
                     && (row->y > top_scroll_margin
                         || CHARPOS (startp) == BEGV))
                {
@@ -12173,6 +12231,7 @@ redisplay_window (window, just_this_one_p)
     {
       /* We set this later on if we have to adjust point.  */
       int new_vpos = -1;
+      int val;
 
       w->force_start = Qnil;
       w->vscroll = 0;
@@ -12206,12 +12265,16 @@ redisplay_window (window, just_this_one_p)
 
       /* Redisplay, then check if cursor has been set during the
         redisplay.  Give up if new fonts were loaded.  */
-      if (!try_window (window, startp))
+      val = try_window (window, startp, 1);
+      if (!val)
        {
          w->force_start = Qt;
          clear_glyph_matrix (w->desired_matrix);
          goto need_larger_matrices;
        }
+      /* Point was outside the scroll margins.  */
+      if (val < 0)
+       new_vpos = window_box_height (w) / 2;
 
       if (w->cursor.vpos < 0 && !w->frozen_window_start_p)
        {
@@ -12254,7 +12317,7 @@ redisplay_window (window, just_this_one_p)
              && !NILP (current_buffer->mark_active))
            {
              clear_glyph_matrix (w->desired_matrix);
-             if (!try_window (window, startp))
+             if (!try_window (window, startp, 0))
                goto need_larger_matrices;
            }
        }
@@ -12344,7 +12407,11 @@ redisplay_window (window, just_this_one_p)
               = try_window_reusing_current_matrix (w)))
        {
          IF_DEBUG (debug_method_add (w, "1"));
-         try_window (window, startp);
+         if (try_window (window, startp, 1) < 0)
+           /* -1 means we need to scroll.
+              0 means we need new matrices, but fonts_changed_p
+              is set in that case, so we will detect it below.  */
+           goto try_to_scroll;
        }
 
       if (fonts_changed_p)
@@ -12474,7 +12541,7 @@ redisplay_window (window, just_this_one_p)
       || MINI_WINDOW_P (w)
       || !(used_current_matrix_p
           = try_window_reusing_current_matrix (w)))
-    try_window (window, startp);
+    try_window (window, startp, 0);
 
   /* If new fonts have been loaded (due to fontsets), give up.  We
      have to start a new redisplay since we need to re-adjust glyph
@@ -12494,13 +12561,13 @@ redisplay_window (window, just_this_one_p)
        {
          clear_glyph_matrix (w->desired_matrix);
          move_it_by_lines (&it, 1, 0);
-         try_window (window, it.current.pos);
+         try_window (window, it.current.pos, 0);
        }
       else if (PT < IT_CHARPOS (it))
        {
          clear_glyph_matrix (w->desired_matrix);
          move_it_by_lines (&it, -1, 0);
-         try_window (window, it.current.pos);
+         try_window (window, it.current.pos, 0);
        }
       else
        {
@@ -12683,14 +12750,18 @@ redisplay_window (window, just_this_one_p)
 
 
 /* Build the complete desired matrix of WINDOW with a window start
-   buffer position POS.  Value is non-zero if successful.  It is zero
-   if fonts were loaded during redisplay which makes re-adjusting
-   glyph matrices necessary.  */
+   buffer position POS.
+
+   Value is 1 if successful.  It is zero if fonts were loaded during
+   redisplay which makes re-adjusting glyph matrices necessary, and -1
+   if point would appear in the scroll margins.
+   (We check that only if CHECK_MARGINS is nonzero.  */
 
 int
-try_window (window, pos)
+try_window (window, pos, check_margins)
      Lisp_Object window;
      struct text_pos pos;
+     int check_margins;
 {
   struct window *w = XWINDOW (window);
   struct it it;
@@ -12715,6 +12786,31 @@ try_window (window, pos)
        return 0;
     }
 
+  /* Don't let the cursor end in the scroll margins.  */
+  if (check_margins
+      && !MINI_WINDOW_P (w))
+    {
+      int this_scroll_margin, cursor_height;
+
+      this_scroll_margin = max (0, scroll_margin);
+      this_scroll_margin = min (this_scroll_margin, WINDOW_TOTAL_LINES (w) / 4);
+      this_scroll_margin *= FRAME_LINE_HEIGHT (it.f);
+      cursor_height = MATRIX_ROW (w->desired_matrix, w->cursor.vpos)->height;
+
+      if ((w->cursor.y < this_scroll_margin
+          && CHARPOS (pos) > BEGV)
+         /* rms: considering make_cursor_line_fully_visible_p here
+            seems to give wrong results.  We don't want to recenter
+            when the last line is partly visible, we want to allow
+            that case to be handled in the usual way.  */
+         || (w->cursor.y + 1) > it.last_visible_y)
+       {
+         w->cursor.vpos = -1;
+         clear_glyph_matrix (w->desired_matrix);
+         return -1;
+       }
+    }
+
   /* If bottom moved off end of frame, change mode line percentage.  */
   if (XFASTINT (w->window_end_pos) <= 0
       && Z != IT_CHARPOS (it))
@@ -14957,10 +15053,12 @@ 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 (if the row is continued it doesn't end in a
-        newline).  */
+        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.  */
       if (CHARPOS (row->end.string_pos) >= 0)
-       cursor_row_p = row->continued_p;
+       cursor_row_p = (row->continued_p
+                       || PT >= MATRIX_ROW_START_CHARPOS (row));
       else if (MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P (row))
        {
          /* If the row ends in middle of a real character,
@@ -22363,6 +22461,9 @@ x_draw_vertical_border (w)
       window_box_edges (w, -1, &x0, &y0, &x1, &y1);
       y1 -= 1;
 
+      if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+       x1 -= 1;
+
       rif->draw_vertical_window_border (w, x1, y0, y1);
     }
   else if (!WINDOW_LEFTMOST_P (w)
@@ -22373,6 +22474,9 @@ x_draw_vertical_border (w)
       window_box_edges (w, -1, &x0, &y0, &x1, &y1);
       y1 -= 1;
 
+      if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
+       x0 -= 1;
+
       rif->draw_vertical_window_border (w, x0, y0, y1);
     }
 }
@@ -23032,6 +23136,12 @@ 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 ("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.
+See `set-window-redisplay-end-trigger'.  */);
+  Vredisplay_end_trigger_functions = Qnil;
+
   DEFVAR_BOOL ("mouse-autoselect-window", &mouse_autoselect_window,
     doc: /* *Non-nil means autoselect window with mouse pointer.  */);
   mouse_autoselect_window = 0;