From 4ef1e4daf5e3569fed748f4487058d68a4c20ae6 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 3 Jul 2022 09:41:32 +0800 Subject: [PATCH] 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. --- lisp/x-dnd.el | 9 +++++++ src/xfns.c | 71 +++++++++++++++++++++++++++++++-------------------- src/xselect.c | 11 +++++--- src/xterm.c | 39 ++++++++++++++++++++++++++++ src/xterm.h | 5 ++++ 5 files changed, 104 insertions(+), 31 deletions(-) diff --git a/lisp/x-dnd.el b/lisp/x-dnd.el index 8bea3330121..f9e6b3198e5 100644 --- a/lisp/x-dnd.el +++ b/lisp/x-dnd.el @@ -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)) diff --git a/src/xfns.c b/src/xfns.c index adb4fb58bcf..ea2b1c0b3d3 100644 --- a/src/xfns.c +++ b/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; diff --git a/src/xselect.c b/src/xselect.c index 41fa837c5a4..2521dc171c0 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -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 (); } diff --git a/src/xterm.c b/src/xterm.c index 7ab22f256f6..4353b173cab 100644 --- a/src/xterm.c +++ b/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; } diff --git a/src/xterm.h b/src/xterm.h index 7c09073d765..26d6e4b3d03 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -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 *); -- 2.39.2