1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-30 11:09:23 +00:00

Implement using the OffiX protocol for dropping

* lisp/x-dnd.el (x-dnd-use-offix-drop): New user option.
(x-dnd-handle-unsupported-drop): Return t if the OffiX protocol
was used.
(x-treat-local-requests-remotely): New defvar.
(x-dnd-convert-to-offix, x-dnd-do-offix-drop): New functions.

* src/xterm.c: Update commentary.
(x_term_init): Extend number of DND atoms allocated by default.
This commit is contained in:
Po Lu 2022-06-15 21:00:55 +08:00
parent 8ee9e20f8c
commit 9b053968ef
2 changed files with 98 additions and 11 deletions

View File

@ -102,6 +102,16 @@ The types are chosen in the order they appear in the list."
:type '(repeat string)
:group 'x)
(defcustom x-dnd-use-offix-drop nil
"If non-nil, use the OffiX protocol to drop files and text.
This allows dropping (via `dired-mouse-drag-files' or
`mouse-drag-and-drop-region-cross-program') on some old Java
applets and old KDE programs. Turning this off allows dropping
only text on some other programs such as xterm and urxvt."
:version "29.1"
:type 'boolean
:group 'x)
;; Internal variables
(defvar x-dnd-current-state nil
@ -938,14 +948,82 @@ Return a vector of atoms containing the selection targets."
;;; Handling drops.
(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame _time)
"Return non-nil if the drop described by TARGETS and ACTION should not proceed."
(defvar x-treat-local-requests-remotely)
(defun x-dnd-convert-to-offix (targets)
"Convert the contents of `XdndSelection' to OffiX data.
TARGETS should be the list of targets currently available in
`XdndSelection'. Return a list of an OffiX type, and data
suitable for passing to `x-change-window-property', or nil if the
data could not be converted."
(let ((x-treat-local-requests-remotely t)
file-name-data string-data)
(cond
((and (member "FILE_NAME" targets)
(setq file-name-data
(gui-get-selection 'XdndSelection 'FILE_NAME)))
(if (string-match-p "\0" file-name-data)
;; This means there are multiple file names in
;; XdndSelection. Convert the file name data to a format
;; that OffiX understands.
(cons 'DndTypeFiles (concat file-name-data "\0"))
(cons 'DndTypeFile (concat file-name-data "\0"))))
((and (member "STRING" targets)
(setq string-data
(gui-get-selection 'XdndSelection 'STRING)))
(cons 'DndTypeText (encode-coding-string string-data
'latin-1))))))
(defun x-dnd-do-offix-drop (targets x y frame window-id)
"Perform an OffiX drop on WINDOW-ID with the contents of `XdndSelection'.
Return non-nil if the drop succeeded, or nil if it did not
happen, which can happen if TARGETS didn't contain anything that
the OffiX protocol can represent.
X and Y are the root window coordinates of the drop. TARGETS is
the list of targets `XdndSelection' can be converted to."
(if-let* ((data (x-dnd-convert-to-offix targets))
(type-id (car (rassq (car data)
x-dnd-offix-id-to-name)))
(source-id (string-to-number
(frame-parameter frame 'window-id)))
(message-data (list type-id ; l[0] = DataType
0 ; l[1] = event->xbutton.state
source-id ; l[2] = window
(+ x (* 65536 y)) ; l[3] = drop_x + 65536 * drop_y
1))) ; l[4] = protocol version
(prog1 t
;; Send a legacy (old KDE) message first. Newer clients will
;; ignore it, since the protocol version is 1.
(x-change-window-property "DndSelection"
(cdr data) frame
"STRING" 8 nil 0)
(x-send-client-message frame window-id
frame "DndProtocol"
32 message-data)
;; Now send a modern _DND_PROTOCOL message.
(x-change-window-property "_DND_SELECTION"
(cdr data) frame
"STRING" 8 nil 0)
(x-send-client-message frame window-id
frame "_DND_PROTOCOL"
32 message-data))))
(defun x-dnd-handle-unsupported-drop (targets x y action window-id frame _time)
"Return non-nil if the drop described by TARGETS and ACTION should not proceed.
X and Y are the root window coordinates of the drop.
FRAME is the frame the drop originated on.
WINDOW-ID is the X window the drop should happen to."
(not (and (or (eq action 'XdndActionCopy)
(eq action 'XdndActionMove))
(or (member "STRING" targets)
(member "UTF8_STRING" targets)
(member "COMPOUND_TEXT" targets)
(member "TEXT" targets)))))
(not (and x-dnd-use-offix-drop
(x-dnd-do-offix-drop targets x
y frame window-id)))
(or
(member "STRING" targets)
(member "UTF8_STRING" targets)
(member "COMPOUND_TEXT" targets)
(member "TEXT" targets)))))
(defvar x-dnd-targets-list)
(defvar x-dnd-native-test-function)

View File

@ -520,9 +520,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
replying to the initiating client) is performed from Lisp inside
`x-dnd.el'.
However, dragging contents from Emacs is implemented entirely in C.
X Windows has several competing drag-and-drop protocols, of which
Emacs supports two: the XDND protocol (see
However, dragging contents from Emacs is implemented almost entirely
in C. X Windows has several competing drag-and-drop protocols, of
which Emacs supports two on the C level: the XDND protocol (see
https://freedesktop.org/wiki/Specifications/XDND) and the Motif drag
and drop protocols. These protocols are based on the initiator
owning a special selection, specifying an action the recipient
@ -545,7 +545,16 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
released over the recipient window, Emacs sends a "drop" message to
the target window, waits for a reply, and returns the action
selected by the recipient to the Lisp code that initiated the
drag-and-drop operation. */
drag-and-drop operation.
When a drop happens on a window not supporting any protocol
implemented on the C level, the function inside
`x-dnd-unsupported-drop-function' is called with some parameters of
the drop. If it returns non-nil, then Emacs tries to simulate a
drop happening with the primary selection and synthetic button
events (see `x_dnd_do_unsupported_drop'). That function implements
the OffiX drag-and-drop protocol by default. See
`x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details. */
#include <config.h>
#include <stdlib.h>
@ -26571,7 +26580,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
x_find_modifier_meanings (dpyinfo);
#endif
dpyinfo->x_dnd_atoms_size = 8;
dpyinfo->x_dnd_atoms_size = 16;
dpyinfo->x_dnd_atoms = xmalloc (sizeof *dpyinfo->x_dnd_atoms
* dpyinfo->x_dnd_atoms_size);
dpyinfo->gray