]> git.eshelyaron.com Git - emacs.git/commitdiff
Handle mouse highlighting in the presence of tty child frames
authorGerd Möllmann <gerd@gnu.org>
Sun, 2 Feb 2025 14:09:52 +0000 (15:09 +0100)
committerEshel Yaron <me@eshelyaron.com>
Mon, 3 Feb 2025 11:15:26 +0000 (12:15 +0100)
* src/term.c (tty_draw_row_with_mouse_face): Draw only parts
of the highlighted text that are not covered by other frames.

(cherry picked from commit a8e85243790b6ab9b9e261c77ddfdc65a9867069)

src/term.c

index f307d70931672884ef70afd7c81bb52d4901dae2..fd95e75a0074cef4e82402cfcaeb4ea9fb53ffe9 100644 (file)
@@ -2559,36 +2559,89 @@ A value of zero means TTY uses the system's default value.  */)
 #if !defined DOS_NT && !defined HAVE_ANDROID
 
 /* Implementation of draw_row_with_mouse_face for TTY/GPM and macOS.  */
+
 void
-tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *row,
-                             int start_hpos, int end_hpos,
+tty_draw_row_with_mouse_face (struct window *w, struct glyph_row *window_row,
+                             int window_start_x,
+                             int window_end_x,
                              enum draw_glyphs_face draw)
 {
-  int nglyphs = end_hpos - start_hpos;
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-  struct tty_display_info *tty = FRAME_TTY (f);
-  int face_id = tty->mouse_highlight.mouse_face_face_id;
+  struct frame *f = XFRAME (w->frame);
+  struct frame *root = root_frame (f);
+
+  /* Window coordinates are relative to the text area.  Make
+     them relative to the window's left edge,  */
+  window_end_x = min (window_end_x, window_row->used[TEXT_AREA]);
+  window_start_x += window_row->used[LEFT_MARGIN_AREA];
+  window_end_x += window_row->used[LEFT_MARGIN_AREA];
+
+  /* Translate from window to window's frame.  */
+  int frame_start_x = WINDOW_LEFT_EDGE_X (w) + window_start_x;
+  int frame_end_x = WINDOW_LEFT_EDGE_X (w) + window_end_x;
+  int frame_y = window_row->y + WINDOW_TOP_EDGE_Y (w);
+
+  /* Translate from (possible) child frame to root frame.  */
+  int root_start_x, root_end_x, root_y;
+  root_xy (f, frame_start_x, frame_y, &root_start_x, &root_y);
+  root_xy (f, frame_end_x, frame_y, &root_end_x, &root_y);
+  struct glyph_row *root_row = MATRIX_ROW (root->current_matrix, root_y);
+
+  /* Remember current cursor coordinates so that we can restore
+     them at the end.  */
+  struct tty_display_info *tty = FRAME_TTY (root);
+  int save_x = curX (tty);
+  int save_y = curY (tty);
 
-  if (end_hpos >= row->used[TEXT_AREA])
-    nglyphs = row->used[TEXT_AREA] - start_hpos;
+  /* If the root frame displays child frames, we cannot naively
+     write to the terminal what the window thinks should be drawn.
+     Instead, write only those parts that are not obscured by
+     other frames.  */
+  for (int root_x = root_start_x; root_x < root_end_x; )
+    {
+      /* Find the start of a run of glyphs from frame F.  */
+      struct glyph *root_start = root_row->glyphs[TEXT_AREA] + root_x;
+      while (root_x < root_end_x && root_start->frame != f)
+       ++root_x, ++root_start;
+
+      /* If start of a run of glyphs from F found.  */
+      int root_run_start_x = root_x;
+      if (root_run_start_x < root_end_x)
+       {
+         /* Find the end of the run of glyphs from frame F.  */
+         struct glyph *root_end = root_start;
+         while (root_x < root_end_x && root_end->frame == f)
+           ++root_x, ++root_end;
 
-  int pos_y = row->y + WINDOW_TOP_EDGE_Y (w);
-  int pos_x = row->used[LEFT_MARGIN_AREA] + start_hpos + WINDOW_LEFT_EDGE_X (w);
+         /* If we have a run glyphs to output, do it.  */
+         if (root_end > root_start)
+           {
+             cursor_to (root, root_y, root_run_start_x);
+             ptrdiff_t n = root_end - root_start;
+             switch (draw)
+               {
+               case DRAW_NORMAL_TEXT:
+                 write_glyphs (f, root_start, n);
+                 break;
 
-  /* Save current cursor coordinates.  */
-  int save_y = curY (tty);
-  int save_x = curX (tty);
-  cursor_to (f, pos_y, pos_x);
+               case DRAW_MOUSE_FACE:
+                 {
+                   int face_id = tty->mouse_highlight.mouse_face_face_id;
+                   struct face *face = FACE_FROM_ID (f, face_id);
+                   tty_write_glyphs_with_face (f, root_start, n, face);
+                 }
+                 break;
 
-  if (draw == DRAW_MOUSE_FACE)
-    {
-      struct glyph *glyph = row->glyphs[TEXT_AREA] + start_hpos;
-      struct face *face = FACE_FROM_ID (f, face_id);
-      tty_write_glyphs_with_face (f, glyph, nglyphs, face);
+               case DRAW_INVERSE_VIDEO:
+               case DRAW_CURSOR:
+               case DRAW_IMAGE_RAISED:
+               case DRAW_IMAGE_SUNKEN:
+                 emacs_abort ();
+               }
+           }
+       }
     }
-  else if (draw == DRAW_NORMAL_TEXT)
-    write_glyphs (f, row->glyphs[TEXT_AREA] + start_hpos, nglyphs);
 
+  /* Restore cursor where it was before.  */
   cursor_to (f, save_y, save_x);
 }