piątek, 25 maja 2012

Multiseat setup - Configuring lightdm

There are two pieces of information: a good one and a bad one. The good one is that I did successfully run a Xephyr-based multiseat setup using lightdm as display manager. The bad one is that I managed to modify lightdm from the 1.0 series. It is happily found in Debian wheezy now, but newer releases will likely make it into testing eventually.

Anyway, lets get to configuring it!

The tree of the installed files looks very similar to the layout used for gdm2. The changed/modified entries are indicated in red.

/
|
+-/etc
|  |
|  +-/default
|  |  |
|  |  +-multiseat
|  |
|  +-/lightdm
|  |  |
|  |  +-lightdm.conf
|  |
|  +-/X11
|  |  |
|  |  +-xorg.conf
|  |
|  +-/init.d
|  |  |
|  |  +-multiseat
|  |
|  +-/udev
|  |  |
|  |  +-/rules.d
|  |     |
|  |     +-00-multiseat.rules
|  |
|  +-/multiseat
|     |
|     +-multiseat.conf
|     |
|     +-/scripts
|        |
|        +-helper-functions
|        |
|        +-match-and-name
|        |
|        +-multiseat-greeter
|        |
|        +-fake-greeter
|        |
|        +-Xephyr-seat
| 
+-/usr
    |
    +-/share
       |
       +-/xgreeters
          |
          +-multiseat-greeter.desktop
          |
          +-xinerama.desktop

Now let me explain the files.

lightdm.conf uses the three options added by the patches found on the branch in Launchpad. In [LightDM] there is common-vt=true. It means that all the X servers will use the same vt number. Since in a multiseat setup there are at least two seats, I used a convention that the default seat options are for the Xephyr seats proper, while the X server which covers all the monitors will use a dedicated configuration section of its own. The  xserver-pass-seat-name=true option means that the command used to start the X server (xserver-command) will be added a parameter whose value is the number of the DISPLAY for this X instance. The greeter-pass-seat-id=true means that the command used to start the greeter (found in the Exec entry of the .desktop file) will be added parameters whose values are the number of the DISPLAY for this X instance and the seat name as found in lightdm.conf. E.g., if there are [Seat:1] and [Seat:2], then the seat names will be 1 and 2. Thanks to the greeter-pass-seat-id=true option the multiseat-greeter is simpler and it moves only the Xephyr of interest to its desired position. The Xauthority files are also different than in the gdm-based setup. The fake-greeter just sleeps. But, in order to cleanly shut down, it handles the TERM signal and kills the sleep command if a signal is received. Thanks to the xserver-pass-seat-name=true option the Xephyr-seat is also a bit simpler, as it expects seat name and display number as parameters. The desktop files are used to specify the command to be run as a greeter.

The fake greeter is a kind of a hack. In fact it would be best to force lightdm not to start a greeter at all, just X server.

All works similar to the gdm2 case. Only the configuration of the display manager and location and names of Xauthority files are different.

Multiseat setup - lightdm.conf

[LightDM]
greeter-user=root
user-authority-in-system-dir=false
common-vt=true

[SeatDefaults]
xserver-command=/etc/multiseat/scripts/Xephyr-seat
xserver-allow-tcp=false
xserver-pass-seat-name=true
greeter-pass-seat-id=true
greeter-hide-users=true
greeter-session=multiseat-greeter
user-session=lightdm-xsession
session-wrapper=/etc/X11/Xsession

[Seat:0]
xserver-command=X -br -dpms -s 0 -novtswitch
xserver-pass-seat-name=false
greeter-pass-seat-id=false
greeter-session=xinerama

[Seat:1]
[Seat:2]

Multiseat setup - multiseat-greeter.desktop

[Desktop Entry]
Name=LightDM GTK+ Greeter
Comment=This runs the GTK+ greeter, it should only be run from LightDM
Exec=/etc/multiseat/scripts/multiseat-greeter
Type=Application
X-Ubuntu-Gettext-Domain=lightdm

Multiseat setup - xinerama.desktop

[Desktop Entry]
Name=LightDM Placeholder Greeter
Comment=This runs no greeter at all, it should only be run from LightDM
Exec=/etc/multiseat/scripts/fake-greeter
Type=Application
X-Ubuntu-Gettext-Domain=lightdm

Multiseat setup - fake-greeter

#!/bin/bash

pid_set=0

kill_sleep()
{
    if [ $pid_set -ne 0 ];
    then
        kill -15 $pid
    fi
    exit 0
}

trap 'kill_sleep' TERM

while true;

do

sleep 1000 &

pid=$!
pid_set=1

wait $pid

done

Multiseat setup - multiseat-greeter

#!/bin/bash
#
#multiseat wrapper around ligthdm greeter in order to position each Xephyr instance
#
. /etc/multiseat/scripts/helper-functions

PRIMARY=`get_conf 0 PRIMARY`
SEAT=$1

if [ $SEAT != $PRIMARY ]; then
    XEP=`XAUTHORITY=/var/run/lightdm/root/:0 xwininfo -root -children -display :0 | grep "Xephyr on :$SEAT" --max-count=1`;
    XEPHYR_WIN_ID=`echo ${XEP} | cut -d' ' -f1`;
    DISPLACEMENT=`get_conf $SEAT DISPLACEMENT`
    DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 wmctrl 2>&1 -v -i -r ${XEPHYR_WIN_ID} -e 0,${DISPLACEMENT},-1,-1;
fi

XAUTHORITY=/var/run/lightdm/root/:$2
DISPLAY=:$2
exec /usr/sbin/lightdm-gtk-greeter

Multiseat setup - Xephyr-seat

#!/bin/bash
#
# $1 - seat name of this Xephyr (from Seat:<n> in lightdm.conf)
# $2 - display number of this Xephyr

. /etc/multiseat/scripts/helper-functions

trap "" usr1

XEPHYR=/root/Xephyr
export DISPLAY=:0
export XAUTHORITY=/var/run/lightdm/root/:0

SEAT=$1

SIZE=`get_conf $SEAT SIZE`
KEYBOARD=`get_conf $SEAT KEYBOARD`
LAYOUT=`get_conf $SEAT LAYOUT`
MOUSE=`get_conf $SEAT MOUSE`
DPI=`get_conf $SEAT DPI`

exec $XEPHYR -retro -screen ${SIZE} -keybd evdev,,device=/dev/input/${KEYBOARD},xkbrules=evdev,xkbmodel=evdev,xkblayout=${LAYOUT} -mouse evdev,,device=/dev/input/${MOUSE} -dpi ${DPI} $2

gdm3 sucks!


So I really wanted to configure gdm3 for multiseat. Anyone knows how gdm3 is configured? Finding a manual for that seems a holy grail. And the gazillion of configuration files it requires is just too intimidating. Paraphrazing a saying about emacs, one could say that gdm3 is a fairly good operating system, it only lacks a decent display manager. So I decided I would give lightdm a try.


In Debian wheezy as of this writing there is lightdm 1.0.11. It does not have a good documentation either and I didn't manage to configure it out of the box. But, as its authors declare, it is of "low code complexity". Well, I did delve into the source code.

The result is promising. I am able to run two Xephyr seats now. Only the Xephyr currently found in wheezy (1.12.1-2) does not seem to support the "evdev" protocol for keyboard and mouse. That's too bad. I have to use an older binary from 1.7.7-11. Or do I? Anyone knows about Xephyr? My name is not Keith Packard...

You can browse the source code here. You can also fetch it using bazaar. Why bazaar? I use git for everyday work. Bazaar seems bazzare to me ;) But they use it on Launchpad. So what can you do? Here is a command which fetches the code from Launchpad

bzr branch lp:~andrzejtp2010/lightdm/lightdm-1.0-xephyr-multiseat

There is also a lightdm-xephyr-multiseat branch, but, at least now, it is no good.
autogen.sh, configure, make and enjoy! Or, if you prefer to build it the debian way, you can. It is even perhaps easier in a way. But first you need a patch. The easiest way is to fetch the source from Launchpad, and then generate a patch:

bzr diff -r1307 > multiseat.patch

And then something on the lines of:

apt-get source lightdm
sudo apt-get build-dep lightdm
dch -l 'Xephyr-based multiseat revision'
patch -p1 < multiseat.patch (mind the directory you are in)
dpkg-source -commit
debuild -uc -us

And there you go. You can install the package. Alternatively, it is just enough to only copy the resulting binary from your newly built package into /usr/sbin. Voila!

But how to configure it for multiseat? Stay tuned.