]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle obscured cursor differently
authorGerd Möllmann <gerd@gnu.org>
Wed, 23 Oct 2024 10:59:09 +0000 (12:59 +0200)
committerEshel Yaron <me@eshelyaron.com>
Mon, 23 Dec 2024 14:53:33 +0000 (15:53 +0100)
This also fixes an error made when porting this to savannah.

* src/dispnew.c (abs_cursor_pos, (is_cursor_obscured)
(terminal_cursor_magic): Port correctly and fix.

(cherry picked from commit 9b8d1e0addeca9b508324537e7743d0af508a630)

src/dispnew.c

index 1235ab431c031daa8d2d3e9db358516b7a4823b4..0d7e7770bb001ddacbf29751426aa95e23070eb7 100644 (file)
@@ -3804,25 +3804,68 @@ update_tty_frame (struct frame *f, bool force_p)
   return false;
 }
 
-static void
+/* Return the cursor position of the selected window of frame F, in
+   absolute coordinates in *X and *Y.  Note that if F is a child frame,
+   its cursor may be clipped, i.e. outside of the bounds of the terminal
+   window.  Value is false if the selected window of F doesn't have
+   valid cursor position info.  */
+
+static bool
 abs_cursor_pos (struct frame *f, int *x, int *y)
 {
-  frame_pos_abs (f, x, y);
   struct window *w = XWINDOW (f->selected_window);
-  *x += w->cursor.x;
-  *y += w->cursor.y;
+  if (w->cursor.vpos >= 0
+      /* The cursor vpos may be temporarily out of bounds
+        in the following situation:  There is one window,
+        with the cursor in the lower half of it.  The window
+        is split, and a message causes a redisplay before
+        a new cursor position has been computed.  */
+      && w->cursor.vpos < WINDOW_TOTAL_LINES (w))
+    {
+      int wx = WINDOW_TO_FRAME_HPOS (w, w->cursor.hpos);
+      int wy = WINDOW_TO_FRAME_VPOS (w, w->cursor.vpos);
+
+      wx += max (0, w->left_margin_cols);
+
+      int fx, fy;
+      frame_pos_abs (f, &fx, &fy);
+      *x = fx + wx;
+      *y = fy + wy;
+      return true;
+    }
+
+  *x = *y = 0;
+  return false;
+}
+
+static bool
+is_in_matrix (struct frame *f, int x, int y)
+{
+  struct frame *root = root_frame (f);
+  if (x < 0 || x >= root->current_matrix->matrix_w || y < 0
+      || y >= root->current_matrix->matrix_h)
+    return false;
+  return true;
 }
 
-/* Is the terminal cursor of frame F obscured by a child frame?  */
+/* Is the terminal cursor of the selected frame obscured by a child
+   frame?  */
 
 static bool
 is_cursor_obscured (void)
 {
+  /* Give up if we can't tell where the cursor currently is.  */
   int x, y;
-  abs_cursor_pos (SELECTED_FRAME (), &x, &y);
+  if (!abs_cursor_pos (SELECTED_FRAME (), &x, &y))
+    return false;
+
+  /* (x, y) may be outside of the root frame in case the selected frame is a
+     child frame which is clipped.  */
   struct frame *root = root_frame (SELECTED_FRAME ());
+  if (!is_in_matrix (root, x, y))
+    return true;
+
   struct glyph_row *cursor_row = MATRIX_ROW (root->current_matrix, y);
-  eassert (x < root->current_matrix->matrix_w);
   struct glyph *cursor_glyph = cursor_row->glyphs[0] + x;
   return cursor_glyph->frame != SELECTED_FRAME ();
 }
@@ -3851,14 +3894,18 @@ terminal_cursor_magic (struct frame *root, struct frame *topmost_child)
       Lisp_Object frame;
       XSETFRAME (frame, topmost_child);
 
+      int x, y;
       Lisp_Object cursor = Fframe_parameter (frame, Qtty_non_selected_cursor);
-      if (!NILP (cursor))
+      if (!NILP (cursor) && abs_cursor_pos (topmost_child, &x, &y))
        {
-         int x, y;
-         abs_cursor_pos (topmost_child, &x, &y);
-         cursor_to (root, y, x);
-         tty_show_cursor (FRAME_TTY (topmost_child));
-       }
+         if (is_in_matrix (root, x, y))
+           {
+             cursor_to (root, y, x);
+             tty_show_cursor (FRAME_TTY (topmost_child));
+           }
+         else
+           tty_hide_cursor (FRAME_TTY (root));
+      }
     }
 }