How do I prevent Cygwin's XWin Server automatically starting xterm?

UPDATE: This answer is now out of date. For an up-to-date answer, see user551570's answer below.

From man startxwin:

If no specific client program is given on the command line, startxwin will look for a file in the user's home directory called .startxwinrc to run as a shell script to start up client programs. If no such file exists, startxwin will use the following as a default:

xterm  -geometry  +1+1  -n  login  -display  :0

Thus, to avoid having any program start up when you start the X Server, you want a blank .startxwinrc file. Just run the following from a Cygwin prompt:

touch ~/.startxwinrc

It seems that startxwin's behavior has changed since @me_and originally answered the question, so simply creating an empty .startxwinrc in your home directory won't work anymore.

I found an answer here. In essence when the last command in .startxwinrc exits, the server will exit. If you want to prevent that, you can put this as the last line in your .startxwinrc:

sleep inf

This won't start any client programs, but will also prevent .startxwinrc from exiting.

As of November 2014, the latest versions of startxwin use xinit to start the Cygwin/X server, which is actually called XWin.exe. The process goes something like this:

  1. You call startxwin
  2. startxwin creates a new .Xauthority file and one called .serverauth.1234 (where 1234 changes each time you start X)
  3. startxwin sets up some client and server parameters
  4. startxwin calls xinit with the client and server parameters, including some optional shell scripts and a reference to the auth file.
  5. xinit starts the X server, running some of the rc scripts
  6. xinit starts the client (usually xterm) or client rc script. We want to avoid this
  7. When you close the client or the client rc script finishes, xinit shuts down the X server. If we avoid step 6, we also need to avoid this

It is possible to run XWin.exe directly from within a Bash login shell, without the surrounding tasks that startxwin and xinit perform. The main advantage of this is that it behaves like we want: the X server starts and remains running. Unfortunately, since there is no .Xauthority file passed during startup, your X server would permit any local process to connect to it, which is insecure.

Fortunately it's xinit that does most of the stuff we don't want. There's a quick hack that bypasses xinit but keeps the remaining elements of startxwin that are related to the server itself.

TL;DR: In startxwin, there's a line near the bottom that reads:

eval xinit \"$client\" $clientargs -- \"$server\" $display $serverargs

Change that line to:

eval \"$server\" $display $serverargs

From now on, the startxwin script will call XWin.exe directly, rather than calling xinit. Obviously this will disable any client rc scripts, but we didn't want those in the first place. It also means that X will continue running without needing a client process to keep it alive (i.e. keep xinit from killing it).