My “multiseat” (actually multiple X servers and one physical seat) configuration and zaphodkvm


I know I’m not the first to run with multiple X servers for a single user, but since these configurations are so rare I thought it would be good to put my details out there. I also wrote a program I call zaphodkvm to handle my input devices. My motivation for this project was to be able to use my second monitor to browse the web while using my primary monitor for fullscreen games that grab input devices, Dota 2 being my main concern at the moment (if you’d like to connect via Steam, hit me up for my Steam name via email). There is a program that does this for Windows called “Actual Multiple Monitors,” that is slightly more featureful, but it seems like getting something really similar to AMM on Linux would require a lot of window manager specific hacking. I could be wrong about that, but for now I went with a multiple X server approach rather than xrandr. That leads me to a discussion of:

Limitations

  • I can’t drag windows between the monitors, since they are separate X servers.
  • I may eventually add copy/paste sync but for now, the monitors have separate clipboards.
  • After I put my computer to sleep (ACPI S3, suspend-to-ram) and wake it up, the second X server dies along with any programs running on it. To restart the second monitor, if I want to use it, requires quitting the primary X server and reloading the module “nvidia”.
  • I use the package xbindkeys to handle keyboard shortcuts. For some reason, xbindkeys doesn’t seem to like zaphodkvm. xbindkeys will randomly start capturing my “up” key presses, making me restart xbindkeys to fix it. I might switch to Xfce keyboard shortcuts instead.
  • I use a simple mouse and keyboard. zaphodkvm won’t work for fancy mice and keyboards without a tiny bit of tweaking. If you need that let me know and it shouldn’t be hard to fix.

Hardware

I have an nVidia GTX 660 as my primary video card. I bought a second nVidia card, a GT 610, to run the second monitor. A separate graphics device is definitely required (no using multiple outputs on a single card). I initially tried using my onboard HD 4000 Intel graphics for the second monitor. Unfortunately, the kernel modesetting portions of the i915 driver did not interact well with nVidia’s binary driver. VTs 1 through 6 were messed up, and after a suspend/resume, the GTX 660 would go down, requiring a reboot. I read a thread somewhere saying that the kernel isn’t able to reset multiple cards at all after a resume, so I consider myself lucky that only the GT 610 is having suspend/resume issues.
My GTX 660
My GT 610: Zotac ZT-60607-10L (I needed a PCIe x1 card)

Xorg

lspci | grep VGA
01:00.0 VGA compatible controller: NVIDIA Corporation GK106 [GeForce GTX 660] (rev a1)
03:00.0 VGA compatible controller: NVIDIA Corporation GF119 [GeForce GT 610] (rev a1)

xorg.conf for the primary monitor:

Section "ServerLayout"
   Identifier     "Simple Layout"
   Screen      0  "Screen0" 0 0
   Option         "SingleCard" "true"
   InputDevice    "mouse0"     "CorePointer"
   InputDevice    "keyboard0"  "CoreKeyboard"
EndSection

#possibly only useful for archaic apps
Section "Files"
   FontPath        "/usr/share/fonts/misc/"
   FontPath        "/usr/share/fonts/Type1/"
   FontPath        "/usr/share/fonts/75dpi/"
   FontPath        "/usr/share/fonts/100dpi/"
   FontPath        "/usr/share/fonts/winfonts/"
   FontPath        "/usr/share/fonts/terminus/"
   FontPath        "/usr/share/fonts/ttf-bitstream-vera/"
   FontPath        "/usr/share/fonts/unifont/"
   FontPath        "/usr/share/fonts/freefont/"
EndSection

Section "ServerFlags"
   Option         "StandbyTime" "20"
   Option         "SuspendTime" "20"
   Option         "OffTime" "20"
   Option         "BlankTime" "0" # Blank the screen after 5 minutes (Fake)
   #For zaphodkvm
   Option         "AutoAddDevices" "false"
   Option         "AutoEnableDevices" "false"
   Option         "AllowMouseOpenFail" "on"
   Option         "AllowEmptyInput" "on"
EndSection

Section "InputClass"
   Identifier     "MyInputClass"
   Option         "Ignore"       "yes"
EndSection

Section "InputDevice"
   Identifier "keyboard0"
   Driver     "evdev"
   Option     "Device"     "/dev/input/by-id/zaphodkvm_kbd0"
   Option     "GrabDevice" "true"
EndSection

Section "InputDevice"
   Identifier "mouse0"
   Driver     "evdev"
   Option     "Device"     "/dev/input/by-id/zaphodkvm_mouse0"
   Option     "GrabDevice" "true"
EndSection

Section "Monitor"
   Identifier     "Monitor0"
   Option         "DPMS"
EndSection

Section "Device"
   Identifier     "Videocard0"
   Driver         "nvidia"
   Option         "NoLogo" "true"
   Option         "RandRRotation"
   Option         "ModeValidation" "NoHorizSyncCheck,NoVertRefreshCheck,NoVesaModes"
   Option         "AddARGBGLXVisuals" "True"
   Option         "ProbeAllGpus" "false"
   BusId          "PCI:1:0:0"
EndSection

Section "Screen"
   Identifier     "Screen0"
   Device         "Videocard0"
   Monitor        "Monitor0"
   DefaultDepth    24
EndSection

xorg.conf for the second monitor (I called this file nvidia610.conf):

Section "ServerLayout"
   Identifier     "Simple Layout"
   Screen         0  "Screen0" 0 0
   Option         "SingleCard" "true"
   InputDevice    "mouse0"     "CorePointer"
   InputDevice    "keyboard0"  "CoreKeyboard"
EndSection

#possibly only useful for archaic apps
Section "Files"
   FontPath        "/usr/share/fonts/misc/"
   FontPath        "/usr/share/fonts/Type1/"
   FontPath        "/usr/share/fonts/75dpi/"
   FontPath        "/usr/share/fonts/100dpi/"
   FontPath        "/usr/share/fonts/winfonts/"
   FontPath        "/usr/share/fonts/terminus/"
   FontPath        "/usr/share/fonts/ttf-bitstream-vera/"
   FontPath        "/usr/share/fonts/unifont/"
   FontPath        "/usr/share/fonts/freefont/"
EndSection

Section "ServerFlags"
   Option         "StandbyTime" "40"
   Option         "SuspendTime" "40"
   Option         "OffTime" "40"
   Option         "BlankTime" "0" # Blank the screen after 5 minutes (Fake)
   Option         "AutoAddDevices" "false"
   Option         "AutoEnableDevices" "false"
   Option         "AllowMouseOpenFail" "on"
   Option         "AllowEmptyInput" "on"
   #this should do the exact same thing as -novtswitch , but it's here just to make sure
   Option         "DontVTSwitch" "true"
EndSection

Section "InputClass"
   Identifier     "MyInputClass"
   Option         "Ignore"       "yes"
EndSection

Section "InputDevice"
   Identifier "keyboard0"
   Driver     "evdev"
   Option     "Device"    "/dev/input/by-id/zaphodkvm_kbd1"
   Option     "GrabDevice" "true"
EndSection

Section "InputDevice"
   Identifier "mouse0"
   Driver     "evdev"
   Option     "Device"    "/dev/input/by-id/zaphodkvm_mouse1"
   Option     "GrabDevice" "true"
EndSection

Section "Monitor"
   Identifier     "Monitor0"
   Option         "DPMS"
EndSection

Section "Device"
   Identifier     "Videocard0"
   Driver         "nvidia"
   Option         "NoLogo" "true"
   Option         "RandRRotation"
   Option         "ModeValidation" "NoHorizSyncCheck,NoVertRefreshCheck,NoVesaModes"
   Option         "AddARGBGLXVisuals" "True"
   Option         "ProbeAllGpus" "false"
   BusId          "PCI:3:0:0"
EndSection

Section "Screen"
   Identifier     "Screen0"
   Device         "Videocard0"
   Monitor        "Monitor0"
   DefaultDepth    24
EndSection

To start the primary monitor:

startx -- :0 -dpi 96

To start the second monitor:

startx -- :1 -dpi 96 vt8 -nolisten tcp -novtswitch -sharevts -config nvidia610.conf

zaphodkvm

In order to use a single keyboard and mouse to control both X servers, I needed to switch between them somehow. Somebody had done that using synergy; I tried the synergy approach and it didn’t work with Dota 2, so I had to write zaphodkvm. The synergy setup involved running both synergyc and synergys on the same computer and using non-hostname aliases for the screens. It would also probably be possible to use a physical KVM for this, but my experiences with USB KVMs have been less than optimal.

zaphodkvm-0.1.tgz

zaphodkvm - software KVM switch for multiple X servers
Copyright (C) 2014 by geekamole, released under the GNU GPLv3 or later (see COPYING)

libsuinput used and distributed under terms of the GNU GPLv3 or later, and obtained from
   http://tjjr.fi/sw/libsuinput/

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see http://www.gnu.org/licenses/

----------------------------------------------------------------------------------------

To install: simply

make

then copy the binary "zaphodkvm" to somewhere in your path. It should be run as root. I run it
early in the boot process which seems to resolve some race conditions with X and the VTs.
It runs in the foreground but it should be put in the background and disowned so that it runs
as a daemon while the system is running.

Since this program uses the uinput kernel module, be sure to enable it as built-in or module.
This program also uses the system command "fgconsole," which on Gentoo is in the sys-apps/kbd
package.

zaphodkvm implements a software-based KVM switch (really just the KM part) for a multiseat-X
Linux configuration. With only one user controlling all the physical input devices, it might
be more appropriately called a single-seat-multiple-X-server configuration.

zaphodkvm listens to all connected USB mice and keyboards, and supports hotplugging them via
libudev. It generates four virtual input devices, two "mice" and two "keyboards," and
redirects all input events from the real hardware to one or the other of the virtual
mice/keyboard sets. Double-tapping scroll lock switches the active virtual mice/keyboard set.
If your mice and keyboards aren't USB devices, you will need to change the udev filters in
zaphodkvm.cpp. The filters are there to keep the uinput devices from being detected as
physical input devices.

When uinput devices are created, they show up as a node with the form /dev/input/eventX.
Unlike a physical HID device, udev does not automatically create a persistent symlink in
/dev/input/by-id/. I had to add some rules to my /etc/udev/rules.d/00-custom-persistent.rules
file:

ATTRS{name}=="zaphodkvm_kbd0", DEVPATH=="*event*", SYMLINK+="input/by-id/zaphodkvm_kbd0"
ATTRS{name}=="zaphodkvm_kbd1", DEVPATH=="*event*", SYMLINK+="input/by-id/zaphodkvm_kbd1"
ATTRS{name}=="zaphodkvm_mouse0", DEVPATH=="*event*", SYMLINK+="input/by-id/zaphodkvm_mouse0"
ATTRS{name}=="zaphodkvm_mouse1", DEVPATH=="*event*", SYMLINK+="input/by-id/zaphodkvm_mouse1"

Then either reboot or do a "udevadm control --reload-rules" to activate the new rules. Once
the persistent symlinks are present, configure X servers to use the symlinks as their only
input devices.

I use simple, standard mice with the normal left/right buttons and clickwheel. I also use
standard keyboards. Fancy mice or keyboards might require you to add additional calls to
suinput_enable_event() in zaphodkvm.cpp, to turn on the additional buttons. I also discard
all the raw scancodes from the physical /dev/input/eventX devices, but those might be
useful to your application.

Since the virtual terminals 1-6 tend to latch onto the uinput device nodes when they are
created, I initially had issues with duplicate keystrokes when the X servers weren't running
or when I switched VTs with Ctrl-Alt-FX. Now, zaphodkvm checks to see if VT7 is the active
virtual terminal, and only passes on input events when it is. The X server on VT8 uses
-sharevts and DontVTSwitch so it doesn't affect fgconsole/VT detection.

I set this up for a two-X-server system, but it could be easily extended to an arbitrary
number of X servers.

So far it’s been pretty nice to adjust my system volume, browse the web, and do email while listening to and watching Dota 2 party chat. It’s also nice to have the Dota 2 wiki open while playing unfamiliar heroes. Finally–yes, this stuff really works here despite it being posted on April 1 ๐Ÿ™‚


5 responses to “My “multiseat” (actually multiple X servers and one physical seat) configuration and zaphodkvm”

  1. Hi! Is your config still working well? I have a 4th gen core i3 CPU with graphics support and I am considering to buy a GeForce GT 610 besides to achieve multi-seat on Ubuntu 14.04. Do you they will work together?
    Thanks for your answer ๐Ÿ™‚

  2. Sorry about the delay; yes, it is all still working well. I don’t know for certain whether your attempt would work, since you would have the Intel device as the primary server, but my guess would be that it probably (60%) won’t work due to the modesetting conflicts. I had my issues when the nVidia driver was already running and I started the Intel driver; so maybe starting the Intel first will work better.

  3. Hi, I’m just wondering if you managed to fix that suspend problem on second monitor?
    I know it’s passed 5 years from your post, but I can’t find any proper solution for this problem. ๐Ÿ™

    • No, I never fixed it, but my workaround is to run a script when I come out of suspend that
      1) checks to see if any programs are open (using xlsclients)
      2) if not, kills the X server, unloads the nVidia module, and restarts X

      which 95% of the time, causes the second screen to start working again. Sometimes I need to do a full reboot.

Leave a Reply to Iljo Cancel reply

Your email address will not be published. Required fields are marked *