Subject: bug#28620: Interact directly on Emacs bug#28620: mouse drag event records wrong release window

From: Robert Weiner <[email-masked]>
Date: Wed, 11 Oct 2017 14:49:45 -0400

On Wed, Oct 11, 2017 at 1:16 PM, Robert Weiner <[email-masked]> wrote:

>
> ​Martin wrote:​
>
>> 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.
>> ​​
>>
> ​​

​  Eli wrote:
    ​​
Why cannot you compute the frame at button release using the a
​​
lgorithm
         proposed by Martin, given the mouse position at button release?​

>
>> ​​
>>
> I w
> ​​
> rote:
>   ​
> ​​
> frame-list-z-order is Emacs 26 only; I need something that works with
> older versions.​
> ​​
> ​​
> I'll see if I can make this work under Emacs 26 and then we can
> contemplate a solution that would apply to earlier versions.
> ​​
> Thanks for the reminder.  It does still seem to me that there should be a
> function that takes a mouse position and returns
> ​​
> the top-most Emacs window that the position is in or nil.  I'll work on it.
>
​​
 And now there is such a function.  It was easier than I expected thanks
to Martin's pointers.  Now how can we make this work (replacing
frame-list-z-order) for Emacs versions prior to 26?  -- Bob

(defun window-at-absolute-pixel-position (&optional position)
  "Return the top-most Emacs window at optional POSITION ((X . Y) in
pixels) or mouse position.
If POSITION is not in a window, return nil.  Considers all windows on the
the same terminal
display as the selected frame."
  (interactive)
  (setq position (or position (mouse-absolute-pixel-position)))
  (let* ((top-to-bottom-frames (frame-list-z-order))
(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.
    (setq pos-x (/ (- pos-x left) (frame-char-width in-frame))
  pos-y (/ (- pos-y top) (frame-char-height in-frame))
  window (window-at pos-x pos-y in-frame))
    (if (called-interactively-p 'interactive)
  (message "%s at absolute pixel position %s"
   (or window "No Emacs window") position))
    window))