diff options
author | Po Lu <luangruo@yahoo.com> | 2022-04-06 20:29:30 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-04-06 20:30:24 +0800 |
commit | c0bb11432ee07228d8819cc98c6ce29ccd42ae97 (patch) | |
tree | 38ea48626b74e8fd4fd2826397b7dff1b212b39a | |
parent | 406da54bc63b1099b6e51b3d3e025712a16a1912 (diff) | |
download | emacs-c0bb11432ee07228d8819cc98c6ce29ccd42ae97.tar.gz |
Move some X11 drag and drop processing to Lisp
* lisp/term/x-win.el: Set unsupported drop function.
* lisp/x-dnd.el (x-dnd-handle-unsupported-drop): New function.
* src/keyboard.c (kbd_buffer_get_event): Handle
UNSUPPORTED_DROP_EVENT.
* src/termhooks.h (enum event_kind): New event
`UNSUPPORTED_DROP_EVENT'.
* src/xterm.c (x_dnd_send_unsupported_drop): Send those events
instead.
(x_dnd_do_unsupported_drop): Move actual unsupported drop
handling here.
(syms_of_xterm): New variable `x-dnd-unsupported-drop-function'.
* src/xterm.h: Update prototypes.
-rw-r--r-- | lisp/term/x-win.el | 2 | ||||
-rw-r--r-- | lisp/x-dnd.el | 13 | ||||
-rw-r--r-- | src/keyboard.c | 35 | ||||
-rw-r--r-- | src/termhooks.h | 19 | ||||
-rw-r--r-- | src/xterm.c | 126 | ||||
-rw-r--r-- | src/xterm.h | 3 |
6 files changed, 161 insertions, 37 deletions
diff --git a/lisp/term/x-win.el b/lisp/term/x-win.el index f0b9b27f66b..a71ae87e215 100644 --- a/lisp/term/x-win.el +++ b/lisp/term/x-win.el @@ -86,6 +86,7 @@ (defvar x-session-id) (defvar x-session-previous-id) (defvar x-dnd-movement-function) +(defvar x-dnd-unsupported-drop-function) (defun x-handle-no-bitmap-icon (_switch) (setq default-frame-alist (cons '(icon-type) default-frame-alist))) @@ -1583,6 +1584,7 @@ frames on all displays." (redisplay)) (setq x-dnd-movement-function #'x-dnd-movement) +(setq x-dnd-unsupported-drop-function #'x-dnd-handle-unsupported-drop) (provide 'x-win) (provide 'term/x-win) diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index af9c7b83d97..47d8ae14cfc 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el @@ -779,6 +779,19 @@ FORMAT is 32 (not used). MESSAGE is the data part of an XClientMessageEvent." ;;; + + +;;; Handling drops. + +(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame) + "Return non-nil if the drop described by TARGETS and ACTION should not proceeed." + (not (and (or (eq action 'XdndActionCopy) + (eq action 'XdndActionMove)) + (or (member "STRING" targets) + (member "UTF8_STRING" targets) + (member "COMPOUND_TEXT" targets) + (member "TEXT" targets))))) + (provide 'x-dnd) ;;; x-dnd.el ends here diff --git a/src/keyboard.c b/src/keyboard.c index d34bec48a6b..d99fe4be092 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4006,6 +4006,41 @@ kbd_buffer_get_event (KBOARD **kbp, } break; +#ifdef HAVE_X_WINDOWS + case UNSUPPORTED_DROP_EVENT: + { + struct frame *f; + + kbd_fetch_ptr = next_kbd_event (event); + input_pending = readable_events (0); + + f = XFRAME (event->ie.frame_or_window); + + if (!FRAME_LIVE_P (f)) + break; + + if (!NILP (Vx_dnd_unsupported_drop_function)) + { + if (!NILP (call6 (Vx_dnd_unsupported_drop_function, + XCAR (XCDR (event->ie.arg)), event->ie.x, + event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))), + make_uint (event->ie.code), + event->ie.frame_or_window))) + break; + } + + x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f), + event->ie.frame_or_window, + XCAR (event->ie.arg), + XCAR (XCDR (event->ie.arg)), + (Window) event->ie.code, + XFIXNUM (event->ie.x), + XFIXNUM (event->ie.y), + event->ie.timestamp); + break; + } +#endif + #ifdef HAVE_EXT_MENU_BAR case MENU_BAR_ACTIVATE_EVENT: { diff --git a/src/termhooks.h b/src/termhooks.h index 93ac9ba0d2e..0f02b56e9ee 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -208,6 +208,25 @@ enum event_kind representation of the dropped items. .timestamp gives a timestamp (in milliseconds) for the click. */ +#ifdef HAVE_X_WINDOWS + UNSUPPORTED_DROP_EVENT, /* Event sent when the regular C + drag-and-drop machinery could not + handle a drop to a window. + + .code is the XID of the window that + could not be dropped to. + + .arg is a list of the local value of + XdndSelection, a list of selection + targets, and the intended action to + be taken upon drop, and .timestamp + gives the timestamp where the drop + happened. + + .x and .y give the coordinates of + the drop originating from the root + window. */ +#endif USER_SIGNAL_EVENT, /* A user signal. code is a number identifying it, index into lispy_user_signals. */ diff --git a/src/xterm.c b/src/xterm.c index b6aed004ed3..b6fe5fda0fa 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2774,45 +2774,35 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, Dropping on windows that do not support XDND - Since middle clicking is the universal shortcut for pasting in X, - one can drop data into a window that does not support XDND by: - - 1. After the mouse has been released to trigger the drop, obtain - ownership of XA_PRIMARY. - - 2. Send a ButtonPress event and then a ButtonRelease event to the - deepest subwindow containing the mouse to simulate a middle click. - The times for these events should be the time of the actual button - release +1 and +2, respectively. These values will not be used by - anybody else, so one can unambiguously recognize the resulting - XConvertSelection() request. - - 3. If a request for XA_PRIMARY arrives bearing the timestamp of - either the ButtonPress or the ButtonRelease event, treat it as a - request for XdndSelection. Note that you must use the X data - types instead of the MIME types in this case. (e.g. XA_STRING - instead of text/plain). */ -static void -x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window, - int root_x, int root_y, Time before) + Since middle clicking is the universal shortcut for pasting + in X, one can drop data into a window that does not support + XDND by: + + 1. After the mouse has been released to trigger the drop, + obtain ownership of XA_PRIMARY. + + 2. Send a ButtonPress event and then a ButtonRelease event to + the deepest subwindow containing the mouse to simulate a + middle click. The times for these events should be the time + of the actual button release +1 and +2, respectively. These + values will not be used by anybody else, so one can + unambiguously recognize the resulting `XConvertSelection' + request. + + 3. If a request for XA_PRIMARY arrives bearing the timestamp + of either the ButtonPress or the ButtonRelease event, treat + it as a request for XdndSelection. Note that you must use + the X data types instead of the MIME types in this case. + (e.g. XA_STRING instead of text/plain). */ +void +x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, + Lisp_Object frame, Lisp_Object value, + Lisp_Object targets, Window target_window, + int root_x, int root_y, Time before) { XEvent event; int dest_x, dest_y; Window child_return, child; - Lisp_Object frame; - int i; - - for (i = 0; i < x_dnd_n_targets; ++i) - { - if (x_dnd_targets[i] == XA_STRING - || x_dnd_targets[i] == dpyinfo->Xatom_TEXT - || x_dnd_targets[i] == dpyinfo->Xatom_COMPOUND_TEXT - || x_dnd_targets[i] == dpyinfo->Xatom_UTF8_STRING) - break; - } - - if (i == x_dnd_n_targets) - return; event.xbutton.type = ButtonPress; event.xbutton.serial = 0; @@ -2822,8 +2812,6 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo event.xbutton.x_root = root_x; event.xbutton.y_root = root_y; - XSETFRAME (frame, x_dnd_frame); - x_catch_errors (dpyinfo->display); child = dpyinfo->root_window; @@ -2868,6 +2856,55 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo x_uncatch_errors (); } +static void +x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window, + int root_x, int root_y, Time before) +{ + struct input_event ie; + Lisp_Object targets, arg; + int i; + char **atom_names, *name; + + EVENT_INIT (ie); + targets = Qnil; + atom_names = alloca (sizeof *atom_names * x_dnd_n_targets); + + if (!XGetAtomNames (dpyinfo->display, x_dnd_targets, + x_dnd_n_targets, atom_names)) + return; + + for (i = x_dnd_n_targets; i > 0; --i) + { + targets = Fcons (build_string (atom_names[i - 1]), + targets); + XFree (atom_names[i - 1]); + } + + name = XGetAtomName (dpyinfo->display, + x_dnd_wanted_action); + + if (name) + { + arg = intern (name); + XFree (name); + } + else + arg = Qnil; + + ie.kind = UNSUPPORTED_DROP_EVENT; + ie.code = (unsigned) target_window; + ie.arg = list3 (assq_no_quit (QXdndSelection, + dpyinfo->terminal->Vselection_alist), + targets, arg); + ie.timestamp = before; + + XSETINT (ie.x, root_x); + XSETINT (ie.y, root_y); + XSETFRAME (ie.frame_or_window, x_dnd_frame); + + kbd_buffer_store_event (&ie); +} + static Window x_dnd_get_target_window (struct x_display_info *dpyinfo, int root_x, int root_y, int *proto_out, @@ -23273,4 +23310,19 @@ It should either be nil, or accept two arguments FRAME and POSITION, where FRAME is the frame the mouse is on top of, and POSITION is a mouse position list. */); Vx_dnd_movement_function = Qnil; + + DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function, + doc: /* Function called when trying to drop on an unsupported window. +This function is called whenever the user tries to drop +something on a window that does not support either the XDND or +Motif protocols for drag-and-drop. It should return a non-nil +value if the drop was handled by the function, and nil if it was +not. It should accept several arguments TARGETS, X, Y, ACTION, +WINDOW-ID and FRAME, where TARGETS is the list of targets that +was passed to `x-begin-drag', WINDOW-ID is the numeric XID of +the window that is being dropped on, X and Y are the root +window-relative coordinates where the drop happened, ACTION +is the action that was passed to `x-begin-drag', and FRAME is +the frame which initiated the drag-and-drop operation. */); + Vx_dnd_unsupported_drop_function = Qnil; } diff --git a/src/xterm.h b/src/xterm.h index 4eb16d0c142..d8898162d11 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1391,6 +1391,9 @@ extern void x_scroll_bar_configure (GdkEvent *); extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom, Lisp_Object, Atom *, const char **, size_t, bool); +extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object, + Lisp_Object, Lisp_Object, Window, int, + int, Time); extern void x_set_dnd_targets (Atom *, int); INLINE int |