I now have drags working across frames (after manipulating the drag button release event data to include the proper window and coordinates, though only in Lisp right now).  As shown in the last message, I also have a function that finds the proper Emacs window given some display coordinates.  The only remaining problem seems to be that none of this accounts for external application windows that may be obscuring an Emacs frame.

So if I have 2 frames, f1 and f2, and a Chrome web browser window that is atop f2, then if I drag from f1 into Chrome above f2, my drag release code reports that the release window is in f2 rather than nil, as it should be.  I am on macOS which uses click to focus, so Emacs still gets the release event since Chrome has not been selected with a click.

Is there any way to deal with external window z-order layering such that one can tell within Emacs whether the topmost OS-level window at an absolute mouse position is an Emacs frame or not?

Thanks,

Bob


On Wed, Oct 11, 2017 at 2:49 PM, Robert Weiner <rsw@gnu.org> wrote:
On Wed, Oct 11, 2017 at 1:16 PM, Robert Weiner <rsw@gnu.org> 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))