forked from Github/emacs
Speed up receiving drops over slow connections
* lisp/x-dnd.el (x-dnd-debug-errors): New variable. (x-dnd-handle-drag-n-drop-event): Bind `x-fast-protocol-requests' to t if that is off. * src/xfns.c (Fx_change_window_property): (Fx_delete_window_property): * src/xselect.c (Fx_send_client_message, x_send_client_event): Don't sync to check for errors if fast protocol requests are enabled. * src/xterm.c (x_catch_errors_for_lisp, x_check_errors_for_lisp) (x_uncatch_errors_for_lisp): New functions. (syms_of_xterm): New variable `x-fast-protocol-requests'. * src/xterm.h: Update prototypes.
This commit is contained in:
parent
782e48b3db
commit
4ef1e4daf5
5 changed files with 104 additions and 31 deletions
|
|
@ -151,6 +151,12 @@ data types in this list."
|
|||
|
||||
;; Internal variables
|
||||
|
||||
(defvar x-dnd-debug-errors nil
|
||||
"Whether or not to signal protocol errors during drag-and-drop.
|
||||
This is useful for debugging errors in the DND code, but makes
|
||||
drag-and-drop much slower over network connections with high
|
||||
latency.")
|
||||
|
||||
(defvar x-dnd-current-state nil
|
||||
"The current state for a drop.
|
||||
This is an alist with one entry for each display. The value for each display
|
||||
|
|
@ -425,11 +431,14 @@ nil if not."
|
|||
(select-frame frame)
|
||||
(funcall handler window action data))))))
|
||||
|
||||
(defvar x-fast-protocol-requests)
|
||||
|
||||
(defun x-dnd-handle-drag-n-drop-event (event)
|
||||
"Receive drag and drop events (X client messages).
|
||||
Currently XDND, Motif and old KDE 1.x protocols are recognized."
|
||||
(interactive "e")
|
||||
(let* ((client-message (car (cdr (cdr event))))
|
||||
(x-fast-protocol-requests (not x-dnd-debug-errors))
|
||||
(window (posn-window (event-start event))))
|
||||
(if (eq (and (consp client-message)
|
||||
(car client-message))
|
||||
|
|
|
|||
71
src/xfns.c
71
src/xfns.c
|
|
@ -7339,18 +7339,23 @@ If VALUE is a string and FORMAT is 32, then the format of VALUE is
|
|||
system-specific. VALUE must contain unsigned integer data in native
|
||||
endian-ness in multiples of the size of the C type 'long': the low 32
|
||||
bits of each such number are used as the value of each element of the
|
||||
property. */)
|
||||
property.
|
||||
|
||||
Wait for the request to complete and signal any error, unless
|
||||
`x-fast-protocol-requests' is non-nil, in which case errors will be
|
||||
silently ignored. */)
|
||||
(Lisp_Object prop, Lisp_Object value, Lisp_Object frame,
|
||||
Lisp_Object type, Lisp_Object format, Lisp_Object outer_p,
|
||||
Lisp_Object window_id)
|
||||
{
|
||||
struct frame *f = decode_window_system_frame (frame);
|
||||
struct frame *f;
|
||||
Atom prop_atom;
|
||||
Atom target_type = XA_STRING;
|
||||
int element_format = 8;
|
||||
unsigned char *data;
|
||||
int nelements;
|
||||
Window target_window;
|
||||
struct x_display_info *dpyinfo;
|
||||
#ifdef USE_XCB
|
||||
bool intern_prop;
|
||||
bool intern_target;
|
||||
|
|
@ -7361,6 +7366,9 @@ property. */)
|
|||
bool rc;
|
||||
#endif
|
||||
|
||||
f = decode_window_system_frame (frame);
|
||||
dpyinfo = FRAME_DISPLAY_INFO (f);
|
||||
|
||||
CHECK_STRING (prop);
|
||||
|
||||
if (! NILP (format))
|
||||
|
|
@ -7412,7 +7420,7 @@ property. */)
|
|||
{
|
||||
CONS_TO_INTEGER (window_id, Window, target_window);
|
||||
if (! target_window)
|
||||
target_window = FRAME_DISPLAY_INFO (f)->root_window;
|
||||
target_window = dpyinfo->root_window;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -7424,47 +7432,47 @@ property. */)
|
|||
|
||||
block_input ();
|
||||
#ifndef USE_XCB
|
||||
prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
|
||||
SSDATA (prop), false);
|
||||
prop_atom = x_intern_cached_atom (dpyinfo, SSDATA (prop),
|
||||
false);
|
||||
if (! NILP (type))
|
||||
{
|
||||
CHECK_STRING (type);
|
||||
target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
|
||||
SSDATA (type), false);
|
||||
target_type = x_intern_cached_atom (dpyinfo, SSDATA (type),
|
||||
false);
|
||||
}
|
||||
#else
|
||||
rc = true;
|
||||
intern_target = true;
|
||||
intern_prop = true;
|
||||
|
||||
prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
|
||||
SSDATA (prop), true);
|
||||
prop_atom = x_intern_cached_atom (dpyinfo, SSDATA (prop),
|
||||
true);
|
||||
|
||||
if (prop_atom != None)
|
||||
intern_prop = false;
|
||||
else
|
||||
prop_atom_cookie
|
||||
= xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
|
||||
= xcb_intern_atom (dpyinfo->xcb_connection,
|
||||
0, SBYTES (prop), SSDATA (prop));
|
||||
|
||||
if (!NILP (type))
|
||||
{
|
||||
CHECK_STRING (type);
|
||||
|
||||
target_type = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
|
||||
SSDATA (type), true);
|
||||
target_type = x_intern_cached_atom (dpyinfo, SSDATA (type),
|
||||
true);
|
||||
|
||||
if (target_type)
|
||||
intern_target = false;
|
||||
else
|
||||
target_type_cookie
|
||||
= xcb_intern_atom (FRAME_DISPLAY_INFO (f)->xcb_connection,
|
||||
= xcb_intern_atom (dpyinfo->xcb_connection,
|
||||
0, SBYTES (type), SSDATA (type));
|
||||
}
|
||||
|
||||
if (intern_prop)
|
||||
{
|
||||
reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
|
||||
reply = xcb_intern_atom_reply (dpyinfo->xcb_connection,
|
||||
prop_atom_cookie, &generic_error);
|
||||
|
||||
if (reply)
|
||||
|
|
@ -7481,7 +7489,7 @@ property. */)
|
|||
|
||||
if (!NILP (type) && intern_target)
|
||||
{
|
||||
reply = xcb_intern_atom_reply (FRAME_DISPLAY_INFO (f)->xcb_connection,
|
||||
reply = xcb_intern_atom_reply (dpyinfo->xcb_connection,
|
||||
target_type_cookie, &generic_error);
|
||||
|
||||
if (reply)
|
||||
|
|
@ -7500,15 +7508,18 @@ property. */)
|
|||
error ("Failed to intern type or property atom");
|
||||
#endif
|
||||
|
||||
x_catch_errors (FRAME_X_DISPLAY (f));
|
||||
XChangeProperty (FRAME_X_DISPLAY (f), target_window,
|
||||
prop_atom, target_type, element_format, PropModeReplace,
|
||||
data, nelements);
|
||||
x_catch_errors_for_lisp (dpyinfo);
|
||||
|
||||
if (CONSP (value)) xfree (data);
|
||||
x_check_errors (FRAME_X_DISPLAY (f),
|
||||
"Couldn't change window property: %s");
|
||||
x_uncatch_errors_after_check ();
|
||||
XChangeProperty (dpyinfo->display, target_window,
|
||||
prop_atom, target_type, element_format,
|
||||
PropModeReplace, data, nelements);
|
||||
|
||||
if (CONSP (value))
|
||||
xfree (data);
|
||||
|
||||
x_check_errors_for_lisp (dpyinfo,
|
||||
"Couldn't change window property: %s");
|
||||
x_uncatch_errors_for_lisp (dpyinfo);
|
||||
|
||||
unblock_input ();
|
||||
return value;
|
||||
|
|
@ -7525,7 +7536,11 @@ If WINDOW-ID is non-nil, remove property from that window instead
|
|||
across X displays or screens on the same display, so FRAME provides
|
||||
context for the window ID.
|
||||
|
||||
Value is PROP. */)
|
||||
Value is PROP.
|
||||
|
||||
Wait for the request to complete and signal any error, unless
|
||||
`x-fast-protocol-requests' is non-nil, in which case errors will be
|
||||
silently ignored. */)
|
||||
(Lisp_Object prop, Lisp_Object frame, Lisp_Object window_id)
|
||||
{
|
||||
struct frame *f = decode_window_system_frame (frame);
|
||||
|
|
@ -7545,11 +7560,11 @@ Value is PROP. */)
|
|||
prop_atom = x_intern_cached_atom (FRAME_DISPLAY_INFO (f),
|
||||
SSDATA (prop), false);
|
||||
|
||||
x_catch_errors (FRAME_X_DISPLAY (f));
|
||||
x_catch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
|
||||
XDeleteProperty (FRAME_X_DISPLAY (f), target_window, prop_atom);
|
||||
x_check_errors (FRAME_X_DISPLAY (f),
|
||||
"Couldn't delete window property: %s");
|
||||
x_uncatch_errors_after_check ();
|
||||
x_check_errors_for_lisp (FRAME_DISPLAY_INFO (f),
|
||||
"Couldn't delete window property: %s");
|
||||
x_uncatch_errors_for_lisp (FRAME_DISPLAY_INFO (f));
|
||||
|
||||
unblock_input ();
|
||||
return prop;
|
||||
|
|
|
|||
|
|
@ -2749,7 +2749,11 @@ to send. If a value is a string, it is converted to an Atom and the value of
|
|||
the Atom is sent. If a value is a cons, it is converted to a 32 bit number
|
||||
with the high 16 bits from the car and the lower 16 bit from the cdr.
|
||||
If more values than fits into the event is given, the excessive values
|
||||
are ignored. */)
|
||||
are ignored.
|
||||
|
||||
Wait for the event to be sent and signal any error, unless
|
||||
`x-fast-protocol-requests' is non-nil, in which case errors will be
|
||||
silently ignored. */)
|
||||
(Lisp_Object display, Lisp_Object dest, Lisp_Object from,
|
||||
Lisp_Object message_type, Lisp_Object format, Lisp_Object values)
|
||||
{
|
||||
|
|
@ -2830,7 +2834,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
|
|||
the destination window. But if we are sending to the root window,
|
||||
there is no such client. Then we set the event mask to 0xffffff. The
|
||||
event then goes to clients selecting for events on the root window. */
|
||||
x_catch_errors (dpyinfo->display);
|
||||
x_catch_errors_for_lisp (dpyinfo);
|
||||
{
|
||||
bool propagate = !to_root;
|
||||
long mask = to_root ? 0xffffff : 0;
|
||||
|
|
@ -2838,7 +2842,8 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from,
|
|||
XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
|
||||
XFlush (dpyinfo->display);
|
||||
}
|
||||
x_uncatch_errors ();
|
||||
x_check_errors_for_lisp (dpyinfo, "Failed to send client event: %s");
|
||||
x_uncatch_errors_for_lisp (dpyinfo);
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
|
|
|
|||
39
src/xterm.c
39
src/xterm.c
|
|
@ -27836,6 +27836,36 @@ mark_xterm (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
/* Error handling functions for Lisp functions that expose X protocol
|
||||
requests. They are mostly like `x_catch_errors' and friends, but
|
||||
respect `x-fast-protocol-requests'. */
|
||||
|
||||
void
|
||||
x_catch_errors_for_lisp (struct x_display_info *dpyinfo)
|
||||
{
|
||||
if (!x_fast_protocol_requests)
|
||||
x_catch_errors (dpyinfo->display);
|
||||
else
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
}
|
||||
|
||||
void
|
||||
x_check_errors_for_lisp (struct x_display_info *dpyinfo,
|
||||
const char *format)
|
||||
{
|
||||
if (!x_fast_protocol_requests)
|
||||
x_check_errors (dpyinfo->display, format);
|
||||
}
|
||||
|
||||
void
|
||||
x_uncatch_errors_for_lisp (struct x_display_info *dpyinfo)
|
||||
{
|
||||
if (!x_fast_protocol_requests)
|
||||
x_uncatch_errors ();
|
||||
else
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
void
|
||||
syms_of_xterm (void)
|
||||
{
|
||||
|
|
@ -28141,4 +28171,13 @@ When nil, do not use the primary selection and synthetic mouse clicks
|
|||
to emulate the drag-and-drop of `STRING', `UTF8_STRING',
|
||||
`COMPOUND_TEXT' or `TEXT'. */);
|
||||
x_dnd_use_unsupported_drop = true;
|
||||
|
||||
DEFVAR_BOOL ("x-fast-protocol-requests", x_fast_protocol_requests,
|
||||
doc: /* Whether or not X protocol-related functions should wait for errors.
|
||||
When this is nil, functions such as `x-delete-window-property',
|
||||
`x-change-window-property' and `x-send-client-message' will wait for a
|
||||
reply from the X server, and signal any errors that occurred while
|
||||
executing the protocol request. Otherwise, errors will be silently
|
||||
ignored without waiting, which is generally faster. */);
|
||||
x_fast_protocol_requests = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1445,6 +1445,11 @@ extern bool x_text_icon (struct frame *, const char *);
|
|||
extern void x_catch_errors (Display *);
|
||||
extern void x_catch_errors_with_handler (Display *, x_special_error_handler,
|
||||
void *);
|
||||
extern void x_catch_errors_for_lisp (struct x_display_info *);
|
||||
extern void x_uncatch_errors_for_lisp (struct x_display_info *);
|
||||
extern void x_check_errors_for_lisp (struct x_display_info *,
|
||||
const char *)
|
||||
ATTRIBUTE_FORMAT_PRINTF (2, 0);
|
||||
extern void x_check_errors (Display *, const char *)
|
||||
ATTRIBUTE_FORMAT_PRINTF (2, 0);
|
||||
extern bool x_had_errors_p (Display *);
|
||||
|
|
|
|||
Loading…
Reference in a new issue