Subject: bug#13623: 24.3.50; Redisplay issue with transient-mark-mode

From: Dmitry Antipov <[email-masked]>
Date: Tue, 05 Feb 2013 16:07:47 +0400

On 02/05/2013 08:54 AM, Dmitry Antipov wrote:

> Hm.  Although this is an obvious bug, are you sure that we must redisplay
> the whole window even if the region doesn't span multiple lines? IIUC
> it should be enough to redisplay the current line only.

E.g. something like attached. This is the revert of 111673 plus special
treatment of single-line region.

Dmitry

=== modified file 'src/window.h'
--- src/window.h	2013-02-04 15:39:55 +0000
+++ src/window.h	2013-02-05 09:58:36 +0000
@@ -333,15 +333,13 @@
        the frame image that window_end_pos did not get onto the frame.  */
     unsigned window_end_valid : 1;
 
+    /* Nonzero if we have highlighted the region (or any part of it).  */
+    unsigned region_showing : 1;
+
     /* Amount by which lines of this window are scrolled in
        y-direction (smooth scrolling).  */
     int vscroll;
 
-    /* If we have highlighted the region (or any part of it), the mark
-       position or -1 (the latter is used by the iterator for internal
-       purposes); otherwise zero.  */
-    ptrdiff_t region_showing;
-
     /* Z_BYTE - buffer position of the last glyph in the current matrix of W.
        Should be nonnegative, and only valid if window_end_valid is nonzero.  */
     ptrdiff_t window_end_bytepos;

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2013-02-04 15:39:55 +0000
+++ src/xdisp.c	2013-02-05 11:59:01 +0000
@@ -2536,8 +2536,8 @@
 
 #endif /* GLYPH_DEBUG and ENABLE_CHECKING */
 
-/* Return mark position if current buffer has the region of non-zero length,
-   or -1 otherwise.  */
+/* Return mark position if current buffer has the region of non-zero
+   length, zero if mark and point are the same, or -1 otherwise.  */
 
 static ptrdiff_t
 markpos_of_region (void)
@@ -2547,9 +2547,7 @@
       && XMARKER (BVAR (current_buffer, mark))->buffer != NULL)
     {
       ptrdiff_t markpos = XMARKER (BVAR (current_buffer, mark))->charpos;
-
-      if (markpos != PT)
-	return markpos;
+      return markpos == PT ? 0 : markpos;
     }
   return -1;
 }
@@ -2689,7 +2687,7 @@
      and IT->region_end_charpos to the start and end of a visible region
      in window IT->w.  Set both to -1 to indicate no region.  */
   markpos = markpos_of_region ();
-  if (0 <= markpos
+  if (0 < markpos
       /* Maybe highlight only in selected window.  */
       && (/* Either show region everywhere.  */
 	  highlight_nonselected_windows
@@ -10753,7 +10751,7 @@
 
   return (((BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) != w->last_had_star)
 	  || ((!NILP (Vtransient_mark_mode) && !NILP (BVAR (b, mark_active)))
-	      != (w->region_showing != 0)));
+	      != w->region_showing));
 }
 
 /* Nonzero if W has %c in its mode line and mode line should be updated.  */
@@ -12793,7 +12791,7 @@
   int must_finish = 0;
   struct text_pos tlbufpos, tlendpos;
   int number_of_visible_frames;
-  ptrdiff_t count, count1;
+  ptrdiff_t pos, count, count1;
   struct frame *sf;
   int polling_stopped_here = 0;
   Lisp_Object tail, frame;
@@ -12806,6 +12804,9 @@
   /* Non-zero means redisplay has to redisplay the miniwindow.  */
   int update_miniwindow_p = 0;
 
+  /* Non-zero means the mark is on the same line as point.  */
+  bool mark_at_this_line = 0;
+
   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
 
   /* No redisplay if running in batch mode or frame is not yet fully
@@ -13016,23 +13017,17 @@
       clear_garbaged_frames ();
     }
 
-  /* If showing the region, and mark has changed, we must redisplay
-     the whole window.  The assignment to this_line_start_pos prevents
-     the optimization directly below this if-statement.  */
-  if (((!NILP (Vtransient_mark_mode)
-	&& !NILP (BVAR (XBUFFER (w->buffer), mark_active)))
-       != (w->region_showing > 0))
-      || (w->region_showing
-	  && w->region_showing
-	  != XINT (Fmarker_position (BVAR (XBUFFER (w->buffer), mark)))))
-    CHARPOS (this_line_start_pos) = 0;
-
   /* Optimize the case that only the line containing the cursor in the
      selected window has changed.  Variables starting with this_ are
      set in display_line and record information about the line
      containing the cursor.  */
   tlbufpos = this_line_start_pos;
   tlendpos = this_line_end_pos;
+  pos = markpos_of_region ();
+  if (pos != -1)
+    mark_at_this_line = (CHARPOS (tlbufpos) <= pos
+			 && pos <= Z - CHARPOS (tlendpos));
+
   if (!consider_all_windows_p
       && CHARPOS (tlbufpos) > 0
       && !w->update_mode_line
@@ -13048,6 +13043,8 @@
       /* Point must be on the line that we have info recorded about.  */
       && PT >= CHARPOS (tlbufpos)
       && PT <= Z - CHARPOS (tlendpos)
+      /* No region or region which doesn't span multiple lines.  */
+      && (pos == -1 || mark_at_this_line)
       /* All text outside that line, including its final newline,
 	 must be unchanged.  */
       && text_outside_line_unchanged_p (w, CHARPOS (tlbufpos),
@@ -13059,7 +13056,7 @@
 	      || FETCH_BYTE (BYTEPOS (tlbufpos)) == '\n'))
 	/* Former continuation line has disappeared by becoming empty.  */
 	goto cancel;
-      else if (window_outdated (w) || MINI_WINDOW_P (w))
+      else if (window_outdated (w) || MINI_WINDOW_P (w) || mark_at_this_line)
 	{
 	  /* We have to handle the case of continuation around a
 	     wide-column character (see the comment in indent.c around
@@ -13239,8 +13236,6 @@
   ++clear_image_cache_count;
 #endif
 
-  w->region_showing = XINT (Fmarker_position (BVAR (XBUFFER (w->buffer), mark)));
-
   /* Build desired matrices, and update the display.  If
      consider_all_windows_p is non-zero, do it for all windows on all
      frames.  Otherwise do it for selected_window, only.  */
@@ -14837,7 +14832,7 @@
       /* Can't use this case if highlighting a region.  When a
          region exists, cursor movement has to do more than just
          set the cursor.  */
-      && markpos_of_region () < 0
+      && markpos_of_region () <= 0
       && !w->region_showing
       && NILP (Vshow_trailing_whitespace)
       /* This code is not used for mini-buffer for the sake of the case
@@ -15505,7 +15500,7 @@
 
 	  /* If we are highlighting the region, then we just changed
 	     the region, so redisplay to show it.  */
-	  if (0 <= markpos_of_region ())
+	  if (0 < markpos_of_region ())
 	    {
 	      clear_glyph_matrix (w->desired_matrix);
 	      if (!try_window (window, startp, 0))
@@ -16206,7 +16201,7 @@
     return 0;
 
   /* Can't do this if region may have changed.  */
-  if (0 <= markpos_of_region ()
+  if (0 < markpos_of_region ()
       || w->region_showing
       || !NILP (Vshow_trailing_whitespace))
     return 0;
@@ -17038,7 +17033,7 @@
 
   /* Can't use this if highlighting a region because a cursor movement
      will do more than just set the cursor.  */
-  if (0 <= markpos_of_region ())
+  if (0 < markpos_of_region ())
     GIVE_UP (9);
 
   /* Likewise if highlighting trailing whitespace.  */
@@ -19133,7 +19128,7 @@
     }
 
   /* Is IT->w showing the region?  */
-  it->w->region_showing = it->region_beg_charpos > 0 ? -1 : 0;
+  it->w->region_showing = it->region_beg_charpos > 0;
 
   /* Clear the result glyph row and enable it.  */
   prepare_desired_row (row);