unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* mouse-drag-and-drop-region
@ 2017-11-14  9:54 martin rudalics
  2017-11-14 17:01 ` mouse-drag-and-drop-region Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-14  9:54 UTC (permalink / raw)
  To: emacs-devel, tak.kunihiro

Sorry for reacting late to the addition of ‘mouse-drag-and-drop-region’
but it never worked with multiple windows here so I had to find the
source of that problem first.  It turned out that having
‘mouse-autoselect-window’ non-nil interferes, because whenever the mouse
enters another window, a 'select-window' event will be generated which
the code should ignore.  I now installed the necessary change.

The code should ignore ‘switch-frame’ events too.  But this won't
accomplish much at the moment because to drag text from one frame to
another we need additional provisions.  In principle, Emacs should
always avoid switching frames during and after mouse tracking but I'm
not yet sure how to do that consistently.

Anyway, here are some comments:

(1) Why does the value selection happen within the ‘track-mouse’ form
     and why do you delete the mouse overlay?  That is, why don't we move
     this part

         (unless value-selection ; initialization
           (delete-overlay mouse-secondary-overlay)
           (setq value-selection (buffer-substring start end))
           (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)

     right to the beginning so we have something like

   (let* ((start (region-beginning))
          (end (region-end))
          (point (point))
          (buffer (current-buffer))
          (window (selected-window))
          (value-selection (buffer-substring start end)))
     (move-overlay mouse-secondary-overlay start end)
     (track-mouse
       ...

     there?

(2) Activating the secondary overlay can be distracting and should be
     made optional (facultatively keeping the primary overlay in place
     provided (4) below is done).

(3) Showing tooltips can be distracting and should be optional.  Note
     also, that usurping tooltips this way may prevent them from showing
     interesting properties of the drop area like whether the text there
     is read only.  OTOH we might consider retaining properties of the
     text in (non-GTK) tooltips.

(4) The (deactivate-mark) and (mouse-set-point event) trick to allow
     showing point the way ‘mouse-drag-track’ does can be distracting and
     should be made optional.

(5) The mouse pointer shape should take care of indicating the exact
     position where the drop occurs.  We should probably also signal
     whenever the current drop position is invalid.  This is IIUC usual
     practice on most window systems now.

(6) Dropping should allow to copy text into the region itself.  There's
     no reason forbidding that.

(7) IMO either cutting should be the default too when the drop occurs in
     a different buffer or copying would be the default and pressing the
     modifier should produce a cut instead.  The current behavior wants
     me to always keep in mind whether the target buffer is the same as
     the source buffer.  At least, this behavior should be made optional.

(8) Read-only text should be handled.  An attempt to drop text into a
     read-only area should be signalled to the user.  An attempt to cut
     text from a read-only text/buffer should be signalled as well.

(9) The code must become resilient against any failures by wrapping it
     into a ‘condition-case’ and doing the necessary clean up operations
     (restoring region and point, deleting the secondary overlay).

I think (8) and (9) should be fixed before the release.  As for future
releases we might also consider a ‘set-transient-map’ based solution.

Sincerely, martin




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

* Re: mouse-drag-and-drop-region
  2017-11-14  9:54 mouse-drag-and-drop-region martin rudalics
@ 2017-11-14 17:01 ` Eli Zaretskii
  2017-11-14 18:29   ` mouse-drag-and-drop-region martin rudalics
  2017-11-14 20:17 ` mouse-drag-and-drop-region Alex
  2017-11-16  0:28 ` mouse-drag-and-drop-region Tak Kunihiro
  2 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-14 17:01 UTC (permalink / raw)
  To: martin rudalics; +Cc: tak.kunihiro, emacs-devel

> Date: Tue, 14 Nov 2017 10:54:09 +0100
> From: martin rudalics <rudalics@gmx.at>
> 
> (8) Read-only text should be handled.  An attempt to drop text into a
>      read-only area should be signalled to the user.  An attempt to cut
>      text from a read-only text/buffer should be signalled as well.

For the latter, we copy text instead (cf C-w in read-only text).  So I
think this feature should behave similarly, at least by default.

Thanks for the review.



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

* Re: mouse-drag-and-drop-region
  2017-11-14 17:01 ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-14 18:29   ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-14 18:29 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tak.kunihiro, emacs-devel

 >> (8) Read-only text should be handled.  An attempt to drop text into a
 >>       read-only area should be signalled to the user.  An attempt to cut
 >>       text from a read-only text/buffer should be signalled as well.
 >
 > For the latter, we copy text instead (cf C-w in read-only text).  So I
 > think this feature should behave similarly, at least by default.

I just noticed that the code does use ‘kill-region’ already.  This has
the side-effect of putting the text into the kill ring, something which
should be documented at least.  But I think the code should rather use
‘delete-region’ instead with the behavior you proposed.

martin




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

* Re: mouse-drag-and-drop-region
  2017-11-14  9:54 mouse-drag-and-drop-region martin rudalics
  2017-11-14 17:01 ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-14 20:17 ` Alex
  2017-11-15  9:22   ` mouse-drag-and-drop-region martin rudalics
  2017-11-15 20:22   ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-16  0:28 ` mouse-drag-and-drop-region Tak Kunihiro
  2 siblings, 2 replies; 89+ messages in thread
From: Alex @ 2017-11-14 20:17 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

martin rudalics <rudalics@gmx.at> writes:


> Anyway, here are some comments:
>
> (1) Why does the value selection happen within the ‘track-mouse’ form
>     and why do you delete the mouse overlay?  That is, why don't we move
>     this part
>
>         (unless value-selection ; initialization
>           (delete-overlay mouse-secondary-overlay)
>           (setq value-selection (buffer-substring start end))
>           (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
>
>     right to the beginning so we have something like
>
>   (let* ((start (region-beginning))
>          (end (region-end))
>          (point (point))
>          (buffer (current-buffer))
>          (window (selected-window))
>          (value-selection (buffer-substring start end)))
>     (move-overlay mouse-secondary-overlay start end)
>     (track-mouse
>       ...
>
>     there?

I imagine that this has to do with inputting a non-mouse-movement event
before moving the mouse at all. If you use your change and press "C-g"
before moving the mouse, then the region will still be pasted.

Doing the above without your change currently results in an error due to
`insert' using a nil `value-selection', though.  So it's faulty either
way.

> (3) Showing tooltips can be distracting and should be optional.  Note
>     also, that usurping tooltips this way may prevent them from showing
>     interesting properties of the drop area like whether the text there
>     is read only.  OTOH we might consider retaining properties of the
>     text in (non-GTK) tooltips.

Also, trying to use `tooltip-show' in text-terminals using
`xterm-mouse-mode' yields a lot of "Error while displaying tooltip"
messages.

> I think (8) and (9) should be fixed before the release.  As for future
> releases we might also consider a ‘set-transient-map’ based solution.

Perhaps (3) should be fixed before release as well (at least disabling
tooltips when they can't be shown)?

Eli, would it be okay to make the same `read-event' -> `read-key' change
(specific to xt-mouse as in Bug#29150) here as well to tide over until
the function uses `set-transient-map'?  This appears to be the last
`read-event' present in mouse.el to get rid of.



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

* Re: mouse-drag-and-drop-region
  2017-11-14 20:17 ` mouse-drag-and-drop-region Alex
@ 2017-11-15  9:22   ` martin rudalics
  2017-11-15 18:22     ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-15 19:46     ` mouse-drag-and-drop-region Alex
  2017-11-15 20:22   ` mouse-drag-and-drop-region Eli Zaretskii
  1 sibling, 2 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-15  9:22 UTC (permalink / raw)
  To: Alex; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

 > I imagine that this has to do with inputting a non-mouse-movement event
 > before moving the mouse at all. If you use your change and press "C-g"
 > before moving the mouse, then the region will still be pasted.
 >
 > Doing the above without your change currently results in an error due to
 > `insert' using a nil `value-selection', though.  So it's faulty either
 > way.

I'm missing you.  Doesn't C-g deactivate the mark?

 >> (3) Showing tooltips can be distracting and should be optional.  Note
 >>      also, that usurping tooltips this way may prevent them from showing
 >>      interesting properties of the drop area like whether the text there
 >>      is read only.  OTOH we might consider retaining properties of the
 >>      text in (non-GTK) tooltips.
 >
 > Also, trying to use `tooltip-show' in text-terminals using
 > `xterm-mouse-mode' yields a lot of "Error while displaying tooltip"
 > messages.

That's a plain bug.  ‘tooltip-show’ on a text terminal must use the echo
area.

 > Perhaps (3) should be fixed before release as well (at least disabling
 > tooltips when they can't be shown)?

Sure.

martin




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

* Re: mouse-drag-and-drop-region
  2017-11-15  9:22   ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-15 18:22     ` Eli Zaretskii
  2017-11-15 18:50       ` mouse-drag-and-drop-region martin rudalics
  2017-11-15 19:46     ` mouse-drag-and-drop-region Alex
  1 sibling, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-15 18:22 UTC (permalink / raw)
  To: martin rudalics; +Cc: tak.kunihiro, agrambot, emacs-devel

> Date: Wed, 15 Nov 2017 10:22:45 +0100
> From: martin rudalics <rudalics@gmx.at>
> Cc: Eli Zaretskii <eliz@gnu.org>, tak.kunihiro@gmail.com,
> 	emacs-devel <emacs-devel@gnu.org>
> 
>  > Also, trying to use `tooltip-show' in text-terminals using
>  > `xterm-mouse-mode' yields a lot of "Error while displaying tooltip"
>  > messages.
> 
> That's a plain bug.  ‘tooltip-show’ on a text terminal must use the echo
> area.

It does, if you invoke it with 2nd argument non-nil.

It's not a bug, it's the intended behavior.



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

* Re: mouse-drag-and-drop-region
  2017-11-15 18:22     ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-15 18:50       ` martin rudalics
  2017-11-15 20:01         ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-15 18:50 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tak.kunihiro, agrambot, emacs-devel

 >> That's a plain bug.  ‘tooltip-show’ on a text terminal must use the echo
 >> area.
 >
 > It does, if you invoke it with 2nd argument non-nil.
 >
 > It's not a bug, it's the intended behavior.

It's a bug in 'mouse-drag-and-drop-region' obviously.

martin




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

* Re: mouse-drag-and-drop-region
  2017-11-15  9:22   ` mouse-drag-and-drop-region martin rudalics
  2017-11-15 18:22     ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-15 19:46     ` Alex
  2017-11-15 20:15       ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-16  9:04       ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 2 replies; 89+ messages in thread
From: Alex @ 2017-11-15 19:46 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> I imagine that this has to do with inputting a non-mouse-movement event
>> before moving the mouse at all. If you use your change and press "C-g"
>> before moving the mouse, then the region will still be pasted.
>>
>> Doing the above without your change currently results in an error due to
>> `insert' using a nil `value-selection', though.  So it's faulty either
>> way.
>
> I'm missing you.  Doesn't C-g deactivate the mark?

Usually, but I don't think it does in this case.  To be clear, it's not
just C-g that does this.  Here's a recipe:

1. Select a region.
2. Hold down-mouse-1 inside of this region.
3. Press any key before moving or releasing the mouse.

Doing this yields an error without your change, and it pastes the region
with your change.  Even when this key is C-g, `mark-active' is t after
step 3.

>>> (3) Showing tooltips can be distracting and should be optional.  Note
>>>      also, that usurping tooltips this way may prevent them from showing
>>>      interesting properties of the drop area like whether the text there
>>>      is read only.  OTOH we might consider retaining properties of the
>>>      text in (non-GTK) tooltips.
>>
>> Also, trying to use `tooltip-show' in text-terminals using
>> `xterm-mouse-mode' yields a lot of "Error while displaying tooltip"
>> messages.
>
> That's a plain bug.  ‘tooltip-show’ on a text terminal must use the echo
> area.
>
>> Perhaps (3) should be fixed before release as well (at least disabling
>> tooltips when they can't be shown)?
>
> Sure.

I suppose (display-graphic-p) should be supplied as the 2nd argument to
`tooltip-show', then?

I also noticed that when dragging in an X window, the tooltip flickers
quite a bit. Is there any easy remedy for this?  Removing the
`mouse-set-point' call in `track-mouse' helps in some cases, but not
completely.



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

* Re: mouse-drag-and-drop-region
  2017-11-15 18:50       ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-15 20:01         ` Eli Zaretskii
  2017-11-16  9:04           ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-15 20:01 UTC (permalink / raw)
  To: martin rudalics; +Cc: tak.kunihiro, agrambot, emacs-devel

> Date: Wed, 15 Nov 2017 19:50:26 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: tak.kunihiro@gmail.com, agrambot@gmail.com, emacs-devel@gnu.org
> 
>  >> That's a plain bug.  ‘tooltip-show’ on a text terminal must use the echo
>  >> area.
>  >
>  > It does, if you invoke it with 2nd argument non-nil.
>  >
>  > It's not a bug, it's the intended behavior.
> 
> It's a bug in 'mouse-drag-and-drop-region' obviously.

Right.  (I think it shouldn't show a tip on TTY frames, not in the
echo area, not anywhere.)



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

* Re: mouse-drag-and-drop-region
  2017-11-15 19:46     ` mouse-drag-and-drop-region Alex
@ 2017-11-15 20:15       ` Eli Zaretskii
  2017-11-15 22:03         ` mouse-drag-and-drop-region Alex
  2017-11-16  9:04       ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-15 20:15 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, tak.kunihiro, emacs-devel

> From: Alex <agrambot@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,  tak.kunihiro@gmail.com,  emacs-devel <emacs-devel@gnu.org>
> Date: Wed, 15 Nov 2017 13:46:42 -0600
> 
> I suppose (display-graphic-p) should be supplied as the 2nd argument to
> `tooltip-show', then?

display-multi-frame-p is more appropriate.  But I think the tooltip
should not be shown at all on TTY frames, it looks unnecessary and
even silly to show the dragged text in the echo area.

> I also noticed that when dragging in an X window, the tooltip flickers
> quite a bit. Is there any easy remedy for this?

We constantly redisplay the tooltip frame, don't we?  Or does this
happen only with GTK tooltips?



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

* Re: mouse-drag-and-drop-region
  2017-11-14 20:17 ` mouse-drag-and-drop-region Alex
  2017-11-15  9:22   ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-15 20:22   ` Eli Zaretskii
  1 sibling, 0 replies; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-15 20:22 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, tak.kunihiro, emacs-devel

> From: Alex <agrambot@gmail.com>
> Cc: emacs-devel <emacs-devel@gnu.org>,  tak.kunihiro@gmail.com, Eli Zaretskii <eliz@gnu.org>
> Date: Tue, 14 Nov 2017 14:17:25 -0600
> 
> Eli, would it be okay to make the same `read-event' -> `read-key' change
> (specific to xt-mouse as in Bug#29150) here as well to tide over until
> the function uses `set-transient-map'?

This is a new feature, so we can do that unconditionally.



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

* Re: mouse-drag-and-drop-region
  2017-11-15 20:15       ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-15 22:03         ` Alex
  2017-11-16 15:54           ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: Alex @ 2017-11-15 22:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, tak.kunihiro, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Alex <agrambot@gmail.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>,  tak.kunihiro@gmail.com,  emacs-devel <emacs-devel@gnu.org>
>> Date: Wed, 15 Nov 2017 13:46:42 -0600
>> 
>> I suppose (display-graphic-p) should be supplied as the 2nd argument to
>> `tooltip-show', then?
>
> display-multi-frame-p is more appropriate.

That appears to be an alias to `display-graphic-p'.

> But I think the tooltip should not be shown at all on TTY frames, it
> looks unnecessary and even silly to show the dragged text in the echo
> area.

That sounds better.  Though I wonder if tooltips could be shown in TTY
frames using a method similar to how `x-popup-menu' displays a menu in
them?

>> I also noticed that when dragging in an X window, the tooltip flickers
>> quite a bit. Is there any easy remedy for this?
>
> We constantly redisplay the tooltip frame, don't we?  Or does this
> happen only with GTK tooltips?

I don't know the details, but it appears that there are some redisplay
cycles that don't show the tooltip, leading to flickering.

I've only tested this with GTK tooltips so far.

There's also a side issue that subsequent mouse-movement events appear
to only be generated after moving a character rather than by a
configurable amount of pixels, which leads to the tooltip movement being
a bit jerky.



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

* Re: mouse-drag-and-drop-region
  2017-11-14  9:54 mouse-drag-and-drop-region martin rudalics
  2017-11-14 17:01 ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-14 20:17 ` mouse-drag-and-drop-region Alex
@ 2017-11-16  0:28 ` Tak Kunihiro
  2017-11-16  9:11   ` mouse-drag-and-drop-region martin rudalics
  2 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-11-16  0:28 UTC (permalink / raw)
  To: rudalics; +Cc: tak.kunihiro, emacs-devel

> (1) Why does the value selection happen within the ‘track-mouse’
>     form and why do you delete the mouse overlay?  That is, why
>     don't we move this part
>
>         (unless value-selection ; initialization
>           (delete-overlay mouse-secondary-overlay)
>           (setq value-selection (buffer-substring
>           start end))
>           (move-overlay mouse-secondary-overlay
>           start end)) ; (deactivate-mark)
>
>     right to the beginning so we have something like
>
>   (let* ((start (region-beginning))
>          (end (region-end))
>          (point (point))
>          (buffer (current-buffer))
>          (window (selected-window))
>          (value-selection (buffer-substring start
>          end)))
>     (move-overlay mouse-secondary-overlay start
>     end)
>     (track-mouse
>       ...
>
>     there?

There could be two operations that are `click' and `drag'.  Later on
line 40, value-selection is also used to identify whether operation is
`drag'.  Probably code should be improved.

39:  ;; "drag negligible" or "drag to read-only", restore region.
40:  (value-selection
41:   (select-window window) ; In case miss drag to other window
42:   (goto-char point)

> (2) Activating the secondary overlay can be distracting and should
>     be made optional (facultatively keeping the primary overlay in
>     place provided (4) below is done).

Region on the other window is not visible.  Thus original region
should be hi-lighted somehow.  Since mouse-drag-and-drop-region is
located on mouse.el, mouse-secondary-overlay was used.

Do you suggest to have option such like
 (defvar mouse-drag-and-drop-region-overlay 'mouse-secondary-overlay)
?

> (3) Showing tooltips can be distracting and should be optional.
>     Note also, that usurping tooltips this way may prevent them from
>     showing interesting properties of the drop area like whether the
>     text there is read only.  OTOH we might consider retaining
>     properties of the text in (non-GTK) tooltips.

Do you suggest to have option like
 (defvar mouse-drag-and-drop-region-preview t)
or implement other way to show the text besides using tooltips?

> (4) The (deactivate-mark) and (mouse-set-point event) trick to allow
>     showing point the way ‘mouse-drag-track’ does can be distracting
>     and should be made optional.

I think that this is very related to 2, 3, and 5 (as you inferred).

> (5) The mouse pointer shape should take care of indicating the exact
>     position where the drop occurs.  We should probably also signal
>     whenever the current drop position is invalid.  This is IIUC
>     usual practice on most window systems now.

I think it is a good idea.

> (6) Dropping should allow to copy text into the region itself.
>     There's no reason forbidding that.

I suppose that you mean when drop onto region itself with key pressed.
I agree.

> (7) IMO either cutting should be the default too when the drop
>     occurs in a different buffer or copying would be the default and
>     pressing the modifier should produce a cut instead.  The current
>     behavior wants me to always keep in mind whether the target
>     buffer is the same as the source buffer.  At least, this
>     behavior should be made optional.

Default behavior followed that of file browser on `drag' a file.
Between the same volume (buffer), `drag' does `cut' instead of `copy'.
I prefer current behavior as default but have
no objection to have option something like
 (defvar mouse-drag-and-drop-region-cut-hungry t)
.

> (8) Read-only text should be handled.  An attempt to drop text into
>     a read-only area should be signalled to the user.  An attempt to
>     cut text from a read-only text/buffer should be signalled as
>     well.

> For the latter, we copy text instead (cf C-w in read-only text).  So
> I think this feature should behave similarly, at least by default.

> I just noticed that the code does use ‘kill-region’ already.  This
> has the side-effect of putting the text into the kill ring,
> something which should be documented at least.  But I think the code
> should rather use ‘delete-region’ instead with the behavior you
> proposed.

I suppose that you suggest to tell user more explicitly in echo area
how he cannot change the text.  I am not against the suggestion.

On an user perspective, operation `drag-and-drop-region' is a
combination of `cut' and `paste'.  Thus text was killed instead of
deleted.  How you think delete is more preferred?  I have no objection
to document it.

> (9) The code must become resilient against any failures by wrapping
>     it into a ‘condition-case’ and doing the necessary clean up
>     operations (restoring region and point, deleting the secondary
>     overlay).
>
> I think (8) and (9) should be fixed before the release.  As for
> future releases we might also consider a ‘set-transient-map’ based
> solution.

No objection.  There is other thread about mouse-drag-and-drop-region.

https://lists.gnu.org/archive/html/emacs-devel/2017-10/msg00588.html

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

* Re: mouse-drag-and-drop-region
  2017-11-15 19:46     ` mouse-drag-and-drop-region Alex
  2017-11-15 20:15       ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-16  9:04       ` martin rudalics
  2017-11-17  6:02         ` mouse-drag-and-drop-region Alex
  1 sibling, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-16  9:04 UTC (permalink / raw)
  To: Alex; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

 > 1. Select a region.
 > 2. Hold down-mouse-1 inside of this region.
 > 3. Press any key before moving or releasing the mouse.
 >
 > Doing this yields an error without your change,

Something like

mouse-drag-region: Wrong type argument: char-or-string-p, nil

I suppose.  'value-selection' must have been nil then.

 > and it pastes the region
 > with your change.  Even when this key is C-g, `mark-active' is t after
 > step 3.

Not much better.  But doing mouse-down and pressing another key at the
same time is somewhat obscure behavior.

 > I suppose (display-graphic-p) should be supplied as the 2nd argument to
 > `tooltip-show', then?

For example, yes.

 > I also noticed that when dragging in an X window, the tooltip flickers
 > quite a bit. Is there any easy remedy for this?  Removing the
 > `mouse-set-point' call in `track-mouse' helps in some cases, but not
 > completely.

Would customizing 'tooltip-reuse-hidden-frame' change anything or are
you using GTK tooltips?

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-15 20:01         ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-16  9:04           ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-16  9:04 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tak.kunihiro, agrambot, emacs-devel

 > Right.  (I think it shouldn't show a tip on TTY frames, not in the
 > echo area, not anywhere.)

Agreed.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-16  0:28 ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-11-16  9:11   ` martin rudalics
  2017-11-20 13:29     ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-16  9:11 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: emacs-devel

 > There could be two operations that are `click' and `drag'.  Later on
 > line 40, value-selection is also used to identify whether operation is
 > `drag'.  Probably code should be improved.

Did you ever consider using the "r" interactive switch instead of the
"e" one?

 >> (2) Activating the secondary overlay can be distracting and should
 >>      be made optional (facultatively keeping the primary overlay in
 >>      place provided (4) below is done).
 >
 > Region on the other window is not visible.  Thus original region
 > should be hi-lighted somehow.  Since mouse-drag-and-drop-region is
 > located on mouse.el, mouse-secondary-overlay was used.

You mean that you highlight the original region with the secondary
overlay so that the overlay shows up on the target window as well and
the user is informed that dropping there might lead to say "dubious"
results?

 > Do you suggest to have option such like
 >   (defvar mouse-drag-and-drop-region-overlay 'mouse-secondary-overlay)
 > ?

I mean something like

(defcustom mouse-drag-and-drop-region-show-secondary-overlay t ...)

where setting this to nil means to just not show any overlay.  And your
code would have to accept that there is no secondary overlay at the time
of the drop.

 >> (3) Showing tooltips can be distracting and should be optional.
 >>      Note also, that usurping tooltips this way may prevent them from
 >>      showing interesting properties of the drop area like whether the
 >>      text there is read only.  OTOH we might consider retaining
 >>      properties of the text in (non-GTK) tooltips.
 >
 > Do you suggest to have option like
 >   (defvar mouse-drag-and-drop-region-preview t)
 > or implement other way to show the text besides using tooltips?

I would say

(defcustom mouse-drag-and-drop-region-show-tooltip t)

and never show a tooltip on text-only terminals even if this is t.

 >> (4) The (deactivate-mark) and (mouse-set-point event) trick to allow
 >>      showing point the way ‘mouse-drag-track’ does can be distracting
 >>      and should be made optional.
 >
 > I think that this is very related to 2, 3, and 5 (as you inferred).

Yes.  It's irritating to drag a block cursor with the mouse.  Do you
know of any other applications which do such a thing?

 >> (5) The mouse pointer shape should take care of indicating the exact
 >>      position where the drop occurs.  We should probably also signal
 >>      whenever the current drop position is invalid.  This is IIUC
 >>      usual practice on most window systems now.
 >
 > I think it is a good idea.

We probably need to define additional cursors for this so it's not for
Emacs 26.

 >> (7) IMO either cutting should be the default too when the drop
 >>      occurs in a different buffer or copying would be the default and
 >>      pressing the modifier should produce a cut instead.  The current
 >>      behavior wants me to always keep in mind whether the target
 >>      buffer is the same as the source buffer.  At least, this
 >>      behavior should be made optional.
 >
 > Default behavior followed that of file browser on `drag' a file.

Which file browser?

 > Between the same volume (buffer), `drag' does `cut' instead of `copy'.
 > I prefer current behavior as default but have
 > no objection to have option something like
 >   (defvar mouse-drag-and-drop-region-cut-hungry t)

I would be more radical with

(defcustom mouse-drag-and-drop-region-cut-or-copy t)

where the values 'cut and 'copy would always categorically cut or copy
(unless the value of 'mouse-drag-and-drop-region' implies to copy
instead of cut) and t means your original behavior.

 >> (8) Read-only text should be handled.  An attempt to drop text into
 >>      a read-only area should be signalled to the user.  An attempt to
 >>      cut text from a read-only text/buffer should be signalled as
 >>      well.
 >
 >> For the latter, we copy text instead (cf C-w in read-only text).  So
 >> I think this feature should behave similarly, at least by default.
 >
 >> I just noticed that the code does use ‘kill-region’ already.  This
 >> has the side-effect of putting the text into the kill ring,
 >> something which should be documented at least.  But I think the code
 >> should rather use ‘delete-region’ instead with the behavior you
 >> proposed.
 >
 > I suppose that you suggest to tell user more explicitly in echo area
 > how he cannot change the text.

The echo area should be avoided during tracking.  Think of users who
invoke 'mouse-drag-and-drop-region' on a frame without a minibuffer.

I think that first of all you should use 'delete-region' instead of
'kill-region' to avoid the above-mentioned side effect.  Then your code
should silently swallow any bugs for cutting from read-only text
provided 'kill-read-only-ok' is t.  For that purpose, simply peruse the
corresponding code from 'kill-region'.

A final drop into read-only text should always give an error.  We should
be able to redeem that by providing a feedback in form of a mouse cursor
when the mouse is either over read-only text or no buffer text at all.

 > On an user perspective, operation `drag-and-drop-region' is a
 > combination of `cut' and `paste'.  Thus text was killed instead of
 > deleted.  How you think delete is more preferred?  I have no objection
 > to document it.

IMO using 'kill-region' is an unexpected side effect.  If people
think differently, we could add yet another option like

(defucstom mouse-drag-and-drop-region-cut-does-kill-region t)

 > There is other thread about mouse-drag-and-drop-region.
 >
 > https://lists.gnu.org/archive/html/emacs-devel/2017-10/msg00588.html

I'm aware of that.  I have changed some Emacs internals to make it work
here but I have no idea of the consequences these changes might have for
other mouse-tracking functions.  So this is strictly for Emacs 27.

Thanks, martin




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

* Re: mouse-drag-and-drop-region
  2017-11-15 22:03         ` mouse-drag-and-drop-region Alex
@ 2017-11-16 15:54           ` Eli Zaretskii
  2017-11-17  6:33             ` mouse-drag-and-drop-region Alex
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-16 15:54 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, tak.kunihiro, emacs-devel

> From: Alex <agrambot@gmail.com>
> Cc: rudalics@gmx.at,  tak.kunihiro@gmail.com,  emacs-devel@gnu.org
> Date: Wed, 15 Nov 2017 16:03:17 -0600
> 
> >> I suppose (display-graphic-p) should be supplied as the 2nd argument to
> >> `tooltip-show', then?
> >
> > display-multi-frame-p is more appropriate.
> 
> That appears to be an alias to `display-graphic-p'.

That's an implementation detail.  But even if it will always remain
the alias, using it still conveys the intent more clearly that
display-graphic-p, don't you agree?

> > But I think the tooltip should not be shown at all on TTY frames, it
> > looks unnecessary and even silly to show the dragged text in the echo
> > area.
> 
> That sounds better.  Though I wonder if tooltips could be shown in TTY
> frames using a method similar to how `x-popup-menu' displays a menu in
> them?

No, it can't.  TTY menus pre-empt the command loop, so they cannot be
shown during mouse-tracking, AFAIR.

> >> I also noticed that when dragging in an X window, the tooltip flickers
> >> quite a bit. Is there any easy remedy for this?
> >
> > We constantly redisplay the tooltip frame, don't we?  Or does this
> > happen only with GTK tooltips?
> 
> I don't know the details, but it appears that there are some redisplay
> cycles that don't show the tooltip, leading to flickering.
> 
> I've only tested this with GTK tooltips so far.

Does the flickering disappear if you set x-gtk-use-system-tooltips to
nil?

> There's also a side issue that subsequent mouse-movement events appear
> to only be generated after moving a character rather than by a
> configurable amount of pixels, which leads to the tooltip movement being
> a bit jerky.

If that, too, disappears when GTK tooltips are not used, then maybe
it's due to the way we show GTK tooltips.



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

* Re: mouse-drag-and-drop-region
  2017-11-16  9:04       ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-17  6:02         ` Alex
  2017-11-17  8:53           ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Alex @ 2017-11-17  6:02 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> 1. Select a region.
>> 2. Hold down-mouse-1 inside of this region.
>> 3. Press any key before moving or releasing the mouse.
>>
>> Doing this yields an error without your change,
>
> Something like
>
> mouse-drag-region: Wrong type argument: char-or-string-p, nil
>
> I suppose.  'value-selection' must have been nil then.

Right, that's the issue. Or perhaps _an_ issue, since `kill-region' is
sent nil arguments in this case.

>> and it pastes the region
>> with your change.  Even when this key is C-g, `mark-active' is t after
>> step 3.
>
> Not much better.  But doing mouse-down and pressing another key at the
> same time is somewhat obscure behavior.

Somewhat obscure, but it should be handled better, right?

>> I also noticed that when dragging in an X window, the tooltip flickers
>> quite a bit. Is there any easy remedy for this?  Removing the
>> `mouse-set-point' call in `track-mouse' helps in some cases, but not
>> completely.
>
> Would customizing 'tooltip-reuse-hidden-frame' change anything or are
> you using GTK tooltips?

It appears that it only happens with GTK tooltips.



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

* Re: mouse-drag-and-drop-region
  2017-11-16 15:54           ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-17  6:33             ` Alex
  2017-11-17  7:33               ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-17  8:53               ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 2 replies; 89+ messages in thread
From: Alex @ 2017-11-17  6:33 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, tak.kunihiro, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> > display-multi-frame-p is more appropriate.
>> 
>> That appears to be an alias to `display-graphic-p'.
>
> That's an implementation detail.  But even if it will always remain
> the alias, using it still conveys the intent more clearly that
> display-graphic-p, don't you agree?

Yeah, I agree.

>> > But I think the tooltip should not be shown at all on TTY frames, it
>> > looks unnecessary and even silly to show the dragged text in the echo
>> > area.
>> 
>> That sounds better.  Though I wonder if tooltips could be shown in TTY
>> frames using a method similar to how `x-popup-menu' displays a menu in
>> them?
>
> No, it can't.  TTY menus pre-empt the command loop, so they cannot be
> shown during mouse-tracking, AFAIR.

I didn't mean to use menus directly, but to use a similar method of
displaying something "on top of" a TTY frame.  Is displaying the
rectangle that makes up a menu necessarily incompatible with a regular
command loop?  If so, do you know why?

>> > We constantly redisplay the tooltip frame, don't we?  Or does this
>> > happen only with GTK tooltips?
>> 
>> I don't know the details, but it appears that there are some redisplay
>> cycles that don't show the tooltip, leading to flickering.
>> 
>> I've only tested this with GTK tooltips so far.
>
> Does the flickering disappear if you set x-gtk-use-system-tooltips to
> nil?

Yes, it appears that only GTK tooltips are affected here.  Should I file
a bug report?

>> There's also a side issue that subsequent mouse-movement events appear
>> to only be generated after moving a character rather than by a
>> configurable amount of pixels, which leads to the tooltip movement being
>> a bit jerky.
>
> If that, too, disappears when GTK tooltips are not used, then maybe
> it's due to the way we show GTK tooltips.

I don't believe this one has to do with GTK.  If you set `track-mouse' to
t, then, after the first pixel movement, you will only see
mouse-movement events when you move the mouse to a whole character
position.  This might be intentional, but I think it's poor behaviour.



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

* Re: mouse-drag-and-drop-region
  2017-11-17  6:33             ` mouse-drag-and-drop-region Alex
@ 2017-11-17  7:33               ` Eli Zaretskii
  2017-11-17 15:58                 ` mouse-drag-and-drop-region Stefan Monnier
  2017-11-18  6:48                 ` mouse-drag-and-drop-region Alex
  2017-11-17  8:53               ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 2 replies; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-17  7:33 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, tak.kunihiro, emacs-devel

> From: Alex <agrambot@gmail.com>
> Cc: rudalics@gmx.at,  tak.kunihiro@gmail.com,  emacs-devel@gnu.org
> Date: Fri, 17 Nov 2017 00:33:48 -0600
> 
> >> That sounds better.  Though I wonder if tooltips could be shown in TTY
> >> frames using a method similar to how `x-popup-menu' displays a menu in
> >> them?
> >
> > No, it can't.  TTY menus pre-empt the command loop, so they cannot be
> > shown during mouse-tracking, AFAIR.
> 
> I didn't mean to use menus directly, but to use a similar method of
> displaying something "on top of" a TTY frame.  Is displaying the
> rectangle that makes up a menu necessarily incompatible with a regular
> command loop?

Yes, it is incompatible.

> If so, do you know why?

Because TTY menus are implemented by overwriting parts of the glyph
matrix with text that comes "out of nowhere", as far as the normal
redisplay is concerned.  IOW, there's no buffer or display string or
overlay string that the display engine knows about that produce this
text.  So if we let the command loop do its thing, it will eventually
enter redisplay, and the menu will be erased, partially or fully.

> > Does the flickering disappear if you set x-gtk-use-system-tooltips to
> > nil?
> 
> Yes, it appears that only GTK tooltips are affected here.  Should I file
> a bug report?

Yes, of course.  Though I doubt we have the expertise to fix it (or
maybe it's even unfixable as long as we implement the GTK support the
way we do).

> >> There's also a side issue that subsequent mouse-movement events appear
> >> to only be generated after moving a character rather than by a
> >> configurable amount of pixels, which leads to the tooltip movement being
> >> a bit jerky.
> >
> > If that, too, disappears when GTK tooltips are not used, then maybe
> > it's due to the way we show GTK tooltips.
> 
> I don't believe this one has to do with GTK.  If you set `track-mouse' to
> t, then, after the first pixel movement, you will only see
> mouse-movement events when you move the mouse to a whole character
> position.  This might be intentional, but I think it's poor behaviour.

Can you show a Lisp recipe to reproduce this?



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

* Re: mouse-drag-and-drop-region
  2017-11-17  6:02         ` mouse-drag-and-drop-region Alex
@ 2017-11-17  8:53           ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-17  8:53 UTC (permalink / raw)
  To: Alex; +Cc: Eli Zaretskii, tak.kunihiro, emacs-devel

 >> Not much better.  But doing mouse-down and pressing another key at the
 >> same time is somewhat obscure behavior.
 >
 > Somewhat obscure, but it should be handled better, right?

Right.

 > It appears that it only happens with GTK tooltips.

GTK tooltips are a pain.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-17  6:33             ` mouse-drag-and-drop-region Alex
  2017-11-17  7:33               ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-17  8:53               ` martin rudalics
  2017-11-18  6:49                 ` mouse-drag-and-drop-region Alex
  1 sibling, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-17  8:53 UTC (permalink / raw)
  To: Alex, Eli Zaretskii; +Cc: tak.kunihiro, emacs-devel

 > I don't believe this one has to do with GTK.  If you set `track-mouse' to
 > t, then, after the first pixel movement, you will only see
 > mouse-movement events when you move the mouse to a whole character
 > position.  This might be intentional, but I think it's poor behaviour.

Does anything change when setting 'frame-resize-pixelwise' to t?

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-17  7:33               ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-17 15:58                 ` Stefan Monnier
  2017-11-17 16:39                   ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-18  6:48                 ` mouse-drag-and-drop-region Alex
  1 sibling, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-17 15:58 UTC (permalink / raw)
  To: emacs-devel

>> >> That sounds better.  Though I wonder if tooltips could be shown in TTY
>> >> frames using a method similar to how `x-popup-menu' displays a menu in
>> >> them?
[...]
> Because TTY menus are implemented by overwriting parts of the glyph
> matrix with text that comes "out of nowhere", as far as the normal
> redisplay is concerned.

If we really wanted, we could implement some kind of tooltips in
a similar way, tho:

- overwrite parts of the glyph matrix
- register some "pre-redisplay hook"
- return to the normal command loop

the "pre-redisplay hook" would then remove the tooltip-overwrite from the
glyph matrix before the redisplay bumps into it.  Then if we want the
tooltip to last longer than "until the next redisplay" (which sounds
rather likely), we'd need some way to re-add the tooltip after the
redisplay is done.

Sounds pretty ugly/messy, obviously.

A more general solution could be to add two more glyph matrices (one for
overlay thingies like menus and tooltips, and another that combines the
"normal" glyph matrix with the one for overlay thingies (and it's this
one which is then sent to be displayed)).


        Stefan




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

* Re: mouse-drag-and-drop-region
  2017-11-17 15:58                 ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-17 16:39                   ` Eli Zaretskii
  2017-11-17 22:44                     ` mouse-drag-and-drop-region Stefan Monnier
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-17 16:39 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Date: Fri, 17 Nov 2017 10:58:57 -0500
> 
> > Because TTY menus are implemented by overwriting parts of the glyph
> > matrix with text that comes "out of nowhere", as far as the normal
> > redisplay is concerned.
> 
> If we really wanted, we could implement some kind of tooltips in
> a similar way, tho:
> 
> - overwrite parts of the glyph matrix
> - register some "pre-redisplay hook"
> - return to the normal command loop
> 
> the "pre-redisplay hook" would then remove the tooltip-overwrite from the
> glyph matrix before the redisplay bumps into it.  Then if we want the
> tooltip to last longer than "until the next redisplay" (which sounds
> rather likely), we'd need some way to re-add the tooltip after the
> redisplay is done.
> 
> Sounds pretty ugly/messy, obviously.

Not only that, it probably won't work without much more ugliness to
support it.

> A more general solution could be to add two more glyph matrices (one for
> overlay thingies like menus and tooltips, and another that combines the
> "normal" glyph matrix with the one for overlay thingies (and it's this
> one which is then sent to be displayed)).

I don't see how this solves the problem, because the display engine
will still know nothing about that "second" matrix.

The only way to make TTY menus a first-class display citizen is to
come up with some object which the display engine would routinely
consult in deciding what to display in a window.  Right now, it
consults the text of the buffer pointed to by the window, and any Lisp
strings related to the buffer.  We need something else to add to this
soup, and the problem with that something is that it spans several
lines, but only part of each line.  Maybe it should be modeled on the
mouse-highlight, with the assumption of a rectangular region added...



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

* Re: mouse-drag-and-drop-region
  2017-11-17 16:39                   ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-17 22:44                     ` Stefan Monnier
  2017-11-18  7:54                       ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-17 22:44 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>> A more general solution could be to add two more glyph matrices (one for
>> overlay thingies like menus and tooltips, and another that combines the
>> "normal" glyph matrix with the one for overlay thingies (and it's this
>> one which is then sent to be displayed)).
> I don't see how this solves the problem, because the display engine
> will still know nothing about that "second" matrix.

As mentioned: "it's this one which is then sent to be displayed", so
this assumes we'd change the display engine to use the combined matrix:

    render buffer text to desired-glyph-matrix
    combine desired-glyph-matrix with overlay-matrix into combined-matrix
    send combined-matrix to screen


-- Stefan



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

* Re: mouse-drag-and-drop-region
  2017-11-17  7:33               ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-17 15:58                 ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-18  6:48                 ` Alex
  2017-11-18  9:07                   ` mouse-drag-and-drop-region Eli Zaretskii
  1 sibling, 1 reply; 89+ messages in thread
From: Alex @ 2017-11-18  6:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, tak.kunihiro, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:
>> If so, do you know why?
>
> Because TTY menus are implemented by overwriting parts of the glyph
> matrix with text that comes "out of nowhere", as far as the normal
> redisplay is concerned.  IOW, there's no buffer or display string or
> overlay string that the display engine knows about that produce this
> text.  So if we let the command loop do its thing, it will eventually
> enter redisplay, and the menu will be erased, partially or fully.

Oh, that's unfortunate.  Thanks for the explanation.

>> > If that, too, disappears when GTK tooltips are not used, then maybe
>> > it's due to the way we show GTK tooltips.
>> 
>> I don't believe this one has to do with GTK.  If you set `track-mouse' to
>> t, then, after the first pixel movement, you will only see
>> mouse-movement events when you move the mouse to a whole character
>> position.  This might be intentional, but I think it's poor behaviour.
>
> Can you show a Lisp recipe to reproduce this?

  (setq track-mouse t)
  (setq count 0)

  (global-set-key [mouse-movement]
                  (lambda ()
                    (interactive)
                    (message "%d" (setq count (1+ count)))))

This will only message on the first mouse-movement event (after a
non-mouse-movement event), and after moving to a new character position.
It also messages after a down-click, which feels like a bug.



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

* Re: mouse-drag-and-drop-region
  2017-11-17  8:53               ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-18  6:49                 ` Alex
  0 siblings, 0 replies; 89+ messages in thread
From: Alex @ 2017-11-18  6:49 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, emacs-devel

martin rudalics <rudalics@gmx.at> writes:

>> I don't believe this one has to do with GTK.  If you set `track-mouse' to
>> t, then, after the first pixel movement, you will only see
>> mouse-movement events when you move the mouse to a whole character
>> position.  This might be intentional, but I think it's poor behaviour.
>
> Does anything change when setting 'frame-resize-pixelwise' to t?
>
> martin

No, unfortunately.



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

* Re: mouse-drag-and-drop-region
  2017-11-17 22:44                     ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-18  7:54                       ` Eli Zaretskii
  2017-11-18 14:36                         ` mouse-drag-and-drop-region Stefan Monnier
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-18  7:54 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: emacs-devel@gnu.org
> Date: Fri, 17 Nov 2017 17:44:02 -0500
> 
> > I don't see how this solves the problem, because the display engine
> > will still know nothing about that "second" matrix.
> 
> As mentioned: "it's this one which is then sent to be displayed", so
> this assumes we'd change the display engine to use the combined matrix:
> 
>     render buffer text to desired-glyph-matrix
>     combine desired-glyph-matrix with overlay-matrix into combined-matrix
>     send combined-matrix to screen

If you mean that literally, then the above will disable (almost) all
redisplay optimizations, and will cause Emacs always to display each
window in its entirety.  Redisplay optimizations require that Emacs be
able to _reason_ about parts of the window display being unchanged, by
looking at the related objects and variables -- buffers, overlays,
etc.  You introduce a factor into this equation about which Emacs will
not be able to reason, because its relation to the other objects is
unknown.

E.g., the most frequent redisplay use case is cursor movement with no
other changes.  This case is detected and handled specially, because
it must be fast.  How will that work with your proposal, when cursor
motion will (or could) change some parts in that "second" matrix?

Am I missing something?



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

* Re: mouse-drag-and-drop-region
  2017-11-18  6:48                 ` mouse-drag-and-drop-region Alex
@ 2017-11-18  9:07                   ` Eli Zaretskii
  2017-11-18 21:58                     ` mouse-drag-and-drop-region Alex
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-18  9:07 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, tak.kunihiro, emacs-devel

> From: Alex <agrambot@gmail.com>
> Date: Sat, 18 Nov 2017 00:48:27 -0600
> Cc: rudalics@gmx.at, tak.kunihiro@gmail.com, emacs-devel@gnu.org
> 
> Eli Zaretskii <eliz@gnu.org> writes:
> >> If so, do you know why?
> >
> > Because TTY menus are implemented by overwriting parts of the glyph
> > matrix with text that comes "out of nowhere", as far as the normal
> > redisplay is concerned.  IOW, there's no buffer or display string or
> > overlay string that the display engine knows about that produce this
> > text.  So if we let the command loop do its thing, it will eventually
> > enter redisplay, and the menu will be erased, partially or fully.
> 
> Oh, that's unfortunate.

If you or someone else has better ideas for implementing menus on a
TTY, let's hear them.

> >> I don't believe this one has to do with GTK.  If you set `track-mouse' to
> >> t, then, after the first pixel movement, you will only see
> >> mouse-movement events when you move the mouse to a whole character
> >> position.  This might be intentional, but I think it's poor behaviour.
> >
> > Can you show a Lisp recipe to reproduce this?
> 
>   (setq track-mouse t)
>   (setq count 0)
> 
>   (global-set-key [mouse-movement]
>                   (lambda ()
>                     (interactive)
>                     (message "%d" (setq count (1+ count)))))
> 
> This will only message on the first mouse-movement event (after a
> non-mouse-movement event), and after moving to a new character position.

That's the intended behavior, see note_mouse_movement.

> It also messages after a down-click, which feels like a bug.

Not here, it doesn't.  I only see a message after a movement to
another glyph.



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

* Re: mouse-drag-and-drop-region
  2017-11-18  7:54                       ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-18 14:36                         ` Stefan Monnier
  2017-11-18 15:04                           ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-18 14:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>> render buffer text to desired-glyph-matrix
>> combine desired-glyph-matrix with overlay-matrix into combined-matrix
>> send combined-matrix to screen
> If you mean that literally, then the above will disable (almost) all
> redisplay optimizations, and will cause Emacs always to display each
> window in its entirety.
> Redisplay optimizations require that Emacs be
> able to _reason_ about parts of the window display being unchanged, by
> looking at the related objects and variables -- buffers, overlays,
> etc.

The above is the *model*.  I'd describe the current model as:

    render buffer text to glyph-matrix
    send glyph-matrix to screen

both models are amenable to various optimizations.  Most of the
optimizations applicable to the current model should be applicable to
the other as well.


        Stefan



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

* Re: mouse-drag-and-drop-region
  2017-11-18 14:36                         ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-18 15:04                           ` Eli Zaretskii
  2017-11-18 15:49                             ` mouse-drag-and-drop-region Stefan Monnier
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-18 15:04 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: emacs-devel@gnu.org
> Date: Sat, 18 Nov 2017 09:36:40 -0500
> 
> > Redisplay optimizations require that Emacs be
> > able to _reason_ about parts of the window display being unchanged, by
> > looking at the related objects and variables -- buffers, overlays,
> > etc.
> 
> The above is the *model*.  I'd describe the current model as:
> 
>     render buffer text to glyph-matrix
>     send glyph-matrix to screen

This model is incomplete.  Emacs first tries to reuse (parts of) the
current matrix, if that's possible given the information about what
has changed since the last redisplay cycle.  It only generates a new
("desired") glyph matrix if the attempt to reuse the current one
failed.

In addition, AFAIR there are situations when only small portions of
the desired matrix are generated.  When doing this, Emacs must be able
to decide which parts don't need to be regenerated.

> both models are amenable to various optimizations.  Most of the
> optimizations applicable to the current model should be applicable to
> the other as well.

If you are thinking about reviewing the existing optimizations and
changing them to account for the new model, including adding some new
optimization methods, then I'm sure it's possible.  But it's a large
job, and I cannot promise that the result will be acceptable,
performance-wise, unless very deep changes are done in the control and
logic flow of the current code.

IOW, I think the way redisplay is implemented simply isn't ready for
such changes.  The current implementation of the TTY menus was
proposed by Gerd Möllmann, the author of the current display engine;
if something like what you suggest were feasible, he'd most probably
mention it when this was discussed.  He didn't.  Of course, it's
possible that he simply didn't think about such an alternative, but I
personally find that unlikely.



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

* Re: mouse-drag-and-drop-region
  2017-11-18 15:04                           ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-18 15:49                             ` Stefan Monnier
  0 siblings, 0 replies; 89+ messages in thread
From: Stefan Monnier @ 2017-11-18 15:49 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

> This model is incomplete.  Emacs first tries to reuse (parts of) the
> current matrix, if that's possible given the information about what
> has changed since the last redisplay cycle.  It only generates a new
> ("desired") glyph matrix if the attempt to reuse the current one
> failed.
> In addition, AFAIR there are situations when only small portions of
> the desired matrix are generated.  When doing this, Emacs must be able
> to decide which parts don't need to be regenerated.

Right.  These are optimizations which would apply identically to the
other model, (where the "current matrix" would be the "desired matrix"
computed last time, rather than the "combined matrix" computed last
time).

> If you are thinking about reviewing the existing optimizations and
> changing them to account for the new model, including adding some new
> optimization methods, then I'm sure it's possible.  But it's a large
> job, and I cannot promise that the result will be acceptable,
> performance-wise, unless very deep changes are done in the control and
> logic flow of the current code.

Indeed.  I'm pretty sure it can be done with good enough performance,
but I do not know how much work it would take.


        Stefan



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

* Re: mouse-drag-and-drop-region
  2017-11-18  9:07                   ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-18 21:58                     ` Alex
  2017-11-19 15:27                       ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: Alex @ 2017-11-18 21:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

>> > Can you show a Lisp recipe to reproduce this?
>> 
>>   (setq track-mouse t)
>>   (setq count 0)
>> 
>>   (global-set-key [mouse-movement]
>>                   (lambda ()
>>                     (interactive)
>>                     (message "%d" (setq count (1+ count)))))
>> 
>> This will only message on the first mouse-movement event (after a
>> non-mouse-movement event), and after moving to a new character position.
>
> That's the intended behavior, see note_mouse_movement.

Thanks for pointing me to it.  I can understand the intention, but I
think it would be useful to be able to track the mouse with every pixel
change in addition to the current behaviour.  On topic, it should make
dragging the tooltip a lot smoother.

Would such a feature be considered?  I'm not sure what the best way to
implement it would be; perhaps a new value for track-mouse?  Then
note_mouse_movement could conditionally use last_mouse_motion_{x,y}?

>> It also messages after a down-click, which feels like a bug.
>
> Not here, it doesn't.  I only see a message after a movement to
> another glyph.

That's odd, you can't reproduce it at all?  On my end, I sometimes have
to click a few times (sometimes slowly) before an erroneous message
appears.



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

* Re: mouse-drag-and-drop-region
  2017-11-18 21:58                     ` mouse-drag-and-drop-region Alex
@ 2017-11-19 15:27                       ` Eli Zaretskii
  0 siblings, 0 replies; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-19 15:27 UTC (permalink / raw)
  To: Alex; +Cc: rudalics, emacs-devel

> From: Alex <agrambot@gmail.com>
> Cc: rudalics@gmx.at, emacs-devel@gnu.org
> Date: Sat, 18 Nov 2017 15:58:17 -0600
> 
> >> This will only message on the first mouse-movement event (after a
> >> non-mouse-movement event), and after moving to a new character position.
> >
> > That's the intended behavior, see note_mouse_movement.
> 
> Thanks for pointing me to it.  I can understand the intention, but I
> think it would be useful to be able to track the mouse with every pixel
> change in addition to the current behaviour.  On topic, it should make
> dragging the tooltip a lot smoother.

Does it, indeed?  Did you try that?

> Would such a feature be considered?

What other uses would it have except this one (assuming it helps
there)?  It will certainly flood Emacs with input events, the question
is: is that justified?

> >> It also messages after a down-click, which feels like a bug.
> >
> > Not here, it doesn't.  I only see a message after a movement to
> > another glyph.
> 
> That's odd, you can't reproduce it at all?

No.

> On my end, I sometimes have to click a few times (sometimes slowly)
> before an erroneous message appears.

GTK issue again, perhaps?



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

* Re: mouse-drag-and-drop-region
  2017-11-16  9:11   ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-20 13:29     ` Tak Kunihiro
  2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 2 replies; 89+ messages in thread
From: Tak Kunihiro @ 2017-11-20 13:29 UTC (permalink / raw)
  To: rudalics, Eli Zaretskii, Alex; +Cc: tak.kunihiro, emacs-devel

I revised mouse-drag-and-drop-region.  I'm sending replay to
https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00387.html,
ChangeLog, and patch.

* ChangeLog

2017-11-21 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>

        Improve comments and have two new options

        * lisp/mouse.el (mouse-drag-and-drop-region): Make tooltip preview to be an option.  Have an option to make dragging cut among buffers.
        (mouse-drag-and-drop-region-cut-among-buffer): New flag.  When t, text is cut instead of copy when dragged among buffers.
        (mouse-drag-and-drop-region-show-tooltip): New flag.  When t, text is shown by a tooltip in a graphic display.

* Replay

> Did you ever consider using the "r" interactive switch instead of the
> "e" one?

I suppose you suggest something like below.  I cannot make this work.
Thus this revision, I do not use "r" interactive switch.

(defun mouse-drag-and-drop-region (event start and)
  (interactive "e\nr")
  ...)

>>> (2) Activating the secondary overlay can be distracting and should
>>>     be made optional (facultatively keeping the primary overlay in
>>>     place provided (4) below is done).
>>
>> Region on the other window is not visible.  Thus original region
>> should be hi-lighted somehow.  Since mouse-drag-and-drop-region is
>> located on mouse.el, mouse-secondary-overlay was used.
>
> You mean that you highlight the original region with the secondary
> overlay so that the overlay shows up on the target window as well and
> the user is informed that dropping there might lead to say "dubious"
> results?

I think yes.  Also, since value-selection would be inserted before the
point and mark, I thought it is handy to keep track where was the
region by an overlay.

> I mean something like
>
> (defcustom mouse-drag-and-drop-region-show-secondary-overlay t ...)
>
> where setting this to nil means to just not show any overlay.  And
> your code would have to accept that there is no secondary overlay at
> the time of the drop.

I found this takes significant time.  I skip to get rid of usage of
secondary-overlay on this revision.

>>> (3) Showing tooltips can be distracting and should be optional.
>>>     Note also, that usurping tooltips this way may prevent them from
>>>     showing interesting properties of the drop area like whether the
>>>     text there is read only.  OTOH we might consider retaining
>>>     properties of the text in (non-GTK) tooltips.
>>
> I would say
>
> (defcustom mouse-drag-and-drop-region-show-tooltip t)
>
> and never show a tooltip on text-only terminals even if this is t.

OK.

>>> (4) The (deactivate-mark) and (mouse-set-point event) trick to allow
>>>     showing point the way ‘mouse-drag-track’ does can be distracting
>>>     and should be made optional.
>>
>> I think that this is very related to 2, 3, and 5 (as you inferred).
>
> Yes.  It's irritating to drag a block cursor with the mouse.  Do you
> know of any other applications which do such a thing?

I cannot think of a way to show insert point besides (mouse-set-point
event).  Do you suggest overlay-put "|" or change cursor-type to 'bar
during drag?  I thought who prefers bar changes the default cursor
anyway.  I did not revise code in this respect.

>>> (5) The mouse pointer shape should take care of indicating the exact
>>>     position where the drop occurs.  We should probably also signal
>>>     whenever the current drop position is invalid.  This is IIUC
>>>     usual practice on most window systems now.
>>
>> I think it is a good idea.
>
> We probably need to define additional cursors for this so it's not for
> Emacs 26.

I did not revise code in this aspect.

>>> (7) IMO either cutting should be the default too when the drop
>>>     occurs in a different buffer or copying would be the default and
>>>     pressing the modifier should produce a cut instead.  The current
>>>     behavior wants me to always keep in mind whether the target
>>>     buffer is the same as the source buffer.  At least, this
>>>     behavior should be made optional.
>>
>> Default behavior followed that of file browser on `drag' a file.
>
> Which file browser?

Finder on macOS and File Explorer on Windows 10 behave like that way.

>> Between the same volume (buffer), `drag' does `cut' instead of `copy'.
>> I prefer current behavior as default but have
>> no objection to have option something like
>>   (defvar mouse-drag-and-drop-region-cut-hungry t)
>
> I would be more radical with
>
> (defcustom mouse-drag-and-drop-region-cut-or-copy t)
>
> where the values 'cut and 'copy would always categorically cut or copy
> (unless the value of 'mouse-drag-and-drop-region' implies to copy
> instead of cut) and t means your original behavior.

A new option was created.  Now `cut' can be default even among
buffers.

(defvar mouse-drag-and-drop-region-cut-among-buffer nil
  "When t, text is cut instead of copy when dragged among buffers.")

>>> (8) Read-only text should be handled.  An attempt to drop text into
>>>     a read-only area should be signalled to the user.  An attempt to
>>>     cut text from a read-only text/buffer should be signalled as
>>>     well.
>>
>>> For the latter, we copy text instead (cf C-w in read-only text).  So
>>> I think this feature should behave similarly, at least by default.
>>
>>> I just noticed that the code does use ‘kill-region’ already.  This
>>> has the side-effect of putting the text into the kill ring,
>>> something which should be documented at least.  But I think the code
>>> should rather use ‘delete-region’ instead with the behavior you
>>> proposed.
>>
>> I suppose that you suggest to tell user more explicitly in echo area
>> how he cannot change the text.
>
> The echo area should be avoided during tracking.  Think of users who
> invoke 'mouse-drag-and-drop-region' on a frame without a minibuffer.

OK.

> I think that first of all you should use 'delete-region' instead of
> 'kill-region' to avoid the above-mentioned side effect.  Then your
> code should silently swallow any bugs for cutting from read-only
> text provided 'kill-read-only-ok' is t.  For that purpose, simply
> peruse the corresponding code from 'kill-region'.

OK.  Now `delete-region' is used.

> A final drop into read-only text should always give an error.  We
> should be able to redeem that by providing a feedback in form of a
> mouse cursor when the mouse is either over read-only text or no
> buffer text at all.

I revised only to give message.  I could not tell how to bring
condition-case to code.

>> On an user perspective, operation `drag-and-drop-region' is a
>> combination of `cut' and `paste'.  Thus text was killed instead of
>> deleted.  How you think delete is more preferred?  I have no
>> objection to document it.

> IMO using 'kill-region' is an unexpected side effect.  If people
> think differently, we could add yet another option like
>
> (defucstom mouse-drag-and-drop-region-cut-does-kill-region t)

Now `delete-region' is used instead of `kill-region'.

* Patch

diff --git a/lisp/mouse.el b/lisp/mouse.el
old mode 100644
new mode 100755
index 17d1732..08f70d4
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,12 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defvar mouse-drag-and-drop-region-cut-among-buffer nil
+  "When t, text is cut instead of copy when dragged among buffers.")
+
+(defvar mouse-drag-and-drop-region-show-tooltip t
+  "When t, text is shown by a tooltip in a graphic display.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,64 +2375,98 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
+  (let ((mouse-drag-and-drop-region-show-tooltip
+         (and mouse-drag-and-drop-region-show-tooltip
+              (display-multi-frame-p)
+              (require 'tooltip)))
+        (start (region-beginning))
         (end (region-end))
         (point (point))
         (buffer (current-buffer))
         (window (selected-window))
-        value-selection)
+        no-modifier-on-drop
+        value-selection)    ; This remains nil when event was "click".
     (track-mouse
-      ;; When event was click instead of drag, skip loop
+      ;; When event was "click" instead of "drag", skip loop.
       (while (progn
                (setq event (read-event))
                (or (mouse-movement-p event)
                    ;; Handle `mouse-autoselect-window'.
                    (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
+        ;; Obtain the text in region.  When the loop was skipped,
+        ;; value-selection remains nil.
+        (unless value-selection
           (delete-overlay mouse-secondary-overlay)
           (setq value-selection (buffer-substring start end))
           (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
+        (ignore-errors
+          (deactivate-mark)         ; Maintain region in other window.
+          (mouse-set-point event)
+          (when mouse-drag-and-drop-region-show-tooltip
+            (tooltip-show value-selection))))
+      ;; Check if modifier was pressed on drop.
+      (setq no-modifier-on-drop
+            (not (member mouse-drag-and-drop-region (event-modifiers event))))
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide)))
+    ;; Do not modify buffer under mouse when event is "click", "drag
+    ;; but negligible", or "drag to read-only".  Operation "drag but
+    ;; negligible" is defined as drag-and-drop the text to
+    ;; secondary-selection without modifier pressed.  When pressed,
+    ;; the text will be inserted to inside of secondary-selection.
+    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "click"
+            (and (member 'secondary-selection ; "drag but negligible"
+                         (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                 (overlays-at (posn-point (event-end event)))))
+                 no-modifier-on-drop)
+            buffer-read-only)           ; "drag to read-only"
         (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
+         ;; Set back the original text as region on "drag but negligible"
+         ;; or "drag to read-only".
          (value-selection
-          (select-window window) ; In case miss drag to other window
+          (if buffer-read-only (message "Buffer is read-only")) ; (barf-if-buffer-read-only)
+          (select-window window) ; Select the source windows back on miss-drag to other window.
           (goto-char point)
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
+         ;; Move point within region on "click".
          (t
           (deactivate-mark)
           (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
+      ;; Intert the text to destination buffer under mouse.
       (push-mark)
       (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
+      ;; On success, set the text as region on destination buffer.
+      (when (not (equal (mark) (point)))
         (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
+        (activate-mark))
+      ;; Set back the original text as region or delete the original
+      ;; text on source buffer.
+      (if (equal (current-buffer) buffer)
+          ;; When source buffer and destination buffer are the same,
+          ;; remove the original text.
+          (let (deactivate-mark)
+            (if no-modifier-on-drop
+                (delete-region (overlay-start mouse-secondary-overlay)
+                               (overlay-end mouse-secondary-overlay))))
+        ;; When source buffer and destination buffer are different,
+        ;; keep (set back the original text as region) or remove the
+        ;; original text.
+        (let ((window1 (selected-window)))
+          (select-window window)   ; Select window with source buffer.
+          (goto-char point) ; Move point to the original text on source buffer.
+          (if (or (if no-modifier-on-drop
+                      (not mouse-drag-and-drop-region-cut-among-buffer)
+                    mouse-drag-and-drop-region-cut-among-buffer)
+                  buffer-read-only)
+              ;; Set back the original text as region on source buffer
+              ;; like operation `copy'.
+              (progn
+                (if buffer-read-only (message "Source is read-only")) ; (barf-if-buffer-read-only)
+                (activate-mark))
+            ;; Remove the original text from source buffer like
+            ;; operation `cut'.
+            (delete-region (overlay-start mouse-secondary-overlay)
+                           (overlay-end mouse-secondary-overlay)))
           (select-window window1))))
     (delete-overlay mouse-secondary-overlay)))
 \f

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

* RE: mouse-drag-and-drop-region
  2017-11-20 13:29     ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-11-20 16:03       ` Drew Adams
  2017-11-20 16:09         ` mouse-drag-and-drop-region Alan Schmitt
                           ` (2 more replies)
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 3 replies; 89+ messages in thread
From: Drew Adams @ 2017-11-20 16:03 UTC (permalink / raw)
  To: Tak Kunihiro, rudalics, Eli Zaretskii, Alex; +Cc: emacs-devel

FWIW, your mails are incomprehensible, to me.  A long
jumble, with (apparently) no newlines, just one long line.

> -----Original Message-----
> From: Tak Kunihiro [mailto:tak.kunihiro@gmail.com]
> Sent: Monday, November 20, 2017 5:30 AM
> To: rudalics@gmx.at; Eli Zaretskii <eliz@gnu.org>; Alex
> <agrambot@gmail.com>
> Cc: tak.kunihiro@gmail.com; emacs-devel@gnu.org
> Subject: Re: mouse-drag-and-drop-region
> 
> I revised mouse-drag-and-drop-region.  I'm sending replay
> tohttps://urldefense.proofpoint.com/v2/url?u=https-
> 3A__lists.gnu.org_archive_html_emacs-2Ddevel_2017-
> 2D11_msg00387.html&d=DwIGCQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE
> &r=kI3P6ljGv6CTHIKju0jqInF6AOwMCYRDQUmqX22rJ98&m=7dAC1SXS16w1t_k03RCaPT4y
> x9Dj2w0sgzE9HrhKdH4&s=i_DYhSyvTHRfqzR6fFgh4X_gjdsRoGvmXF4Fq-z-
> eEU&e=,ChangeLog, and patch.* ChangeLog2017-11-21 Tak Kunihiro
> <tkk@misasa.okayama-u.ac.jp>        Improve comments and have two new
> options        * lisp/mouse.el (mouse-drag-and-drop-region): Make tooltip
> preview to be an option.  Have an option to make dragging cut among
> buffers.        (mouse-drag-and-drop-region-cut-among-buffer): New flag.
> When t, text is cut instead of copy when dragged among buffers.
> (mouse-drag-and-drop-region-show-tooltip): New flag.  When t, text is
> shown by a tooltip in a graphic display.* Replay> Did you ever consider
> using the "r" interactive switch instead of the> "e" one?I suppose you
> suggest something like below.  I cannot make this work.Thus this
> revision, I do not use "r" interactive switch.(defun mouse-drag-and-drop-
> region (event start and)  (interactive "e\nr")  ...)>>> (2) Activating
> the secondary overlay can be distracting and should>>>     be made
> optional (facultatively keeping the primary overlay in>>>     place
> provided (4) below is done).>>>> Region on the other window is not
> visible.  Thus original region>> should be hi-lighted somehow.  Since
> mouse-drag-and-drop-region is>> located on mouse.el, mouse-secondary-
> overlay was used.>> You mean that you highlight the original region with
> the secondary> overlay so that the overlay shows up on the target window
> as well and> the user is informed that dropping there might lead to say
> "dubious"> results?I think yes.  Also, since value-selection would be
> inserted before thepoint and mark, I thought it is handy to keep track
> where was theregion by an overlay.> I mean something like>> (defcustom
> mouse-drag-and-drop-region-show-secondary-overlay t ...)>> where setting
> this to nil means to just not show any overlay.  And> your code would
> have to accept that there is no secondary overlay at> the time of the
> drop.I found this takes significant time.  I skip to get rid of usage
> ofsecondary-overlay on this revision.>>> (3) Showing tooltips can be
> distracting and should be optional.>>>     Note also, that usurping
> tooltips this way may prevent them from>>>     showing interesting
> properties of the drop area like whether the>>>     text there is read
> only.  OTOH we might consider retaining>>>     properties of the text in
> (non-GTK) tooltips.>>> I would say>> (defcustom mouse-drag-and-drop-
> region-show-tooltip t)>> and never show a tooltip on text-only terminals
> even if this is t.OK.>>> (4) The (deactivate-mark) and (mouse-set-point
> event) trick to allow>>>     showing point the way ?mouse-drag-track?
> does can be distracting>>>     and should be made optional.>>>> I think
> that this is very related to 2, 3, and 5 (as you inferred).>> Yes.  It's
> irritating to drag a block cursor with the mouse.  Do you> know of any
> other applications which do such a thing?I cannot think of a way to show
> insert point besides (mouse-set-pointevent).  Do you suggest overlay-put
> "|" or change cursor-type to 'barduring drag?  I thought who prefers bar
> changes the default cursoranyway.  I did not revise code in this
> respect.>>> (5) The mouse pointer shape should take care of indicating
> the exact>>>     position where the drop occurs.  We should probably also
> signal>>>     whenever the current drop position is invalid.  This is
> IIUC>>>     usual practice on most window systems now.>>>> I think it is
> a good idea.>> We probably need to define additional cursors for this so
> it's not for> Emacs 26.I did not revise code in this aspect.>>> (7) IMO
> either cutting should be the default too when the drop>>>     occurs in a
> different buffer or copying would be the default and>>>     pressing the
> modifier should produce a cut instead.  The current>>>     behavior wants
> me to always keep in mind whether the target>>>     buffer is the same as
> the source buffer.  At least, this>>>     behavior should be made
> optional.>>>> Default behavior followed that of file browser on `drag' a
> file.>> Which file browser?Finder on macOS and File Explorer on Windows
> 10 behave like that way.>> Between the same volume (buffer), `drag' does
> `cut' instead of `copy'.>> I prefer current behavior as default but
> have>> no objection to have option something like>>   (defvar mouse-drag-
> and-drop-region-cut-hungry t)>> I would be more radical with>> (defcustom
> mouse-drag-and-drop-region-cut-or-copy t)>> where the values 'cut and
> 'copy would always categorically cut or copy> (unless the value of
> 'mouse-drag-and-drop-region' implies to copy> instead of cut) and t means
> your original behavior.A new option was created.  Now `cut' can be
> default even amongbuffers.(defvar mouse-drag-and-drop-region-cut-among-
> buffer nil  "When t, text is cut instead of copy when dragged among
> buffers.")>>> (8) Read-only text should be handled.  An attempt to drop
> text into>>>     a read-only area should be signalled to the user.  An
> attempt to>>>     cut text from a read-only text/buffer should be
> signalled as>>>     well.>>>>> For the latter, we copy text instead (cf
> C-w in read-only text).  So>>> I think this feature should behave
> similarly, at least by default.>>>>> I just noticed that the code does
> use ?kill-region? already.  This>>> has the side-effect of putting the
> text into the kill ring,>>> something which should be documented at
> least.  But I think the code>>> should rather use ?delete-region? instead
> with the behavior you>>> proposed.>>>> I suppose that you suggest to tell
> user more explicitly in echo area>> how he cannot change the text.>> The
> echo area should be avoided during tracking.  Think of users who> invoke
> 'mouse-drag-and-drop-region' on a frame without a minibuffer.OK.> I think
> that first of all you should use 'delete-region' instead of> 'kill-
> region' to avoid the above-mentioned side effect.  Then your> code should
> silently swallow any bugs for cutting from read-only> text provided
> 'kill-read-only-ok' is t.  For that purpose, simply> peruse the
> corresponding code from 'kill-region'.OK.  Now `delete-region' is used.>
> A final drop into read-only text should always give an error.  We> should
> be able to redeem that by providing a feedback in form of a> mouse cursor
> when the mouse is either over read-only text or no> buffer text at all.I
> revised only to give message.  I could not tell how to bringcondition-
> case to code.>> On an user perspective, operation `drag-and-drop-region'
> is a>> combination of `cut' and `paste'.  Thus text was killed instead
> of>> deleted.  How you think delete is more preferred?  I have no>>
> objection to document it.> IMO using 'kill-region' is an unexpected side
> effect.  If people> think differently, we could add yet another option
> like>> (defucstom mouse-drag-and-drop-region-cut-does-kill-region t)Now
> `delete-region' is used instead of `kill-region'.* Patchdiff --git
> a/lisp/mouse.el b/lisp/mouse.elold mode 100644new mode 100755index
> 17d1732..08f70d4--- a/lisp/mouse.el+++ b/lisp/mouse.el@@ -2361,6 +2361,12
> @@ text is copied instead of being cut."   :version "26.1"   :group
> 'mouse) +(defvar mouse-drag-and-drop-region-cut-among-buffer nil+  "When
> t, text is cut instead of copy when dragged among buffers.")++(defvar
> mouse-drag-and-drop-region-show-tooltip t+  "When t, text is shown by a
> tooltip in a graphic display.")+ (defun mouse-drag-and-drop-region
> (event)   "Move text in the region to point where mouse is dragged to.
> The transportation of text is also referred as `drag and drop'.@@ -
> 2369,64 +2375,98 @@ modifier key was pressed when dropping, and the value
> of the variable `mouse-drag-and-drop-region' is that modifier, the text
> is copied instead of being cut."   (interactive "e")-  (require
> 'tooltip)-  (let ((start (region-beginning))+  (let ((mouse-drag-and-
> drop-region-show-tooltip+         (and mouse-drag-and-drop-region-show-
> tooltip+              (display-multi-frame-p)+              (require
> 'tooltip)))+        (start (region-beginning))         (end (region-end))
> (point (point))         (buffer (current-buffer))         (window
> (selected-window))-        value-selection)+        no-modifier-on-drop+
> value-selection)    ; This remains nil when event was "click".
> (track-mouse-      ;; When event was click instead of drag, skip loop+
> ;; When event was "click" instead of "drag", skip loop.       (while
> (progn                (setq event (read-event))                (or
> (mouse-movement-p event)                    ;; Handle `mouse-autoselect-
> window'.                    (eq (car-safe event) 'select-window)))-
> (unless value-selection ; initialization+        ;; Obtain the text in
> region.  When the loop was skipped,+        ;; value-selection remains
> nil.+        (unless value-selection           (delete-overlay mouse-
> secondary-overlay)           (setq value-selection (buffer-substring
> start end))           (move-overlay mouse-secondary-overlay start end)) ;
> (deactivate-mark)-        (ignore-errors (deactivate-mark) ; care
> existing region in other window-                       (mouse-set-point
> event)-                       (tooltip-show value-selection)))-
> (tooltip-hide))-    ;; Do not modify buffer under mouse when "event was
> click",-    ;;                                       "drag negligible",
> or-    ;;                                       "drag to read-only".-
> (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ;
> "event was click"-            (member 'secondary-selection ; "drag
> negligible"-                    (mapcar (lambda (xxx) (overlay-get xxx
> 'face))-                            (overlays-at (posn-point (event-end
> event)))))-            buffer-read-only)-        ;; Do not modify buffer
> under mouse.+        (ignore-errors+          (deactivate-mark)         ;
> Maintain region in other window.+          (mouse-set-point event)+
> (when mouse-drag-and-drop-region-show-tooltip+            (tooltip-show
> value-selection))))+      ;; Check if modifier was pressed on drop.+
> (setq no-modifier-on-drop+            (not (member mouse-drag-and-drop-
> region (event-modifiers event))))+      (when mouse-drag-and-drop-region-
> show-tooltip (tooltip-hide)))+    ;; Do not modify buffer under mouse
> when event is "click", "drag+    ;; but negligible", or "drag to read-
> only".  Operation "drag but+    ;; negligible" is defined as drag-and-
> drop the text to+    ;; secondary-selection without modifier pressed.
> When pressed,+    ;; the text will be inserted to inside of secondary-
> selection.+    (if (or (equal (mouse-posn-property (event-end event)
> 'face) 'region) ; "click"+            (and (member 'secondary-selection ;
> "drag but negligible"+                         (mapcar (lambda (xxx)
> (overlay-get xxx 'face))+                                 (overlays-at
> (posn-point (event-end event)))))+                 no-modifier-on-drop)+
> buffer-read-only)           ; "drag to read-only"         (cond-
> ;; "drag negligible" or "drag to read-only", restore region.+         ;;
> Set back the original text as region on "drag but negligible"+         ;;
> or "drag to read-only".          (value-selection-          (select-
> window window) ; In case miss drag to other window+          (if buffer-
> read-only (message "Buffer is read-only")) ; (barf-if-buffer-read-only)+
> (select-window window) ; Select the source windows back on miss-drag to
> other window.           (goto-char point)           (setq deactivate-mark
> nil)           (activate-mark))-         ;; "event was click"+         ;;
> Move point within region on "click".          (t           (deactivate-
> mark)           (mouse-set-point event)))-      ;; Modify buffer under
> mouse by inserting text.+      ;; Intert the text to destination buffer
> under mouse.       (push-mark)       (insert value-selection)-      (when
> (not (equal (mark) (point))) ; on success insert+      ;; On success, set
> the text as region on destination buffer.+      (when (not (equal (mark)
> (point)))         (setq deactivate-mark nil)-        (activate-mark)) ;
> have region on destination-      ;; Take care of initial region on
> source.-      (if (equal (current-buffer) buffer) ; when same buffer-
> (let (deactivate-mark) ; remove text-            (unless (member mouse-
> drag-and-drop-region (event-modifiers event))-              (kill-region
> (overlay-start mouse-secondary-overlay)-
> (overlay-end mouse-secondary-overlay))))-        (let ((window1
> (selected-window))) ; when beyond buffer-          (select-window
> window)-          (goto-char point) ; restore point on source window-
> (activate-mark) ; restore region+        (activate-mark))+      ;; Set
> back the original text as region or delete the original+      ;; text on
> source buffer.+      (if (equal (current-buffer) buffer)+          ;;
> When source buffer and destination buffer are the same,+          ;;
> remove the original text.+          (let (deactivate-mark)+
> (if no-modifier-on-drop+                (delete-region (overlay-start
> mouse-secondary-overlay)+                               (overlay-end
> mouse-secondary-overlay))))+        ;; When source buffer and destination
> buffer are different,+        ;; keep (set back the original text as
> region) or remove the+        ;; original text.+        (let ((window1
> (selected-window)))+          (select-window window)   ; Select window
> with source buffer.+          (goto-char point) ; Move point to the
> original text on source buffer.+          (if (or (if no-modifier-on-
> drop+                      (not mouse-drag-and-drop-region-cut-among-
> buffer)+                    mouse-drag-and-drop-region-cut-among-buffer)+
> buffer-read-only)+              ;; Set back the original text as region
> on source buffer+              ;; like operation `copy'.+
> (progn+                (if buffer-read-only (message "Source is read-
> only")) ; (barf-if-buffer-read-only)+                (activate-mark))+
> ;; Remove the original text from source buffer like+            ;;
> operation `cut'.+            (delete-region (overlay-start mouse-
> secondary-overlay)+                           (overlay-end mouse-
> secondary-overlay)))           (select-window window1))))     (delete-
> overlay mouse-secondary-overlay)))



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

* Re: mouse-drag-and-drop-region
  2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
@ 2017-11-20 16:09         ` Alan Schmitt
  2017-11-20 17:34         ` mouse-drag-and-drop-region Eli Zaretskii
  2017-11-20 18:17         ` mouse-drag-and-drop-region Paul Eggert
  2 siblings, 0 replies; 89+ messages in thread
From: Alan Schmitt @ 2017-11-20 16:09 UTC (permalink / raw)
  To: emacs-devel

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

On 2017-11-20 08:03, Drew Adams <drew.adams@oracle.com> writes:

> FWIW, your mails are incomprehensible, to me.  A long
> jumble, with (apparently) no newlines, just one long line.

They look good here (using gnus).

Best,

Alan

-- 
OpenPGP Key ID : 040D0A3B4ED2E5C7
Monthly Athmospheric CO₂, Mauna Loa Obs. 2017-10: 403.64, 2016-10: 401.57

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 528 bytes --]

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

* Re: mouse-drag-and-drop-region
  2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
  2017-11-20 16:09         ` mouse-drag-and-drop-region Alan Schmitt
@ 2017-11-20 17:34         ` Eli Zaretskii
  2017-11-20 18:17         ` mouse-drag-and-drop-region Paul Eggert
  2 siblings, 0 replies; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-20 17:34 UTC (permalink / raw)
  To: Drew Adams; +Cc: rudalics, tak.kunihiro, agrambot, emacs-devel

> Date: Mon, 20 Nov 2017 08:03:41 -0800 (PST)
> From: Drew Adams <drew.adams@oracle.com>
> Cc: emacs-devel@gnu.org
> 
> FWIW, your mails are incomprehensible, to me.  A long
> jumble, with (apparently) no newlines, just one long line.

May I suggest to change your MUA?  Those emails are perfectly legible
in Emacs's Rmail, for example.



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

* Re: mouse-drag-and-drop-region
  2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
  2017-11-20 16:09         ` mouse-drag-and-drop-region Alan Schmitt
  2017-11-20 17:34         ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-20 18:17         ` Paul Eggert
  2 siblings, 0 replies; 89+ messages in thread
From: Paul Eggert @ 2017-11-20 18:17 UTC (permalink / raw)
  To: Drew Adams, Tak Kunihiro; +Cc: emacs-devel

On 11/20/2017 08:03 AM, Drew Adams wrote:
> FWIW, your mails are incomprehensible, to me.  A long
> jumble, with (apparently) no newlines, just one long line.

You might try switching to a better mailer, since the mail is in a 
standard format, namely Content-Type: Text/Plain; charset=iso-8859-7 
(Latin/Greek), Content-Transfer-Encoding: base64. I decoded it by hand 
and it looks fine, so it appears that the problem is on your end. 
Perhaps you can save the mail to a file, and then use Gnus or Rmail to 
read the file, since they can handle the format.

Your mailer identifies itself as "Oracle Beehive Extensions for Outlook 
2.0.1.9.1 (1003210) [OL 16.0.4615.0 (x86)]", so another possibility is 
for you to fix your mailer's bug yourself, or ask one of your colleagues 
at Oracle to fix it.




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

* Re: mouse-drag-and-drop-region
  2017-11-20 13:29     ` mouse-drag-and-drop-region Tak Kunihiro
  2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
@ 2017-11-21  9:24       ` martin rudalics
  2017-11-21 13:09         ` mouse-drag-and-drop-region Stefan Monnier
                           ` (3 more replies)
  1 sibling, 4 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-21  9:24 UTC (permalink / raw)
  To: Tak Kunihiro, Eli Zaretskii, Alex; +Cc: emacs-devel

 >> Did you ever consider using the "r" interactive switch instead of the
 >> "e" one?
 >
 > I suppose you suggest something like below.  I cannot make this work.
 > Thus this revision, I do not use "r" interactive switch.
 >
 > (defun mouse-drag-and-drop-region (event start and)
 >    (interactive "e\nr")
 >    ...)

We would probably have to change 'mouse-drag-region' for that to work.

 >> I mean something like
 >>
 >> (defcustom mouse-drag-and-drop-region-show-secondary-overlay t ...)
 >>
 >> where setting this to nil means to just not show any overlay.  And
 >> your code would have to accept that there is no secondary overlay at
 >> the time of the drop.
 >
 > I found this takes significant time.  I skip to get rid of usage of
 > secondary-overlay on this revision.

What takes significant time?  Please elaborate.

 > I cannot think of a way to show insert point besides (mouse-set-point
 > event).  Do you suggest overlay-put "|" or change cursor-type to 'bar
 > during drag?  I thought who prefers bar changes the default cursor
 > anyway.  I did not revise code in this respect.

I think that using 'mouse-set-point' as we do for 'mouse-drag-track' is
not necessarily a good idea.  The idea with 'mouse-drag-track' is that
its user usually wants point to go where the mouse moves.  The idea with
'mouse-drag-and-drop-region' is that the user wants to drop text where
the mouse goes but not necessarily also move point there.  If we want
'mouse-drag-and-drop-region' to do additional things (like killing the
region or moving point) we should make these customizable at least.

 >>>> (7) IMO either cutting should be the default too when the drop
 >>>>      occurs in a different buffer or copying would be the default and
 >>>>      pressing the modifier should produce a cut instead.  The current
 >>>>      behavior wants me to always keep in mind whether the target
 >>>>      buffer is the same as the source buffer.  At least, this
 >>>>      behavior should be made optional.
 >>>
 >>> Default behavior followed that of file browser on `drag' a file.
 >>
 >> Which file browser?
 >
 > Finder on macOS and File Explorer on Windows 10 behave like that way.

Do you mean that they move a file when the target directories differ and
copy it when they are the same?  Isn't that then the opposite of

 >>> Between the same volume (buffer), `drag' does `cut' instead of `copy'.

In either case I fail to see the volume/buffer connection relationship.
But maybe that's just me.

 >> I think that first of all you should use 'delete-region' instead of
 >> 'kill-region' to avoid the above-mentioned side effect.  Then your
 >> code should silently swallow any bugs for cutting from read-only
 >> text provided 'kill-read-only-ok' is t.  For that purpose, simply
 >> peruse the corresponding code from 'kill-region'.
 >
 > OK.  Now `delete-region' is used.

As mentioned, we can always add an option to kill the region instead.

 > I revised only to give message.  I could not tell how to bring
 > condition-case to code.

IMO this is one of the two major things to fix before the release.
Think of someone using this function in a way you didn't anticipate (for
example, take the bug mentioned by Alex that someone hits some other key
while dragging).  If mouse tracking then throws an error and you changed
point or the region or leave the secondary overlay around, this can be
very irritating.  After all, we want people to have a smooth experience
especially when using a new function.

Obviously, if you do not move point, do not create a secondary overlay
or do not change the region, these are not needed.  Otherwise, the
function should restore the entire configuration (selected window,
point, region, overlays at least) that existed before dragging started
so that the user can restart from there.

More precisely, you should wrap 'track-mouse' and whatever you do after
it terminates in a 'condition-case' form and in the error part restore
everything to the saved values.  Like so:

(... ; save the state here
  (condition-case nil
      (progn
        (track-mouse
	 )
        )
    (error ... ; restore the state here
	  )))

If you have any problems coding that, please ask.

 > +(defvar mouse-drag-and-drop-region-cut-among-buffer nil
 > +  "When t, text is cut instead of copy when dragged among buffers.")

This should be a 'defcustom'.  I would write instead

(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
   "If non-nil, cut text also when source and destination buffers differ.
If this option is nil, `mouse-drag-and-drop-region' will leave
the text in the source buffer alone when dropping it in a
different buffer.  If this is non-nil, it will cut the text just
as it does when dropping text in the source buffer."
   :type 'boolean
   :version "27.1"
   :group 'mouse)

and likewise for 'mouse-drag-and-drop-region-show-tooltip' (note also
the use of active voice and non-nil instead of t).

 > +          (when mouse-drag-and-drop-region-show-tooltip
 > +            (tooltip-show value-selection))))

Still not quite right: Never show a tooltip on text-only frames.  Think
of people who want to show tooltips but occasionally work on TTYs.

 > +          (if buffer-read-only (message "Buffer is read-only")) ; (barf-if-buffer-read-only)

'buffer-read-only' is not sufficient.  Please handle read-only
text properties at this position.

 > +      ;; Intert the text to destination buffer under mouse.
               ^

 > +        (let ((window1 (selected-window)))
 > +          (select-window window)   ; Select window with source buffer.
 > +          (goto-char point) ; Move point to the original text on source buffer.
[...]
 >             (select-window window1))))

I think

(set-window-point window point)

instead of the above should suffice.

And if I'm not mistaken you still disallow to copy text into itself.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-21 13:09         ` Stefan Monnier
  2017-11-21 14:05           ` mouse-drag-and-drop-region martin rudalics
  2017-11-21 15:45         ` mouse-drag-and-drop-region Eli Zaretskii
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-21 13:09 UTC (permalink / raw)
  To: emacs-devel

> I think that using 'mouse-set-point' as we do for 'mouse-drag-track' is
> not necessarily a good idea.

Hmm... mouse-drag-track does not mouse-set-point nowadays (it just
highlights the text while you drag the mouse, but what happens when you
finally release the button is determined by the normal keymap bindings).


        Stefan




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

* Re: mouse-drag-and-drop-region
  2017-11-21 13:09         ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-21 14:05           ` martin rudalics
  2017-11-21 19:07             ` mouse-drag-and-drop-region Stefan Monnier
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-21 14:05 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

 > Hmm... mouse-drag-track does not mouse-set-point nowadays (it just
 > highlights the text while you drag the mouse,

IIUC it uses 'mouse-set-point' initially and
'mouse--drag-set-mark-and-point' while dragging.

 > but what happens when you
 > finally release the button is determined by the normal keymap bindings).

Sure.  But the idea is that it synchronizes point with the mouse
position till then.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
  2017-11-21 13:09         ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-21 15:45         ` Eli Zaretskii
  2017-11-22  8:22           ` mouse-drag-and-drop-region martin rudalics
  2017-11-21 18:52         ` mouse-drag-and-drop-region Robert Weiner
  2017-11-23 23:28         ` mouse-drag-and-drop-region Tak Kunihiro
  3 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-21 15:45 UTC (permalink / raw)
  To: martin rudalics; +Cc: tak.kunihiro, agrambot, emacs-devel

> Date: Tue, 21 Nov 2017 10:24:26 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: emacs-devel@gnu.org
> 
>  > +(defvar mouse-drag-and-drop-region-cut-among-buffer nil
>  > +  "When t, text is cut instead of copy when dragged among buffers.")
> 
> This should be a 'defcustom'.  I would write instead
> 
> (defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
>    "If non-nil, cut text also when source and destination buffers differ.
> If this option is nil, `mouse-drag-and-drop-region' will leave
> the text in the source buffer alone when dropping it in a
> different buffer.  If this is non-nil, it will cut the text just
> as it does when dropping text in the source buffer."
>    :type 'boolean
>    :version "27.1"

"26.1", I should expect.



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

* Re: mouse-drag-and-drop-region
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
  2017-11-21 13:09         ` mouse-drag-and-drop-region Stefan Monnier
  2017-11-21 15:45         ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-21 18:52         ` Robert Weiner
  2017-11-22  8:22           ` mouse-drag-and-drop-region martin rudalics
  2017-11-23 23:28         ` mouse-drag-and-drop-region Tak Kunihiro
  3 siblings, 1 reply; 89+ messages in thread
From: Robert Weiner @ 2017-11-21 18:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, Tak Kunihiro, Alex, emacs-devel

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

On Tue, Nov 21, 2017 at 4:24 AM, martin rudalics <rudalics@gmx.at> wrote:

>
> (defcustom mouse-drag-and-drop-region-cut-when-buffers-differ


​A few suggestions.  This name is too specific.  If such an option is
introduced it could just be named
mouse-drag-and-drop-region-cut-flag and any limitations could be included
in the doc string, as they are already.  Then
if its behavior were modified in the future, the name would not need
changing.

But the option, mouse-drag-and-drop-region, already exists and does a bunch
of things that control cutting and copying
of the dragged region.  It would make sense if this setting could somehow
be integrated in there (one source of truth)
so there were no need to add a boolean just for this one aspect of regional
drag and drop.​

​Bob
​

[-- Attachment #2: Type: text/html, Size: 2002 bytes --]

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

* Re: mouse-drag-and-drop-region
  2017-11-21 14:05           ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-21 19:07             ` Stefan Monnier
  2017-11-22  8:26               ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-21 19:07 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

>> but what happens when you
>> finally release the button is determined by the normal keymap bindings).
> Sure.  But the idea is that it synchronizes point with the mouse
> position till then.

Indeed.  It should probably be generalized for uses where that's not
appropriate (similarly for uses where the mark shouldn't be modified
(not even temporarily)).  E.g. for mouse-drag-secondary.


        Stefan



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

* Re: mouse-drag-and-drop-region
  2017-11-21 15:45         ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-22  8:22           ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-22  8:22 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tak.kunihiro, agrambot, emacs-devel

 >>     :version "27.1"
 >
 > "26.1", I should expect.

Let's hope for the best.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-21 18:52         ` mouse-drag-and-drop-region Robert Weiner
@ 2017-11-22  8:22           ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-22  8:22 UTC (permalink / raw)
  To: rswgnu; +Cc: Eli Zaretskii, Tak Kunihiro, Alex, emacs-devel

 >> (defcustom mouse-drag-and-drop-region-cut-when-buffers-differ
 >
 >
 > ​A few suggestions.  This name is too specific.  If such an option is
 > introduced it could just be named
 > mouse-drag-and-drop-region-cut-flag and any limitations could be included
 > in the doc string, as they are already.  Then
 > if its behavior were modified in the future, the name would not need
 > changing.

The option could also allow to copy text without having to rely on the
modifier key.  Then pressing the modifier key could just invert the
standard behavior specified by that option.

 > But the option, mouse-drag-and-drop-region, already exists and does a bunch
 > of things that control cutting and copying
 > of the dragged region.  It would make sense if this setting could somehow
 > be integrated in there (one source of truth)
 > so there were no need to add a boolean just for this one aspect of regional
 > drag and drop.​

If the default behavior is different wrt whether the buffers differ, I
see no way to avoid an extra option.

martin




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

* Re: mouse-drag-and-drop-region
  2017-11-21 19:07             ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-22  8:26               ` martin rudalics
  2017-11-22 21:20                 ` mouse-drag-and-drop-region Stefan Monnier
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-22  8:26 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

 > Indeed.  It should probably be generalized for uses where that's not
 > appropriate (similarly for uses where the mark shouldn't be modified
 > (not even temporarily)).  E.g. for mouse-drag-secondary.

Tracking the mouse and keeping the region intact is impossible unless we
continuously synchronize the position of point and the mouse cursor.
Anything else would invalidate the region as soon as scrolling the
window moves point.  So unless we allow alternative semantics of the
"region" 'mouse-drag-track' will have to modify the region as it does
now.

Note in this context that the doc-string of 'mouse-drag-track'

     "Track mouse drags by highlighting area between point and cursor.
The region will be defined with mark and point."

is completely misleading.  It should start with a line like

"Track mouse drags by synchronizing point with the mouse cursor."

where we could explain that "synchronizing" means something like moving
point to the most nearby buffer position corresponding to the current
mouse position on the screen and that dragging leaves the mark unchanged
and the highlighted region will change accordingly.

Obviously, we can give 'mouse-drag-track' an extra argument which
'mouse-drag-region' (and 'mouse-drag-secondary') would set appropriately
to tell it how to handle the region.  Before doing that we should,
however, establish the canonical way to handle mouse tracking.  More
precisely, we should decide whether we prefer the 'track-mouse' plus
'read-event' approach or the 'set-transient-map' one.  Currently, this
doesn't seem entirely clear to me.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-22  8:26               ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-22 21:20                 ` Stefan Monnier
  2017-11-23  7:46                   ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-22 21:20 UTC (permalink / raw)
  To: emacs-devel

> More precisely, we should decide whether we prefer the 'track-mouse'
> plus 'read-event' approach or the 'set-transient-map' one.  Currently,
> this doesn't seem entirely clear to me.

I very clearly vote in favor of set-transient-map, since the use
read-event leads inevitably to lots of corner case problems that are in
general impossible to fix.


        Stefan




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

* Re: mouse-drag-and-drop-region
  2017-11-22 21:20                 ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-23  7:46                   ` martin rudalics
  2017-11-23 14:00                     ` mouse-drag-and-drop-region Stefan Monnier
  2017-11-23 16:09                     ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 2 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-23  7:46 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

 > I very clearly vote in favor of set-transient-map, since the use
 > read-event leads inevitably to lots of corner case problems that are in
 > general impossible to fix.

Actually, this boils down to marking `track-mouse' obsolete in a not so
distant future.  Additionally, `mouse-drag-track' should be renamed once
more - to something like `mouse-drag-within-window' - the distinguishing
factor being that all events are interpreted relative to the window of
the starting event.  And we should provide a `mouse-drag-anywhere'
function which, among others, does not auto scroll the window of the
starting event.  Hence `mouse-drag-and-drop-region' could use the latter.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-23  7:46                   ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-23 14:00                     ` Stefan Monnier
  2017-11-23 16:09                     ` mouse-drag-and-drop-region Eli Zaretskii
  1 sibling, 0 replies; 89+ messages in thread
From: Stefan Monnier @ 2017-11-23 14:00 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

>> I very clearly vote in favor of set-transient-map, since the use
>> read-event leads inevitably to lots of corner case problems that are in
>> general impossible to fix.
> Actually, this boils down to marking `track-mouse' obsolete in a not so
> distant future.

You mean the special-form, right?  Because the variable is still very
much needed.  Yes, for me we can mark it obsolete.

> Additionally, `mouse-drag-track' should be renamed once
> more - to something like `mouse-drag-within-window' - the distinguishing
> factor being that all events are interpreted relative to the window of
> the starting event.  And we should provide a `mouse-drag-anywhere'
> function which, among others, does not auto scroll the window of the
> starting event.  Hence `mouse-drag-and-drop-region' could use the latter.

Actually, maybe mouse-drag-and-drop-region could also make use of
a generalized version of mouse-drag-track.


        Stefan



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

* Re: mouse-drag-and-drop-region
  2017-11-23  7:46                   ` mouse-drag-and-drop-region martin rudalics
  2017-11-23 14:00                     ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-23 16:09                     ` Eli Zaretskii
  2017-11-24  9:02                       ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-23 16:09 UTC (permalink / raw)
  To: martin rudalics; +Cc: monnier, emacs-devel

> Date: Thu, 23 Nov 2017 08:46:52 +0100
> From: martin rudalics <rudalics@gmx.at>
> 
>  > I very clearly vote in favor of set-transient-map, since the use
>  > read-event leads inevitably to lots of corner case problems that are in
>  > general impossible to fix.
> 
> Actually, this boils down to marking `track-mouse' obsolete in a not so
> distant future.

If we do, what will replace it?



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

* Re: mouse-drag-and-drop-region
  2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
                           ` (2 preceding siblings ...)
  2017-11-21 18:52         ` mouse-drag-and-drop-region Robert Weiner
@ 2017-11-23 23:28         ` Tak Kunihiro
  2017-11-24  9:02           ` mouse-drag-and-drop-region martin rudalics
  3 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-11-23 23:28 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

Thank you for the replay.

>>> I mean something like
>>>
>>> (defcustom
>>> mouse-drag-and-drop-region-show-secondary-overlay t
>>> ...)

>>> where setting this to nil means to just not show any overlay.  And
>>> your code would have to accept that there is no secondary overlay
>>> at the time of the drop.

>> I found this takes significant time.  I skip to get rid of usage of
>> secondary-overlay on this revision.
>
> What takes significant time?  Please elaborate.

I meant I need to spend significant time to make secondary-overlay
option.  I have started to fix things from easy ones.


>> I cannot think of a way to show insert point besides
>> (mouse-set-point event).  Do you suggest overlay-put "|" or change
>> cursor-type to 'bar during drag?  I thought who prefers bar changes
>> the default cursor anyway.  I did not revise code in this respect.
>
> I think that using 'mouse-set-point' as we do for 'mouse-drag-track'
> is not necessarily a good idea.  The idea with 'mouse-drag-track' is
> that its user usually wants point to go where the mouse moves.  The
> idea with 'mouse-drag-and-drop-region' is that the user wants to
> drop text where the mouse goes but not necessarily also move point
> there.  If we want 'mouse-drag-and-drop-region' to do additional
> things (like killing the region or moving point) we should make
> these customizable at least.

How to show insert point?
Do you mean restore active cursor back to source text?


>>>>> (7) IMO either cutting should be the default too when the drop
>>>>> occurs in a different buffer or copying would be the default and
>>>>> pressing the modifier should produce a cut instead.  The current
>>>>> behavior wants me to always keep in mind whether the target
>>>>> buffer is the same as the source buffer.  At least, this
>>>>> behavior should be made optional.
>>>>
>>>> Default behavior followed that of file browser on `drag' a file.
>>>>
>>> Which file browser?
>>
>> Finder on macOS and File Explorer on Windows 10 behave like that
>> way.
>
> Do you mean that they move a file when the target directories differ
> and copy it when they are the same?  Isn't that then the opposite of
>
>>>> Between the same volume (buffer), `drag' does `cut' instead of
>>>> `copy'.
>
> In either case I fail to see the volume/buffer connection
> relationship.  But maybe that's just me.

When an Icon of c:/runemacs.exe is dragged to d:/, copy.  When an Icon
of c:/runemacs.exe is dragged to c:/emacs-26.0.90/bin, cut.


>> I could not tell how to bring condition-case to code.
>
> IMO this is one of the two major things to fix before the release.
> Think of someone using this function in a way you didn't anticipate
> (for example, take the bug mentioned by Alex that someone hits some
> other key while dragging).  If mouse tracking then throws an error
> and you changed point or the region or leave the secondary overlay
> around, this can be very irritating.  After all, we want people to
> have a smooth experience especially when using a new function.
...
> (... ; save the state here
>  (condition-case nil
>      (progn
>        (track-mouse
> 	 )
>        )
>    (error ... ; restore the state here
> 	  )))
>
> If you have any problems coding that, please ask.

OK.  I will (but not yet).


>> +(defvar mouse-drag-and-drop-region-cut-among-buffer
>> nil
>> + "When t, text is cut instead of copy when dragged
>> among buffers.")

> This should be a 'defcustom'.  I would write instead
>
> (defcustom
> mouse-drag-and-drop-region-cut-when-buffers-differ nil
>   "If non-nil, cut text also when source and
>   destination buffers differ.
> If this option is nil, `mouse-drag-and-drop-region'
> will leave
> the text in the source buffer alone when dropping it
> in a
> different buffer.  If this is non-nil, it will cut the
> text just
> as it does when dropping text in the source buffer."
>   :type 'boolean
>   :version "27.1"
>   :group 'mouse)
>
> and likewise for
> 'mouse-drag-and-drop-region-show-tooltip' (note also
> the use of active voice and non-nil instead of t).

OK.


>> + (when mouse-drag-and-drop-region-show-tooltip
>> +            (tooltip-show value-selection))))

> Still not quite right: Never show a tooltip on text-only frames.
> Think of people who want to show tooltips but occasionally work on
> TTYs.

I think the patch covered that.  The approach is to overwrite
mouse-drag-and-drop-region-show-tooltip locally.

 (let ((mouse-drag-and-drop-region-show-tooltip
         (and mouse-drag-and-drop-region-show-tooltip
              (display-multi-frame-p)
              (require 'tooltip)))


>> + (if buffer-read-only (message "Buffer is
>> read-only")) ; (barf-if-buffer-read-only)
>
> 'buffer-read-only' is not sufficient.  Please handle
> read-only
> text properties at this position.

OK.


>> +        (let ((window1 (selected-window)))
>> + (select-window window) ; Select window with source
>> buffer.
>> + (goto-char point) ; Move point to the original
>> text on source buffer.
> [...]
>>             (select-window window1))))
>
> I think
>
> (set-window-point window point)
>
> instead of the above should suffice.

To select window is necessary for the case.  I try to use it when
fits.


> And if I'm not mistaken you still disallow to copy
> text into itself.

I forgot to mention, that was fixed.


I think that there are two significant TODOs.
- Make drag robust using condition-case
- Make secondary-overlay option



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

* Re: mouse-drag-and-drop-region
  2017-11-23 16:09                     ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-24  9:02                       ` martin rudalics
  2017-11-24  9:19                         ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-24  9:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

 >> Actually, this boils down to marking `track-mouse' obsolete in a not so
 >> distant future.
 >
 > If we do, what will replace it?

Something based on the transient keymap paradigm.  Whether that will be
a macro or some rule to suitably set/restore `track-mouse' around a call
of `set-transient-map'.  But I only draw conclusion from arguments
against using `read-event' (maybe in the context of mouse tracking only)
which I yet don't fully understand.  And I also don't understand whether
an unprotected (re-)setting of `track-mouse' is safe wrt redisplay but
maybe you can clarify that.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-23 23:28         ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-11-24  9:02           ` martin rudalics
  2017-11-27 13:11             ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-24  9:02 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, agrambot, emacs-devel

 > I meant I need to spend significant time to make secondary-overlay
 > option.  I have started to fix things from easy ones.

Do you mean that it's difficult to make the code work if it does not use
the secondary overlay?  I don't understand why, instead of perusing the
secondary overlay, you don't use your own overlay to indicate start and
end of the text you cut or copy.  When done with the operation or when
an error occurs during dragging, you simply remove that overlay.  In
addition, you can define a face the user can customize in order to
highlight that overlay.  This way, any secondary overlay that existed
already when the user started dragging would be just left alone.

 > How to show insert point?

I think that by default the insert point should be shown by the mouse
cursor alone.  Personally, I'd also prefer that when the original
position of point is scrolled off-screen, the normal cursor should not
be shown at all because it's by no means sure that it will stay there
after the drop occurred: If the drop happens in another buffer, you
restore the original point to where it was before.  Note that this is
not the case with `mouse-drag-region' which always leaves the normal
cursor at its last position even after the window was auto-scrolled.

Optionally, I see no problem showing the normal cursor just as
`mouse-drag-region' does, maybe with some customizable cursor type (I
think "bar" would give a better feeling than "box").

 > Do you mean restore active cursor back to source text?

When an error occurs, definitely so.  Then you should do what you do
when the drop happens in another buffer.  Maybe in these cases you
additionally should restore the window start position too, so that the
user can start from where she left off.  If you restore the window's
point only as you do now, then the region will be often partially
off-screen (at least here) although it was on-screen before.

When everything "goes well", point obviously will go to the position of
the inserted text.  Although when the drop happens in another window
showing the same buffer, it might be interesting to restore the source
window's state just as if the drop happened in another buffer.

 > When an Icon of c:/runemacs.exe is dragged to d:/, copy.  When an Icon
 > of c:/runemacs.exe is dragged to c:/emacs-26.0.90/bin, cut.

I see what you mean now but I doubt that many users of
`mouse-drag-and-drop-region' will be aware of such an analogy.

 > I think the patch covered that.  The approach is to overwrite
 > mouse-drag-and-drop-region-show-tooltip locally.
 >
 >   (let ((mouse-drag-and-drop-region-show-tooltip
 >           (and mouse-drag-and-drop-region-show-tooltip
 >                (display-multi-frame-p)
 >                (require 'tooltip)))

You're right.  I apparently missed that.

 > I think that there are two significant TODOs.
 > - Make drag robust using condition-case

Definitely.

 > - Make secondary-overlay option

This would be nice to have.

Thank you, martin



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

* Re: mouse-drag-and-drop-region
  2017-11-24  9:02                       ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-24  9:19                         ` Eli Zaretskii
  2017-11-24  9:41                           ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-24  9:19 UTC (permalink / raw)
  To: martin rudalics; +Cc: monnier, emacs-devel

> Date: Fri, 24 Nov 2017 10:02:08 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> 
>  >> Actually, this boils down to marking `track-mouse' obsolete in a not so
>  >> distant future.
>  >
>  > If we do, what will replace it?
> 
> Something based on the transient keymap paradigm.

Obsoleting such a veteran feature needs a very good reason, because it
causes annoyances across the community, as it's most probably is used
in a lot of places outside of the Emacs tree.  If the only reason we
have is that there are some disadvantages in some corner cases, it's
not enough to obsolete the form, IMO.

> And I also don't understand whether an unprotected (re-)setting of
> `track-mouse' is safe wrt redisplay but maybe you can clarify that.

Why would it be unsafe wrt redisplay?



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

* Re: mouse-drag-and-drop-region
  2017-11-24  9:19                         ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-24  9:41                           ` martin rudalics
  2017-11-24 13:25                             ` mouse-drag-and-drop-region Stefan Monnier
  2017-11-24 13:45                             ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 2 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-24  9:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

 > Obsoleting such a veteran feature needs a very good reason, because it
 > causes annoyances across the community, as it's most probably is used
 > in a lot of places outside of the Emacs tree.  If the only reason we
 > have is that there are some disadvantages in some corner cases, it's
 > not enough to obsolete the form, IMO.

Yes.  I already said that I don't fully understand the arguments against
`read-event'.

 > Why would it be unsafe wrt redisplay?

Because of that part of tracking_off:

       /* Redisplay may have been preempted because there was input
	 available, and it assumes it will be called again after the
	 input has been processed.  If the only input available was
	 the sort that we have just disabled, then we need to call
	 redisplay.  */
       if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
	{
	  redisplay_preserve_echo_area (6);
	  get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
	}

IIUC we don't do that in `mouse-drag-track'.

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-24  9:41                           ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-24 13:25                             ` Stefan Monnier
  2017-11-26 10:24                               ` mouse-drag-and-drop-region martin rudalics
  2017-11-24 13:45                             ` mouse-drag-and-drop-region Eli Zaretskii
  1 sibling, 1 reply; 89+ messages in thread
From: Stefan Monnier @ 2017-11-24 13:25 UTC (permalink / raw)
  To: emacs-devel

> Yes.  I already said that I don't fully understand the arguments against
> `read-event'.

There's no problem with read-event itself.  The problems is that you
can't reliably *un*read an event, so the arguments are against uses of
read-event that just "peek" at the next event without the intention to
fully consume it.


        Stefan




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

* Re: mouse-drag-and-drop-region
  2017-11-24  9:41                           ` mouse-drag-and-drop-region martin rudalics
  2017-11-24 13:25                             ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-24 13:45                             ` Eli Zaretskii
  2017-11-26 10:24                               ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-24 13:45 UTC (permalink / raw)
  To: martin rudalics; +Cc: monnier, emacs-devel

> Date: Fri, 24 Nov 2017 10:41:12 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> 
>  > Why would it be unsafe wrt redisplay?
> 
> Because of that part of tracking_off:
> 
>        /* Redisplay may have been preempted because there was input
> 	 available, and it assumes it will be called again after the
> 	 input has been processed.  If the only input available was
> 	 the sort that we have just disabled, then we need to call
> 	 redisplay.  */
>        if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
> 	{
> 	  redisplay_preserve_echo_area (6);
> 	  get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
> 	}

With redisplay-dont-pause being t by default, this shouldn't happen
unless someone customizes that option.

> IIUC we don't do that in `mouse-drag-track'.

Why should we?  mouse-drag-track works via the normal command loop
machinery.



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

* Re: mouse-drag-and-drop-region
  2017-11-24 13:25                             ` mouse-drag-and-drop-region Stefan Monnier
@ 2017-11-26 10:24                               ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-11-26 10:24 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel

 > There's no problem with read-event itself.  The problems is that you
 > can't reliably *un*read an event, so the arguments are against uses of
 > read-event that just "peek" at the next event without the intention to
 > fully consume it.

Couldn't you then write up some text that tells us about the pitfalls of
unreading an event and what should be done instead?  All I found in the
Elisp manual is:

      The reliable and easy way to extract events from a key sequence so
      as to put them in `unread-command-events' is to use
      `listify-key-sequence' (see below).

but I see no explanation how `unread-command-events' can be updated
safely after a `read-event' and whether/when that should be avoided.

Pretty please, martin



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

* Re: mouse-drag-and-drop-region
  2017-11-24 13:45                             ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-26 10:24                               ` martin rudalics
  2017-11-26 15:54                                 ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-26 10:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

 >> IIUC we don't do that in `mouse-drag-track'.
 >
 > Why should we?  mouse-drag-track works via the normal command loop
 > machinery.

Which can only process or ignore but never postpone events?

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-26 10:24                               ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-26 15:54                                 ` Eli Zaretskii
  2017-11-27  8:48                                   ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-26 15:54 UTC (permalink / raw)
  To: martin rudalics; +Cc: monnier, emacs-devel

> Date: Sun, 26 Nov 2017 11:24:50 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> 
>  >> IIUC we don't do that in `mouse-drag-track'.
>  >
>  > Why should we?  mouse-drag-track works via the normal command loop
>  > machinery.
> 
> Which can only process or ignore but never postpone events?

Which is not different from keyboard input, and therefore doesn't need
special handling or consideration, AFAIU.



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

* Re: mouse-drag-and-drop-region
  2017-11-26 15:54                                 ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-11-27  8:48                                   ` martin rudalics
  2017-11-27 15:59                                     ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-27  8:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: monnier, emacs-devel

 >> Which can only process or ignore but never postpone events?
 >
 > Which is not different from keyboard input, and therefore doesn't need
 > special handling or consideration, AFAIU.

That's what I meant.  Now `mouse-drag-track' does two essential things:
It sets `track-mouse' to non-nil so mouse movement creates input events
and it uses a transient keymap to process them.  However, an application
that wants to look into an event and postpone it via "unreading" it, is
still able to do so, right?  So the only difference to using the
`track-mouse' macro is that the transient keymap approach obfuscates the
underlying event reading mechanism and thus does not overtly invite the
application to unread events.  Is that interpretation correct?

martin



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

* Re: mouse-drag-and-drop-region
  2017-11-24  9:02           ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-27 13:11             ` Tak Kunihiro
  2017-11-28  8:50               ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-11-27 13:11 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

I re-revised mouse-drag-and-drop-region.  I'm sending replay to
https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00589.html,
ChangeLog, and patch.

* ChangeLog

2017-11-27 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>

        Improve comments and have three new options

        * lisp/mouse.el (mouse-drag-and-drop-region): Make usage of tooltip option.  Have option to make dragging cut among buffers.
        (mouse-drag-and-drop-region-cut-when-buffers-differ): New variable.  If non-nil, text is cut instead of copied when dragged among buffers.
        (mouse-drag-and-drop-region-show-tooltip): New variable.  If non-nil, text is shown by tooltip in a graphic display.
        (mouse-drag-and-drop-region-face): New variable for face.  The face is used to highlight the original text.

* Replay

> instead of perusing the secondary overlay, you don't use your own
> overlay to indicate start and end of the text you cut or copy.  When
> done with the operation or when an error occurs during dragging, you
> simply remove that overlay.  In addition, you can define a face the
> user can customize in order to highlight that overlay.

OK.  That is a good idea.  I got rid of usage of secondary-overlay.  I
define a new variable mouse-drag-and-drop-region-face.

>> How to show insert point?
>
> I think that by default the insert point should be shown by the
> mouse cursor alone.  Optionally, I see no problem showing the normal
> cursor just as `mouse-drag-region' does, maybe with some
> customizable cursor type (I think "bar" would give a better feeling
> than "box").

OK.  Only set point by mouse-set-point when
mouse-drag-and-drop-region-show-tooltip is non-nil with changing
cursor type.  I also changed the default of
mouse-drag-and-drop-region-show-tooltip to nil to be more stable
against accident during dragging.

> More precisely, you should wrap 'track-mouse' and whatever you do
> after it terminates in a 'condition-case' form and in the error part
> restore everything to the saved values.  Like so:
>
> (... ; save the state here
>  (condition-case nil
>      (progn
>        (track-mouse
> 	 )
>        )
>    (error ... ; restore the state here
> 	  )))
>
> If you have any problems coding that, please ask.

Even track-mouse is sandwiched by condition-case, I cannot catch a
error typing during dragging.  However, as inferred already, when
mouse-drag-and-drop-region-show-tooltip is nil, it is more stable even
typing key during dragging.


* Patch

diff --git a/lisp/mouse.el b/lisp/mouse.el
old mode 100644
new mode 100755
index 17d1732..b81d56e
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,29 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip nil
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is non-nil, point is set to where the mouse cursor
+is during dragging and the original text is highlighted by face
+`mouse-drag-and-drop-region-face'."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-tooltip'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2392,171 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
+  (let* ((mouse-drag-and-drop-region-show-tooltip
+          (and mouse-drag-and-drop-region-show-tooltip
+               (display-multi-frame-p)
+               (require 'tooltip)))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (cursor-type cursor-type)
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay
+          (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection)   ; This remains nil when event was "click".
+
+    ;; FIXME: Handle error such as hitting C-g while dragging.  See
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
     (track-mouse
-      ;; When event was click instead of drag, skip loop
+      ;; When event was "click" instead of "drag", skip loop.
       (while (progn
                (setq event (read-event))
                (or (mouse-movement-p event)
                    ;; Handle `mouse-autoselect-window'.
                    (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
+        ;; Obtain the dragged text in region.  When the loop was
+        ;; skipped, value-selection remains nil.
+        (unless value-selection
           (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
+
+          ;; Check if selected text is read-only.
+          (dolist (index (number-sequence start end))
+            ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+            (setq text-from-read-only (or text-from-read-only
+                                          (get-text-property index 'read-only)))))
+        (ignore-errors
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+
+          ;; Check if point under mouse is read-only.
+          (save-window-excursion
+            (select-window window-to-paste)
+            ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+            (setq point-to-paste-read-only
+                  (or buffer-read-only
+                      (get-text-property point-to-paste 'read-only))))
+
+          ;; Check if "drag but negligible".  Operation "drag but
+          ;; negligible" is defined as drag-and-drop the text to
+          ;; the original region.  When modifier is pressed, the
+          ;; text will be inserted to inside of the original
+          ;; region.
+          (setq drag-but-negligible
+                (member mouse-drag-and-drop-region-face
+                        (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                (overlays-at point-to-paste))))
+
+          ;; Show tooltip.
+          (when mouse-drag-and-drop-region-show-tooltip
+            (overlay-put mouse-drag-and-drop-overlay
+                         'face mouse-drag-and-drop-region-face)
+            (deactivate-mark)   ; Maintain region in other window.
+            (mouse-set-point event)
+            (setq cursor-type (if (or point-to-paste-read-only
+                                      drag-but-negligible)
+                                  'hollow
+                                'bar))
+            (if (and (not drag-but-negligible)
+                     (not point-to-paste-read-only))
+                (tooltip-show value-selection)
+              (tooltip-hide)))))
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide)))
+    
+
+    ;; Check if modifier was pressed on drop.
+    (setq no-modifier-on-drop
+          (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+    ;; Check if event was "click".
+    ;; (setq clicked (equal (mouse-posn-property (event-end event) 'face) 'region))
+    (setq clicked (not value-selection))
+
+    ;; Do not modify any buffers when event is "click",
+    ;; "drag but negligible", or "drag to read-only".
+    (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+            (if no-modifier-on-drop
+                mouse-drag-and-drop-region-cut-when-buffers-differ
+              (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+           (wanna-paste-to-same-buffer (equal (window-buffer window-to-paste) buffer))
+           (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                          no-modifier-on-drop))
+           (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                           mouse-drag-and-drop-region-cut-when-buffers-differ))
+           (cannot-paste (or point-to-paste-read-only
+                             (when (or wanna-cut-on-same-buffer
+                                       wanna-cut-on-other-buffer)
+                               text-from-read-only))))
+
+      (cond
+       ;; Move point within region.
+       (clicked
+        (deactivate-mark)
+        (mouse-set-point event))
+       ;; Undo operation. Set back the original text as region.
+       ((or (and drag-but-negligible
+                 no-modifier-on-drop)
+            cannot-paste)
+        ;; Inform user either source or destination buffer cannot be modified.
+        (when (and (not drag-but-negligible)
+                   cannot-paste)
+          (message "Buffer is read-only"))
+
+        ;; Select source window back and restore region.
+        ;; (set-window-point window point)
+        (select-window window)
+        (goto-char point)
+        (setq deactivate-mark nil)
+        (activate-mark))
+       ;; Modify buffers.
+       (t
+        ;; * DESTINATION BUFFER::
+        ;; Insert the text to destination buffer under mouse.
+        (select-window window-to-paste)
+        (goto-char point-to-paste)
+        (push-mark)
+        (insert value-selection)
+        ;; On success, set the text as region on destination buffer.
+        (when (not (equal (mark) (point)))
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+
+        ;; * SOURCE BUFFER::
+        ;; Set back the original text as region or delete the original
+        ;; text, on source buffer.
+        (if wanna-paste-to-same-buffer
+            ;; When source buffer and destination buffer are the same,
+            ;; remove the original text.
+            (when no-modifier-on-drop
+              (let (deactivate-mark)
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))))
+          ;; When source buffer and destination buffer are different,
+          ;; keep (set back the original text as region) or remove the
+          ;; original text.
+          (select-window window)   ; Select window with source buffer.
+          (goto-char point) ; Move point to the original text on source buffer.
+
+          (if mouse-drag-and-drop-region-cut-when-buffers-differ
+              ;; Remove the dragged text from source buffer like
+              ;; operation `cut'.
+              (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                             (overlay-end mouse-drag-and-drop-overlay))
+            ;; Set back the dragged text as region on source buffer
+            ;; like operation `copy'.
+            (activate-mark))
+          (select-window window-to-paste)))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)))
 \f
 
 ;;; Bindings for mouse commands.



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

* Re: mouse-drag-and-drop-region
  2017-11-27  8:48                                   ` mouse-drag-and-drop-region martin rudalics
@ 2017-11-27 15:59                                     ` Eli Zaretskii
  0 siblings, 0 replies; 89+ messages in thread
From: Eli Zaretskii @ 2017-11-27 15:59 UTC (permalink / raw)
  To: martin rudalics; +Cc: monnier, emacs-devel

> Date: Mon, 27 Nov 2017 09:48:44 +0100
> From: martin rudalics <rudalics@gmx.at>
> CC: monnier@iro.umontreal.ca, emacs-devel@gnu.org
> 
> That's what I meant.  Now `mouse-drag-track' does two essential things:
> It sets `track-mouse' to non-nil so mouse movement creates input events
> and it uses a transient keymap to process them.  However, an application
> that wants to look into an event and postpone it via "unreading" it, is
> still able to do so, right?  So the only difference to using the
> `track-mouse' macro is that the transient keymap approach obfuscates the
> underlying event reading mechanism and thus does not overtly invite the
> application to unread events.  Is that interpretation correct?

I think so, but I'm not an expert on this stuff.



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

* Re: mouse-drag-and-drop-region
  2017-11-27 13:11             ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-11-28  8:50               ` martin rudalics
  2017-12-01 14:16                 ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-11-28  8:50 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

 > I re-revised mouse-drag-and-drop-region.  I'm sending replay to
 > https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00589.html,
 > ChangeLog, and patch.

Thanks.  Kindly send patches always as attachments, this one choked here
because of a missing form feed near the end.

 > I got rid of usage of secondary-overlay.  I
 > define a new variable mouse-drag-and-drop-region-face.

Very good.

 >>> How to show insert point?
 >>
 >> I think that by default the insert point should be shown by the
 >> mouse cursor alone.  Optionally, I see no problem showing the normal
 >> cursor just as `mouse-drag-region' does, maybe with some
 >> customizable cursor type (I think "bar" would give a better feeling
 >> than "box").
 >
 > OK.  Only set point by mouse-set-point when
 > mouse-drag-and-drop-region-show-tooltip is non-nil with changing
 > cursor type.  I also changed the default of
 > mouse-drag-and-drop-region-show-tooltip to nil to be more stable
 > against accident during dragging.

This reverts too much from your initial proposal.  Basically, all your
initial ideas are fine, just that if on one or the other system they
don't work as intended or some user finds them annoying, there should be
options to turn them off.  And, if accidents happen during dragging with
any of the options non-nil, we should try to handle or fix them anyway.
So I would use three options instead of one:

`mouse-drag-and-drop-region-show-tooltip' to toggle the showing of
tooltips during dragging and nothing else.

`mouse-drag-and-drop-region-highlight-region' to toggle highlighting the
region with `mouse-drag-and-drop-region-face' (which gives the user the
feedback whether cutting may fail when dropping into the region itself,
which was your initial intention IIUC).

`mouse-drag-and-drop-region-show-cursor' which should synchronize the
cursor with the mouse cursor just as `mouse-drag-track' does.  This is
the only option I personally would default to nil but if you or others
like it on by default I certainly won't insist.

 >> More precisely, you should wrap 'track-mouse' and whatever you do
 >> after it terminates in a 'condition-case' form and in the error part
 >> restore everything to the saved values.  Like so:
 >>
 >> (... ; save the state here
 >>   (condition-case nil
 >>       (progn
 >>         (track-mouse
 >> 	 )
 >>         )
 >>     (error ... ; restore the state here
 >> 	  )))
 >>
 >> If you have any problems coding that, please ask.
 >
 > Even track-mouse is sandwiched by condition-case, I cannot catch a
 > error typing during dragging.

When I try to drop the region on the toolbar or another frame (things
some users might try out soon because they are not too far-fetched) I
currently get something like

Wrong type argument: windowp, #<frame emacs@MACHNO 05408d00>

Before your last patch this was a complaint about an overlay.  In either
case, users who don't know much about the internals of Emacs will wonder
what these messages are about and where they come from.  We should tell
them instead something like "Drop failed" or "Cannot drop into initial
region".  And, if such an error occurs, we should be sure to delete the
`mouse-drag-and-drop-overlay' and restore the initial region, if
necessary.

 > However, as inferred already, when
 > mouse-drag-and-drop-region-show-tooltip is nil, it is more stable even
 > typing key during dragging.

Yes.  But typing during dragging should be caught by us in some way.  It
should not defer us from showing tooltips by default.

One final remark: Stepping through every single character in

           ;; Check if selected text is read-only.
           (dolist (index (number-sequence start end))
             ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
             (setq text-from-read-only (or text-from-read-only
                                           (get-text-property index 'read-only)))))
					
is not very efficient if the region is large.  Please consider using
`next-single-char-property-change' instead.

Thanks again, martin



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

* Re: mouse-drag-and-drop-region
  2017-11-28  8:50               ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-01 14:16                 ` Tak Kunihiro
  2017-12-02 10:16                   ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-01 14:16 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

I re-re-revised mouse-drag-and-drop-region.  I'm sending replay to
https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html,
ChangeLog, and patch.

* ChangeLog

2017-12-01 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>

        Improve comments and have four new options

        * lisp/mouse.el (mouse-drag-and-drop-region): Have option to make dragging cut among buffers. Make usage of tooltip option.
        (mouse-drag-and-drop-region-cut-when-buffers-differ): New variable. If non-nil, text is cut instead of copied when dragged among buffers.
        (mouse-drag-and-drop-region-show-tooltip): New variable. If non-nil, text is shown by tooltip in a graphic display.
        (mouse-drag-and-drop-region-show-cursor): New variable. If non-nil, point is set to where the mouse cursor.
        (mouse-drag-and-drop-region-face): New variable for face. The face is used to highlight the original text.


* Replay

> `mouse-drag-and-drop-region-show-tooltip' to toggle the showing of
> tooltips during dragging and nothing else.

OK.

> `mouse-drag-and-drop-region-highlight-region' to toggle highlighting
> the region with `mouse-drag-and-drop-region-face'
> 
> `mouse-drag-and-drop-region-show-cursor' which should synchronize the
> cursor with the mouse cursor just as `mouse-drag-track' does.

OK.  A new variable `mouse-drag-and-drop-region-show-cursor' is
defined.  When mouse-drag-and-drop-region-show-cursor is non-nil, the
region also is highlighted.  I did not define a variable
`mouse-drag-and-drop-region-highlight-region'.  Also, cursor-type
would be changed to give user feedback.

> When I try to drop the region on the toolbar or another frame (things
> some users might try out soon because they are not too far-fetched) I
> currently get something like
> 
> Wrong type argument: windowp, #<frame emacs@MACHNO 05408d00>
>
> We should tell them instead something like "Drop failed" or "Cannot
> drop into initial region".  And, if such an error occurs, we should be
> sure to delete the `mouse-drag-and-drop-overlay' and restore the
> initial region, if necessary.

Now the code checks if cursor is on the text area.  If not, it restore
the initial region.  I'm not sure to tell "Drop failed" is a good
idea.  When an user wants to undo the drag, he may drag to toolbar.
Restore the initial region is what is expected.  The code for now does
not tell the message.

> But typing during dragging should be caught by us in some way.  It
> should not defer us from showing tooltips by default.

I tried read-key instead of read-event as suggested by Alex and that
solved the problem.

> Stepping through every single character in
> 
>    (dolist (index (number-sequence start end))
>    ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
>    (setq text-from-read-only (or text-from-read-only
>                                  (get-text-property index 'read-only)))))
> 
> is not very efficient if the region is large.  Please consider using
> `next-single-char-property-change' instead.

OK.


* Patch

diff --git a/lisp/mouse.el b/lisp/mouse.el
old mode 100644
new mode 100755
index 17d1732..3e59f6f
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,31 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)

+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip t
+  "If non-nil, text is shown by a tooltip in a graphic display."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, point is set to where the mouse cursor is during
+dragging and the original text is highlighted by face
+`mouse-drag-and-drop-region-face'.")
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-cursor'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2394,197 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (and mouse-drag-and-drop-region-show-tooltip
+               (display-multi-frame-p)
+               (require 'tooltip)))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (cursor-type cursor-type)
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection)   ; This remains nil when event was "click".
+
     (track-mouse
-      ;; When event was click instead of drag, skip loop
+      ;; When event was "click" instead of "drag", skip loop.
       (while (progn
-               (setq event (read-event))
+               ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+               (setq event (read-key)) ; read-event or read-key
                (or (mouse-movement-p event)
                    ;; Handle `mouse-autoselect-window'.
                    (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
+        ;; Obtain the dragged text in region.  When the loop was
+        ;; skipped, value-selection remains nil.
+        (unless value-selection
           (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
+
+          ;; Check if selected text is read-only.
+          ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+          ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+          (setq text-from-read-only (or text-from-read-only
+                                        (get-text-property start 'read-only)
+                                        (not (equal
+                                              (next-single-char-property-change start 'read-only nil end)
+                                              end)))))
+        (ignore-errors
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+          (setq buffer-to-paste (and (windowp window-to-paste)
+                                     (window-buffer window-to-paste)))
+          (setq cursor-in-text-area (and window-to-paste
+                                         point-to-paste
+                                         buffer-to-paste))
+
+          (when cursor-in-text-area
+            ;; Check if point under mouse is read-only.
+            (save-window-excursion
+              (select-window window-to-paste)
+              ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+              (setq point-to-paste-read-only
+                    (or buffer-read-only
+                        (get-text-property point-to-paste 'read-only))))
+
+            ;; Check if "drag but negligible".  Operation "drag but
+            ;; negligible" is defined as drag-and-drop the text to
+            ;; the original region.  When modifier is pressed, the
+            ;; text will be inserted to inside of the original
+            ;; region.
+            (setq drag-but-negligible
+                  (member mouse-drag-and-drop-region-face
+                          (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                  (overlays-at point-to-paste)))))
+
+          ;; Show a tooltip.
+          (if (and mouse-drag-and-drop-region-show-tooltip
+                   (not drag-but-negligible)
+                   (not point-to-paste-read-only)
+                   cursor-in-text-area)
+              (tooltip-show value-selection)
+            (tooltip-hide))
+
+          ;; Show cursor and highlight the original region.
+          (when mouse-drag-and-drop-region-show-cursor
+            ;; Modify cursor even when point is out of frame.
+            (setq cursor-type (cond
+                               ((not cursor-in-text-area)
+                                nil)
+                               ((or point-to-paste-read-only
+                                    drag-but-negligible)
+                                'hollow)
+                               (t
+                                'bar)))
+            (when cursor-in-text-area
+              (overlay-put mouse-drag-and-drop-overlay
+                           'face mouse-drag-and-drop-region-face)
+              (deactivate-mark)      ; Maintain region in other window.
+              (mouse-set-point event)))))
+
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide)))
+
+    ;; Check if modifier was pressed on drop.
+    (setq no-modifier-on-drop
+          (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+    ;; Check if event was "click".
+    (setq clicked (not value-selection))
+
+    ;; Restore status on drag to outside of text-area or non-mouse input.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+    (when (or (not cursor-in-text-area)
+              (not (equal (event-basic-type event) mouse-button)))
+      (setq drag-but-negligible t
+            no-modifier-on-drop t))
+
+    ;; Do not modify any buffers when event is "click",
+    ;; "drag but negligible", or "drag to read-only".
+    (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+            (if no-modifier-on-drop
+                mouse-drag-and-drop-region-cut-when-buffers-differ
+              (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+           (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+           (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                          no-modifier-on-drop))
+           (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                           mouse-drag-and-drop-region-cut-when-buffers-differ))
+           (cannot-paste (or point-to-paste-read-only
+                             (when (or wanna-cut-on-same-buffer
+                                       wanna-cut-on-other-buffer)
+                               text-from-read-only))))
+
+      (cond
+       ;; Move point within region.
+       (clicked
+        (deactivate-mark)
+        (mouse-set-point event))
+       ;; Undo operation. Set back the original text as region.
+       ((or (and drag-but-negligible
+                 no-modifier-on-drop)
+            cannot-paste)
+        ;; Inform user either source or destination buffer cannot be modified.
+        (when (and (not drag-but-negligible)
+                   cannot-paste)
+          (message "Buffer is read-only"))
+
+        ;; Select source window back and restore region.
+        ;; (set-window-point window point)
+        (select-window window)
+        (goto-char point)
+        (setq deactivate-mark nil)
+        (activate-mark))
+       ;; Modify buffers.
+       (t
+        ;; * DESTINATION BUFFER::
+        ;; Insert the text to destination buffer under mouse.
+        (select-window window-to-paste)
+        (goto-char point-to-paste)
+        (push-mark)
+        (insert value-selection)
+        ;; On success, set the text as region on destination buffer.
+        (when (not (equal (mark) (point)))
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+
+        ;; * SOURCE BUFFER::
+        ;; Set back the original text as region or delete the original
+        ;; text, on source buffer.
+        (if wanna-paste-to-same-buffer
+            ;; When source buffer and destination buffer are the same,
+            ;; remove the original text.
+            (when no-modifier-on-drop
+              (let (deactivate-mark)
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))))
+          ;; When source buffer and destination buffer are different,
+          ;; keep (set back the original text as region) or remove the
+          ;; original text.
+          (select-window window)   ; Select window with source buffer.
+          (goto-char point) ; Move point to the original text on source buffer.
+
+          (if mouse-drag-and-drop-region-cut-when-buffers-differ
+              ;; Remove the dragged text from source buffer like
+              ;; operation `cut'.
+              (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                             (overlay-end mouse-drag-and-drop-overlay))
+            ;; Set back the dragged text as region on source buffer
+            ;; like operation `copy'.
+            (activate-mark))
+          (select-window window-to-paste)))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)))
 \f

 ;;; Bindings for mouse commands.



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

* Re: mouse-drag-and-drop-region
  2017-12-01 14:16                 ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-02 10:16                   ` martin rudalics
  2017-12-03 10:06                     ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-02 10:16 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

 > I re-re-revised mouse-drag-and-drop-region.  I'm sending replay to
 > https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html,
 > ChangeLog, and patch.

Thank you.  Still, please consider sending patches as attachments so
applying them is simpler.

 > OK.  A new variable `mouse-drag-and-drop-region-show-cursor' is
 > defined.

Please note that the first line of a doc string may contain complete
sentences only.  You could write something like

(defvar mouse-drag-and-drop-region-show-cursor t
   "If non-nil, move point with mouse cursor during dragging.
In addition, highlight the original region with
`mouse-drag-and-drop-region-face'.")

 > Now the code checks if cursor is on the text area.  If not, it restore
 > the initial region.  I'm not sure to tell "Drop failed" is a good
 > idea.  When an user wants to undo the drag, he may drag to toolbar.
 > Restore the initial region is what is expected.  The code for now does
 > not tell the message.

OK.  But the code fails to poperly restore the previous cursor type when
the drop fails.  For example when with emacs -Q I evaluate

(progn
   (setq mouse-drag-and-drop-region t)
   (setq mouse-drag-and-drop-region-show-cursor t)
   (display-buffer "*Messages*"))

mark some text in the *scratch* buffer and accidentally drag-and-drop it
on the mode line of the *Messages* buffer, the cursor in the *Messages*
buffer disappears.  I think you have to remember the old cursor type and
make sure it gets restored whatever happens.

martin



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

* Re: mouse-drag-and-drop-region
  2017-12-02 10:16                   ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-03 10:06                     ` martin rudalics
  2017-12-03 13:36                       ` mouse-drag-and-drop-region martin rudalics
  2017-12-05  4:57                       ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 2 replies; 89+ messages in thread
From: martin rudalics @ 2017-12-03 10:06 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

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

I have found some time to look into this again and encountered a few
additional problems.

One is that when a user has three windows - T at the top of a frame, M
in the middle and B at the bottom of the frame - and wants to drag a
region from T to B.  In this case the position of M's point will
inevitably change although the user probably had no intentions to do
that.  So we should make sure to restore the point of any window that
might be affected by the drag.

Another one is that when a user has set `scroll-margin' to some non-zero
value, any window involved in the drag may scroll in order to move that
window's point out of the scroll margin.  This may affect unrelated
windows (as in the TMB example above) but also the window where the drag
started.

We could use the trick of `mouse-drag-track' to bind `scroll-margin' to
zero but this might not work if a user has made this variable
buffer-local (note that `mouse-drag-track' never leaves the current
buffer so it has no such problem).

So I think that we should remember for each window on the involved frame
its start and point positions and restore them unless the window is the
one where the drop happened.  I attached a patch for this which also
restores the cursor type of every window.  The patch includes all your
latest changes (so it should apply against the repository version) and
is largely untested but should give you the idea what to do.

Please consider also the following four bindings in `mouse-drag-track':

          (echo-keystrokes 0)

	 (make-cursor-line-fully-visible nil)

	 ;; Suppress automatic hscrolling, because that is a nuisance
	 ;; when setting point near the right fringe (but see below).
	 (auto-hscroll-mode-saved auto-hscroll-mode)

          (old-track-mouse track-mouse)

Maybe they are useful for you as well (a lot of experience went into the
coding of that function).

Also please consider to restrict the size of the tooltip shown (think of
someone who wants to drag the entire text of a buffer).  I think
`mouse-drag-and-drop-region-show-tooltip' should optionally allow to
specify a number giving the maximum length of the string which I would
divide into one half for the beginning of the text, one half for the end
and ellipses in between.

Finally, please think of how to embed your function into other packages:
For example, how would a user drag file names from one dired buffer to
another in order to copy or move the associated files from one directory
to another?  Can we accomodate an exit function to do the pasting job?

Thanks, martin

[-- Attachment #2: mouse.el.diff --]
[-- Type: text/plain, Size: 15560 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..02ba364 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,31 @@ mouse-drag-and-drop-region
   :version "26.1"
   :group 'mouse)

+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip t
+  "If non-nil, text is shown by a tooltip in a graphic display."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, point is set to where the mouse cursor is during
+dragging and the original text is highlighted by face
+`mouse-drag-and-drop-region-face'.")
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-cursor'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2394,233 @@ mouse-drag-and-drop-region
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
-          (setq deactivate-mark nil)
-          (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (and mouse-drag-and-drop-region-show-tooltip
+               (display-multi-frame-p)
+               (require 'tooltip)))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         states
+         window-dropped)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+	       (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (condition-case nil
+        (progn
+          (track-mouse
+            ;; When event was "click" instead of "drag", skip loop.
+            (while (progn
+                     ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                     (setq event (read-key))  ; read-event or read-key
+                     (or (mouse-movement-p event)
+                         ;; Handle `mouse-autoselect-window'.
+                         (eq (car-safe event) 'select-window)))
+              ;; Obtain the dragged text in region.  When the loop was
+              ;; skipped, value-selection remains nil.
+              (unless value-selection
+                (setq value-selection (buffer-substring start end))
+
+                ;; Check if selected text is read-only.
+                ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+                ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                (setq text-from-read-only (or text-from-read-only
+                                              (get-text-property start 'read-only)
+                                              (not (equal
+                                                    (next-single-char-property-change start 'read-only nil end)
+                                                    end)))))
+              (setq window-to-paste (posn-window (event-end event)))
+              (setq point-to-paste (posn-point (event-end event)))
+              (setq buffer-to-paste (and (windowp window-to-paste)
+                                         (window-buffer window-to-paste)))
+              (setq cursor-in-text-area (and window-to-paste
+                                             point-to-paste
+                                             buffer-to-paste))
+
+              (when cursor-in-text-area
+                ;; Check if point under mouse is read-only.
+                (save-window-excursion
+                  (select-window window-to-paste)
+                  ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                  (setq point-to-paste-read-only
+                        (or buffer-read-only
+                            (get-text-property point-to-paste 'read-only))))
+
+                ;; Check if "drag but negligible".  Operation "drag but
+                ;; negligible" is defined as drag-and-drop the text to
+                ;; the original region.  When modifier is pressed, the
+                ;; text will be inserted to inside of the original
+                ;; region.
+                (setq drag-but-negligible
+                      (member mouse-drag-and-drop-region-face
+                              (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                      (overlays-at point-to-paste)))))
+
+              ;; Show a tooltip.
+              (if (and mouse-drag-and-drop-region-show-tooltip
+                       (not drag-but-negligible)
+                       (not point-to-paste-read-only)
+                       cursor-in-text-area)
+                  (tooltip-show value-selection)
+                (tooltip-hide))
+
+              ;; Show cursor and highlight the original region.
+              (when mouse-drag-and-drop-region-show-cursor
+                ;; Modify cursor even when point is out of frame.
+                (setq cursor-type (cond
+                                   ((not cursor-in-text-area)
+                                    nil)
+                                   ((or point-to-paste-read-only
+                                        drag-but-negligible)
+                                    'hollow)
+                                   (t
+                                    'bar)))
+                (when cursor-in-text-area
+                  (overlay-put mouse-drag-and-drop-overlay
+                               'face mouse-drag-and-drop-region-face)
+                  (deactivate-mark) ; Maintain region in other window.
+                  (mouse-set-point event)))))
+
+          ;; Hide a tooltip.
+          (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+          ;; Check if modifier was pressed on drop.
+          (setq no-modifier-on-drop
+                (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+          ;; Check if event was "click".
+          (setq clicked (not value-selection))
+
+          ;; Restore status on drag to outside of text-area or non-mouse input.
+          ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+          (when (or (not cursor-in-text-area)
+                    (not (equal (event-basic-type event) mouse-button)))
+            (setq drag-but-negligible t
+                  no-modifier-on-drop t))
+
+          ;; Do not modify any buffers when event is "click",
+          ;; "drag but negligible", or "drag to read-only".
+          (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+                  (if no-modifier-on-drop
+                      mouse-drag-and-drop-region-cut-when-buffers-differ
+                    (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+                 (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+                 (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                                no-modifier-on-drop))
+                 (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                                 mouse-drag-and-drop-region-cut-when-buffers-differ))
+                 (cannot-paste (or point-to-paste-read-only
+                                   (when (or wanna-cut-on-same-buffer
+                                             wanna-cut-on-other-buffer)
+                                     text-from-read-only))))
+
+            (cond
+             ;; Move point within region.
+             (clicked
+              (deactivate-mark)
+              (mouse-set-point event))
+             ;; Undo operation. Set back the original text as region.
+             ((or (and drag-but-negligible
+                       no-modifier-on-drop)
+                  cannot-paste)
+              ;; Inform user either source or destination buffer cannot be modified.
+              (when (and (not drag-but-negligible)
+                         cannot-paste)
+                (message "Buffer is read-only"))
+
+              ;; Select source window back and restore region.
+              ;; (set-window-point window point)
+              (select-window window)
+              (goto-char point)
+              (setq deactivate-mark nil)
+              (activate-mark))
+             ;; Modify buffers.
+             (t
+              ;; * DESTINATION BUFFER::
+              ;; Insert the text to destination buffer under mouse.
+              (select-window window-to-paste)
+              (setq window-dropped window-to-paste)
+              (goto-char point-to-paste)
+              (push-mark)
+              (insert value-selection)
+              ;; On success, set the text as region on destination buffer.
+              (when (not (equal (mark) (point)))
+                (setq deactivate-mark nil)
+                (activate-mark))
+
+              ;; * SOURCE BUFFER::
+              ;; Set back the original text as region or delete the original
+              ;; text, on source buffer.
+              (if wanna-paste-to-same-buffer
+                  ;; When source buffer and destination buffer are the same,
+                  ;; remove the original text.
+                  (when no-modifier-on-drop
+                    (let (deactivate-mark)
+                      (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                     (overlay-end mouse-drag-and-drop-overlay))))
+                ;; When source buffer and destination buffer are different,
+                ;; keep (set back the original text as region) or remove the
+                ;; original text.
+                (select-window window) ; Select window with source buffer.
+                (goto-char point) ; Move point to the original text on source buffer.
+
+                (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                    ;; Remove the dragged text from source buffer like
+                    ;; operation `cut'.
+                    (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                   (overlay-end mouse-drag-and-drop-overlay))
+                  ;; Set back the dragged text as region on source buffer
+                  ;; like operation `copy'.
+                  (activate-mark))
+                (select-window window-to-paste))))))
+      (error nil))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (unless (eq window window-dropped)
+          (set-window-start window (nth 1 state) 'noforce)
+	  (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+	  (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f

 ;;; Bindings for mouse commands.

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

* Re: mouse-drag-and-drop-region
  2017-12-03 10:06                     ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-03 13:36                       ` martin rudalics
  2017-12-05  4:57                       ` mouse-drag-and-drop-region Tak Kunihiro
  1 sibling, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-12-03 13:36 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

 > We could use the trick of `mouse-drag-track' to bind `scroll-margin' to
 > zero but this might not work if a user has made this variable
 > buffer-local (note that `mouse-drag-track' never leaves the current
 > buffer so it has no such problem).

Ignore this: Binding `scroll-margin' to zero obviously overrides any
buffer-local setting as well.

martin



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

* Re: mouse-drag-and-drop-region
  2017-12-03 10:06                     ` mouse-drag-and-drop-region martin rudalics
  2017-12-03 13:36                       ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-05  4:57                       ` Tak Kunihiro
  2017-12-05  8:53                         ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-05  4:57 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

[-- Attachment #1: Type: Text/Plain, Size: 2122 bytes --]

> So I think that we should remember for each window on the involved frame
> its start and point positions and restore them unless the window is the
> one where the drop happened.  I attached a patch for this which also
> restores the cursor type of every window.  The patch includes all your
> latest changes (so it should apply against the repository version) and
> is largely untested but should give you the idea what to do.

Thank you.  I think that by your revision, the problem was solved.  I
also revised code not to let user drop the text to minibuffer.  This
time, I attach a patch as a separated file.

> Please consider also the following four bindings in `mouse-drag-track':
> 
>          (echo-keystrokes 0)
> 
>          (make-cursor-line-fully-visible nil)
> 
>          ;; Suppress automatic hscrolling, because that is a nuisance
>          ;; when setting point near the right fringe (but see below).
>          (auto-hscroll-mode-saved auto-hscroll-mode)
> 
>          (old-track-mouse track-mouse)
> 
> Maybe they are useful for you as well (a lot of experience went into the
> coding of that function).

I wonder if this is beyond my skill.  Could you revise this part?

> Also please consider to restrict the size of the tooltip shown (think of
> someone who wants to drag the entire text of a buffer).  I think
> `mouse-drag-and-drop-region-show-tooltip' should optionally allow to
> specify a number giving the maximum length of the string which I would
> divide into one half for the beginning of the text, one half for the end
> and ellipses in between.

It is a good idea.  Now tooltip shows only substring.  I think
mouse-drag-and-drop-region-show-tooltip should be something like 256
by default.

> Finally, please think of how to embed your function into other packages:
> For example, how would a user drag file names from one dired buffer to
> another in order to copy or move the associated files from one directory
> to another?  Can we accomodate an exit function to do the pasting job?

It is a good idea.  I suppose you mean dragging `file' when
event-start is with 'dired-filename.


[-- Attachment #2: mouse.el.diff --]
[-- Type: Text/X-Patch, Size: 16782 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..f1ca0ec
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,33 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is an integer, such as 32 or 64, a number giving
+the maximum length of the string shown in tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+In addition, highlight the original region with
+`mouse-drag-and-drop-region-face'.")
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-cursor'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2396,248 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
-          (setq deactivate-mark nil)
-          (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-dropped)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (condition-case nil
+        (progn
+          (track-mouse
+            ;; When event was "click" instead of "drag", skip loop.
+            (while (progn
+                     ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                     (setq event (read-key))  ; read-event or read-key
+                     (or (mouse-movement-p event)
+                         ;; Handle `mouse-autoselect-window'.
+                         (eq (car-safe event) 'select-window)))
+              ;; Obtain the dragged text in region.  When the loop was
+              ;; skipped, value-selection remains nil.
+              (unless value-selection
+                (setq value-selection (buffer-substring start end))
+                (when mouse-drag-and-drop-region-show-tooltip
+                  (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                    (setq text-tooltip (if (and (integerp text-size)
+                                                (> (length value-selection) text-size))
+                                           (concat
+                                            (substring value-selection 0 (/ text-size 2))
+                                            "\n...\n"
+                                            (substring value-selection (- (/ text-size 2)) -1))
+                                         value-selection))))
+
+                ;; Check if selected text is read-only.
+                ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+                ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                (setq text-from-read-only (or text-from-read-only
+                                              (get-text-property start 'read-only)
+                                              (not (equal
+                                                    (next-single-char-property-change start 'read-only nil end)
+                                                    end)))))
+              (setq window-to-paste (posn-window (event-end event)))
+              (setq point-to-paste (posn-point (event-end event)))
+              (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                      (when (windowp window-to-paste)
+                                        (setq buf (window-buffer window-to-paste))
+                                        (when (not (minibufferp buf))
+                                          buf))))
+              (setq cursor-in-text-area (and window-to-paste
+                                             point-to-paste
+                                             buffer-to-paste))
+
+              (when cursor-in-text-area
+                ;; Check if point under mouse is read-only.
+                (save-window-excursion
+                  (select-window window-to-paste)
+                  ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                  (setq point-to-paste-read-only
+                        (or buffer-read-only
+                            (get-text-property point-to-paste 'read-only))))
+
+                ;; Check if "drag but negligible".  Operation "drag but
+                ;; negligible" is defined as drag-and-drop the text to
+                ;; the original region.  When modifier is pressed, the
+                ;; text will be inserted to inside of the original
+                ;; region.
+                (setq drag-but-negligible
+                      (member mouse-drag-and-drop-region-face
+                              (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                      (overlays-at point-to-paste)))))
+
+              ;; Show a tooltip.
+              (if (and mouse-drag-and-drop-region-show-tooltip
+                       (not drag-but-negligible)
+                       (not point-to-paste-read-only)
+                       cursor-in-text-area)
+                  (tooltip-show text-tooltip)
+                (tooltip-hide))
+
+              ;; Show cursor and highlight the original region.
+              (when mouse-drag-and-drop-region-show-cursor
+                ;; Modify cursor even when point is out of frame.
+                (setq cursor-type (cond
+                                   ((not cursor-in-text-area)
+                                    nil)
+                                   ((or point-to-paste-read-only
+                                        drag-but-negligible)
+                                    'hollow)
+                                   (t
+                                    'bar)))
+                (when cursor-in-text-area
+                  (overlay-put mouse-drag-and-drop-overlay
+                               'face mouse-drag-and-drop-region-face)
+                  (deactivate-mark) ; Maintain region in other window.
+                  (mouse-set-point event)))))
+
+          ;; Hide a tooltip.
+          (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+          ;; Check if modifier was pressed on drop.
+          (setq no-modifier-on-drop
+                (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+          ;; Check if event was "click".
+          (setq clicked (not value-selection))
+
+          ;; Restore status on drag to outside of text-area or non-mouse input.
+          ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+          (when (or (not cursor-in-text-area)
+                    (not (equal (event-basic-type event) mouse-button)))
+            (setq drag-but-negligible t
+                  no-modifier-on-drop t))
+
+          ;; Do not modify any buffers when event is "click",
+          ;; "drag but negligible", or "drag to read-only".
+          (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+                  (if no-modifier-on-drop
+                      mouse-drag-and-drop-region-cut-when-buffers-differ
+                    (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+                 (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+                 (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                                no-modifier-on-drop))
+                 (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                                 mouse-drag-and-drop-region-cut-when-buffers-differ))
+                 (cannot-paste (or point-to-paste-read-only
+                                   (when (or wanna-cut-on-same-buffer
+                                             wanna-cut-on-other-buffer)
+                                     text-from-read-only))))
+
+            (cond
+             ;; Move point within region.
+             (clicked
+              (deactivate-mark)
+              (mouse-set-point event))
+             ;; Undo operation. Set back the original text as region.
+             ((or (and drag-but-negligible
+                       no-modifier-on-drop)
+                  cannot-paste)
+              ;; Inform user either source or destination buffer cannot be modified.
+              (when (and (not drag-but-negligible)
+                         cannot-paste)
+                (message "Buffer is read-only"))
+
+              ;; Select source window back and restore region.
+              ;; (set-window-point window point)
+              (select-window window)
+              (goto-char point)
+              (setq deactivate-mark nil)
+              (activate-mark))
+             ;; Modify buffers.
+             (t
+              ;; * DESTINATION BUFFER::
+              ;; Insert the text to destination buffer under mouse.
+              (select-window window-to-paste)
+              (setq window-dropped window-to-paste)
+              (goto-char point-to-paste)
+              (push-mark)
+              (insert value-selection)
+              ;; On success, set the text as region on destination buffer.
+              (when (not (equal (mark) (point)))
+                (setq deactivate-mark nil)
+                (activate-mark))
+
+              ;; * SOURCE BUFFER::
+              ;; Set back the original text as region or delete the original
+              ;; text, on source buffer.
+              (if wanna-paste-to-same-buffer
+                  ;; When source buffer and destination buffer are the same,
+                  ;; remove the original text.
+                  (when no-modifier-on-drop
+                    (let (deactivate-mark)
+                      (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                     (overlay-end mouse-drag-and-drop-overlay))))
+                ;; When source buffer and destination buffer are different,
+                ;; keep (set back the original text as region) or remove the
+                ;; original text.
+                (select-window window) ; Select window with source buffer.
+                (goto-char point) ; Move point to the original text on source buffer.
+
+                (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                    ;; Remove the dragged text from source buffer like
+                    ;; operation `cut'.
+                    (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                   (overlay-end mouse-drag-and-drop-overlay))
+                  ;; Set back the dragged text as region on source buffer
+                  ;; like operation `copy'.
+                  (activate-mark))
+                (select-window window-to-paste))))))
+      (error nil))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (unless (eq window window-dropped)
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.

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

* Re: mouse-drag-and-drop-region
  2017-12-05  4:57                       ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-05  8:53                         ` martin rudalics
  2017-12-06  9:29                           ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-05  8:53 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, agrambot, emacs-devel

 > Thank you.  I think that by your revision, the problem was solved.  I
 > also revised code not to let user drop the text to minibuffer.

Thanks.  One issue I'm yet uncertain about: This part

               (if (and mouse-drag-and-drop-region-show-tooltip
                        (not drag-but-negligible)
                        (not point-to-paste-read-only)
                        cursor-in-text-area)
                   (tooltip-show text-tooltip)
                 (tooltip-hide))

means that the tooltip text does not appear as long as the mouse is
within the initial region (because there drag-but-negligible is non-nil,
I presume).  This comes somewhat unexpected - I'd expect the initial
feedback via a tooltip to appear right away as soon as I start dragging.

Personally, I'd even show the tooltip text when the mouse is temporarily
out of the frame and leave it to the cursor to indicate whether a drop
is possible at that position.  But this is a personal preference - I'll
check in whatever you prefer.

 > This
 > time, I attach a patch as a separated file.

Highly appreciated.  Applies without any problems now.

 >> Please consider also the following four bindings in `mouse-drag-track':
 >>
 >>           (echo-keystrokes 0)

I remember that occasionally during dragging some thing (I don't
remember whether it does happen with the region) I see in the echo area
text like down-mouse-1 or the like appear.  If you see that too, this
binding might be useful to suppress such feedback.

 >>
 >>           (make-cursor-line-fully-visible nil)
 >>
 >>           ;; Suppress automatic hscrolling, because that is a nuisance
 >>           ;; when setting point near the right fringe (but see below).
 >>           (auto-hscroll-mode-saved auto-hscroll-mode)

Both of theses might have impact when you move the cursor to a position
that is only partially visible at some border of the window.  You might
have to experiment, for example, by starting with a horizontally
scrolled window or a window with point near the bottom to see the
impact.

 >>           (old-track-mouse track-mouse)

This should handle the case where `mouse-drag-and-drop-region'
intercepts an already ongoing track operation.  I have no idea whether
such a thing can happen in practice.

 >> Maybe they are useful for you as well (a lot of experience went into the
 >> coding of that function).
 >
 > I wonder if this is beyond my skill.  Could you revise this part?

I indicated above whether and why these may be useful.  We probably
should just wait until real problems show up in this regard.

 > It is a good idea.  Now tooltip shows only substring.  I think
 > mouse-drag-and-drop-region-show-tooltip should be something like 256
 > by default.

OK.

 >> Finally, please think of how to embed your function into other packages:
 >> For example, how would a user drag file names from one dired buffer to
 >> another in order to copy or move the associated files from one directory
 >> to another?  Can we accomodate an exit function to do the pasting job?
 >
 > It is a good idea.  I suppose you mean dragging `file' when
 > event-start is with 'dired-filename.

Never using dired I have no idea.  But ISTR that most two-pane file
managers (aka Norton Commander clones) have some mouse support to do
that.  So it might be a good idea to think about how to incorporate such
support right now.

One issue with dired and customization buffers we probably have to
resolve is the following: When `inhibit-read-only' is non-nil, we should
allow cutting/pasting from/into read-only buffers or text.  I've never
looked into this matter.  Maybe you can find some code which does handle
that so we can steal it.

martin



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

* Re: mouse-drag-and-drop-region
  2017-12-05  8:53                         ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-06  9:29                           ` Tak Kunihiro
  2017-12-07  9:26                             ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-06  9:29 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

[-- Attachment #1: Type: Text/Plain, Size: 1406 bytes --]

Thank you for comments.

> I'd expect the initial feedback via a tooltip to appear right away
> as soon as I start dragging.  Personally, I'd even show the tooltip
> text when the mouse is temporarily out of the frame and leave it to
> the cursor to indicate whether a drop is possible at that position.

I think you are right.  I revised the code back.

>>>           (echo-keystrokes 0)
>>>           (make-cursor-line-fully-visible nil)
>>>           (auto-hscroll-mode-saved auto-hscroll-mode)
>>>           (old-track-mouse track-mouse)
> We probably should just wait until real problems show up in this
> regard.

Thank you for the comments.  I agree.  Let's postpone.

> (dolist (state states)
>       (let ((window (car state)))
>         (unless (eq window window-dropped)
>           (set-window-start window (nth 1 state) 'noforce)
>           (set-marker (nth 1 state) nil)
>           ;; If window is selected, the following automatically sets
>           ;; point for that window's buffer.
>           (set-window-point window (nth 2 state))
>           (set-marker (nth 2 state) nil))
>         (with-current-buffer (window-buffer window)
>           (setq cursor-type (nth 3 state)))))

I found a glitch.  I think

  (unless (eq window window-dropped)...

should be something like

  (when (and window-dropped
             (not (eq window window-dropped)))...

.

I attach the revise code.

[-- Attachment #2: mouse.el.diff --]
[-- Type: Text/X-Patch, Size: 16946 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..aacb550
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,33 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is an integer, such as 32 or 64, a number giving
+the maximum length of the string shown in tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+In addition, highlight the original region with
+`mouse-drag-and-drop-region-face'.")
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-cursor'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2396,251 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
-          (setq deactivate-mark nil)
-          (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-dropped)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (condition-case nil
+        (progn
+          (track-mouse
+            ;; When event was "click" instead of "drag", skip loop.
+            (while (progn
+                     ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                     (setq event (read-key))  ; read-event or read-key
+                     (or (mouse-movement-p event)
+                         ;; Handle `mouse-autoselect-window'.
+                         (eq (car-safe event) 'select-window)))
+              ;; Obtain the dragged text in region.  When the loop was
+              ;; skipped, value-selection remains nil.
+              (unless value-selection
+                (setq value-selection (buffer-substring start end))
+                (when mouse-drag-and-drop-region-show-tooltip
+                  (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                    (setq text-tooltip (if (and (integerp text-size)
+                                                (> (length value-selection) text-size))
+                                           (concat
+                                            (substring value-selection 0 (/ text-size 2))
+                                            "\n...\n"
+                                            (substring value-selection (- (/ text-size 2)) -1))
+                                         value-selection))))
+
+                ;; Check if selected text is read-only.
+                ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+                ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                (setq text-from-read-only (or text-from-read-only
+                                              (get-text-property start 'read-only)
+                                              (not (equal
+                                                    (next-single-char-property-change start 'read-only nil end)
+                                                    end)))))
+              (setq window-to-paste (posn-window (event-end event)))
+              (setq point-to-paste (posn-point (event-end event)))
+              (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                      (when (windowp window-to-paste)
+                                        (setq buf (window-buffer window-to-paste))
+                                        (when (not (minibufferp buf))
+                                          buf))))
+              (setq cursor-in-text-area (and window-to-paste
+                                             point-to-paste
+                                             buffer-to-paste))
+
+              (when cursor-in-text-area
+                ;; Check if point under mouse is read-only.
+                (save-window-excursion
+                  (select-window window-to-paste)
+                  ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                  (setq point-to-paste-read-only
+                        (or buffer-read-only
+                            (get-text-property point-to-paste 'read-only))))
+
+                ;; Check if "drag but negligible".  Operation "drag but
+                ;; negligible" is defined as drag-and-drop the text to
+                ;; the original region.  When modifier is pressed, the
+                ;; text will be inserted to inside of the original
+                ;; region.
+                (setq drag-but-negligible
+                      (member mouse-drag-and-drop-region-face
+                              (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                      (overlays-at point-to-paste)))))
+
+              ;; Show a tooltip.
+              (if mouse-drag-and-drop-region-show-tooltip
+                  ;; (and mouse-drag-and-drop-region-show-tooltip
+                  ;;      (not drag-but-negligible)
+                  ;;      (not point-to-paste-read-only)
+                  ;;      cursor-in-text-area)
+                  (tooltip-show text-tooltip)
+                (tooltip-hide))
+
+              ;; Show cursor and highlight the original region.
+              (when mouse-drag-and-drop-region-show-cursor
+                ;; Modify cursor even when point is out of frame.
+                (setq cursor-type (cond
+                                   ((not cursor-in-text-area)
+                                    nil)
+                                   ((or point-to-paste-read-only
+                                        drag-but-negligible)
+                                    'hollow)
+                                   (t
+                                    'bar)))
+                (when cursor-in-text-area
+                  (overlay-put mouse-drag-and-drop-overlay
+                               'face mouse-drag-and-drop-region-face)
+                  (deactivate-mark) ; Maintain region in other window.
+                  (mouse-set-point event)))))
+
+          ;; Hide a tooltip.
+          (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+          ;; Check if modifier was pressed on drop.
+          (setq no-modifier-on-drop
+                (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+          ;; Check if event was "click".
+          (setq clicked (not value-selection))
+
+          ;; Restore status on drag to outside of text-area or non-mouse input.
+          ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+          (when (or (not cursor-in-text-area)
+                    (not (equal (event-basic-type event) mouse-button)))
+            (setq drag-but-negligible t
+                  no-modifier-on-drop t))
+
+          ;; Do not modify any buffers when event is "click",
+          ;; "drag but negligible", or "drag to read-only".
+          (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+                  (if no-modifier-on-drop
+                      mouse-drag-and-drop-region-cut-when-buffers-differ
+                    (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+                 (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+                 (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                                no-modifier-on-drop))
+                 (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                                 mouse-drag-and-drop-region-cut-when-buffers-differ))
+                 (cannot-paste (or point-to-paste-read-only
+                                   (when (or wanna-cut-on-same-buffer
+                                             wanna-cut-on-other-buffer)
+                                     text-from-read-only))))
+
+            (cond
+             ;; Move point within region.
+             (clicked
+              (deactivate-mark)
+              (mouse-set-point event))
+             ;; Undo operation. Set back the original text as region.
+             ((or (and drag-but-negligible
+                       no-modifier-on-drop)
+                  cannot-paste)
+              ;; Inform user either source or destination buffer cannot be modified.
+              (when (and (not drag-but-negligible)
+                         cannot-paste)
+                (message "Buffer is read-only"))
+
+              ;; Select source window back and restore region.
+              ;; (set-window-point window point)
+              (select-window window)
+              (goto-char point)
+              (setq deactivate-mark nil)
+              (activate-mark))
+             ;; Modify buffers.
+             (t
+              ;; * DESTINATION BUFFER::
+              ;; Insert the text to destination buffer under mouse.
+              (select-window window-to-paste)
+              (setq window-dropped window-to-paste)
+              (goto-char point-to-paste)
+              (push-mark)
+              (insert value-selection)
+              ;; On success, set the text as region on destination buffer.
+              (when (not (equal (mark) (point)))
+                (setq deactivate-mark nil)
+                (activate-mark))
+
+              ;; * SOURCE BUFFER::
+              ;; Set back the original text as region or delete the original
+              ;; text, on source buffer.
+              (if wanna-paste-to-same-buffer
+                  ;; When source buffer and destination buffer are the same,
+                  ;; remove the original text.
+                  (when no-modifier-on-drop
+                    (let (deactivate-mark)
+                      (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                     (overlay-end mouse-drag-and-drop-overlay))))
+                ;; When source buffer and destination buffer are different,
+                ;; keep (set back the original text as region) or remove the
+                ;; original text.
+                (select-window window) ; Select window with source buffer.
+                (goto-char point) ; Move point to the original text on source buffer.
+
+                (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                    ;; Remove the dragged text from source buffer like
+                    ;; operation `cut'.
+                    (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                   (overlay-end mouse-drag-and-drop-overlay))
+                  ;; Set back the dragged text as region on source buffer
+                  ;; like operation `copy'.
+                  (activate-mark))
+                (select-window window-to-paste))))))
+      (error nil))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-dropped
+                   (not (eq window window-dropped)))
+          ;; unless (eq window window-dropped)
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.

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

* Re: mouse-drag-and-drop-region
  2017-12-06  9:29                           ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-07  9:26                             ` martin rudalics
  2017-12-07 21:45                               ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-07  9:26 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, agrambot, emacs-devel

 > I found a glitch.  I think
 >
 >    (unless (eq window window-dropped)...
 >
 > should be something like
 >
 >    (when (and window-dropped
 >               (not (eq window window-dropped)))...

Wouldn't this mean that when window-dropped is nil and the user has
changed the point of some other window, that other's window point is not
reverted to its original position?  I think the

     (unless (eq window window-dropped)

DTRT: WINDOW cannot be nil here and if it equals WINDOW-DROPPED then we
should not revert its point.  Or am I missing something?

But to relax indentation we should turn the

+    (condition-case nil
+        (progn
...
+      (error nil))

into either

      (ignore-errors
       ...)

or the more informative

      (with-demoted-errors
       "mouse-drag-and-drop-region error: %s"
       ...)

whichever you prefer.

martin



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

* Re: mouse-drag-and-drop-region
  2017-12-07  9:26                             ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-07 21:45                               ` Tak Kunihiro
  2017-12-08 10:12                                 ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-07 21:45 UTC (permalink / raw)
  To: rudalics; +Cc: eliz, tak.kunihiro, agrambot, emacs-devel

>> I found a glitch.  I think
>>
>>    (unless (eq window window-dropped)...
>>
>> should be something like
>>
>>    (when (and window-dropped
>>               (not (eq window window-dropped)))...
>
> Wouldn't this mean that when window-dropped is nil and the user has
> changed the point of some other window, that other's window point is
> not reverted to its original position?  I think the
>
>     (unless (eq window window-dropped)
> 
> DTRT: WINDOW cannot be nil here and if it equals WINDOW-DROPPED then
> we should not revert its point.  Or am I missing something?

When the user just clicks within the region (no drag), window-dropped
remains nil.  On such condition, window-start should not be set.

Let's say there are two window top and bottom (T and B) in a frame.
Scroll T to the end.  Make region in B.  Then click the region.  I
will see T to be scrolled to the beginning.



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

* Re: mouse-drag-and-drop-region
  2017-12-07 21:45                               ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-08 10:12                                 ` martin rudalics
  2017-12-08 16:14                                   ` mouse-drag-and-drop-region Robert Weiner
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-08 10:12 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, agrambot, emacs-devel

 > When the user just clicks within the region (no drag), window-dropped
 > remains nil.  On such condition, window-start should not be set.
 >
 > Let's say there are two window top and bottom (T and B) in a frame.
 > Scroll T to the end.  Make region in B.  Then click the region.  I
 > will see T to be scrolled to the beginning.

Aha...  Then let's rename window-dropped to something like window-exempt
and set window-exempt to the window either clicked at or where the drop
occurs.  Would that be OK?

martin



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

* Re: mouse-drag-and-drop-region
  2017-12-08 10:12                                 ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-08 16:14                                   ` Robert Weiner
  2017-12-09 10:35                                     ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Robert Weiner @ 2017-12-08 16:14 UTC (permalink / raw)
  To: martin rudalics; +Cc: Eli Zaretskii, Tak Kunihiro, Alex, emacs-devel

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

On Fri, Dec 8, 2017 at 5:12 AM, martin rudalics <rudalics@gmx.at> wrote:

> > When the user just clicks within the region (no drag), window-dropped
> > remains nil.  On such condition, window-start should not be set.
> >
> > Let's say there are two window top and bottom (T and B) in a frame.
> > Scroll T to the end.  Make region in B.  Then click the region.  I
> > will see T to be scrolled to the beginning.
>
> Aha...  Then let's rename window-dropped to something like window-exempt
> and set window-exempt to the window either clicked at or where the drop
> occurs.  Would that be OK?


​Better names might be droppped-window or destination-window.
If this is nil, then no drag-and-drop occurred; otherwise,
it is the window of the drop, so why call it window-exempt?

Bob
​

[-- Attachment #2: Type: text/html, Size: 1808 bytes --]

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

* Re: mouse-drag-and-drop-region
  2017-12-08 16:14                                   ` mouse-drag-and-drop-region Robert Weiner
@ 2017-12-09 10:35                                     ` martin rudalics
  2017-12-14 23:14                                       ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-09 10:35 UTC (permalink / raw)
  To: rswgnu; +Cc: Eli Zaretskii, Tak Kunihiro, Alex, emacs-devel

 > ​Better names might be droppped-window or destination-window.
 > If this is nil, then no drag-and-drop occurred; otherwise,
 > it is the window of the drop, so why call it window-exempt?

Because the click or drop exempts that window from the point restoration
mechanism.

martin




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

* Re: mouse-drag-and-drop-region
  2017-12-09 10:35                                     ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-14 23:14                                       ` Tak Kunihiro
  2017-12-15  8:50                                         ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-14 23:14 UTC (permalink / raw)
  To: martin rudalics; +Cc: rswgnu, Eli Zaretskii, Kunihiro Tak, Alex, emacs-devel

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

I re-re-re-revised mouse-drag-and-drop-region.  I'm sending reply to https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00258.html, ChangeLog, and patch.

* ChangeLog

2017-12-16 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>

        Improve comments and have four new options

        * lisp/mouse.el (mouse-drag-and-drop-region): Have option to make dragging cut among buffers. Make usage of tooltip option.
        (mouse-drag-and-drop-region-cut-when-buffers-differ): New variable. If non-nil, text is cut instead of copied when dragged among buffers.
        (mouse-drag-and-drop-region-show-tooltip): New variable. If non-nil, text is shown by tooltip in a graphic display.
        (mouse-drag-and-drop-region-show-cursor): New variable. If non-nil, point is set to where the mouse cursor.
        (mouse-drag-and-drop-region-face): New variable for face. The face is used to highlight the original text.

* Reply

>>> When the user just clicks within the region (no drag), window-dropped
>>> remains nil.  On such condition, window-start should not be set.
>>>
>>> Let's say there are two window top and bottom (T and B) in a frame.
>>> Scroll T to the end.  Make region in B.  Then click the region.  I
>>> will see T to be scrolled to the beginning.
>>
>> Then let's rename window-dropped to something like window-exempt
>> and set window-exempt to the window either clicked at or where the drop
>> occurs.
>
>> ​Better names might be droppped-window or destination-window.
>> If this is nil, then no drag-and-drop occurred; otherwise,
>> it is the window of the drop, so why call it window-exempt?
>
> Because the click or drop exempts that window from the point restoration
> mechanism.

OK.  I changed from `window-dropped' to `window-exempt’.


[-- Attachment #2: mouse.el.diff --]
[-- Type: application/octet-stream, Size: 17243 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..bc56448
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2361,6 +2361,33 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is an integer, such as 32 or 64, a number giving
+the maximum length of the string shown in tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defvar mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+In addition, highlight the original region with
+`mouse-drag-and-drop-region-face'.")
+
+(defvar mouse-drag-and-drop-region-face 'region
+  "Face to highlight the original text during dragging.
+See also `mouse-drag-and-drop-region-show-cursor'.")
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2396,250 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
-        (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
-          (goto-char point)
-          (setq deactivate-mark nil)
-          (activate-mark))
-         ;; "event was click"
-         (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-exempt)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (condition-case nil
+        (progn
+          (track-mouse
+            ;; When event was "click" instead of "drag", skip loop.
+            (while (progn
+                     ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                     (setq event (read-key))  ; read-event or read-key
+                     (or (mouse-movement-p event)
+                         ;; Handle `mouse-autoselect-window'.
+                         (eq (car-safe event) 'select-window)))
+              ;; Obtain the dragged text in region.  When the loop was
+              ;; skipped, value-selection remains nil.
+              (unless value-selection
+                (setq value-selection (buffer-substring start end))
+                (when mouse-drag-and-drop-region-show-tooltip
+                  (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                    (setq text-tooltip (if (and (integerp text-size)
+                                                (> (length value-selection) text-size))
+                                           (concat
+                                            (substring value-selection 0 (/ text-size 2))
+                                            "\n...\n"
+                                            (substring value-selection (- (/ text-size 2)) -1))
+                                         value-selection))))
+
+                ;; Check if selected text is read-only.
+                ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+                ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                (setq text-from-read-only (or text-from-read-only
+                                              (get-text-property start 'read-only)
+                                              (not (equal
+                                                    (next-single-char-property-change start 'read-only nil end)
+                                                    end)))))
+              (setq window-to-paste (posn-window (event-end event)))
+              (setq point-to-paste (posn-point (event-end event)))
+              (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                      (when (windowp window-to-paste)
+                                        (setq buf (window-buffer window-to-paste))
+                                        (when (not (minibufferp buf))
+                                          buf))))
+              (setq cursor-in-text-area (and window-to-paste
+                                             point-to-paste
+                                             buffer-to-paste))
+
+              (when cursor-in-text-area
+                ;; Check if point under mouse is read-only.
+                (save-window-excursion
+                  (select-window window-to-paste)
+                  ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+                  (setq point-to-paste-read-only
+                        (or buffer-read-only
+                            (get-text-property point-to-paste 'read-only))))
+
+                ;; Check if "drag but negligible".  Operation "drag but
+                ;; negligible" is defined as drag-and-drop the text to
+                ;; the original region.  When modifier is pressed, the
+                ;; text will be inserted to inside of the original
+                ;; region.
+                (setq drag-but-negligible
+                      (member mouse-drag-and-drop-region-face
+                              (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                      (overlays-at point-to-paste)))))
+
+              ;; Show a tooltip.
+              (if mouse-drag-and-drop-region-show-tooltip
+                  ;; (and mouse-drag-and-drop-region-show-tooltip
+                  ;;      (not drag-but-negligible)
+                  ;;      (not point-to-paste-read-only)
+                  ;;      cursor-in-text-area)
+                  (tooltip-show text-tooltip)
+                (tooltip-hide))
+
+              ;; Show cursor and highlight the original region.
+              (when mouse-drag-and-drop-region-show-cursor
+                ;; Modify cursor even when point is out of frame.
+                (setq cursor-type (cond
+                                   ((not cursor-in-text-area)
+                                    nil)
+                                   ((or point-to-paste-read-only
+                                        drag-but-negligible)
+                                    'hollow)
+                                   (t
+                                    'bar)))
+                (when cursor-in-text-area
+                  (overlay-put mouse-drag-and-drop-overlay
+                               'face mouse-drag-and-drop-region-face)
+                  (deactivate-mark) ; Maintain region in other window.
+                  (mouse-set-point event)))))
+
+          ;; Hide a tooltip.
+          (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+          ;; Check if modifier was pressed on drop.
+          (setq no-modifier-on-drop
+                (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+          ;; Check if event was "click".
+          (setq clicked (not value-selection))
+
+          ;; Restore status on drag to outside of text-area or non-mouse input.
+          ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+          (when (or (not cursor-in-text-area)
+                    (not (equal (event-basic-type event) mouse-button)))
+            (setq drag-but-negligible t
+                  no-modifier-on-drop t))
+
+          ;; Do not modify any buffers when event is "click",
+          ;; "drag but negligible", or "drag to read-only".
+          (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+                  (if no-modifier-on-drop
+                      mouse-drag-and-drop-region-cut-when-buffers-differ
+                    (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+                 (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+                 (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                                no-modifier-on-drop))
+                 (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                                 mouse-drag-and-drop-region-cut-when-buffers-differ))
+                 (cannot-paste (or point-to-paste-read-only
+                                   (when (or wanna-cut-on-same-buffer
+                                             wanna-cut-on-other-buffer)
+                                     text-from-read-only))))
+
+            (cond
+             ;; Move point within region.
+             (clicked
+              (deactivate-mark)
+              (mouse-set-point event))
+             ;; Undo operation. Set back the original text as region.
+             ((or (and drag-but-negligible
+                       no-modifier-on-drop)
+                  cannot-paste)
+              ;; Inform user either source or destination buffer cannot be modified.
+              (when (and (not drag-but-negligible)
+                         cannot-paste)
+                (message "Buffer is read-only"))
+
+              ;; Select source window back and restore region.
+              ;; (set-window-point window point)
+              (select-window window)
+              (goto-char point)
+              (setq deactivate-mark nil)
+              (activate-mark))
+             ;; Modify buffers.
+             (t
+              ;; * DESTINATION BUFFER::
+              ;; Insert the text to destination buffer under mouse.
+              (select-window window-to-paste)
+              (setq window-exempt window-to-paste)
+              (goto-char point-to-paste)
+              (push-mark)
+              (insert value-selection)
+              ;; On success, set the text as region on destination buffer.
+              (when (not (equal (mark) (point)))
+                (setq deactivate-mark nil)
+                (activate-mark))
+
+              ;; * SOURCE BUFFER::
+              ;; Set back the original text as region or delete the original
+              ;; text, on source buffer.
+              (if wanna-paste-to-same-buffer
+                  ;; When source buffer and destination buffer are the same,
+                  ;; remove the original text.
+                  (when no-modifier-on-drop
+                    (let (deactivate-mark)
+                      (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                     (overlay-end mouse-drag-and-drop-overlay))))
+                ;; When source buffer and destination buffer are different,
+                ;; keep (set back the original text as region) or remove the
+                ;; original text.
+                (select-window window) ; Select window with source buffer.
+                (goto-char point) ; Move point to the original text on source buffer.
+
+                (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                    ;; Remove the dragged text from source buffer like
+                    ;; operation `cut'.
+                    (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                   (overlay-end mouse-drag-and-drop-overlay))
+                  ;; Set back the dragged text as region on source buffer
+                  ;; like operation `copy'.
+                  (activate-mark))
+                (select-window window-to-paste))))))
+      (error nil))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-exempt
+                   (not (eq window window-exempt)))
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.

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

* Re: mouse-drag-and-drop-region
  2017-12-14 23:14                                       ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-15  8:50                                         ` martin rudalics
  2017-12-15 13:25                                           ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-15  8:50 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: Eli Zaretskii, rswgnu, Alex, emacs-devel

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

 > I re-re-re-revised mouse-drag-and-drop-region.  I'm sending reply to https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00258.html, ChangeLog, and patch.
 >
 > * ChangeLog
 >
 > 2017-12-16 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
 >
 >          Improve comments and have four new options
 >
 >          * lisp/mouse.el (mouse-drag-and-drop-region): Have option to make dragging cut among buffers. Make usage of tooltip option.
 >          (mouse-drag-and-drop-region-cut-when-buffers-differ): New variable. If non-nil, text is cut instead of copied when dragged among buffers.
 >          (mouse-drag-and-drop-region-show-tooltip): New variable. If non-nil, text is shown by tooltip in a graphic display.
 >          (mouse-drag-and-drop-region-show-cursor): New variable. If non-nil, point is set to where the mouse cursor.
 >          (mouse-drag-and-drop-region-face): New variable for face. The face is used to highlight the original text.

Thanks.  I resend you yet another revised version which mostly fixes the
doc-strings of these options and replaces the option
`mouse-drag-and-drop-region-face' with a face
`mouse-drag-and-drop-region' inheriting from the region face.  Please
have a look.  Unless you or someone else sees problems, I will install
it.

Thanks again for your efforts, martin

[-- Attachment #2: mouse.el.diff --]
[-- Type: text/plain, Size: 17171 bytes --]

--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2345,10 +2345,10 @@ mouse-appearance-menu
 \f
 ;; Drag and drop support.
 (defcustom mouse-drag-and-drop-region nil
-  "If non-nil, dragging the mouse drags the region, if that exists.
-If the value is a modifier, such as `control' or `shift' or `meta',
-then if that modifier key is pressed when dropping the region, region
-text is copied instead of being cut."
+  "If non-nil, dragging the mouse drags the region, if it exists.
+If the value is a modifier, such as `control' or `shift' or
+`meta', then if that modifier key is pressed when dropping the
+region, text is copied instead of being cut."
   :type `(choice
           (const :tag "Disable dragging the region" nil)
           ,@(mapcar
@@ -2361,6 +2361,45 @@ mouse-drag-and-drop-region
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is nil, `mouse-drag-and-drop-region' does not show
+tooltips.  If this is t, it shows the entire text dragged in a
+tooltip.  If this is an integer (as with the default value of
+256), it will show that many characters of the dragged text in
+a tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+If this is nil, `mouse-drag-and-drop-region' leaves point alone.
+Otherwise, it will move point together with the mouse cursor and,
+in addition, temporarily highlight the original region with the
+`mouse-drag-and-drop-region' face."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defface mouse-drag-and-drop-region '((t :inherit region))
+  "Face to highlight original text during dragging.
+This face is used by `mouse-drag-and-drop-region' to temporarily
+highlight the original region when
+`mouse-drag-and-drop-region-show-cursor' is non-nil."
+  :version "26.1"
+  :group 'mouse)
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2408,248 @@ mouse-drag-and-drop-region
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-exempt)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (ignore-errors
+      (track-mouse
+        ;; When event was "click" instead of "drag", skip loop.
+        (while (progn
+                 ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                 (setq event (read-key))      ; read-event or read-key
+                 (or (mouse-movement-p event)
+                     ;; Handle `mouse-autoselect-window'.
+                     (eq (car-safe event) 'select-window)))
+          ;; Obtain the dragged text in region.  When the loop was
+          ;; skipped, value-selection remains nil.
+          (unless value-selection
+            (setq value-selection (buffer-substring start end))
+            (when mouse-drag-and-drop-region-show-tooltip
+              (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                (setq text-tooltip (if (and (integerp text-size)
+                                            (> (length value-selection) text-size))
+                                       (concat
+                                        (substring value-selection 0 (/ text-size 2))
+                                        "\n...\n"
+                                        (substring value-selection (- (/ text-size 2)) -1))
+                                     value-selection))))
+
+            ;; Check if selected text is read-only.
+            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+            ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+            (setq text-from-read-only (or text-from-read-only
+                                          (get-text-property start 'read-only)
+                                          (not (equal
+                                                (next-single-char-property-change start 'read-only nil end)
+                                                end)))))
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+          (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                  (when (windowp window-to-paste)
+                                    (setq buf (window-buffer window-to-paste))
+                                    (when (not (minibufferp buf))
+                                      buf))))
+          (setq cursor-in-text-area (and window-to-paste
+                                         point-to-paste
+                                         buffer-to-paste))
+
+          (when cursor-in-text-area
+            ;; Check if point under mouse is read-only.
+            (save-window-excursion
+              (select-window window-to-paste)
+              ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+              (setq point-to-paste-read-only
+                    (or buffer-read-only
+                        (get-text-property point-to-paste 'read-only))))
+
+            ;; Check if "drag but negligible".  Operation "drag but
+            ;; negligible" is defined as drag-and-drop the text to
+            ;; the original region.  When modifier is pressed, the
+            ;; text will be inserted to inside of the original
+            ;; region.
+            (setq drag-but-negligible
+                  (member mouse-drag-and-drop-region
+                          (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                  (overlays-at point-to-paste)))))
+
+          ;; Show a tooltip.
+          (if mouse-drag-and-drop-region-show-tooltip
+              ;; (and mouse-drag-and-drop-region-show-tooltip
+              ;;      (not drag-but-negligible)
+              ;;      (not point-to-paste-read-only)
+              ;;      cursor-in-text-area)
+              (tooltip-show text-tooltip)
+            (tooltip-hide))
+
+          ;; Show cursor and highlight the original region.
+          (when mouse-drag-and-drop-region-show-cursor
+            ;; Modify cursor even when point is out of frame.
+            (setq cursor-type (cond
+                               ((not cursor-in-text-area)
+                                nil)
+                               ((or point-to-paste-read-only
+                                    drag-but-negligible)
+                                'hollow)
+                               (t
+                                'bar)))
+            (when cursor-in-text-area
+              (overlay-put mouse-drag-and-drop-overlay
+                           'face mouse-drag-and-drop-region)
+              (deactivate-mark)     ; Maintain region in other window.
+              (mouse-set-point event)))))
+
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+      ;; Check if modifier was pressed on drop.
+      (setq no-modifier-on-drop
+            (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+      ;; Check if event was "click".
+      (setq clicked (not value-selection))
+
+      ;; Restore status on drag to outside of text-area or non-mouse input.
+      ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+      (when (or (not cursor-in-text-area)
+                (not (equal (event-basic-type event) mouse-button)))
+        (setq drag-but-negligible t
+              no-modifier-on-drop t))
+
+      ;; Do not modify any buffers when event is "click",
+      ;; "drag but negligible", or "drag to read-only".
+      (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+              (if no-modifier-on-drop
+                  mouse-drag-and-drop-region-cut-when-buffers-differ
+                (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+             (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+             (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                            no-modifier-on-drop))
+             (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                             mouse-drag-and-drop-region-cut-when-buffers-differ))
+             (cannot-paste (or point-to-paste-read-only
+                               (when (or wanna-cut-on-same-buffer
+                                         wanna-cut-on-other-buffer)
+                                 text-from-read-only))))
+
         (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
+         ;; Move point within region.
+         (clicked
+          (deactivate-mark)
+          (mouse-set-point event))
+         ;; Undo operation. Set back the original text as region.
+         ((or (and drag-but-negligible
+                   no-modifier-on-drop)
+              cannot-paste)
+          ;; Inform user either source or destination buffer cannot be modified.
+          (when (and (not drag-but-negligible)
+                     cannot-paste)
+            (message "Buffer is read-only"))
+
+          ;; Select source window back and restore region.
+          ;; (set-window-point window point)
+          (select-window window)
           (goto-char point)
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
+         ;; Modify buffers.
          (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+          ;; * DESTINATION BUFFER::
+          ;; Insert the text to destination buffer under mouse.
+          (select-window window-to-paste)
+          (setq window-exempt window-to-paste)
+          (goto-char point-to-paste)
+          (push-mark)
+          (insert value-selection)
+          ;; On success, set the text as region on destination buffer.
+          (when (not (equal (mark) (point)))
+            (setq deactivate-mark nil)
+            (activate-mark))
+
+          ;; * SOURCE BUFFER::
+          ;; Set back the original text as region or delete the original
+          ;; text, on source buffer.
+          (if wanna-paste-to-same-buffer
+              ;; When source buffer and destination buffer are the same,
+              ;; remove the original text.
+              (when no-modifier-on-drop
+                (let (deactivate-mark)
+                  (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                 (overlay-end mouse-drag-and-drop-overlay))))
+            ;; When source buffer and destination buffer are different,
+            ;; keep (set back the original text as region) or remove the
+            ;; original text.
+            (select-window window) ; Select window with source buffer.
+            (goto-char point) ; Move point to the original text on source buffer.
+
+            (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                ;; Remove the dragged text from source buffer like
+                ;; operation `cut'.
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))
+              ;; Set back the dragged text as region on source buffer
+              ;; like operation `copy'.
+              (activate-mark))
+            (select-window window-to-paste))))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-exempt
+                   (not (eq window window-exempt)))
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.


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

* Re: mouse-drag-and-drop-region
  2017-12-15  8:50                                         ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-15 13:25                                           ` martin rudalics
  2017-12-16  2:07                                             ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-15 13:25 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: Eli Zaretskii, rswgnu, Alex, emacs-devel

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

 > Thanks.  I resend you yet another revised version which mostly fixes the
 > doc-strings of these options and replaces the option
 > `mouse-drag-and-drop-region-face' with a face
 > `mouse-drag-and-drop-region' inheriting from the region face.  Please
 > have a look.  Unless you or someone else sees problems, I will install
 > it.

The version I attached had a silly bug.  Please use the one I attach
now.

martin

[-- Attachment #2: mouse.el.diff --]
[-- Type: text/plain, Size: 17245 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..ea8cf78 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2345,10 +2345,10 @@ mouse-appearance-menu
 \f
 ;; Drag and drop support.
 (defcustom mouse-drag-and-drop-region nil
-  "If non-nil, dragging the mouse drags the region, if that exists.
-If the value is a modifier, such as `control' or `shift' or `meta',
-then if that modifier key is pressed when dropping the region, region
-text is copied instead of being cut."
+  "If non-nil, dragging the mouse drags the region, if it exists.
+If the value is a modifier, such as `control' or `shift' or
+`meta', then if that modifier key is pressed when dropping the
+region, text is copied instead of being cut."
   :type `(choice
           (const :tag "Disable dragging the region" nil)
           ,@(mapcar
@@ -2361,6 +2361,45 @@ mouse-drag-and-drop-region
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is nil, `mouse-drag-and-drop-region' does not show
+tooltips.  If this is t, it shows the entire text dragged in a
+tooltip.  If this is an integer (as with the default value of
+256), it will show that many characters of the dragged text in
+a tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+If this is nil, `mouse-drag-and-drop-region' leaves point alone.
+Otherwise, it will move point together with the mouse cursor and,
+in addition, temporarily highlight the original region with the
+`mouse-drag-and-drop-region' face."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defface mouse-drag-and-drop-region '((t :inherit region))
+  "Face to highlight original text during dragging.
+This face is used by `mouse-drag-and-drop-region' to temporarily
+highlight the original region when
+`mouse-drag-and-drop-region-show-cursor' is non-nil."
+  :version "26.1"
+  :group 'mouse)
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2408,248 @@ mouse-drag-and-drop-region
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-exempt)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (ignore-errors
+      (track-mouse
+        ;; When event was "click" instead of "drag", skip loop.
+        (while (progn
+                 ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                 (setq event (read-key))      ; read-event or read-key
+                 (or (mouse-movement-p event)
+                     ;; Handle `mouse-autoselect-window'.
+                     (eq (car-safe event) 'select-window)))
+          ;; Obtain the dragged text in region.  When the loop was
+          ;; skipped, value-selection remains nil.
+          (unless value-selection
+            (setq value-selection (buffer-substring start end))
+            (when mouse-drag-and-drop-region-show-tooltip
+              (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                (setq text-tooltip (if (and (integerp text-size)
+                                            (> (length value-selection) text-size))
+                                       (concat
+                                        (substring value-selection 0 (/ text-size 2))
+                                        "\n...\n"
+                                        (substring value-selection (- (/ text-size 2)) -1))
+                                     value-selection))))
+
+            ;; Check if selected text is read-only.
+            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+            ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+            (setq text-from-read-only (or text-from-read-only
+                                          (get-text-property start 'read-only)
+                                          (not (equal
+                                                (next-single-char-property-change start 'read-only nil end)
+                                                end)))))
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+          (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                  (when (windowp window-to-paste)
+                                    (setq buf (window-buffer window-to-paste))
+                                    (when (not (minibufferp buf))
+                                      buf))))
+          (setq cursor-in-text-area (and window-to-paste
+                                         point-to-paste
+                                         buffer-to-paste))
+
+          (when cursor-in-text-area
+            ;; Check if point under mouse is read-only.
+            (save-window-excursion
+              (select-window window-to-paste)
+              ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+              (setq point-to-paste-read-only
+                    (or buffer-read-only
+                        (get-text-property point-to-paste 'read-only))))
+
+            ;; Check if "drag but negligible".  Operation "drag but
+            ;; negligible" is defined as drag-and-drop the text to
+            ;; the original region.  When modifier is pressed, the
+            ;; text will be inserted to inside of the original
+            ;; region.
+            (setq drag-but-negligible
+                  (member mouse-drag-and-drop-region
+                          (mapcar (lambda (xxx) (overlay-get xxx 'face))
+                                  (overlays-at point-to-paste)))))
+
+          ;; Show a tooltip.
+          (if mouse-drag-and-drop-region-show-tooltip
+              ;; (and mouse-drag-and-drop-region-show-tooltip
+              ;;      (not drag-but-negligible)
+              ;;      (not point-to-paste-read-only)
+              ;;      cursor-in-text-area)
+              (tooltip-show text-tooltip)
+            (tooltip-hide))
+
+          ;; Show cursor and highlight the original region.
+          (when mouse-drag-and-drop-region-show-cursor
+            ;; Modify cursor even when point is out of frame.
+            (setq cursor-type (cond
+                               ((not cursor-in-text-area)
+                                nil)
+                               ((or point-to-paste-read-only
+                                    drag-but-negligible)
+                                'hollow)
+                               (t
+                                'bar)))
+            (when cursor-in-text-area
+              (overlay-put mouse-drag-and-drop-overlay
+                           'face 'mouse-drag-and-drop-region)
+              (deactivate-mark)     ; Maintain region in other window.
+              (mouse-set-point event)))))
+
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+      ;; Check if modifier was pressed on drop.
+      (setq no-modifier-on-drop
+            (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+      ;; Check if event was "click".
+      (setq clicked (not value-selection))
+
+      ;; Restore status on drag to outside of text-area or non-mouse input.
+      ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+      (when (or (not cursor-in-text-area)
+                (not (equal (event-basic-type event) mouse-button)))
+        (setq drag-but-negligible t
+              no-modifier-on-drop t))
+
+      ;; Do not modify any buffers when event is "click",
+      ;; "drag but negligible", or "drag to read-only".
+      (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+              (if no-modifier-on-drop
+                  mouse-drag-and-drop-region-cut-when-buffers-differ
+                (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+             (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+             (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                            no-modifier-on-drop))
+             (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                             mouse-drag-and-drop-region-cut-when-buffers-differ))
+             (cannot-paste (or point-to-paste-read-only
+                               (when (or wanna-cut-on-same-buffer
+                                         wanna-cut-on-other-buffer)
+                                 text-from-read-only))))
+
         (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
+         ;; Move point within region.
+         (clicked
+          (deactivate-mark)
+          (mouse-set-point event))
+         ;; Undo operation. Set back the original text as region.
+         ((or (and drag-but-negligible
+                   no-modifier-on-drop)
+              cannot-paste)
+          ;; Inform user either source or destination buffer cannot be modified.
+          (when (and (not drag-but-negligible)
+                     cannot-paste)
+            (message "Buffer is read-only"))
+
+          ;; Select source window back and restore region.
+          ;; (set-window-point window point)
+          (select-window window)
           (goto-char point)
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
+         ;; Modify buffers.
          (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+          ;; * DESTINATION BUFFER::
+          ;; Insert the text to destination buffer under mouse.
+          (select-window window-to-paste)
+          (setq window-exempt window-to-paste)
+          (goto-char point-to-paste)
+          (push-mark)
+          (insert value-selection)
+          ;; On success, set the text as region on destination buffer.
+          (when (not (equal (mark) (point)))
+            (setq deactivate-mark nil)
+            (activate-mark))
+
+          ;; * SOURCE BUFFER::
+          ;; Set back the original text as region or delete the original
+          ;; text, on source buffer.
+          (if wanna-paste-to-same-buffer
+              ;; When source buffer and destination buffer are the same,
+              ;; remove the original text.
+              (when no-modifier-on-drop
+                (let (deactivate-mark)
+                  (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                 (overlay-end mouse-drag-and-drop-overlay))))
+            ;; When source buffer and destination buffer are different,
+            ;; keep (set back the original text as region) or remove the
+            ;; original text.
+            (select-window window) ; Select window with source buffer.
+            (goto-char point) ; Move point to the original text on source buffer.
+
+            (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                ;; Remove the dragged text from source buffer like
+                ;; operation `cut'.
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))
+              ;; Set back the dragged text as region on source buffer
+              ;; like operation `copy'.
+              (activate-mark))
+            (select-window window-to-paste))))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-exempt
+                   (not (eq window window-exempt)))
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.


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

* Re: mouse-drag-and-drop-region
  2017-12-15 13:25                                           ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-16  2:07                                             ` Tak Kunihiro
  2017-12-16  9:42                                               ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-16  2:07 UTC (permalink / raw)
  To: rudalics; +Cc: tkk, eliz, rswgnu, agrambot, emacs-devel

>> option `mouse-drag-and-drop-region-face' with a face
>> `mouse-drag-and-drop-region' inheriting from the region face.

During the drag, when mouse point is on the original region, cursor
would be set to hollow.  With this revision, I see that the cursor is
not set.

To do it, drag-but-negligible should be set to t.  The
drag-but-negligible is set by following expressions.

2507        ;; Check if "drag but negligible".  Operation "drag but
2508        ;; negligible" is defined as drag-and-drop the text to
2509        ;; the original region.  When modifier is pressed, the
2510        ;; text will be inserted to inside of the original
2511        ;; region.
2512        (setq drag-but-negligible
2513              (member mouse-drag-and-drop-region
2514                      (mapcar (lambda (xxx) (overlay-get xxx 'face))
2515                              (overlays-at point-to-paste)))))

On this revision, I wonder if mouse-drag-and-drop-region on line 2513
refers to variable instead of face.  No?



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

* Re: mouse-drag-and-drop-region
  2017-12-16  2:07                                             ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-16  9:42                                               ` martin rudalics
  2017-12-17  4:40                                                 ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-16  9:42 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, rswgnu, agrambot, emacs-devel

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

 > During the drag, when mouse point is on the original region, cursor
 > would be set to hollow.  With this revision, I see that the cursor is
 > not set.

Right.

 > To do it, drag-but-negligible should be set to t.  The
 > drag-but-negligible is set by following expressions.
 >
 > 2507        ;; Check if "drag but negligible".  Operation "drag but
 > 2508        ;; negligible" is defined as drag-and-drop the text to
 > 2509        ;; the original region.  When modifier is pressed, the
 > 2510        ;; text will be inserted to inside of the original
 > 2511        ;; region.
 > 2512        (setq drag-but-negligible
 > 2513              (member mouse-drag-and-drop-region
 > 2514                      (mapcar (lambda (xxx) (overlay-get xxx 'face))
 > 2515                              (overlays-at point-to-paste)))))
 >
 > On this revision, I wonder if mouse-drag-and-drop-region on line 2513
 > refers to variable instead of face.  No?

Right again.  What about directly checking the overlay boundaries
instead as in the attached patch which appears cleaner than to rely on
face properties?  Note that this way a user can also insert the text
immediately before the original region which IIUC is not possible with
the original behavior.

Maybe we should also call the face `mouse-drag-and-drop-highlight' so
that there is less confusion.  OT1H faces should not end with the
postfix "-face" and OTOH the simple variable you used initially had a
user rely on predefined faces only which is an unnecessary restriction.
Some users might dislike `region' and `secondary-selection' here.

And please go over the entire text once again so that lines are no more
longer than 80 characters at most (I already tried that in some cases).

Thanks, martin

[-- Attachment #2: mouse.el.diff --]
[-- Type: text/plain, Size: 17273 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..e90eada 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2345,10 +2345,10 @@ mouse-appearance-menu
 \f
 ;; Drag and drop support.
 (defcustom mouse-drag-and-drop-region nil
-  "If non-nil, dragging the mouse drags the region, if that exists.
-If the value is a modifier, such as `control' or `shift' or `meta',
-then if that modifier key is pressed when dropping the region, region
-text is copied instead of being cut."
+  "If non-nil, dragging the mouse drags the region, if it exists.
+If the value is a modifier, such as `control' or `shift' or
+`meta', then if that modifier key is pressed when dropping the
+region, text is copied instead of being cut."
   :type `(choice
           (const :tag "Disable dragging the region" nil)
           ,@(mapcar
@@ -2361,6 +2361,45 @@ mouse-drag-and-drop-region
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is nil, `mouse-drag-and-drop-region' does not show
+tooltips.  If this is t, it shows the entire text dragged in a
+tooltip.  If this is an integer (as with the default value of
+256), it will show that many characters of the dragged text in
+a tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+If this is nil, `mouse-drag-and-drop-region' leaves point alone.
+Otherwise, it will move point together with the mouse cursor and,
+in addition, temporarily highlight the original region with the
+`mouse-drag-and-drop-region' face."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defface mouse-drag-and-drop-region '((t :inherit region))
+  "Face to highlight original text during dragging.
+This face is used by `mouse-drag-and-drop-region' to temporarily
+highlight the original region when
+`mouse-drag-and-drop-region-show-cursor' is non-nil."
+  :version "26.1"
+  :group 'mouse)
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2408,251 @@ mouse-drag-and-drop-region
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-exempt)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (ignore-errors
+      (track-mouse
+        ;; When event was "click" instead of "drag", skip loop.
+        (while (progn
+                 ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00364.html
+                 (setq event (read-key))      ; read-event or read-key
+                 (or (mouse-movement-p event)
+                     ;; Handle `mouse-autoselect-window'.
+                     (eq (car-safe event) 'select-window)))
+          ;; Obtain the dragged text in region.  When the loop was
+          ;; skipped, value-selection remains nil.
+          (unless value-selection
+            (setq value-selection (buffer-substring start end))
+            (when mouse-drag-and-drop-region-show-tooltip
+              (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                (setq text-tooltip
+                      (if (and (integerp text-size)
+                               (> (length value-selection) text-size))
+                          (concat
+                           (substring value-selection 0 (/ text-size 2))
+                           "\n...\n"
+                           (substring value-selection (- (/ text-size 2)) -1))
+                        value-selection))))
+
+            ;; Check if selected text is read-only.
+            ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00663.html
+            ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+            (setq text-from-read-only (or text-from-read-only
+                                          (get-text-property start 'read-only)
+                                          (not (equal
+                                                (next-single-char-property-change
+                                                 start 'read-only nil end)
+                                                end)))))
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+          (setq buffer-to-paste (let (buf) ; Set nil when target buffer is minibuffer.
+                                  (when (windowp window-to-paste)
+                                    (setq buf (window-buffer window-to-paste))
+                                    (when (not (minibufferp buf))
+                                      buf))))
+          (setq cursor-in-text-area (and window-to-paste
+                                         point-to-paste
+                                         buffer-to-paste))
+
+          (when cursor-in-text-area
+            ;; Check if point under mouse is read-only.
+            (save-window-excursion
+              (select-window window-to-paste)
+              ;; (add-text-properties (region-beginning) (region-end) '(read-only t))
+              (setq point-to-paste-read-only
+                    (or buffer-read-only
+                        (get-text-property point-to-paste 'read-only))))
+
+            ;; Check if "drag but negligible".  Operation "drag but
+            ;; negligible" is defined as drag-and-drop the text to
+            ;; the original region.  When modifier is pressed, the
+            ;; text will be inserted to inside of the original
+            ;; region.
+            (setq drag-but-negligible
+                  (and (< (overlay-start mouse-drag-and-drop-overlay)
+                          point-to-paste)
+                       (< point-to-paste
+                          (overlay-end mouse-drag-and-drop-overlay)))))
+
+          ;; Show a tooltip.
+          (if mouse-drag-and-drop-region-show-tooltip
+              ;; (and mouse-drag-and-drop-region-show-tooltip
+              ;;      (not drag-but-negligible)
+              ;;      (not point-to-paste-read-only)
+              ;;      cursor-in-text-area)
+              (tooltip-show text-tooltip)
+            (tooltip-hide))
+
+          ;; Show cursor and highlight the original region.
+          (when mouse-drag-and-drop-region-show-cursor
+            ;; Modify cursor even when point is out of frame.
+            (setq cursor-type (cond
+                               ((not cursor-in-text-area)
+                                nil)
+                               ((or point-to-paste-read-only
+                                    drag-but-negligible)
+                                'hollow)
+                               (t
+                                'bar)))
+            (when cursor-in-text-area
+              (overlay-put mouse-drag-and-drop-overlay
+                           'face 'mouse-drag-and-drop-region)
+              (deactivate-mark)     ; Maintain region in other window.
+              (mouse-set-point event)))))
+
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+      ;; Check if modifier was pressed on drop.
+      (setq no-modifier-on-drop
+            (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+      ;; Check if event was "click".
+      (setq clicked (not value-selection))
+
+      ;; Restore status on drag to outside of text-area or non-mouse input.
+      ;; https://lists.gnu.org/archive/html/emacs-devel/2017-11/msg00486.html
+      (when (or (not cursor-in-text-area)
+                (not (equal (event-basic-type event) mouse-button)))
+        (setq drag-but-negligible t
+              no-modifier-on-drop t))
+
+      ;; Do not modify any buffers when event is "click",
+      ;; "drag but negligible", or "drag to read-only".
+      (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+              (if no-modifier-on-drop
+                  mouse-drag-and-drop-region-cut-when-buffers-differ
+                (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+             (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+             (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                            no-modifier-on-drop))
+             (wanna-cut-on-other-buffer (and (not wanna-paste-to-same-buffer)
+                                             mouse-drag-and-drop-region-cut-when-buffers-differ))
+             (cannot-paste (or point-to-paste-read-only
+                               (when (or wanna-cut-on-same-buffer
+                                         wanna-cut-on-other-buffer)
+                                 text-from-read-only))))
+
         (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
+         ;; Move point within region.
+         (clicked
+          (deactivate-mark)
+          (mouse-set-point event))
+         ;; Undo operation. Set back the original text as region.
+         ((or (and drag-but-negligible
+                   no-modifier-on-drop)
+              cannot-paste)
+          ;; Inform user either source or destination buffer cannot be modified.
+          (when (and (not drag-but-negligible)
+                     cannot-paste)
+            (message "Buffer is read-only"))
+
+          ;; Select source window back and restore region.
+          ;; (set-window-point window point)
+          (select-window window)
           (goto-char point)
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
+         ;; Modify buffers.
          (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+          ;; * DESTINATION BUFFER::
+          ;; Insert the text to destination buffer under mouse.
+          (select-window window-to-paste)
+          (setq window-exempt window-to-paste)
+          (goto-char point-to-paste)
+          (push-mark)
+          (insert value-selection)
+          ;; On success, set the text as region on destination buffer.
+          (when (not (equal (mark) (point)))
+            (setq deactivate-mark nil)
+            (activate-mark))
+
+          ;; * SOURCE BUFFER::
+          ;; Set back the original text as region or delete the original
+          ;; text, on source buffer.
+          (if wanna-paste-to-same-buffer
+              ;; When source buffer and destination buffer are the same,
+              ;; remove the original text.
+              (when no-modifier-on-drop
+                (let (deactivate-mark)
+                  (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                 (overlay-end mouse-drag-and-drop-overlay))))
+            ;; When source buffer and destination buffer are different,
+            ;; keep (set back the original text as region) or remove the
+            ;; original text.
+            (select-window window) ; Select window with source buffer.
+            (goto-char point) ; Move point to the original text on source buffer.
+
+            (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                ;; Remove the dragged text from source buffer like
+                ;; operation `cut'.
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))
+              ;; Set back the dragged text as region on source buffer
+              ;; like operation `copy'.
+              (activate-mark))
+            (select-window window-to-paste))))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-exempt
+                   (not (eq window window-exempt)))
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.


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

* Re: mouse-drag-and-drop-region
  2017-12-16  9:42                                               ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-17  4:40                                                 ` Tak Kunihiro
  2017-12-17 10:44                                                   ` mouse-drag-and-drop-region martin rudalics
  0 siblings, 1 reply; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-17  4:40 UTC (permalink / raw)
  To: rudalics; +Cc: tkk, eliz, rswgnu, agrambot, emacs-devel

[-- Attachment #1: Type: Text/Plain, Size: 1624 bytes --]

Thank you for the response.

> What about directly checking the overlay boundaries instead as in
> the attached patch which appears cleaner than to rely on face
> properties?

I think that is good.

> Maybe we should also call the face `mouse-drag-and-drop-highlight'
> so that there is less confusion.  OT1H faces should not end with the
> postfix "-face" and OTOH the simple variable you used initially had
> a user rely on predefined faces only which is an unnecessary
> restriction.  Some users might dislike `region' and
> `secondary-selection' here.

There already are function `mouse-drag-and-drop' and variable
`mouse-drag-and-drop'.  Thus I think there is no problem to have face
`mouse-drag-and-drop'.

> And please go over the entire text once again so that lines are no
> more longer than 80 characters at most.

I take out several comments to make lines no more longer than 80
characters.

I'm sending ChangeLog, and patch.


* ChangeLog

2017-12-17 Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>

Improve comments and have new options

* lisp/mouse.el (mouse-drag-and-drop-region): Have options to make dragging cut among buffers. Make usage of tooltip option.
(mouse-drag-and-drop-region-cut-when-buffers-differ): New variable. If non-nil, cut text also when source and destination buffers differ.
(mouse-drag-and-drop-region-show-tooltip): New variable. If non-nil, text is shown by a tooltip in a graphic display.
(mouse-drag-and-drop-region-show-cursor): New variable. If non-nil, move point with mouse cursor during dragging.
(mouse-drag-and-drop-region): New face to highlight original text during dragging.


[-- Attachment #2: mouse.el.diff --]
[-- Type: Text/X-Patch, Size: 16669 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index 17d1732..d326202
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -2345,10 +2345,10 @@ choose a font."
 \f
 ;; Drag and drop support.
 (defcustom mouse-drag-and-drop-region nil
-  "If non-nil, dragging the mouse drags the region, if that exists.
-If the value is a modifier, such as `control' or `shift' or `meta',
-then if that modifier key is pressed when dropping the region, region
-text is copied instead of being cut."
+  "If non-nil, dragging the mouse drags the region, if it exists.
+If the value is a modifier, such as `control' or `shift' or
+`meta', then if that modifier key is pressed when dropping the
+region, text is copied instead of being cut."
   :type `(choice
           (const :tag "Disable dragging the region" nil)
           ,@(mapcar
@@ -2361,6 +2361,45 @@ text is copied instead of being cut."
   :version "26.1"
   :group 'mouse)
 
+(defcustom mouse-drag-and-drop-region-cut-when-buffers-differ nil
+  "If non-nil, cut text also when source and destination buffers differ.
+If this option is nil, `mouse-drag-and-drop-region' will leave
+the text in the source buffer alone when dropping it in a
+different buffer.  If this is non-nil, it will cut the text just
+as it does when dropping text in the source buffer."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-tooltip 256
+  "If non-nil, text is shown by a tooltip in a graphic display.
+If this option is nil, `mouse-drag-and-drop-region' does not show
+tooltips.  If this is t, it shows the entire text dragged in a
+tooltip.  If this is an integer (as with the default value of
+256), it will show that many characters of the dragged text in
+a tooltip."
+  :type 'integer
+  :version "26.1"
+  :group 'mouse)
+
+(defcustom mouse-drag-and-drop-region-show-cursor t
+  "If non-nil, move point with mouse cursor during dragging.
+If this is nil, `mouse-drag-and-drop-region' leaves point alone.
+Otherwise, it will move point together with the mouse cursor and,
+in addition, temporarily highlight the original region with the
+`mouse-drag-and-drop-region' face."
+  :type 'boolean
+  :version "26.1"
+  :group 'mouse)
+
+(defface mouse-drag-and-drop-region '((t :inherit region))
+  "Face to highlight original text during dragging.
+This face is used by `mouse-drag-and-drop-region' to temporarily
+highlight the original region when
+`mouse-drag-and-drop-region-show-cursor' is non-nil."
+  :version "26.1"
+  :group 'mouse)
+
 (defun mouse-drag-and-drop-region (event)
   "Move text in the region to point where mouse is dragged to.
 The transportation of text is also referred as `drag and drop'.
@@ -2369,66 +2408,244 @@ modifier key was pressed when dropping, and the value of the
 variable `mouse-drag-and-drop-region' is that modifier, the text
 is copied instead of being cut."
   (interactive "e")
-  (require 'tooltip)
-  (let ((start (region-beginning))
-        (end (region-end))
-        (point (point))
-        (buffer (current-buffer))
-        (window (selected-window))
-        value-selection)
-    (track-mouse
-      ;; When event was click instead of drag, skip loop
-      (while (progn
-               (setq event (read-event))
-               (or (mouse-movement-p event)
-                   ;; Handle `mouse-autoselect-window'.
-                   (eq (car-safe event) 'select-window)))
-        (unless value-selection ; initialization
-          (delete-overlay mouse-secondary-overlay)
-          (setq value-selection (buffer-substring start end))
-          (move-overlay mouse-secondary-overlay start end)) ; (deactivate-mark)
-        (ignore-errors (deactivate-mark) ; care existing region in other window
-                       (mouse-set-point event)
-                       (tooltip-show value-selection)))
-      (tooltip-hide))
-    ;; Do not modify buffer under mouse when "event was click",
-    ;;                                       "drag negligible", or
-    ;;                                       "drag to read-only".
-    (if (or (equal (mouse-posn-property (event-end event) 'face) 'region) ; "event was click"
-            (member 'secondary-selection ; "drag negligible"
-                    (mapcar (lambda (xxx) (overlay-get xxx 'face))
-                            (overlays-at (posn-point (event-end event)))))
-            buffer-read-only)
-        ;; Do not modify buffer under mouse.
+  (let* ((mouse-button (event-basic-type last-input-event))
+         (mouse-drag-and-drop-region-show-tooltip
+          (when (and mouse-drag-and-drop-region-show-tooltip
+                     (display-multi-frame-p)
+                     (require 'tooltip))
+            mouse-drag-and-drop-region-show-tooltip))
+         (start (region-beginning))
+         (end (region-end))
+         (point (point))
+         (buffer (current-buffer))
+         (window (selected-window))
+         (text-from-read-only buffer-read-only)
+         (mouse-drag-and-drop-overlay (make-overlay start end))
+         point-to-paste
+         point-to-paste-read-only
+         window-to-paste
+         buffer-to-paste
+         cursor-in-text-area
+         no-modifier-on-drop
+         drag-but-negligible
+         clicked
+         value-selection    ; This remains nil when event was "click".
+         text-tooltip
+         states
+         window-exempt)
+
+    ;; STATES stores for each window on this frame its start and point
+    ;; positions so we can restore them on all windows but for the one
+    ;; where the drop occurs.  For inter-frame drags we'll have to do
+    ;; this for all windows on all visible frames.  In addition we save
+    ;; also the cursor type for the window's buffer so we can restore it
+    ;; in case we modified it.
+    ;; https://lists.gnu.org/archive/html/emacs-devel/2017-12/msg00090.html
+    (walk-window-tree
+     (lambda (window)
+       (setq states
+             (cons
+              (list
+               window
+               (copy-marker (window-start window))
+               (copy-marker (window-point window))
+               (with-current-buffer (window-buffer window)
+                 cursor-type))
+              states))))
+
+    (ignore-errors
+      (track-mouse
+        ;; When event was "click" instead of "drag", skip loop.
+        (while (progn
+                 (setq event (read-key))      ; read-event or read-key
+                 (or (mouse-movement-p event)
+                     ;; Handle `mouse-autoselect-window'.
+                     (eq (car-safe event) 'select-window)))
+          ;; Obtain the dragged text in region.  When the loop was
+          ;; skipped, value-selection remains nil.
+          (unless value-selection
+            (setq value-selection (buffer-substring start end))
+            (when mouse-drag-and-drop-region-show-tooltip
+              (let ((text-size mouse-drag-and-drop-region-show-tooltip))
+                (setq text-tooltip
+                      (if (and (integerp text-size)
+                               (> (length value-selection) text-size))
+                          (concat
+                           (substring value-selection 0 (/ text-size 2))
+                           "\n...\n"
+                           (substring value-selection (- (/ text-size 2)) -1))
+                        value-selection))))
+
+            ;; Check if selected text is read-only.
+            (setq text-from-read-only (or text-from-read-only
+                                          (get-text-property start 'read-only)
+                                          (not (equal
+                                                (next-single-char-property-change
+                                                 start 'read-only nil end)
+                                                end)))))
+          (setq window-to-paste (posn-window (event-end event)))
+          (setq point-to-paste (posn-point (event-end event)))
+          ;; Set nil when target buffer is minibuffer.
+          (setq buffer-to-paste (let (buf)
+                                  (when (windowp window-to-paste)
+                                    (setq buf (window-buffer window-to-paste))
+                                    (when (not (minibufferp buf))
+                                      buf))))
+          (setq cursor-in-text-area (and window-to-paste
+                                         point-to-paste
+                                         buffer-to-paste))
+
+          (when cursor-in-text-area
+            ;; Check if point under mouse is read-only.
+            (save-window-excursion
+              (select-window window-to-paste)
+              (setq point-to-paste-read-only
+                    (or buffer-read-only
+                        (get-text-property point-to-paste 'read-only))))
+
+            ;; Check if "drag but negligible".  Operation "drag but
+            ;; negligible" is defined as drag-and-drop the text to
+            ;; the original region.  When modifier is pressed, the
+            ;; text will be inserted to inside of the original
+            ;; region.
+            (setq drag-but-negligible
+                  (and (< (overlay-start mouse-drag-and-drop-overlay)
+                          point-to-paste)
+                       (< point-to-paste
+                          (overlay-end mouse-drag-and-drop-overlay)))))
+
+          ;; Show a tooltip.
+          (if mouse-drag-and-drop-region-show-tooltip
+              (tooltip-show text-tooltip)
+            (tooltip-hide))
+
+          ;; Show cursor and highlight the original region.
+          (when mouse-drag-and-drop-region-show-cursor
+            ;; Modify cursor even when point is out of frame.
+            (setq cursor-type (cond
+                               ((not cursor-in-text-area)
+                                nil)
+                               ((or point-to-paste-read-only
+                                    drag-but-negligible)
+                                'hollow)
+                               (t
+                                'bar)))
+            (when cursor-in-text-area
+              (overlay-put mouse-drag-and-drop-overlay
+                           'face 'mouse-drag-and-drop-region)
+              (deactivate-mark)     ; Maintain region in other window.
+              (mouse-set-point event)))))
+
+      ;; Hide a tooltip.
+      (when mouse-drag-and-drop-region-show-tooltip (tooltip-hide))
+
+      ;; Check if modifier was pressed on drop.
+      (setq no-modifier-on-drop
+            (not (member mouse-drag-and-drop-region (event-modifiers event))))
+
+      ;; Check if event was "click".
+      (setq clicked (not value-selection))
+
+      ;; Restore status on drag to outside of text-area or non-mouse input.
+      (when (or (not cursor-in-text-area)
+                (not (equal (event-basic-type event) mouse-button)))
+        (setq drag-but-negligible t
+              no-modifier-on-drop t))
+
+      ;; Do not modify any buffers when event is "click",
+      ;; "drag but negligible", or "drag to read-only".
+      (let* ((mouse-drag-and-drop-region-cut-when-buffers-differ
+              (if no-modifier-on-drop
+                  mouse-drag-and-drop-region-cut-when-buffers-differ
+                (not mouse-drag-and-drop-region-cut-when-buffers-differ)))
+             (wanna-paste-to-same-buffer (equal buffer-to-paste buffer))
+             (wanna-cut-on-same-buffer (and wanna-paste-to-same-buffer
+                                            no-modifier-on-drop))
+             (wanna-cut-on-other-buffer
+              (and (not wanna-paste-to-same-buffer)
+                   mouse-drag-and-drop-region-cut-when-buffers-differ))
+             (cannot-paste (or point-to-paste-read-only
+                               (when (or wanna-cut-on-same-buffer
+                                         wanna-cut-on-other-buffer)
+                                 text-from-read-only))))
+
         (cond
-         ;; "drag negligible" or "drag to read-only", restore region.
-         (value-selection
-          (select-window window) ; In case miss drag to other window
+         ;; Move point within region.
+         (clicked
+          (deactivate-mark)
+          (mouse-set-point event))
+         ;; Undo operation. Set back the original text as region.
+         ((or (and drag-but-negligible
+                   no-modifier-on-drop)
+              cannot-paste)
+          ;; Inform user either source or destination buffer cannot be modified.
+          (when (and (not drag-but-negligible)
+                     cannot-paste)
+            (message "Buffer is read-only"))
+
+          ;; Select source window back and restore region.
+          ;; (set-window-point window point)
+          (select-window window)
           (goto-char point)
           (setq deactivate-mark nil)
           (activate-mark))
-         ;; "event was click"
+         ;; Modify buffers.
          (t
-          (deactivate-mark)
-          (mouse-set-point event)))
-      ;; Modify buffer under mouse by inserting text.
-      (push-mark)
-      (insert value-selection)
-      (when (not (equal (mark) (point))) ; on success insert
-        (setq deactivate-mark nil)
-        (activate-mark)) ; have region on destination
-      ;; Take care of initial region on source.
-      (if (equal (current-buffer) buffer) ; when same buffer
-          (let (deactivate-mark) ; remove text
-            (unless (member mouse-drag-and-drop-region (event-modifiers event))
-              (kill-region (overlay-start mouse-secondary-overlay)
-                           (overlay-end mouse-secondary-overlay))))
-        (let ((window1 (selected-window))) ; when beyond buffer
-          (select-window window)
-          (goto-char point) ; restore point on source window
-          (activate-mark) ; restore region
-          (select-window window1))))
-    (delete-overlay mouse-secondary-overlay)))
+          ;; * DESTINATION BUFFER::
+          ;; Insert the text to destination buffer under mouse.
+          (select-window window-to-paste)
+          (setq window-exempt window-to-paste)
+          (goto-char point-to-paste)
+          (push-mark)
+          (insert value-selection)
+          ;; On success, set the text as region on destination buffer.
+          (when (not (equal (mark) (point)))
+            (setq deactivate-mark nil)
+            (activate-mark))
+
+          ;; * SOURCE BUFFER::
+          ;; Set back the original text as region or delete the original
+          ;; text, on source buffer.
+          (if wanna-paste-to-same-buffer
+              ;; When source buffer and destination buffer are the same,
+              ;; remove the original text.
+              (when no-modifier-on-drop
+                (let (deactivate-mark)
+                  (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                                 (overlay-end mouse-drag-and-drop-overlay))))
+            ;; When source buffer and destination buffer are different,
+            ;; keep (set back the original text as region) or remove the
+            ;; original text.
+            (select-window window) ; Select window with source buffer.
+            (goto-char point) ; Move point to the original text on source buffer.
+
+            (if mouse-drag-and-drop-region-cut-when-buffers-differ
+                ;; Remove the dragged text from source buffer like
+                ;; operation `cut'.
+                (delete-region (overlay-start mouse-drag-and-drop-overlay)
+                               (overlay-end mouse-drag-and-drop-overlay))
+              ;; Set back the dragged text as region on source buffer
+              ;; like operation `copy'.
+              (activate-mark))
+            (select-window window-to-paste))))))
+
+    ;; Clean up.
+    (delete-overlay mouse-drag-and-drop-overlay)
+
+    ;; Restore old states but for the window where the drop
+    ;; occurred. Restore cursor types for all windows.
+    (dolist (state states)
+      (let ((window (car state)))
+        (when (and window-exempt
+                   (not (eq window window-exempt)))
+          (set-window-start window (nth 1 state) 'noforce)
+          (set-marker (nth 1 state) nil)
+          ;; If window is selected, the following automatically sets
+          ;; point for that window's buffer.
+          (set-window-point window (nth 2 state))
+          (set-marker (nth 2 state) nil))
+        (with-current-buffer (window-buffer window)
+          (setq cursor-type (nth 3 state)))))))
 \f
 
 ;;; Bindings for mouse commands.

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

* Re: mouse-drag-and-drop-region
  2017-12-17  4:40                                                 ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-17 10:44                                                   ` martin rudalics
  2017-12-21  1:36                                                     ` mouse-drag-and-drop-region Tak Kunihiro
  0 siblings, 1 reply; 89+ messages in thread
From: martin rudalics @ 2017-12-17 10:44 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, rswgnu, agrambot, emacs-devel

 > I take out several comments to make lines no more longer than 80
 > characters.
 >
 > I'm sending ChangeLog, and patch.

I pushed it now with slight changes in the ChangeLog entry and one
change in my earlier calculation of `drag-but-negligible' to avoid that
a drop is rejected when source and destination buffer differ but the
position in the destination buffer is a position in the original region
of the source buffer.  Please have a look.

I believe the following calculations ...

                       (if (and (integerp text-size)
                                (> (length value-selection) text-size))
                           (concat
                            (substring value-selection 0 (/ text-size 2))
                            "\n...\n"
                            (substring value-selection (- (/ text-size 2)) -1))
                         value-selection))))

... could be improved when the user has chosen a very small value for
'mouse-drag-and-drop-region-show-tooltip' but I have no good idea how to
do that.  Maybe also a value of zero should be handled like nil.  But
there's no great need for doing that.

So let's see if there are any complaints.  And maybe it's time to write
some documentation now ...

Thanks, martin



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

* Re: mouse-drag-and-drop-region
  2017-12-17 10:44                                                   ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-21  1:36                                                     ` Tak Kunihiro
  2017-12-22  8:43                                                       ` mouse-drag-and-drop-region martin rudalics
  2017-12-22  9:25                                                       ` mouse-drag-and-drop-region Eli Zaretskii
  0 siblings, 2 replies; 89+ messages in thread
From: Tak Kunihiro @ 2017-12-21  1:36 UTC (permalink / raw)
  To: rudalics; +Cc: tkk, eliz, rswgnu, agrambot, emacs-devel

[-- Attachment #1: Type: Text/Plain, Size: 116 bytes --]

Thank you for the response.

> it's time to write some documentation now ...

Here I attach draft of documentation.

[-- Attachment #2: frames.texi.diff --]
[-- Type: Text/X-Patch, Size: 938 bytes --]

diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
index c94d690cf7..110199304e 100644
--- a/doc/emacs/frames.texi
+++ b/doc/emacs/frames.texi
@@ -1106,6 +1106,14 @@ then pressing that modifier key when dropping the text will copy it
 instead of cutting it, even if you drop on the same buffer as the one
 from which the text came.
 
+If you want to cut text even when source and destination buffers
+differ, set variable
+@code{mouse-drag-and-drop-region-cut-when-buffers-differ} to non-nil.
+If you do not want to see selected text in a tooltip in a graphic
+display and/or move point together with the mouse cursor during
+dragging, set @code{mouse-drag-and-drop-region-show-tooltip} and/or
+@code{mouse-drag-and-drop-region-show-cursor} to nil.
+
 @vindex dnd-open-file-other-window
   Dropping a file normally visits it in the window you drop it on.  If
 you prefer to visit the file in a new window in such cases, customize

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

* Re: mouse-drag-and-drop-region
  2017-12-21  1:36                                                     ` mouse-drag-and-drop-region Tak Kunihiro
@ 2017-12-22  8:43                                                       ` martin rudalics
  2017-12-22  9:25                                                       ` mouse-drag-and-drop-region Eli Zaretskii
  1 sibling, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-12-22  8:43 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: eliz, rswgnu, agrambot, emacs-devel

 > Here I attach draft of documentation.

Installed with modifications and also updated the NEWS entry.  Please
have a look.

Thanks, martin



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

* Re: mouse-drag-and-drop-region
  2017-12-21  1:36                                                     ` mouse-drag-and-drop-region Tak Kunihiro
  2017-12-22  8:43                                                       ` mouse-drag-and-drop-region martin rudalics
@ 2017-12-22  9:25                                                       ` Eli Zaretskii
  2017-12-22 17:57                                                         ` mouse-drag-and-drop-region martin rudalics
  1 sibling, 1 reply; 89+ messages in thread
From: Eli Zaretskii @ 2017-12-22  9:25 UTC (permalink / raw)
  To: Tak Kunihiro; +Cc: rudalics, rswgnu, agrambot, emacs-devel

> Date: Thu, 21 Dec 2017 10:36:46 +0900 (JST)
> Cc: eliz@gnu.org, rswgnu@gmail.com, agrambot@gmail.com,
>  emacs-devel@gnu.org, tkk@misasa.okayama-u.ac.jp
> From: Tak Kunihiro <tkk@misasa.okayama-u.ac.jp>
> 
> diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi
> index c94d690cf7..110199304e 100644
> --- a/doc/emacs/frames.texi
> +++ b/doc/emacs/frames.texi
> @@ -1106,6 +1106,14 @@ then pressing that modifier key when dropping the text will copy it
>  instead of cutting it, even if you drop on the same buffer as the one
>  from which the text came.
>  
> +If you want to cut text even when source and destination buffers
> +differ, set variable
> +@code{mouse-drag-and-drop-region-cut-when-buffers-differ} to non-nil.
> +If you do not want to see selected text in a tooltip in a graphic
> +display and/or move point together with the mouse cursor during
> +dragging, set @code{mouse-drag-and-drop-region-show-tooltip} and/or
> +@code{mouse-drag-and-drop-region-show-cursor} to nil.
> +
>  @vindex dnd-open-file-other-window
>    Dropping a file normally visits it in the window you drop it on.  If
>  you prefer to visit the file in a new window in such cases, customize

Thanks.

When you describe in the manual functions or variables that were never
described before, please always add index entries for them, using
@findex or @vindex as appropriate.  (I did it this time.)  We want all
the functions/variables mentioned in the manual to be indexed, so that
their description could be easily found by users.  Also, some
documentation-related Emacs features rely on them being indexed, and
will fail if they aren't.



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

* Re: mouse-drag-and-drop-region
  2017-12-22  9:25                                                       ` mouse-drag-and-drop-region Eli Zaretskii
@ 2017-12-22 17:57                                                         ` martin rudalics
  0 siblings, 0 replies; 89+ messages in thread
From: martin rudalics @ 2017-12-22 17:57 UTC (permalink / raw)
  To: Eli Zaretskii, Tak Kunihiro; +Cc: rswgnu, agrambot, emacs-devel

 > When you describe in the manual functions or variables that were never
 > described before, please always add index entries for them, using
 > @findex or @vindex as appropriate.  (I did it this time.)  We want all
 > the functions/variables mentioned in the manual to be indexed, so that
 > their description could be easily found by users.  Also, some
 > documentation-related Emacs features rely on them being indexed, and
 > will fail if they aren't.

Thanks for the reminder.  I tend to forget indexing when editing the
Emacs manual.

martin



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

end of thread, other threads:[~2017-12-22 17:57 UTC | newest]

Thread overview: 89+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-14  9:54 mouse-drag-and-drop-region martin rudalics
2017-11-14 17:01 ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-14 18:29   ` mouse-drag-and-drop-region martin rudalics
2017-11-14 20:17 ` mouse-drag-and-drop-region Alex
2017-11-15  9:22   ` mouse-drag-and-drop-region martin rudalics
2017-11-15 18:22     ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-15 18:50       ` mouse-drag-and-drop-region martin rudalics
2017-11-15 20:01         ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-16  9:04           ` mouse-drag-and-drop-region martin rudalics
2017-11-15 19:46     ` mouse-drag-and-drop-region Alex
2017-11-15 20:15       ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-15 22:03         ` mouse-drag-and-drop-region Alex
2017-11-16 15:54           ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-17  6:33             ` mouse-drag-and-drop-region Alex
2017-11-17  7:33               ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-17 15:58                 ` mouse-drag-and-drop-region Stefan Monnier
2017-11-17 16:39                   ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-17 22:44                     ` mouse-drag-and-drop-region Stefan Monnier
2017-11-18  7:54                       ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-18 14:36                         ` mouse-drag-and-drop-region Stefan Monnier
2017-11-18 15:04                           ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-18 15:49                             ` mouse-drag-and-drop-region Stefan Monnier
2017-11-18  6:48                 ` mouse-drag-and-drop-region Alex
2017-11-18  9:07                   ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-18 21:58                     ` mouse-drag-and-drop-region Alex
2017-11-19 15:27                       ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-17  8:53               ` mouse-drag-and-drop-region martin rudalics
2017-11-18  6:49                 ` mouse-drag-and-drop-region Alex
2017-11-16  9:04       ` mouse-drag-and-drop-region martin rudalics
2017-11-17  6:02         ` mouse-drag-and-drop-region Alex
2017-11-17  8:53           ` mouse-drag-and-drop-region martin rudalics
2017-11-15 20:22   ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-16  0:28 ` mouse-drag-and-drop-region Tak Kunihiro
2017-11-16  9:11   ` mouse-drag-and-drop-region martin rudalics
2017-11-20 13:29     ` mouse-drag-and-drop-region Tak Kunihiro
2017-11-20 16:03       ` mouse-drag-and-drop-region Drew Adams
2017-11-20 16:09         ` mouse-drag-and-drop-region Alan Schmitt
2017-11-20 17:34         ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-20 18:17         ` mouse-drag-and-drop-region Paul Eggert
2017-11-21  9:24       ` mouse-drag-and-drop-region martin rudalics
2017-11-21 13:09         ` mouse-drag-and-drop-region Stefan Monnier
2017-11-21 14:05           ` mouse-drag-and-drop-region martin rudalics
2017-11-21 19:07             ` mouse-drag-and-drop-region Stefan Monnier
2017-11-22  8:26               ` mouse-drag-and-drop-region martin rudalics
2017-11-22 21:20                 ` mouse-drag-and-drop-region Stefan Monnier
2017-11-23  7:46                   ` mouse-drag-and-drop-region martin rudalics
2017-11-23 14:00                     ` mouse-drag-and-drop-region Stefan Monnier
2017-11-23 16:09                     ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-24  9:02                       ` mouse-drag-and-drop-region martin rudalics
2017-11-24  9:19                         ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-24  9:41                           ` mouse-drag-and-drop-region martin rudalics
2017-11-24 13:25                             ` mouse-drag-and-drop-region Stefan Monnier
2017-11-26 10:24                               ` mouse-drag-and-drop-region martin rudalics
2017-11-24 13:45                             ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-26 10:24                               ` mouse-drag-and-drop-region martin rudalics
2017-11-26 15:54                                 ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-27  8:48                                   ` mouse-drag-and-drop-region martin rudalics
2017-11-27 15:59                                     ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-21 15:45         ` mouse-drag-and-drop-region Eli Zaretskii
2017-11-22  8:22           ` mouse-drag-and-drop-region martin rudalics
2017-11-21 18:52         ` mouse-drag-and-drop-region Robert Weiner
2017-11-22  8:22           ` mouse-drag-and-drop-region martin rudalics
2017-11-23 23:28         ` mouse-drag-and-drop-region Tak Kunihiro
2017-11-24  9:02           ` mouse-drag-and-drop-region martin rudalics
2017-11-27 13:11             ` mouse-drag-and-drop-region Tak Kunihiro
2017-11-28  8:50               ` mouse-drag-and-drop-region martin rudalics
2017-12-01 14:16                 ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-02 10:16                   ` mouse-drag-and-drop-region martin rudalics
2017-12-03 10:06                     ` mouse-drag-and-drop-region martin rudalics
2017-12-03 13:36                       ` mouse-drag-and-drop-region martin rudalics
2017-12-05  4:57                       ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-05  8:53                         ` mouse-drag-and-drop-region martin rudalics
2017-12-06  9:29                           ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-07  9:26                             ` mouse-drag-and-drop-region martin rudalics
2017-12-07 21:45                               ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-08 10:12                                 ` mouse-drag-and-drop-region martin rudalics
2017-12-08 16:14                                   ` mouse-drag-and-drop-region Robert Weiner
2017-12-09 10:35                                     ` mouse-drag-and-drop-region martin rudalics
2017-12-14 23:14                                       ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-15  8:50                                         ` mouse-drag-and-drop-region martin rudalics
2017-12-15 13:25                                           ` mouse-drag-and-drop-region martin rudalics
2017-12-16  2:07                                             ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-16  9:42                                               ` mouse-drag-and-drop-region martin rudalics
2017-12-17  4:40                                                 ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-17 10:44                                                   ` mouse-drag-and-drop-region martin rudalics
2017-12-21  1:36                                                     ` mouse-drag-and-drop-region Tak Kunihiro
2017-12-22  8:43                                                       ` mouse-drag-and-drop-region martin rudalics
2017-12-22  9:25                                                       ` mouse-drag-and-drop-region Eli Zaretskii
2017-12-22 17:57                                                         ` mouse-drag-and-drop-region martin rudalics

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