forked from Github/emacs
Fix race conditions in handling of unsupported drops on X
* lisp/x-dnd.el (x-dnd-handle-unsupported-drop): Adjust for new parameters. * src/keyboard.c (kbd_buffer, kbd_fetch_ptr, kbd_store_ptr): Export variables. (kbd_buffer_get_event): Ignore already handled unsupported drops. * src/keyboard.h: Update prototypes. * src/termhooks.h (enum event_kind): Document meaning of `modifiers' in UNSUPPORTED_DROP_EVENTs. * src/xterm.c (x_dnd_send_unsupported_drop): Set event modifiers to current level. (x_toggle_visible_pointer): Fix fixes fallback. (x_dnd_begin_drag_and_drop): Handle UNSUPPORTED_DROP_EVENTs already in the keyboard buffer before starting DND. (syms_of_xterm): Give timestamp to unsupported drop function. * src/xterm.h: Update prototypes.
This commit is contained in:
parent
8d788a195f
commit
3d846efb85
6 changed files with 110 additions and 25 deletions
|
|
@ -783,7 +783,7 @@ 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)
|
||||
(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 proceeed."
|
||||
(not (and (or (eq action 'XdndActionCopy)
|
||||
(eq action 'XdndActionMove))
|
||||
|
|
|
|||
|
|
@ -95,8 +95,6 @@ volatile int interrupt_input_blocked;
|
|||
The maybe_quit function checks this. */
|
||||
volatile bool pending_signals;
|
||||
|
||||
enum { KBD_BUFFER_SIZE = 4096 };
|
||||
|
||||
KBOARD *initial_kboard;
|
||||
KBOARD *current_kboard;
|
||||
static KBOARD *all_kboards;
|
||||
|
|
@ -290,14 +288,14 @@ bool input_was_pending;
|
|||
|
||||
/* Circular buffer for pre-read keyboard input. */
|
||||
|
||||
static union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
|
||||
union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
|
||||
|
||||
/* Pointer to next available character in kbd_buffer.
|
||||
If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. */
|
||||
static union buffered_input_event *kbd_fetch_ptr;
|
||||
union buffered_input_event *kbd_fetch_ptr;
|
||||
|
||||
/* Pointer to next place to store character in kbd_buffer. */
|
||||
static union buffered_input_event *kbd_store_ptr;
|
||||
union buffered_input_event *kbd_store_ptr;
|
||||
|
||||
/* The above pair of variables forms a "queue empty" flag. When we
|
||||
enqueue a non-hook event, we increment kbd_store_ptr. When we
|
||||
|
|
@ -4022,6 +4020,11 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
kbd_fetch_ptr = next_kbd_event (event);
|
||||
input_pending = readable_events (0);
|
||||
|
||||
/* This means this event was already handled in
|
||||
`x_dnd_begin_drag_and_drop'. */
|
||||
if (event->ie.modifiers < x_dnd_unsupported_event_level)
|
||||
break;
|
||||
|
||||
f = XFRAME (event->ie.frame_or_window);
|
||||
|
||||
if (!FRAME_LIVE_P (f))
|
||||
|
|
@ -4029,11 +4032,12 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
|
||||
if (!NILP (Vx_dnd_unsupported_drop_function))
|
||||
{
|
||||
if (!NILP (call6 (Vx_dnd_unsupported_drop_function,
|
||||
if (!NILP (call7 (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)))
|
||||
event->ie.frame_or_window,
|
||||
make_int (event->ie.timestamp))))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -358,6 +358,11 @@ enum menu_item_idx
|
|||
MENU_ITEMS_ITEM_LENGTH
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
KBD_BUFFER_SIZE = 4096
|
||||
};
|
||||
|
||||
extern void unuse_menu_items (void);
|
||||
|
||||
/* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU
|
||||
|
|
@ -419,6 +424,10 @@ extern void unuse_menu_items (void);
|
|||
happens. */
|
||||
extern struct timespec *input_available_clear_time;
|
||||
|
||||
extern union buffered_input_event kbd_buffer[KBD_BUFFER_SIZE];
|
||||
extern union buffered_input_event *kbd_fetch_ptr;
|
||||
extern union buffered_input_event *kbd_store_ptr;
|
||||
|
||||
extern bool ignore_mouse_drag_p;
|
||||
|
||||
extern Lisp_Object parse_modifiers (Lisp_Object);
|
||||
|
|
|
|||
|
|
@ -223,6 +223,11 @@ enum event_kind
|
|||
gives the timestamp where the drop
|
||||
happened.
|
||||
|
||||
.modifiers gives a number that
|
||||
determines if an event was already
|
||||
handled by
|
||||
`x_dnd_begin_drag_and_drop'.
|
||||
|
||||
.x and .y give the coordinates of
|
||||
the drop originating from the root
|
||||
window. */
|
||||
|
|
|
|||
100
src/xterm.c
100
src/xterm.c
|
|
@ -868,6 +868,10 @@ static int x_filter_event (struct x_display_info *, XEvent *);
|
|||
/* Flag that indicates if a drag-and-drop operation is in progress. */
|
||||
bool x_dnd_in_progress;
|
||||
|
||||
/* Number that indicates the last "generation" of
|
||||
UNSUPPORTED_DROP_EVENTs handled. */
|
||||
unsigned x_dnd_unsupported_event_level;
|
||||
|
||||
/* The frame where the drag-and-drop operation originated. */
|
||||
struct frame *x_dnd_frame;
|
||||
|
||||
|
|
@ -3070,6 +3074,7 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
|
|||
|
||||
ie.kind = UNSUPPORTED_DROP_EVENT;
|
||||
ie.code = (unsigned) target_window;
|
||||
ie.modifiers = x_dnd_unsupported_event_level;
|
||||
ie.arg = list3 (assq_no_quit (QXdndSelection,
|
||||
dpyinfo->terminal->Vselection_alist),
|
||||
targets, arg);
|
||||
|
|
@ -9479,15 +9484,18 @@ x_toggle_visible_pointer (struct frame *f, bool invisible)
|
|||
invisible = false;
|
||||
#else
|
||||
/* But if Xfixes is available, try using it instead. */
|
||||
if (x_probe_xfixes_extension (dpyinfo))
|
||||
if (dpyinfo->invisible_cursor == None)
|
||||
{
|
||||
dpyinfo->fixes_pointer_blanking = true;
|
||||
xfixes_toggle_visible_pointer (f, invisible);
|
||||
if (x_probe_xfixes_extension (dpyinfo))
|
||||
{
|
||||
dpyinfo->fixes_pointer_blanking = true;
|
||||
xfixes_toggle_visible_pointer (f, invisible);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
else
|
||||
invisible = false;
|
||||
}
|
||||
else
|
||||
invisible = false;
|
||||
#endif
|
||||
|
||||
if (invisible)
|
||||
|
|
@ -9864,6 +9872,64 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
#ifndef USE_GTK
|
||||
struct x_display_info *event_display;
|
||||
#endif
|
||||
union buffered_input_event *events, *event;
|
||||
int n_events;
|
||||
struct frame *event_frame;
|
||||
|
||||
/* Before starting drag-and-drop, walk through the keyboard buffer
|
||||
to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
|
||||
if they exist, to prevent race conditions from happening due to
|
||||
multiple unsupported drops running at once. */
|
||||
|
||||
block_input ();
|
||||
events = alloca (sizeof *events * KBD_BUFFER_SIZE);
|
||||
n_events = 0;
|
||||
event = kbd_fetch_ptr;
|
||||
|
||||
while (event != kbd_store_ptr)
|
||||
{
|
||||
if (event->ie.kind == UNSUPPORTED_DROP_EVENT
|
||||
&& event->ie.modifiers < x_dnd_unsupported_event_level)
|
||||
events[n_events++] = *event;
|
||||
|
||||
event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
|
||||
? kbd_buffer : event + 1);
|
||||
}
|
||||
|
||||
x_dnd_unsupported_event_level += 1;
|
||||
unblock_input ();
|
||||
|
||||
for (i = 0; i < n_events; ++i)
|
||||
{
|
||||
maybe_quit ();
|
||||
|
||||
event = &events[i];
|
||||
event_frame = XFRAME (event->ie.frame_or_window);
|
||||
|
||||
if (!FRAME_LIVE_P (event_frame))
|
||||
continue;
|
||||
|
||||
if (!NILP (Vx_dnd_unsupported_drop_function))
|
||||
{
|
||||
if (!NILP (call7 (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,
|
||||
make_int (event->ie.timestamp))))
|
||||
continue;
|
||||
}
|
||||
|
||||
x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
|
||||
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;
|
||||
}
|
||||
|
||||
if (!FRAME_VISIBLE_P (f))
|
||||
{
|
||||
|
|
@ -24849,16 +24915,16 @@ mouse position list. */);
|
|||
|
||||
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. */);
|
||||
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, FRAME and TIME,
|
||||
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', FRAME is the frame which initiated the drag-and-drop
|
||||
operation, and TIME is the X server time when the drop happened. */);
|
||||
Vx_dnd_unsupported_drop_function = Qnil;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1586,6 +1586,7 @@ extern struct input_event xg_pending_quit_event;
|
|||
|
||||
extern bool x_dnd_in_progress;
|
||||
extern struct frame *x_dnd_frame;
|
||||
extern unsigned x_dnd_unsupported_event_level;
|
||||
|
||||
#ifdef HAVE_XINPUT2
|
||||
extern struct xi_device_t *xi_device_from_id (struct x_display_info *, int);
|
||||
|
|
|
|||
Loading…
Reference in a new issue