unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
@ 2021-11-07 23:26 Drew Adams
  2021-11-08  8:28 ` tomas
  0 siblings, 1 reply; 7+ messages in thread
From: Drew Adams @ 2021-11-07 23:26 UTC (permalink / raw)
  To: Emacs developers

I got no response to my question of how to tell
whether `mouse-1' is still pressed during a click.

But I found an answer that seems to work across
Emacs releases (24 through 27, the latest I have).

Now let me pose a different question/suggestion.
I think `use-region-p' does the wrong thing in a
particular case, and I suggest a fix for that.

Here's the problem I see.  Admittedly, most code
hasn't, and won't, run into it.

`use-region-p' is designed to let code know that
either (1) the active region is nonempty or (2)
the user has OK'd the use of an empty region
(non-nil option `use-empty-active-region').

It should return non-nil in those cases _only_.

The problem I've run into comes in #2: empty
active region that's declared to be OK to use.

I think the real motivation for "use" must be for
the user (or some code) to act on the region with
the _next_ action - in particular, a user input
action - a command.  If the region is active and
usable then you can act on it - that's the idea.

In simple user terms, in this context (being able
to act on the active region) a click of `mouse-1'
can be considered a single user action.  There's
no intention, and little ability, for a user to
act _between_ the down & up events of a click (as
opposed to a drag).

(About the only thing a user can do between the
down & up events is hit a keyboard key.)

I think a user who's OK'd acting on (aka "using")
the empty active region really expects that
action ("use") to come after the down-&-up click,
not between the down & up events.

But `use-region-p' is a general test, and it can
be used anytime - including between down & up.

The current implementation doesn't effectively
check whether the region is active and useful
for an upcoming user action.  If some code tests
between down & up, and if the result of that
test is shown to a user, then a false impression
of "usable" is given - if only momentarily (till
the up event).

This problem just hasn't been noticed, most
likely, because `use-region-p' hasn't been
invoked in between those events.

My use case is to have the active region - as
something that can be acted on by users - be
indicated in the mode-line.  When active, you
see that it's active (you see the region size
indicated also, but that's irrelevant here).

In particular, OK'ing the use of an empty
active region is helpful in this context
because you see, in the mode-line, that
you're about to act on the empty region -
something you typically don't want to do.
IOW, this is a way to _see_ ahead of time
that you're trying to use an empty region.

I use a different user option for this from
`use-empty-active-region', and its default
value is non-nil.  So this feature doesn't
interfere with whatever value you prefer for
that standard option.

But I think the solution I've found (after I
posed the question looking for one) should
be considered as a fix for the problem in
`use-region-p' itself.  Why not fix this
corner case, even though people aren't very
likely to run into it?

Here's the code I'd propose:

---

(defun use-region-p ()
  "Return non-nil if it is appropriate to act on the region.
This is used by commands that act specially on the region when
Transient Mark mode is enabled.

The return value is non-nil if the region is active and either of the
following conditions is true; otherwise, the return value is nil.
 * The region is nonempty.
 * Option `use-empty-active-region' is non-nil, and the last input did
   not use `mouse-1' to set or adjust the region.

For some commands, it might be appropriate to ignore the value of
`use-empty-active-region'; in that case, use `region-active-p'."
  (ignore-errors
    (and (region-active-p)
         (or (> (region-end) (region-beginning))
             (and use-empty-active-region
                  (not (eq 'down-mouse-1
                           (car-safe last-input-event)))
                  (not (mouse-movement-p
                         last-input-event)))))))
---

(The fix ANDs those two mouse conditions to
`use-empty-active-region'.)

I'm no expert on events, mouse or otherwise,
so if someone sees a better implementation,
great.  (I'm not sure the `ignore-errors' is
needed, for example.)

The question is really whether preventing
`use-region-p' from returning true between
the down-&-up events of a click makes sense,
and if so, how best to do that.



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

* Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
  2021-11-07 23:26 Fix for `use-region-p' problem [was: Elisp test for whether `mouse-1' is pressed?] Drew Adams
@ 2021-11-08  8:28 ` tomas
  2021-11-08 18:32   ` [External] : " Drew Adams
  0 siblings, 1 reply; 7+ messages in thread
From: tomas @ 2021-11-08  8:28 UTC (permalink / raw)
  To: emacs-devel

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

On Sun, Nov 07, 2021 at 11:26:45PM +0000, Drew Adams wrote:
> I got no response to my question of how to tell
> whether `mouse-1' is still pressed during a click.

[...]

I read twice through your text and I'm still trying to wrap my
head around the gist of it.

Perhaps that's because I don't use the mouse much (when doing
text, at least). Perhaps it's something else.

My feeling (it mitght be totally wrong: I'm trying to expound
it just in an attempt to debug what's going on) is that you
are connecting directly two layers which are too far apart: at
the abstract/model/text end selection and its handling, at the
concrete/physical/UI end the mouse clicks.

In another debugging attempt: could you try to explain what you
are up to assuming the user has no mouse?

Now the above sounds as if I was trying to imply that you are
somehow "wrong". That I am not! I'm just at a loss trying to
understand what you are trying and even feel it's difficult for
me adequately expressing my difficulties.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* RE: [External] : Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
  2021-11-08  8:28 ` tomas
@ 2021-11-08 18:32   ` Drew Adams
  2021-11-09 11:29     ` tomas
  0 siblings, 1 reply; 7+ messages in thread
From: Drew Adams @ 2021-11-08 18:32 UTC (permalink / raw)
  To: tomas@tuxteam.de, emacs-devel@gnu.org

Thanks for replying, Tomas.

> > I got no response to my question of how to tell
> > whether `mouse-1' is still pressed during a click.
> 
> [...]
> 
> I read twice through your text and I'm still trying
> to wrap my head around the gist of it.

Sorry for any confusion or difficulty.

I can't tell if you mean that you had difficulty with
(1) the original post, asking how to tell when mouse-1
is pressed (the text you quoted) or with (2) my last
message (with changed Subject), which is what you
replied to.  Or perhaps you had difficulty with both?

> My feeling (it mitght be totally wrong: I'm trying to expound
> it just in an attempt to debug what's going on) is that you
> are connecting directly two layers which are too far apart: at
> the abstract/model/text end selection and its handling, at the
> concrete/physical/UI end the mouse clicks.

I can't speak to your feeling or the distinction you
describe.  You can select text with the mouse (or
otherwise) - maybe that's one connection.

I have no problem with the abstract behavior of
selection, with or without the mouse.  And I have no
problem with its concrete realization.

The problem I described is only with the implementation
of predicate `use-region-p'.  Its (minor) failing is
only with a corner case: returning true between mouse-1
down and up events during a click action (down & up at
the same place).

When you press mouse-1, drag-tracking is started, so
that if you move the mouse across text, that text gets
selected.  As long as you hold mouse-1 down, tracking
continues (well, unless interrupted by some other event
such as a keyboard key).

Roughly speaking, When you release mouse-1 the selected
text is used for the region, and the region/mark is
left activated.  But if you release mouse-1 at the same
place you pressed it, that release (button-up) event
deactivates the (empty) region.

From a _user_ point of view, when you start to do
something just after a click the region is inactive.
Your action after a click does _not_ act on an empty
active region.  This is all as it should be.

Event `down-mouse-1' (button-down) activates the region,
and event `mouse-1' (button-up) either (1) leaves it
activated, if the positions of down & up differ, or (2)
deactivates it, if those positions are the same.  (See
function `mouse-drag-track' for details.)

My original question was how to tell whether/when the
mouse is tracking.  In Emacs 24 (only) I found it was
sufficient to test whether `echo-keystrokes' is 0 - a
dumb and fragile hack.  I was now looking for a better
test, one that works across Emacs versions.

The better test I came up with, is this:

(and (not (eq 'down-mouse-1 (car-safe last-input-event)))
     (not (mouse-movement-p last-input-event)))

That is, whenever the region is empty (and assuming
the user OK's empty-region indication), if the last
input event wasn't `down-mouse-1' and it wasn't a
mouse movement, then it's OK to show the
active-region indication in the mode-line.

(Not sure why, but apparently if you click mouse-1 on
a different frame then the last event after pressing
mouse-1 is a mouse movement, not `down-mouse-1'.)

That seems to work well in the releases I support for
this so far: Emacs 24-27.  Maybe it too is fragile
and fortuitous, and won't work in Emacs release 42.
(Maybe Emacs should provide a predicate for mouse-1
being pressed and not yet released?)

> In another debugging attempt: could you try to explain
> what you are up to assuming the user has no mouse?

If the user has no mouse, or isn't using it in this
context, there's no change at all.  There's also no
effect on dragging the mouse (e.g. selecting text -
nonempty region).  The behavior to be fixed only
involves a mouse-1 click (down & up at the same place).  

> Now the above sounds as if I was trying to imply that you are
> somehow "wrong". That I am not! I'm just at a loss trying to
> understand what you are trying and even feel it's difficult for
> me adequately expressing my difficulties.

I appreciate your response.  I hope others will also
read what I wrote and speak up.  Let me know what
else I can add, if something's still unclear.
___

Some more background about my use case, in case it
helps or you're interested.  (The code is small,
in modeline-region.el - see URL below.)

Minor mode `modeline-region-mode' shows, in the
mode-line, whether the region is active (and some
info about its size - various counts etc.).

Standard Emacs commands such as search & replace
are advised when the mode is on, so that the
mode-line indication of the region status makes
clear that the current command is actually acting
on the region, not the buffer.  (The face used is
a bit different, to draw attention to this.)

Non-nil option `mlr-empty-region-flag' means show
the active-region indication in the mode-line even
when the region is empty.  It's non-nil by default,
because being told that you're acting on, or about
to act on, the empty region can save you some bother.

All of this description applies regardless of how
you select text - using the mouse or otherwise.

What was problematic, and the problem I wanted to
fix, was that if you clicked mouse-1 then an empty
region was briefly indicated spuriously.

This happened because as soon as you press mouse-1
the region is activated, even though as soon as
you release mouse-1 it is deactivated.  In this
case you momentarily saw, in the mode-line, an
indication of an activated empty region.  That
momentary display (~ a flash) was a bit bothersome.

I fixed that.  I think the problem is present also
for vanilla Emacs, and the same fix makes sense
for it.  That's what my message now is about: the
problem with `use-region-p' and a proposed fix.

Admittedly, unless you have some similar use case -
continually monitoring and indicating region
activation - you won't notice or care about the
problem.  And yes, if you don't use a mouse then
you also won't care about it.

I think it's worth it for Emacs to fix this corner
case, e.g., have `use-region-p' return nil when
the region is empty if mouse-1 is currently still
pressed.

Why?  Because you can't use the active region then,
and that's what `use-region-p' is for: saying when
you can use the active region.
___


Description:
https://www.emacswiki.org/emacs/ModeLineRegion

Code:
https://www.emacswiki.org/emacs/download/modeline-region.el

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

* Re: [External] : Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
  2021-11-08 18:32   ` [External] : " Drew Adams
@ 2021-11-09 11:29     ` tomas
  2021-11-09 16:17       ` Drew Adams
  0 siblings, 1 reply; 7+ messages in thread
From: tomas @ 2021-11-09 11:29 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel@gnu.org

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

On Mon, Nov 08, 2021 at 06:32:41PM +0000, Drew Adams wrote:
> Thanks for replying, Tomas.
> 
> > > I got no response to my question of how to tell
> > > whether `mouse-1' is still pressed during a click.
> > 
> > [...]
> > 
> > I read twice through your text and I'm still trying
> > to wrap my head around the gist of it.
> 
> Sorry for any confusion or difficulty.

Come on. No need to apologise.

> I can't tell if you mean that you had difficulty with
> (1) the original post, asking how to tell when mouse-1
> is pressed (the text you quoted) or with (2) my last
> message (with changed Subject), which is what you
> replied to.  Or perhaps you had difficulty with both?

The direct ref would be (2), but my confusion is so
diffuse that I'd take everything with its grain of
salt :)

> > My feeling (it mitght be totally wrong [...])

[...]

> The problem I described is only with the implementation
> of predicate `use-region-p'.  Its (minor) failing is
> only with a corner case: returning true between mouse-1
> down and up events during a click action (down & up at
> the same place).

Oh, I think I get it now. So I did the following experiment:

  (setq my-timer
        (run-with-timer 0 0.05
                        (lambda()
                          (message "%s  REG=%s"
                                   (current-time-string)
                                   (use-region-p)))))

The antidote is:

  (cancel-timer my-timer)

...I keep it around in the same buffer.

Now while the above is running, when I click with mouse-1, REG
says "nil" /until/ I move the mouse far enough that the region
is at least one char wide: then REG says t. If I go back to the
starting point (while keeping mouse-1 down all the time), REG
says nil again.

I'm not a heavy mouse user (TBH, I'm a reluctant mouse user),
but the above behaviour looks reasonable to me.

> Event `down-mouse-1' (button-down) activates the region,
  [...]

This doesn't happen for me. I've to drag the mouse a bit for
the region to become active (a bit: one char width, as far as
I can discern).

FWIW, that's "my" Emacs:

    This is GNU Emacs, one component of the GNU/Linux operating system.

    GNU Emacs 28.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 2.24.32,
    cairo version 1.16.0) of 2021-09-30

I haven't tried with -Q, but I would, if you think that
might shed more light on the topic.

> and event `mouse-1' (button-up) either (1) leaves it
> activated, if the positions of down & up differ, or (2)
> deactivates it, if those positions are the same.  (See
> function `mouse-drag-track' for details.)

I think we're seeing different things, so there might
still be a gap between what I think I've understood
and what I've actually understood :)

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* RE: [External] : Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
  2021-11-09 11:29     ` tomas
@ 2021-11-09 16:17       ` Drew Adams
  2021-11-09 16:58         ` tomas
  0 siblings, 1 reply; 7+ messages in thread
From: Drew Adams @ 2021-11-09 16:17 UTC (permalink / raw)
  To: tomas@tuxteam.de; +Cc: emacs-devel@gnu.org

> Oh, I think I get it now. So I did the following experiment:
> 
>   (setq my-timer
>         (run-with-timer 0 0.05
>                         (lambda()
>                           (message "%s  REG=%s"
>                                    (current-time-string)
>                                    (use-region-p)))))
...

Cool.  Thanks for trying, and looking into it.

> Now while the above is running, when I click with mouse-1, REG
> says "nil" /until/ I move the mouse far enough that the region
> is at least one char wide: then REG says t. If I go back to the
> starting point (while keeping mouse-1 down all the time), REG
> says nil again.

That's exactly right.  That's the point of the fix.

I know that you're talking about using that recipe
_without_ the fix.  And you're right, in what you say.

But only when option `use-empty-active-region' is nil.

The point of the fix is for the behavior you see to be
used even if that option is non-nil.

Why?  Because a click (down&up) always DEactivates the
region.  A click is a single action, from a user point
of view, even though it's realized using two events.

There really is no way, normally, to get an empty
active region with the mouse - other than keeping
mouse-1 pressed.

The aim of the fix I proposed is this: if you turn on
`use-empty-active-region'.  The region won't be
considered empty when mouse-1 is still pressed and at
the same position.

> I'm not a heavy mouse user (TBH, I'm a reluctant mouse user),

Many are in the same boat.  And that might be an
additional reason that this (admittedly corner) case
wasn't taken into account before.

> but the above behaviour looks reasonable to me.

It's the right behavior for both values of
`use-empty-active-region', IMO.  That's the point.

If you happen to agree then there are two of us... ;-)

> > Event `down-mouse-1' (button-down) activates the region,
> 
> This doesn't happen for me. I've to drag the mouse a bit for
> the region to become active (a bit: one char width, as far as
> I can discern).

It does happen - see the code.  It's just that your
recipe to test it uses `use-region-p' (without the
fix), and your value of `use-empty-active-region' is
nil.  Set that option to t and then try your recipe
again.

> I haven't tried with -Q, but I would, if you think that
> might shed more light on the topic.

(I used emacs -Q with Emacs 27.)

> > and event `mouse-1' (button-up) either (1) leaves it
> > activated, if the positions of down & up differ, or (2)
> > deactivates it, if those positions are the same.  (See
> > function `mouse-drag-track' for details.)
> 
> I think we're seeing different things, so there might
> still be a gap between what I think I've understood
> and what I've actually understood :)

I think the gap is just `use-empty-active-region'.
Set it to t and try your recipe.

That option is for users to tell Emacs how to handle
an active empty region.  IMO it shouldn't recognize
the momentary active empty region that is manifested
during a mouse-1 click (down&up at the same location).

That's really all there is to what I'm saying/proposing.

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

* Re: [External] : Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
  2021-11-09 16:17       ` Drew Adams
@ 2021-11-09 16:58         ` tomas
  0 siblings, 0 replies; 7+ messages in thread
From: tomas @ 2021-11-09 16:58 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel@gnu.org

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

On Tue, Nov 09, 2021 at 04:17:01PM +0000, Drew Adams wrote:
> > Oh, I think I get it now. So I did the following experiment:
> > 
> >   (setq my-timer
> >         (run-with-timer 0 0.05
> >                         (lambda()
> >                           (message "%s  REG=%s"
> >                                    (current-time-string)
> >                                    (use-region-p)))))
> ...
> 
> Cool.  Thanks for trying, and looking into it.
> 
> > Now while the above is running, when I click with mouse-1, REG
> > says "nil" /until/ I move the mouse far enough that the region
> > is at least one char wide: then REG says t. If I go back to the
> > starting point (while keeping mouse-1 down all the time), REG
> > says nil again.
> 
> That's exactly right.  That's the point of the fix.
> 
> I know that you're talking about using that recipe
> _without_ the fix.  And you're right, in what you say.
> 
> But only when option `use-empty-active-region' is nil.

Oh, now I see it, too. Thanks.

In this light, I'd think your fix makes sense.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

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

* Re: Fix for `use-region-p' problem   [was: Elisp test for whether `mouse-1' is pressed?]
@ 2021-11-15 17:48 Drew Adams
  0 siblings, 0 replies; 7+ messages in thread
From: Drew Adams @ 2021-11-15 17:48 UTC (permalink / raw)
  To: tomas@tuxteam.de; +Cc: emacs-devel@gnu.org

> Oh, now I see it, too. Thanks.
> In this light, I'd think your fix makes sense.

(Still no other response here.)  I've filed bug #51874.

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=51874

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

end of thread, other threads:[~2021-11-15 17:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-07 23:26 Fix for `use-region-p' problem [was: Elisp test for whether `mouse-1' is pressed?] Drew Adams
2021-11-08  8:28 ` tomas
2021-11-08 18:32   ` [External] : " Drew Adams
2021-11-09 11:29     ` tomas
2021-11-09 16:17       ` Drew Adams
2021-11-09 16:58         ` tomas
  -- strict thread matches above, loose matches on Subject: below --
2021-11-15 17:48 Drew Adams

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).