diff options
| author | Po Lu | 2022-07-15 16:19:41 +0800 |
|---|---|---|
| committer | Po Lu | 2022-07-15 16:19:52 +0800 |
| commit | 200938b95d1b73d03ce758e69a69d4fb198be4e8 (patch) | |
| tree | 16d187bd8747d8bed5dd84c58cef71c7b2d35498 | |
| parent | ffe4a5dac0dbc9fd85064200ed7b46b4ab3b910a (diff) | |
| download | emacs-200938b95d1b73d03ce758e69a69d4fb198be4e8.tar.gz emacs-200938b95d1b73d03ce758e69a69d4fb198be4e8.zip | |
Fix generated drag-and-drop mouse rectangles
* lisp/x-dnd.el (x-dnd-get-drop-width-height): Handle window
width and height correctly. Remove unused parameter.
(x-dnd-after-move-frame): New function.
(move-frame-functions): Add new hook.
(x-dnd-compute-root-window-position): New function.
(x-dnd-get-drop-x-y): Use that instead of `left' and `top'
parameters, which include the title bar.
(x-dnd-handle-xdnd): Update accordingly.
* src/xfns.c (Fx_translate_coordinates): New function.
(syms_of_xfns): New defsym.
| -rw-r--r-- | lisp/x-dnd.el | 48 | ||||
| -rw-r--r-- | src/xfns.c | 88 |
2 files changed, 122 insertions, 14 deletions
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index 92899e7a0c6..b25d2ea3d9d 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el | |||
| @@ -588,6 +588,7 @@ message (format 32) that caused EVENT to be generated." | |||
| 588 | 588 | ||
| 589 | (declare-function x-change-window-property "xfns.c" | 589 | (declare-function x-change-window-property "xfns.c" |
| 590 | (prop value &optional frame type format outer-P window-id)) | 590 | (prop value &optional frame type format outer-P window-id)) |
| 591 | (declare-function x-translate-coordinates "xfns.c") | ||
| 591 | 592 | ||
| 592 | (defun x-dnd-init-xdnd-for-frame (frame) | 593 | (defun x-dnd-init-xdnd-for-frame (frame) |
| 593 | "Set the XdndAware property for FRAME to indicate that we do XDND." | 594 | "Set the XdndAware property for FRAME to indicate that we do XDND." |
| @@ -595,33 +596,53 @@ message (format 32) that caused EVENT to be generated." | |||
| 595 | '(5) ;; The version of XDND we support. | 596 | '(5) ;; The version of XDND we support. |
| 596 | frame "ATOM" 32 t)) | 597 | frame "ATOM" 32 t)) |
| 597 | 598 | ||
| 598 | (defun x-dnd-get-drop-width-height (frame w accept) | 599 | (defun x-dnd-get-drop-width-height (w accept) |
| 599 | "Return the width/height to be sent in a XdndStatus message. | 600 | "Return the width/height to be sent in a XdndStatus message. |
| 600 | FRAME is the frame and W is the window where the drop happened. | 601 | W is the window where the drop happened. |
| 601 | If ACCEPT is nil return 0 (empty rectangle), | 602 | If ACCEPT is nil return 0 (empty rectangle), |
| 602 | otherwise if W is a window, return its width/height, | 603 | otherwise if W is a window, return its width/height, |
| 603 | otherwise return the frame width/height." | 604 | otherwise return the frame width/height." |
| 604 | (if accept | 605 | (if accept |
| 605 | (if (windowp w) ;; w is not a window if dropping on the menu bar, | 606 | (if (windowp w) ;; w is not a window if dropping on the menu bar, |
| 606 | ;; scroll bar or tool bar. | 607 | ;; scroll bar or tool bar. |
| 607 | (let ((edges (window-inside-pixel-edges w))) | 608 | (cons (window-pixel-width) |
| 608 | (cons | 609 | (window-pixel-height)) |
| 609 | (- (nth 2 edges) (nth 0 edges)) ;; right - left | 610 | ;; Don't confine to mouse rect if w is not a window. |
| 610 | (- (nth 3 edges) (nth 1 edges)))) ;; bottom - top | 611 | ;; Otherwise, we won't get position events once the mouse does |
| 611 | (cons (frame-pixel-width frame) | 612 | ;; move into a window. |
| 612 | (frame-pixel-height frame))) | 613 | 0) |
| 613 | 0)) | 614 | 0)) |
| 614 | 615 | ||
| 616 | (defun x-dnd-after-move-frame (frame) | ||
| 617 | "Handle FRAME moving to a different position. | ||
| 618 | Clear any cached root window position." | ||
| 619 | (set-frame-parameter frame 'dnd-root-window-position | ||
| 620 | nil)) | ||
| 621 | |||
| 622 | (add-hook 'move-frame-functions #'x-dnd-after-move-frame) | ||
| 623 | |||
| 624 | (defun x-dnd-compute-root-window-position (frame) | ||
| 625 | "Return the position of FRAME's edit widget relative to the root window. | ||
| 626 | The value is a cons of (X . Y), describing the position of | ||
| 627 | FRAME's edit widget (inner window) relative to the root window of | ||
| 628 | its screen." | ||
| 629 | (or (frame-parameter frame 'dnd-root-window-position) | ||
| 630 | (let* ((result (x-translate-coordinates frame)) | ||
| 631 | (param (cons (car result) (cadr result)))) | ||
| 632 | (unless result | ||
| 633 | (error "Frame isn't on the same screen as its root window")) | ||
| 634 | (prog1 param | ||
| 635 | (set-frame-parameter frame 'dnd-root-window-position param))))) | ||
| 636 | |||
| 615 | (defun x-dnd-get-drop-x-y (frame w) | 637 | (defun x-dnd-get-drop-x-y (frame w) |
| 616 | "Return the x/y coordinates to be sent in a XdndStatus message. | 638 | "Return the x/y coordinates to be sent in a XdndStatus message. |
| 617 | Coordinates are required to be absolute. | 639 | Coordinates are required to be absolute. |
| 618 | FRAME is the frame and W is the window where the drop happened. | 640 | FRAME is the frame and W is the window where the drop happened. |
| 619 | If W is a window, return its absolute coordinates, | 641 | If W is a window, return its absolute coordinates, |
| 620 | otherwise return the frame coordinates." | 642 | otherwise return the frame coordinates." |
| 621 | (let* ((frame-left (or (car-safe (cdr-safe (frame-parameter frame 'left))) | 643 | (let* ((position (x-dnd-compute-root-window-position frame)) |
| 622 | (frame-parameter frame 'left))) | 644 | (frame-left (car position)) |
| 623 | (frame-top (or (car-safe (cdr-safe (frame-parameter frame 'top))) | 645 | (frame-top (cdr position))) |
| 624 | (frame-parameter frame 'top)))) | ||
| 625 | (if (windowp w) | 646 | (if (windowp w) |
| 626 | (let ((edges (window-inside-pixel-edges w))) | 647 | (let ((edges (window-inside-pixel-edges w))) |
| 627 | (cons | 648 | (cons |
| @@ -700,8 +721,7 @@ FORMAT is 32 (not used). MESSAGE is the data part of an XClientMessageEvent." | |||
| 700 | ;; widget bounds". | 721 | ;; widget bounds". |
| 701 | (+ (if dnd-indicate-insertion-point 2 0) accept) | 722 | (+ (if dnd-indicate-insertion-point 2 0) accept) |
| 702 | (x-dnd-get-drop-x-y frame window) | 723 | (x-dnd-get-drop-x-y frame window) |
| 703 | (x-dnd-get-drop-width-height | 724 | (x-dnd-get-drop-width-height window (eq accept 1)) |
| 704 | frame window (eq accept 1)) | ||
| 705 | ;; The no-toolkit Emacs build can actually | 725 | ;; The no-toolkit Emacs build can actually |
| 706 | ;; receive drops from programs that speak | 726 | ;; receive drops from programs that speak |
| 707 | ;; versions of XDND earlier than 3 (such as | 727 | ;; versions of XDND earlier than 3 (such as |
diff --git a/src/xfns.c b/src/xfns.c index 748ea10c952..1a65698f490 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -7833,6 +7833,92 @@ Otherwise, the return value is a vector with the following fields: | |||
| 7833 | return prop_attr; | 7833 | return prop_attr; |
| 7834 | } | 7834 | } |
| 7835 | 7835 | ||
| 7836 | |||
| 7837 | /*********************************************************************** | ||
| 7838 | Coordinate management | ||
| 7839 | ***********************************************************************/ | ||
| 7840 | |||
| 7841 | DEFUN ("x-translate-coordinates", Fx_translate_coordinates, | ||
| 7842 | Sx_translate_coordinates, | ||
| 7843 | 1, 5, 0, doc: /* Translate coordinates from FRAME. | ||
| 7844 | Translate the given coordinates SOURCE-X and SOURCE-Y from | ||
| 7845 | SOURCE-WINDOW's coordinate space to that of DEST-WINDOW, on FRAME. | ||
| 7846 | |||
| 7847 | If SOURCE-X and SOURCE-Y are nil, use 0 instead. | ||
| 7848 | |||
| 7849 | FRAME can either be a terminal or a frame. If nil, it defaults to the | ||
| 7850 | selected frame. SOURCE-WINDOW must be an X window ID, 0 (which means | ||
| 7851 | to use the root window), or nil, which means to use FRAME's inner | ||
| 7852 | window. DEST-WINDOW must be another X window ID, or nil (which means | ||
| 7853 | to use the root window). | ||
| 7854 | |||
| 7855 | Return a list of (X Y CHILD) if the given coordinates are on the same | ||
| 7856 | screen, or nil otherwise, where X and Y are the coordinates in | ||
| 7857 | DEST-WINDOW's coordinate space, and CHILD is the window ID of any | ||
| 7858 | mapped child in DEST-WINDOW at those coordinates, or nil if there is | ||
| 7859 | no such window. */) | ||
| 7860 | (Lisp_Object frame, Lisp_Object source_window, | ||
| 7861 | Lisp_Object dest_window, Lisp_Object source_x, | ||
| 7862 | Lisp_Object source_y) | ||
| 7863 | { | ||
| 7864 | struct x_display_info *dpyinfo; | ||
| 7865 | struct frame *source_frame; | ||
| 7866 | int dest_x, dest_y; | ||
| 7867 | Window child_return, src, dest; | ||
| 7868 | Bool rc; | ||
| 7869 | |||
| 7870 | dpyinfo = check_x_display_info (frame); | ||
| 7871 | dest_x = 0; | ||
| 7872 | dest_y = 0; | ||
| 7873 | |||
| 7874 | if (!NILP (source_x)) | ||
| 7875 | { | ||
| 7876 | CHECK_FIXNUM (source_x); | ||
| 7877 | dest_x = XFIXNUM (source_x); | ||
| 7878 | } | ||
| 7879 | |||
| 7880 | if (!NILP (source_y)) | ||
| 7881 | { | ||
| 7882 | CHECK_FIXNUM (source_y); | ||
| 7883 | dest_y = XFIXNUM (source_y); | ||
| 7884 | } | ||
| 7885 | |||
| 7886 | if (!NILP (source_window)) | ||
| 7887 | CONS_TO_INTEGER (source_window, Window, src); | ||
| 7888 | else | ||
| 7889 | { | ||
| 7890 | source_frame = decode_window_system_frame (frame); | ||
| 7891 | src = FRAME_X_WINDOW (source_frame); | ||
| 7892 | } | ||
| 7893 | |||
| 7894 | if (!src) | ||
| 7895 | src = dpyinfo->root_window; | ||
| 7896 | |||
| 7897 | if (!NILP (dest_window)) | ||
| 7898 | CONS_TO_INTEGER (dest_window, Window, dest); | ||
| 7899 | else | ||
| 7900 | dest = dpyinfo->root_window; | ||
| 7901 | |||
| 7902 | block_input (); | ||
| 7903 | x_catch_errors (dpyinfo->display); | ||
| 7904 | rc = XTranslateCoordinates (dpyinfo->display, src, dest, | ||
| 7905 | dest_x, dest_y, &dest_x, &dest_y, | ||
| 7906 | &child_return); | ||
| 7907 | x_check_errors (dpyinfo->display, | ||
| 7908 | "Couldn't translate coordinates: %s"); | ||
| 7909 | x_uncatch_errors_after_check (); | ||
| 7910 | unblock_input (); | ||
| 7911 | |||
| 7912 | if (!rc) | ||
| 7913 | return Qnil; | ||
| 7914 | |||
| 7915 | return list3 (make_int (dest_x), | ||
| 7916 | make_int (dest_y), | ||
| 7917 | (child_return != None | ||
| 7918 | ? make_uint (child_return) | ||
| 7919 | : Qnil)); | ||
| 7920 | } | ||
| 7921 | |||
| 7836 | /*********************************************************************** | 7922 | /*********************************************************************** |
| 7837 | Tool tips | 7923 | Tool tips |
| 7838 | ***********************************************************************/ | 7924 | ***********************************************************************/ |
| @@ -10003,6 +10089,8 @@ eliminated in future versions of Emacs. */); | |||
| 10003 | defsubr (&Sx_double_buffered_p); | 10089 | defsubr (&Sx_double_buffered_p); |
| 10004 | defsubr (&Sx_begin_drag); | 10090 | defsubr (&Sx_begin_drag); |
| 10005 | defsubr (&Sx_display_set_last_user_time); | 10091 | defsubr (&Sx_display_set_last_user_time); |
| 10092 | defsubr (&Sx_translate_coordinates); | ||
| 10093 | |||
| 10006 | tip_timer = Qnil; | 10094 | tip_timer = Qnil; |
| 10007 | staticpro (&tip_timer); | 10095 | staticpro (&tip_timer); |
| 10008 | tip_frame = Qnil; | 10096 | tip_frame = Qnil; |