Banging on multiple heads

I spent a bit of time each of the past few weeks trying out different graphics cards to drive two displays—a multihead configuration. Presently, I’m using an older ATI Radeon 7000-based card to run two displays at 1600 × 1200 each. The radeon driver included with the X.org X server can knit these together into a single display with an effective resolution of 3200 × 1200.

Other folks are using nVidia drivers to get similar configurations.

Once I had this setup running, I started to see familiar applications fail with a pleasant message:

$ gvim
The program 'gvim' received an X Window System error.
This probably reflects a bug in the program.
The error was 'BadWindow (invalid Window parameter)'.
(Details: serial 13 error_code 3 request_code 128 minor_code 2)
(Note to programmers: normally, X errors are reported asynchronously;
that is, you will receive the error a while after causing it.
To debug your program, run it with the --sync command line
option to change this behavior. You can then get a meaningful
backtrace from your debugger if you break on the gdk_x_error() function.)

Dave Powell helped me to use xscope to watch the X11 protocol requests. This, and a little code browsing allows us a diagnosis.

It turns out that Xsun and Xorg use different implementations of the Xinerama extension (but with similar names). As far as I can tell, the standard behaviour changed after Sun developed support for a draft proposal. Now, a few years later, the applications know how to deal with both versions. With Xorg though, you now have a Sun system which doesn’t speak Sun’s Xinerama variant–hence our error message. Alan knows how to fix this for real but, after looking at libgdk startup, it’s pretty easy to work around this with a preloaded shared object.

All we do is pretend that our display can’t do Sun’s Xinerama. That means we need a function like

$ cat > xin_shim.c
int
XineramaGetState()
{
return (0);
}
^D
We then compile it into a shared object
$ cc -o xin_shim.so -G -Kpic xin_shim.c
or we could freely compile it into a shared object
$ which gcc
/usr/sfw/bin/gcc
$ gcc -o xin_shim.so -G -fpic xin_shim.c

Then, to use your shim, you use LD_PRELOAD (with an absolute path)

$ LD_PRELOAD=`pwd`/xin_shim.so gvim
[happy editing...]

Because xin_shim.so isn’t in /usr/lib/secure, you may see messages from setuid processes as the linker refuses to preload your potentially unsafe object. The message looks something like

ld.so.1: /usr/lib/utmp_update: warning:
/home/sch/src/preloads/xin_shim.so: open failed: illegal insecure pathname