Dual-seat X on a dual-head graphics card using Xgl Jori Liesenborgs (jori.liesenborgs@gmail.com) March 17, 2007 1. Introduction This document describes how you can use a dual-head graphics card to create a dual-seat X configuration. The approach is very general and can easily be extended to more seats, creating a multi-seat X configuration. The dual-seat configuration is created by starting a 'master' X server which initializes the two monitors connected to the video card. On each screen, an Xgl server is then started and using a separate program, events from keyboards and mice are redirected to the appropriate Xgl servers. 2. Disclaimer This document is distributed in the hope that it will be useful, but without any warranty. The information in this document is correct to the best of my knowledge, but there's a always a chance I've made some mistakes, so don't follow everything too blindly, especially if it seems wrong. Nothing here should have a detrimental effect on your computer, but just in case I take no responsibility for any damages incurred from the use of the information contained herein. 3. Configuring the 'master' X server Here are some sections from my own xorg.conf file, illustrating how two monitors can be controlled by the main X server. Adjust where needed. I've defined two monitor sections: Section "Monitor" Identifier "My Monitor0" HorizSync 31.5 - 64.3 VertRefresh 40-65 EndSection Section "Monitor" Identifier "My Monitor1" HorizSync 31.5 - 64.3 VertRefresh 40-65 EndSection Two devices, corresponding to the two outputs of my video card: Section "Device" Identifier "nvidia0" Driver "nvidia" BusID "PCI:01:00:0" Screen 0 Option "UseDisplayDevice" "CRT-1" Option "RenderAccel" "true" EndSection Section "Device" Identifier "nvidia1" Driver "nvidia" BusID "PCI:01:00:0" Screen 1 Option "UseDisplayDevice" "CRT-0" Option "RenderAccel" "true" EndSection Two screens, each one connecting a device to a monitor: Section "Screen" Identifier "Screen0" Device "nvidia0" Monitor "My Monitor0" DefaultDepth 24 Subsection "Display" Depth 24 Modes "1280x1024" ViewPort 0 0 EndSubsection EndSection Section "Screen" Identifier "Screen1" Device "nvidia1" Monitor "My Monitor1" DefaultDepth 24 Subsection "Display" Depth 24 Modes "1280x1024" ViewPort 0 0 EndSubsection EndSection Finally, the server layout tells the X server to actually use both screens. Section "ServerLayout" Identifier "Layout1" Screen 0 "Screen0" Screen 1 "Screen1" rightOf "Screen0" InputDevice "Keyboard1" "CoreKeyboard" InputDevice "Mouse1" "CorePointer" EndSection 4. Helper programs 4.1 XglScript.sh You may have to adjust some settings in the script to reflect your own configuration. Note that if you don't copy the XglScript.sh file in /usr/local/sbin, you'll have to adjust the 'command' lines in the gdm.conf settings below. 4.2 XevdevScript.sh Here too, you may have to adjust some settings at the top of the script. The gdm.conf settings below assume that this script is installed in the directory /usr/local/sbin. 4.3 The 'startsched' program This allows you to start a program with a higher priority. Something like the 'nice' program, but with real-time priorities. I've found it helpful to start 'xevdevserver' with a real-time priority, to make sure that input events are handled right away. The XglScript.sh and XevdevScript.sh files look in /usr/local/sbin/ for this program, unless you modify the scripts. To compile the program, simply type: gcc -o startsched startsched.c 4.4 XevdevServer This program can capture a keyboard and mouse, and redirect the events to a specified X display. Compile xevdevserver and copy the executable to any location you like. I've installed mine in /usr/local/sbin and this is the default location in the XglScript.sh and XevdevScript.sh files. You'll need xevdevserver-1.3.0 for the scripts to work. 5. GDM configuration 5.1 First approach In this approach, the main X server is started first. Then, when each Xgl server is started, an xevdevserver instance is started at the same time. In the [daemon] section, set: AlwaysRestartServer=true For the servers you'll have to do something like this: [servers] 0=MainServer 1=Xgl1 2=Xgl2 [server-MainServer] name=MainServer command=/usr/X11R6/bin/Xorg handled=false flexible=false [server-Xgl1] name=Xgl1 command=/usr/local/sbin/XglScript.sh -display :0.1 -keyboard /dev/input/event4 -mouse /dev/input/event1 -dpi 86 -fullscreen -ac -accel glx:pbuffer -accel xv:pbuffer -xkbmap be -softcursor handled=true flexible=false [server-Xgl2] name=Xgl2 command=/usr/local/sbin/XglScript.sh -display :0.0 -keyboard /dev/input/event2 -mouse /dev/input/event0 -dpi 86 -fullscreen -ac -accel glx:pbuffer -accel xv:pbuffer -xkbmap be handled=true flexible=false 5.2 Second approach In this second approach, all the required xevdevserver instances are started even before the actual main X server is started. These xevdevserver instances keep trying to connect to their Xgl servers, so shortly after an Xgl server has been started, it will receive the input from the corresponding xevdevserver. In the [daemon] section, set: AlwaysRestartServer=true For the servers you'll have to do something like this: [servers] 0=MainServer 1=Xgl1 2=Xgl2 [server-MainServer] name=MainServer command=/usr/local/sbin/XevdevScript.sh -xevdev ":1,/dev/input/event4,/dev/input/event1" -xevdev ":2,/dev/input/event2,/dev/input/event0" handled=false flexible=false [server-Xgl1] name=Xgl1 command=/usr/local/sbin/XglScript.sh -display :0.1 -dpi 86 -fullscreen -ac -accel glx:pbuffer -accel xv:pbuffer -xkbmap be -softcursor handled=true flexible=false [server-Xgl2] name=Xgl2 command=/usr/local/sbin/XglScript.sh -display :0.0 -dpi 86 -fullscreen -ac -accel glx:pbuffer -accel xv:pbuffer -xkbmap be handled=true flexible=false The script XevdevScript.sh accepts parameters like -xevdev ":1,/dev/input/event4,/dev/input/event1" This means that an xevdevserver will be started, redirecting input events from the keyboard device /dev/input/event4 and mouse device /dev/input/event1 to the Xgl display :1 5.3 General remarks Make sure you adjust the input devices and your keyboard map. Instead of using identifiers like /dev/input/event0, you can also use other identifiers listed in /proc/bus/input/devices. For example, for an entry like I: Bus=0003 Vendor=045e Product=0040 Version=0300 N: Name="Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)" P: Phys=usb-0000:00:03.0-1/input0 S: Sysfs=/class/input/input0 H: Handlers=mouse0 event0 B: EV=7 B: KEY=70000 0 0 0 0 0 0 0 0 B: REL=103 you can use -mouse usb-0000:00:03.0-1/input0 or even -mouse "Microsoft Microsoft 3-Button Mouse with IntelliEye(TM)" and something similar for '-xevdev' arguments. The script XglScript.sh will translate such identifiers to an appropriate device name like /dev/input/event0. Be careful when using the 'Name' identifier as this might not be unique. Unfortunately only one of the monitors connected to a single card can use the hardware cursor, which is why the software cursor has been enabled in one of the Xgl instances. I'm not sure which 'accel' options are best, you can always take a look at http://www.freedesktop.org/wiki/Software_2fXgl for some other settings.