1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-24 07:20:37 +00:00

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.
This commit is contained in:
Po Lu 2022-04-06 20:29:30 +08:00
parent 406da54bc6
commit c0bb11432e
6 changed files with 158 additions and 34 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:
{

View File

@ -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. */

View File

@ -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:
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.
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.
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)
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;
}

View File

@ -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