unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Moving point after character when clicking latter half of it
@ 2023-07-08 21:01 Moritz Maxeiner
  2023-07-09  6:35 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-08 21:01 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1013 bytes --]

I am using emacs gtk gui alongside other graphical text editors (left to right text only).

In all of the ones I'm using (other than emacs), clicking with the mouse
on a character moves the point either in front of, or after that character,
depending on whether you clicked the left or right half of it.

In emacs, however, point seems to always be moved in front of the clicked character,
regardless of where on it you click. It would be great if emacs could (optionally) also
support the before/after behavior described above.

After delving into the code, it seems that this would need changes in C.
I have attached a proof of concept patch that changes emacs' behavior,
but it lacks an option mechanism. I also am not familiar enough
with what unintended consequences this change may have.

I am looking for feedback of whether this feature in general is something
that would be acceptable to have in emacs and if there are any pitfalls
this change may cause that I need to be aware of.

Best,
Moritz Maxeiner

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf.patch --]
[-- Type: text/x-patch, Size: 823 bytes --]

diff --git a/src/xdisp.c b/src/xdisp.c
index 763af7d3bc8..46611628d06 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -9905,6 +9905,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT)			\
 	  /* More than one glyph or glyph doesn't fit on line.  All
 	     glyphs have the same width.  */
 	  int single_glyph_width = it->pixel_width / it->nglyphs;
+	  int single_glyph_halfwidth = single_glyph_width / 2;
 	  int new_x;
 	  int x_before_this_char = x;
 	  int hpos_before_this_char = it->hpos;
@@ -9914,7 +9915,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT)			\
 	      new_x = x + single_glyph_width;
 
 	      /* We want to leave anything reaching TO_X to the caller.  */
-	      if ((op & MOVE_TO_X) && new_x > to_x)
+	      if ((op & MOVE_TO_X) && (x + single_glyph_halfwidth) > to_x)
 		{
 		  if (BUFFER_POS_REACHED_P ())
 		    {

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-08 21:01 Moving point after character when clicking latter half of it Moritz Maxeiner
@ 2023-07-09  6:35 ` Eli Zaretskii
  2023-07-09 12:44   ` Moritz Maxeiner
  2023-07-09 12:40 ` Benjamin Riefenstahl
       [not found] ` <12248204.O9o76ZdvQC@anduin>
  2 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-09  6:35 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Date: Sat, 08 Jul 2023 23:01:12 +0200
> 
> I am using emacs gtk gui alongside other graphical text editors (left to right text only).
> 
> In all of the ones I'm using (other than emacs), clicking with the mouse
> on a character moves the point either in front of, or after that character,
> depending on whether you clicked the left or right half of it.
> 
> In emacs, however, point seems to always be moved in front of the clicked character,
> regardless of where on it you click. It would be great if emacs could (optionally) also
> support the before/after behavior described above.
> 
> After delving into the code, it seems that this would need changes in C.
> I have attached a proof of concept patch that changes emacs' behavior,
> but it lacks an option mechanism. I also am not familiar enough
> with what unintended consequences this change may have.

Thanks, but the place where you suggest to make the change is not the
correct one.  The function move_it_in_display_line_to is the workhorse
of "display emulation", and is used by any code which needs to perform
calculations related to display layout without producing anything on
the glass.  It is fundamentally wrong to modify how all of that code
finds the position corresponding to a certain X coordinate just
because the user wants a mouse click to move point to the next
character.

The right place is in buffer_posn_from_coords.  The change will be
more complex there, but there's no way around this, since we want this
change to affect only mouse clicks.

> I am looking for feedback of whether this feature in general is something
> that would be acceptable to have in emacs and if there are any pitfalls
> this change may cause that I need to be aware of.

I think this will be acceptable as optional behavior, yes.  But we
need to consider all of its implications, such as what should happen
when the use drags the mouse -- do we also want the drag to affect
only the following character if the initial click is half-way across a
character's glyph?



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-08 21:01 Moving point after character when clicking latter half of it Moritz Maxeiner
  2023-07-09  6:35 ` Eli Zaretskii
@ 2023-07-09 12:40 ` Benjamin Riefenstahl
  2023-07-09 12:47   ` Moritz Maxeiner
  2023-07-09 15:15   ` [External] : " Drew Adams
       [not found] ` <12248204.O9o76ZdvQC@anduin>
  2 siblings, 2 replies; 47+ messages in thread
From: Benjamin Riefenstahl @ 2023-07-09 12:40 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

Hi Moritz,

Moritz Maxeiner writes:
> In all of the ones I'm using (other than emacs), clicking with the mouse
> on a character moves the point either in front of, or after that character,
> depending on whether you clicked the left or right half of it.

Interesting, I never tested that before.  It explains why I am so often
missing the first character when I try to copy text with the mouse.  IOW
I personally find this an anti-feature.

benny



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09  6:35 ` Eli Zaretskii
@ 2023-07-09 12:44   ` Moritz Maxeiner
  2023-07-09 13:23     ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-09 12:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3190 bytes --]

On Sunday 9 July 2023 08:35:42 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Date: Sat, 08 Jul 2023 23:01:12 +0200
> > 
> > I am using emacs gtk gui alongside other graphical text editors (left to
> > right text only).
> > 
> > In all of the ones I'm using (other than emacs), clicking with the mouse
> > on a character moves the point either in front of, or after that
> > character,
> > depending on whether you clicked the left or right half of it.
> > 
> > In emacs, however, point seems to always be moved in front of the clicked
> > character, regardless of where on it you click. It would be great if
> > emacs could (optionally) also support the before/after behavior described
> > above.
> > 
> > After delving into the code, it seems that this would need changes in C.
> > I have attached a proof of concept patch that changes emacs' behavior,
> > but it lacks an option mechanism. I also am not familiar enough
> > with what unintended consequences this change may have.
> 
> Thanks, but the place where you suggest to make the change is not the
> correct one.  The function move_it_in_display_line_to is the workhorse
> of "display emulation", and is used by any code which needs to perform
> calculations related to display layout without producing anything on
> the glass.  It is fundamentally wrong to modify how all of that code
> finds the position corresponding to a certain X coordinate just
> because the user wants a mouse click to move point to the next
> character.
> 
> The right place is in buffer_posn_from_coords.  The change will be
> more complex there, but there's no way around this, since we want this
> change to affect only mouse clicks.

I am not surprised, given that I know little about Emacs internals at this 
time. Thank you for the explanation. After looking at it a bit more I'm not 
sure if/how it can be accomplished without any modifications to 
move_it_in_display_line_to, given that it uses/modifies the iterator in many 
places and afaict we don't have access to glyph width outside of it.

Would adding another option to move_it_in_display_line_to be acceptable? That 
way only functions that explicitly select the new halfway behavior, like I did 
with buffer_posn_from_coords in the new version of the poc patch.

So far it doesn't yet include an user-configurable option as I don't yet know 
how to do that in emacs' c source.

> 
> > I am looking for feedback of whether this feature in general is something
> > that would be acceptable to have in emacs and if there are any pitfalls
> > this change may cause that I need to be aware of.
> 
> I think this will be acceptable as optional behavior, yes.  But we
> need to consider all of its implications, such as what should happen
> when the use drags the mouse -- do we also want the drag to affect
> only the following character if the initial click is half-way across a
> character's glyph?

That's good to hear. With respect to mouse dragging: Specifically in the case 
that it's used to select text, yes, I would also like it to use the new 
halfway behavior in that case, but I have not yet found where in emacs' source 
code that change would need to happen.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.2.patch --]
[-- Type: text/x-patch, Size: 2015 bytes --]

diff --git a/src/dispextern.h b/src/dispextern.h
index ece128949f5..d5eceef2369 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2841,7 +2841,10 @@ #define PRODUCE_GLYPHS(IT)                              \
   MOVE_TO_VPOS = 0x04,
 
   /* Stop if specified buffer or string position is reached.  */
-  MOVE_TO_POS = 0x08
+  MOVE_TO_POS = 0x08,
+
+  /* If MOVE_TO_X, x-position is only reached by a glyph's first half. */
+  MOVE_TO_X_FIRSTHALF = 0x10
 };
 
 /***********************************************************************
diff --git a/src/dispnew.c b/src/dispnew.c
index 65d9cf9b4e1..e0d972c8be2 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -5610,7 +5610,7 @@ buffer_posn_from_coords (struct window *w, int *x, int *y, struct display_pos *p
   /* Now move horizontally in the row to the glyph under *X.  Second
      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);
+  move_it_in_display_line (&it, ZV, to_x, MOVE_TO_X | MOVE_TO_X_FIRSTHALF);
   bidi_unshelve_cache (itdata, 0);
 
   Fset_buffer (old_current_buffer);
diff --git a/src/xdisp.c b/src/xdisp.c
index 763af7d3bc8..d3fdfa0b583 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -9905,6 +9905,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT)			\
 	  /* More than one glyph or glyph doesn't fit on line.  All
 	     glyphs have the same width.  */
 	  int single_glyph_width = it->pixel_width / it->nglyphs;
+	  int single_glyph_halfwidth = ceil(single_glyph_width / 2.0);
 	  int new_x;
 	  int x_before_this_char = x;
 	  int hpos_before_this_char = it->hpos;
@@ -9914,7 +9915,7 @@ #define IT_RESET_X_ASCENT_DESCENT(IT)			\
 	      new_x = x + single_glyph_width;
 
 	      /* We want to leave anything reaching TO_X to the caller.  */
-	      if ((op & MOVE_TO_X) && new_x > to_x)
+	      if ((op & MOVE_TO_X) && ((op & MOVE_TO_X_FIRSTHALF)? (x + single_glyph_halfwidth) : new_x) > to_x)
 		{
 		  if (BUFFER_POS_REACHED_P ())
 		    {

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 12:40 ` Benjamin Riefenstahl
@ 2023-07-09 12:47   ` Moritz Maxeiner
  2023-07-09 13:37     ` Benjamin Riefenstahl
  2023-07-09 15:15   ` [External] : " Drew Adams
  1 sibling, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-09 12:47 UTC (permalink / raw)
  To: Benjamin Riefenstahl; +Cc: emacs-devel

On Sunday 9 July 2023 14:40:31 CEST Benjamin Riefenstahl wrote:
> Hi Moritz,
> 
> Moritz Maxeiner writes:
> > In all of the ones I'm using (other than emacs), clicking with the mouse
> > on a character moves the point either in front of, or after that
> > character,
> > depending on whether you clicked the left or right half of it.
> 
> Interesting, I never tested that before.  It explains why I am so often
> missing the first character when I try to copy text with the mouse.  IOW
> I personally find this an anti-feature.
> 
> benny

Hi Benny,

from your message I'm not sure whether you consider emacs' current behavior, 
or the one of other text editors to be the anti-feature?

I'm going to assume you mean that you prefer emacs' current behavior: I do not 
propose changing the current default, the patch I sent is merely to quickly 
allow people to see/test the behavior I would like to be able to optionally 
enable. So even if this were to be included in emacs, you wouldn't have to do 
anything to not have it.

Best,
Moritz





^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 12:44   ` Moritz Maxeiner
@ 2023-07-09 13:23     ` Eli Zaretskii
  2023-07-09 13:51       ` Moritz Maxeiner
  2023-07-09 13:58       ` Yuri Khan
  0 siblings, 2 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-09 13:23 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Sun, 09 Jul 2023 14:44:28 +0200
> 
> > The right place is in buffer_posn_from_coords.  The change will be
> > more complex there, but there's no way around this, since we want this
> > change to affect only mouse clicks.
> 
> I am not surprised, given that I know little about Emacs internals at this 
> time. Thank you for the explanation. After looking at it a bit more I'm not 
> sure if/how it can be accomplished without any modifications to 
> move_it_in_display_line_to, given that it uses/modifies the iterator in many 
> places and afaict we don't have access to glyph width outside of it.

That's not true.  buffer_posn_from_coords calls several functions of
the move_it_* family, including move_it_in_display_line_to itself, and
the information that your proposed patch accessed via it->pixel_width
is available to buffer_posn_from_coords through the 'struct it'
variable it passes to those move_it_* functions.  The only
complication is that you might need to call these functions more
times, to asses whether this or the next glyph are closer to the click
coordinates.

> Would adding another option to move_it_in_display_line_to be acceptable? That 
> way only functions that explicitly select the new halfway behavior, like I did 
> with buffer_posn_from_coords in the new version of the poc patch.

I don't see how this would work.  buffer_posn_from_coords calls
move_it_to and move_it_in_display_line, it doesn't call
move_it_in_display_line_to directly.  Are you suggesting to copy all 3
of those functions, and only change them to account for this minor
quirk?  That would be a terribly inelegant solution, since those
functions are quite large and complex.

> That's good to hear. With respect to mouse dragging: Specifically in the case 
> that it's used to select text, yes, I would also like it to use the new 
> halfway behavior in that case, but I have not yet found where in emacs' source 
> code that change would need to happen.

Dragging is handled by the same code: all we need is to know the
beginning and the end buffer position.  I was more asking about user
expectations: those could be different when clicking to move point and
when dragging.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 12:47   ` Moritz Maxeiner
@ 2023-07-09 13:37     ` Benjamin Riefenstahl
  0 siblings, 0 replies; 47+ messages in thread
From: Benjamin Riefenstahl @ 2023-07-09 13:37 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

Moritz Maxeiner writes:
> I'm going to assume you mean that you prefer emacs' current behavior:

Right.  I was just trying to give a vote for that, based on my
experience.

benny



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 13:23     ` Eli Zaretskii
@ 2023-07-09 13:51       ` Moritz Maxeiner
  2023-07-09 14:14         ` Eli Zaretskii
  2023-07-09 13:58       ` Yuri Khan
  1 sibling, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-09 13:51 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

On Sunday 9 July 2023 15:23:40 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Cc: emacs-devel@gnu.org
> > Date: Sun, 09 Jul 2023 14:44:28 +0200
> > 
> > > The right place is in buffer_posn_from_coords.  The change will be
> > > more complex there, but there's no way around this, since we want this
> > > change to affect only mouse clicks.
> > 
> > I am not surprised, given that I know little about Emacs internals at this
> > time. Thank you for the explanation. After looking at it a bit more I'm
> > not
> > sure if/how it can be accomplished without any modifications to
> > move_it_in_display_line_to, given that it uses/modifies the iterator in
> > many places and afaict we don't have access to glyph width outside of it.
> That's not true.  buffer_posn_from_coords calls several functions of
> the move_it_* family, including move_it_in_display_line_to itself, and
> the information that your proposed patch accessed via it->pixel_width
> is available to buffer_posn_from_coords through the 'struct it'
> variable it passes to those move_it_* functions.  The only
> complication is that you might need to call these functions more
> times, to asses whether this or the next glyph are closer to the click
> coordinates.

Ok, thanks for the corection. I might look into this, then.

> 
> > Would adding another option to move_it_in_display_line_to be acceptable?
> > That way only functions that explicitly select the new halfway behavior,
> > like I did with buffer_posn_from_coords in the new version of the poc
> > patch.
> 
> I don't see how this would work.  buffer_posn_from_coords calls
> move_it_to and move_it_in_display_line, it doesn't call
> move_it_in_display_line_to directly. 

It works because move_it_in_display_line forwards its op parameter to 
move_it_in_display_line_to. See the poc-0.2 patch I attached in my previous 
email.

> Are you suggesting to copy all 3
> of those functions, and only change them to account for this minor
> quirk?  That would be a terribly inelegant solution, since those
> functions are quite large and complex.

No, I just added a flag to move_operation_enum, which is passed by 
buffer_posn_from_coords to move_it_in_display_line in the op parameter, which 
already forwards it to move_it_in_display_line_to.

> 
> > That's good to hear. With respect to mouse dragging: Specifically in the
> > case that it's used to select text, yes, I would also like it to use the
> > new halfway behavior in that case, but I have not yet found where in
> > emacs' source code that change would need to happen.
> 
> Dragging is handled by the same code: all we need is to know the
> beginning and the end buffer position.  I was more asking about user
> expectations: those could be different when clicking to move point and
> when dragging.

Well, from my personal user expectation: If there is an option to toggle this 
halfway behavior on, I would expect it to also toggle it on for dragging, 
unless there's a second option explicitly for dragging. Personally, I think 
one option to toggle both would be good.





^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 13:23     ` Eli Zaretskii
  2023-07-09 13:51       ` Moritz Maxeiner
@ 2023-07-09 13:58       ` Yuri Khan
  1 sibling, 0 replies; 47+ messages in thread
From: Yuri Khan @ 2023-07-09 13:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Moritz Maxeiner, emacs-devel

On Sun, 9 Jul 2023 at 20:24, Eli Zaretskii <eliz@gnu.org> wrote:

> I was more asking about user
> expectations: those could be different when clicking to move point and
> when dragging.

In my head, it’s a matter of rounding pixel coordinates to integer
boundaries between characters. It feels natural to round to the
nearest boundary. That feeling does not change whether it is for the
purpose of insertion or region selection; in both cases we target the
boundary.

One case which feels different is moving point for the purpose of
overwriting (overwrite-mode). Ostensibly, in this case we target the
character, rather than the boundary between characters. Since
overwrite-mode overwrites the character after the point, this means
rounding towards the beginning of the buffer.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 13:51       ` Moritz Maxeiner
@ 2023-07-09 14:14         ` Eli Zaretskii
  2023-07-09 21:47           ` Moritz Maxeiner
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-09 14:14 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Sun, 09 Jul 2023 15:51:10 +0200
> 
> On Sunday 9 July 2023 15:23:40 CEST Eli Zaretskii wrote:
> > That's not true.  buffer_posn_from_coords calls several functions of
> > the move_it_* family, including move_it_in_display_line_to itself, and
> > the information that your proposed patch accessed via it->pixel_width
> > is available to buffer_posn_from_coords through the 'struct it'
> > variable it passes to those move_it_* functions.  The only
> > complication is that you might need to call these functions more
> > times, to asses whether this or the next glyph are closer to the click
> > coordinates.
> 
> Ok, thanks for the corection. I might look into this, then.

Basically, you need to examine it.current_x after the last call to
move_it_in_display_line returns, and if it is closer to
to_x+it.pixel_width than to to_x, call move_it_in_display_line again
to get to to_x+it.pixel_width.

> > > Would adding another option to move_it_in_display_line_to be acceptable?
> > > That way only functions that explicitly select the new halfway behavior,
> > > like I did with buffer_posn_from_coords in the new version of the poc
> > > patch.
> > 
> > I don't see how this would work.  buffer_posn_from_coords calls
> > move_it_to and move_it_in_display_line, it doesn't call
> > move_it_in_display_line_to directly. 
> 
> It works because move_it_in_display_line forwards its op parameter to 
> move_it_in_display_line_to. See the poc-0.2 patch I attached in my previous 
> email.

Oh, you mean another value for the move_operation_enum enumeration?
That's possible, but sounds too much, since all you need is another
call to move_it_in_display_line.

> > Dragging is handled by the same code: all we need is to know the
> > beginning and the end buffer position.  I was more asking about user
> > expectations: those could be different when clicking to move point and
> > when dragging.
> 
> Well, from my personal user expectation: If there is an option to toggle this 
> halfway behavior on, I would expect it to also toggle it on for dragging, 
> unless there's a second option explicitly for dragging. Personally, I think 
> one option to toggle both would be good.

Maybe.  We will need to hear more opinions, I guess.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-09 12:40 ` Benjamin Riefenstahl
  2023-07-09 12:47   ` Moritz Maxeiner
@ 2023-07-09 15:15   ` Drew Adams
  2023-07-09 15:33     ` Moritz Maxeiner
  2023-07-12 18:21     ` Benjamin Riefenstahl
  1 sibling, 2 replies; 47+ messages in thread
From: Drew Adams @ 2023-07-09 15:15 UTC (permalink / raw)
  To: Benjamin Riefenstahl, Moritz Maxeiner; +Cc: emacs-devel@gnu.org

> > In all of the ones I'm using (other than emacs), clicking with the mouse
> > on a character moves the point either in front of, or after that
> character,
> > depending on whether you clicked the left or right half of it.
> 
> Interesting, I never tested that before.  It explains why I am so often
> missing the first character when I try to copy text with the mouse.  IOW
> I personally find this an anti-feature.

I understand that the feature would be optional.
Still, I tend to agree with you (Benjamin).

I can imagine editing text with a very large font
(I use larger fonts as time goes by...), and in
that case I'd see better which half of a char I
was clicking.  IOW, that would allow me to take
advantage of such half-char clicking.

Nevertheless, I don't really see what the feature
adds.  You can already precisely click here or
there to place point or select whichever starting
(with (mouse-1) or ending (with mouse-3) char you
like.

It seems like all this would do is to halve the
distance between such click positions - in essence
_requiring_ even better visibility/sensing of the
positions.  And thus requiring even a closer zoom
of the text.  IOW, instead of having to feel/find
the start or end of a char you'd have to do that
for the start, the end, and the middle.

Sounds like multiplying things unnecessarily,
making poor Occam roll over in the grave.  What,
exactly, is the improvement or use case?  Could
someone please describe a scenario where this
would actually help someone more?



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-09 15:15   ` [External] : " Drew Adams
@ 2023-07-09 15:33     ` Moritz Maxeiner
  2023-07-09 16:06       ` Drew Adams
                         ` (2 more replies)
  2023-07-12 18:21     ` Benjamin Riefenstahl
  1 sibling, 3 replies; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-09 15:33 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel@gnu.org

On Sunday 9 July 2023 17:15:02 CEST you wrote:
> > > In all of the ones I'm using (other than emacs), clicking with the mouse
> > > on a character moves the point either in front of, or after that
> > 
> > character,
> > 
> > > depending on whether you clicked the left or right half of it.
> > 
> > Interesting, I never tested that before.  It explains why I am so often
> > missing the first character when I try to copy text with the mouse.  IOW
> > I personally find this an anti-feature.
> 
> I understand that the feature would be optional.
> Still, I tend to agree with you (Benjamin).
> 
> I can imagine editing text with a very large font
> (I use larger fonts as time goes by...), and in
> that case I'd see better which half of a char I
> was clicking.  IOW, that would allow me to take
> advantage of such half-char clicking.
> 
> Nevertheless, I don't really see what the feature
> adds.  You can already precisely click here or
> there to place point or select whichever starting
> (with (mouse-1) or ending (with mouse-3) char you
> like.

It allows people to not have to shift mental models when interacting with GUI 
Emacs vs. other GUI applications deadling with text.

> 
> It seems like all this would do is to halve the
> distance between such click positions - in essence
> _requiring_ even better visibility/sensing of the
> positions. 

Clicking the latter half of glyph n, as well as the first half of glyph n+1 
would result in the point being but between glyph n and n+1. The total length 
of the selection range remains the same, it is only shifted half a glyph to 
the left. I ask that you try my poc patch out before making such strong 
claims.

> And thus requiring even a closer zoom
> of the text.  IOW, instead of having to feel/find
> the start or end of a char you'd have to do that
> for the start, the end, and the middle.
> 
> Sounds like multiplying things unnecessarily,
> making poor Occam roll over in the grave.  What,
> exactly, is the improvement or use case?  Could
> someone please describe a scenario where this
> would actually help someone more?

The use case is described in my very first post, but I'll go into more detail: 
Every other GUI application dealing with text I'm using already works this 
way, including e.g. KMail (which I'm typing this email in). When using emacs, 
I have to switch my mental model from "normal GUI application" to "Emacs GUI" 
and still often misclick due to Emacs' behaving differently from other GUI 
applications.

That being said, if there's wide opposition of this being included in Emacs, 
I'll maintain it as a downstream patch as Emacs' current default behavior, to 
me, is unacceptable.





^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-09 15:33     ` Moritz Maxeiner
@ 2023-07-09 16:06       ` Drew Adams
  2023-07-09 16:21       ` Brian Cully via Emacs development discussions.
  2023-07-09 16:43       ` [External] : " Eli Zaretskii
  2 siblings, 0 replies; 47+ messages in thread
From: Drew Adams @ 2023-07-09 16:06 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel@gnu.org

> > > I personally find this an anti-feature.
> >
> > I understand that the feature would be optional.
> > Still, I tend to agree with you (Benjamin).
> >
> > I can imagine editing text with a very large font
> > (I use larger fonts as time goes by...), and in
> > that case I'd see better which half of a char I
> > was clicking.  IOW, that would allow me to take
> > advantage of such half-char clicking.
> >
> > Nevertheless, I don't really see what the feature
> > adds.  You can already precisely click here or
> > there to place point or select whichever starting
> > (with (mouse-1) or ending (with mouse-3) char you
> > like.
> 
> It allows people to not have to shift mental models when interacting with
> GUI Emacs vs. other GUI applications deadling with text.

Thanks for making that explicit.

So that's it?  Whether it's a useful feature
in its own right or not?

So this would be analogous to Emacs's optional
support for CUA, etc.  If optional, OK by me,
but I'd like to see the doc for it point this
out explicitly: that other than perhaps giving
you behavior you might be used to from outside
Emacs, this behavior provides no advantage.
And it introduces the disadvantage of making
you distinguish the click position even more
precisely (smaller click radius, to get the
given effect).

> > It seems like all this would do is to halve the
> > distance between such click positions - in essence
> > _requiring_ even better visibility/sensing of the
> > positions.
> 
> Clicking the latter half of glyph n, as well as the first half of glyph
> n+1 would result in the point being but between glyph n and n+1. The total
> length of the selection range remains the same, it is only shifted half a glyph
> to the left.

That description sounds like a (less-clear)
repeat of what I said.

> I ask that you try my poc patch out before
> making such strong claims.

I didn't make any claim.  I tried to imagine
the behavior, based on your description.

I don't build Emacs, so I won't be trying
your C patch.

> > And thus requiring even a closer zoom
> > of the text.  IOW, instead of having to feel/find
> > the start or end of a char you'd have to do that
> > for the start, the end, and the middle.
> >
> > Sounds like multiplying things unnecessarily,
> > making poor Occam roll over in the grave.  What,
> > exactly, is the improvement or use case?  Could
> > someone please describe a scenario where this
> > would actually help someone more?
> 
> The use case is described in my very first post,

No, I don't think so, if you intend the
use to be more than providing the behavior
you see outside Emacs: click left or right
of the center line of a char, rather than
clicking left or right of the start of a
char.

(It's true that that's the same zoom or
resolution requirement.  But I'd argue
that the start of a char may be generally
easier to discern than its midline.)

> but I'll go into more detail:
> Every other GUI application dealing with text I'm using already works this
> way, including e.g. KMail (which I'm typing this email in). When using
> emacs, I have to switch my mental model from "normal GUI application" to "Emacs
> GUI" and still often misclick due to Emacs' behaving differently from other GUI
> applications.

That repeats what you said in your first
mail: the aim is to provide the same
behavior you see outside Emacs.  Nothing
wrong with offering that option, IMO.

> That being said, if there's wide opposition of this being included in
> Emacs, I'll maintain it as a downstream patch as Emacs' current default behavior,
> to me, is unacceptable.

Please reread what I wrote.  I, for one,
didn't express any opposition to such an
optional feature being added.  But if the
only benefit is matching non-Emacs behavior
then let's please make that clear in the
doc.  IOW, if this is analogous to, say,
CUA support, then - just as we do for CUA
support - let's make that clear.

I'm guessing there will be others who also
appreciate having Emacs match outside
click behavior, in which case this is a
good thing.  To me, on its own, midline as
frontier is less desirable than char start
(or end), as it's less discernible.  But
matching outside behavior might be more
important for some users (such as you).

Thanks for making clear what this is about.
It gets my vote.  (I take your word that
the described behavior is a common one
outside Emacs.)



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-09 15:33     ` Moritz Maxeiner
  2023-07-09 16:06       ` Drew Adams
@ 2023-07-09 16:21       ` Brian Cully via Emacs development discussions.
  2023-07-09 18:01         ` Jens Schmidt
  2023-07-09 16:43       ` [External] : " Eli Zaretskii
  2 siblings, 1 reply; 47+ messages in thread
From: Brian Cully via Emacs development discussions. @ 2023-07-09 16:21 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Drew Adams, emacs-devel


Moritz Maxeiner <mm@ucw.sh> writes:

> That being said, if there's wide opposition of this being 
> included in Emacs, 
> I'll maintain it as a downstream patch as Emacs' current default 
> behavior, to 
> me, is unacceptable.

Until you'd posted this patch, I had no idea why I always seem to 
struggle when selecting text with the mouse in Emacs, to the point 
that I actively avoid using the mouse for it because I find Emacs' 
current behavior so unpredictable.

So, for me at least, I welcome this patch.

-bjc



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-09 15:33     ` Moritz Maxeiner
  2023-07-09 16:06       ` Drew Adams
  2023-07-09 16:21       ` Brian Cully via Emacs development discussions.
@ 2023-07-09 16:43       ` Eli Zaretskii
  2 siblings, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-09 16:43 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: drew.adams, emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> Date: Sun, 09 Jul 2023 17:33:25 +0200
> 
> That being said, if there's wide opposition of this being included in Emacs, 
> I'll maintain it as a downstream patch as Emacs' current default behavior, to 
> me, is unacceptable.

There's no such opposition.  Optional behavior that is so easy to
implement and doesn't affect anything except people who choose to turn
it on, cannot justify any serious opposition.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 16:21       ` Brian Cully via Emacs development discussions.
@ 2023-07-09 18:01         ` Jens Schmidt
  0 siblings, 0 replies; 47+ messages in thread
From: Jens Schmidt @ 2023-07-09 18:01 UTC (permalink / raw)
  To: Brian Cully, Moritz Maxeiner; +Cc: Drew Adams, emacs-devel

On 2023-07-09  18:21, Brian Cully wrote:

> Until you'd posted this patch, I had no idea why I always seem to 
> struggle when selecting text with the mouse in Emacs, to the point that 
> I actively avoid using the mouse for it because I find Emacs' current 
> behavior so unpredictable.

And that's another interesting problem with this patch or option: How
would a user struggling as you did even expect that this is something
she can configure in Emacs?

I remember at least one other voice here that expressed surprise about
the existence of different selection models, and I join that duet:
Coming from xterm and Emacs and other "legacy" software, I frequently
and (until now) inexplicably have been struggling with the selection of
the first character in the window of "modern" applications.

(To clarify: I join the choir of those surprised, not of those who are
in favor of the "modern" model.)



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 14:14         ` Eli Zaretskii
@ 2023-07-09 21:47           ` Moritz Maxeiner
  2023-07-10 12:46             ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-09 21:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3388 bytes --]

On Sunday, 9 July 2023 16:14:06 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Cc: emacs-devel@gnu.org
> > Date: Sun, 09 Jul 2023 15:51:10 +0200
> > 
> > On Sunday 9 July 2023 15:23:40 CEST Eli Zaretskii wrote:
> > > That's not true.  buffer_posn_from_coords calls several functions of
> > > the move_it_* family, including move_it_in_display_line_to itself, and
> > > the information that your proposed patch accessed via it->pixel_width
> > > is available to buffer_posn_from_coords through the 'struct it'
> > > variable it passes to those move_it_* functions.  The only
> > > complication is that you might need to call these functions more
> > > times, to asses whether this or the next glyph are closer to the click
> > > coordinates.
> > 
> > Ok, thanks for the corection. I might look into this, then.
> 
> Basically, you need to examine it.current_x after the last call to
> move_it_in_display_line returns, and if it is closer to
> to_x+it.pixel_width than to to_x, call move_it_in_display_line again
> to get to to_x+it.pixel_width.

Thanks, I've implemented something along those lines. Same source position,
but the check is if to_x exceeds half of the selected display element's width
and if so rerun move_it_in_display_line at it.current_x + it.pixel_width
(so first pixel of the next display element).
Running it at to_x+it.pixel_width might run into trouble if the current display
element is a lot wider than the one after it.

I've also added an option mouse_point_alternate (temporary name, didn't know
what else to call it, open to suggestions) to enable it. It defaults to off.

> 
> > > > Would adding another option to move_it_in_display_line_to be acceptable?
> > > > That way only functions that explicitly select the new halfway behavior,
> > > > like I did with buffer_posn_from_coords in the new version of the poc
> > > > patch.
> > > 
> > > I don't see how this would work.  buffer_posn_from_coords calls
> > > move_it_to and move_it_in_display_line, it doesn't call
> > > move_it_in_display_line_to directly. 
> > 
> > It works because move_it_in_display_line forwards its op parameter to 
> > move_it_in_display_line_to. See the poc-0.2 patch I attached in my previous 
> > email.
> 
> Oh, you mean another value for the move_operation_enum enumeration?
> That's possible, but sounds too much, since all you need is another
> call to move_it_in_display_line.

Well, it is certainly a less invasive change that way so I'm going with it for now.
But I have to say it feels wasteful to call the function twice instead of having
it deal with it "correctly" the first time around with an option.

> 
> > > Dragging is handled by the same code: all we need is to know the
> > > beginning and the end buffer position.  I was more asking about user
> > > expectations: those could be different when clicking to move point and
> > > when dragging.
> > 
> > Well, from my personal user expectation: If there is an option to toggle this 
> > halfway behavior on, I would expect it to also toggle it on for dragging, 
> > unless there's a second option explicitly for dragging. Personally, I think 
> > one option to toggle both would be good.
> 
> Maybe.  We will need to hear more opinions, I guess.
> 

Sure, until then next up for me is figuring out where I'll need to make
mouse dragging behave in line with the "mouse-alternate-point" mode.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.3.patch --]
[-- Type: text/x-patch, Size: 1739 bytes --]

diff --git a/src/dispnew.c b/src/dispnew.c
index 65d9cf9b4e1..bd288286924 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -22,6 +22,7 @@ Copyright (C) 1985-1988, 1993-1995, 1997-2023 Free Software Foundation,
 
 #include "sysstdio.h"
 #include <stdlib.h>
+#include <math.h>
 #include <unistd.h>
 
 #include "lisp.h"
@@ -5611,6 +5612,9 @@ 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_point_alternate && to_x > it.current_x + ceil (it.pixel_width / 2.0))
+    move_it_in_display_line (&it, ZV, it.current_x + it.pixel_width, MOVE_TO_X);
+
   bidi_unshelve_cache (itdata, 0);
 
   Fset_buffer (old_current_buffer);
@@ -6468,6 +6472,7 @@ init_display_interactive (void)
 
   inverse_video = 0;
   cursor_in_echo_area = false;
+  mouse_point_alternate = false;
 
   /* Now is the time to initialize this; it's used by init_sys_modes
      during startup.  */
@@ -6788,6 +6793,11 @@ syms_of_display (void)
   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-point-alternate", mouse_point_alternate,
+	       doc: /* Non-nil means use alternate mode for mouse click selection of point.
+In alternate mode, if the clicked x coordinate exceeds half of the selected
+display element's width, put point after it.  */);
+
   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.

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-09 21:47           ` Moritz Maxeiner
@ 2023-07-10 12:46             ` Eli Zaretskii
  2023-07-10 14:43               ` [External] : " Drew Adams
  2023-07-10 20:02               ` Moritz Maxeiner
  0 siblings, 2 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-10 12:46 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Sun, 09 Jul 2023 23:47:51 +0200
> 
> > Basically, you need to examine it.current_x after the last call to
> > move_it_in_display_line returns, and if it is closer to
> > to_x+it.pixel_width than to to_x, call move_it_in_display_line again
> > to get to to_x+it.pixel_width.
> 
> Thanks, I've implemented something along those lines. Same source position,
> but the check is if to_x exceeds half of the selected display element's width
> and if so rerun move_it_in_display_line at it.current_x + it.pixel_width
> (so first pixel of the next display element).
> Running it at to_x+it.pixel_width might run into trouble if the current display
> element is a lot wider than the one after it.

OK, but would you please rewrite the condition to avoid unnecessary
floating-point computations?  There's no need to compute half of
pixel_width, only to see if to_x is closer to the next display element
than it is to the current display element.

> I've also added an option mouse_point_alternate (temporary name, didn't know
> what else to call it, open to suggestions) to enable it. It defaults to off.

I can suggest mouse-click-prefer-closest-char.

> But I have to say it feels wasteful to call the function twice instead of having
> it deal with it "correctly" the first time around with an option.

That's because you aren't accustomed with this kind of code.  We do
this all the time, and there's nothing wasteful about it.

>  #include "sysstdio.h"
>  #include <stdlib.h>
> +#include <math.h>
>  #include <unistd.h>

This will be unnecessary once you get rid of the FP calculations.

>    move_it_in_display_line (&it, ZV, to_x, MOVE_TO_X);
> +  if (mouse_point_alternate && to_x > it.current_x + ceil (it.pixel_width / 2.0))
> +    move_it_in_display_line (&it, ZV, it.current_x + it.pixel_width, MOVE_TO_X);

These two lines are too long, please break them in two.

> @@ -6468,6 +6472,7 @@ init_display_interactive (void)
>  
>    inverse_video = 0;
>    cursor_in_echo_area = false;
> +  mouse_point_alternate = false;

This initialization should be immediately after the DEFVAR.

> +  DEFVAR_BOOL ("mouse-point-alternate", mouse_point_alternate,
> +	       doc: /* Non-nil means use alternate mode for mouse click selection of point.

The first line of the doc string will be more useful if it says
something about the effect of the option.  Something like this,
perhaps:

  Non-nil means mouse click prefers the closest glyph.

> +In alternate mode, if the clicked x coordinate exceeds half of the selected
> +display element's width, put point after it.  */);

This describes the effect in terms of the implementation more than in
terms of UX.  How about

  When this is non-nil, clicking inside a glyph picks up the next
  glyph if the click is closer to it than half the width of the
  clicked glyph.

This variable should be added to cus-start.el, with a suitable
customization form, since this is a user option.  It should also be
called out in etc/NEWS.

Thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* RE: [External] : Re: Moving point after character when clicking latter half of it
  2023-07-10 12:46             ` Eli Zaretskii
@ 2023-07-10 14:43               ` Drew Adams
  2023-07-10 20:02               ` Moritz Maxeiner
  1 sibling, 0 replies; 47+ messages in thread
From: Drew Adams @ 2023-07-10 14:43 UTC (permalink / raw)
  To: Eli Zaretskii, Moritz Maxeiner; +Cc: emacs-devel@gnu.org

Wrt the doc: Is it about "mouse click" or
"mouse press"?

I'm guessing it applies to any mouse button,
and it's about the "down" mouse event for a
button.

IOW, I'm guessing it applies to actions such
as pressing mouse-1 and dragging to another
position, as well as to actions such as
pressing mouse-3 (e.g. to extend the region
or to bring up a context menu or...).




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-10 12:46             ` Eli Zaretskii
  2023-07-10 14:43               ` [External] : " Drew Adams
@ 2023-07-10 20:02               ` Moritz Maxeiner
  2023-07-11 12:29                 ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-10 20:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1406 bytes --]

Thank you for your suggestions (I've not quoted them in this reply for 
brevity). Unless I've overlooked something I've implemented them all, except 
for the etc/NEWS entry.

On Monday 10 July 2023 14:46:39 CEST Eli Zaretskii wrote:
> It should also be called out in etc/NEWS.

I agree, but I feel this should be done in the last iteration of the patch, 
once all other changes are done. Which leads me to the next point:

I had to add another piece of code to src/xterm.c, because while text 
selection via mouse dragging did automatically factor in the new optional 
behavior after releasing the mouse, it did not update the highlighted / 
selected region, as that requires mouse-movement events to be triggered, which 
are picked up in mouse.el via mouse-drag-track, which then updated the 
highlighted region. That event, however, is only triggered by leaving the 
previous glyph, so we need to trigger it while still being on the glyph.

I tried sending the event only when crossing the vertical midline of the 
glyph, but for a reason unknown to me, sending the event only once did not 
result in the highlight being updated when dragging the mouse to the right, 
only to the left.

As a workaround, I now trigger the event always while dragging with the 
optional behavior on. If there is a more elegant solution I don't see I'd 
welcome it. For now the overhead doesn't seem noticeable in practice.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.4.patch --]
[-- Type: text/x-patch, Size: 3071 bytes --]

diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 054683d7cf6..489471f8eab 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -231,6 +231,7 @@ minibuffer-prompt-properties--setter
 	     (inverse-video display boolean)
 	     (visible-bell display boolean)
 	     (no-redraw-on-reenter display boolean)
+	     (mouse-click-prefer-closest-char display boolean)
 
              ;; doc.c
              (text-quoting-style display
diff --git a/src/dispnew.c b/src/dispnew.c
index 65d9cf9b4e1..5fcecd5811d 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_click_prefer_closest_char)
+    {
+      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,12 @@ syms_of_display (void)
   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-click-prefer-closest-char", mouse_click_prefer_closest_char,
+	       doc: /* Non-nil means mouse click prefers the closest glyph as point.
+When this is non-nil, clicking inside a glyph picks up the next glyph if the click
+is closer to it then half the width of the clicked glyph.  */);
+  mouse_click_prefer_closest_char = 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..44dcc8b1761 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -14206,11 +14206,13 @@ x_note_mouse_movement (struct frame *frame, const XMotionEvent *event,
     }
 
 
-  /* Has the mouse moved off the glyph it was on at the last sighting?  */
+  /* Has the mouse moved off the glyph it was on at the last sighting?
+     Is the mouse being dragged while we need to keep point to the nearest glyph? */
   r = &dpyinfo->last_mouse_glyph;
   if (frame != dpyinfo->last_mouse_glyph_frame
       || event->x < r->x || event->x >= r->x + r->width
-      || event->y < r->y || event->y >= r->y + r->height)
+      || event->y < r->y || event->y >= r->y + r->height
+      || mouse_click_prefer_closest_char && EQ (track_mouse, Qdrag_tracking))
     {
       frame->mouse_moved = true;
       frame->last_mouse_device = device;
@@ -31705,4 +31707,6 @@ syms_of_xterm (void)
 If that is still too slow, setting this variable to the symbol
 `really-fast' will make Emacs return only cached values.  */);
   Vx_use_fast_mouse_position = Qnil;
+
+  DEFSYM (Qdrag_tracking, "drag-tracking");
 }

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-10 20:02               ` Moritz Maxeiner
@ 2023-07-11 12:29                 ` Eli Zaretskii
  2023-07-11 13:10                   ` Po Lu
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-11 12:29 UTC (permalink / raw)
  To: Moritz Maxeiner, Po Lu; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Mon, 10 Jul 2023 22:02:23 +0200
> 
> On Monday 10 July 2023 14:46:39 CEST Eli Zaretskii wrote:
> > It should also be called out in etc/NEWS.
> 
> I agree, but I feel this should be done in the last iteration of the patch, 
> once all other changes are done.

We are basically there.

> I had to add another piece of code to src/xterm.c, because while text 
> selection via mouse dragging did automatically factor in the new optional 
> behavior after releasing the mouse, it did not update the highlighted / 
> selected region, as that requires mouse-movement events to be triggered, which 
> are picked up in mouse.el via mouse-drag-track, which then updated the 
> highlighted region. That event, however, is only triggered by leaving the 
> previous glyph, so we need to trigger it while still being on the glyph.
> 
> I tried sending the event only when crossing the vertical midline of the 
> glyph, but for a reason unknown to me, sending the event only once did not 
> result in the highlight being updated when dragging the mouse to the right, 
> only to the left.
> 
> As a workaround, I now trigger the event always while dragging with the 
> optional behavior on. If there is a more elegant solution I don't see I'd 
> welcome it. For now the overhead doesn't seem noticeable in practice.

I'm not sure this is TRT.  In particular, it sounds like the change
you made in xterm.c also overrides the Y coordinate condition? that
doesn't sound right to me.  Po Lu, WDYT about this?

The other changes LGTM, thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-11 12:29                 ` Eli Zaretskii
@ 2023-07-11 13:10                   ` Po Lu
  2023-07-11 18:01                     ` Moritz Maxeiner
  0 siblings, 1 reply; 47+ messages in thread
From: Po Lu @ 2023-07-11 13:10 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Moritz Maxeiner, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> I'm not sure this is TRT.  In particular, it sounds like the change
> you made in xterm.c also overrides the Y coordinate condition? that
> doesn't sound right to me.  Po Lu, WDYT about this?
>
> The other changes LGTM, thanks.

This part of the patch

>    if (frame != dpyinfo->last_mouse_glyph_frame
>        || event->x < r->x || event->x >= r->x + r->width
> -      || event->y < r->y || event->y >= r->y + r->height)
> +      || event->y < r->y || event->y >= r->y + r->height
> +      || mouse_click_prefer_closest_char && EQ (track_mouse, Qdrag_tracking))

appears to special case a value of `track_mouse', and unconditionally
report mouse movement upon such a value being set, without considering
if the mouse pointer has moved to a position within the glyph that could
lead to a new position being reported.  This is not only wrong (since
Emacs shouldn't report mouse events differently even if `track_mouse' is
some other non-nil value), but is also inefficient, as setting
mouse_moved unnecessarily will result in an excessive number of mouse
motion events being reported.

I don't think we should disable the optimizations here entirely;
instead, it should be just as effective to save only the half of the
glyph containing the mouse pointer inside `remember_mouse_glyph' when
`mouse_click_prefer_closest_char' is true.

> +  DEFVAR_BOOL ("mouse-click-prefer-closest-char", mouse_click_prefer_closest_char,
> +	       doc: /* Non-nil means mouse click prefers the closest glyph as point.
> +When this is non-nil, clicking inside a glyph picks up the next glyph if the click
> +is closer to it then half the width of the clicked glyph.  */);
> +  mouse_click_prefer_closest_char = false;

Since this affects much more than just mouse clicks, shouldn't the
variable be named something else?  How about naming the variable
`mouse-prefer-closest-glyph', and using the following doc string
instead:

  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.

Also, shouldn't the Lisp reference manual mention this variable?  In
(elisp)Accessing Mouse, for example.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-11 13:10                   ` Po Lu
@ 2023-07-11 18:01                     ` Moritz Maxeiner
  2023-07-12  0:52                       ` Po Lu
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-11 18:01 UTC (permalink / raw)
  To: Eli Zaretskii, Po Lu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 3525 bytes --]

On Tuesday 11 July 2023 15:10:24 CEST Po Lu wrote:
> Eli Zaretskii <eliz@gnu.org> writes:
> > I'm not sure this is TRT.  In particular, it sounds like the change
> > you made in xterm.c also overrides the Y coordinate condition? that
> > doesn't sound right to me.  Po Lu, WDYT about this?
> > 
> > The other changes LGTM, thanks.
> 
> This part of the patch
> 
> >    if (frame != dpyinfo->last_mouse_glyph_frame
> >    
> >        || event->x < r->x || event->x >= r->x + r->width
> > 
> > -      || event->y < r->y || event->y >= r->y + r->height)
> > +      || event->y < r->y || event->y >= r->y + r->height
> > +      || mouse_click_prefer_closest_char && EQ (track_mouse,
> > Qdrag_tracking))
> appears to special case a value of `track_mouse', and unconditionally
> report mouse movement upon such a value being set, without considering
> if the mouse pointer has moved to a position within the glyph that could
> lead to a new position being reported.

True, though it is still conditional on the optional feature being enabled 
(both mouse_click_prefer_closest_char and drag_tracking, which mouse.el sets, 
need to be true). That being said I tried before to have this only be reported 
when the mouse crosses halfway point (without modifying the glyph itself) but 
that didn't really work.

> This is not only wrong (since
> Emacs shouldn't report mouse events differently even if `track_mouse' is
> some other non-nil value), but is also inefficient, as setting
> mouse_moved unnecessarily will result in an excessive number of mouse
> motion events being reported.

I'm not clear on why that would make it wrong (as in incorrect semantics). 
It's definitely inefficient (though I've not noticed the overhead in practice), 
which is why I asked if there's a more elegant solution.

> 
> I don't think we should disable the optimizations here entirely;
> instead, it should be just as effective to save only the half of the
> glyph containing the mouse pointer inside `remember_mouse_glyph' when
> `mouse_click_prefer_closest_char' is true.

Which this is, thank you very much for pointing that out. I've changed that 
part of the patch accordingly, though this does unfortunately mean that a new 
function is required, due to multiple places setting the glyph rectangle as it 
relates to dragging.


> 
> > +  DEFVAR_BOOL ("mouse-click-prefer-closest-char",
> > mouse_click_prefer_closest_char, +	       doc: /* Non-nil means mouse
> > click prefers the closest glyph as point. +When this is non-nil, clicking
> > inside a glyph picks up the next glyph if the click +is closer to it then
> > half the width of the clicked glyph.  */);
> > +  mouse_click_prefer_closest_char = false;
> 
> Since this affects much more than just mouse clicks, shouldn't the
> variable be named something else?  How about naming the variable
> `mouse-prefer-closest-glyph', and using the following doc string
> instead:
> 
>   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.

I've included those changes.

> 
> Also, shouldn't the Lisp reference manual mention this variable?  In
> (elisp)Accessing Mouse, for example.

Assuming this version of the implementation meets muster I will work on the 
etc/NEWS entry and can look into adding something to (elisp)Accessing Mouse, 
as well.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.5.patch --]
[-- Type: text/x-patch, Size: 3956 bytes --]

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;

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-11 18:01                     ` Moritz Maxeiner
@ 2023-07-12  0:52                       ` Po Lu
  2023-07-12 19:58                         ` Moritz Maxeiner
  0 siblings, 1 reply; 47+ messages in thread
From: Po Lu @ 2023-07-12  0:52 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Eli Zaretskii, emacs-devel

Moritz Maxeiner <mm@ucw.sh> writes:

> I'm not clear on why that would make it wrong (as in incorrect semantics). 
> It's definitely inefficient (though I've not noticed the overhead in practice), 
> which is why I asked if there's a more elegant solution.

The overhead is apparent when options such as
`mouse-drag-and-drop-region' are enabled and the connection to the X
server is slow.

> Which this is, thank you very much for pointing that out. I've changed that 
> part of the patch accordingly, though this does unfortunately mean that a new 
> function is required, due to multiple places setting the glyph rectangle as it 
> relates to dragging.

I find that difficult to believe.  Would you please describe the other
callers of `remember_mouse_glyph' that make adjustments there
impossible?

I asked you to make the change in `remember_mouse_glyph' because that
would avoid the need to modify each of the *term.[cm] files
individually.  Replacing it with a different function would miss the
point of the change.

> Assuming this version of the implementation meets muster I will work
> on the etc/NEWS entry and can look into adding something to
> (elisp)Accessing Mouse, as well.

Several other comments below:

> +/* 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;
> +}

Please follow the GNU coding standards for both function declarators and
comments, by capitalizing (not quoting) arguments which appear in the
commentary, and placing a space between the identifier name and the
opening parentheses of the parameter type list.  Also, use the active
voice when describing the behavior of a function within its commentary:

/* Replace *GLYPH, a rectangle containing the bounds of a glyph, with
   the half of the rectangle containing the position X.  */

static void
x_vertical_bisect_glyph (XRectangle *glyph, int x)
{
  /* ... */
}

In addition, we don't use Markdown style quotes for code.  When quoting
identifier names in the future, either write:

  /* `foo' is used to perform ...  */

or

  /* 'foo' is used to perform ...  */

>  /* 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);

Please place a space between the identifier name and the opening brace
of each function call.

However, implementing this feature shouldn't need changes to xterm.c at
all.  Please make the change in `remember_mouse_glyph', not in window
system specific code.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: : Re: Moving point after character when clicking latter half of it
  2023-07-09 15:15   ` [External] : " Drew Adams
  2023-07-09 15:33     ` Moritz Maxeiner
@ 2023-07-12 18:21     ` Benjamin Riefenstahl
  2023-07-12 18:32       ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: Benjamin Riefenstahl @ 2023-07-12 18:21 UTC (permalink / raw)
  To: Drew Adams; +Cc: Moritz Maxeiner, emacs-devel@gnu.org

Hi all,

benny writes:
>> Interesting, I never tested that before.  It explains why I am so
>> often missing the first character when I try to copy text with the
>> mouse.  IOW I personally find this an anti-feature.

Drew Adams writes:
> I can imagine editing text with a very large font
> (I use larger fonts as time goes by...),

I think, displays have higher resolutions than they used to, so smaller
fonts become more readable, which means more use of smaller fonts.  I
guess I'm clumsy, but I often have a hard time hitting the right
character at all, now it seems I am expected to hit the correct half of
the character?  And no, aiming at the previous character or "between
them" is not intuitive for me, I want the character I see before me, I
click on that one.  Also often there is no character before the one I am
aiming at.  Of course things get even worse with touchpads or touch
screens like on the phone.

There seems to be a tension, like Eli alluded to, between placing the
cursor, where this behaviour may sound useful, and starting to mark a
selection, where it is problematic for me.  These two should in theory
behave the same (because every drag starts as a downclick), but as
explained I find the usability doubtful.  Add to that that it is usually
simple to correct the cursor position with the keyboard, but that does
not go for correcting the selection.  Or maybe I just do not know how.

I am not opposed to people to have the option of course.  Just wondering
why.

benny



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: : Re: Moving point after character when clicking latter half of it
  2023-07-12 18:21     ` Benjamin Riefenstahl
@ 2023-07-12 18:32       ` Eli Zaretskii
  0 siblings, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-12 18:32 UTC (permalink / raw)
  To: Benjamin Riefenstahl; +Cc: drew.adams, mm, emacs-devel

> From: Benjamin Riefenstahl <b.riefenstahl@turtle-trading.net>
> Cc: Moritz Maxeiner <mm@ucw.sh>,  "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> Date: Wed, 12 Jul 2023 20:21:35 +0200
> 
> I am not opposed to people to have the option of course.  Just wondering
> why.

They explained it: they are used to it from other programs.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12  0:52                       ` Po Lu
@ 2023-07-12 19:58                         ` Moritz Maxeiner
  2023-07-12 21:17                           ` Yuan Fu
                                             ` (2 more replies)
  0 siblings, 3 replies; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-12 19:58 UTC (permalink / raw)
  To: Po Lu, Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 5480 bytes --]

On Wednesday 12 July 2023 02:52:01 CEST Po Lu wrote:
> Moritz Maxeiner <mm@ucw.sh> writes:
> > I'm not clear on why that would make it wrong (as in incorrect semantics).
> > It's definitely inefficient (though I've not noticed the overhead in
> > practice), which is why I asked if there's a more elegant solution.
> 
> The overhead is apparent when options such as
> `mouse-drag-and-drop-region' are enabled and the connection to the X
> server is slow.
> 
> > Which this is, thank you very much for pointing that out. I've changed
> > that
> > part of the patch accordingly, though this does unfortunately mean that a
> > new function is required, due to multiple places setting the glyph
> > rectangle as it relates to dragging.
> 
> I find that difficult to believe.  Would you please describe the other
> callers of `remember_mouse_glyph' that make adjustments there
> impossible?
> 
> I asked you to make the change in `remember_mouse_glyph' because that
> would avoid the need to modify each of the *term.[cm] files
> individually.  Replacing it with a different function would miss the
> point of the change.

My apologies, after rereading your previous message I realize I misunderstood. 
I thought I was to put the changes after the remember_mouse_glyph call (like I 
was previously asked to do for move_it_in_display_line instead of modifying 
another xdisp.c function, move_it_in_display_line_to). My comment derived from 
that misunderstanding as there are multiple calls to remember_mouse_glyph that 
need to be affected.

I have adjusted the patch as requested (I think), added some documentation in 
commands.texi, as well as a NEWS entry. I'm not sure about correct placement / 
formatting of the latter two.

Btw. I'm not particularly happy about needed to add the `original_gx' 
variable, but since the function seems to overwrite its argument, which I need 
access to at its end (once the full glyph has been determined), I don't see 
another option. I'm also not super happy about the needed division, but I also 
don't see a way around that. If you know a more elegant solution I'd be happy 
to hear it.

> 
> > Assuming this version of the implementation meets muster I will work
> > on the etc/NEWS entry and can look into adding something to
> > (elisp)Accessing Mouse, as well.
> 
> Several other comments below:
> > +/* 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;
> > +}
> 
> Please follow the GNU coding standards for both function declarators and
> comments, by capitalizing (not quoting) arguments which appear in the
> commentary, and placing a space between the identifier name and the
> opening parentheses of the parameter type list.  Also, use the active
> voice when describing the behavior of a function within its commentary:
> 
> /* Replace *GLYPH, a rectangle containing the bounds of a glyph, with
>    the half of the rectangle containing the position X.  */
> 
> static void
> x_vertical_bisect_glyph (XRectangle *glyph, int x)
> {
>   /* ... */
> }
> 
> In addition, we don't use Markdown style quotes for code.  When quoting
> identifier names in the future, either write:
> 
>   /* `foo' is used to perform ...  */
> 
> or
> 
>   /* 'foo' is used to perform ...  */
> 
> >  /* 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);
> 
> Please place a space between the identifier name and the opening brace
> of each function call.
> 
> However, implementing this feature shouldn't need changes to xterm.c at
> all.  Please make the change in `remember_mouse_glyph', not in window
> system specific code.

Since that function (and calls to it) are now merged into 
`remember_mouse_glyph', I think these are solved by default. I'll take more 
care next time, though, thank you for the correction.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.6.patch --]
[-- Type: text/x-patch, Size: 6061 bytes --]

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index cd1745614eb..274c456d8c3 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -1969,6 +1969,8 @@ events do not appear.  @xref{Mouse Tracking}.
 When non-@code{nil}, mouse motion events are generated even for very
 small movements.  Otherwise, motion events are not generated as long
 as the mouse cursor remains pointing to the same glyph in the text.
+Note that non-@code{nil} @code{mouse-prefer-closest-glyph} changes
+that to the left/right half of the glyph under the mouse cursor instead.
 @end defvar
 
 @node Touchscreen Events
@@ -2751,6 +2753,14 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
 to the entire window area including scroll bars, margins and fringes.
 @end defun
 
+@defvar mouse-prefer-closest-glyph
+If you set this variable to non-@code{nil}, whenever you click or drag the mouse,
+instead of the point being always set in front of the clicked glyph, the point
+horizontally closest to the mouse position will be used.
+So if you click in the left half of a glyph, point is set in front of it,
+but if you click in the right half, point is set after it.
+@end defvar
+
 @node Accessing Scroll
 @subsection Accessing Scroll Bar Events
 @cindex scroll bar events, data in
diff --git a/etc/NEWS b/etc/NEWS
index 9e6f0c16bcd..978ba0dfa69 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -952,6 +952,14 @@ wheel reports.  Unlike 'pixel-scroll-mode', this mode scrolls the
 display pixel-by-pixel, as opposed to only animating line-by-line
 scrolls.
 
++++
+** New user option 'mouse-prefer-closest-glyph'.
+When enabled, clicking or dragging with the mouse will put the point
+in front of the glyph with the closest x coordinate to the mouse pointer.
+In other words, if the mouse pointer is in the right half of a glyph,
+point will be put after that glyph, while if the mouse pointer is in the
+left half of a glyph, point will be put in front of that glyph.
+
 ** Terminal Emacs
 
 ---
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/xdisp.c b/src/xdisp.c
index 763af7d3bc8..4ab53d47f0c 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2723,6 +2723,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   enum window_part part;
   enum glyph_row_area area;
   int x, y, width, height;
+  int original_gx;
 
   if (mouse_fine_grained_tracking)
     {
@@ -2733,6 +2734,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
+  original_gx = gx;
+
   if (window_resize_pixelwise)
     {
       width = height = 1;
@@ -2950,6 +2953,16 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
  store_rect:
   STORE_NATIVE_RECT (*rect, gx, gy, width, height);
 
+  if (mouse_prefer_closest_glyph)
+    {
+      int half_width = rect->width / 2;
+      rect->width = half_width;
+
+      int bisection = rect->x + half_width;
+      if (original_gx > bisection)
+        rect->x = bisection;
+    }
+
   /* Visible feedback for debugging.  */
 #if false && defined HAVE_X_WINDOWS
   XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
@@ -37345,7 +37358,10 @@ may be more familiar to users.  */);
   DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
     doc: /* Non-nil for pixel-wise mouse-movement.
 When nil, mouse-movement events will not be generated as long as the
-mouse stays within the extent of a single glyph (except for images).  */);
+mouse stays within the extent of a single glyph (except for images).
+When nil and mouse-prefer-closest-glyph is non-nil, mouse-movement
+events will instead not be generated as long as the mouse stays within
+the extent of a single left/right half glyph (except for images).  */);
   mouse_fine_grained_tracking = false;
 
   DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 19:58                         ` Moritz Maxeiner
@ 2023-07-12 21:17                           ` Yuan Fu
  2023-07-12 21:36                             ` Moritz Maxeiner
  2023-07-13  5:27                             ` Eli Zaretskii
  2023-07-13  0:31                           ` Po Lu
  2023-07-13  8:47                           ` Eli Zaretskii
  2 siblings, 2 replies; 47+ messages in thread
From: Yuan Fu @ 2023-07-12 21:17 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Po Lu, Eli Zaretskii, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 6020 bytes --]



> On Jul 12, 2023, at 12:58 PM, Moritz Maxeiner <mm@ucw.sh> wrote:
> 
> On Wednesday 12 July 2023 02:52:01 CEST Po Lu wrote:
>> Moritz Maxeiner <mm@ucw.sh> writes:
>>> I'm not clear on why that would make it wrong (as in incorrect semantics).
>>> It's definitely inefficient (though I've not noticed the overhead in
>>> practice), which is why I asked if there's a more elegant solution.
>> 
>> The overhead is apparent when options such as
>> `mouse-drag-and-drop-region' are enabled and the connection to the X
>> server is slow.
>> 
>>> Which this is, thank you very much for pointing that out. I've changed
>>> that
>>> part of the patch accordingly, though this does unfortunately mean that a
>>> new function is required, due to multiple places setting the glyph
>>> rectangle as it relates to dragging.
>> 
>> I find that difficult to believe.  Would you please describe the other
>> callers of `remember_mouse_glyph' that make adjustments there
>> impossible?
>> 
>> I asked you to make the change in `remember_mouse_glyph' because that
>> would avoid the need to modify each of the *term.[cm] files
>> individually.  Replacing it with a different function would miss the
>> point of the change.
> 
> My apologies, after rereading your previous message I realize I misunderstood. 
> I thought I was to put the changes after the remember_mouse_glyph call (like I 
> was previously asked to do for move_it_in_display_line instead of modifying 
> another xdisp.c function, move_it_in_display_line_to). My comment derived from 
> that misunderstanding as there are multiple calls to remember_mouse_glyph that 
> need to be affected.
> 
> I have adjusted the patch as requested (I think), added some documentation in 
> commands.texi, as well as a NEWS entry. I'm not sure about correct placement / 
> formatting of the latter two.
> 
> Btw. I'm not particularly happy about needed to add the `original_gx' 
> variable, but since the function seems to overwrite its argument, which I need 
> access to at its end (once the full glyph has been determined), I don't see 
> another option. I'm also not super happy about the needed division, but I also 
> don't see a way around that. If you know a more elegant solution I'd be happy 
> to hear it.
> 
>> 
>>> Assuming this version of the implementation meets muster I will work
>>> on the etc/NEWS entry and can look into adding something to
>>> (elisp)Accessing Mouse, as well.
>> 
>> Several other comments below:
>>> +/* 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;
>>> +}
>> 
>> Please follow the GNU coding standards for both function declarators and
>> comments, by capitalizing (not quoting) arguments which appear in the
>> commentary, and placing a space between the identifier name and the
>> opening parentheses of the parameter type list.  Also, use the active
>> voice when describing the behavior of a function within its commentary:
>> 
>> /* Replace *GLYPH, a rectangle containing the bounds of a glyph, with
>>   the half of the rectangle containing the position X.  */
>> 
>> static void
>> x_vertical_bisect_glyph (XRectangle *glyph, int x)
>> {
>>  /* ... */
>> }
>> 
>> In addition, we don't use Markdown style quotes for code.  When quoting
>> identifier names in the future, either write:
>> 
>>  /* `foo' is used to perform ...  */
>> 
>> or
>> 
>>  /* 'foo' is used to perform ...  */
>> 
>>> /* 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);
>> 
>> Please place a space between the identifier name and the opening brace
>> of each function call.
>> 
>> However, implementing this feature shouldn't need changes to xterm.c at
>> all.  Please make the change in `remember_mouse_glyph', not in window
>> system specific code.
> 
> Since that function (and calls to it) are now merged into 
> `remember_mouse_glyph', I think these are solved by default. I'll take more 
> care next time, though, thank you for the correction.<emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.6.patch>

Sorry for joining late into the discussion. But I wonder if a Elisp solution would suffice? Someone had requested this feature to me in the past and this is my solution at the time.

Yuan


[-- Attachment #2: delicate-click.el --]
[-- Type: application/octet-stream, Size: 1792 bytes --]

;;; delicate-click.el --- Delicate click position      -*- lexical-binding: t; -*-

;; Author: Yuan Fu <casouri@gmail.com>

;;; This file is NOT part of GNU Emacs

;;; Commentary:
;;
;; If you set ‘cursor-type’ to bar and clicks on the right side of a
;; character, you would expect the point to be set after that
;; character. Normally that’s not the case, this package provides
;; ‘delicate-click-mode’ that makes Emacs to do the right thing.
;;
;; To use:
;;     M-x delicate-click-mode RET

;;; Code:
;;

(defun adjust-point-after-click (event &optional _)
  "Adjust point.
Adjust point depending on which portion of the character the
cursor clicked on, if on the right half, move point after.
EVENT is the mouse event."
  (let* ((posn (event-end event))
         (x (car (posn-object-x-y posn)))
         (w (car (posn-object-width-height posn))))
    ;; ‘mouse-set-point’ is called twice when you click mouse, first
    ;; in ‘down-mouse-1’, called by ‘mouse-drag-region’ ->
    ;; ‘mouse-drag-track’ to set point, second in ‘mouse-1’, when
    ;; mouse released and Emacs realized that this is a click event.
    ;; We want to adjust point in both cases.
    (when (and (null (posn-object posn))
               (> x (/ w 2))
               (not (eq (char-after) ?\n)))
      (forward-char))))

(define-minor-mode delicate-click-mode
  "Accurate point position on click.
That is, if you click on the right half of a character, the point
is set to after it."
  :global t
  :lighter ""
  (if delicate-click-mode
      (advice-add 'mouse-set-point :after #'adjust-point-after-click)
    (advice-remove 'mouse-set-point #'adjust-point-after-click)))

(provide 'delicate-click)

;;; delicate-click.el ends here

[-- Attachment #3: Type: text/plain, Size: 2 bytes --]




^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 21:17                           ` Yuan Fu
@ 2023-07-12 21:36                             ` Moritz Maxeiner
  2023-07-12 22:08                               ` Yuan Fu
  2023-07-13  5:27                             ` Eli Zaretskii
  1 sibling, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-12 21:36 UTC (permalink / raw)
  To: Yuan Fu; +Cc: Po Lu, Eli Zaretskii, emacs-devel

On Wednesday, 12 July 2023 23:17:41 CEST Yuan Fu wrote:
> 
> > On Jul 12, 2023, at 12:58 PM, Moritz Maxeiner <mm@ucw.sh> wrote:
> > 
> > On Wednesday 12 July 2023 02:52:01 CEST Po Lu wrote:
> >> Moritz Maxeiner <mm@ucw.sh> writes:
> >>> I'm not clear on why that would make it wrong (as in incorrect semantics).
> >>> It's definitely inefficient (though I've not noticed the overhead in
> >>> practice), which is why I asked if there's a more elegant solution.
> >> 
> >> The overhead is apparent when options such as
> >> `mouse-drag-and-drop-region' are enabled and the connection to the X
> >> server is slow.
> >> 
> >>> Which this is, thank you very much for pointing that out. I've changed
> >>> that
> >>> part of the patch accordingly, though this does unfortunately mean that a
> >>> new function is required, due to multiple places setting the glyph
> >>> rectangle as it relates to dragging.
> >> 
> >> I find that difficult to believe.  Would you please describe the other
> >> callers of `remember_mouse_glyph' that make adjustments there
> >> impossible?
> >> 
> >> I asked you to make the change in `remember_mouse_glyph' because that
> >> would avoid the need to modify each of the *term.[cm] files
> >> individually.  Replacing it with a different function would miss the
> >> point of the change.
> > 
> > My apologies, after rereading your previous message I realize I misunderstood. 
> > I thought I was to put the changes after the remember_mouse_glyph call (like I 
> > was previously asked to do for move_it_in_display_line instead of modifying 
> > another xdisp.c function, move_it_in_display_line_to). My comment derived from 
> > that misunderstanding as there are multiple calls to remember_mouse_glyph that 
> > need to be affected.
> > 
> > I have adjusted the patch as requested (I think), added some documentation in 
> > commands.texi, as well as a NEWS entry. I'm not sure about correct placement / 
> > formatting of the latter two.
> > 
> > Btw. I'm not particularly happy about needed to add the `original_gx' 
> > variable, but since the function seems to overwrite its argument, which I need 
> > access to at its end (once the full glyph has been determined), I don't see 
> > another option. I'm also not super happy about the needed division, but I also 
> > don't see a way around that. If you know a more elegant solution I'd be happy 
> > to hear it.
> > 
> >> 
> >>> Assuming this version of the implementation meets muster I will work
> >>> on the etc/NEWS entry and can look into adding something to
> >>> (elisp)Accessing Mouse, as well.
> >> 
> >> Several other comments below:
> >>> +/* 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;
> >>> +}
> >> 
> >> Please follow the GNU coding standards for both function declarators and
> >> comments, by capitalizing (not quoting) arguments which appear in the
> >> commentary, and placing a space between the identifier name and the
> >> opening parentheses of the parameter type list.  Also, use the active
> >> voice when describing the behavior of a function within its commentary:
> >> 
> >> /* Replace *GLYPH, a rectangle containing the bounds of a glyph, with
> >>   the half of the rectangle containing the position X.  */
> >> 
> >> static void
> >> x_vertical_bisect_glyph (XRectangle *glyph, int x)
> >> {
> >>  /* ... */
> >> }
> >> 
> >> In addition, we don't use Markdown style quotes for code.  When quoting
> >> identifier names in the future, either write:
> >> 
> >>  /* `foo' is used to perform ...  */
> >> 
> >> or
> >> 
> >>  /* 'foo' is used to perform ...  */
> >> 
> >>> /* 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);
> >> 
> >> Please place a space between the identifier name and the opening brace
> >> of each function call.
> >> 
> >> However, implementing this feature shouldn't need changes to xterm.c at
> >> all.  Please make the change in `remember_mouse_glyph', not in window
> >> system specific code.
> > 
> > Since that function (and calls to it) are now merged into 
> > `remember_mouse_glyph', I think these are solved by default. I'll take more 
> > care next time, though, thank you for the correction.<emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.6.patch>
> 
> Sorry for joining late into the discussion. But I wonder if a Elisp solution would suffice? Someone had requested this feature to me in the past and this is my solution at the time.
> 
> Yuan
> 
> 

Thank you for the code. I've tried it out and it does seem to do the same thing for a single mouse click, but it does not change the behavior of mouse dragging (selection highlighting) in the same way, which I also want/need (and this patch does).






^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 21:36                             ` Moritz Maxeiner
@ 2023-07-12 22:08                               ` Yuan Fu
  0 siblings, 0 replies; 47+ messages in thread
From: Yuan Fu @ 2023-07-12 22:08 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Po Lu, Eli Zaretskii, emacs-devel



> On Jul 12, 2023, at 2:36 PM, Moritz Maxeiner <mm@ucw.sh> wrote:
> 
> On Wednesday, 12 July 2023 23:17:41 CEST Yuan Fu wrote:
>> 
>>> On Jul 12, 2023, at 12:58 PM, Moritz Maxeiner <mm@ucw.sh> wrote:
>>> 
>>> On Wednesday 12 July 2023 02:52:01 CEST Po Lu wrote:
>>>> Moritz Maxeiner <mm@ucw.sh> writes:
>>>>> I'm not clear on why that would make it wrong (as in incorrect semantics).
>>>>> It's definitely inefficient (though I've not noticed the overhead in
>>>>> practice), which is why I asked if there's a more elegant solution.
>>>> 
>>>> The overhead is apparent when options such as
>>>> `mouse-drag-and-drop-region' are enabled and the connection to the X
>>>> server is slow.
>>>> 
>>>>> Which this is, thank you very much for pointing that out. I've changed
>>>>> that
>>>>> part of the patch accordingly, though this does unfortunately mean that a
>>>>> new function is required, due to multiple places setting the glyph
>>>>> rectangle as it relates to dragging.
>>>> 
>>>> I find that difficult to believe.  Would you please describe the other
>>>> callers of `remember_mouse_glyph' that make adjustments there
>>>> impossible?
>>>> 
>>>> I asked you to make the change in `remember_mouse_glyph' because that
>>>> would avoid the need to modify each of the *term.[cm] files
>>>> individually.  Replacing it with a different function would miss the
>>>> point of the change.
>>> 
>>> My apologies, after rereading your previous message I realize I misunderstood. 
>>> I thought I was to put the changes after the remember_mouse_glyph call (like I 
>>> was previously asked to do for move_it_in_display_line instead of modifying 
>>> another xdisp.c function, move_it_in_display_line_to). My comment derived from 
>>> that misunderstanding as there are multiple calls to remember_mouse_glyph that 
>>> need to be affected.
>>> 
>>> I have adjusted the patch as requested (I think), added some documentation in 
>>> commands.texi, as well as a NEWS entry. I'm not sure about correct placement / 
>>> formatting of the latter two.
>>> 
>>> Btw. I'm not particularly happy about needed to add the `original_gx' 
>>> variable, but since the function seems to overwrite its argument, which I need 
>>> access to at its end (once the full glyph has been determined), I don't see 
>>> another option. I'm also not super happy about the needed division, but I also 
>>> don't see a way around that. If you know a more elegant solution I'd be happy 
>>> to hear it.
>>> 
>>>> 
>>>>> Assuming this version of the implementation meets muster I will work
>>>>> on the etc/NEWS entry and can look into adding something to
>>>>> (elisp)Accessing Mouse, as well.
>>>> 
>>>> Several other comments below:
>>>>> +/* 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;
>>>>> +}
>>>> 
>>>> Please follow the GNU coding standards for both function declarators and
>>>> comments, by capitalizing (not quoting) arguments which appear in the
>>>> commentary, and placing a space between the identifier name and the
>>>> opening parentheses of the parameter type list.  Also, use the active
>>>> voice when describing the behavior of a function within its commentary:
>>>> 
>>>> /* Replace *GLYPH, a rectangle containing the bounds of a glyph, with
>>>>  the half of the rectangle containing the position X.  */
>>>> 
>>>> static void
>>>> x_vertical_bisect_glyph (XRectangle *glyph, int x)
>>>> {
>>>> /* ... */
>>>> }
>>>> 
>>>> In addition, we don't use Markdown style quotes for code.  When quoting
>>>> identifier names in the future, either write:
>>>> 
>>>> /* `foo' is used to perform ...  */
>>>> 
>>>> or
>>>> 
>>>> /* 'foo' is used to perform ...  */
>>>> 
>>>>> /* 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);
>>>> 
>>>> Please place a space between the identifier name and the opening brace
>>>> of each function call.
>>>> 
>>>> However, implementing this feature shouldn't need changes to xterm.c at
>>>> all.  Please make the change in `remember_mouse_glyph', not in window
>>>> system specific code.
>>> 
>>> Since that function (and calls to it) are now merged into 
>>> `remember_mouse_glyph', I think these are solved by default. I'll take more 
>>> care next time, though, thank you for the correction.<emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.6.patch>
>> 
>> Sorry for joining late into the discussion. But I wonder if a Elisp solution would suffice? Someone had requested this feature to me in the past and this is my solution at the time.
>> 
>> Yuan
>> 
>> 
> 
> Thank you for the code. I've tried it out and it does seem to do the same thing for a single mouse click, but it does not change the behavior of mouse dragging (selection highlighting) in the same way, which I also want/need (and this patch does).

Ah, the code is just to show that similar things might be accomplishable by modifying Elisp functions. I don’t suggest using it as-is. Besides what you pointed out, it also uses advice, which is bad.

Yuan


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 19:58                         ` Moritz Maxeiner
  2023-07-12 21:17                           ` Yuan Fu
@ 2023-07-13  0:31                           ` Po Lu
  2023-07-13  8:47                           ` Eli Zaretskii
  2 siblings, 0 replies; 47+ messages in thread
From: Po Lu @ 2023-07-13  0:31 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Eli Zaretskii, emacs-devel

Moritz Maxeiner <mm@ucw.sh> writes:

> My apologies, after rereading your previous message I realize I misunderstood. 
> I thought I was to put the changes after the remember_mouse_glyph call (like I 
> was previously asked to do for move_it_in_display_line instead of modifying 
> another xdisp.c function, move_it_in_display_line_to). My comment derived from 
> that misunderstanding as there are multiple calls to remember_mouse_glyph that 
> need to be affected.
>
> I have adjusted the patch as requested (I think), added some documentation in 
> commands.texi, as well as a NEWS entry. I'm not sure about correct placement / 
> formatting of the latter two.
>
> Btw. I'm not particularly happy about needed to add the `original_gx' 
> variable, but since the function seems to overwrite its argument, which I need 
> access to at its end (once the full glyph has been determined), I don't see 
> another option. I'm also not super happy about the needed division, but I also 
> don't see a way around that. If you know a more elegant solution I'd be happy 
> to hear it.

I don't see a problem with that, but please see below.

> diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
> index cd1745614eb..274c456d8c3 100644
> --- a/doc/lispref/commands.texi
> +++ b/doc/lispref/commands.texi
> @@ -1969,6 +1969,8 @@ events do not appear.  @xref{Mouse Tracking}.
>  When non-@code{nil}, mouse motion events are generated even for very
>  small movements.  Otherwise, motion events are not generated as long
>  as the mouse cursor remains pointing to the same glyph in the text.
> +Note that non-@code{nil} @code{mouse-prefer-closest-glyph} changes
> +that to the left/right half of the glyph under the mouse cursor instead.

I think this change is unnecessary and could at least be reworded or
moved to a more suitable venue.

>  @end defvar
>  
>  @node Touchscreen Events
> @@ -2751,6 +2753,14 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
>  to the entire window area including scroll bars, margins and fringes.
>  @end defun
>  
> +@defvar mouse-prefer-closest-glyph
> +If you set this variable to non-@code{nil}, whenever you click or drag the mouse,
> +instead of the point being always set in front of the clicked glyph, the point
> +horizontally closest to the mouse position will be used.
> +So if you click in the left half of a glyph, point is set in front of it,
> +but if you click in the right half, point is set after it.
> +@end defvar

How about:

If this variable is non-@code{nil}, the @code{posn-point} of a mouse
position list will be set to the position of the glyph whose left most
position is closest to the mouse pointer, as opposed to the position of
the glyph underneath the mouse pointer itself.  For example, if
@code{posn-at-x-y} is called with @var{x} set to @code{9}, which is
contained within a character of width 10 positioned at column 0, the
point saved within the mouse position list will be after that character.

?

> +  DEFVAR_BOOL ("mouse-prefer-closest-glyph", mouse_prefer_closest_glyph,
> +	       doc: /*  Non-nil means mouse position lists are reported relative
                      ^^

There is superfluous whitespace here.

>    if (window_resize_pixelwise)
>      {
>        width = height = 1;
> @@ -2950,6 +2953,16 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
>   store_rect:
>    STORE_NATIVE_RECT (*rect, gx, gy, width, height);
>  
> +  if (mouse_prefer_closest_glyph)
> +    {
> +      int half_width = rect->width / 2;
> +      rect->width = half_width;
> +
> +      int bisection = rect->x + half_width;
> +      if (original_gx > bisection)
> +        rect->x = bisection;
> +    }

Instead of repeatedly loading from and storing to RECT, why not modify
width and height before the expansion of STORE_NATIVE_RECT?

Thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 21:17                           ` Yuan Fu
  2023-07-12 21:36                             ` Moritz Maxeiner
@ 2023-07-13  5:27                             ` Eli Zaretskii
  2023-07-13 23:25                               ` Yuan Fu
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-13  5:27 UTC (permalink / raw)
  To: Yuan Fu; +Cc: mm, luangruo, emacs-devel

> From: Yuan Fu <casouri@gmail.com>
> Date: Wed, 12 Jul 2023 14:17:41 -0700
> Cc: Po Lu <luangruo@yahoo.com>,
>  Eli Zaretskii <eliz@gnu.org>,
>  emacs-devel@gnu.org
> 
> Sorry for joining late into the discussion. But I wonder if a Elisp solution would suffice? Someone had requested this feature to me in the past and this is my solution at the time.

Thanks.

I like this solution less, since it advises primitives, something that
should be the last resort.  Also, handling layout in Lisp is always
tricky; for example, posn-* functions are not very reliable in some
obscure/rare use cases.  The solution in the display code is simple
and very local, so I think it should be preferred.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-12 19:58                         ` Moritz Maxeiner
  2023-07-12 21:17                           ` Yuan Fu
  2023-07-13  0:31                           ` Po Lu
@ 2023-07-13  8:47                           ` Eli Zaretskii
  2023-07-21 19:04                             ` Moritz Maxeiner
  2 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-13  8:47 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: luangruo, emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Wed, 12 Jul 2023 21:58:44 +0200
> 
> +@defvar mouse-prefer-closest-glyph

This is a user option, so please use @defopt, not @defvar.

Also, please use some smaller (preferably, default) value for
fill-column, as the text you posted uses too long lines.

> +If you set this variable to non-@code{nil}, whenever you click or drag the mouse,
> +instead of the point being always set in front of the clicked glyph, the point
> +horizontally closest to the mouse position will be used.
> +So if you click in the left half of a glyph, point is set in front of it,
> +but if you click in the right half, point is set after it.

There's too much of passive voice here.  I think the alternative
wording proposed by Po Lu is better.

> ++++
> +** New user option 'mouse-prefer-closest-glyph'.
> +When enabled, clicking or dragging with the mouse will put the point
> +in front of the glyph with the closest x coordinate to the mouse pointer.
                                                       ^^^^^^^^^^^^^^^^^^^^
"to the click or start of the drag"

> +In other words, if the mouse pointer is in the right half of a glyph,
> +point will be put after that glyph, while if the mouse pointer is in the
> +left half of a glyph, point will be put in front of that glyph.

Point is buffer position, whereas "glyph" is something on display.  So
this should say something like "point will be put after the buffer
position corresponding to that glyph".

Also, please state explicitly that the default of this feature is OFF.

I understand that the details of the code are still under discussion,
but I thought I'd post these comments anyway.

Thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-13  5:27                             ` Eli Zaretskii
@ 2023-07-13 23:25                               ` Yuan Fu
  0 siblings, 0 replies; 47+ messages in thread
From: Yuan Fu @ 2023-07-13 23:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Moritz Maxeiner, Po Lu, emacs-devel



> On Jul 12, 2023, at 10:27 PM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> From: Yuan Fu <casouri@gmail.com>
>> Date: Wed, 12 Jul 2023 14:17:41 -0700
>> Cc: Po Lu <luangruo@yahoo.com>,
>> Eli Zaretskii <eliz@gnu.org>,
>> emacs-devel@gnu.org
>> 
>> Sorry for joining late into the discussion. But I wonder if a Elisp solution would suffice? Someone had requested this feature to me in the past and this is my solution at the time.
> 
> Thanks.
> 
> I like this solution less, since it advises primitives, something that
> should be the last resort.  Also, handling layout in Lisp is always
> tricky; for example, posn-* functions are not very reliable in some
> obscure/rare use cases.  The solution in the display code is simple
> and very local, so I think it should be preferred.

That’s good to hear!

Yuan


^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-13  8:47                           ` Eli Zaretskii
@ 2023-07-21 19:04                             ` Moritz Maxeiner
  2023-07-21 23:57                               ` Po Lu
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-21 19:04 UTC (permalink / raw)
  To: Eli Zaretskii, luangruo; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 2045 bytes --]

On Thursday 13 July 2023 10:47:36 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Cc: emacs-devel@gnu.org
> > Date: Wed, 12 Jul 2023 21:58:44 +0200
> > 
> > +@defvar mouse-prefer-closest-glyph
> 
> This is a user option, so please use @defopt, not @defvar.
> 
> Also, please use some smaller (preferably, default) value for
> fill-column, as the text you posted uses too long lines.
> 
> > +If you set this variable to non-@code{nil}, whenever you click or drag
> > the mouse, +instead of the point being always set in front of the clicked
> > glyph, the point +horizontally closest to the mouse position will be
> > used.
> > +So if you click in the left half of a glyph, point is set in front of it,
> > +but if you click in the right half, point is set after it.
> 
> There's too much of passive voice here.  I think the alternative
> wording proposed by Po Lu is better.
> 
> > ++++
> > +** New user option 'mouse-prefer-closest-glyph'.
> > +When enabled, clicking or dragging with the mouse will put the point
> > +in front of the glyph with the closest x coordinate to the mouse pointer.
> 
>                                                        ^^^^^^^^^^^^^^^^^^^^
> "to the click or start of the drag"
> 
> > +In other words, if the mouse pointer is in the right half of a glyph,
> > +point will be put after that glyph, while if the mouse pointer is in the
> > +left half of a glyph, point will be put in front of that glyph.
> 
> Point is buffer position, whereas "glyph" is something on display.  So
> this should say something like "point will be put after the buffer
> position corresponding to that glyph".
> 
> Also, please state explicitly that the default of this feature is OFF.
> 
> I understand that the details of the code are still under discussion,
> but I thought I'd post these comments anyway.
> 
> Thanks.

Thank you both for your continued feedback. I haven't had time to work on this 
in a bit, but I think the patch now includes all your latest suggestions 
(sorry if I overlooked something).

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.7.patch --]
[-- Type: text/x-patch, Size: 5807 bytes --]

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index cd1745614eb..d1b8f9c494c 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2751,6 +2751,16 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
 to the entire window area including scroll bars, margins and fringes.
 @end defun
 
+@defopt mouse-prefer-closest-glyph
+If this variable is non-@code{nil}, the @code{posn-point} of a mouse
+position list will be set to the position of the glyph whose left most
+position is closest to the mouse pointer, as opposed to the position of
+the glyph underneath the mouse pointer itself.  For example, if
+@code{posn-at-x-y} is called with @var{x} set to @code{9}, which is
+contained within a character of width 10 positioned at column 0, the
+point saved within the mouse position list will be after that character.
+@end defopt
+
 @node Accessing Scroll
 @subsection Accessing Scroll Bar Events
 @cindex scroll bar events, data in
diff --git a/etc/NEWS b/etc/NEWS
index 9e6f0c16bcd..348152cb7be 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -952,6 +952,17 @@ wheel reports.  Unlike 'pixel-scroll-mode', this mode scrolls the
 display pixel-by-pixel, as opposed to only animating line-by-line
 scrolls.
 
++++
+** New user option 'mouse-prefer-closest-glyph'.
+When enabled, clicking or dragging with the mouse will put the point
+in front of the buffer position corresponding to the glyph with the
+closest x coordinate to the click or start of the drag.
+In other words, if the mouse pointer is in the right half of a glyph,
+point will be put after the buffer position corresponding to that glyph,
+whereas if the mouse pointer is in the left half of a glyph, point
+will be put in front the buffer position corresponding to that glyph.
+This new option defaults to off.
+
 ** Terminal Emacs
 
 ---
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..143dda412e9 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/xdisp.c b/src/xdisp.c
index 763af7d3bc8..1d71bb02641 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2723,6 +2723,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   enum window_part part;
   enum glyph_row_area area;
   int x, y, width, height;
+  int original_gx;
 
   if (mouse_fine_grained_tracking)
     {
@@ -2733,6 +2734,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
+  original_gx = gx;
+
   if (window_resize_pixelwise)
     {
       width = height = 1;
@@ -2948,6 +2951,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   gy += WINDOW_TOP_EDGE_Y (w);
 
  store_rect:
+  if (mouse_prefer_closest_glyph)
+    {
+      int half_width = width / 2;
+      width = half_width;
+
+      int bisection = gx + half_width;
+      if (original_gx > bisection)
+        gx = bisection;
+    }
   STORE_NATIVE_RECT (*rect, gx, gy, width, height);
 
   /* Visible feedback for debugging.  */
@@ -37345,7 +37357,10 @@ may be more familiar to users.  */);
   DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
     doc: /* Non-nil for pixel-wise mouse-movement.
 When nil, mouse-movement events will not be generated as long as the
-mouse stays within the extent of a single glyph (except for images).  */);
+mouse stays within the extent of a single glyph (except for images).
+When nil and mouse-prefer-closest-glyph is non-nil, mouse-movement
+events will instead not be generated as long as the mouse stays within
+the extent of a single left/right half glyph (except for images).  */);
   mouse_fine_grained_tracking = false;
 
   DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-21 19:04                             ` Moritz Maxeiner
@ 2023-07-21 23:57                               ` Po Lu
  2023-07-22  5:41                                 ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Po Lu @ 2023-07-21 23:57 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Eli Zaretskii, emacs-devel

Moritz Maxeiner <mm@ucw.sh> writes:

> ++++
> +** New user option 'mouse-prefer-closest-glyph'.
> +When enabled, clicking or dragging with the mouse will put the point
> +in front of the buffer position corresponding to the glyph with the
> +closest x coordinate to the click or start of the drag.

Please capitalize `x' here.

> +This new option defaults to off.

I think this sentence is redundant.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-21 23:57                               ` Po Lu
@ 2023-07-22  5:41                                 ` Eli Zaretskii
  2023-07-22 10:07                                   ` Moritz Maxeiner
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-22  5:41 UTC (permalink / raw)
  To: Po Lu; +Cc: mm, emacs-devel

> From: Po Lu <luangruo@yahoo.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> Date: Sat, 22 Jul 2023 07:57:53 +0800
> 
> Moritz Maxeiner <mm@ucw.sh> writes:
> 
> > +This new option defaults to off.
> 
> I think this sentence is redundant.

It isn't.  But a better wording would be

  By default this is disabled.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22  5:41                                 ` Eli Zaretskii
@ 2023-07-22 10:07                                   ` Moritz Maxeiner
  2023-07-22 11:31                                     ` Po Lu
  2023-07-22 12:51                                     ` Eli Zaretskii
  0 siblings, 2 replies; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-22 10:07 UTC (permalink / raw)
  To: Po Lu, Eli Zaretskii; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 717 bytes --]

On Saturday 22 July 2023 07:41:53 CEST Eli Zaretskii wrote:
> > From: Po Lu <luangruo@yahoo.com>
> > Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> > Date: Sat, 22 Jul 2023 07:57:53 +0800
> > 
> > Moritz Maxeiner <mm@ucw.sh> writes:
> > > +This new option defaults to off.
> > 
> > I think this sentence is redundant.
> 
> It isn't.  But a better wording would be
> 
>   By default this is disabled.

Done. Though I am concerned that capitalizing "x coordinate" to  "X 
coordinate" will lead to confusion, as capitalized X seems to usually refer to 
the X window system within NEWS. In this instance, it's not supposed to be 
referring to that, instead it's referring to the x of the (x,y) coordinate 
pair.

[-- Attachment #2: emacs-29-move_it_in_display_line_to-nextglyphafterhalf-poc-0.8.patch --]
[-- Type: text/x-patch, Size: 5803 bytes --]

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index cd1745614eb..d1b8f9c494c 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2751,6 +2751,16 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
 to the entire window area including scroll bars, margins and fringes.
 @end defun
 
+@defopt mouse-prefer-closest-glyph
+If this variable is non-@code{nil}, the @code{posn-point} of a mouse
+position list will be set to the position of the glyph whose left most
+position is closest to the mouse pointer, as opposed to the position of
+the glyph underneath the mouse pointer itself.  For example, if
+@code{posn-at-x-y} is called with @var{x} set to @code{9}, which is
+contained within a character of width 10 positioned at column 0, the
+point saved within the mouse position list will be after that character.
+@end defopt
+
 @node Accessing Scroll
 @subsection Accessing Scroll Bar Events
 @cindex scroll bar events, data in
diff --git a/etc/NEWS b/etc/NEWS
index 9e6f0c16bcd..3c127aa9bd7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -952,6 +952,17 @@ wheel reports.  Unlike 'pixel-scroll-mode', this mode scrolls the
 display pixel-by-pixel, as opposed to only animating line-by-line
 scrolls.
 
++++
+** New user option 'mouse-prefer-closest-glyph'.
+When enabled, clicking or dragging with the mouse will put the point
+in front of the buffer position corresponding to the glyph with the
+closest X coordinate to the click or start of the drag.
+In other words, if the mouse pointer is in the right half of a glyph,
+point will be put after the buffer position corresponding to that glyph,
+whereas if the mouse pointer is in the left half of a glyph, point
+will be put in front the buffer position corresponding to that glyph.
+By default this is disabled.
+
 ** Terminal Emacs
 
 ---
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..143dda412e9 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/xdisp.c b/src/xdisp.c
index 763af7d3bc8..1d71bb02641 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2723,6 +2723,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   enum window_part part;
   enum glyph_row_area area;
   int x, y, width, height;
+  int original_gx;
 
   if (mouse_fine_grained_tracking)
     {
@@ -2733,6 +2734,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
+  original_gx = gx;
+
   if (window_resize_pixelwise)
     {
       width = height = 1;
@@ -2948,6 +2951,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   gy += WINDOW_TOP_EDGE_Y (w);
 
  store_rect:
+  if (mouse_prefer_closest_glyph)
+    {
+      int half_width = width / 2;
+      width = half_width;
+
+      int bisection = gx + half_width;
+      if (original_gx > bisection)
+        gx = bisection;
+    }
   STORE_NATIVE_RECT (*rect, gx, gy, width, height);
 
   /* Visible feedback for debugging.  */
@@ -37345,7 +37357,10 @@ may be more familiar to users.  */);
   DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
     doc: /* Non-nil for pixel-wise mouse-movement.
 When nil, mouse-movement events will not be generated as long as the
-mouse stays within the extent of a single glyph (except for images).  */);
+mouse stays within the extent of a single glyph (except for images).
+When nil and mouse-prefer-closest-glyph is non-nil, mouse-movement
+events will instead not be generated as long as the mouse stays within
+the extent of a single left/right half glyph (except for images).  */);
   mouse_fine_grained_tracking = false;
 
   DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 10:07                                   ` Moritz Maxeiner
@ 2023-07-22 11:31                                     ` Po Lu
  2023-07-22 12:51                                     ` Eli Zaretskii
  1 sibling, 0 replies; 47+ messages in thread
From: Po Lu @ 2023-07-22 11:31 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Eli Zaretskii, emacs-devel

Moritz Maxeiner <mm@ucw.sh> writes:

> Done. Though I am concerned that capitalizing "x coordinate" to  "X 
> coordinate" will lead to confusion, as capitalized X seems to usually refer to 
> the X window system within NEWS. In this instance, it's not supposed to be 
> referring to that, instead it's referring to the x of the (x,y) coordinate 
> pair.

I think that what the X refers to is sufficiently clear from the
surrounding context.  If you're still concerned, however, how about
``cordinate on the X axis''?

> diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
> index cd1745614eb..d1b8f9c494c 100644
> --- a/doc/lispref/commands.texi
> +++ b/doc/lispref/commands.texi
> @@ -2751,6 +2751,16 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
>  to the entire window area including scroll bars, margins and fringes.
>  @end defun
>  
> +@defopt mouse-prefer-closest-glyph
> +If this variable is non-@code{nil}, the @code{posn-point} of a mouse
> +position list will be set to the position of the glyph whose left most
> +position is closest to the mouse pointer, as opposed to the position of
> +the glyph underneath the mouse pointer itself.  For example, if
> +@code{posn-at-x-y} is called with @var{x} set to @code{9}, which is
> +contained within a character of width 10 positioned at column 0, the
> +point saved within the mouse position list will be after that character.
> +@end defopt
> +
>  @node Accessing Scroll
>  @subsection Accessing Scroll Bar Events
>  @cindex scroll bar events, data in
> diff --git a/etc/NEWS b/etc/NEWS
> index 9e6f0c16bcd..3c127aa9bd7 100644
> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -952,6 +952,17 @@ wheel reports.  Unlike 'pixel-scroll-mode', this mode scrolls the
>  display pixel-by-pixel, as opposed to only animating line-by-line
>  scrolls.
>  
> ++++
> +** New user option 'mouse-prefer-closest-glyph'.
> +When enabled, clicking or dragging with the mouse will put the point
> +in front of the buffer position corresponding to the glyph with the
> +closest X coordinate to the click or start of the drag.
> +In other words, if the mouse pointer is in the right half of a glyph,
> +point will be put after the buffer position corresponding to that glyph,
> +whereas if the mouse pointer is in the left half of a glyph, point
> +will be put in front the buffer position corresponding to that glyph.
> +By default this is disabled.
> +
>  ** Terminal Emacs
>  
>  ---
> 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..143dda412e9 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/xdisp.c b/src/xdisp.c
> index 763af7d3bc8..1d71bb02641 100644
> --- a/src/xdisp.c
> +++ b/src/xdisp.c
> @@ -2723,6 +2723,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
>    enum window_part part;
>    enum glyph_row_area area;
>    int x, y, width, height;
> +  int original_gx;
>  
>    if (mouse_fine_grained_tracking)
>      {
> @@ -2733,6 +2734,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
>    /* Try to determine frame pixel position and size of the glyph under
>       frame pixel coordinates X/Y on frame F.  */
>  
> +  original_gx = gx;
> +
>    if (window_resize_pixelwise)
>      {
>        width = height = 1;
> @@ -2948,6 +2951,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
>    gy += WINDOW_TOP_EDGE_Y (w);
>  
>   store_rect:
> +  if (mouse_prefer_closest_glyph)
> +    {
> +      int half_width = width / 2;
> +      width = half_width;
> +
> +      int bisection = gx + half_width;
> +      if (original_gx > bisection)
> +        gx = bisection;
> +    }
>    STORE_NATIVE_RECT (*rect, gx, gy, width, height);
>  
>    /* Visible feedback for debugging.  */
> @@ -37345,7 +37357,10 @@ may be more familiar to users.  */);
>    DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
>      doc: /* Non-nil for pixel-wise mouse-movement.
>  When nil, mouse-movement events will not be generated as long as the
> -mouse stays within the extent of a single glyph (except for images).  */);
> +mouse stays within the extent of a single glyph (except for images).
> +When nil and mouse-prefer-closest-glyph is non-nil, mouse-movement
> +events will instead not be generated as long as the mouse stays within
> +the extent of a single left/right half glyph (except for images).  */);
>    mouse_fine_grained_tracking = false;
>  
>    DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,

Otherwise, LGTM.  Thanks.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 10:07                                   ` Moritz Maxeiner
  2023-07-22 11:31                                     ` Po Lu
@ 2023-07-22 12:51                                     ` Eli Zaretskii
  2023-07-22 15:28                                       ` Moritz Maxeiner
  1 sibling, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-22 12:51 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: luangruo, emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: emacs-devel@gnu.org
> Date: Sat, 22 Jul 2023 12:07:27 +0200
> 
> On Saturday 22 July 2023 07:41:53 CEST Eli Zaretskii wrote:
> > > From: Po Lu <luangruo@yahoo.com>
> > > Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> > > Date: Sat, 22 Jul 2023 07:57:53 +0800
> > > 
> > > Moritz Maxeiner <mm@ucw.sh> writes:
> > > > +This new option defaults to off.
> > > 
> > > I think this sentence is redundant.
> > 
> > It isn't.  But a better wording would be
> > 
> >   By default this is disabled.
> 
> Done. Though I am concerned that capitalizing "x coordinate" to  "X 
> coordinate" will lead to confusion, as capitalized X seems to usually refer to 
> the X window system within NEWS. In this instance, it's not supposed to be 
> referring to that, instead it's referring to the x of the (x,y) coordinate 
> pair.

Thanks.  So now, to make it ready to go, please produce the patch in
the "git format-patch" format, or at least add to the patch a
ChangeLog-style commit log message describing the changes with their
file names and function names.  You can find the instructions for that
in CONTRIBUTE, and a lot of examples in "git log".



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
       [not found]   ` <87ilac2kla.fsf@yahoo.com>
@ 2023-07-22 14:48     ` Moritz Maxeiner
  2023-07-22 15:26       ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-22 14:48 UTC (permalink / raw)
  To: Po Lu; +Cc: Eli Zaretskii, emacs-devel

On Saturday, 22 July 2023 14:32:01 CEST you wrote:
> Moritz Maxeiner <mm@ucw.sh> writes:
> 
> > Alright, if you feel it's clear that's good enough for me. Thank you for the 
> > feedback. I assume the next step would be sending the patch to
> > bug-gnu-emacs@gnu.org ?
> 
> No, that's not necessary (even though we do prefer patches to be sent to
> bug-gnu-emacs@gnu.org initially.)
> 
> Your patch makes significant changes to more than 15 lines of Emacs
> source code; this means we will require copyright assignment to the FSF
> before it can be installed.
> 
> Have you assigned copyright to the FSF for changes to Emacs?  If not,
> Eli can send you the form to get you started.
> 

I know that many years ago I did sign a snail mail form for the FSF, but I don't remember which project it was for, sorry. I'm happy to do that (again) for Emacs, though I do have to point out (and I did that back then as well IIRC) that as a German citizen, my copyright can technically never be assigned no matter what forms I sign [1]. It would, to my understanding, at most count as granting of all-encompassing exclusive usage rights.


[1] https://script-ed.org/article/drafting-options-contributor-agreements-free-open-source-software-assignment-nonexclusive-licence-legal-consequences-comparative-analysis-german-law/





^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 14:48     ` Moritz Maxeiner
@ 2023-07-22 15:26       ` Eli Zaretskii
  0 siblings, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-22 15:26 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: luangruo, emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
> Date: Sat, 22 Jul 2023 16:48:41 +0200
> 
> > Your patch makes significant changes to more than 15 lines of Emacs
> > source code; this means we will require copyright assignment to the FSF
> > before it can be installed.
> > 
> > Have you assigned copyright to the FSF for changes to Emacs?  If not,
> > Eli can send you the form to get you started.
> > 
> 
> I know that many years ago I did sign a snail mail form for the FSF, but I don't remember which project it was for, sorry. I'm happy to do that (again) for Emacs, though I do have to point out (and I did that back then as well IIRC) that as a German citizen, my copyright can technically never be assigned no matter what forms I sign [1]. It would, to my understanding, at most count as granting of all-encompassing exclusive usage rights.

Your assignment is for Emacs, and it is on file, so there are no
problems in that department.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 12:51                                     ` Eli Zaretskii
@ 2023-07-22 15:28                                       ` Moritz Maxeiner
  2023-07-22 15:51                                         ` Eli Zaretskii
  0 siblings, 1 reply; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-22 15:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: luangruo, emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1433 bytes --]

On Saturday 22 July 2023 14:51:20 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Cc: emacs-devel@gnu.org
> > Date: Sat, 22 Jul 2023 12:07:27 +0200
> > 
> > On Saturday 22 July 2023 07:41:53 CEST Eli Zaretskii wrote:
> > > > From: Po Lu <luangruo@yahoo.com>
> > > > Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org
> > > > Date: Sat, 22 Jul 2023 07:57:53 +0800
> > > > 
> > > > Moritz Maxeiner <mm@ucw.sh> writes:
> > > > > +This new option defaults to off.
> > > > 
> > > > I think this sentence is redundant.
> > > 
> > > It isn't.  But a better wording would be
> > > 
> > >   By default this is disabled.
> > 
> > Done. Though I am concerned that capitalizing "x coordinate" to  "X
> > coordinate" will lead to confusion, as capitalized X seems to usually
> > refer to the X window system within NEWS. In this instance, it's not
> > supposed to be referring to that, instead it's referring to the x of the
> > (x,y) coordinate pair.
> 
> Thanks.  So now, to make it ready to go, please produce the patch in
> the "git format-patch" format, or at least add to the patch a
> ChangeLog-style commit log message describing the changes with their
> file names and function names.  You can find the instructions for that
> in CONTRIBUTE, and a lot of examples in "git log".

Sure, I hope the attached patch meets the requirements. I wasn't 100% on
some of the rules so I tried emulating what I saw in git log.

[-- Attachment #2: 0001-Implement-new-option-mouse-prefer-closest-glyph.patch --]
[-- Type: text/x-patch, Size: 6802 bytes --]

From f4efae2e7a089a784cd074080fcd211e0ca9ddb5 Mon Sep 17 00:00:00 2001
From: Moritz Maxeiner <mm@ucw.sh>
Date: Sat, 22 Jul 2023 16:55:07 +0200
Subject: [PATCH] Implement new option mouse-prefer-closest-glyph

* doc/lispref/commands.texi (Accessing Mouse): Update documentation to
say what the new option does when enabled.
* etc/NEWS: Announce the new option.
* lisp/cus-start.el (standard): New user custom
`mouse-prefer-closest-glyph'.
* src/dispnew.c (mouse_prefer_closest_glyph): New global variable.
(buffer_posn_from_coords):
* src/xdispc.c (remember_mouse_glyph):
Respect `mouse_prefer_closest_glyph'.
(mouse_fine_grained_tracking): Update documentation to include
`mouse_prefer_closest_glyph' effects.
---
 doc/lispref/commands.texi | 10 ++++++++++
 etc/NEWS                  | 11 +++++++++++
 lisp/cus-start.el         |  1 +
 src/dispnew.c             | 18 ++++++++++++++++++
 src/xdisp.c               | 17 ++++++++++++++++-
 5 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index cd1745614eb..d1b8f9c494c 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2751,6 +2751,16 @@ If @var{whole} is non-@code{nil}, the @var{x} coordinate is relative
 to the entire window area including scroll bars, margins and fringes.
 @end defun
 
+@defopt mouse-prefer-closest-glyph
+If this variable is non-@code{nil}, the @code{posn-point} of a mouse
+position list will be set to the position of the glyph whose left most
+position is closest to the mouse pointer, as opposed to the position of
+the glyph underneath the mouse pointer itself.  For example, if
+@code{posn-at-x-y} is called with @var{x} set to @code{9}, which is
+contained within a character of width 10 positioned at column 0, the
+point saved within the mouse position list will be after that character.
+@end defopt
+
 @node Accessing Scroll
 @subsection Accessing Scroll Bar Events
 @cindex scroll bar events, data in
diff --git a/etc/NEWS b/etc/NEWS
index 9e6f0c16bcd..3c127aa9bd7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -952,6 +952,17 @@ wheel reports.  Unlike 'pixel-scroll-mode', this mode scrolls the
 display pixel-by-pixel, as opposed to only animating line-by-line
 scrolls.
 
++++
+** New user option 'mouse-prefer-closest-glyph'.
+When enabled, clicking or dragging with the mouse will put the point
+in front of the buffer position corresponding to the glyph with the
+closest X coordinate to the click or start of the drag.
+In other words, if the mouse pointer is in the right half of a glyph,
+point will be put after the buffer position corresponding to that glyph,
+whereas if the mouse pointer is in the left half of a glyph, point
+will be put in front the buffer position corresponding to that glyph.
+By default this is disabled.
+
 ** Terminal Emacs
 
 ---
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..143dda412e9 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/xdisp.c b/src/xdisp.c
index 763af7d3bc8..1d71bb02641 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2723,6 +2723,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   enum window_part part;
   enum glyph_row_area area;
   int x, y, width, height;
+  int original_gx;
 
   if (mouse_fine_grained_tracking)
     {
@@ -2733,6 +2734,8 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   /* Try to determine frame pixel position and size of the glyph under
      frame pixel coordinates X/Y on frame F.  */
 
+  original_gx = gx;
+
   if (window_resize_pixelwise)
     {
       width = height = 1;
@@ -2948,6 +2951,15 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
   gy += WINDOW_TOP_EDGE_Y (w);
 
  store_rect:
+  if (mouse_prefer_closest_glyph)
+    {
+      int half_width = width / 2;
+      width = half_width;
+
+      int bisection = gx + half_width;
+      if (original_gx > bisection)
+        gx = bisection;
+    }
   STORE_NATIVE_RECT (*rect, gx, gy, width, height);
 
   /* Visible feedback for debugging.  */
@@ -37345,7 +37357,10 @@ may be more familiar to users.  */);
   DEFVAR_BOOL ("mouse-fine-grained-tracking", mouse_fine_grained_tracking,
     doc: /* Non-nil for pixel-wise mouse-movement.
 When nil, mouse-movement events will not be generated as long as the
-mouse stays within the extent of a single glyph (except for images).  */);
+mouse stays within the extent of a single glyph (except for images).
+When nil and mouse-prefer-closest-glyph is non-nil, mouse-movement
+events will instead not be generated as long as the mouse stays within
+the extent of a single left/right half glyph (except for images).  */);
   mouse_fine_grained_tracking = false;
 
   DEFVAR_BOOL ("tab-bar--dragging-in-progress", tab_bar__dragging_in_progress,
-- 
2.41.0


^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 15:28                                       ` Moritz Maxeiner
@ 2023-07-22 15:51                                         ` Eli Zaretskii
  2023-07-22 15:59                                           ` Moritz Maxeiner
  0 siblings, 1 reply; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-22 15:51 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: luangruo, emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Cc: luangruo@yahoo.com, emacs-devel@gnu.org
> Date: Sat, 22 Jul 2023 17:28:34 +0200
> 
> > Thanks.  So now, to make it ready to go, please produce the patch in
> > the "git format-patch" format, or at least add to the patch a
> > ChangeLog-style commit log message describing the changes with their
> > file names and function names.  You can find the instructions for that
> > in CONTRIBUTE, and a lot of examples in "git log".
> 
> Sure, I hope the attached patch meets the requirements. I wasn't 100% on
> some of the rules so I tried emulating what I saw in git log.

Thanks, it was mostly correct (see the minor changes I've done as
followup).

Now installed on the master branch.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 15:51                                         ` Eli Zaretskii
@ 2023-07-22 15:59                                           ` Moritz Maxeiner
  2023-07-22 16:34                                             ` Eli Zaretskii
  2023-07-22 19:10                                             ` Yuan Fu
  0 siblings, 2 replies; 47+ messages in thread
From: Moritz Maxeiner @ 2023-07-22 15:59 UTC (permalink / raw)
  To: Eli Zaretskii, emacs-devel

On Saturday 22 July 2023 17:51:54 CEST Eli Zaretskii wrote:
> > From: Moritz Maxeiner <mm@ucw.sh>
> > Cc: luangruo@yahoo.com, emacs-devel@gnu.org
> > Date: Sat, 22 Jul 2023 17:28:34 +0200
> > 
> > > Thanks.  So now, to make it ready to go, please produce the patch in
> > > the "git format-patch" format, or at least add to the patch a
> > > ChangeLog-style commit log message describing the changes with their
> > > file names and function names.  You can find the instructions for that
> > > in CONTRIBUTE, and a lot of examples in "git log".
> > 
> > Sure, I hope the attached patch meets the requirements. I wasn't 100% on
> > some of the rules so I tried emulating what I saw in git log.
> 
> Thanks, it was mostly correct (see the minor changes I've done as
> followup).
> 
> Now installed on the master branch.

Awesome, thanks! Just one last question: Is there any avenue to have this 
included in the Emacs 29 release, or is it too late for that?





^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 15:59                                           ` Moritz Maxeiner
@ 2023-07-22 16:34                                             ` Eli Zaretskii
  2023-07-22 19:10                                             ` Yuan Fu
  1 sibling, 0 replies; 47+ messages in thread
From: Eli Zaretskii @ 2023-07-22 16:34 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: emacs-devel

> From: Moritz Maxeiner <mm@ucw.sh>
> Date: Sat, 22 Jul 2023 17:59:58 +0200
> 
> On Saturday 22 July 2023 17:51:54 CEST Eli Zaretskii wrote:
> > 
> > Now installed on the master branch.
> 
> Awesome, thanks! Just one last question: Is there any avenue to have this 
> included in the Emacs 29 release, or is it too late for that?

Too late, sorry.



^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: Moving point after character when clicking latter half of it
  2023-07-22 15:59                                           ` Moritz Maxeiner
  2023-07-22 16:34                                             ` Eli Zaretskii
@ 2023-07-22 19:10                                             ` Yuan Fu
  1 sibling, 0 replies; 47+ messages in thread
From: Yuan Fu @ 2023-07-22 19:10 UTC (permalink / raw)
  To: Moritz Maxeiner; +Cc: Eli Zaretskii, emacs-devel


> On Jul 22, 2023, at 8:59 AM, Moritz Maxeiner <mm@ucw.sh> wrote:
> 
> On Saturday 22 July 2023 17:51:54 CEST Eli Zaretskii wrote:
>>> From: Moritz Maxeiner <mm@ucw.sh>
>>> Cc: luangruo@yahoo.com, emacs-devel@gnu.org
>>> Date: Sat, 22 Jul 2023 17:28:34 +0200
>>> 
>>>> Thanks.  So now, to make it ready to go, please produce the patch in
>>>> the "git format-patch" format, or at least add to the patch a
>>>> ChangeLog-style commit log message describing the changes with their
>>>> file names and function names.  You can find the instructions for that
>>>> in CONTRIBUTE, and a lot of examples in "git log".
>>> 
>>> Sure, I hope the attached patch meets the requirements. I wasn't 100% on
>>> some of the rules so I tried emulating what I saw in git log.
>> 
>> Thanks, it was mostly correct (see the minor changes I've done as
>> followup).
>> 
>> Now installed on the master branch.
> 
> Awesome, thanks! Just one last question: Is there any avenue to have this 
> included in the Emacs 29 release, or is it too late for that?

Awesome! I’ll be turning this on in my build ;-)

Yuan



^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2023-07-22 19:10 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-08 21:01 Moving point after character when clicking latter half of it Moritz Maxeiner
2023-07-09  6:35 ` Eli Zaretskii
2023-07-09 12:44   ` Moritz Maxeiner
2023-07-09 13:23     ` Eli Zaretskii
2023-07-09 13:51       ` Moritz Maxeiner
2023-07-09 14:14         ` Eli Zaretskii
2023-07-09 21:47           ` Moritz Maxeiner
2023-07-10 12:46             ` Eli Zaretskii
2023-07-10 14:43               ` [External] : " Drew Adams
2023-07-10 20:02               ` Moritz Maxeiner
2023-07-11 12:29                 ` Eli Zaretskii
2023-07-11 13:10                   ` Po Lu
2023-07-11 18:01                     ` Moritz Maxeiner
2023-07-12  0:52                       ` Po Lu
2023-07-12 19:58                         ` Moritz Maxeiner
2023-07-12 21:17                           ` Yuan Fu
2023-07-12 21:36                             ` Moritz Maxeiner
2023-07-12 22:08                               ` Yuan Fu
2023-07-13  5:27                             ` Eli Zaretskii
2023-07-13 23:25                               ` Yuan Fu
2023-07-13  0:31                           ` Po Lu
2023-07-13  8:47                           ` Eli Zaretskii
2023-07-21 19:04                             ` Moritz Maxeiner
2023-07-21 23:57                               ` Po Lu
2023-07-22  5:41                                 ` Eli Zaretskii
2023-07-22 10:07                                   ` Moritz Maxeiner
2023-07-22 11:31                                     ` Po Lu
2023-07-22 12:51                                     ` Eli Zaretskii
2023-07-22 15:28                                       ` Moritz Maxeiner
2023-07-22 15:51                                         ` Eli Zaretskii
2023-07-22 15:59                                           ` Moritz Maxeiner
2023-07-22 16:34                                             ` Eli Zaretskii
2023-07-22 19:10                                             ` Yuan Fu
2023-07-09 13:58       ` Yuri Khan
2023-07-09 12:40 ` Benjamin Riefenstahl
2023-07-09 12:47   ` Moritz Maxeiner
2023-07-09 13:37     ` Benjamin Riefenstahl
2023-07-09 15:15   ` [External] : " Drew Adams
2023-07-09 15:33     ` Moritz Maxeiner
2023-07-09 16:06       ` Drew Adams
2023-07-09 16:21       ` Brian Cully via Emacs development discussions.
2023-07-09 18:01         ` Jens Schmidt
2023-07-09 16:43       ` [External] : " Eli Zaretskii
2023-07-12 18:21     ` Benjamin Riefenstahl
2023-07-12 18:32       ` Eli Zaretskii
     [not found] ` <12248204.O9o76ZdvQC@anduin>
     [not found]   ` <87ilac2kla.fsf@yahoo.com>
2023-07-22 14:48     ` Moritz Maxeiner
2023-07-22 15:26       ` Eli Zaretskii

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).