Add knob to make `mouse-position' faster on X

* etc/PROBLEMS (Improving performance with slow X connections):
Add new advice.
* src/xterm.c (XTmouse_position): Add alternative
implementations for slow connections.
(syms_of_xterm): Add new variable to enable them.
* src/xterm.h (struct x_display_info): Update commentary.
This commit is contained in:
Po Lu 2022-11-18 09:08:59 +08:00
parent 682b068ba7
commit 32e29afe64
3 changed files with 170 additions and 30 deletions

View file

@ -1640,16 +1640,21 @@ X expects to find it.
*** Improving performance with slow X connections.
There are several ways to improve this performance, any subset of which can
be carried out at the same time:
There are several ways to improve this performance, any subset of
which can be carried out at the same time:
1) If you don't need X Input Methods (XIM) for entering text in some
1) Use the "--with-x-toolkit=no" build of Emacs. By not relying on
any toolkit (exhibiting potentially slow behavior), it has been
made very fast over networks exhibiting high latency, but suitable
bandwidth.
2) If you don't need X Input Methods (XIM) for entering text in some
language you use, you can improve performance on WAN links by using
the X resource useXIM to turn off use of XIM. This does not affect
the use of Emacs's own input methods, which are part of the Leim
package.
2) If the connection is very slow, you might also want to consider
3) If the connection is very slow, you might also want to consider
switching off scroll bars, menu bar, and tool bar. Adding the
following forms to your .emacs file will accomplish that, but only
after the initial frame is displayed:
@ -1665,26 +1670,45 @@ be carried out at the same time:
Emacs.menuBar: off
Emacs.toolBar: off
3) Use ssh to forward the X connection, and enable compression on this
4) Use ssh to forward the X connection, and enable compression on this
forwarded X connection (ssh -XC remotehostname emacs ...).
4) Use lbxproxy on the remote end of the connection. This is an interface
to the low bandwidth X extension in most modern X servers, which
improves performance dramatically, at the slight expense of correctness
of the X protocol. lbxproxy achieves the performance gain by grouping
several X requests in one TCP packet and sending them off together,
instead of requiring a round-trip for each X request in a separate
packet. The switches that seem to work best for emacs are:
-noatomsfile -nowinattr -cheaterrors -cheatevents
Note that the -nograbcmap option is known to cause problems.
For more about lbxproxy, see:
Keep in mind that this does not help with latency problems, only
andwidth ones.
5) Use lbxproxy on the remote end of the connection. This is an
interface to the low bandwidth X extension in some outdated X
servers, which improves performance dramatically, at the slight
expense of correctness of the X protocol. lbxproxy achieves the
performance gain by grouping several X requests in one TCP packet
and sending them off together, instead of requiring a round-trip
for each X request in a separate packet. The switches that seem to
work best for emacs are: -noatomsfile -nowinattr -cheaterrors
-cheatevents Note that the -nograbcmap option is known to cause
problems. For more about lbxproxy, see:
http://www.x.org/archive/X11R6.8.0/doc/lbxproxy.1.html
5) If copying and killing is slow, try to disable the interaction with the
Keep in mind that lbxproxy and the LBX extension are now obsolete.
6) If copying and killing is slow, try to disable the interaction with the
native system's clipboard by adding these lines to your .emacs file:
(setq interprogram-cut-function nil)
(setq interprogram-paste-function nil)
7) If selecting text with the mouse is slow, the main culprit is
likely `select-active-regions', coupled with a program monitoring
the clipboard on the X server you are connected to. Try turning
that off.
However, over networks with moderate to high latency, with no
clipboard monitor running, the bottleneck is likely to be
`mouse-position' instead. Set the variable
`x-use-fast-mouse-position' to either any non-nil value, or to the
symbol `really-fast' if that is still too slow. Doing so will also
cause Emacs features that relies on accurate mouse position
reporting to stop working reliably.
*** Emacs gives the error, Couldn't find per display information.
This can result if the X server runs out of memory because Emacs uses

View file

@ -14261,8 +14261,113 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
Time *timestamp)
{
struct frame *f1, *maybe_tooltip;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
struct x_display_info *dpyinfo;
bool unrelated_tooltip;
Lisp_Object tail, frame;
dpyinfo = FRAME_DISPLAY_INFO (*fp);
if (!NILP (Vx_use_fast_mouse_position))
{
/* The user says that Emacs is running over the network, and a
fast approximation of `mouse-position' should be used.
Depending on what the value of `x-use-fast-mouse-position'
is, do one of two things: only perform the XQueryPointer to
obtain the coordinates from the last mouse frame, or only
return the last mouse motion frame and the
last_mouse_motion_x and Y. */
if (!EQ (Vx_use_fast_mouse_position, Qreally_fast))
{
int root_x, root_y, win_x, win_y;
unsigned int mask;
Window dummy;
/* This means that Emacs should select a frame and report
the mouse position relative to it. The approach used
here avoids making multiple roundtrips to the X server
querying for the window beneath the pointer, and was
borrowed from haiku_mouse_position in haikuterm.c. */
FOR_EACH_FRAME (tail, frame)
{
if (FRAME_X_P (XFRAME (frame)))
XFRAME (frame)->mouse_moved = false;
}
if (gui_mouse_grabbed (dpyinfo)
&& !EQ (track_mouse, Qdropping)
&& !EQ (track_mouse, Qdrag_source))
/* Pick the last mouse frame if dropping. */
f1 = x_display_list->last_mouse_frame;
else
/* Otherwise, pick the last mouse motion frame. */
f1 = x_display_list->last_mouse_motion_frame;
if (!f1 && FRAME_X_P (SELECTED_FRAME ()))
f1 = SELECTED_FRAME ();
if (!f1 || (!FRAME_X_P (f1) && (insist > 0)))
FOR_EACH_FRAME (tail, frame)
if (FRAME_X_P (XFRAME (frame)) &&
!FRAME_X_P (XFRAME (frame)))
f1 = XFRAME (frame);
if (f1 && FRAME_TOOLTIP_P (f1))
f1 = NULL;
if (f1 && FRAME_X_P (f1) && FRAME_X_WINDOW (f1))
{
if (!x_query_pointer (dpyinfo->display, FRAME_X_WINDOW (f1),
&dummy, &dummy, &root_x, &root_y,
&win_x, &win_y, &mask))
/* The pointer is out of the screen. */
return;
remember_mouse_glyph (f1, win_x, win_y,
&dpyinfo->last_mouse_glyph);
x_display_list->last_mouse_glyph_frame = f1;
*bar_window = Qnil;
*part = scroll_bar_nowhere;
/* If track-mouse is `drag-source' and the mouse pointer is
certain to not be actually under the chosen frame, return
NULL in FP. */
if (EQ (track_mouse, Qdrag_source)
&& (win_x < 0 || win_y < 0
|| win_x >= FRAME_PIXEL_WIDTH (f1)
|| win_y >= FRAME_PIXEL_HEIGHT (f1)))
*fp = NULL;
else
*fp = f1;
*timestamp = dpyinfo->last_mouse_movement_time;
XSETINT (*x, win_x);
XSETINT (*y, win_y);
}
}
else
{
/* This means Emacs should only report the coordinates of
the last mouse motion. */
if (dpyinfo->last_mouse_motion_frame)
{
*fp = dpyinfo->last_mouse_motion_frame;
*timestamp = dpyinfo->last_mouse_movement_time;
*x = make_fixnum (dpyinfo->last_mouse_motion_x);
*y = make_fixnum (dpyinfo->last_mouse_motion_y);
*bar_window = Qnil;
*part = scroll_bar_nowhere;
dpyinfo->last_mouse_motion_frame->mouse_moved = false;
}
}
return;
}
block_input ();
@ -31131,6 +31236,7 @@ With MS Windows, Haiku windowing or Nextstep, the value is t. */);
DEFSYM (Qimitate_pager, "imitate-pager");
DEFSYM (Qnewer_time, "newer-time");
DEFSYM (Qraise_and_focus, "raise-and-focus");
DEFSYM (Qreally_fast, "really-fast");
DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
doc: /* Which keys Emacs uses for the ctrl modifier.
@ -31410,4 +31516,19 @@ not bypass window manager focus stealing prevention):
- The symbol `raise-and-focus', which means to raise the window and
focus it manually. */);
Vx_allow_focus_stealing = Qnewer_time;
DEFVAR_LISP ("x-use-fast-mouse-position", Vx_use_fast_mouse_position,
doc: /* How to make `mouse-position' faster.
`mouse-position' and `mouse-pixel-position' default to querying the X
server for the window under the mouse pointer. This results in
accurate results, but is also very slow when the X connection has
moderate to high latency. Setting this variable to a non-nil value
makes Emacs query only for the position of the pointer, which is
usually faster. Doing so improves the performance of dragging to
select text over slow X connections.
If that is still too slow, setting this variable to the symbol
`really-fast' will make Emacs return only cached values. */);
Vx_use_fast_mouse_position = Qnil;
}

View file

@ -580,7 +580,9 @@ struct x_display_info
Time last_user_time;
/* Position where the mouse was last time we reported a motion.
This is a position on last_mouse_motion_frame. */
This is a position on last_mouse_motion_frame. It is used in
some situations to report the mouse position as well: see
XTmouse_position. */
int last_mouse_motion_x;
int last_mouse_motion_y;
@ -1605,22 +1607,15 @@ SELECTION_EVENT_DISPLAY (struct selection_input_event *ev)
extern void x_free_gcs (struct frame *);
extern void x_relative_mouse_position (struct frame *, int *, int *);
extern void x_real_pos_and_offsets (struct frame *f,
int *left_offset_x,
int *right_offset_x,
int *top_offset_y,
int *bottom_offset_y,
int *x_pixels_diff,
int *y_pixels_diff,
int *xptr,
int *yptr,
int *outer_border);
extern void x_real_pos_and_offsets (struct frame *, int *, int *, int *,
int *, int *, int *, int *, int *,
int *);
extern void x_default_font_parameter (struct frame *, Lisp_Object);
/* From xrdb.c. */
XrmDatabase x_load_resources (Display *, const char *, const char *,
const char *);
extern XrmDatabase x_load_resources (Display *, const char *, const char *,
const char *);
extern const char *x_get_string_resource (void *, const char *, const char *);
/* Defined in xterm.c */