diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 054683d7cf6..2ed904f178f 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -231,6 +231,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of (inverse-video display boolean) (visible-bell display boolean) (no-redraw-on-reenter display boolean) + (mouse-prefer-closest-glyph display boolean) ;; doc.c (text-quoting-style display diff --git a/src/dispnew.c b/src/dispnew.c index 65d9cf9b4e1..669cd5f4d33 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -5611,6 +5611,15 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p argument is ZV to prevent move_it_in_display_line from matching based on buffer positions. */ move_it_in_display_line (&it, ZV, to_x, MOVE_TO_X); + if (mouse_prefer_closest_glyph) + { + int next_x = it.current_x + it.pixel_width; + int before_dx = to_x - it.current_x; + int after_dx = next_x - to_x; + if (before_dx > after_dx) + move_it_in_display_line (&it, ZV, next_x, MOVE_TO_X); + } + bidi_unshelve_cache (itdata, 0); Fset_buffer (old_current_buffer); @@ -6788,6 +6797,15 @@ predicates which report frame's specific UI-related capabilities. */); DEFVAR_BOOL ("cursor-in-echo-area", cursor_in_echo_area, doc: /* Non-nil means put cursor in minibuffer, at end of any message there. */); + DEFVAR_BOOL ("mouse-prefer-closest-glyph", mouse_prefer_closest_glyph, + doc: /* Non-nil means mouse position lists are reported relative +to the glyph closest to their coordinates. + + When non-nil, mouse position lists will be reported with their +`posn-point' set to the position of the glyph closest to the mouse +pointer, instead of the glyph immediately under. */); + mouse_prefer_closest_glyph = false; + DEFVAR_LISP ("glyph-table", Vglyph_table, doc: /* Table defining how to output a glyph code to the frame. If not nil, this is a vector indexed by glyph code to define the glyph. diff --git a/src/xterm.c b/src/xterm.c index 5840b15bcb7..b460603068c 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -14161,6 +14161,20 @@ x_construct_mouse_click (struct input_event *result, return Qnil; } +/* Function to bisect `glyph` into left and right halves, then + replace it with the half in which `x` is. */ + +static void +x_vertical_bisect_glyph(XRectangle *glyph, int x) +{ + int halfwidth = glyph->width / 2; + glyph->width = halfwidth; + + int bisection = glyph->x + halfwidth; + if (x > bisection) + glyph->x = bisection; +} + /* Function to report a mouse movement to the mainstream Emacs code. The input handler calls this. @@ -14218,6 +14232,8 @@ x_note_mouse_movement (struct frame *frame, const XMotionEvent *event, note_mouse_highlight (frame, event->x, event->y); /* Remember which glyph we're now on. */ remember_mouse_glyph (frame, event->x, event->y, r); + if (mouse_prefer_closest_glyph) + x_vertical_bisect_glyph(r, event->x); dpyinfo->last_mouse_glyph_frame = frame; return true; } @@ -14382,6 +14398,8 @@ x_fast_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph); dpyinfo->last_mouse_glyph_frame = f1; + if (mouse_prefer_closest_glyph) + x_vertical_bisect_glyph(&dpyinfo->last_mouse_glyph, win_x); *bar_window = Qnil; *part = scroll_bar_nowhere; @@ -14733,6 +14751,8 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, dpyinfo = FRAME_DISPLAY_INFO (f1); remember_mouse_glyph (f1, win_x, win_y, &dpyinfo->last_mouse_glyph); dpyinfo->last_mouse_glyph_frame = f1; + if (mouse_prefer_closest_glyph) + x_vertical_bisect_glyph(&dpyinfo->last_mouse_glyph, win_x); *bar_window = Qnil; *part = 0;