unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#28620: Mouse drag event records wrong window for release when crossing frames
@ 2017-09-27 15:44 Robert Weiner
  2017-10-03 20:54 ` bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window) Robert Weiner
                   ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-27 15:44 UTC (permalink / raw)
  To: 28620

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

With Emacs 25.3 under MacOS 10.12, a drag with mouse-1 depressed from
the text area of frame F1 to the text area of frame F2 improperly
generates a drag event whose (posn-window (event-end <event>)) shows
F1 rather than F2.

Note that for a drag between frames, posn-window should return a frame
(according to the Elisp manual but not its own doc string).  The bug is
that the event itself records the wrong frame (the depress frame rather
than the release frame).

I have confirmed this with Emacs 25.2 under Windows 7 as well.

Bob


In GNU Emacs 25.3.1 (x86_64-apple-darwin13.4.0, NS appkit-1265.21 Version
10.9.5 (Build 13F1911))
 of 2017-09-12 built on builder10-9.local
Windowing system distributor 'Apple', version 10.3.1504
Configured using:
 'configure --with-ns '--enable-locallisppath=/Library/Application
 Support/Emacs/${version}/site-lisp:/Library/Application
 Support/Emacs/site-lisp' --with-modules'

Configured features:
NOTIFY ACL GNUTLS LIBXML2 ZLIB TOOLKIT_SCROLL_BARS NS MODULES

Important settings:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Emacs-Lisp

Minor modes in effect:
  recentf-mode: t
  shell-dirtrack-mode: t
  diff-auto-refine-mode: t
  desktop-save-mode: t
  winner-mode: t
  which-key-mode: t
  show-paren-mode: t
  which-function-mode: t
  persistent-scratch-autosave-mode: t
  paredit-everywhere-mode: t
  dynamic-completion-mode: t
  global-edit-server-edit-mode: t
  delete-selection-mode: t
  auto-compile-on-load-mode: t
  auto-compile-on-save-mode: t
  auto-compile-mode: t
  outline-minor-mode: t
  minibuffer-depth-indicate-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  column-number-mode: t
  line-number-mode: t
  auto-fill-function: do-auto-fill
  transient-mark-mode: t

Features:
(shadow mail-extr emacsbug tabify man magit-utils crm pulse glasses
cus-start cus-load mule-diag ispell filecache two-column iso-transl
debug recentf tree-widget helm-x-files helm-for-files helm-bookmark
helm-adaptive helm-info bookmark helm-external helm-net helm-files
image-dired ffap helm-tags helm-locate tramp tramp-compat tramp-loaddefs
trampver eieio-opt speedbar sb-image ezimage dframe helm-buffers
helm-grep helm-regexp helm-utils helm-help helm-types thai-util
thai-word misearch multi-isearch pcmpl-unix pcmpl-gnu shell dired-aux
grep hywconfig network-stream nsm starttls web-beautify org-element
org-rmail org-mhe org-irc org-info org-gnus org-docview org-bibtex
bibtex org-bbdb org-w3m doc-view arc-mode archive-mode eww mm-url gnus
gnus-ems nnheader wid-edit url-queue shr dom texinfo make-mode
skewer-html markdown-mode color sh-script smie executable rst conf-mode
tern-auto-complete tern jsdock helm-dash cursor-sensor image-mode
flycheck rx flymake jedi auto-complete popup jedi-core
python-environment epc ctable concurrent deferred pydock pydoc goto-addr
autorevert filenotify vc-git diff-mode .emacs desktop frameset
window-jump winner which-key supercite regi sort skewer-setup
skewer-mode cache-table js2-mode js cc-mode cc-fonts cc-guess cc-menus
cc-cmds cc-styles cc-align cc-engine cc-vars cc-defs simple-httpd pp
json map python-mode compile thingatpt aggressive-indent paren
which-func imenu persistent-scratch js-lookup paredit-everywhere
paredit-menu paredit par-align rep-region id-edit wrect rect id-linecol
bw-tags apropos file-hdr lib site-key site-func id-keys id-vers
chrome-macos emmet-mode dired-x completion ido server edit-server delsel
jka-compr auto-compile packed dash hmouse-tag etags xref project
rsw-helm helm-easymenu helm edmacro kmacro helm-source eieio-compat
helm-multi-match helm-lib wdired async hyperbole hinit hibtypes
hib-doc-id hsys-www klink subr-x hib-kbd hib-social hib-debbugs
debbugs-gnu debbugs soap-client url-http tls gnutls url-auth url-gw
warnings rng-xsd rng-dt rng-util xsd-regexp hsys-org org org-macro
org-footnote org-pcomplete pcomplete org-list org-faces org-entities
org-version ob-emacs-lisp ob ob-tangle ob-ref ob-lob ob-table ob-exp
org-src ob-keys ob-comint ob-core ob-eval org-compat org-macs
org-loaddefs find-func hactypes comint ansi-color hui-mini hui hui-mouse
hui-window hargs hui-menu hyrolo-menu hyrolo google-contacts xml
url-cache url url-proxy url-privacy url-expand url-methods url-history
url-cookie url-domsuf mailcap url-util url-parse auth-source cl-seq
eieio url-vars google-oauth hmail hui-jmenu noutline outline easy-mmode
hmouse-key hmouse-sh hmouse-drv hypb locate hsettings hui-em-but hbut
hact hpath hhist hbdata htz cal-julian cal-menu calendar cal-loaddefs
hbmap hmoccur derived browse-url hui-select web-mode disp-table
sgml-mode hvar set hversion hload-path package-x mail-hist sendmail ring
message dired format-spec rfc822 mml mml-sec password-cache epg
gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047
rfc2045 ietf-drums mm-util help-fns mail-prsvr mailabbrev mail-utils
gmm-utils mailheader rsw-evernote epic htmlize cl add-log
exec-path-from-shell finder-inf eieio-core cl-macs kotl-loaddefs
pydoc-info advice info-look info package epg-config seq byte-opt gv
bytecomp byte-compile cl-extra help-mode cconv mb-depth edebug easymenu
cl-loaddefs pcase cl-lib time-date mule-util tooltip eldoc electric
uniquify ediff-hook vc-hooks lisp-float-type mwheel ns-win ucs-normalize
term/common-win tool-bar dnd fontset image regexp-opt fringe
tabulated-list newcomment elisp-mode lisp-mode prog-mode register page
menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core frame cl-generic cham georgian utf-8-lang
misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms
cp51932 hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese charscript case-table epa-hook jka-cmpr-hook help
simple abbrev minibuffer cl-preloaded nadvice loaddefs button faces
cus-face macroexp files text-properties overlay sha1 md5 base64 format
env code-pages mule custom widget hashtable-print-readable backquote
kqueue cocoa ns multi-tty make-network-process emacs)

Memory information:
((conses 16 1208296 206512)
 (symbols 48 87755 1)
 (miscs 40 9963 6750)
 (strings 32 234897 19520)
 (string-bytes 1 7230712)
 (vectors 16 99432)
 (vector-slots 8 2323157 242912)
 (floats 8 1648 1850)
 (intervals 56 53652 6347)
 (buffers 976 433))

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
@ 2017-09-27 16:01 Robert Weiner
  2017-09-27 21:34 ` John Wiegley
                   ` (2 more replies)
  0 siblings, 3 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-27 16:01 UTC (permalink / raw)
  To: 28621

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

The doc for posn-window is incomplete.  posn-set-point does not handle drag
events whose end point argument is a frame, rather than a window.
This patch fixes both of these.  Read the code of posn-set-point to ensure
the logic is right in terms of using frame-selected-window.

This diff is against subr.el in Emacs 25.3 but I see none of this has yet
changed in Emacs 26 either, so it is still applicable.

*** subr.el.gz 2017-09-27 11:50:06.000000000 -0400
--- subr-new.el.gz 2017-09-27 11:50:06.000000000 -0400
***************
*** 1090,1096 ****
  The following accessor functions are used to access the elements
  of the position:

! `posn-window': The window the event is in.
  `posn-area': A symbol identifying the area the event occurred in,
  or nil if the event occurred in the text area.
  `posn-point': The buffer position of the event.
--- 1090,1096 ----
  The following accessor functions are used to access the elements
  of the position:

! `posn-window': The window or frame of the event end.
  `posn-area': A symbol identifying the area the event occurred in,
  or nil if the event occurred in the text area.
  `posn-point': The buffer position of the event.
***************
*** 1141,1148 ****

  (defsubst posn-window (position)
    "Return the window in POSITION.
! POSITION should be a list of the form returned by the `event-start'
! and `event-end' functions."
    (nth 0 position))

  (defsubst posn-area (position)
--- 1141,1149 ----

  (defsubst posn-window (position)
    "Return the window in POSITION.
! If POSITION is outside the frame where the event was initiated, return
! that frame instead.  POSITION should be a list of the form returned by
! the `event-start' and `event-end' functions."
    (nth 0 position))

  (defsubst posn-area (position)
***************
*** 1169,1177 ****
  (defun posn-set-point (position)
    "Move point to POSITION.
  Select the corresponding window as well."
!   (if (not (windowp (posn-window position)))
!       (error "Position not in text area of window"))
!   (select-window (posn-window position))
    (if (numberp (posn-point position))
        (goto-char (posn-point position))))

--- 1170,1182 ----
  (defun posn-set-point (position)
    "Move point to POSITION.
  Select the corresponding window as well."
!   (if (framep (posn-window position))
!       (progn (if (not (windowp (frame-selected-window (posn-window
position))))
! (error "Position not in text area of window"))
!      (select-window (frame-selected-window (posn-window position))))
!     (if (not (windowp (posn-window position)))
! (error "Position not in text area of window"))
!     (select-window (posn-window position)))
    (if (numberp (posn-point position))
        (goto-char (posn-point position))))

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-27 16:01 bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Robert Weiner
@ 2017-09-27 21:34 ` John Wiegley
  2017-09-29  8:34 ` martin rudalics
  2017-09-29 19:41 ` Eli Zaretskii
  2 siblings, 0 replies; 33+ messages in thread
From: John Wiegley @ 2017-09-27 21:34 UTC (permalink / raw)
  To: Robert Weiner; +Cc: rswgnu, 28621

>>>>> "RW" == Robert Weiner <rsw@gnu.org> writes:

RW> The doc for posn-window is incomplete. posn-set-point does not handle drag
RW> events whose end point argument is a frame, rather than a window. This
RW> patch fixes both of these. Read the code of posn-set-point to ensure the
RW> logic is right in terms of using frame-selected-window.

I'm happy to see this applied, just want confirmation from someone who
understands this code better that this is the correct clarification...

-- 
John Wiegley                  GPG fingerprint = 4710 CF98 AF9B 327B B80F
http://newartisans.com                          60E1 46C4 BD1A 7AC1 4BA2





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-27 16:01 bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Robert Weiner
  2017-09-27 21:34 ` John Wiegley
@ 2017-09-29  8:34 ` martin rudalics
  2017-09-29 16:48   ` Robert Weiner
  2017-09-29 19:42   ` Eli Zaretskii
  2017-09-29 19:41 ` Eli Zaretskii
  2 siblings, 2 replies; 33+ messages in thread
From: martin rudalics @ 2017-09-29  8:34 UTC (permalink / raw)
  To: rswgnu, 28621

 > ! `posn-window': The window or frame of the event end.

If we start talking about "event ends" here we should export that
concept to the remaining ‘posn-*’ functions as well.

 > ! If POSITION is outside the frame where the event was initiated, return
 > ! that frame instead.  POSITION should be a list of the form returned by

I suppose this is not sufficient: We get a frame also when the mouse is
on its tool or menu bar, some of ist borders ...

But note that I've never been able to understand the purpose of these
‘posn-*’ functions and they usually confuse the hell out of me.  IMHO it
would make much more sense to declare them obsolete and concentrate on
describing event structures better.

martin






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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-29  8:34 ` martin rudalics
@ 2017-09-29 16:48   ` Robert Weiner
  2017-09-29 19:42   ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-29 16:48 UTC (permalink / raw)
  To: martin rudalics; +Cc: 28621

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

On Fri, Sep 29, 2017 at 4:34 AM, martin rudalics <rudalics@gmx.at> wrote:

> > ! `posn-window': The window or frame of the event end.
>
> If we start talking about "event ends" here we should export that
> ​​
> concept to the remaining ‘posn-*’ functions as well.
> ​​
>

​Yes.

> ​​
> ​​
>
> ​​
> > ! If POSITION is outside the frame where the event was initiated, return
> ​​
> > ! that frame instead.  POSITION should be a list of the form returned by
> ​​
>
> ​​
> I suppose this is not sufficient: We get a frame also when the mouse is
> ​​
> on its tool or menu bar, some of ist borders ...
>

​posn-area reports whether the event was in the text area or not.​

​​
>
> ​​
> But note that I've never been able to understand the purpose of these
> ​​
> ‘posn-*’ functions and they usually confuse the hell out of me.  IMHO it
> ​​
> would make much more sense to declare them obsolete and concentrate on
> ​​
> describing event structures better.


​It does seem like some additional work is needed to simplify event
handling and handle a multi-frame world better.

Bob

​​
​​

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-27 16:01 bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Robert Weiner
  2017-09-27 21:34 ` John Wiegley
  2017-09-29  8:34 ` martin rudalics
@ 2017-09-29 19:41 ` Eli Zaretskii
  2017-09-29 20:11   ` Robert Weiner
  2 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2017-09-29 19:41 UTC (permalink / raw)
  To: rswgnu; +Cc: 28621

> From: Robert Weiner <rsw@gnu.org>
> Date: Wed, 27 Sep 2017 12:01:50 -0400
> 
> The doc for posn-window is incomplete.  posn-set-point does not handle drag
> events whose end point argument is a frame, rather than a window.
> This patch fixes both of these.  Read the code of posn-set-point to ensure
> the logic is right in terms of using frame-selected-window.
> 
> This diff is against subr.el in Emacs 25.3 but I see none of this has yet
> changed in Emacs 26 either, so it is still applicable.

Thanks.  Some comments below.

> ! `posn-window': The window the event is in.
>   `posn-area': A symbol identifying the area the event occurred in,
>   or nil if the event occurred in the text area.
>   `posn-point': The buffer position of the event.
> --- 1090,1096 ----
>   The following accessor functions are used to access the elements
>   of the position:
> 
> ! `posn-window': The window or frame of the event end.

I think we should say a bit more about this.  For example:

 `posn-window': The window of the event end, or its frame if event
                end point belongs to no window.

>   (defun posn-set-point (position)
>     "Move point to POSITION.
>   Select the corresponding window as well."
> !   (if (not (windowp (posn-window position)))
> !       (error "Position not in text area of window"))
> !   (select-window (posn-window position))
>     (if (numberp (posn-point position))
>         (goto-char (posn-point position))))
> 
> --- 1170,1182 ----
>   (defun posn-set-point (position)
>     "Move point to POSITION.
>   Select the corresponding window as well."
> !   (if (framep (posn-window position))
> !       (progn (if (not (windowp (frame-selected-window (posn-window
> position))))
> ! (error "Position not in text area of window"))
> !      (select-window (frame-selected-window (posn-window position))))

Why should we select the selected-window on that frame in this case?
Can you describe a use case where this would be a useful behavior?

In any case, the change in posn-set-point's behavior, if we agree on
it, should be described in NEWS.  The changes also lack a log entry.

I'm okay with installing the documentation changes in the release
branch, but the change in posn-set-point should be discussed first, as
I'm not sure we want that.  If we agree on making that change, it
should go to master, I think.





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-29  8:34 ` martin rudalics
  2017-09-29 16:48   ` Robert Weiner
@ 2017-09-29 19:42   ` Eli Zaretskii
  1 sibling, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2017-09-29 19:42 UTC (permalink / raw)
  To: martin rudalics; +Cc: rswgnu, 28621

> Date: Fri, 29 Sep 2017 10:34:44 +0200
> From: martin rudalics <rudalics@gmx.at>
> 
>  > ! `posn-window': The window or frame of the event end.
> 
> If we start talking about "event ends" here we should export that
> concept to the remaining ‘posn-*’ functions as well.

Agreed.

>  > ! If POSITION is outside the frame where the event was initiated, return
>  > ! that frame instead.  POSITION should be a list of the form returned by
> 
> I suppose this is not sufficient: We get a frame also when the mouse is
> on its tool or menu bar, some of ist borders ...

Right.  Btw, the manual has this problem as well.

> But note that I've never been able to understand the purpose of these
> ‘posn-*’ functions and they usually confuse the hell out of me.  IMHO it
> would make much more sense to declare them obsolete and concentrate on
> describing event structures better.

We should do both, IMO.





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-29 19:41 ` Eli Zaretskii
@ 2017-09-29 20:11   ` Robert Weiner
  2017-09-30  8:32     ` martin rudalics
  2019-06-24 16:08     ` bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Lars Ingebrigtsen
  0 siblings, 2 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-29 20:11 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 28621

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

On Fri, Sep 29, 2017 at 3:41 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > From: Robert Weiner <rsw@gnu.org>
> > Date: Wed, 27 Sep 2017 12:01:50 -0400
> >
> > The doc for posn-window is incomplete.  posn-set-point does not handle
> drag
> > events whose end point argument is a frame, rather than a window.
> > This patch fixes both of these.


> > ! `posn-window': The window or frame of the event end.
>
> I think we should say a bit more about this.  For example:
>
>  `posn-window': The window of the event end, or its frame if event
>                 end point belongs to no window.
>

​Fine.
​

>
> >   (defun posn-set-point (position)
> >     "Move point to POSITION.
> >   Select the corresponding window as well."
> > !   (if (not (windowp (posn-window position)))
> > !       (error "Position not in text area of window"))
> > !   (select-window (posn-window position))
> >     (if (numberp (posn-point position))
> >         (goto-char (posn-point position))))
> >
> > --- 1170,1182 ----
> >   (defun posn-set-point (position)
> >     "Move point to POSITION.
> >   Select the corresponding window as well."
> > !   (if (framep (posn-window position))
> > !       (progn (if (not (windowp (frame-selected-window (posn-window
> > position))))
> > ! (error "Position not in text area of window"))
> > !      (select-window (frame-selected-window (posn-window position))))
>
> Why should we select the selected-window on that frame in this case?
>

​Because when position includes a window, the window is selected (the
latter logic in this function).  So if position is in a window in another
frame, shouldn't we select the window there?  We are trying to set point
here
based on a mouse position​, so the user must have moved his focus there.  I
am
looking for input on whether the logic is right.

​​
> Can you
> ​​
> describe a use case where this would be a useful behavior?
> ​​
>
​​
​If you bind commands to both the depress and release events of a mouse
button
and then drag between windows on two separate frames, you'll often want to
do
something in the buffer at the point of the drag release​.  Since drag
events
provide only the release frame and not the release window, unless this
window
is selected, there is no way to know which window to use.  I want to use
this
to display a buffer menu item in a window of my choosing; I have this
working
already for windows within a single frame.

Maybe posn-window should be rewritten such that if the release event
contains
a frame, it actually computes the window of the release event based on the
position
(rather than just returning the frame, as it does now and leading to a
cascade
of potential conditionals).

Presently, mouse-select-window assumes that posn-window always returns a
window,
so it doesn't handle cross-frame drags either.

If we just had a way to get a window from a set of coordinates within a
window,
then I think this would help solve a lot of this (then drag events could
end with
a window rather than a frame) and the caller could determine whether the
depress
and release events are in the same frame or not, as needed.  Does such a
function
exist in Emacs 26?

​​
>
>
> In any case, the change in posn-set-point's behavior, if we agree on
> ​​
> it, should be described in NEWS.  The changes also lack a log entry.
>

​I am not an Emacs committer, mainly due to time.  My hope is that you will
take
the ideas and code and augment them as you know best how to do into
whichever
branches you feel they should go.

​​
>
> ​​
> I'm okay with installing the documentation changes in the release
> ​​
> branch, but the change in posn-set-point should be discussed first, as
> ​​
> I'm not sure we want that.  If we agree on making that change, it
> ​​
> should go to master, I think.
>

​Sure, no problem.  Let's figure out a good solution and work towards that.

Bob
​

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-29 20:11   ` Robert Weiner
@ 2017-09-30  8:32     ` martin rudalics
  2017-09-30 12:45       ` Robert Weiner
  2019-06-24 16:08     ` bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Lars Ingebrigtsen
  1 sibling, 1 reply; 33+ messages in thread
From: martin rudalics @ 2017-09-30  8:32 UTC (permalink / raw)
  To: rswgnu, Eli Zaretskii; +Cc: 28621

 >>> !      (select-window (frame-selected-window (posn-window position))))
 >>
 >> Why should we select the selected-window on that frame in this case?
 >>
 >
 > ​Because when position includes a window, the window is selected (the
 > latter logic in this function).  So if position is in a window in another
 > frame, shouldn't we select the window there?  We are trying to set point
 > here
 > based on a mouse position​, so the user must have moved his focus there.  I
 > am
 > looking for input on whether the logic is right.

(frame-selected-window (posn-window position)) might not be the window
under the mouse cursor.

martin






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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-30  8:32     ` martin rudalics
@ 2017-09-30 12:45       ` Robert Weiner
  2017-09-30 12:52         ` Robert Weiner
  2017-09-30 17:12         ` martin rudalics
  0 siblings, 2 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-30 12:45 UTC (permalink / raw)
  To: martin rudalics; +Cc: 28621

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

On Sat, Sep 30, 2017 at 4:32 AM, martin rudalics <rudalics@gmx.at> wrot

>
> (frame-selected-window (posn-window position)) might not be the window
> under the mouse cursor.


​You are correct.  Though in testing 5 different mouse key bindings it was
correct 4 out of 5 times because the depress part of the cross-frame drag
event selected the window of the depress which is probably more accurate
than existing results.  I agree though that there may be uses of drag
events where one does not want to select the window of the depress.

This speaks to my point in my most recent prior message, "If we just had a
way to get a window from a set of coordinates within a frame, then I think
this would help solve a lot of this."  If the event-end of Emacs mouse drag
events included a window, rather than a frame, when the endpoint of the
drag is at a position unique to a window (considering Z-frame order), I
think that would solve all these issues and simplify parts of the posn code.

Bob

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-30 12:45       ` Robert Weiner
@ 2017-09-30 12:52         ` Robert Weiner
  2017-09-30 17:12         ` martin rudalics
  1 sibling, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-30 12:52 UTC (permalink / raw)
  To: martin rudalics; +Cc: 28621

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

On Sat, Sep 30, 2017 at 8:45 AM, Robert Weiner <rsw@gnu.org> wrote:

> On Sat, Sep 30, 2017 at 4:32 AM, martin rudalics <rudalics@gmx.at> wrot
>
>>
>> (frame-selected-window (posn-window position)) might not be the window
>> under the mouse cursor.
>
>
> ​You are correct.  Though in testing 5 different mouse key bindings it was
> correct 4 out of 5 times because the depress part of the cross-frame drag
> event selected the window of the depress which is probably more accurate
> than existing results.  I agree though that there may be uses of drag
> events where one does not want to select the window of the depress.
>

​Please ignore the above paragraph as I wasn't thinking about the end part
of the drag.
​

>
> This speaks to my point in my most recent prior message, "If we just had
> a way to get a window from a set of coordinates within a frame, then I
> think this would help solve a lot of this."  If the event-end of Emacs
> mouse drag events included a window, rather than a frame, when the endpoint
> of the drag is at a position unique to a window (considering Z-frame
> order), I think that would solve all these issues and simplify parts of the
> posn code.
>

​Just read the above paragragph.

Bob

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

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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-30 12:45       ` Robert Weiner
  2017-09-30 12:52         ` Robert Weiner
@ 2017-09-30 17:12         ` martin rudalics
  2017-09-30 21:56           ` bug#28620: " Robert Weiner
  1 sibling, 1 reply; 33+ messages in thread
From: martin rudalics @ 2017-09-30 17:12 UTC (permalink / raw)
  To: rswgnu; +Cc: 28621

 > This speaks to my point in my most recent prior message, "If we just had a
 > way to get a window from a set of coordinates within a frame, then I think
 > this would help solve a lot of this."  If the event-end of Emacs mouse drag
 > events included a window, rather than a frame, when the endpoint of the
 > drag is at a position unique to a window (considering Z-frame order), I
 > think that would solve all these issues and simplify parts of the posn code.

Take the position of the event-end (if it's a frame) and translate it
into absolute screen coordinates (the Elisp manual should give you
enough clues to do that).  Or, try ‘mouse-absolute-pixel-position’ - it
should give you the screen position of the mouse at that time so you can
ignore the event completely.

Then walk all your windows and compare that position with whatever
‘window-absolute-pixel-edges’ returns for that window.  If you have two
or more positives, run ‘frame-list-z-order’ and compare the result
against those windows' frames.  No hands, IMHO.

martin






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

* bug#28620: bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-30 17:12         ` martin rudalics
@ 2017-09-30 21:56           ` Robert Weiner
  2017-09-30 23:34             ` Robert Weiner
  2017-10-16 15:11             ` bug#28620: Emacs bug#28620: (PARTIAL SOLUTION) mouse-position wrong on macOS and Windows 7 after mouse-1 click Bob Weiner
  0 siblings, 2 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-30 21:56 UTC (permalink / raw)
  To: martin rudalics; +Cc: 28620

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

On Sat, Sep 30, 2017 at 1:12 PM, martin rudalics <rudalics@gmx.at> wrote:

> > This speaks to my point in my most recent prior message, "If we just had
> a
> > way to get a window from a set of coordinates within a frame, then I
> think
> > this would help solve a lot of this."  If the event-end of Emacs mouse
> drag
> > events included a window, rather than a frame, when the endpoint of the
> > drag is at a position unique to a window (considering Z-frame order), I
> > think that would solve all these issues and simplify parts of the posn
> code.
>

​The issue, to recap, is that I can't find a function that
will report the window that a mouse release button event
occurs in if the depress and release are in different frames
(for Emacs 25).

In fact, the release event (drag event) contains the wrong
frame (that of the depress rather than the release).  The wrong
frame is also reported by mouse-position and mouse-pixel-position,
so window-at can't be used either.

The problem seems to be documented in the Emacs event design.
Frame selection events are deferred when they occur while a button
is depressed to prevent some kind of state inconsistency.  But as
a result, the drag release event records the wrong frame and there
is no way for the release binding to determine and record the right
one.


> Take the position of the event-end (if it's a frame) and translate it
> into absolute screen coordinates (the Elisp manual should give you
> enough clues to do that).  Or, try ‘mouse-absolute-pixel-position’ - it
> should give you the screen position of the mouse at that time so you can
> ignore the event completely.
>
> Then walk all your windows and compare that position with whatever
> ‘window-absolute-pixel-edges’ returns for that window.  If you have two
> or more positives, run ‘frame-list-z-order’ and compare the result
> against those windows' frames.  No hands, IMHO.


​frame-list-z-order is Emacs 26 only; I need something that works with
older versions.​

Bob

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

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

* bug#28620: bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-30 21:56           ` bug#28620: " Robert Weiner
@ 2017-09-30 23:34             ` Robert Weiner
  2017-10-16 15:11             ` bug#28620: Emacs bug#28620: (PARTIAL SOLUTION) mouse-position wrong on macOS and Windows 7 after mouse-1 click Bob Weiner
  1 sibling, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2017-09-30 23:34 UTC (permalink / raw)
  To: martin rudalics; +Cc: 28620

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

On Sat, Sep 30, 2017 at 5:56 PM, Robert Weiner <rsw@gnu.org> wrote:

> In fact, the release event (drag event) contains the wrong
> frame (that of the depress rather than the release).
>

​In looking at how mouse-1 is able to select the proper window of a mouse
click,
I found that the release binding of mouse-1 changes when a click is in a
frame
other than the selected one.  In that case, it shifts from mouse-set-point
to
handle-switch-frame which selects the new frame.  Is this shift due to the
transient-map
map setting in mouse-drag-track?

Eli, if you could point me to where the switch-frame event is generated
when the click
is in another frame, with that I might be able to produce a temporary fix
for this problem.

It would also help if in handle-switch-frame, the handle-focus-in hook
invocation occurred
after the call to do_switch_frame rather than before; then we could grab
the value of the
newly selected frame rather than the old one.

Bob


tBut I can't find anywhere in
the Emacs 25 code where mouse-1 is bound to handle-switch-frame.

Can you point me to where this is coded?  Is the keymap in use changing?
Is there any way to capture a switch-frame event and attach my own handler
to
it?  (I guess I could redefine the primitive handle-switch-fraem

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

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

* bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window)
  2017-09-27 15:44 bug#28620: Mouse drag event records wrong window for release when crossing frames Robert Weiner
@ 2017-10-03 20:54 ` Robert Weiner
  2017-10-16 15:57 ` bug#28620: (PARTIAL SOLUTION) Mouse drag event records wrong window for release when crossing frames Bob Weiner
  2019-07-27  9:26 ` bug#36269: bug#28620: " martin rudalics
  2 siblings, 0 replies; 33+ messages in thread
From: Robert Weiner @ 2017-10-03 20:54 UTC (permalink / raw)
  To: 28620

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

Interestingly, mouse wheel scroll events work properly.  Such events always
include the window the mouse is over (when mouse-wheel-follow-mouse is t,
which it is by default).  They select this window and then scroll that
window, so I can move the mouse across frames and scroll arbitrary windows,
which suggests that drag events should operate similarly and include the
window of the drag release.

Now to find out how the position of the mouse is used differently in mouse
drags compared to mouse wheel events.

Bob

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

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

* bug#28620: Emacs bug#28620: (PARTIAL SOLUTION) mouse-position wrong on macOS and Windows 7 after mouse-1 click
  2017-09-30 21:56           ` bug#28620: " Robert Weiner
  2017-09-30 23:34             ` Robert Weiner
@ 2017-10-16 15:11             ` Bob Weiner
  1 sibling, 0 replies; 33+ messages in thread
From: Bob Weiner @ 2017-10-16 15:11 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii, 28620

Robert Weiner <rsw@gnu.org> writes:

I wrote:
>
> ​The issue, to recap, is that I can't find a function that
> will report the window that a mouse release button event
> occurs in if the depress and release are in different frames
> (for Emacs 25).
>
> In fact, the release event (drag event) contains the wrong
> frame (that of the depress rather than the release).  The wrong 
> frame is also reported by mouse-position and mouse-pixel-position,
> so window-at can't be used either.

The following is a temporary fix for the mouse-position and
mouse-pixel-position part of the problem.  Something needs to be fixed
in the original functions in the C code, though.  -- Bob

;; From mouse-position:
;;    f = SELECTED_FRAME ();
;;    XSETFRAME (lispy_dummy, f);
;;  It seems like the XSETFRAME macro is not properly copying the value of f on initial frame selection under the macOS window system.
;;  The problem occurs on other systems as well, e.g. Emacs 25.2 under Windows 7.
;;  The function below is a temporary fix for this.
(setq mouse-position-function
      (lambda (frame-x-dot-y)
	"Under macOS, mouse-position and mouse-pixel-position sometimes fail to return the selected-frame (returning the prior frame instead); fix that here."
	(setcar frame-x-dot-y (selected-frame))
	frame-x-dot-y))






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

* bug#28620: (PARTIAL SOLUTION) Mouse drag event records wrong window for release when crossing frames
  2017-09-27 15:44 bug#28620: Mouse drag event records wrong window for release when crossing frames Robert Weiner
  2017-10-03 20:54 ` bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window) Robert Weiner
@ 2017-10-16 15:57 ` Bob Weiner
  2019-07-27  9:26 ` bug#36269: bug#28620: " martin rudalics
  2 siblings, 0 replies; 33+ messages in thread
From: Bob Weiner @ 2017-10-16 15:57 UTC (permalink / raw)
  To: 28620

Robert Weiner <rsw@gnu.org> writes:

> With Emacs 25.3 under MacOS 10.12, a drag with mouse-1 depressed from
> the text area of frame F1 to the text area of frame F2 improperly
> generates a drag event whose (posn-window (event-end <event>)) shows
> F1 rather than F2.
>
> Note that for a drag between frames, posn-window should return a frame
> (according to the Elisp manual but not its own doc string).  The bug is
> that the event itself records the wrong frame (the depress frame rather
> than the release frame).
>
> I have confirmed this with Emacs 25.2 under Windows 7 as well.

I have this fixed and working nicely for the GNU Hyperbole package,
which does extensive mouse drag handling.  Hyperbole can now drag buffer
menu items, dired items, and buffers themselves across frames and
display them in any window that receives a release event.  It can also
tell whether the topmost application window at the point of release was
an Emacs frame or a window of another application (for macOS windowing
only), so drags can start in Emacs and end outside.

But this required a good bit of code that I include below just
so you can see what was required.  It would be much simpler once the
drag event release C code in Emacs is improved based upon this work to
at least return the actual window of drag release.

Bob

----------
Code from forthcoming Hyperbole 6.0.2e pre-release (the Python script
at the end will be converted to Objective-C at some point):


(defvar action-key-depress-args nil
  "List of mouse event args from most recent depress of the Action Key.")
(defvar assist-key-depress-args nil
  "List of mouse event args from most recent depress of the Assist Key.")

(defvar action-key-release-args nil
  "List of mouse event args from most recent release of the Action Key.")
(defvar assist-key-release-args nil
  "List of mouse event args from most recent release of the Assist Key.")

(defvar action-key-depress-window nil
  "The last window in which the Action Key was depressed or nil.
This is set to nil when the depress is on an inactive minibuffer.")
(defvar assist-key-depress-window nil
  "The last window in which the Assist Key was depressed or nil.
This is set to nil when the depress is on an inactive minibuffer.")
(defvar action-key-release-window nil
  "The last window in which the Action Key was released or nil.")
(defvar assist-key-release-window nil
  "The last window in which the Assist Key was released or nil.")

(defvar action-key-depress-position nil
  "The last screen position at which the Action Key was depressed or nil.")
(defvar assist-key-depress-position nil
  "The last screen position at which the Assist Key was depressed or nil.")


(defun hmouse-key-release-args-emacs (event)
  "For GNU Emacs, return a possibly modified version of EVENT as a list.
For mouse drags and double and triple clicks, remove any depress location,
compute the actual release location and include that."
  (if (integerp event)
      (list event)
    (let ((ev-type-str (and (listp event) (symbol-name (car event)))))
      (if (or (and ev-type-str
		   (string-match "\\(double\\|triple\\)-mouse" ev-type-str))
	      (not (= (length event) 3)))
	  event
	(let ((pos (event-end event))
	      coords window-and-char-coords)
	  (when (and ev-type-str (string-match "drag-mouse" ev-type-str)
		     ;; end of drag event; If drag crossed frames, the location
		     ;; will contain the frame of the depress point and
		     ;; some relative coordinates; change these to the window of
		     ;; release and window's character coordinates if within a window
		     ;; and to nil if outside of Emacs (as best we can tell).
		     (framep (posn-window pos)))
	    (setq window-and-char-coords (hmouse-window-coordinates event)
		  window (car window-and-char-coords)
		  coords (cadr window-and-char-coords))
	    ;; Modify the values in the event-end structure even if no
	    ;; valid window was found.
	    (setcar pos window)
	    (setcar (nthcdr 2 pos) coords)))
	;; Remove depress coordinates and send only original release coordinates.
	(list (car event) (nth 2 event))))))

(defun hmouse-window-coordinates (&optional event)
  "Return a list (window (x-chars . y-chars)) for optional EVENT.
Always ignores EVENT coordinates and uses current mouse position.
The area of the EVENT is utilized. If EVENT is not given and the
free variable `assist-flag' is non-nil, EVENT is set to
`assist-key-release-args', otherwise, `action-key-release-args'.

The coordinates x-chars and y-chars are relative character
coordinates within the window.  If POSITION is not in a live
window, return nil.  Considers all windows on the selected frame's display."
  (interactive)
  (unless (eventp event)
    (setq event (if assist-flag assist-key-release-args action-key-release-args)))
  (let* ((position (mouse-absolute-pixel-position))
	 (pos-x (car position))
	 (pos-y (cdr position))
	 (window (hmouse-window-at-absolute-pixel-position position t))
	 (edges (when (window-live-p window) (window-edges window t t t)))
	 left top right bottom
	 frame)
    (when edges
      (setq left   (nth 0 edges)
	    top    (nth 1 edges)
	    right  (nth 2 edges)
	    bottom (nth 3 edges))
      (when (or (and event (eq (posn-area (event-start event)) 'mode-line))
		(and (>= pos-x left) (<= pos-x right)
		     (>= pos-y top)  (<= pos-y bottom)))
	;; If position is in a live window, compute position's character
	;; coordinates within the window and return the window with these
	;; coordinates.
	(setq frame (window-frame window)
	      pos-x (round (/ (- pos-x left) (frame-char-width frame)))
	      pos-y (round (/ (- pos-y top)  (+ (frame-char-height frame)
						(hmouse-vertical-line-spacing frame)))))))
    (when (called-interactively-p 'interactive)
      (message "%s at %s coordinates (%s . %s)"
	       (if edges window "No live Emacs window")
	       (if frame "character" "absolute pixel")
	       pos-x pos-y))
    (when edges (list window (cons pos-x pos-y)))))

(defvar hmouse-verify-release-window-flag t
  "When non-nil under the macOS window system, verifies the application of top-most window.
Forces a window system check at a screen position that the top-most
window there is an Emacs frame or treats the location as outside Emacs,
even though an Emacs frame may be below the top-most window.

See function `hmouse-window-at-absolute-pixel-position' for more details.")

(defun hmouse-window-at-absolute-pixel-position (&optional position release-flag)
  "Return the top-most Emacs window at optional POSITION ((x . y) in absolute pixels) or mouse position.
If POSITION is not in a window, return nil.  Considers all windows on
the same display as the selected frame.

If optional RELEASE-FLAG is non-nil, this is part of a Smart Key
release computation, so optimize window selection based on the depress
window already computed.

If the selected frame is a graphical macOS window and
`hmouse-verity-release-window-flag' is non-nil, then return the
top-most Emacs window only if it is the top-most application window at
the position (not below another application's window)."
  (interactive)
  (setq position (or position (mouse-absolute-pixel-position)))
  ;; Proper top-to-bottom listing of frames is available only in Emacs
  ;; 26 and above.  For prior versions, the ordering of the frames
  ;; returned is not guaranteed, so the frame whose window is returned
  ;; may not be the uppermost.
  (let* ((top-to-bottom-frames (if (fboundp 'frame-list-z-order)
				   (frame-list-z-order)
				 (frame-list)))
	 (pos-x (car position))
	 (pos-y (cdr position))
	 edges left top right bottom
	 frame
	 in-frame
	 window)
    ;; First find top-most frame containing position.
    (while (and (not in-frame) top-to-bottom-frames)
      (setq frame (car top-to-bottom-frames)
	    top-to-bottom-frames (cdr top-to-bottom-frames))
      ;; Check that in-frame is valid with frame-live-p since under macOS
      ;; when position is outside a frame, in-frame could be invalid and
      ;; frame-visible-p would trigger an error in that case.
      (when (and (frame-live-p frame) (frame-visible-p frame))
	(setq edges (frame-edges frame)
	      left   (nth 0 edges)
	      top    (nth 1 edges)
	      right  (nth 2 edges)
	      bottom (nth 3 edges))
	(when (and (>= pos-x left) (<= pos-x right)
		   (>= pos-y top)  (<= pos-y bottom))
	  (setq in-frame frame))))
    ;; If in-frame is found, find which of its windows contains
    ;; position and return that.  The window-at call below requires
    ;; character coordinates relative to in-frame, so compute them.
    (when in-frame
      (let ((depress-position (and release-flag (if assist-flag
						    assist-key-depress-position
						  action-key-depress-position)))
	    (depress-window  (and release-flag (if assist-flag
						   assist-key-depress-window
						 action-key-depress-window))))
	(if (and release-flag depress-window (equal position depress-position))
	    ;; This was a click, so we know that the frame of the click
	    ;; is topmost on screen or the mouse events would not have
	    ;; been routed to Emacs.  Reuse saved window of depress rather
	    ;; then running possibly expensive computation to find the
	    ;; topmost application window.
	    (setq window depress-window)
	  (let ((char-x (/ (- pos-x left) (frame-char-width in-frame)))
		(line-y (/ (- pos-y top) (+ (frame-char-height in-frame)
					    (hmouse-vertical-line-spacing in-frame)))))
	    (setq window (window-at char-x line-y in-frame)))
	  ;;
	  ;; Even if in-frame is found, under click-to-focus external window
	  ;; managers, Emacs may have received the drag release event when
	  ;; in-frame was covered by an external application's window.
	  ;; Emacs presently has no way to handle this.  However, for the
	  ;; macOS window system only, Hyperbole has a Python script, topwin, which
	  ;; computes the application of the topmost window at the point of release.
	  ;; If that is Emacs, then we have the right window and nothing need be
	  ;; done; otherwise, set window to nil and return.
	  ;;
	  (when (and hmouse-verify-release-window-flag
		     window (eq (window-system) 'ns))
	    (let ((topwin (executable-find "topwin"))
		  (case-fold-search t)
		  topmost-app)
	      (when (and topwin (file-executable-p topwin))
		(setq topmost-app (shell-command-to-string
				   (format "topwin %d %d" pos-x pos-y)))
		(cond ((string-match "emacs" topmost-app)) ; In an Emacs frame, do nothing.
		      ((or (equal topmost-app "")
			   ;; Any non-Emacs app window
			   (string-match "\\`\\[" topmost-app))
		       ;; Outside of any Emacs frame
		       (setq window nil))
		      (t		; topwin error message
		       ;; Setup of the topwin script is somewhat complicated,
		       ;; so don't trigger an error just because of it.  But
		       ;; display a message so the user knows something happened
		       ;; when topwin encounters an error.
		       (message "(Hyperbole): topwin Python script error: %s" topmost-app)))))))))

    (when (called-interactively-p 'interactive)
      (message "%s at absolute pixel position %s"
	       (or window "No Emacs window") position))
    window))

;; Based on code from subr.el.
(defun hmouse-vertical-line-spacing (frame)
  "Return any extra vertical spacing in pixels between text lines or 0 if none."
  (let ((spacing (when (display-graphic-p frame)
                   (or (with-current-buffer (window-buffer (frame-selected-window frame))
                         line-spacing)
		       (frame-parameter frame 'line-spacing)))))
    (cond ((floatp spacing)
	   (setq spacing (truncate (* spacing (frame-char-height frame)))))
	  ((null spacing)
	   (setq spacing 0)))
    spacing))

------
#!python2
#
# SUMMARY:      topwin: Outputs the [application name] of the topmost window at mouse screen position or nothing if none
# USAGE:        <script> <x-screen-coordinate> <y-screen-coordinate>
#
# REQUIRES:     macOS window system and the python2 and the PyObjC libraries available here: https://pythonhosted.org/pyobjc/install.html
#
# AUTHOR:       Bob Weiner <rsw@gnu.org>
# ORIG-DATE:    14-Oct-17 at 16:21:53
#
# Copyright (C) 2017  Free Software Foundation, Inc.
# See the "HY-COPY" file for license information.
#
# DESCRIPTION:  
# DESCRIP-END.

import Quartz
from sys import argv, exit

if len(argv) < 3:
    print "%s: ERROR - Call with 2 numeric arguments, X and Y representing an absolute screen position" % argv[0]
    exit(1)

x = int(argv[1]); y = int(argv[2])

# Return the first window only that x,y falls within since the windows are listed in z-order (top of stack to bottom)
def filter_and_print_top_window(x, y):
    win_x = win_y = win_width = win_height = 0

    for v in Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID ):
        val = v.valueForKey_
        bounds_val = val('kCGWindowBounds').valueForKey_
        
        # If item has a non-zero WindowLayer, it is not an app and is probably system-level, so skip it.
        if not val('kCGWindowIsOnscreen') or val('kCGWindowLayer'):
            continue

        win_x = int(bounds_val('X')); win_y = int(bounds_val('Y'))
        win_width = int(bounds_val('Width')); win_height = int(bounds_val('Height'))

        if win_x <= x and x < win_x + win_width and win_y <= y and y < win_y + win_height:
            print ('[' + ((val('kCGWindowOwnerName') or '') + ']')).encode('utf8')
            # Add this line back in if you need to see the specific window within the app at the given position.
            # + ('' if val('kCGWindowName') is None else (' ' + val('kCGWindowName') or '')) \

            break

# Filter to just the topmost window at (x,y) screen coordinates and print the bracketed [window name], if any.
filter_and_print_top_window(x, y)






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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2017-09-29 20:11   ` Robert Weiner
  2017-09-30  8:32     ` martin rudalics
@ 2019-06-24 16:08     ` Lars Ingebrigtsen
  2019-06-27  2:20       ` Robert Weiner
  1 sibling, 1 reply; 33+ messages in thread
From: Lars Ingebrigtsen @ 2019-06-24 16:08 UTC (permalink / raw)
  To: Robert Weiner; +Cc: rswgnu, 28621

Robert Weiner <rsw@gnu.org> writes:

>  ​​I'm okay with installing the documentation changes in the release
>  ​​branch, but the change in posn-set-point should be discussed first, as
>  ​​I'm not sure we want that.  If we agree on making that change, it
>  ​​should go to master, I think.
>
> ​Sure, no problem.  Let's figure out a good solution and work towards that.

As far as I can tell, none of the posn-* doc strings were changed, even
though everybody seemed to agree that they should be.  Robert, did you
continue working on this?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2019-06-24 16:08     ` bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Lars Ingebrigtsen
@ 2019-06-27  2:20       ` Robert Weiner
  2019-06-27 10:39         ` Lars Ingebrigtsen
  2019-06-27 12:27         ` Robert Weiner
  0 siblings, 2 replies; 33+ messages in thread
From: Robert Weiner @ 2019-06-27  2:20 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 28621, Robert Weiner

I think all my changes are in the first message here.  Lars, can you see about integrating from there?  Thanks.

-- Bob

> On Jun 24, 2019, at 12:08 PM, Lars Ingebrigtsen <larsi@gnus.org> wrote:
> 
> Robert Weiner <rsw@gnu.org> writes:
> 
>> ​​I'm okay with installing the documentation changes in the release
>> ​​branch, but the change in posn-set-point should be discussed first, as
>> ​​I'm not sure we want that.  If we agree on making that change, it
>> ​​should go to master, I think.
>> 
>> ​Sure, no problem.  Let's figure out a good solution and work towards that.
> 
> As far as I can tell, none of the posn-* doc strings were changed, even
> though everybody seemed to agree that they should be.  Robert, did you
> continue working on this?
> 
> -- 
> (domestic pets only, the antidote for overdose, milk.)
>   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2019-06-27  2:20       ` Robert Weiner
@ 2019-06-27 10:39         ` Lars Ingebrigtsen
  2019-06-27 12:27         ` Robert Weiner
  1 sibling, 0 replies; 33+ messages in thread
From: Lars Ingebrigtsen @ 2019-06-27 10:39 UTC (permalink / raw)
  To: Robert Weiner; +Cc: 28621, Robert Weiner

Robert Weiner <rswgnu@gmail.com> writes:

> I think all my changes are in the first message here.  Lars, can you
> see about integrating from there?  Thanks.

If I understood the thread correctly, there was some worry that the
changes weren't completely correct in the presence of various frame
configurations?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2019-06-27  2:20       ` Robert Weiner
  2019-06-27 10:39         ` Lars Ingebrigtsen
@ 2019-06-27 12:27         ` Robert Weiner
  2020-08-24 13:28           ` Lars Ingebrigtsen
  2020-08-24 13:29           ` Lars Ingebrigtsen
  1 sibling, 2 replies; 33+ messages in thread
From: Robert Weiner @ 2019-06-27 12:27 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 28621, Robert Weiner

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


> On Jun 26, 2019, at 10:20 PM, Robert Weiner <rswgnu@gmail.com> wrote:
> 
> I think all my changes are in the first message here.  Lars, can you see about integrating from there?  Thanks.
> 

Plus, this message now that I have re-read the thread.  I think the main issue was just documenting the changes in NEWS, Changes, the manuals, etc.  I have been using these patches for all this time now with Hyperbole’s cross-frame drags on multiple platforms under Emacs 26 without incident.  It would be great to see this moved forward.  — Bob

Robert Weiner <rsw@gnu.org> writes:

I wrote:
> 
> ​The issue, to recap, is that I can't find a function that
> will report the window that a mouse release button event
> occurs in if the depress and release are in different frames
> (for Emacs 25).
> 
> In fact, the release event (drag event) contains the wrong
> frame (that of the depress rather than the release).  The wrong 
> frame is also reported by mouse-position and mouse-pixel-position,
> so window-at can't be used either.

Show Quoted Content
> 
> ​The issue, to recap, is that I can't find a function that
> will report the window that a mouse release button event
> occurs in if the depress and release are in different frames
> (for Emacs 25).
> 
> In fact, the release event (drag event) contains the wrong
> frame (that of the depress rather than the release).  The wrong 
> frame is also reported by mouse-position and mouse-pixel-position,
> so window-at can't be used either.

The following is a temporary fix for the mouse-position and
mouse-pixel-position part of the problem.  Something needs to be fixed
in the original functions in the C code, though.  -- Bob

;; From mouse-position:
;;    f = SELECTED_FRAME ();
;;    XSETFRAME (lispy_dummy, f);
;;  It seems like the XSETFRAME macro is not properly copying the value of f on initial frame selection under the macOS window system.
;;  The problem occurs on other systems as well, e.g. Emacs 25.2 under Windows 7.
;;  The function below is a temporary fix for this.
(setq mouse-position-function
     (lambda (frame-x-dot-y)
   "Under macOS, mouse-position and mouse-pixel-position sometimes fail to return the selected-frame (returning the prior frame instead); fix that here."
   (setcar frame-x-dot-y (selected-frame))
   frame-x-dot-y))

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

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

* bug#36269: bug#28620: Mouse drag event records wrong window for release when crossing frames
  2017-09-27 15:44 bug#28620: Mouse drag event records wrong window for release when crossing frames Robert Weiner
  2017-10-03 20:54 ` bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window) Robert Weiner
  2017-10-16 15:57 ` bug#28620: (PARTIAL SOLUTION) Mouse drag event records wrong window for release when crossing frames Bob Weiner
@ 2019-07-27  9:26 ` martin rudalics
  2019-07-27 10:08   ` Eli Zaretskii
  2 siblings, 1 reply; 33+ messages in thread
From: martin rudalics @ 2019-07-27  9:26 UTC (permalink / raw)
  To: rswgnu, 28620, 36269, Scott Otterson

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

 > With Emacs 25.3 under MacOS 10.12, a drag with mouse-1 depressed from
 > the text area of frame F1 to the text area of frame F2 improperly
 > generates a drag event whose (posn-window (event-end <event>)) shows
 > F1 rather than F2.
 >
 > Note that for a drag between frames, posn-window should return a frame
 > (according to the Elisp manual but not its own doc string).  The bug is
 > that the event itself records the wrong frame (the depress frame rather
 > than the release frame).
 >
 > I have confirmed this with Emacs 25.2 under Windows 7 as well.

I tried to address this problem in the attached patch.  Tested with
GTK, Lucid, Motif and Windows builds.  Since my GNUstep Emacs is
currently broken, somebody please verify that it does something
reasonable (if anything at all) on MacOS.  Otherwise, I'd need help
from people working there.

The patch should also fix the mouse drag and drop region vs. mouse
avoidance mode problem.  Please someone verify that it does TRT now.

TIA, martin

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

diff --git a/lisp/avoid.el b/lisp/avoid.el
index 7d69fa2a24..43e5062b76 100644
--- a/lisp/avoid.el
+++ b/lisp/avoid.el
@@ -327,6 +327,9 @@ mouse-avoidance-ignore-p
         executing-kbd-macro	       ; don't check inside macro
 	(null (cadr mp))	       ; don't move unless in an Emacs frame
 	(not (eq (car mp) (selected-frame)))
+        ;; Don't interfere with ongoing `mouse-drag-and-drop-region'
+        ;; (Bug#36269).
+        (eq track-mouse 'dropping)
 	;; Don't do anything if last event was a mouse event.
 	;; FIXME: this code fails in the case where the mouse was moved
 	;; since the last key-press but without generating any event.
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a532a15e5..e947e16d47 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1296,7 +1296,7 @@ mouse-drag-track
      t (lambda ()
          (setq track-mouse old-track-mouse)
          (setq auto-hscroll-mode auto-hscroll-mode-saved)
-          (deactivate-mark)
+         (deactivate-mark)
          (pop-mark)))))
 
 (defun mouse--drag-set-mark-and-point (start click click-count)
@@ -2467,12 +2467,13 @@ mouse-drag-and-drop-region
 
     (ignore-errors
       (track-mouse
+        (setq track-mouse 'dropping)
         ;; 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)))
+                     (memq (car event) '(select-window switch-frame))))
           ;; Obtain the dragged text in region.  When the loop was
           ;; skipped, value-selection remains nil.
           (unless value-selection
diff --git a/src/dispnew.c b/src/dispnew.c
index 0131b63767..74d53fb46d 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3402,9 +3402,9 @@ update_window (struct window *w, bool force_p)
   if (!force_p)
     detect_input_pending_ignore_squeezables ();
 
-  /* If forced to complete the update, or if no input is pending, do
-     the update.  */
-  if (force_p || !input_pending || !NILP (do_mouse_tracking))
+  /* If forced to complete the update, no input is pending or we are
+     tracking the mouse do the update.  */
+  if (force_p || !input_pending || !NILP (track_mouse))
     {
       struct glyph_row *row, *end;
       struct glyph_row *mode_line_row;
diff --git a/src/keyboard.c b/src/keyboard.c
index b86ad03851..4224ab01b3 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1159,14 +1159,14 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
   user_error ("No recursive edit is in progress");
 }
 \f
-/* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
-   of this function.  */
+/* Restore mouse tracking enablement.  See Finternal_track_mouse for
+   the only use of this function.  */
 
 static void
-tracking_off (Lisp_Object old_value)
+tracking_off (Lisp_Object old_track_mouse)
 {
-  do_mouse_tracking = old_value;
-  if (NILP (old_value))
+  track_mouse = old_track_mouse;
+  if (NILP (old_track_mouse))
     {
       /* Redisplay may have been preempted because there was input
 	 available, and it assumes it will be called again after the
@@ -1181,24 +1181,24 @@ tracking_off (Lisp_Object old_value)
     }
 }
 
-DEFUN ("internal--track-mouse", Ftrack_mouse, Strack_mouse, 1, 1, 0,
+DEFUN ("internal--track-mouse", Finternal_track_mouse, Sinternal_track_mouse,
+       1, 1, 0,
        doc: /* Call BODYFUN with mouse movement events enabled.  */)
   (Lisp_Object bodyfun)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object val;
 
-  record_unwind_protect (tracking_off, do_mouse_tracking);
+  record_unwind_protect (tracking_off, track_mouse);
 
-  do_mouse_tracking = Qt;
+  track_mouse = Qt;
 
   val = call0 (bodyfun);
   return unbind_to (count, val);
 }
 
-/* If mouse has moved on some frame, return one of those frames.
-
-   Return 0 otherwise.
+/* If mouse has moved on some frame and we are tracking the mouse,
+   return one of those frames.  Return NULL otherwise.
 
    If ignore_mouse_drag_p is non-zero, ignore (implicit) mouse movement
    after resizing the tool-bar window.  */
@@ -1210,11 +1210,8 @@ some_mouse_moved (void)
 {
   Lisp_Object tail, frame;
 
-  if (ignore_mouse_drag_p)
-    {
-      /* ignore_mouse_drag_p = false; */
-      return 0;
-    }
+  if (NILP (track_mouse) || ignore_mouse_drag_p)
+    return NULL;
 
   FOR_EACH_FRAME (tail, frame)
     {
@@ -1222,7 +1219,7 @@ some_mouse_moved (void)
 	return XFRAME (frame);
     }
 
-  return 0;
+  return NULL;
 }
 
 \f
@@ -2071,7 +2068,8 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
 	 This causes trouble if we are trying to read a mouse motion
 	 event (i.e., if we are inside a `track-mouse' form), so we
 	 restore the mouse_moved flag.  */
-      struct frame *f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved ();
+      struct frame *f = some_mouse_moved ();
+
       help = call1 (Qmouse_fixup_help_message, help);
       if (f)
 	f->mouse_moved = true;
@@ -3403,8 +3401,7 @@ readable_events (int flags)
 	return 1;
     }
 
-  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
-      && !NILP (do_mouse_tracking) && some_mouse_moved ())
+  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ())
     return 1;
   if (single_kboard)
     {
@@ -3786,7 +3783,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 
       if (kbd_fetch_ptr != kbd_store_ptr)
 	break;
-      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+      if (some_mouse_moved ())
 	break;
 
       /* If the quit flag is set, then read_char will return
@@ -3802,7 +3799,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #endif
       if (kbd_fetch_ptr != kbd_store_ptr)
 	break;
-      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+      if (some_mouse_moved ())
 	break;
       if (end_time)
 	{
@@ -3941,8 +3938,9 @@ kbd_buffer_get_event (KBOARD **kbp,
         break;
       default:
 	{
-	  /* If this event is on a different frame, return a switch-frame this
-	     time, and leave the event in the queue for next time.  */
+	  /* If this event is on a different frame, return a
+	     switch-frame this time and leave the event in the queue
+	     for next time.  */
 	  Lisp_Object frame;
 	  Lisp_Object focus;
 
@@ -3956,14 +3954,13 @@ kbd_buffer_get_event (KBOARD **kbp,
 	  if (! NILP (focus))
 	    frame = focus;
 
-	  if (! EQ (frame, internal_last_event_frame)
+	  if (!EQ (frame, internal_last_event_frame)
 	      && !EQ (frame, selected_frame))
 	    obj = make_lispy_switch_frame (frame);
 	  internal_last_event_frame = frame;
 
 	  /* If we didn't decide to make a switch-frame event, go ahead
 	     and build a real event from the queue entry.  */
-
 	  if (NILP (obj))
 	    {
 	      obj = make_lispy_event (&event->ie);
@@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       }
     }
   /* Try generating a mouse motion event.  */
-  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+  else if (some_mouse_moved ())
     {
       struct frame *f = some_mouse_moved ();
       Lisp_Object bar_window;
@@ -4027,7 +4024,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 	  if (NILP (frame))
 	    XSETFRAME (frame, f);
 
-	  if (! EQ (frame, internal_last_event_frame)
+	  if (!EQ (frame, internal_last_event_frame)
 	      && !EQ (frame, selected_frame))
 	    obj = make_lispy_switch_frame (frame);
 	  internal_last_event_frame = frame;
@@ -10935,7 +10932,7 @@ init_keyboard (void)
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  do_mouse_tracking = Qnil;
+  track_mouse = Qnil;
   input_pending = false;
   interrupt_input_blocked = 0;
   pending_signals = false;
@@ -11297,7 +11294,7 @@ syms_of_keyboard (void)
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
   defsubr (&Srecursive_edit);
-  defsubr (&Strack_mouse);
+  defsubr (&Sinternal_track_mouse);
   defsubr (&Sinput_pending_p);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
@@ -11642,8 +11639,15 @@ and the minor mode maps regardless of `overriding-local-map'.  */);
 	       doc: /* Keymap defining bindings for special events to execute at low level.  */);
   Vspecial_event_map = list1 (Qkeymap);
 
-  DEFVAR_LISP ("track-mouse", do_mouse_tracking,
-	       doc: /* Non-nil means generate motion events for mouse motion.  */);
+  DEFVAR_LISP ("track-mouse", track_mouse,
+	       doc: /* Non-nil means generate motion events for mouse motion.
+The sepecial values 'dragging' and 'dropping' assert that the moue
+cursor retains its appearance during mouse motion.  Any non-nil value
+but 'dropping' asserts that motion events always relate to the frame
+where the the mouse movement started.  The value 'dropping' asserts
+that motion events relate to the frame where the mouse cursor is seen
+when generating the event.  If there's no such frame, such motion
+events relate to the frame where the mouse movement started.  */);
 
   DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist,
 		 doc: /* Alist of system-specific X windows key symbols.
diff --git a/src/nsterm.m b/src/nsterm.m
index 02331826d9..75bf85617b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2480,7 +2480,11 @@ so some key presses (TAB) are swallowed by the system.  */
       XFRAME (frame)->mouse_moved = 0;
 
   dpyinfo->last_mouse_scroll_bar = nil;
+  f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame : SELECTED_FRAME ();
   if (dpyinfo->last_mouse_frame
+      /* While dropping use the last mouse frame only if there is no
+	 currently focused frame.  */
+      && (!EQ (track_mouse, Qdropping) || !f)
       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
     f = dpyinfo->last_mouse_frame;
   else
diff --git a/src/term.c b/src/term.c
index b058d8bdad..a88d47f923 100644
--- a/src/term.c
+++ b/src/term.c
@@ -3033,18 +3033,18 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
       bool usable_input = 1;
       mi_result st = MI_CONTINUE;
       struct tty_display_info *tty = FRAME_TTY (sf);
-      Lisp_Object saved_mouse_tracking = do_mouse_tracking;
+      Lisp_Object old_track_mouse = track_mouse;
 
       /* Signal the keyboard reading routines we are displaying a menu
 	 on this terminal.  */
       tty->showing_menu = 1;
       /* We want mouse movements be reported by read_menu_command.  */
-      do_mouse_tracking = Qt;
+      track_mouse = Qt;
       do {
 	cmd = read_menu_command ();
       } while (NILP (cmd));
       tty->showing_menu = 0;
-      do_mouse_tracking = saved_mouse_tracking;
+      track_mouse = old_track_mouse;
 
       if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
 	  /* If some input switched frames under our feet, exit the
diff --git a/src/w32fns.c b/src/w32fns.c
index acd9c80528..a2a88b2588 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -4586,7 +4586,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	if (button_state & this)
 	  return 0;
 
-	if (button_state == 0)
+	/* Don't capture mouse when dropping.  */
+	if (button_state == 0 && !EQ (track_mouse, Qdropping))
 	  SetCapture (hwnd);
 
 	button_state |= this;
@@ -4707,8 +4708,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
 	if (parse_button (msg, HIWORD (wParam), &button, &up))
 	  {
-	    if (up) ReleaseCapture ();
-	    else SetCapture (hwnd);
+	    if (up)
+	      ReleaseCapture ();
+	    /* Don't capture mouse when dropping.  */
+	    else if (!EQ (track_mouse, Qdropping))
+	      SetCapture (hwnd);
 	    button = (button == 0) ? LMOUSE :
 	      ((button == 1) ? MMOUSE  : RMOUSE);
 	    if (up)
@@ -5351,8 +5355,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	else if (button_state & RMOUSE)
 	  flags |= TPM_RIGHTBUTTON;
 
-	/* Remember we did a SetCapture on the initial mouse down event,
-	   so for safety, we make sure the capture is canceled now.  */
+	/* We may have done a SetCapture on the initial mouse down
+	   event, so for safety, make sure the capture is canceled
+	   now.  */
 	ReleaseCapture ();
 	button_state = 0;
 
diff --git a/src/w32term.c b/src/w32term.c
index c6e175e7e5..ad96287a43 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3525,72 +3525,78 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 
       /* Now we have a position on the root; find the innermost window
 	 containing the pointer.  */
-      {
-	/* If mouse was grabbed on a frame, give coords for that
-	   frame even if the mouse is now outside it.  Otherwise
-	   check for window under mouse on one of our frames.  */
-	if (gui_mouse_grabbed (dpyinfo))
-	  f1 = dpyinfo->last_mouse_frame;
-	else
-	  {
-	    HWND wfp = WindowFromPoint (pt);
 
-	    if (wfp)
-	      {
-		f1 = w32_window_to_frame (dpyinfo, wfp);
-		if (f1)
-		  {
-		    HWND cwfp = ChildWindowFromPoint (wfp, pt);
+      /* If mouse was grabbed on a frame and we are not dropping,
+	 give coords for that frame even if the mouse is now outside
+	 it.  Otherwise check for window under mouse on one of our
+	 frames.  */
+      if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
+	f1 = dpyinfo->last_mouse_frame;
+      else
+	{
+	  HWND wfp = WindowFromPoint (pt);
 
-		    if (cwfp)
-		      {
-			struct frame *f2 = w32_window_to_frame (dpyinfo, cwfp);
+	  if (wfp)
+	    {
+	      f1 = w32_window_to_frame (dpyinfo, wfp);
+	      if (f1)
+		{
+		  HWND cwfp = ChildWindowFromPoint (wfp, pt);
 
-			/* If a child window was found, make sure that its
-			   frame is a child frame (Bug#26615, maybe).  */
-			if (f2 && FRAME_PARENT_FRAME (f2))
-			  f1 = f2;
-		      }
-		  }
-	      }
-	  }
+		  if (cwfp)
+		    {
+		      struct frame *f2 = w32_window_to_frame (dpyinfo, cwfp);
 
-	/* If not, is it one of our scroll bars?  */
-	if (! f1)
-	  {
-	    struct scroll_bar *bar
-              = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
+		      /* If a child window was found, make sure that its
+			 frame is a child frame (Bug#26615, maybe).  */
+		      if (f2 && FRAME_PARENT_FRAME (f2))
+			f1 = f2;
+		    }
+		}
+	    }
+	}
 
-	    if (bar)
-	      f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
-	  }
+      if (!f1 || FRAME_TOOLTIP_P (f1))
+	/* Don't use a tooltip frame.  */
+	f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (dpyinfo))
+	      ? dpyinfo->last_mouse_frame
+	      : NULL);
 
-	if (f1 == 0 && insist > 0)
-	  f1 = SELECTED_FRAME ();
+      /* If not, is it one of our scroll bars?  */
+      if (!f1)
+	{
+	  struct scroll_bar *bar
+	    = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
 
-	if (f1)
-	  {
-	    /* Ok, we found a frame.  Store all the values.
-	       last_mouse_glyph is a rectangle used to reduce the
-	       generation of mouse events.  To not miss any motion
-	       events, we must divide the frame into rectangles of the
-	       size of the smallest character that could be displayed
-	       on it, i.e. into the same rectangles that matrices on
-	       the frame are divided into.  */
-
-	    dpyinfo = FRAME_DISPLAY_INFO (f1);
-	    ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
-	    remember_mouse_glyph (f1, pt.x, pt.y, &dpyinfo->last_mouse_glyph);
-	    dpyinfo->last_mouse_glyph_frame = f1;
-
-	    *bar_window = Qnil;
-	    *part = scroll_bar_above_handle;
-	    *fp = f1;
-	    XSETINT (*x, pt.x);
-	    XSETINT (*y, pt.y);
-	    *time = dpyinfo->last_mouse_movement_time;
-	  }
-      }
+	  if (bar)
+	    f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
+	}
+
+      if (!f1 && insist > 0)
+	f1 = SELECTED_FRAME ();
+
+      if (f1)
+	{
+	  /* Ok, we found a frame.  Store all the values.
+	     last_mouse_glyph is a rectangle used to reduce the
+	     generation of mouse events.  To not miss any motion
+	     events, we must divide the frame into rectangles of the
+	     size of the smallest character that could be displayed
+	     on it, i.e. into the same rectangles that matrices on
+	     the frame are divided into.  */
+
+	  dpyinfo = FRAME_DISPLAY_INFO (f1);
+	  ScreenToClient (FRAME_W32_WINDOW (f1), &pt);
+	  remember_mouse_glyph (f1, pt.x, pt.y, &dpyinfo->last_mouse_glyph);
+	  dpyinfo->last_mouse_glyph_frame = f1;
+
+	  *bar_window = Qnil;
+	  *part = scroll_bar_above_handle;
+	  *fp = f1;
+	  XSETINT (*x, pt.x);
+	  XSETINT (*y, pt.y);
+	  *time = dpyinfo->last_mouse_movement_time;
+	}
     }
 
   unblock_input ();
@@ -4667,6 +4673,37 @@ static short temp_buffer[100];
 /* Temporarily store lead byte of DBCS input sequences.  */
 static char dbcs_lead = 0;
 
+/**
+  mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
+  for DPYINFO, return the frame where the mouse was seen last.  If
+  there's no such frame, return the frame according to WDESC.  When
+  dropping, return the frame according to WDESC.  If there's no such
+  frame and the mouse was grabbed for DPYINFO, return the frame where
+  the mouse was seen last.  In either case, never return a tooltip
+  frame.  */
+static struct frame *
+mouse_or_wdesc_frame (struct w32_display_info *dpyinfo, HWND wdesc)
+{
+  struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
+			? dpyinfo->last_mouse_frame
+			: NULL);
+
+  if (lm_f && !EQ (track_mouse, Qdropping))
+    return lm_f;
+  else
+    {
+      struct frame *w_f = w32_window_to_frame (dpyinfo, wdesc);
+
+      /* Do not return a tooltip frame.  */
+      if (!w_f || FRAME_TOOLTIP_P (w_f))
+	return EQ (track_mouse, Qdropping) ? lm_f : NULL;
+      else
+	/* When dropping it would be probably nice to raise w_f
+	   here.  */
+	return w_f;
+    }
+}
+
 /* Read events coming from the W32 shell.
    This routine is called by the SIGIO handler.
    We return as soon as there are no more events to be read.
@@ -4940,15 +4977,13 @@ w32_read_socket (struct terminal *terminal,
           previous_help_echo_string = help_echo_string;
 	  help_echo_string = Qnil;
 
-	  f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-	       : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
 	  if (hlinfo->mouse_face_hidden)
 	    {
 	      hlinfo->mouse_face_hidden = false;
 	      clear_mouse_face (hlinfo);
 	    }
 
+	  f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	  if (f)
 	    {
 	      /* Maybe generate SELECT_WINDOW_EVENTs for
@@ -5020,9 +5055,7 @@ w32_read_socket (struct terminal *terminal,
 	    int button = 0;
 	    int up = 0;
 
-	    f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-		 : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
+	    f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	    if (f)
 	      {
                 w32_construct_mouse_click (&inev, &msg, f);
@@ -5081,9 +5114,7 @@ w32_read_socket (struct terminal *terminal,
 	case WM_MOUSEWHEEL:
         case WM_MOUSEHWHEEL:
 	  {
-	    f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-		 : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
+	    f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	    if (f)
 	      {
 		if (!dpyinfo->w32_focus_frame
@@ -5439,6 +5470,7 @@ w32_read_socket (struct terminal *terminal,
 	      if (any_help_event_p)
 		do_help = -1;
 	    }
+
 	  break;
 
 	case WM_SETFOCUS:
diff --git a/src/xdisp.c b/src/xdisp.c
index 1bb5f5e0f2..7338d2b7d4 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -17289,7 +17289,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 	 the mouse, resulting in an unwanted mouse-movement rather
 	 than a simple mouse-click.  */
       if (!w->start_at_line_beg
-	  && NILP (do_mouse_tracking)
+	  && NILP (track_mouse)
       	  && CHARPOS (startp) > BEGV
 	  && CHARPOS (startp) > BEG + beg_unchanged
 	  && CHARPOS (startp) <= Z - end_unchanged
@@ -30279,7 +30279,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
 
 #ifdef HAVE_WINDOW_SYSTEM
   /* Change the mouse cursor.  */
-  if (FRAME_WINDOW_P (f) && NILP (do_mouse_tracking))
+  if (FRAME_WINDOW_P (f) && NILP (track_mouse))
     {
 #ifndef HAVE_EXT_TOOL_BAR
       if (draw == DRAW_NORMAL_TEXT
@@ -31226,7 +31226,7 @@ define_frame_cursor1 (struct frame *f, Emacs_Cursor cursor, Lisp_Object pointer)
     return;
 
   /* Do not change cursor shape while dragging mouse.  */
-  if (EQ (do_mouse_tracking, Qdragging))
+  if (EQ (track_mouse, Qdragging) || EQ (track_mouse, Qdropping))
     return;
 
   if (!NILP (pointer))
@@ -32956,6 +32956,7 @@ be let-bound around code that needs to disable messages temporarily. */);
   /* also Qtext */
 
   DEFSYM (Qdragging, "dragging");
+  DEFSYM (Qdropping, "dropping");
 
   DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
diff --git a/src/xterm.c b/src/xterm.c
index c96aa74a7a..97d14f7d45 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5167,20 +5167,15 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
       /* Figure out which root window we're on.  */
       XQueryPointer (FRAME_X_DISPLAY (*fp),
 		     DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
-
 		     /* The root window which contains the pointer.  */
 		     &root,
-
 		     /* Trash which we can't trust if the pointer is on
 			a different screen.  */
 		     &dummy_window,
-
 		     /* The position on that root window.  */
 		     &root_x, &root_y,
-
 		     /* More trash we can't trust.  */
 		     &dummy, &dummy,
-
 		     /* Modifier keys and pointer buttons, about which
 			we don't care.  */
 		     (unsigned int *) &dummy);
@@ -5203,21 +5198,17 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 
 	x_catch_errors (FRAME_X_DISPLAY (*fp));
 
-	if (gui_mouse_grabbed (dpyinfo))
+	if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
 	  {
 	    /* If mouse was grabbed on a frame, give coords for that frame
 	       even if the mouse is now outside it.  */
 	    XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
-
 				   /* From-window.  */
 				   root,
-
 				   /* To-window.  */
 				   FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
-
 				   /* From-position, to-position.  */
 				   root_x, root_y, &win_x, &win_y,
-
 				   /* Child of win.  */
 				   &child);
 	    f1 = dpyinfo->last_mouse_frame;
@@ -5227,16 +5218,12 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 	    while (true)
 	      {
 		XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
-
 				       /* From-window, to-window.  */
 				       root, win,
-
 				       /* From-position, to-position.  */
 				       root_x, root_y, &win_x, &win_y,
-
 				       /* Child of win.  */
 				       &child);
-
 		if (child == None || child == win)
 		  {
 #ifdef USE_GTK
@@ -5299,13 +5286,35 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 #endif /* USE_X_TOOLKIT */
 	  }
 
+	if ((!f1 || FRAME_TOOLTIP_P (f1))
+	    && EQ (track_mouse, Qdropping)
+	    && gui_mouse_grabbed (dpyinfo))
+	  {
+	    /* When dropping then if we didn't get a frame or only a
+	       tooltip frame and the mouse was grabbed on a frame,
+	       give coords for that frame even if the mouse is now
+	       outside it.  */
+	    XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
+				   /* From-window.  */
+				   root,
+				   /* To-window.  */
+				   FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
+				   /* From-position, to-position.  */
+				   root_x, root_y, &win_x, &win_y,
+				   /* Child of win.  */
+				   &child);
+	    f1 = dpyinfo->last_mouse_frame;
+	  }
+	else if (f1 && FRAME_TOOLTIP_P (f1))
+	  f1 = NULL;
+
 	if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
-	  f1 = 0;
+	  f1 = NULL;
 
 	x_uncatch_errors_after_check ();
 
 	/* If not, is it one of our scroll bars?  */
-	if (! f1)
+	if (!f1)
 	  {
 	    struct scroll_bar *bar;
 
@@ -5319,7 +5328,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 	      }
 	  }
 
-	if (f1 == 0 && insist > 0)
+	if (!f1 && insist > 0)
 	  f1 = SELECTED_FRAME ();
 
 	if (f1)
@@ -7788,6 +7797,37 @@ flush_dirty_back_buffers (void)
   unblock_input ();
 }
 
+/**
+  mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
+  for DPYINFO, return the frame where the mouse was seen last.  If
+  there's no such frame, return the frame according to WDESC.  When
+  dropping, return the frame according to WDESC.  If there's no such
+  frame and the mouse was grabbed for DPYINFO, return the frame where
+  the mouse was seen last.  In either case, never return a tooltip
+  frame.  */
+static struct frame *
+mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
+{
+  struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
+			? dpyinfo->last_mouse_frame
+			: NULL);
+
+  if (lm_f && !EQ (track_mouse, Qdropping))
+    return lm_f;
+  else
+    {
+      struct frame *w_f = x_window_to_frame (dpyinfo, wdesc);
+
+      /* Do not return a tooltip frame.  */
+      if (!w_f || FRAME_TOOLTIP_P (w_f))
+	return EQ (track_mouse, Qdropping) ? lm_f : NULL;
+      else
+	/* When dropping it would be probably nice to raise w_f
+	   here.  */
+	return w_f;
+    }
+}
+
 /* Handles the XEvent EVENT on display DPYINFO.
 
    *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -8720,15 +8760,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         previous_help_echo_string = help_echo_string;
         help_echo_string = Qnil;
 
-	f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-	     : x_window_to_frame (dpyinfo, event->xmotion.window));
-
-        if (hlinfo->mouse_face_hidden)
+	if (hlinfo->mouse_face_hidden)
           {
             hlinfo->mouse_face_hidden = false;
             clear_mouse_face (hlinfo);
           }
 
+	f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
+
 #ifdef USE_GTK
         if (f && xg_event_is_for_scrollbar (f, event))
           f = 0;
@@ -8970,33 +9009,27 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 	dpyinfo->last_mouse_glyph_frame = NULL;
 	x_display_set_last_user_time (dpyinfo, event->xbutton.time);
 
-	if (gui_mouse_grabbed (dpyinfo))
-	  f = dpyinfo->last_mouse_frame;
-	else
+	f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
+	if (f && event->xbutton.type == ButtonPress
+	    && !popup_activated ()
+	    && !x_window_to_scroll_bar (event->xbutton.display,
+					event->xbutton.window, 2)
+	    && !FRAME_NO_ACCEPT_FOCUS (f))
 	  {
-	    f = x_window_to_frame (dpyinfo, event->xbutton.window);
+	    /* When clicking into a child frame or when clicking
+	       into a parent frame with the child frame selected and
+	       `no-accept-focus' is not set, select the clicked
+	       frame.  */
+	    struct frame *hf = dpyinfo->highlight_frame;
 
-	    if (f && event->xbutton.type == ButtonPress
-		&& !popup_activated ()
-		&& !x_window_to_scroll_bar (event->xbutton.display,
-					    event->xbutton.window, 2)
-		&& !FRAME_NO_ACCEPT_FOCUS (f))
+	    if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
 	      {
-		/* When clicking into a child frame or when clicking
-		   into a parent frame with the child frame selected and
-		   `no-accept-focus' is not set, select the clicked
-		   frame.  */
-		struct frame *hf = dpyinfo->highlight_frame;
-
-		if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
-		  {
-		    block_input ();
-		    XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
-				    RevertToParent, CurrentTime);
-		    if (FRAME_PARENT_FRAME (f))
-		      XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
-		    unblock_input ();
-		  }
+		block_input ();
+		XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+				RevertToParent, CurrentTime);
+		if (FRAME_PARENT_FRAME (f))
+		  XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+		unblock_input ();
 	      }
 	  }
 


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

* bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-07-27  9:26 ` bug#36269: bug#28620: " martin rudalics
@ 2019-07-27 10:08   ` Eli Zaretskii
  2019-07-28  7:34     ` martin rudalics
  0 siblings, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2019-07-27 10:08 UTC (permalink / raw)
  To: martin rudalics; +Cc: rswgnu, scotto, 28620, 36269

> From: martin rudalics <rudalics@gmx.at>
> Date: Sat, 27 Jul 2019 11:26:47 +0200
> 
> I tried to address this problem in the attached patch.  Tested with
> GTK, Lucid, Motif and Windows builds.  Since my GNUstep Emacs is
> currently broken, somebody please verify that it does something
> reasonable (if anything at all) on MacOS.  Otherwise, I'd need help
> from people working there.
> 
> The patch should also fix the mouse drag and drop region vs. mouse
> avoidance mode problem.  Please someone verify that it does TRT now.

Thanks, a few minor comments below.

> +  /* If forced to complete the update, no input is pending or we are
> +     tracking the mouse do the update.  */

Commas missing here.  Should be

  /* If forced to complete the update, no input is pending, or we are
     tracking the mouse, do the update.  */


> -	  /* If this event is on a different frame, return a switch-frame this
> -	     time, and leave the event in the queue for next time.  */
> +	  /* If this event is on a different frame, return a
> +	     switch-frame this time and leave the event in the queue

A comma missing before "and".

> @@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp,
>        }
>      }
>    /* Try generating a mouse motion event.  */
> -  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
> +  else if (some_mouse_moved ())

Can't we have mouse motion events outside track-mouse?

> +  DEFVAR_LISP ("track-mouse", track_mouse,
> +	       doc: /* Non-nil means generate motion events for mouse motion.
> +The sepecial values 'dragging' and 'dropping' assert that the moue
       ^^^^^^^^                                                  ^^^^
Typos.

Also, the quoting in doc strings should be `like this'.

> +      /* While dropping use the last mouse frame only if there is no
> +	 currently focused frame.  */

A comma missing before "use".

There's too much of whitespace changes in the rest of the patch,
making it very hard to review.  Can you show the patch without
whitespace differences?

Thanks.





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

* bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-07-27 10:08   ` Eli Zaretskii
@ 2019-07-28  7:34     ` martin rudalics
  2019-07-29 23:21       ` Robert Weiner
  2019-08-03 11:25       ` Eli Zaretskii
  0 siblings, 2 replies; 33+ messages in thread
From: martin rudalics @ 2019-07-28  7:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rswgnu, scotto, 28620, 36269

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

 > Thanks, a few minor comments below.

Thanks for the comments.  I hopefully applied all changes you
proposed.

Please keep in mind that I wrote the code almost two years ago and
then forgot about it.  It's only in the context of Bug#36269 that I
resurrected it - with all its inadequacies.

 >> @@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 >>         }
 >>       }
 >>     /* Try generating a mouse motion event.  */
 >> -  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
 >> +  else if (some_mouse_moved ())
 >
 > Can't we have mouse motion events outside track-mouse?

Not to my knowledge.  In either case, I wouldn't want to change
anything in this regard here.

 > There's too much of whitespace changes in the rest of the patch,
 > making it very hard to review.  Can you show the patch without
 > whitespace differences?

I attach a patch which re-adds some extraneous braces to w32term.c.
If you want me to restore more of the old code, please tell me.

Also, I do not intend to push the changes until someone tells me that
they work.  I neither use the mouse to drop nor mouse avoidance mode
and so have never given it any serious testing.

Thanks, martin

[-- Attachment #2: track-mouse-with-braces.diff --]
[-- Type: text/plain, Size: 25044 bytes --]

diff --git a/lisp/avoid.el b/lisp/avoid.el
index 7d69fa2a24..43e5062b76 100644
--- a/lisp/avoid.el
+++ b/lisp/avoid.el
@@ -327,6 +327,9 @@ mouse-avoidance-ignore-p
         executing-kbd-macro	       ; don't check inside macro
 	(null (cadr mp))	       ; don't move unless in an Emacs frame
 	(not (eq (car mp) (selected-frame)))
+        ;; Don't interfere with ongoing `mouse-drag-and-drop-region'
+        ;; (Bug#36269).
+        (eq track-mouse 'dropping)
 	;; Don't do anything if last event was a mouse event.
 	;; FIXME: this code fails in the case where the mouse was moved
 	;; since the last key-press but without generating any event.
diff --git a/lisp/mouse.el b/lisp/mouse.el
index 4a532a15e5..e947e16d47 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1296,7 +1296,7 @@ mouse-drag-track
      t (lambda ()
          (setq track-mouse old-track-mouse)
          (setq auto-hscroll-mode auto-hscroll-mode-saved)
-          (deactivate-mark)
+         (deactivate-mark)
          (pop-mark)))))
 
 (defun mouse--drag-set-mark-and-point (start click click-count)
@@ -2467,12 +2467,13 @@ mouse-drag-and-drop-region
 
     (ignore-errors
       (track-mouse
+        (setq track-mouse 'dropping)
         ;; 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)))
+                     (memq (car event) '(select-window switch-frame))))
           ;; Obtain the dragged text in region.  When the loop was
           ;; skipped, value-selection remains nil.
           (unless value-selection
diff --git a/src/dispnew.c b/src/dispnew.c
index 0131b63767..799ef2beae 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3402,9 +3402,9 @@ update_window (struct window *w, bool force_p)
   if (!force_p)
     detect_input_pending_ignore_squeezables ();
 
-  /* If forced to complete the update, or if no input is pending, do
-     the update.  */
-  if (force_p || !input_pending || !NILP (do_mouse_tracking))
+  /* If forced to complete the update, no input is pending, or we are
+     tracking the mouse, do the update.  */
+  if (force_p || !input_pending || !NILP (track_mouse))
     {
       struct glyph_row *row, *end;
       struct glyph_row *mode_line_row;
diff --git a/src/keyboard.c b/src/keyboard.c
index b86ad03851..765b6e85c1 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1159,14 +1159,14 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0,
   user_error ("No recursive edit is in progress");
 }
 \f
-/* Restore mouse tracking enablement.  See Ftrack_mouse for the only use
-   of this function.  */
+/* Restore mouse tracking enablement.  See Finternal_track_mouse for
+   the only use of this function.  */
 
 static void
-tracking_off (Lisp_Object old_value)
+tracking_off (Lisp_Object old_track_mouse)
 {
-  do_mouse_tracking = old_value;
-  if (NILP (old_value))
+  track_mouse = old_track_mouse;
+  if (NILP (old_track_mouse))
     {
       /* Redisplay may have been preempted because there was input
 	 available, and it assumes it will be called again after the
@@ -1181,24 +1181,24 @@ tracking_off (Lisp_Object old_value)
     }
 }
 
-DEFUN ("internal--track-mouse", Ftrack_mouse, Strack_mouse, 1, 1, 0,
+DEFUN ("internal--track-mouse", Finternal_track_mouse, Sinternal_track_mouse,
+       1, 1, 0,
        doc: /* Call BODYFUN with mouse movement events enabled.  */)
   (Lisp_Object bodyfun)
 {
   ptrdiff_t count = SPECPDL_INDEX ();
   Lisp_Object val;
 
-  record_unwind_protect (tracking_off, do_mouse_tracking);
+  record_unwind_protect (tracking_off, track_mouse);
 
-  do_mouse_tracking = Qt;
+  track_mouse = Qt;
 
   val = call0 (bodyfun);
   return unbind_to (count, val);
 }
 
-/* If mouse has moved on some frame, return one of those frames.
-
-   Return 0 otherwise.
+/* If mouse has moved on some frame and we are tracking the mouse,
+   return one of those frames.  Return NULL otherwise.
 
    If ignore_mouse_drag_p is non-zero, ignore (implicit) mouse movement
    after resizing the tool-bar window.  */
@@ -1210,11 +1210,8 @@ some_mouse_moved (void)
 {
   Lisp_Object tail, frame;
 
-  if (ignore_mouse_drag_p)
-    {
-      /* ignore_mouse_drag_p = false; */
-      return 0;
-    }
+  if (NILP (track_mouse) || ignore_mouse_drag_p)
+    return NULL;
 
   FOR_EACH_FRAME (tail, frame)
     {
@@ -1222,7 +1219,7 @@ some_mouse_moved (void)
 	return XFRAME (frame);
     }
 
-  return 0;
+  return NULL;
 }
 
 \f
@@ -2071,7 +2068,8 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object,
 	 This causes trouble if we are trying to read a mouse motion
 	 event (i.e., if we are inside a `track-mouse' form), so we
 	 restore the mouse_moved flag.  */
-      struct frame *f = NILP (do_mouse_tracking) ? NULL : some_mouse_moved ();
+      struct frame *f = some_mouse_moved ();
+
       help = call1 (Qmouse_fixup_help_message, help);
       if (f)
 	f->mouse_moved = true;
@@ -3403,8 +3401,7 @@ readable_events (int flags)
 	return 1;
     }
 
-  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
-      && !NILP (do_mouse_tracking) && some_mouse_moved ())
+  if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES) && some_mouse_moved ())
     return 1;
   if (single_kboard)
     {
@@ -3786,7 +3783,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 
       if (kbd_fetch_ptr != kbd_store_ptr)
 	break;
-      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+      if (some_mouse_moved ())
 	break;
 
       /* If the quit flag is set, then read_char will return
@@ -3802,7 +3799,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #endif
       if (kbd_fetch_ptr != kbd_store_ptr)
 	break;
-      if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+      if (some_mouse_moved ())
 	break;
       if (end_time)
 	{
@@ -3941,8 +3938,9 @@ kbd_buffer_get_event (KBOARD **kbp,
         break;
       default:
 	{
-	  /* If this event is on a different frame, return a switch-frame this
-	     time, and leave the event in the queue for next time.  */
+	  /* If this event is on a different frame, return a
+	     switch-frame this time, and leave the event in the queue
+	     for next time.  */
 	  Lisp_Object frame;
 	  Lisp_Object focus;
 
@@ -3956,14 +3954,13 @@ kbd_buffer_get_event (KBOARD **kbp,
 	  if (! NILP (focus))
 	    frame = focus;
 
-	  if (! EQ (frame, internal_last_event_frame)
+	  if (!EQ (frame, internal_last_event_frame)
 	      && !EQ (frame, selected_frame))
 	    obj = make_lispy_switch_frame (frame);
 	  internal_last_event_frame = frame;
 
 	  /* If we didn't decide to make a switch-frame event, go ahead
 	     and build a real event from the queue entry.  */
-
 	  if (NILP (obj))
 	    {
 	      obj = make_lispy_event (&event->ie);
@@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       }
     }
   /* Try generating a mouse motion event.  */
-  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+  else if (some_mouse_moved ())
     {
       struct frame *f = some_mouse_moved ();
       Lisp_Object bar_window;
@@ -4027,7 +4024,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 	  if (NILP (frame))
 	    XSETFRAME (frame, f);
 
-	  if (! EQ (frame, internal_last_event_frame)
+	  if (!EQ (frame, internal_last_event_frame)
 	      && !EQ (frame, selected_frame))
 	    obj = make_lispy_switch_frame (frame);
 	  internal_last_event_frame = frame;
@@ -10935,7 +10932,7 @@ init_keyboard (void)
   recent_keys_index = 0;
   kbd_fetch_ptr = kbd_buffer;
   kbd_store_ptr = kbd_buffer;
-  do_mouse_tracking = Qnil;
+  track_mouse = Qnil;
   input_pending = false;
   interrupt_input_blocked = 0;
   pending_signals = false;
@@ -11297,7 +11294,7 @@ syms_of_keyboard (void)
   defsubr (&Sread_key_sequence);
   defsubr (&Sread_key_sequence_vector);
   defsubr (&Srecursive_edit);
-  defsubr (&Strack_mouse);
+  defsubr (&Sinternal_track_mouse);
   defsubr (&Sinput_pending_p);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
@@ -11642,8 +11639,15 @@ and the minor mode maps regardless of `overriding-local-map'.  */);
 	       doc: /* Keymap defining bindings for special events to execute at low level.  */);
   Vspecial_event_map = list1 (Qkeymap);
 
-  DEFVAR_LISP ("track-mouse", do_mouse_tracking,
-	       doc: /* Non-nil means generate motion events for mouse motion.  */);
+  DEFVAR_LISP ("track-mouse", track_mouse,
+	       doc: /* Non-nil means generate motion events for mouse motion.
+The special values `dragging' and `dropping' assert that the mouse
+cursor retains its appearance during mouse motion.  Any non-nil value
+but `dropping' asserts that motion events always relate to the frame
+where the the mouse movement started.  The value `dropping' asserts
+that motion events relate to the frame where the mouse cursor is seen
+when generating the event.  If there's no such frame, such motion
+events relate to the frame where the mouse movement started.  */);
 
   DEFVAR_KBOARD ("system-key-alist", Vsystem_key_alist,
 		 doc: /* Alist of system-specific X windows key symbols.
diff --git a/src/nsterm.m b/src/nsterm.m
index 02331826d9..fb2e55929e 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2480,7 +2480,11 @@ so some key presses (TAB) are swallowed by the system.  */
       XFRAME (frame)->mouse_moved = 0;
 
   dpyinfo->last_mouse_scroll_bar = nil;
+  f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame : SELECTED_FRAME ();
   if (dpyinfo->last_mouse_frame
+      /* While dropping, use the last mouse frame only if there is no
+	 currently focused frame.  */
+      && (!EQ (track_mouse, Qdropping) || !f)
       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
     f = dpyinfo->last_mouse_frame;
   else
diff --git a/src/term.c b/src/term.c
index b058d8bdad..a88d47f923 100644
--- a/src/term.c
+++ b/src/term.c
@@ -3033,18 +3033,18 @@ read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
       bool usable_input = 1;
       mi_result st = MI_CONTINUE;
       struct tty_display_info *tty = FRAME_TTY (sf);
-      Lisp_Object saved_mouse_tracking = do_mouse_tracking;
+      Lisp_Object old_track_mouse = track_mouse;
 
       /* Signal the keyboard reading routines we are displaying a menu
 	 on this terminal.  */
       tty->showing_menu = 1;
       /* We want mouse movements be reported by read_menu_command.  */
-      do_mouse_tracking = Qt;
+      track_mouse = Qt;
       do {
 	cmd = read_menu_command ();
       } while (NILP (cmd));
       tty->showing_menu = 0;
-      do_mouse_tracking = saved_mouse_tracking;
+      track_mouse = old_track_mouse;
 
       if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
 	  /* If some input switched frames under our feet, exit the
diff --git a/src/w32fns.c b/src/w32fns.c
index acd9c80528..a2a88b2588 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -4586,7 +4586,8 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	if (button_state & this)
 	  return 0;
 
-	if (button_state == 0)
+	/* Don't capture mouse when dropping.  */
+	if (button_state == 0 && !EQ (track_mouse, Qdropping))
 	  SetCapture (hwnd);
 
 	button_state |= this;
@@ -4707,8 +4708,11 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 
 	if (parse_button (msg, HIWORD (wParam), &button, &up))
 	  {
-	    if (up) ReleaseCapture ();
-	    else SetCapture (hwnd);
+	    if (up)
+	      ReleaseCapture ();
+	    /* Don't capture mouse when dropping.  */
+	    else if (!EQ (track_mouse, Qdropping))
+	      SetCapture (hwnd);
 	    button = (button == 0) ? LMOUSE :
 	      ((button == 1) ? MMOUSE  : RMOUSE);
 	    if (up)
@@ -5351,8 +5355,9 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	else if (button_state & RMOUSE)
 	  flags |= TPM_RIGHTBUTTON;
 
-	/* Remember we did a SetCapture on the initial mouse down event,
-	   so for safety, we make sure the capture is canceled now.  */
+	/* We may have done a SetCapture on the initial mouse down
+	   event, so for safety, make sure the capture is canceled
+	   now.  */
 	ReleaseCapture ();
 	button_state = 0;
 
diff --git a/src/w32term.c b/src/w32term.c
index c6e175e7e5..0058b98ed4 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3525,11 +3525,13 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 
       /* Now we have a position on the root; find the innermost window
 	 containing the pointer.  */
+
       {
-	/* If mouse was grabbed on a frame, give coords for that
-	   frame even if the mouse is now outside it.  Otherwise
-	   check for window under mouse on one of our frames.  */
-	if (gui_mouse_grabbed (dpyinfo))
+	/* If mouse was grabbed on a frame and we are not dropping,
+	   give coords for that frame even if the mouse is now outside
+	   it.  Otherwise check for window under mouse on one of our
+	   frames.  */
+	if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
 	  f1 = dpyinfo->last_mouse_frame;
 	else
 	  {
@@ -3555,17 +3557,23 @@ w32_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 	      }
 	  }
 
+	if (!f1 || FRAME_TOOLTIP_P (f1))
+	  /* Don't use a tooltip frame.  */
+	  f1 = ((EQ (track_mouse, Qdropping) && gui_mouse_grabbed (dpyinfo))
+		? dpyinfo->last_mouse_frame
+		: NULL);
+
 	/* If not, is it one of our scroll bars?  */
-	if (! f1)
+	if (!f1)
 	  {
 	    struct scroll_bar *bar
-              = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
+	      = w32_window_to_scroll_bar (WindowFromPoint (pt), 2);
 
 	    if (bar)
 	      f1 = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
 	  }
 
-	if (f1 == 0 && insist > 0)
+	if (!f1 && insist > 0)
 	  f1 = SELECTED_FRAME ();
 
 	if (f1)
@@ -4667,6 +4675,37 @@ static short temp_buffer[100];
 /* Temporarily store lead byte of DBCS input sequences.  */
 static char dbcs_lead = 0;
 
+/**
+  mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
+  for DPYINFO, return the frame where the mouse was seen last.  If
+  there's no such frame, return the frame according to WDESC.  When
+  dropping, return the frame according to WDESC.  If there's no such
+  frame and the mouse was grabbed for DPYINFO, return the frame where
+  the mouse was seen last.  In either case, never return a tooltip
+  frame.  */
+static struct frame *
+mouse_or_wdesc_frame (struct w32_display_info *dpyinfo, HWND wdesc)
+{
+  struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
+			? dpyinfo->last_mouse_frame
+			: NULL);
+
+  if (lm_f && !EQ (track_mouse, Qdropping))
+    return lm_f;
+  else
+    {
+      struct frame *w_f = w32_window_to_frame (dpyinfo, wdesc);
+
+      /* Do not return a tooltip frame.  */
+      if (!w_f || FRAME_TOOLTIP_P (w_f))
+	return EQ (track_mouse, Qdropping) ? lm_f : NULL;
+      else
+	/* When dropping it would be probably nice to raise w_f
+	   here.  */
+	return w_f;
+    }
+}
+
 /* Read events coming from the W32 shell.
    This routine is called by the SIGIO handler.
    We return as soon as there are no more events to be read.
@@ -4940,15 +4979,13 @@ w32_read_socket (struct terminal *terminal,
           previous_help_echo_string = help_echo_string;
 	  help_echo_string = Qnil;
 
-	  f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-	       : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
 	  if (hlinfo->mouse_face_hidden)
 	    {
 	      hlinfo->mouse_face_hidden = false;
 	      clear_mouse_face (hlinfo);
 	    }
 
+	  f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	  if (f)
 	    {
 	      /* Maybe generate SELECT_WINDOW_EVENTs for
@@ -5020,9 +5057,7 @@ w32_read_socket (struct terminal *terminal,
 	    int button = 0;
 	    int up = 0;
 
-	    f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-		 : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
+	    f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	    if (f)
 	      {
                 w32_construct_mouse_click (&inev, &msg, f);
@@ -5081,9 +5116,7 @@ w32_read_socket (struct terminal *terminal,
 	case WM_MOUSEWHEEL:
         case WM_MOUSEHWHEEL:
 	  {
-	    f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-		 : w32_window_to_frame (dpyinfo, msg.msg.hwnd));
-
+	    f = mouse_or_wdesc_frame (dpyinfo, msg.msg.hwnd);
 	    if (f)
 	      {
 		if (!dpyinfo->w32_focus_frame
@@ -5439,6 +5472,7 @@ w32_read_socket (struct terminal *terminal,
 	      if (any_help_event_p)
 		do_help = -1;
 	    }
+
 	  break;
 
 	case WM_SETFOCUS:
diff --git a/src/xdisp.c b/src/xdisp.c
index 1bb5f5e0f2..7338d2b7d4 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -17289,7 +17289,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 	 the mouse, resulting in an unwanted mouse-movement rather
 	 than a simple mouse-click.  */
       if (!w->start_at_line_beg
-	  && NILP (do_mouse_tracking)
+	  && NILP (track_mouse)
       	  && CHARPOS (startp) > BEGV
 	  && CHARPOS (startp) > BEG + beg_unchanged
 	  && CHARPOS (startp) <= Z - end_unchanged
@@ -30279,7 +30279,7 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw)
 
 #ifdef HAVE_WINDOW_SYSTEM
   /* Change the mouse cursor.  */
-  if (FRAME_WINDOW_P (f) && NILP (do_mouse_tracking))
+  if (FRAME_WINDOW_P (f) && NILP (track_mouse))
     {
 #ifndef HAVE_EXT_TOOL_BAR
       if (draw == DRAW_NORMAL_TEXT
@@ -31226,7 +31226,7 @@ define_frame_cursor1 (struct frame *f, Emacs_Cursor cursor, Lisp_Object pointer)
     return;
 
   /* Do not change cursor shape while dragging mouse.  */
-  if (EQ (do_mouse_tracking, Qdragging))
+  if (EQ (track_mouse, Qdragging) || EQ (track_mouse, Qdropping))
     return;
 
   if (!NILP (pointer))
@@ -32956,6 +32956,7 @@ be let-bound around code that needs to disable messages temporarily. */);
   /* also Qtext */
 
   DEFSYM (Qdragging, "dragging");
+  DEFSYM (Qdropping, "dropping");
 
   DEFSYM (Qinhibit_free_realized_faces, "inhibit-free-realized-faces");
 
diff --git a/src/xterm.c b/src/xterm.c
index c96aa74a7a..97d14f7d45 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5167,20 +5167,15 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
       /* Figure out which root window we're on.  */
       XQueryPointer (FRAME_X_DISPLAY (*fp),
 		     DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
-
 		     /* The root window which contains the pointer.  */
 		     &root,
-
 		     /* Trash which we can't trust if the pointer is on
 			a different screen.  */
 		     &dummy_window,
-
 		     /* The position on that root window.  */
 		     &root_x, &root_y,
-
 		     /* More trash we can't trust.  */
 		     &dummy, &dummy,
-
 		     /* Modifier keys and pointer buttons, about which
 			we don't care.  */
 		     (unsigned int *) &dummy);
@@ -5203,21 +5198,17 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 
 	x_catch_errors (FRAME_X_DISPLAY (*fp));
 
-	if (gui_mouse_grabbed (dpyinfo))
+	if (gui_mouse_grabbed (dpyinfo) && !EQ (track_mouse, Qdropping))
 	  {
 	    /* If mouse was grabbed on a frame, give coords for that frame
 	       even if the mouse is now outside it.  */
 	    XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
-
 				   /* From-window.  */
 				   root,
-
 				   /* To-window.  */
 				   FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
-
 				   /* From-position, to-position.  */
 				   root_x, root_y, &win_x, &win_y,
-
 				   /* Child of win.  */
 				   &child);
 	    f1 = dpyinfo->last_mouse_frame;
@@ -5227,16 +5218,12 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 	    while (true)
 	      {
 		XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
-
 				       /* From-window, to-window.  */
 				       root, win,
-
 				       /* From-position, to-position.  */
 				       root_x, root_y, &win_x, &win_y,
-
 				       /* Child of win.  */
 				       &child);
-
 		if (child == None || child == win)
 		  {
 #ifdef USE_GTK
@@ -5299,13 +5286,35 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 #endif /* USE_X_TOOLKIT */
 	  }
 
+	if ((!f1 || FRAME_TOOLTIP_P (f1))
+	    && EQ (track_mouse, Qdropping)
+	    && gui_mouse_grabbed (dpyinfo))
+	  {
+	    /* When dropping then if we didn't get a frame or only a
+	       tooltip frame and the mouse was grabbed on a frame,
+	       give coords for that frame even if the mouse is now
+	       outside it.  */
+	    XTranslateCoordinates (FRAME_X_DISPLAY (*fp),
+				   /* From-window.  */
+				   root,
+				   /* To-window.  */
+				   FRAME_X_WINDOW (dpyinfo->last_mouse_frame),
+				   /* From-position, to-position.  */
+				   root_x, root_y, &win_x, &win_y,
+				   /* Child of win.  */
+				   &child);
+	    f1 = dpyinfo->last_mouse_frame;
+	  }
+	else if (f1 && FRAME_TOOLTIP_P (f1))
+	  f1 = NULL;
+
 	if (x_had_errors_p (FRAME_X_DISPLAY (*fp)))
-	  f1 = 0;
+	  f1 = NULL;
 
 	x_uncatch_errors_after_check ();
 
 	/* If not, is it one of our scroll bars?  */
-	if (! f1)
+	if (!f1)
 	  {
 	    struct scroll_bar *bar;
 
@@ -5319,7 +5328,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
 	      }
 	  }
 
-	if (f1 == 0 && insist > 0)
+	if (!f1 && insist > 0)
 	  f1 = SELECTED_FRAME ();
 
 	if (f1)
@@ -7788,6 +7797,37 @@ flush_dirty_back_buffers (void)
   unblock_input ();
 }
 
+/**
+  mouse_or_wdesc_frame: When not dropping and the mouse was grabbed
+  for DPYINFO, return the frame where the mouse was seen last.  If
+  there's no such frame, return the frame according to WDESC.  When
+  dropping, return the frame according to WDESC.  If there's no such
+  frame and the mouse was grabbed for DPYINFO, return the frame where
+  the mouse was seen last.  In either case, never return a tooltip
+  frame.  */
+static struct frame *
+mouse_or_wdesc_frame (struct x_display_info *dpyinfo, int wdesc)
+{
+  struct frame *lm_f = (gui_mouse_grabbed (dpyinfo)
+			? dpyinfo->last_mouse_frame
+			: NULL);
+
+  if (lm_f && !EQ (track_mouse, Qdropping))
+    return lm_f;
+  else
+    {
+      struct frame *w_f = x_window_to_frame (dpyinfo, wdesc);
+
+      /* Do not return a tooltip frame.  */
+      if (!w_f || FRAME_TOOLTIP_P (w_f))
+	return EQ (track_mouse, Qdropping) ? lm_f : NULL;
+      else
+	/* When dropping it would be probably nice to raise w_f
+	   here.  */
+	return w_f;
+    }
+}
+
 /* Handles the XEvent EVENT on display DPYINFO.
 
    *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -8720,15 +8760,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         previous_help_echo_string = help_echo_string;
         help_echo_string = Qnil;
 
-	f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
-	     : x_window_to_frame (dpyinfo, event->xmotion.window));
-
-        if (hlinfo->mouse_face_hidden)
+	if (hlinfo->mouse_face_hidden)
           {
             hlinfo->mouse_face_hidden = false;
             clear_mouse_face (hlinfo);
           }
 
+	f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
+
 #ifdef USE_GTK
         if (f && xg_event_is_for_scrollbar (f, event))
           f = 0;
@@ -8970,33 +9009,27 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 	dpyinfo->last_mouse_glyph_frame = NULL;
 	x_display_set_last_user_time (dpyinfo, event->xbutton.time);
 
-	if (gui_mouse_grabbed (dpyinfo))
-	  f = dpyinfo->last_mouse_frame;
-	else
+	f = mouse_or_wdesc_frame (dpyinfo, event->xmotion.window);
+	if (f && event->xbutton.type == ButtonPress
+	    && !popup_activated ()
+	    && !x_window_to_scroll_bar (event->xbutton.display,
+					event->xbutton.window, 2)
+	    && !FRAME_NO_ACCEPT_FOCUS (f))
 	  {
-	    f = x_window_to_frame (dpyinfo, event->xbutton.window);
+	    /* When clicking into a child frame or when clicking
+	       into a parent frame with the child frame selected and
+	       `no-accept-focus' is not set, select the clicked
+	       frame.  */
+	    struct frame *hf = dpyinfo->highlight_frame;
 
-	    if (f && event->xbutton.type == ButtonPress
-		&& !popup_activated ()
-		&& !x_window_to_scroll_bar (event->xbutton.display,
-					    event->xbutton.window, 2)
-		&& !FRAME_NO_ACCEPT_FOCUS (f))
+	    if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
 	      {
-		/* When clicking into a child frame or when clicking
-		   into a parent frame with the child frame selected and
-		   `no-accept-focus' is not set, select the clicked
-		   frame.  */
-		struct frame *hf = dpyinfo->highlight_frame;
-
-		if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
-		  {
-		    block_input ();
-		    XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
-				    RevertToParent, CurrentTime);
-		    if (FRAME_PARENT_FRAME (f))
-		      XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
-		    unblock_input ();
-		  }
+		block_input ();
+		XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+				RevertToParent, CurrentTime);
+		if (FRAME_PARENT_FRAME (f))
+		  XRaiseWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f));
+		unblock_input ();
 	      }
 	  }
 


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

* bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-07-28  7:34     ` martin rudalics
@ 2019-07-29 23:21       ` Robert Weiner
  2019-07-30  7:00         ` bug#36269: " martin rudalics
  2019-08-03 11:25       ` Eli Zaretskii
  1 sibling, 1 reply; 33+ messages in thread
From: Robert Weiner @ 2019-07-29 23:21 UTC (permalink / raw)
  To: martin rudalics; +Cc: scotto, 28620, 36269

Martin:

I just want to say that this is an exciting fix and thank you for working on it.  I don’t have much time these days but will try to test it next weekend.  I use do use MacOS sometimes, so I can test there.

-- Bob

> On Jul 28, 2019, at 3:34 AM, martin rudalics <rudalics@gmx.at> wrote:
> 
> > Thanks, a few minor comments below.
> 
> Thanks for the comments.  I hopefully applied all changes you
> proposed.
> 
> Please keep in mind that I wrote the code almost two years ago and
> then forgot about it.  It's only in the context of Bug#36269 that I
> resurrected it - with all its inadequacies.
> 
> >> @@ -3995,7 +3992,7 @@ kbd_buffer_get_event (KBOARD **kbp,
> >>         }
> >>       }
> >>     /* Try generating a mouse motion event.  */
> >> -  else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
> >> +  else if (some_mouse_moved ())
> >
> > Can't we have mouse motion events outside track-mouse?
> 
> Not to my knowledge.  In either case, I wouldn't want to change
> anything in this regard here.
> 
> > There's too much of whitespace changes in the rest of the patch,
> > making it very hard to review.  Can you show the patch without
> > whitespace differences?
> 
> I attach a patch which re-adds some extraneous braces to w32term.c.
> If you want me to restore more of the old code, please tell me.
> 
> Also, I do not intend to push the changes until someone tells me that
> they work.  I neither use the mouse to drop nor mouse avoidance mode
> and so have never given it any serious testing.
> 
> Thanks, martin
> <track-mouse-with-braces.diff>





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

* bug#36269: bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-07-29 23:21       ` Robert Weiner
@ 2019-07-30  7:00         ` martin rudalics
  0 siblings, 0 replies; 33+ messages in thread
From: martin rudalics @ 2019-07-30  7:00 UTC (permalink / raw)
  To: Robert Weiner; +Cc: scotto, 28620, 36269

 > I don’t have much time these days but will try to test it next
 > weekend.  I use do use MacOS sometimes, so I can test there.

Your original report just turned two years old so there really is
no hurry ...

Thanks in advance, martin






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

* bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-07-28  7:34     ` martin rudalics
  2019-07-29 23:21       ` Robert Weiner
@ 2019-08-03 11:25       ` Eli Zaretskii
  2019-08-04  7:59         ` martin rudalics
  1 sibling, 1 reply; 33+ messages in thread
From: Eli Zaretskii @ 2019-08-03 11:25 UTC (permalink / raw)
  To: martin rudalics; +Cc: rswgnu, scotto, 28620, 36269

> Cc: rswgnu@gmail.com, 28620@debbugs.gnu.org, 36269@debbugs.gnu.org,
>  scotto@sharpleaf.org
> From: martin rudalics <rudalics@gmx.at>
> Date: Sun, 28 Jul 2019 09:34:00 +0200
> 
>  > There's too much of whitespace changes in the rest of the patch,
>  > making it very hard to review.  Can you show the patch without
>  > whitespace differences?
> 
> I attach a patch which re-adds some extraneous braces to w32term.c.

Thanks, that helped a lot.

> Also, I do not intend to push the changes until someone tells me that
> they work.  I neither use the mouse to drop nor mouse avoidance mode
> and so have never given it any serious testing.

I think you should push this to master, and we will have enough time
before the release to see if there are any problems with it.

Thanks.





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

* bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-08-03 11:25       ` Eli Zaretskii
@ 2019-08-04  7:59         ` martin rudalics
  2020-08-18 11:31           ` bug#28620: bug#36269: " Stefan Kangas
  0 siblings, 1 reply; 33+ messages in thread
From: martin rudalics @ 2019-08-04  7:59 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rswgnu, scotto, 28620, 36269

 > I think you should push this to master, and we will have enough time
 > before the release to see if there are any problems with it.

Done.  Let's see what it breaks.

martin





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

* bug#28620: bug#36269: bug#28620: Mouse drag event records wrong window for release when crossing frames
  2019-08-04  7:59         ` martin rudalics
@ 2020-08-18 11:31           ` Stefan Kangas
  2020-08-18 12:15             ` Eli Zaretskii
  0 siblings, 1 reply; 33+ messages in thread
From: Stefan Kangas @ 2020-08-18 11:31 UTC (permalink / raw)
  To: martin rudalics; +Cc: rswgnu, scotto, 28620, 36269

martin rudalics <rudalics@gmx.at> writes:

>> I think you should push this to master, and we will have enough time
>> before the release to see if there are any problems with it.
>
> Done.  Let's see what it breaks.

From skimming the thread, the patch here was pushed and there doesn't
seem to me that there is anything more to do here.

Should this bug be closed?

Best regards,
Stefan Kangas





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

* bug#36269: bug#28620: Mouse drag event records wrong window for release when crossing frames
  2020-08-18 11:31           ` bug#28620: bug#36269: " Stefan Kangas
@ 2020-08-18 12:15             ` Eli Zaretskii
  0 siblings, 0 replies; 33+ messages in thread
From: Eli Zaretskii @ 2020-08-18 12:15 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: 28620-done, rswgnu, scotto, 36269-done

> From: Stefan Kangas <stefan@marxist.se>
> Date: Tue, 18 Aug 2020 11:31:30 +0000
> Cc: Eli Zaretskii <eliz@gnu.org>, rswgnu@gmail.com, scotto@sharpleaf.org, 
> 	28620@debbugs.gnu.org, 36269@debbugs.gnu.org
> 
> martin rudalics <rudalics@gmx.at> writes:
> 
> >> I think you should push this to master, and we will have enough time
> >> before the release to see if there are any problems with it.
> >
> > Done.  Let's see what it breaks.
> 
> >From skimming the thread, the patch here was pushed and there doesn't
> seem to me that there is anything more to do here.
> 
> Should this bug be closed?

It should be; done.

Thanks.





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2019-06-27 12:27         ` Robert Weiner
@ 2020-08-24 13:28           ` Lars Ingebrigtsen
  2020-08-24 13:29           ` Lars Ingebrigtsen
  1 sibling, 0 replies; 33+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-24 13:28 UTC (permalink / raw)
  To: Robert Weiner; +Cc: 28621, Robert Weiner

Robert Weiner <rswgnu@gmail.com> writes:

> On Jun 26, 2019, at 10:20 PM, Robert Weiner <rswgnu@gmail.com> wrote:
>
>  I think all my changes are in the first message here.  Lars, can you see about
>  integrating from there?  Thanks.
>
> Plus, this message now that I have re-read the thread.  I think the
> main issue was just documenting the changes in NEWS, Changes, the
> manuals, etc.  I have been using these patches for all this time now
> with Hyperbole’s cross-frame drags on multiple platforms under Emacs
> 26 without incident.  It would be great to see this moved forward.  —
> Bob

Can you respin the patch, including the changes to the manuals etc?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2019-06-27 12:27         ` Robert Weiner
  2020-08-24 13:28           ` Lars Ingebrigtsen
@ 2020-08-24 13:29           ` Lars Ingebrigtsen
  2020-10-11  2:06             ` Lars Ingebrigtsen
  1 sibling, 1 reply; 33+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-24 13:29 UTC (permalink / raw)
  To: Robert Weiner; +Cc: 28621, Robert Weiner

(This is the patch itself -- it didn't apply because it was posted as
HTML.)

diff --git a/lisp/subr.el b/lisp/subr.el
index a58a873a33..12d7383600 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1364,7 +1364,7 @@ event-start
 The following accessor functions are used to access the elements
 of the position:
 
-`posn-window': The window the event is in.
+`posn-window': The window or frame of the event end.
 `posn-area': A symbol identifying the area the event occurred in,
 or nil if the event occurred in the text area.
 `posn-point': The buffer position of the event.
@@ -1420,8 +1420,9 @@ posnp
 
 (defsubst posn-window (position)
   "Return the window in POSITION.
-POSITION should be a list of the form returned by the `event-start'
-and `event-end' functions."
+If POSITION is outside the frame where the event was initiated,
+return that frame instead.  POSITION should be a list of the form
+returned by the `event-start' and `event-end' functions."
   (nth 0 position))
 
 (defsubst posn-area (position)
@@ -1448,9 +1449,14 @@ posn-point
 (defun posn-set-point (position)
   "Move point to POSITION.
 Select the corresponding window as well."
-  (if (not (windowp (posn-window position)))
+  (if (framep (posn-window position))
+      (progn
+        (unless (windowp (frame-selected-window (posn-window position)))
+          (error "Position not in text area of window"))
+        (select-window (frame-selected-window (posn-window position))))
+    (unless (windowp (posn-window position))
       (error "Position not in text area of window"))
-  (select-window (posn-window position))
+    (select-window (posn-window position)))
   (if (numberp (posn-point position))
       (goto-char (posn-point position))))
 

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no






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

* bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments
  2020-08-24 13:29           ` Lars Ingebrigtsen
@ 2020-10-11  2:06             ` Lars Ingebrigtsen
  0 siblings, 0 replies; 33+ messages in thread
From: Lars Ingebrigtsen @ 2020-10-11  2:06 UTC (permalink / raw)
  To: Robert Weiner; +Cc: 28621, Robert Weiner

Lars Ingebrigtsen <larsi@gnus.org> writes:

> (This is the patch itself -- it didn't apply because it was posted as
> HTML.)

I've now applied this with the changes suggested by Eli, I think.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





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

end of thread, other threads:[~2020-10-11  2:06 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-27 15:44 bug#28620: Mouse drag event records wrong window for release when crossing frames Robert Weiner
2017-10-03 20:54 ` bug#28620: (mouse-position_ wrong on macOS after mouse-1 click (Was: Interact directly on Emacs bug#28620: mouse drag event records wrong release window) Robert Weiner
2017-10-16 15:57 ` bug#28620: (PARTIAL SOLUTION) Mouse drag event records wrong window for release when crossing frames Bob Weiner
2019-07-27  9:26 ` bug#36269: bug#28620: " martin rudalics
2019-07-27 10:08   ` Eli Zaretskii
2019-07-28  7:34     ` martin rudalics
2019-07-29 23:21       ` Robert Weiner
2019-07-30  7:00         ` bug#36269: " martin rudalics
2019-08-03 11:25       ` Eli Zaretskii
2019-08-04  7:59         ` martin rudalics
2020-08-18 11:31           ` bug#28620: bug#36269: " Stefan Kangas
2020-08-18 12:15             ` Eli Zaretskii
  -- strict thread matches above, loose matches on Subject: below --
2017-09-27 16:01 bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Robert Weiner
2017-09-27 21:34 ` John Wiegley
2017-09-29  8:34 ` martin rudalics
2017-09-29 16:48   ` Robert Weiner
2017-09-29 19:42   ` Eli Zaretskii
2017-09-29 19:41 ` Eli Zaretskii
2017-09-29 20:11   ` Robert Weiner
2017-09-30  8:32     ` martin rudalics
2017-09-30 12:45       ` Robert Weiner
2017-09-30 12:52         ` Robert Weiner
2017-09-30 17:12         ` martin rudalics
2017-09-30 21:56           ` bug#28620: " Robert Weiner
2017-09-30 23:34             ` Robert Weiner
2017-10-16 15:11             ` bug#28620: Emacs bug#28620: (PARTIAL SOLUTION) mouse-position wrong on macOS and Windows 7 after mouse-1 click Bob Weiner
2019-06-24 16:08     ` bug#28621: Proposed patch for doc of posn-window and code of posn-set-point to handle frame arguments Lars Ingebrigtsen
2019-06-27  2:20       ` Robert Weiner
2019-06-27 10:39         ` Lars Ingebrigtsen
2019-06-27 12:27         ` Robert Weiner
2020-08-24 13:28           ` Lars Ingebrigtsen
2020-08-24 13:29           ` Lars Ingebrigtsen
2020-10-11  2:06             ` Lars Ingebrigtsen

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