Single graphics card multi-seat Ubuntu Linux

Setting up multi-seat configurations under Ubuntu proved to be quite difficult; here I describe how I did it.

Multi-seat computer configuration
Firstly, system information: I'm Ubuntu 10.10, the most recent version, at time of writing of the popular Linux distribution - different distributions may differ slightly. I have an Gigabyte 8400GS PCI Express (PCI-E) card (containing an nVidia 8400 chipset), with one monitor on the DVI (digital) port, and one on the VGA (analogue) port. The motherboard (GeForce6100PM-M2 from Elitegroup / ECS) has onboard graphics, but the BIOS seems to stop the onboard graphics adaptor working when a PCI-E graphics card is added (and no configuration options either on the BIOS that shipped with the motherboard, or after reflashing with the latest version seemed to change that), but using one port on each graphics device worked.

What I was trying to achieve: A multi-seat configuration means having several 'seats' or 'consoles' on set up on the same computer. Each seat has its own screen, keyboard, and mouse, and is used independently by each person. This differs from the (probably more common) multi-head setup, where one user has two screens in front of them.

Secondly, I'm describing how to set it up where both screens share a graphics card. This is the more complicated case, because if you have two seats, each with a different graphics card, you can just run two independent X servers, as described here. If you have two monitors on the same graphics card, you can't do that directly, because Xorg wants to have exclusive control of a graphics card. Instead, you have to set up one main X server (per card) with two (or more) displays on it, and then use one Xephyr instance for each seat. Xephyr is an X server which runs inside another X server; each user has their own Xephyr X server which runs inside the main X server. The main X server has no keyboards or pointers, and instead Xephyr handles them using the evdev framework.

Xephyr is part of the Xorg X server, and Ubuntu comes with Xephyr as a separate package. Unfortunately, however, when building Xephyr, if you want it to support evdev, you need to give it a special configure option, and the version that comes with Ubuntu 10.10 has this turned off. The best solution is to build Xephyr from source. This requires installing some development packages - I had to install the following (but I already had many development packages installed - you might have to install more):

sudo apt-get install x11proto-gl-dev x11proto-bigreqs-dev x11proto-composite-dev x11proto-core-dev x11proto-damage-dev x11proto-dmx-dev x11proto-dri2-dev x11proto-fixes-dev x11proto-fonts-dev x11proto-gl-dev x11proto-input-dev x11proto-kb-dev x11proto-print-dev x11proto-randr-dev x11proto-record-dev x11proto-render-dev x11proto-resource-dev x11proto-scrnsaver-dev x11proto-video-dev x11proto-xcmisc-dev x11proto-xext-dev x11proto-xf86bigfont-dev x11proto-xf86dga-dev x11proto-xf86dri-dev x11proto-xf86vidmode-dev x11proto-xinerama-dev x11proto-xf86misc-dev libxkbfile-dev libxfont-dev libpciaccess-dev libglib2.0-dev libudev-dev libselinux-dev libdbus-1-dev libpixman-1-dev libxv-dev

Download xorg-server from here, and configure and build it with:

./configure --enable-kdrive --enable-xephyr --enable-xfake --enable-xfbdev --enable-kdrive-kbd --enable-kdrive-mouse --enable-kdrive-evdev --enable-glx-tls
make
make install

Note that this installs it in /usr/local instead of /usr/, so your system X.org stays installed.

The next step is to get your X server working. It helps to log in remotely to test this. This is somewhat hardware dependent, but it involves editing /etc/X11/xorg.conf or using a configuration tool to get both screens enabled. Follow a multi-head tutorial to get this working. When you have, edit the ServerLayout to comment out all the InputDevice lines. You also want the following in your ServerLayout section, to stop X adding devices automatically:

    Option         "AutoEnableDevices" "false"
    Option         "AutoAddDevices"  "false"
    Option         "AllowEmptyInput"       "true"

Note that if you start X with such a configuration, you won't be able to do anything, as all pointers and mice are disabled, so it is easier to do it from another computer over the network.

Next, you want to set up your Xephyr programs. The gdm version that comes with Ubuntu 10.10 apparently doesn't support multi-seat, and kdm seems to crash when used with Xephyr. So instead, I simply set up a service to start gnome-session on Xephyr for the user expected on each seat (and for security, start a locked screensaver on each seat). This simple approach will only work if there is always the same user on each seat, but is probably good enough for many applications.

I made a shell script in '/usr/bin/start-screens':

#!/bin/bash
start-user1-screen >/dev/null&
exec start-user2-screen

I also made a script, '/usr/bin/startup-X':

#!/bin/bash

export XAUTHORITY=/var/run/xauth/0.auth
export DISPLAY=:2.0
if [[ $(ps ax |grep " X " |grep " :0" | wc -l) == 0 ]]; then
  nohup /usr/bin/X vt08 -dpms -s 0 :0 >/dev/null 2>/dev/null &
  xauth -f /var/run/xauth/0.auth generate :0.0 .
fi

This checks if X is running, and starts it if it isn't. The -dpms to turn off power saving is very important - otherwise your master X screen will lock up after a certain amount of inactivity, because there are no pointers at all on that server, and no amount of moving the mice in Xephyr will restore it. Likewise, the -s 0 to turn off screen blanking. The vt08 just tells it which virtual terminal to run on.

My user scripts look like this (/usr/bin/start-user1-screen):

#!/bin/bash

while true; do
/usr/bin/startup-X
export DISPLAY=:0.0
export XAUTHORITY=/var/run/xauth/0.auth
/usr/local/bin/Xephyr :1 -dpms -s 0 -screen 1360x768+0x0 -keybd evdev,,device=/dev/input/by-id/usb-Plus_More_Enterprise_LTD._USB-compliant_keyboard-event-kbd,xkbrules=evdev,xkbmodel=pc105,xkblayout=us -mouse evdev,,device=/dev/input/by-id/usb-15d9_USB_Mouse-event-mouse vt09 -once&
sleep 1
export DISPLAY=:1.0
xauth -f /var/run/xauth/1.auth generate :1.0 .
sudo chown user1.user1 /var/run/xauth/1.auth
export XAUTHORITY=/var/run/xauth/1.auth
su -c  gnome-session user1

sleep 5
done

Note that the paths to devices in /dev/input/by-id need to be adjusted to match the correct pointer and keyboard for the user's seat, and the screen size needs to be adjusted to match the actual size of the screen. For the other user (/usr/bin/start-user2-screen):

#!/bin/bash

sleep 1
while true; do
/usr/bin/startup-X

export DISPLAY=:0.1
export XAUTHORITY=/var/run/xauth/0.auth
/usr/local/bin/Xephyr :2 -dpms -s 0 -screen 1440x900 -keybd evdev,,,device=/dev/input/by-id/usb-0b38_USB-compliant_keyboard-event-kbd,xkbrules=evdev,xkbmodel=pc105,xkblayout=us -mouse evdev,,,device=/dev/input/by-path/platform-i8042-serio-1-event-mouse vt07&
sleep 1
export DISPLAY=:2.0
xauth -f /var/run/xauth/2.auth generate :2.0 .
sudo chown user2.user2 /var/run/xauth/2.auth
export XAUTHORITY=/var/run/xauth/2.auth
su -c gnome-session user2

sleep 5;
done

Again, the device paths need to be changed, and of course in all of the above you want to change user1 and user2 to the real user names. Note that in the start-user2-screen script, the mouse is a PS2 mouse - and the path is a /dev/input/by-path/platform-i8042* style path - but it could be like the others if it was a USB mouse.

Finally, to make everything launch on system startup, I needed to make an upstart configuration (people on other Linux systems might need an init script instead). In '/etc/init/xlogin.conf':

# Sets up X seats

start on (filesystem
          and started dbus
          and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1
               or stopped udevtrigger))
stop on runlevel [016]

emits starting-dm

script
    exec /usr/bin/start-screens
end script

One problem I'm experiencing is that the external USB hub holding one of the mice occasionally loses the connection for a second or less - which is enough to render a session useless, because devices are only added to Xephyr when it starts up, and if they stop being available, they get deleted. The only solution is to patch Xephyr - I'm working on a patch to do this. In the meantime, you will want to make sure you have good USB connections to your input devices, and you only unplug them, even temporarily, if you can live with them not working again for that X session.

Update: I made a patch for Xephyr to stop input devices disappearing if they are briefly unplugged. Apply the patch on that bug report to your xorg-server before building it if this is an issue for you.

AttachmentSize
Multiseat.jpg10.89 KB