From: Po Lu via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: larsi@gnus.org, 50660@debbugs.gnu.org
Subject: bug#50660: 28.0.50; Text artifacting when the cursor moves over text under mouse face that originally displayed a box
Date: Mon, 20 Sep 2021 14:33:01 +0800 [thread overview]
Message-ID: <87v92v69k2.fsf@yahoo.com> (raw)
In-Reply-To: <87fsu06oxi.fsf@yahoo.com> (Po Lu's message of "Mon, 20 Sep 2021 09:00:57 +0800")
[-- Attachment #1: Type: text/plain, Size: 83 bytes --]
BTW, here's an updated version of the patch with some issues I noticed
rectified.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: fix-cursor-position.patch --]
[-- Type: text/x-patch, Size: 11642 bytes --]
From e39d92b045b6d90c460874b5b3981c8fce69fab3 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Sun, 19 Sep 2021 21:41:36 +0800
Subject: [PATCH] Fix cursor showing up in incorrect position highlighting box
When computing the pixel width of glyphs, the produce_XXX_glyph series
of functions append the width of box lines to the glyph's pixel width;
This information is used for several tasks, such as calculating the
X-offset of the cursor.
Unfortunately, previously, this information would not be updated when
the the glyphs become displayed under mouse face, which caused issues
when the cursor was drawn over a section of text that was highlighted
while previously having a box.
* src/dispextern.h (have_glyph_with_box_p): New variable.
* src/dispextern.h (mouse_face_glyphs_processed_p): Likewise.
* src/xdisp.c (produce_image_glyph): Mark the row as having a box
if the vertical line width is more than 0.
* src/xdisp.c (produce_xwidget_glyph): Likewise.
* src/xdisp.c (IT_APPLY_FACE_BOX): Mark the iterator's row as having a
box if the vertical line width is more than 0.
* src/xdisp.c (draw_row_with_mouse_face): Modify glyphs in the row to
take into account differing vertical box line widths between the mouse
face and the original face.
* src/xdisp.c (clear_mouse_face): Recompute cursor position after
clearing mouse face.
---
src/dispextern.h | 10 +++
src/xdisp.c | 199 +++++++++++++++++++++++++++++++++++++++++------
2 files changed, 187 insertions(+), 22 deletions(-)
diff --git a/src/dispextern.h b/src/dispextern.h
index 6aefe43e19..dfaf271639 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1065,6 +1065,16 @@ #define CHECK_MATRIX(MATRIX) ((void) 0)
right-to-left paragraph. */
bool_bf reversed_p : 1;
+ /* True means there is at least one glyph in this row with a left
+ box line. See the commentary inside `draw_row_with_mouse_face'
+ in xdisp.c for more details. */
+ bool_bf have_glyph_with_box_p : 1;
+
+ /* True means we have already processed the box glyphs on this
+ row for display under mouse face. This can only be set if
+ have_glyph_with_box_p is true. */
+ bool_bf mouse_face_glyphs_processed_p : 1;
+
/* Continuation lines width at the start of the row. */
int continuation_lines_width;
diff --git a/src/xdisp.c b/src/xdisp.c
index 2e72f6b591..aa352b59f1 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -29519,6 +29519,8 @@ produce_image_glyph (struct it *it)
if (face->box_vertical_line_width > 0)
{
+ if (it->glyph_row)
+ it->glyph_row->have_glyph_with_box_p = 1;
if (it->start_of_box_run_p && slice.x == 0)
it->pixel_width += face->box_vertical_line_width;
if (it->end_of_box_run_p && slice.x + slice.width == img->width)
@@ -29629,6 +29631,8 @@ produce_xwidget_glyph (struct it *it)
if (face->box_vertical_line_width > 0)
{
+ if (it->glyph_row)
+ it->glyph_row->have_glyph_with_box_p = 1;
if (it->start_of_box_run_p)
it->pixel_width += face->box_vertical_line_width;
it->pixel_width += face->box_vertical_line_width;
@@ -30393,27 +30397,29 @@ produce_glyphless_glyph (struct it *it, bool for_no_font, Lisp_Object acronym)
/* If face has a box, add the box thickness to the character
height. If character has a box line to the left and/or
right, add the box line width to the character's width. */
-#define IT_APPLY_FACE_BOX(it, face) \
- do { \
- if (face->box != FACE_NO_BOX) \
- { \
- int thick = face->box_horizontal_line_width; \
- if (thick > 0) \
- { \
- it->ascent += thick; \
- it->descent += thick; \
- } \
- \
- thick = face->box_vertical_line_width; \
- if (thick > 0) \
- { \
- if (it->start_of_box_run_p) \
- it->pixel_width += thick; \
- if (it->end_of_box_run_p) \
- it->pixel_width += thick; \
- } \
- } \
- } while (false)
+#define IT_APPLY_FACE_BOX(it, face) \
+ do { \
+ if (face->box != FACE_NO_BOX) \
+ { \
+ int thick = face->box_horizontal_line_width; \
+ if (thick > 0) \
+ { \
+ it->ascent += thick; \
+ it->descent += thick; \
+ } \
+ \
+ thick = face->box_vertical_line_width; \
+ if (thick > 0) \
+ { \
+ if (it->glyph_row) \
+ it->glyph_row->have_glyph_with_box_p = 1; \
+ if (it->start_of_box_run_p) \
+ it->pixel_width += thick; \
+ if (it->end_of_box_run_p) \
+ it->pixel_width += thick; \
+ } \
+ } \
+ } while (false)
/* RIF:
Produce glyphs/get display metrics for the display element IT is
@@ -32044,7 +32050,97 @@ draw_row_with_mouse_face (struct window *w, int start_x, struct glyph_row *row,
enum draw_glyphs_face draw)
{
#ifdef HAVE_WINDOW_SYSTEM
- if (FRAME_WINDOW_P (XFRAME (w->frame)))
+ /* Basically, when have_glyph_with_box_p is true,
+ we know we are dealing with a row that has at least one
+ glyph with a box line.
+
+ As such, for each glyph within the highlighted region that has
+ box lines and is the start of a box, we subtract the width of the
+ lines from its pixel_width. */
+ int remove_p = draw != DRAW_MOUSE_FACE;
+
+ if (row->have_glyph_with_box_p &&
+ FRAME_WINDOW_P (XFRAME (w->frame)) &&
+ remove_p == row->mouse_face_glyphs_processed_p)
+ {
+ struct frame *f = WINDOW_XFRAME (w);
+ struct face *mouse_face =
+ FACE_FROM_ID_OR_NULL (f, MOUSE_HL_INFO (f)->mouse_face_face_id);
+
+ if (mouse_face == NULL)
+ mouse_face = FACE_FROM_ID (f, MOUSE_FACE_ID);
+
+ int end_of_modified_glyphs = start_x;
+ struct glyph *g = NULL;
+
+ for (int i = start_hpos; i <= end_hpos; ++i)
+ {
+ g = &row->glyphs[TEXT_AREA][i];
+ struct face *mouse = mouse_face;
+ struct face *regular_face = FACE_FROM_ID (f, g->face_id);
+
+ if (remove_p)
+ {
+ if (g->type == CHAR_GLYPH)
+ mouse = FACE_FROM_ID (f, FACE_FOR_CHAR
+ (f, mouse_face, g->u.ch, -1, Qnil));
+
+ struct face *temp = regular_face;
+ regular_face = mouse;
+ mouse = temp;
+ }
+
+ bool do_left_box_p = g->left_box_line_p;
+ bool do_right_box_p = g->right_box_line_p;
+
+ if (row->reversed_p && g->type == IMAGE_GLYPH)
+ {
+ struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+ g->u.img_id);
+ do_left_box_p = g->right_box_line_p &&
+ g->slice.img.x + g->slice.img.width == img->width;
+ do_right_box_p = g->left_box_line_p &&
+ g->slice.img.x == 0;
+ }
+ else if (g->type == IMAGE_GLYPH)
+ {
+ struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+ g->u.img_id);
+ do_left_box_p = g->left_box_line_p &&
+ g->slice.img.x + g->slice.img.width == img->width;
+ do_right_box_p = g->right_box_line_p &&
+ g->slice.img.x == 0;
+ }
+
+ /* If the glyph has a left box line, subtract from it the
+ original width of the line. */
+ if (do_left_box_p)
+ g->pixel_width -= max (0, regular_face->box_vertical_line_width);
+ /* Likewise with the right box line, as there may be a box
+ there as well. */
+ if (do_right_box_p)
+ g->pixel_width -= max (0, regular_face->box_vertical_line_width);
+ /* Now we add the line widths from the new face. */
+ if (g->left_box_line_p)
+ g->pixel_width += max (0, mouse->box_vertical_line_width);
+ if (g->right_box_line_p)
+ g->pixel_width += max (0, mouse->box_vertical_line_width);
+
+ end_of_modified_glyphs += g->pixel_width;
+ }
+ row->mouse_face_glyphs_processed_p = !remove_p;
+
+ /* Redraw the entire row so changes are taken into effect. */
+ draw_glyphs (w, row->x, row, TEXT_AREA,
+ 0, row->used[TEXT_AREA],
+ DRAW_NORMAL_TEXT, 0);
+
+ /* Now draw the mouse face area. */
+ if (draw != DRAW_NORMAL_TEXT)
+ draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0);
+ return;
+ }
+ else if (FRAME_WINDOW_P (XFRAME (w->frame)))
{
draw_glyphs (w, start_x, row, TEXT_AREA, start_hpos, end_hpos, draw, 0);
return;
@@ -32067,6 +32163,8 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
struct window *w = XWINDOW (hlinfo->mouse_face_window);
struct frame *f = XFRAME (WINDOW_FRAME (w));
+ int unblock_flipping = 0;
+
/* Don't bother doing anything if we are on a wrong frame. */
if (f != hlinfo->mouse_face_mouse_frame)
return;
@@ -32148,6 +32246,19 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
if (end_hpos > start_hpos)
{
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (f) &&
+ w->phys_cursor_on_p && MATRIX_ROW (w->current_matrix,
+ w->phys_cursor.vpos) == row)
+ {
+ /* Helps reduce flicker. */
+ unblock_flipping = true;
+ block_buffer_flips ();
+ /* The cursor's position will be changed later, and if we don't clear it now,
+ artifacting can result. */
+ gui_clear_cursor (w);
+ }
+#endif
draw_row_with_mouse_face (w, start_x, row,
start_hpos, end_hpos, draw);
@@ -32173,6 +32284,36 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
hpos = row->used[TEXT_AREA] - 1;
block_input ();
+ /* If there's a row with a box somewhere, by all likelyhood
+ the dimensions of the row has been changed. If that is
+ the case, and we also find a row where the phys cursor
+ is, recalculate the dimensions of the phys cursor. */
+ for (row = first; row <= last && row->enabled_p; ++row)
+ if (row->have_glyph_with_box_p &&
+ MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos) == row)
+ {
+ int cx = 0, hpos = 0;
+ struct glyph *start = row->glyphs[TEXT_AREA];
+ struct glyph *last = start + row->used[TEXT_AREA] - (intptr_t) 1;
+
+ for (struct glyph *glyph = start; glyph <= last; glyph++)
+ {
+
+ if (hpos == w->phys_cursor.hpos)
+ {
+ w->cursor.x = cx;
+ w->phys_cursor.x = cx;
+ goto set_cursor;
+ }
+
+ cx += glyph->pixel_width;
+ ++hpos;
+ }
+ /* Why was the phys cursor glyph not found, even
+ though the phys cursor is on this row? */
+ emacs_abort ();
+ }
+ set_cursor:
display_and_set_cursor (w, true, hpos, w->phys_cursor.vpos,
w->phys_cursor.x, w->phys_cursor.y);
unblock_input ();
@@ -32197,6 +32338,9 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
FRAME_RIF (f)->define_frame_cursor (f, FRAME_OUTPUT_DATA (f)->nontext_cursor);
}
#endif /* HAVE_WINDOW_SYSTEM */
+
+ if (unblock_flipping)
+ unblock_buffer_flips ();
}
/* EXPORT:
@@ -32209,12 +32353,23 @@ clear_mouse_face (Mouse_HLInfo *hlinfo)
{
bool cleared
= !hlinfo->mouse_face_hidden && !NILP (hlinfo->mouse_face_window);
+#ifdef HAVE_WINDOW_SYSTEM
+ bool cursor_was_in_mouse_face_p =
+ cleared && cursor_in_mouse_face_p (XWINDOW (hlinfo->mouse_face_window));
+ struct window *w = cleared ? XWINDOW (hlinfo->mouse_face_window) : NULL;
+#endif /* HAVE_WINDOW_SYSTEM */
if (cleared)
show_mouse_face (hlinfo, DRAW_NORMAL_TEXT);
hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
hlinfo->mouse_face_window = Qnil;
hlinfo->mouse_face_overlay = Qnil;
+#ifdef HAVE_WINDOW_SYSTEM
+ if (cursor_was_in_mouse_face_p)
+ set_cursor_from_row (w, MATRIX_ROW (w->current_matrix,
+ w->phys_cursor.vpos),
+ w->current_matrix, 0, 0, 0, 0);
+#endif /* HAVE_WINDOW_SYSTEM */
return cleared;
}
--
2.33.0
next prev parent reply other threads:[~2021-09-20 6:33 UTC|newest]
Thread overview: 83+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87czp6ysw7.fsf.ref@yahoo.com>
2021-09-18 12:23 ` bug#50660: 28.0.50; Text artifacting when the cursor moves over text under mouse face that originally displayed a box Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-18 13:48 ` Lars Ingebrigtsen
2021-09-19 0:33 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-19 5:47 ` Eli Zaretskii
2021-09-19 13:55 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-19 15:13 ` Lars Ingebrigtsen
2021-09-19 17:01 ` Eli Zaretskii
2021-09-20 1:00 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 5:19 ` Eli Zaretskii
2021-09-20 5:34 ` Eli Zaretskii
2021-09-20 8:02 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 7:07 ` Eli Zaretskii
2021-09-20 7:34 ` Eli Zaretskii
2021-09-20 8:18 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 9:47 ` Eli Zaretskii
2021-09-20 10:27 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 10:51 ` Eli Zaretskii
2021-09-20 11:08 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 12:07 ` Eli Zaretskii
2021-09-20 12:36 ` Eli Zaretskii
2021-09-21 0:38 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 6:11 ` Eli Zaretskii
2021-09-21 7:34 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 8:45 ` Eli Zaretskii
2021-09-21 9:20 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 9:37 ` Eli Zaretskii
2021-09-21 9:45 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 10:17 ` Eli Zaretskii
2021-09-21 10:41 ` Eli Zaretskii
2021-09-21 12:26 ` Eli Zaretskii
2021-09-20 11:09 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 12:46 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 13:10 ` Eli Zaretskii
2021-09-21 13:36 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-21 13:47 ` Eli Zaretskii
2021-09-23 23:53 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-24 6:47 ` Eli Zaretskii
2021-09-26 6:46 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-26 7:04 ` Eli Zaretskii
2021-09-26 9:56 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-27 11:52 ` Eli Zaretskii
2021-09-29 1:35 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-02 8:43 ` Eli Zaretskii
2021-10-02 9:46 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-02 12:52 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 8:58 ` Eli Zaretskii
2021-10-14 10:52 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 11:11 ` Robert Pluim
2021-10-14 11:25 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 11:35 ` Eli Zaretskii
2021-10-14 11:54 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 12:10 ` Eli Zaretskii
2021-10-14 12:16 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 12:20 ` Eli Zaretskii
2021-10-14 12:27 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 12:44 ` Eli Zaretskii
2021-10-14 13:11 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-14 15:51 ` Eli Zaretskii
2021-10-15 1:28 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-15 13:43 ` Eli Zaretskii
2021-10-16 0:18 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 6:09 ` Eli Zaretskii
2021-10-16 6:16 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 6:28 ` Eli Zaretskii
2021-10-16 6:39 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 7:00 ` Eli Zaretskii
2021-10-16 7:13 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 7:26 ` Eli Zaretskii
2021-10-16 7:52 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 10:10 ` Eli Zaretskii
2021-10-16 12:12 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 12:25 ` Eli Zaretskii
2021-10-16 12:36 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 12:45 ` Eli Zaretskii
2021-10-16 13:18 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-16 13:46 ` Eli Zaretskii
2021-10-17 0:32 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-10-17 12:15 ` Eli Zaretskii
2021-10-17 12:39 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 8:02 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-20 6:33 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2021-09-19 0:50 ` Po Lu via Bug reports for GNU Emacs, the Swiss army knife of text editors
2021-09-19 15:10 ` Lars Ingebrigtsen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87v92v69k2.fsf@yahoo.com \
--to=bug-gnu-emacs@gnu.org \
--cc=50660@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=larsi@gnus.org \
--cc=luangruo@yahoo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.