]> code.delx.au - gnu-emacs/blobdiff - src/xdisp.c
* src/xdisp.c (windows_or_buffers_changed): Improve docstring
[gnu-emacs] / src / xdisp.c
index b86307776e2ec51bf6a0125cfc416e61f349bebe..051d3078529022d8391f8693e69b919cc91bf33b 100644 (file)
@@ -434,22 +434,54 @@ static Lisp_Object Vmessage_stack;
 
 static bool message_enable_multibyte;
 
-/* Nonzero if we should redraw the mode lines on the next redisplay.
-   If it has value REDISPLAY_SOME, then only redisplay the mode lines where
-   the `redisplay' bit has been set.  Otherwise, redisplay all mode lines
-   (the number used is then only used to track down the cause for this
-   full-redisplay).  */
+/* At each redisplay cycle, we should refresh everything there is to refresh.
+   To do that efficiently, we use many optimizations that try to make sure we
+   don't waste too much time updating things that haven't changed.
+   The coarsest such optimization is that, in the most common cases, we only
+   look at the selected-window.
+
+   To know whether other windows should be considered for redisplay, we use the
+   variable windows_or_buffers_changed: as long as it is 0, it means that we
+   have not noticed anything that should require updating anything else than
+   the selected-window.  If it is set to REDISPLAY_SOME, it means that since
+   last redisplay, some changes have been made which could impact other
+   windows.  To know which ones need redisplay, every buffer, window, and frame
+   has a `redisplay' bit, which (if true) means that this object needs to be
+   redisplayed.  If windows_or_buffers_changed is 0, we know there's no point
+   looking for those `redisplay' bits (actually, there might be some such bits
+   set, but then only on objects which aren't displayed anyway).
+
+   OTOH if it's non-zero we wil have to loop through all windows and then check
+   the `redisplay' bit of the corresponding window, frame, and buffer, in order
+   to decide whether that window needs attention or not.  Not that we can't
+   just look at the frame's redisplay bit to decide that the whole frame can be
+   skipped, since even if the frame's redisplay bit is unset, some of its
+   windows's redisplay bits may be set.
+
+   Mostly for historical reasons, windows_or_buffers_changed can also take
+   other non-zero values.  In that case, the precise value doesn't matter (it
+   encodes the cause of the setting but is only used for debugging purposes),
+   and what it means is that we shouldn't pay attention to any `redisplay' bits
+   and we should simply try and redisplay every window out there.  */
 
-int update_mode_lines;
+int windows_or_buffers_changed;
 
-/* Nonzero if window sizes or contents other than selected-window have changed
-   since last redisplay that finished.
-   If it has value REDISPLAY_SOME, then only redisplay the windows where
-   the `redisplay' bit has been set.  Otherwise, redisplay all windows
-   (the number used is then only used to track down the cause for this
-   full-redisplay).  */
+/* Nonzero if we should redraw the mode lines on the next redisplay.
+   Similarly to `windows_or_buffers_changed', If it has value REDISPLAY_SOME,
+   then only redisplay the mode lines in those buffers/windows/frames where the
+   `redisplay' bit has been set.
+   For any other value, redisplay all mode lines (the number used is then only
+   used to track down the cause for this full-redisplay).
+
+   The `redisplay' bits are the same as those used for
+   windows_or_buffers_changed, and setting windows_or_buffers_changed also
+   causes recomputation of the mode lines of all those windows.  IOW this
+   variable only has an effect if windows_or_buffers_changed is zero, in which
+   case we should only need to redisplay the mode-line of those objects with
+   a `redisplay' bit set but not the window's text content (tho we may still
+   need to refresh the text content of the selected-window).  */
 
-int windows_or_buffers_changed;
+int update_mode_lines;
 
 /* True after display_mode_line if %l was used and it displayed a
    line number.  */
@@ -2661,10 +2693,18 @@ init_iterator (struct it *it, struct window *w,
      free realized faces now because they depend on face definitions
      that might have changed.  Don't free faces while there might be
      desired matrices pending which reference these faces.  */
-  if (face_change && !inhibit_free_realized_faces)
+  if (!inhibit_free_realized_faces)
     {
-      face_change = false;
-      free_all_realized_faces (Qnil);
+      if (face_change)
+       {
+         face_change = false;
+         free_all_realized_faces (Qnil);
+       }
+      else if (XFRAME (w->frame)->face_change)
+       {
+         XFRAME (w->frame)->face_change = 0;
+         free_all_realized_faces (w->frame);
+       }
     }
 
   /* Perhaps remap BASE_FACE_ID to a user-specified alternative.  */
@@ -4014,21 +4054,26 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
              /* With bidi iteration, the character before the current
                 in the visual order cannot be found by simple
                 iteration, because "reverse" reordering is not
-                supported.  Instead, we need to use the move_it_*
-                family of functions.  */
+                supported.  Instead, we need to start from the string
+                beginning and go all the way to the current string
+                position, remembering the previous position.  */
              /* Ignore face changes before the first visible
                 character on this display line.  */
              if (it->current_x <= it->first_visible_x)
                return it->face_id;
              SAVE_IT (it_copy, *it, it_copy_data);
-             /* Implementation note: Since move_it_in_display_line
-                works in the iterator geometry, and thinks the first
-                character is always the leftmost, even in R2L lines,
-                we don't need to distinguish between the R2L and L2R
-                cases here.  */
-             move_it_in_display_line (&it_copy, SCHARS (it_copy.string),
-                                      it_copy.current_x - 1, MOVE_TO_X);
-             charpos = IT_STRING_CHARPOS (it_copy);
+             IT_STRING_CHARPOS (it_copy) = 0;
+             bidi_init_it (0, 0, FRAME_WINDOW_P (it_copy.f), &it_copy.bidi_it);
+
+             do
+               {
+                 charpos = IT_STRING_CHARPOS (it_copy);
+                 if (charpos >= SCHARS (it->string))
+                   break;
+                 bidi_move_to_visually_next (&it_copy.bidi_it);
+               }
+             while (IT_STRING_CHARPOS (it_copy) != IT_STRING_CHARPOS (*it));
+
              RESTORE_IT (it, it, it_copy_data);
            }
          else
@@ -4108,11 +4153,15 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
        {
          if (before_p)
            {
+             int current_x;
+
              /* With bidi iteration, the character before the current
                 in the visual order cannot be found by simple
                 iteration, because "reverse" reordering is not
                 supported.  Instead, we need to use the move_it_*
-                family of functions.  */
+                family of functions, and move to the previous
+                character starting from the beginning of the visual
+                line.  */
              /* Ignore face changes before the first visible
                 character on this display line.  */
              if (it->current_x <= it->first_visible_x)
@@ -4123,8 +4172,9 @@ face_before_or_after_it_pos (struct it *it, bool before_p)
                 character is always the leftmost, even in R2L lines,
                 we don't need to distinguish between the R2L and L2R
                 cases here.  */
-             move_it_in_display_line (&it_copy, ZV,
-                                      it_copy.current_x - 1, MOVE_TO_X);
+             current_x = it_copy.current_x;
+             move_it_vertically_backward (&it_copy, 0);
+             move_it_in_display_line (&it_copy, ZV, current_x - 1, MOVE_TO_X);
              pos = it_copy.current.pos;
              RESTORE_IT (it, it, it_copy_data);
            }
@@ -5895,6 +5945,13 @@ push_it (struct it *it, struct text_pos *position)
     case GET_FROM_STRETCH:
       p->u.stretch.object = it->object;
       break;
+    case GET_FROM_BUFFER:
+    case GET_FROM_DISPLAY_VECTOR:
+    case GET_FROM_STRING:
+    case GET_FROM_C_STRING:
+      break;
+    default:
+      emacs_abort ();
     }
   p->position = position ? *position : it->position;
   p->current = it->current;
@@ -6017,6 +6074,11 @@ pop_it (struct it *it)
          it->method = GET_FROM_BUFFER;
          it->object = it->w->contents;
        }
+      break;
+    case GET_FROM_C_STRING:
+      break;
+    default:
+      emacs_abort ();
     }
   it->end_charpos = p->end_charpos;
   it->string_nchars = p->string_nchars;
@@ -13306,6 +13368,9 @@ redisplay_internal (void)
   /* True means redisplay has to redisplay the miniwindow.  */
   bool update_miniwindow_p = false;
 
+  /* True means we need to redraw frames whose 'redisplay' bit is set.  */
+  bool consider_some_frames_p = false;
+
   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
 
   /* No redisplay if running in batch mode or frame is not yet fully
@@ -13353,6 +13418,10 @@ redisplay_internal (void)
   pending = false;
   forget_escape_and_glyphless_faces ();
 
+  inhibit_free_realized_faces = false;
+
+  consider_some_frames_p = false;
+
   /* If face_change, init_iterator will free all realized faces, which
      includes the faces referenced from current matrices.  So, we
      can't reuse current matrices in this case.  */
@@ -13400,7 +13469,7 @@ redisplay_internal (void)
          /* If cursor type has been changed on the frame
             other than selected, consider all frames.  */
          if (f != sf && f->cursor_type_changed)
-           update_mode_lines = 31;
+           fset_redisplay (f);
        }
       clear_desired_matrices (f);
     }
@@ -13498,9 +13567,12 @@ redisplay_internal (void)
   consider_all_windows_p = (update_mode_lines
                            || windows_or_buffers_changed);
 
-#define AINC(a,i) \
-  if (VECTORP (a) && i >= 0 && i < ASIZE (a) && INTEGERP (AREF (a, i))) \
-    ASET (a, i, make_number (1 + XINT (AREF (a, i))))
+#define AINC(a,i)                                                      \
+  {                                                                    \
+    Lisp_Object entry = Fgethash (make_number (i), a, make_number (0));        \
+    if (INTEGERP (entry))                                              \
+      Fputhash (make_number (i), make_number (1 + XINT (entry)), a);   \
+  }
 
   AINC (Vredisplay__all_windows_cause, windows_or_buffers_changed);
   AINC (Vredisplay__mode_lines_cause, update_mode_lines);
@@ -13519,6 +13591,8 @@ redisplay_internal (void)
       && FRAME_VISIBLE_P (XFRAME (w->frame))
       && !FRAME_OBSCURED_P (XFRAME (w->frame))
       && !XFRAME (w->frame)->cursor_type_changed
+      && !XFRAME (w->frame)->face_change
+      && !XFRAME (w->frame)->redisplay
       /* Make sure recorded data applies to current buffer, etc.  */
       && this_line_buffer == current_buffer
       && match_p
@@ -13714,13 +13788,31 @@ redisplay_internal (void)
 #endif
 
   /* Build desired matrices, and update the display.  If
-     consider_all_windows_p, do it for all windows on all frames.
-     Otherwise do it for selected_window, only.  */
+     consider_all_windows_p, do it for all windows on all frames.  If
+     a frame's 'redisplay' flag is set, do it for all windows on each
+     such frame.  Otherwise do it for selected_window, only.  */
+
+  if (!consider_all_windows_p)
+    {
+      FOR_EACH_FRAME (tail, frame)
+       {
+         if (XFRAME (frame)->redisplay
+             && XFRAME (frame) != sf
+             && !FRAME_INITIAL_P (XFRAME (frame)))
+           {
+             consider_some_frames_p = true;
+             break;
+           }
+       }
+    }
 
-  if (consider_all_windows_p)
+  if (consider_all_windows_p || consider_some_frames_p)
     {
       FOR_EACH_FRAME (tail, frame)
-       XFRAME (frame)->updated_p = false;
+       {
+         if (XFRAME (frame)->redisplay || consider_all_windows_p)
+           XFRAME (frame)->updated_p = false;
+       }
 
       propagate_buffer_redisplay ();
 
@@ -13734,6 +13826,9 @@ redisplay_internal (void)
              && !EQ (FRAME_TTY (f)->top_frame, frame))
            continue;
 
+         if (!consider_all_windows_p && !f->redisplay)
+           continue;
+
        retry_frame:
          if (FRAME_WINDOW_P (f) || FRAME_TERMCAP_P (f) || f == sf)
            {
@@ -13840,6 +13935,10 @@ redisplay_internal (void)
       if (sf->fonts_changed)
        goto retry;
 
+      /* Prevent freeing of realized faces, since desired matrices are
+        pending that reference the faces we computed and cached.  */
+      inhibit_free_realized_faces = true;
+
       /* Prevent various kinds of signals during display update.
         stdio is not robust about handling signals,
         which can cause an apparent I/O error.  */
@@ -15375,6 +15474,7 @@ try_cursor_movement (Lisp_Object window, struct text_pos startp,
       && !update_mode_lines
       && !windows_or_buffers_changed
       && !f->cursor_type_changed
+      && !f->redisplay
       && NILP (Vshow_trailing_whitespace)
       /* This code is not used for mini-buffer for the sake of the case
         of redisplaying to replace an echo area message; since in
@@ -15865,6 +15965,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
       && REDISPLAY_SOME_P ()
       && !w->redisplay
       && !w->update_mode_line
+      && !f->face_change
       && !f->redisplay
       && !buffer->text->redisplay
       && BUF_PT (buffer) == w->last_point)
@@ -16984,6 +17085,7 @@ try_window_reusing_current_matrix (struct window *w)
       /* Don't try to reuse the display if windows have been split
         or such.  */
       || windows_or_buffers_changed
+      || f->redisplay
       || f->cursor_type_changed)
     return false;
 
@@ -17761,7 +17863,7 @@ try_window_id (struct window *w)
     GIVE_UP (1);
 
   /* This flag is used to prevent redisplay optimizations.  */
-  if (windows_or_buffers_changed || f->cursor_type_changed)
+  if (windows_or_buffers_changed || f->cursor_type_changed || f->redisplay)
     GIVE_UP (2);
 
   /* This function's optimizations cannot be used if overlays have
@@ -19770,7 +19872,8 @@ push_prefix_prop (struct it *it, Lisp_Object prop)
 
   eassert (it->method == GET_FROM_BUFFER
           || it->method == GET_FROM_DISPLAY_VECTOR
-          || it->method == GET_FROM_STRING);
+          || it->method == GET_FROM_STRING
+          || it->method == GET_FROM_IMAGE);
 
   /* We need to save the current buffer/string position, so it will be
      restored by pop_it, because iterate_out_of_display_property
@@ -21026,7 +21129,7 @@ window-specific overlays, which can affect the results.
 
 Strong directional characters `L', `R', and `AL' can have their
 intrinsic directionality overridden by directional override
-control characters RLO \(u+202e) and LRO \(u+202d).  See the
+control characters RLO (u+202e) and LRO (u+202d).  See the
 function `get-char-code-property' for a way to inquire about
 the `bidi-class' property of a character.  */)
   (Lisp_Object from, Lisp_Object to, Lisp_Object object)
@@ -25934,9 +26037,7 @@ produce_stretch_glyph (struct it *it)
       zero_width_ok_p = true;
       width = (int)tem;
     }
-#ifdef HAVE_WINDOW_SYSTEM
-  else if (FRAME_WINDOW_P (it->f)
-          && (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0))
+  else if (prop = Fplist_get (plist, QCrelative_width), NUMVAL (prop) > 0)
     {
       /* Relative width `:relative-width FACTOR' specified and valid.
         Compute the width of the characters having the `glyph'
@@ -25956,10 +26057,9 @@ produce_stretch_glyph (struct it *it)
 
       it2.glyph_row = NULL;
       it2.what = IT_CHARACTER;
-      x_produce_glyphs (&it2);
+      PRODUCE_GLYPHS (&it2);
       width = NUMVAL (prop) * it2.pixel_width;
     }
-#endif /* HAVE_WINDOW_SYSTEM */
   else if ((prop = Fplist_get (plist, QCalign_to), !NILP (prop))
           && calc_pixel_width_or_height (&tem, it, prop, font, true,
                                          &align_to))
@@ -30982,18 +31082,18 @@ This variable is not guaranteed to be accurate except while processing
 
   DEFVAR_LISP ("frame-title-format", Vframe_title_format,
     doc: /* Template for displaying the title bar of visible frames.
-\(Assuming the window manager supports this feature.)
+(Assuming the window manager supports this feature.)
 
 This variable has the same structure as `mode-line-format', except that
 the %c and %l constructs are ignored.  It is used only on frames for
-which no explicit name has been set \(see `modify-frame-parameters').  */);
+which no explicit name has been set (see `modify-frame-parameters').  */);
 
   DEFVAR_LISP ("icon-title-format", Vicon_title_format,
     doc: /* Template for displaying the title bar of an iconified frame.
-\(Assuming the window manager supports this feature.)
+(Assuming the window manager supports this feature.)
 This variable has the same structure as `mode-line-format' (which see),
 and is used only on frames for which no explicit name has been set
-\(see `modify-frame-parameters').  */);
+(see `modify-frame-parameters').  */);
   Vicon_title_format
     = Vframe_title_format
     = listn (CONSTYPE_PURE, 3,
@@ -31052,9 +31152,9 @@ A positive number means delay autoselection by that many seconds: a
 window is autoselected only after the mouse has remained in that
 window for the duration of the delay.
 A negative number has a similar effect, but causes windows to be
-autoselected only after the mouse has stopped moving.  \(Because of
+autoselected only after the mouse has stopped moving.  (Because of
 the way Emacs compares mouse events, you will occasionally wait twice
-that time before the window gets selected.\)
+that time before the window gets selected.)
 Any other value means to autoselect window instantaneously when the
 mouse pointer enters it.
 
@@ -31352,13 +31452,11 @@ display table takes effect; in this case, Emacs does not consult
 
   DEFVAR_LISP ("redisplay--all-windows-cause", Vredisplay__all_windows_cause,
               doc: /*  */);
-  Vredisplay__all_windows_cause
-    = Fmake_vector (make_number (100), make_number (0));
+  Vredisplay__all_windows_cause = Fmake_hash_table (0, NULL);
 
   DEFVAR_LISP ("redisplay--mode-lines-cause", Vredisplay__mode_lines_cause,
               doc: /*  */);
-  Vredisplay__mode_lines_cause
-    = Fmake_vector (make_number (100), make_number (0));
+  Vredisplay__mode_lines_cause = Fmake_hash_table (0, NULL);
 }