Why is X forwarding so slow on NixOS?

I have two computers in my life: a desktop at home, where my code lives; and a laptop which I mostly use to ssh into the desktop. The desktop runs Debian. Until recently, the laptop ran Windows, and I used Ubuntu in WSL to ssh into the desktop.

I switch my laptop to NixOS, and suddenly, my ssh -X sessions become glacially slow. It's worse when I'm on a different network from the desktop, but even when I'm on the local network, it's so slow that Gnome considers the program unresponsive.

A screenshot of the Emacs splash page with a popup reading "Emacs is not responding. You may choose to wait a short while for it to continue or force the app to quit entirely."

What is going on?

First things first, some sanity checks. I compile the latest stable version of Emacs from source on my laptop and on the desktop.

So whatever is happening here, it seems to be a problem with my laptop.

Next, I use xtruss to examine the X11 messages being sent between Emacs and the X server, both on my laptop and when X forwarding to the desktop. I examine the differences between them using ediff.

A screenshot of Emacs showing two buffers, xtruss.local.nots on top and xtruss.remote.nots below it. In the top buffer, a line starting "QueryExtension(name="XKEYBOARD") = {present=True" is highlighted. In the bottom buffer, a line starting "QueryExtension(name="XKEYBOARD") = {present=False" is highlighted A screenshot of Emacs showing two buffers, xtruss.local.nots on top and xtruss.remote.nots below it. The top buffer contains a large highlighted region which starts "QueryExtension(name="RENDER") = {present=True". The bottom buffer contains a smaller highlighted region which starts "QueryExtension(name="RENDER") = {present=False"

The earliest significant difference between these outputs is the lack of some extension support. xkeyboard is apparently not available when X forwarding. And there's some "RENDER" extension that's not working?

The Wikipedia page for the X Rendering Extension. The visible text reads: "The X Rendering Extension (Render or XRender) is an extension to the X11 core protocol to implement image compositing in the X server, to allow an efficient display of transparent images.

History
It was written by Keith Packard in 2000 and was first released with XFree86 version 4.0.1. Its design was influenced by rio, the windowing system for Plan 9.

Motivation
The core X Window System drawing protocol does not have a way to efficiently draw transparent objects: A computer display is composed of individual pixels, which can only show a single color at a time. Thus transparency can only be achieved by mixing the colors of the transparent object to be drawn with the background color (alpha compositing). However, the standard X protocol only allows drawing with solid color, so the only way to achieve transparency is to fetch the background color from the screen, mix it with the object color, then write it back, which is fairly inefficient.

Since many operations require transparency (for example spatial anti-aliasing, especially during font rasterization, and transparency effects in window managers, such as transparent windows or menus), this limitation caused problems, and Xrender was implemented to address it."

Well that looks like the kind of problem that could make things slow. Is there anything about X forwarding that might cause extensions to be disabled? Let's read the ssh man page.

The man page for ssh. The visible text reads "dash capital x: Enables X11 forwarding. This can also be specified on a per-host basis in a configuration file. X11 forwarding should be enabled with caution.  Users with the ability to bypass file permissions on the remote host (for the user's X authorization database) can access the local X11 display through the forwarded connection.  An attacker may then be able to perform activities such as keystroke monitoring. For this reason, X11 forwarding is subjected to X11 SECURITY extension restrictions by default.  Refer to the ssh -Y option and the ForwardX11Trusted directive in ssh_config(5) for more information. (Debian-specific: X11 forwarding is not subjected to X11 SECURITY extension restrictions by default, because too many programs currently crash in this mode.  Set the ForwardX11Trusted option to “no” to restore the upstream behaviour.  This may change in future depending on client-side improvements.) dash lowercase x: Disables X11 forwarding.  dash uppercase y: Enables trusted X11 forwarding.  Trusted X11 forwardings are not subjected to the X11 SECURITY extension controls.  (Debian-specific: In the default configuration, this option is equivalent to -X, since ForwardX11Trusted defaults to “yes” as described above.  Set the ForwardX11Trusted option to “no” to restore the upstream behaviour.  This may change in future de pending on client-side improvements.)"

Remember kids: always read the man page.

-Y are you like this

So, to recap,

The solution

Use -Y instead of -X, or add ForwardX11Trusted=yes as a line in your ~/.ssh/config

-Y is this so hard to Google?

Googling "ssh x forwarding slow nixos" doesn't answer this question, at least not on the first page of results. "ssh x forwarding slow" just brings up discussion about how the X11 protocol is old and inherently slow, which is not helpful. I struggle to find a search term which brings up this solution. If any readers happen to find one, please get in touch so I can hone my Google skills.

Even reading the ssh man page, it might not be obvious that -Y is the solution. The man page makes no mention of slowness, and only the Debian version of the page even mentions that (extremely common) problems can be caused by using -X instead of -Y (I happened to open that page when I was on the desktop, which was very helpful). It was obvious to me, but that's only because I'd spent an hour intercepting and examining the X11 messages.

Footnote: flags

The man page for SSH