diff options
| author | Po Lu | 2022-06-29 10:24:14 +0800 |
|---|---|---|
| committer | Po Lu | 2022-06-29 10:24:14 +0800 |
| commit | 0e6516a1f022e18f4e32848331954deb0e850d4e (patch) | |
| tree | aaf82c350a8aee4ea7867587af7a6555ca6804af | |
| parent | 9705609c0ef5e426606300da95fed4bec54923fb (diff) | |
| download | emacs-0e6516a1f022e18f4e32848331954deb0e850d4e.tar.gz emacs-0e6516a1f022e18f4e32848331954deb0e850d4e.zip | |
Fix reported problem with drag-and-drop inside VirtualBox
* lisp/x-dnd.el (x-dnd-handle-old-kde, x-dnd-handle-offix)
(x-dnd-handle-motif): Select window before handling drop, like
on Xdnd.
(x-dnd-convert-to-offix, x-dnd-do-offix-drop)
(x-dnd-handle-unsupported-drop): Accept local selection data and
use that instead.
* src/keyboard.c (kbd_buffer_get_event): Call unsupported drop
function with local selection data as 8th arg.
* src/xselect.c (x_get_local_selection): Accept new arg
`local_value'. All callers changed.
(Fx_get_local_selection): New function.
(syms_of_xselect): Update defsubrs.
* src/xterm.c (x_dnd_lose_ownership): New function.
(x_dnd_begin_drag_and_drop): Unless new variable is true, disown
XdndSelection after returning. This supposedly makes
drag-and-drop from guest to host work in VirtualBox without
causing pointer motion to become choppy afterwards.
(syms_of_xterm): New variable `x_dnd_preserve_selection_data'
and update doc string of `x-dnd-unsupported-drop-function'.
* test/lisp/dnd-tests.el (dnd-tests-begin-text-drag)
(dnd-tests-begin-file-drag, dnd-tests-begin-drag-files): Set new
variable to nil during tests.
| -rw-r--r-- | lisp/x-dnd.el | 41 | ||||
| -rw-r--r-- | src/keyboard.c | 5 | ||||
| -rw-r--r-- | src/xselect.c | 74 | ||||
| -rw-r--r-- | src/xterm.c | 51 | ||||
| -rw-r--r-- | test/lisp/dnd-tests.el | 10 |
5 files changed, 142 insertions, 39 deletions
diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index 22277033f52..5c6d25ba686 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el | |||
| @@ -443,6 +443,8 @@ EVENT, FRAME, WINDOW and DATA mean the same thing they do in | |||
| 443 | ;; Now call the test function to decide what action to perform. | 443 | ;; Now call the test function to decide what action to perform. |
| 444 | (x-dnd-maybe-call-test-function window 'private) | 444 | (x-dnd-maybe-call-test-function window 'private) |
| 445 | (unwind-protect | 445 | (unwind-protect |
| 446 | (when (windowp window) | ||
| 447 | (select-window window)) | ||
| 446 | (x-dnd-drop-data event frame window data | 448 | (x-dnd-drop-data event frame window data |
| 447 | (symbol-name type)) | 449 | (symbol-name type)) |
| 448 | (x-dnd-forget-drop window)))))) | 450 | (x-dnd-forget-drop window)))))) |
| @@ -500,6 +502,8 @@ message (format 32) that caused EVENT to be generated." | |||
| 500 | ;; Now call the test function to decide what action to perform. | 502 | ;; Now call the test function to decide what action to perform. |
| 501 | (x-dnd-maybe-call-test-function window 'private) | 503 | (x-dnd-maybe-call-test-function window 'private) |
| 502 | (unwind-protect | 504 | (unwind-protect |
| 505 | (when (windowp window) | ||
| 506 | (select-window window)) | ||
| 503 | (x-dnd-drop-data event frame window data | 507 | (x-dnd-drop-data event frame window data |
| 504 | (symbol-name type)) | 508 | (symbol-name type)) |
| 505 | (x-dnd-forget-drop window)))) | 509 | (x-dnd-forget-drop window)))) |
| @@ -926,6 +930,8 @@ Return a vector of atoms containing the selection targets." | |||
| 926 | reply))) | 930 | reply))) |
| 927 | 931 | ||
| 928 | ((eq message-type 'XmDROP_START) | 932 | ((eq message-type 'XmDROP_START) |
| 933 | (when (windowp window) | ||
| 934 | (select-window window)) | ||
| 929 | (let* ((x (x-dnd-motif-value-to-list | 935 | (let* ((x (x-dnd-motif-value-to-list |
| 930 | (x-dnd-get-motif-value data 8 2 source-byteorder) | 936 | (x-dnd-get-motif-value data 8 2 source-byteorder) |
| 931 | 2 my-byteorder)) | 937 | 2 my-byteorder)) |
| @@ -1014,19 +1020,22 @@ Return a vector of atoms containing the selection targets." | |||
| 1014 | ;;; Handling drops. | 1020 | ;;; Handling drops. |
| 1015 | 1021 | ||
| 1016 | (defvar x-treat-local-requests-remotely) | 1022 | (defvar x-treat-local-requests-remotely) |
| 1023 | (declare-function x-get-local-selection "xfns.c") | ||
| 1017 | 1024 | ||
| 1018 | (defun x-dnd-convert-to-offix (targets) | 1025 | (defun x-dnd-convert-to-offix (targets local-selection) |
| 1019 | "Convert the contents of `XdndSelection' to OffiX data. | 1026 | "Convert local selection data to OffiX data. |
| 1020 | TARGETS should be the list of targets currently available in | 1027 | TARGETS should be the list of targets currently available in |
| 1021 | `XdndSelection'. Return a list of an OffiX type, and data | 1028 | `XdndSelection'. Return a list of an OffiX type, and data |
| 1022 | suitable for passing to `x-change-window-property', or nil if the | 1029 | suitable for passing to `x-change-window-property', or nil if the |
| 1023 | data could not be converted." | 1030 | data could not be converted. |
| 1031 | LOCAL-SELECTION should be the local selection data describing the | ||
| 1032 | selection data to convert." | ||
| 1024 | (let ((x-treat-local-requests-remotely t) | 1033 | (let ((x-treat-local-requests-remotely t) |
| 1025 | file-name-data string-data) | 1034 | file-name-data string-data) |
| 1026 | (cond | 1035 | (cond |
| 1027 | ((and (member "FILE_NAME" targets) | 1036 | ((and (member "FILE_NAME" targets) |
| 1028 | (setq file-name-data | 1037 | (setq file-name-data |
| 1029 | (gui-get-selection 'XdndSelection 'FILE_NAME))) | 1038 | (x-get-local-selection local-selection 'FILE_NAME))) |
| 1030 | (if (string-match-p "\0" file-name-data) | 1039 | (if (string-match-p "\0" file-name-data) |
| 1031 | ;; This means there are multiple file names in | 1040 | ;; This means there are multiple file names in |
| 1032 | ;; XdndSelection. Convert the file name data to a format | 1041 | ;; XdndSelection. Convert the file name data to a format |
| @@ -1035,19 +1044,23 @@ data could not be converted." | |||
| 1035 | (cons 'DndTypeFile (concat file-name-data "\0")))) | 1044 | (cons 'DndTypeFile (concat file-name-data "\0")))) |
| 1036 | ((and (member "STRING" targets) | 1045 | ((and (member "STRING" targets) |
| 1037 | (setq string-data | 1046 | (setq string-data |
| 1038 | (gui-get-selection 'XdndSelection 'STRING))) | 1047 | (x-get-local-selection local-selection 'STRING))) |
| 1039 | (cons 'DndTypeText (encode-coding-string string-data | 1048 | (cons 'DndTypeText (encode-coding-string string-data |
| 1040 | 'latin-1)))))) | 1049 | 'latin-1)))))) |
| 1041 | 1050 | ||
| 1042 | (defun x-dnd-do-offix-drop (targets x y frame window-id) | 1051 | (defun x-dnd-do-offix-drop (targets x y frame window-id contents) |
| 1043 | "Perform an OffiX drop on WINDOW-ID with the contents of `XdndSelection'. | 1052 | "Perform an OffiX drop on WINDOW-ID with the given selection contents. |
| 1044 | Return non-nil if the drop succeeded, or nil if it did not | 1053 | Return non-nil if the drop succeeded, or nil if it did not |
| 1045 | happen, which can happen if TARGETS didn't contain anything that | 1054 | happen, which can happen if TARGETS didn't contain anything that |
| 1046 | the OffiX protocol can represent. | 1055 | the OffiX protocol can represent. |
| 1047 | 1056 | ||
| 1048 | X and Y are the root window coordinates of the drop. TARGETS is | 1057 | X and Y are the root window coordinates of the drop. TARGETS is |
| 1049 | the list of targets `XdndSelection' can be converted to." | 1058 | the list of targets CONTENTS can be converted to, and CONTENTS is |
| 1050 | (if-let* ((data (x-dnd-convert-to-offix targets)) | 1059 | the local selection data to drop onto the target window. |
| 1060 | |||
| 1061 | FRAME is the frame that will act as a source window for the | ||
| 1062 | drop." | ||
| 1063 | (if-let* ((data (x-dnd-convert-to-offix targets contents)) | ||
| 1051 | (type-id (car (rassq (car data) | 1064 | (type-id (car (rassq (car data) |
| 1052 | x-dnd-offix-id-to-name))) | 1065 | x-dnd-offix-id-to-name))) |
| 1053 | (source-id (string-to-number | 1066 | (source-id (string-to-number |
| @@ -1074,18 +1087,20 @@ the list of targets `XdndSelection' can be converted to." | |||
| 1074 | frame "_DND_PROTOCOL" | 1087 | frame "_DND_PROTOCOL" |
| 1075 | 32 message-data)))) | 1088 | 32 message-data)))) |
| 1076 | 1089 | ||
| 1077 | (defun x-dnd-handle-unsupported-drop (targets x y action window-id frame _time) | 1090 | (defun x-dnd-handle-unsupported-drop (targets x y action window-id frame _time local-selection-data) |
| 1078 | "Return non-nil if the drop described by TARGETS and ACTION should not proceed. | 1091 | "Return non-nil if the drop described by TARGETS and ACTION should not proceed. |
| 1079 | X and Y are the root window coordinates of the drop. | 1092 | X and Y are the root window coordinates of the drop. |
| 1080 | FRAME is the frame the drop originated on. | 1093 | FRAME is the frame the drop originated on. |
| 1081 | WINDOW-ID is the X window the drop should happen to." | 1094 | WINDOW-ID is the X window the drop should happen to. |
| 1095 | LOCAL-SELECTION-DATA is the local selection data of the drop." | ||
| 1082 | (not (and (or (eq action 'XdndActionCopy) | 1096 | (not (and (or (eq action 'XdndActionCopy) |
| 1083 | (eq action 'XdndActionMove)) | 1097 | (eq action 'XdndActionMove)) |
| 1084 | (not (and x-dnd-use-offix-drop | 1098 | (not (and x-dnd-use-offix-drop local-selection-data |
| 1085 | (or (not (eq x-dnd-use-offix-drop 'files)) | 1099 | (or (not (eq x-dnd-use-offix-drop 'files)) |
| 1086 | (member "FILE_NAME" targets)) | 1100 | (member "FILE_NAME" targets)) |
| 1087 | (x-dnd-do-offix-drop targets x | 1101 | (x-dnd-do-offix-drop targets x |
| 1088 | y frame window-id))) | 1102 | y frame window-id |
| 1103 | local-selection-data))) | ||
| 1089 | (or | 1104 | (or |
| 1090 | (member "STRING" targets) | 1105 | (member "STRING" targets) |
| 1091 | (member "UTF8_STRING" targets) | 1106 | (member "UTF8_STRING" targets) |
diff --git a/src/keyboard.c b/src/keyboard.c index e5708c06d93..8b8d348c41a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -4056,12 +4056,13 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4056 | 4056 | ||
| 4057 | if (!NILP (Vx_dnd_unsupported_drop_function)) | 4057 | if (!NILP (Vx_dnd_unsupported_drop_function)) |
| 4058 | { | 4058 | { |
| 4059 | if (!NILP (call7 (Vx_dnd_unsupported_drop_function, | 4059 | if (!NILP (call8 (Vx_dnd_unsupported_drop_function, |
| 4060 | XCAR (XCDR (event->ie.arg)), event->ie.x, | 4060 | XCAR (XCDR (event->ie.arg)), event->ie.x, |
| 4061 | event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), | 4061 | event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), |
| 4062 | make_uint (event->ie.code), | 4062 | make_uint (event->ie.code), |
| 4063 | event->ie.frame_or_window, | 4063 | event->ie.frame_or_window, |
| 4064 | make_int (event->ie.timestamp)))) | 4064 | make_int (event->ie.timestamp), |
| 4065 | Fcopy_sequence (XCAR (event->ie.arg))))) | ||
| 4065 | break; | 4066 | break; |
| 4066 | } | 4067 | } |
| 4067 | 4068 | ||
diff --git a/src/xselect.c b/src/xselect.c index d90916c6b63..a1f590632f8 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -307,18 +307,30 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, | |||
| 307 | This function is used both for remote requests (LOCAL_REQUEST is zero) | 307 | This function is used both for remote requests (LOCAL_REQUEST is zero) |
| 308 | and for local x-get-selection-internal (LOCAL_REQUEST is nonzero). | 308 | and for local x-get-selection-internal (LOCAL_REQUEST is nonzero). |
| 309 | 309 | ||
| 310 | If LOCAL_VALUE is non-nil, use it as the local copy. Also allow | ||
| 311 | quitting in that case, and let DPYINFO be NULL. | ||
| 312 | |||
| 310 | This calls random Lisp code, and may signal or gc. */ | 313 | This calls random Lisp code, and may signal or gc. */ |
| 311 | 314 | ||
| 312 | static Lisp_Object | 315 | static Lisp_Object |
| 313 | x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, | 316 | x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, |
| 314 | bool local_request, struct x_display_info *dpyinfo) | 317 | bool local_request, struct x_display_info *dpyinfo, |
| 318 | Lisp_Object local_value) | ||
| 315 | { | 319 | { |
| 316 | Lisp_Object local_value, tem; | 320 | Lisp_Object tem; |
| 317 | Lisp_Object handler_fn, value, check; | 321 | Lisp_Object handler_fn, value, check; |
| 322 | bool may_quit; | ||
| 323 | specpdl_ref count; | ||
| 324 | |||
| 325 | may_quit = false; | ||
| 318 | 326 | ||
| 319 | local_value = LOCAL_SELECTION (selection_symbol, dpyinfo); | 327 | if (NILP (local_value)) |
| 328 | local_value = LOCAL_SELECTION (selection_symbol, dpyinfo); | ||
| 329 | else | ||
| 330 | may_quit = true; | ||
| 320 | 331 | ||
| 321 | if (NILP (local_value)) return Qnil; | 332 | if (NILP (local_value)) |
| 333 | return Qnil; | ||
| 322 | 334 | ||
| 323 | /* TIMESTAMP is a special case. */ | 335 | /* TIMESTAMP is a special case. */ |
| 324 | if (EQ (target_type, QTIMESTAMP)) | 336 | if (EQ (target_type, QTIMESTAMP)) |
| @@ -331,8 +343,10 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, | |||
| 331 | /* Don't allow a quit within the converter. | 343 | /* Don't allow a quit within the converter. |
| 332 | When the user types C-g, he would be surprised | 344 | When the user types C-g, he would be surprised |
| 333 | if by luck it came during a converter. */ | 345 | if by luck it came during a converter. */ |
| 334 | specpdl_ref count = SPECPDL_INDEX (); | 346 | count = SPECPDL_INDEX (); |
| 335 | specbind (Qinhibit_quit, Qt); | 347 | |
| 348 | if (!may_quit) | ||
| 349 | specbind (Qinhibit_quit, Qt); | ||
| 336 | 350 | ||
| 337 | CHECK_SYMBOL (target_type); | 351 | CHECK_SYMBOL (target_type); |
| 338 | handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist)); | 352 | handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist)); |
| @@ -804,7 +818,9 @@ x_handle_selection_request (struct selection_input_event *event) | |||
| 804 | target that doesn't support XDND. */ | 818 | target that doesn't support XDND. */ |
| 805 | if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1 | 819 | if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1 |
| 806 | || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2) | 820 | || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2) |
| 807 | selection_symbol = QXdndSelection; | 821 | /* Always reply with the contents of PRIMARY, since that's where |
| 822 | the selection data is. */ | ||
| 823 | selection_symbol = QPRIMARY; | ||
| 808 | 824 | ||
| 809 | local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo); | 825 | local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo); |
| 810 | 826 | ||
| @@ -915,7 +931,7 @@ x_convert_selection (Lisp_Object selection_symbol, | |||
| 915 | 931 | ||
| 916 | lisp_selection | 932 | lisp_selection |
| 917 | = x_get_local_selection (selection_symbol, target_symbol, | 933 | = x_get_local_selection (selection_symbol, target_symbol, |
| 918 | false, dpyinfo); | 934 | false, dpyinfo, Qnil); |
| 919 | 935 | ||
| 920 | frame = selection_request_stack; | 936 | frame = selection_request_stack; |
| 921 | 937 | ||
| @@ -2131,7 +2147,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused. */) | |||
| 2131 | } | 2147 | } |
| 2132 | 2148 | ||
| 2133 | val = x_get_local_selection (selection_symbol, target_type, true, | 2149 | val = x_get_local_selection (selection_symbol, target_type, true, |
| 2134 | FRAME_DISPLAY_INFO (f)); | 2150 | FRAME_DISPLAY_INFO (f), Qnil); |
| 2135 | 2151 | ||
| 2136 | if (NILP (val) && FRAME_LIVE_P (f)) | 2152 | if (NILP (val) && FRAME_LIVE_P (f)) |
| 2137 | { | 2153 | { |
| @@ -2273,6 +2289,45 @@ On Nextstep, TERMINAL is unused. */) | |||
| 2273 | return (owner ? Qt : Qnil); | 2289 | return (owner ? Qt : Qnil); |
| 2274 | } | 2290 | } |
| 2275 | 2291 | ||
| 2292 | DEFUN ("x-get-local-selection", Fx_get_local_selection, Sx_get_local_selection, | ||
| 2293 | 0, 2, 0, | ||
| 2294 | doc: /* Run selection converters for VALUE, and return the result. | ||
| 2295 | TARGET is the selection target that is used to find a suitable | ||
| 2296 | converter. VALUE is a list of 4 values NAME, SELECTION-VALUE, | ||
| 2297 | TIMESTAMP and FRAME. NAME is the name of the selection that will be | ||
| 2298 | passed to selection converters, SELECTION-VALUE is the value of the | ||
| 2299 | selection used by the converter, TIMESTAMP is not meaningful (but must | ||
| 2300 | be a number that fits in an X timestamp), and FRAME is the frame | ||
| 2301 | describing the terminal for which the selection converter will be | ||
| 2302 | run. */) | ||
| 2303 | (Lisp_Object value, Lisp_Object target) | ||
| 2304 | { | ||
| 2305 | Time time; | ||
| 2306 | Lisp_Object name, timestamp, frame, result; | ||
| 2307 | |||
| 2308 | CHECK_SYMBOL (target); | ||
| 2309 | name = Fnth (make_fixnum (0), value); | ||
| 2310 | timestamp = Fnth (make_fixnum (2), value); | ||
| 2311 | frame = Fnth (make_fixnum (3), value); | ||
| 2312 | |||
| 2313 | CHECK_SYMBOL (name); | ||
| 2314 | CONS_TO_INTEGER (timestamp, Time, time); | ||
| 2315 | check_window_system (decode_live_frame (frame)); | ||
| 2316 | |||
| 2317 | result = x_get_local_selection (name, target, true, | ||
| 2318 | NULL, value); | ||
| 2319 | |||
| 2320 | if (CONSP (result) && SYMBOLP (XCAR (result))) | ||
| 2321 | { | ||
| 2322 | result = XCDR (result); | ||
| 2323 | |||
| 2324 | if (CONSP (result) && NILP (XCDR (result))) | ||
| 2325 | result = XCAR (result); | ||
| 2326 | } | ||
| 2327 | |||
| 2328 | return clean_local_selection_data (result); | ||
| 2329 | } | ||
| 2330 | |||
| 2276 | 2331 | ||
| 2277 | /* Send clipboard manager a SAVE_TARGETS request with a UTF8_STRING | 2332 | /* Send clipboard manager a SAVE_TARGETS request with a UTF8_STRING |
| 2278 | property (https://www.freedesktop.org/wiki/ClipboardManager/). */ | 2333 | property (https://www.freedesktop.org/wiki/ClipboardManager/). */ |
| @@ -2809,6 +2864,7 @@ syms_of_xselect (void) | |||
| 2809 | defsubr (&Sx_get_atom_name); | 2864 | defsubr (&Sx_get_atom_name); |
| 2810 | defsubr (&Sx_send_client_message); | 2865 | defsubr (&Sx_send_client_message); |
| 2811 | defsubr (&Sx_register_dnd_atom); | 2866 | defsubr (&Sx_register_dnd_atom); |
| 2867 | defsubr (&Sx_get_local_selection); | ||
| 2812 | 2868 | ||
| 2813 | reading_selection_reply = Fcons (Qnil, Qnil); | 2869 | reading_selection_reply = Fcons (Qnil, Qnil); |
| 2814 | staticpro (&reading_selection_reply); | 2870 | staticpro (&reading_selection_reply); |
diff --git a/src/xterm.c b/src/xterm.c index d7c3bfa7aff..7298feb43a1 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -11234,6 +11234,19 @@ x_dnd_delete_action_list (Lisp_Object frame) | |||
| 11234 | unblock_input (); | 11234 | unblock_input (); |
| 11235 | } | 11235 | } |
| 11236 | 11236 | ||
| 11237 | static void | ||
| 11238 | x_dnd_lose_ownership (Lisp_Object timestamp_and_frame) | ||
| 11239 | { | ||
| 11240 | struct frame *f; | ||
| 11241 | |||
| 11242 | f = XFRAME (XCDR (timestamp_and_frame)); | ||
| 11243 | |||
| 11244 | if (FRAME_LIVE_P (f)) | ||
| 11245 | Fx_disown_selection_internal (QXdndSelection, | ||
| 11246 | XCAR (timestamp_and_frame), | ||
| 11247 | XCDR (timestamp_and_frame)); | ||
| 11248 | } | ||
| 11249 | |||
| 11237 | /* This function is defined far away from the rest of the XDND code so | 11250 | /* This function is defined far away from the rest of the XDND code so |
| 11238 | it can utilize `x_any_window_to_frame'. */ | 11251 | it can utilize `x_any_window_to_frame'. */ |
| 11239 | 11252 | ||
| @@ -11324,12 +11337,13 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11324 | 11337 | ||
| 11325 | if (!NILP (Vx_dnd_unsupported_drop_function)) | 11338 | if (!NILP (Vx_dnd_unsupported_drop_function)) |
| 11326 | { | 11339 | { |
| 11327 | if (!NILP (call7 (Vx_dnd_unsupported_drop_function, | 11340 | if (!NILP (call8 (Vx_dnd_unsupported_drop_function, |
| 11328 | XCAR (XCDR (event->ie.arg)), event->ie.x, | 11341 | XCAR (XCDR (event->ie.arg)), event->ie.x, |
| 11329 | event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), | 11342 | event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), |
| 11330 | make_uint (event->ie.code), | 11343 | make_uint (event->ie.code), |
| 11331 | event->ie.frame_or_window, | 11344 | event->ie.frame_or_window, |
| 11332 | make_int (event->ie.timestamp)))) | 11345 | make_int (event->ie.timestamp), |
| 11346 | Fcopy_sequence (XCAR (event->ie.arg))))) | ||
| 11333 | continue; | 11347 | continue; |
| 11334 | } | 11348 | } |
| 11335 | 11349 | ||
| @@ -11364,12 +11378,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11364 | /* If local_value is nil, then we lost ownership of XdndSelection. | 11378 | /* If local_value is nil, then we lost ownership of XdndSelection. |
| 11365 | Signal a more informative error than args-out-of-range. */ | 11379 | Signal a more informative error than args-out-of-range. */ |
| 11366 | if (NILP (local_value)) | 11380 | if (NILP (local_value)) |
| 11367 | error ("Lost ownership of XdndSelection"); | ||
| 11368 | |||
| 11369 | if (CONSP (local_value)) | ||
| 11370 | x_own_selection (QXdndSelection, | ||
| 11371 | Fnth (make_fixnum (1), local_value), frame); | ||
| 11372 | else | ||
| 11373 | error ("No local value for XdndSelection"); | 11381 | error ("No local value for XdndSelection"); |
| 11374 | 11382 | ||
| 11375 | if (popup_activated ()) | 11383 | if (popup_activated ()) |
| @@ -11387,6 +11395,14 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 11387 | else | 11395 | else |
| 11388 | x_dnd_selection_timestamp = XFIXNUM (ltimestamp); | 11396 | x_dnd_selection_timestamp = XFIXNUM (ltimestamp); |
| 11389 | 11397 | ||
| 11398 | /* Release ownership of XdndSelection after this function returns. | ||
| 11399 | VirtualBox uses the owner of XdndSelection to determine whether | ||
| 11400 | or not mouse motion is part of a drag-and-drop operation. */ | ||
| 11401 | |||
| 11402 | if (!x_dnd_preserve_selection_data) | ||
| 11403 | record_unwind_protect (x_dnd_lose_ownership, | ||
| 11404 | Fcons (ltimestamp, frame)); | ||
| 11405 | |||
| 11390 | x_dnd_motif_operations | 11406 | x_dnd_motif_operations |
| 11391 | = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), xaction); | 11407 | = xm_side_effect_from_action (FRAME_DISPLAY_INFO (f), xaction); |
| 11392 | 11408 | ||
| @@ -27959,17 +27975,21 @@ mouse position list. */); | |||
| 27959 | 27975 | ||
| 27960 | DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, | 27976 | DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, |
| 27961 | doc: /* Function called when trying to drop on an unsupported window. | 27977 | doc: /* Function called when trying to drop on an unsupported window. |
| 27978 | |||
| 27962 | This function is called whenever the user tries to drop something on a | 27979 | This function is called whenever the user tries to drop something on a |
| 27963 | window that does not support either the XDND or Motif protocols for | 27980 | window that does not support either the XDND or Motif protocols for |
| 27964 | drag-and-drop. It should return a non-nil value if the drop was | 27981 | drag-and-drop. It should return a non-nil value if the drop was |
| 27965 | handled by the function, and nil if it was not. It should accept | 27982 | handled by the function, and nil if it was not. It should accept |
| 27966 | several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME and TIME, | 27983 | several arguments TARGETS, X, Y, ACTION, WINDOW-ID, FRAME, TIME and |
| 27967 | where TARGETS is the list of targets that was passed to | 27984 | LOCAL-SELECTION, where TARGETS is the list of targets that was passed |
| 27968 | `x-begin-drag', WINDOW-ID is the numeric XID of the window that is | 27985 | to `x-begin-drag', WINDOW-ID is the numeric XID of the window that is |
| 27969 | being dropped on, X and Y are the root window-relative coordinates | 27986 | being dropped on, X and Y are the root window-relative coordinates |
| 27970 | where the drop happened, ACTION is the action that was passed to | 27987 | where the drop happened, ACTION is the action that was passed to |
| 27971 | `x-begin-drag', FRAME is the frame which initiated the drag-and-drop | 27988 | `x-begin-drag', FRAME is the frame which initiated the drag-and-drop |
| 27972 | operation, and TIME is the X server time when the drop happened. */); | 27989 | operation, TIME is the X server time when the drop happened, and |
| 27990 | LOCAL-SELECTION is the contents of the `XdndSelection' when | ||
| 27991 | `x-begin-drag' was run, which can be passed to | ||
| 27992 | `x-get-local-selection'. */); | ||
| 27973 | Vx_dnd_unsupported_drop_function = Qnil; | 27993 | Vx_dnd_unsupported_drop_function = Qnil; |
| 27974 | 27994 | ||
| 27975 | DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size, | 27995 | DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size, |
| @@ -27996,4 +28016,11 @@ should return a symbol describing what to return from | |||
| 27996 | If the value is nil, or the function returns a value that is not | 28016 | If the value is nil, or the function returns a value that is not |
| 27997 | a symbol, a drop on an Emacs frame will be canceled. */); | 28017 | a symbol, a drop on an Emacs frame will be canceled. */); |
| 27998 | Vx_dnd_native_test_function = Qnil; | 28018 | Vx_dnd_native_test_function = Qnil; |
| 28019 | |||
| 28020 | DEFVAR_BOOL ("x-dnd-preserve-selection-data", x_dnd_preserve_selection_data, | ||
| 28021 | doc: /* Preserve selection data after `x-begin-drag' returns. | ||
| 28022 | This lets you inspect the contents of `XdndSelection' after a | ||
| 28023 | drag-and-drop operation, which is useful when writing tests for | ||
| 28024 | drag-and-drop code. */); | ||
| 28025 | x_dnd_preserve_selection_data = false; | ||
| 27999 | } | 28026 | } |
diff --git a/test/lisp/dnd-tests.el b/test/lisp/dnd-tests.el index aae9c80273f..18dd55c206c 100644 --- a/test/lisp/dnd-tests.el +++ b/test/lisp/dnd-tests.el | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | "Alist of selection names to their values.") | 38 | "Alist of selection names to their values.") |
| 39 | 39 | ||
| 40 | (defvar x-treat-local-requests-remotely) | 40 | (defvar x-treat-local-requests-remotely) |
| 41 | (defvar x-dnd-preserve-selection-data) | ||
| 41 | 42 | ||
| 42 | ;; Define some replacements for functions used by the drag-and-drop | 43 | ;; Define some replacements for functions used by the drag-and-drop |
| 43 | ;; code on X when running under something else. | 44 | ;; code on X when running under something else. |
| @@ -152,7 +153,8 @@ This function only tries to handle strings." | |||
| 152 | ;; program with reasonably correct behavior, such as dtpad, gedit, | 153 | ;; program with reasonably correct behavior, such as dtpad, gedit, |
| 153 | ;; or Mozilla. | 154 | ;; or Mozilla. |
| 154 | ;; ASCII Latin-1 UTF-8 | 155 | ;; ASCII Latin-1 UTF-8 |
| 155 | (let ((test-text "hello, everyone! sæl öllsömul! всем привет")) | 156 | (let ((test-text "hello, everyone! sæl öllsömul! всем привет") |
| 157 | (x-dnd-preserve-selection-data t)) | ||
| 156 | ;; Verify that dragging works. | 158 | ;; Verify that dragging works. |
| 157 | (should (eq (dnd-begin-text-drag test-text) 'copy)) | 159 | (should (eq (dnd-begin-text-drag test-text) 'copy)) |
| 158 | (should (eq (dnd-begin-text-drag test-text nil 'move) 'move)) | 160 | (should (eq (dnd-begin-text-drag test-text nil 'move) 'move)) |
| @@ -187,7 +189,8 @@ This function only tries to handle strings." | |||
| 187 | (normal-multibyte-file (expand-file-name | 189 | (normal-multibyte-file (expand-file-name |
| 188 | (make-temp-name "тест-на-перетаскивание") | 190 | (make-temp-name "тест-на-перетаскивание") |
| 189 | temporary-file-directory)) | 191 | temporary-file-directory)) |
| 190 | (remote-temp-file (dnd-tests-make-temp-name))) | 192 | (remote-temp-file (dnd-tests-make-temp-name)) |
| 193 | (x-dnd-preserve-selection-data t)) | ||
| 191 | ;; Touch those files if they don't exist. | 194 | ;; Touch those files if they don't exist. |
| 192 | (unless (file-exists-p normal-temp-file) | 195 | (unless (file-exists-p normal-temp-file) |
| 193 | (write-region "" 0 normal-temp-file)) | 196 | (write-region "" 0 normal-temp-file)) |
| @@ -273,7 +276,8 @@ This function only tries to handle strings." | |||
| 273 | (expand-file-name (make-temp-name "dnd-test") | 276 | (expand-file-name (make-temp-name "dnd-test") |
| 274 | temporary-file-directory)) | 277 | temporary-file-directory)) |
| 275 | (nonexistent-remote-file (dnd-tests-make-temp-name)) | 278 | (nonexistent-remote-file (dnd-tests-make-temp-name)) |
| 276 | (nonexistent-remote-file-1 (dnd-tests-make-temp-name))) | 279 | (nonexistent-remote-file-1 (dnd-tests-make-temp-name)) |
| 280 | (x-dnd-preserve-selection-data t)) | ||
| 277 | ;; Touch those files if they don't exist. | 281 | ;; Touch those files if they don't exist. |
| 278 | (unless (file-exists-p normal-temp-file) | 282 | (unless (file-exists-p normal-temp-file) |
| 279 | (write-region "" 0 normal-temp-file)) | 283 | (write-region "" 0 normal-temp-file)) |