summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-04-06 20:29:30 +0800
committerPo Lu <luangruo@yahoo.com>2022-04-06 20:30:24 +0800
commitc0bb11432ee07228d8819cc98c6ce29ccd42ae97 (patch)
tree38ea48626b74e8fd4fd2826397b7dff1b212b39a
parent406da54bc63b1099b6e51b3d3e025712a16a1912 (diff)
downloademacs-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.el2
-rw-r--r--lisp/x-dnd.el13
-rw-r--r--src/keyboard.c35
-rw-r--r--src/termhooks.h19
-rw-r--r--src/xterm.c126
-rw-r--r--src/xterm.h3
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