summary refs log tree commit diff
path: root/nixos/modules/services/x11
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-10 13:28:20 +0200
commit5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010 (patch)
treea6c0f605be6de3f372ae69905b331f9f75452da7 /nixos/modules/services/x11
parent6070bc016bd2fd945b04347e25cfd3738622d2ac (diff)
downloadnixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.gz
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.bz2
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.lz
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.xz
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.tar.zst
nixpkgs-5c1f8cbc70cd5e6867ef6a2a06d27a40daa07010.zip
Move all of NixOS to nixos/ in preparation of the repository merge
Diffstat (limited to 'nixos/modules/services/x11')
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix75
-rw-r--r--nixos/modules/services/x11/desktop-managers/e17.nix30
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome.nix42
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix169
-rw-r--r--nixos/modules/services/x11/desktop-managers/none.nix7
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix90
-rw-r--r--nixos/modules/services/x11/desktop-managers/xterm.nix36
-rw-r--r--nixos/modules/services/x11/display-managers/auto.nix52
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix283
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix151
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix119
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix113
-rw-r--r--nixos/modules/services/x11/hardware/multitouch.nix60
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix122
-rw-r--r--nixos/modules/services/x11/hardware/wacom.nix47
-rw-r--r--nixos/modules/services/x11/terminal-server.nix66
-rw-r--r--nixos/modules/services/x11/window-managers/awesome.nix42
-rw-r--r--nixos/modules/services/x11/window-managers/compiz.nix63
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix61
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix43
-rw-r--r--nixos/modules/services/x11/window-managers/icewm.nix42
-rw-r--r--nixos/modules/services/x11/window-managers/metacity.nix42
-rw-r--r--nixos/modules/services/x11/window-managers/none.nix12
-rw-r--r--nixos/modules/services/x11/window-managers/openbox.nix30
-rw-r--r--nixos/modules/services/x11/window-managers/twm.nix42
-rw-r--r--nixos/modules/services/x11/window-managers/wmii.nix47
-rw-r--r--nixos/modules/services/x11/window-managers/xbmc.nix31
-rw-r--r--nixos/modules/services/x11/window-managers/xmonad.nix30
-rw-r--r--nixos/modules/services/x11/xfs.conf15
-rw-r--r--nixos/modules/services/x11/xfs.nix46
-rw-r--r--nixos/modules/services/x11/xserver.nix641
31 files changed, 2649 insertions, 0 deletions
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
new file mode 100644
index 00000000000..0fea74d5ba7
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -0,0 +1,75 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager;
+
+  # Whether desktop manager `d' is capable of setting a background.
+  # If it isn't, the `feh' program is used as a fallback.
+  needBGCond = d: ! (d ? bgSupport && d.bgSupport);
+
+in
+
+{
+  # Note: the order in which desktop manager modules are imported here
+  # determines the default: later modules (if enabled) are preferred.
+  # E.g., if KDE is enabled, it supersedes xterm.
+  imports = [ ./none.nix ./xterm.nix ./xfce.nix ./gnome.nix ./kde4.nix ./e17.nix ];
+
+  options = {
+
+    services.xserver.desktopManager = {
+
+      session = mkOption {
+        default = [];
+        example = singleton
+          { name = "kde";
+            bgSupport = true;
+            start = "...";
+          };
+        description = "
+          Internal option used to add some common line to desktop manager
+          scripts before forwarding the value to the
+          <varname>displayManager</varname>.
+        ";
+        apply = list: {
+          list = map (d: d // {
+            manage = "desktop";
+            start = d.start
+            + optionalString (needBGCond d) ''
+              if test -e $HOME/.background-image; then
+                ${pkgs.feh}/bin/feh --bg-scale $HOME/.background-image
+              fi
+            '';
+          }) list;
+          needBGPackages = [] != filter needBGCond list;
+        };
+      };
+
+      default = mkOption {
+        default = "";
+        example = "none";
+        description = "Default desktop manager loaded if none have been chosen.";
+        merge = mergeOneOption;
+        apply = defaultDM:
+          if defaultDM == "" && cfg.session.list != [] then
+            (head cfg.session.list).name
+          else if any (w: w.name == defaultDM) cfg.session.list then
+            defaultDM
+          else
+            throw "Default desktop manager ($(defaultDM)) not found.";
+      };
+
+    };
+
+  };
+
+  config = {
+    services.xserver.displayManager.session = cfg.session.list;
+    environment.x11Packages =
+      mkIf cfg.session.needBGPackages [ pkgs.feh ];
+  };
+}
diff --git a/nixos/modules/services/x11/desktop-managers/e17.nix b/nixos/modules/services/x11/desktop-managers/e17.nix
new file mode 100644
index 00000000000..3d91617c62a
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/e17.nix
@@ -0,0 +1,30 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.e17;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.e17.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable support for the E17 desktop environment.";
+    };
+
+  };
+
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    services.dbus.packages = [ pkgs.e17.ethumb ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/gnome.nix b/nixos/modules/services/x11/desktop-managers/gnome.nix
new file mode 100644
index 00000000000..b0212446ad3
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/gnome.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.desktopManager.gnome;
+  gnome = pkgs.gnome;
+
+in
+
+{
+
+  options = {
+
+    services.xserver.desktopManager.gnome.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable a gnome terminal as a desktop manager.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.desktopManager.session = singleton
+      { name = "gnome";
+        start = ''
+          ${gnome.gnometerminal}/bin/gnome-terminal -ls &
+          waitPID=$!
+        '';
+      };
+
+    environment.systemPackages =
+      [ gnome.gnometerminal
+        gnome.GConf
+        gnome.gconfeditor
+      ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
new file mode 100644
index 00000000000..c76acfbcd4e
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -0,0 +1,169 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.kde4;
+  xorg = pkgs.xorg;
+
+  # Disable Nepomuk and Strigi by default.  As of KDE 4.7, they don't
+  # really work very well (e.g. searching files often fails to find
+  # files), segfault sometimes and consume significant resources.
+  # They can be re-enabled in the KDE System Settings under "Desktop
+  # Search".
+  nepomukConfig = pkgs.writeTextFile
+    { name = "nepomuk-config";
+      destination = "/share/config/nepomukserverrc";
+      text =
+        ''
+          [Basic Settings]
+          Start Nepomuk=false
+
+          [Service-nepomukstrigiservice]
+          autostart=false
+        '';
+    };
+
+  phononBackends = {
+    gstreamer = [
+      pkgs.phonon_backend_gstreamer
+      pkgs.gst_all.gstPluginsBase
+      pkgs.gst_all.gstPluginsGood
+      pkgs.gst_all.gstPluginsUgly
+      pkgs.gst_all.gstPluginsBad
+      pkgs.gst_all.gstFfmpeg # for mp3 playback
+      pkgs.gst_all.gstreamer # needed?
+    ];
+
+    vlc = [pkgs.phonon_backend_vlc];
+  };
+
+  phononBackendPackages = flip concatMap cfg.phononBackends
+    (name: attrByPath [name] (throw "unknown phonon backend `${name}'") phononBackends);
+
+  wantsUdisks2 = pkgs.kde4.kdelibs.wantsUdisks2 or false;
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.kde4 = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the KDE 4 desktop environment.";
+      };
+
+      phononBackends = mkOption {
+        type = types.listOf types.string;
+        default = ["gstreamer"];
+        example = ["gstreamer" "vlc"];
+        description = "Which phonon multimedia backend kde should use";
+      };
+    };
+
+    environment.kdePackages = mkOption {
+      default = [];
+      example = "[ pkgs.kde4.kdesdk ]";
+      type = types.listOf types.package;
+      description = "This option is obsolete.  Please use <option>environment.systemPackages</option> instead.";
+    };
+
+  };
+
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    # If KDE 4 is enabled, make it the default desktop manager (unless
+    # overridden by the user's configuration).
+    # !!! doesn't work yet ("Multiple definitions. Only one is allowed
+    # for this option.")
+    # services.xserver.desktopManager.default = mkOverrideTemplate 900 "kde4";
+
+    services.xserver.desktopManager.session = singleton
+      { name = "kde4";
+        bgSupport = true;
+        start =
+          ''
+            # The KDE icon cache is supposed to update itself
+            # automatically, but it uses the timestamp on the icon
+            # theme directory as a trigger.  Since in Nix the
+            # timestamp is always the same, this doesn't work.  So as
+            # a workaround, nuke the icon cache on login.  This isn't
+            # perfect, since it may require logging out after
+            # installing new applications to update the cache.
+            # See http://lists-archives.org/kde-devel/26175-what-when-will-icon-cache-refresh.html
+            rm -fv $HOME/.kde/cache-*/icon-cache.kcache
+
+            # Qt writes a weird ‘libraryPath’ line to
+            # ~/.config/Trolltech.conf that causes the KDE plugin
+            # paths of previous KDE invocations to be searched.
+            # Obviously using mismatching KDE libraries is potentially
+            # disastrous, so here we nuke references to the Nix store
+            # in Trolltech.conf.  A better solution would be to stop
+            # Qt from doing this wackiness in the first place.
+            if [ -e $HOME/.config/Trolltech.conf ]; then
+                sed -e '/nix\\store\|nix\/store/ d' -i $HOME/.config/Trolltech.conf
+            fi
+
+            # Start KDE.
+            exec ${pkgs.kde4.kdebase_workspace}/bin/startkde
+          '';
+      };
+
+    security.setuidOwners = singleton
+      { program = "kcheckpass";
+        source = "${pkgs.kde4.kdebase_workspace}/lib/kde4/libexec/kcheckpass";
+        owner = "root";
+        group = "root";
+        setuid = true;
+      };
+
+    environment.systemPackages =
+        [ pkgs.kde4.kdelibs
+
+          pkgs.kde4.kde_baseapps # Splitted kdebase
+          pkgs.kde4.kde_workspace
+          pkgs.kde4.kde_runtime
+          pkgs.kde4.konsole
+          pkgs.kde4.kate
+
+          pkgs.kde4.kde_wallpapers # contains kdm's default background
+          pkgs.kde4.oxygen_icons
+          pkgs.virtuoso # to enable Nepomuk to find Virtuoso
+
+          # Starts KDE's Polkit authentication agent.
+          pkgs.kde4.polkit_kde_agent
+
+          # Miscellaneous runtime dependencies.
+          pkgs.kde4.qt4 # needed for qdbus
+          pkgs.shared_mime_info
+          xorg.xmessage # so that startkde can show error messages
+          xorg.xset # used by startkde, non-essential
+          xorg.xauth # used by kdesu
+          pkgs.shared_desktop_ontologies # used by nepomuk
+          pkgs.strigi # used by nepomuk
+          pkgs.mysql # used by akonadi
+        ]
+      ++ [ nepomukConfig ] ++ phononBackendPackages
+      ++ config.environment.kdePackages;
+
+    environment.pathsToLink = [ "/share" ];
+
+    environment.etc = singleton
+      { source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
+        target = "X11/xkb";
+      };
+
+    # Enable helpful DBus services.
+    services.udisks.enable = ! wantsUdisks2;
+    services.udisks2.enable = wantsUdisks2;
+    services.upower.enable = config.powerManagement.enable;
+
+    security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/none.nix b/nixos/modules/services/x11/desktop-managers/none.nix
new file mode 100644
index 00000000000..af7a376ae02
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/none.nix
@@ -0,0 +1,7 @@
+{
+  services.xserver.desktopManager.session =
+    [ { name = "none";
+        start = "";
+      }
+    ];
+}
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
new file mode 100644
index 00000000000..f5d544ad046
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -0,0 +1,90 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.xfce;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.xfce.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable the Xfce desktop environment.";
+    };
+
+  };
+
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    services.xserver.desktopManager.session = singleton
+      { name = "xfce";
+        bgSupport = true;
+        start =
+          ''
+            # Set GTK_PATH so that GTK+ can find the theme engines.
+            export GTK_PATH=${config.system.path}/lib/gtk-2.0
+
+            # Set GTK_DATA_PREFIX so that GTK+ can find the Xfce themes.
+            export GTK_DATA_PREFIX=${config.system.path}
+
+            # Necessary to get xfce4-mixer to find GST's ALSA plugin.
+            # Ugly.
+            export GST_PLUGIN_PATH=${config.system.path}/lib
+
+            exec ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc}
+          '';
+      };
+
+    environment.systemPackages =
+      [ pkgs.gtk # To get GTK+'s themes.
+        pkgs.hicolor_icon_theme
+        pkgs.tango-icon-theme
+        pkgs.shared_mime_info
+        pkgs.which # Needed by the xfce's xinitrc script.
+        pkgs.xfce.exo
+        pkgs.xfce.gtk_xfce_engine
+        pkgs.xfce.libxfcegui4 # For the icons.
+        pkgs.xfce.mousepad
+        pkgs.xfce.ristretto
+        pkgs.xfce.terminal
+        pkgs.xfce.thunar
+        pkgs.xfce.xfce4icontheme
+        pkgs.xfce.xfce4panel
+        pkgs.xfce.xfce4session
+        pkgs.xfce.xfce4settings
+        pkgs.xfce.xfce4mixer
+        pkgs.xfce.xfceutils
+        pkgs.xfce.xfconf
+        pkgs.xfce.xfdesktop
+        pkgs.xfce.xfwm4
+        # This supplies some "abstract" icons such as
+        # "utilities-terminal" and "accessories-text-editor".
+        pkgs.gnome.gnomeicontheme
+        pkgs.desktop_file_utils
+        pkgs.xfce.libxfce4ui
+        pkgs.xfce.garcon
+        pkgs.xfce.thunar_volman
+        pkgs.xfce.gvfs
+        pkgs.xfce.xfce4_appfinder
+      ]
+      ++ optional config.powerManagement.enable pkgs.xfce.xfce4_power_manager;
+
+    environment.pathsToLink =
+      [ "/share/xfce4" "/share/themes" "/share/mime" "/share/desktop-directories" "/share/gtksourceview-2.0" ];
+
+    environment.variables.GIO_EXTRA_MODULES = "${pkgs.xfce.gvfs}/lib/gio/modules";
+
+    # Enable helpful DBus services.
+    services.udisks2.enable = true;
+    services.upower.enable = config.powerManagement.enable;
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/xterm.nix b/nixos/modules/services/x11/desktop-managers/xterm.nix
new file mode 100644
index 00000000000..edc61c103ea
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/xterm.nix
@@ -0,0 +1,36 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.desktopManager.xterm;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.xterm.enable = mkOption {
+      default = true;
+      example = false;
+      description = "Enable a xterm terminal as a desktop manager.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.desktopManager.session = singleton
+      { name = "xterm";
+        start = ''
+          ${pkgs.xterm}/bin/xterm -ls &
+          waitPID=$!
+        '';
+      };
+
+    environment.systemPackages = [ pkgs.xterm ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/display-managers/auto.nix b/nixos/modules/services/x11/display-managers/auto.nix
new file mode 100644
index 00000000000..33d97e0e07a
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/auto.nix
@@ -0,0 +1,52 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  dmcfg = config.services.xserver.displayManager;
+  cfg = dmcfg.auto;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.displayManager.auto = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the fake "auto" display manager, which
+          automatically logs in the user specified in the
+          <option>user</option> option.  This is mostly useful for
+          automated tests.
+        '';
+      };
+
+      user = mkOption {
+        default = "root";
+        description = "The user account to login automatically.";
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.displayManager.slim = {
+      enable = true;
+      autoLogin = true;
+      defaultUser = cfg.user;
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
new file mode 100644
index 00000000000..c7599e245b0
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -0,0 +1,283 @@
+# This module declares the options to define a *display manager*, the
+# program responsible for handling X logins (such as xdm, kdm, gdb, or
+# SLiM).  The display manager allows the user to select a *session
+# type*.  When the user logs in, the display manager starts the
+# *session script* ("xsession" below) to launch the selected session
+# type.  The session type defines two things: the *desktop manager*
+# (e.g., KDE, Gnome or a plain xterm), and optionally the *window
+# manager* (e.g. kwin or twm).
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver;
+  xorg = pkgs.xorg;
+
+  vaapiDrivers = pkgs.buildEnv {
+    name = "vaapi-drivers";
+    paths = cfg.vaapiDrivers;
+    # We only want /lib/dri, but with a single input path, we need "/" for it to work
+    pathsToLink = [ "/" ];
+  };
+
+  # file provided by services.xserver.displayManager.session.script
+  xsession = wm: dm: pkgs.writeScript "xsession"
+    ''
+      #! /bin/sh
+
+      . /etc/profile
+      cd "$HOME"
+
+      # The first argument of this script is the session type.
+      sessionType="$1"
+      if [ "$sessionType" = default ]; then sessionType=""; fi
+
+      ${optionalString (!cfg.displayManager.job.logsXsession) ''
+        exec > ~/.xsession-errors 2>&1
+      ''}
+
+      ${optionalString cfg.displayManager.desktopManagerHandlesLidAndPower ''
+        # Stop systemd from handling the power button and lid switch,
+        # since presumably the desktop environment will handle these.
+        if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then
+          export _INHIBITION_LOCK_TAKEN=1
+          exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key "$0" "$sessionType"
+        fi
+
+      ''}
+
+      ${optionalString cfg.startOpenSSHAgent ''
+        if test -z "$SSH_AUTH_SOCK"; then
+            # Restart this script as a child of the SSH agent.  (It is
+            # also possible to start the agent as a child that prints
+            # the required environment variabled on stdout, but in
+            # that mode ssh-agent is not terminated when we log out.)
+            export SSH_ASKPASS=${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass
+            exec ${pkgs.openssh}/bin/ssh-agent "$0" "$sessionType"
+        fi
+      ''}
+
+      ${optionalString cfg.startGnuPGAgent ''
+        if test -z "$SSH_AUTH_SOCK"; then
+            # Restart this script as a child of the GnuPG agent.
+            exec "${pkgs.gnupg}/bin/gpg-agent"                         \
+              --enable-ssh-support --daemon                             \
+              --pinentry-program "${pkgs.pinentry}/bin/pinentry-gtk-2"  \
+              --write-env-file "$HOME/.gpg-agent-info"                  \
+              "$0" "$sessionType"
+        fi
+      ''}
+
+      # Handle being called by kdm.
+      if test "''${1:0:1}" = /; then eval exec "$1"; fi
+
+      # Start PulseAudio if enabled.
+      ${optionalString (config.hardware.pulseaudio.enable) ''
+        ${optionalString (!config.hardware.pulseaudio.systemWide)
+          "${pkgs.pulseaudio}/bin/pulseaudio --start"
+        }
+
+        # Publish access credentials in the root window.
+        ${pkgs.pulseaudio}/bin/pactl load-module module-x11-publish "display=$DISPLAY"
+
+        # Keep track of devices.  Mostly useful for Phonon/KDE.
+        ${pkgs.pulseaudio}/bin/pactl load-module module-device-manager "do_routing=1"
+      ''}
+
+      # Load X defaults.
+      if test -e ~/.Xdefaults; then
+          ${xorg.xrdb}/bin/xrdb -merge ~/.Xdefaults
+      fi
+
+      export LIBVA_DRIVERS_PATH=${vaapiDrivers}/lib/dri
+
+      # Speed up application start by 50-150ms according to
+      # http://kdemonkey.blogspot.nl/2008/04/magic-trick.html
+      rm -rf $HOME/.compose-cache
+      mkdir $HOME/.compose-cache
+
+      ${cfg.displayManager.sessionCommands}
+
+      # Allow the user to setup a custom session type.
+      if test -x ~/.xsession; then
+          exec ~/.xsession
+      else
+          if test "$sessionType" = "custom"; then
+              sessionType="" # fall-thru if there is no ~/.xsession
+          fi
+      fi
+
+      # The session type is "<desktop-manager> + <window-manager>", so
+      # extract those.
+      windowManager="''${sessionType##* + }"
+      : ''${windowManager:=${cfg.windowManager.default}}
+      desktopManager="''${sessionType% + *}"
+      : ''${desktopManager:=${cfg.desktopManager.default}}
+
+      # Start the window manager.
+      case $windowManager in
+        ${concatMapStrings (s: ''
+          (${s.name})
+            ${s.start}
+            ;;
+        '') wm}
+        (*) echo "$0: Window manager '$windowManager' not found.";;
+      esac
+
+      # Start the desktop manager.
+      case $desktopManager in
+        ${concatMapStrings (s: ''
+          (${s.name})
+            ${s.start}
+            ;;
+        '') dm}
+        (*) echo "$0: Desktop manager '$desktopManager' not found.";;
+      esac
+
+      test -n "$waitPID" && wait "$waitPID"
+      exit 0
+    '';
+
+  mkDesktops = names: pkgs.runCommand "desktops" {}
+    ''
+      mkdir -p $out
+      ${concatMapStrings (n: ''
+        cat - > "$out/${n}.desktop" << EODESKTOP
+        [Desktop Entry]
+        Version=1.0
+        Type=XSession
+        TryExec=${cfg.displayManager.session.script}
+        Exec=${cfg.displayManager.session.script} '${n}'
+        Name=${n}
+        Comment=
+        EODESKTOP
+      '') names}
+    '';
+
+in
+
+{
+
+  options = {
+
+    services.xserver.displayManager = {
+
+      xauthBin = mkOption {
+        default = "${xorg.xauth}/bin/xauth";
+        description = "Path to the <command>xauth</command> program used by display managers.";
+      };
+
+      xserverBin = mkOption {
+        default = "${xorg.xorgserver}/bin/X";
+        description = "Path to the X server used by display managers.";
+      };
+
+      xserverArgs = mkOption {
+        default = [];
+        example = [ "-ac" "-logverbose" "-nolisten tcp" ];
+        description = "List of arguments for the X server.";
+        apply = toString;
+      };
+
+      sessionCommands = mkOption {
+        default = "";
+        example =
+          ''
+            xmessage "Hello World!" &
+          '';
+        type = types.string;
+        description = "Shell commands executed just before the window or desktop manager is started.";
+      };
+
+      desktopManagerHandlesLidAndPower = mkOption {
+        default = true;
+        description = ''
+          Whether the display manager should prevent systemd from handling
+          lid and power events. This is normally handled by the desktop
+          environment's power manager. Turn this off when using a minimal
+          X11 setup without a full power manager.
+        '';
+      };
+
+      session = mkOption {
+        default = [];
+        example = [
+          {
+            manage = "desktop";
+            name = "xterm";
+            start = "
+              ${pkgs.xterm}/bin/xterm -ls &
+              waitPID=$!
+            ";
+          }
+        ];
+        description = ''
+          List of sessions supported with the command used to start each
+          session.  Each session script can set the
+          <varname>waitPID</varname> shell variable to make this script
+          wait until the end of the user session.  Each script is used
+          to define either a windows manager or a desktop manager.  These
+          can be differentiated by setting the attribute
+          <varname>manage</varname> either to <literal>"window"</literal>
+          or <literal>"desktop"</literal>.
+
+          The list of desktop manager and window manager should appear
+          inside the display manager with the desktop manager name
+          followed by the window manager name.
+        '';
+        apply = list: rec {
+          wm = filter (s: s.manage == "window") list;
+          dm = filter (s: s.manage == "desktop") list;
+          names = flip concatMap dm
+            (d: map (w: d.name + optionalString (w.name != "none") (" + " + w.name))
+              (filter (w: d.name != "none" || w.name != "none") wm));
+          desktops = mkDesktops names;
+          script = xsession wm dm;
+        };
+      };
+
+      job = mkOption {
+        default = {};
+        type = types.uniq types.optionSet;
+        description = "This option defines how to start the display manager.";
+
+        options = {
+
+          preStart = mkOption {
+            default = "";
+            example = "rm -f /var/log/my-display-manager.log";
+            description = "Script executed before the display manager is started.";
+          };
+
+          execCmd = mkOption {
+            example = "${pkgs.slim}/bin/slim";
+            description = "Command to start the display manager.";
+          };
+
+          environment = mkOption {
+            default = {};
+            example = { SLIM_CFGFILE = /etc/slim.conf; };
+            description = "Additional environment variables needed by the display manager.";
+          };
+
+          logsXsession = mkOption {
+            default = false;
+            description = ''
+              Whether the display manager redirects the
+              output of the session script to
+              <filename>~/.xsession-errors</filename>.
+            '';
+          };
+
+        };
+
+      };
+
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
new file mode 100644
index 00000000000..229ab12c6e1
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -0,0 +1,151 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  dmcfg = config.services.xserver.displayManager;
+  cfg = dmcfg.kdm;
+
+  inherit (pkgs.kde4) kdebase_workspace;
+
+  defaultConfig =
+    ''
+      [Shutdown]
+      HaltCmd=${config.systemd.package}/sbin/shutdown -h now
+      RebootCmd=${config.systemd.package}/sbin/shutdown -r now
+      ${optionalString (config.system.boot.loader.id == "grub") ''
+        BootManager=${if config.boot.loader.grub.version == 2 then "Grub2" else "Grub"}
+      ''}
+
+      [X-*-Core]
+      Xrdb=${pkgs.xlibs.xrdb}/bin/xrdb
+      SessionsDirs=${dmcfg.session.desktops}
+      Session=${dmcfg.session.script}
+      FailsafeClient=${pkgs.xterm}/bin/xterm
+
+      [X-:*-Core]
+      ServerCmd=${dmcfg.xserverBin} ${dmcfg.xserverArgs}
+      # KDM calls `rm' somewhere to clean up some temporary directory.
+      SystemPath=${pkgs.coreutils}/bin
+      # The default timeout (15) is too short in a heavily loaded boot process.
+      ServerTimeout=60
+      # Needed to prevent the X server from dying on logout and not coming back:
+      TerminateServer=true
+      ${optionalString (cfg.setupScript != "")
+      ''
+        Setup=${cfg.setupScript}
+      ''} 
+
+      [X-*-Greeter]
+      HiddenUsers=root,nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10
+      PluginsLogin=${kdebase_workspace}/lib/kde4/kgreet_classic.so
+      ${optionalString (cfg.themeDirectory != "")
+      ''
+        UseTheme=true
+        Theme=${cfg.themeDirectory}
+      ''
+      }
+
+      ${optionalString (cfg.enableXDMCP)
+      ''
+        [Xdmcp]
+        Enable=true
+      ''}
+    '';
+
+  kdmrc = pkgs.stdenv.mkDerivation {
+    name = "kdmrc";
+    config = defaultConfig + cfg.extraConfig;
+    buildCommand =
+      ''
+        echo "$config" > $out
+
+        # The default kdmrc would add "-nolisten tcp", and we already
+        # have that managed by nixos. Hence the grep.
+        cat ${kdebase_workspace}/share/config/kdm/kdmrc | grep -v nolisten >> $out
+      '';
+  };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.displayManager.kdm = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the KDE display manager.
+        '';
+      };
+
+      enableXDMCP = mkOption {
+        default = false;
+        description = ''
+          Whether to enable XDMCP, which allows remote logins.
+        '';
+      };
+
+      themeDirectory = mkOption {
+        default = "";
+        description = ''
+          The path to a KDM theme directory. This theme
+          will be used by the KDM greeter.
+        '';
+      };
+
+      setupScript = mkOption {
+        default = "";
+        description = ''
+          The path to a KDM setup script. This script is run as root just
+          before KDM starts. Can be used for setting up
+          monitors with xrandr, for example.
+        '';
+      };
+
+      extraConfig = mkOption {
+        default = "";
+        description = ''
+          Options appended to <filename>kdmrc</filename>, the
+          configuration file of KDM.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.displayManager.slim.enable = false;
+
+    services.xserver.displayManager.job =
+      { execCmd =
+          ''
+            mkdir -m 0755 -p /var/lib/kdm
+            chown kdm /var/lib/kdm
+            ${(optionalString (config.system.boot.loader.id == "grub" && config.system.build.grub != null) "PATH=${config.system.build.grub}/sbin:$PATH ") +
+              "KDEDIRS=/run/current-system/sw exec ${kdebase_workspace}/bin/kdm -config ${kdmrc} -nodaemon"}
+          '';
+        logsXsession = true;
+      };
+
+    security.pam.services = [ { name = "kde"; allowNullPassword = true; startSession = true; } ];
+
+    users.extraUsers = singleton
+      { name = "kdm";
+        uid = config.ids.uids.kdm;
+        description = "KDM user";
+      };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
new file mode 100644
index 00000000000..c2b90d239ea
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -0,0 +1,119 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  dmcfg = config.services.xserver.displayManager;
+  xEnv = config.systemd.services."display-manager".environment;
+  cfg = dmcfg.lightdm;
+
+  inherit (pkgs) stdenv lightdm writeScript writeText;
+
+  # lightdm runs with clearenv(), but we need a few things in the enviornment for X to startup
+  xserverWrapper = writeScript "xserver-wrapper"
+    ''
+      #! /bin/sh
+      ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
+      exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs}
+    '';
+
+  # The default greeter provided with this expression is the GTK greeter.
+  # Again, we need a few things in the environment for the greeter to run with
+  # fonts/icons.
+  wrappedGtkGreeter = stdenv.mkDerivation {
+    name = "lightdm-gtk-greeter";
+    buildInputs = [ pkgs.makeWrapper ];
+
+    buildCommand = ''
+      ensureDir $out/gtk-3.0/
+
+      # This wrapper ensures that we actually get fonts
+      makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
+        $out/greeter \
+        --set XDG_DATA_DIRS ${pkgs.gnome2.gnome_icon_theme}/share \
+        --set FONTCONFIG_FILE /etc/fonts/fonts.conf \
+        --set XDG_CONFIG_HOME $out/
+
+      # We need this to ensure that it actually tries to find icons from gnome-icon-theme
+      cat - > $out/gtk-3.0/settings.ini << EOF
+      [Settings]
+      gtk-icon-theme-name=gnome
+      EOF
+
+      cat - > $out/lightdm-gtk-greeter.desktop << EOF
+      [Desktop Entry]
+      Name=LightDM Greeter
+      Comment=This runs the LightDM Greeter
+      Exec=$out/greeter
+      Type=Application
+      EOF
+    '';
+  };
+
+  lightdmConf = writeText "lightdm.conf"
+    ''
+      [LightDM]
+      greeter-user = ${config.users.extraUsers.lightdm.name}
+      xgreeters-directory = ${cfg.greeter.package}
+      xsessions-directory = ${dmcfg.session.desktops}
+
+      [SeatDefaults]
+      xserver-command = ${xserverWrapper}
+      session-wrapper = ${dmcfg.session.script}
+      greeter-session = ${cfg.greeter.name}
+    '';
+
+in
+{
+  options = {
+    services.xserver.displayManager.lightdm = {
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable lightdm as the display manager.
+        '';
+      };
+
+      greeter = mkOption {
+        description = ''
+          The LightDM greeter to login via. The package should be a directory
+          containing a .desktop file matching the name in the 'name' option.
+        '';
+        default = {
+          name = "lightdm-gtk-greeter";
+          package = wrappedGtkGreeter;
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.displayManager.job = {
+      logsXsession = true;
+
+      # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
+      execCmd = ''
+        export PATH=${lightdm}/sbin:$PATH
+        ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run --config=${lightdmConf}
+      '';
+    };
+
+    services.dbus.enable = true;
+    services.dbus.packages = [ lightdm ];
+
+    security.pam.services = [
+      { name = "lightdm"; allowNullPassword = true; startSession = true; }
+      { name = "lightdm-greeter"; allowNullPassword = true; startSession = true; }
+    ];
+
+    users.extraUsers.lightdm = {
+      createHome = true;
+      home = "/var/lib/lightdm";
+      group = "lightdm";
+      uid = config.ids.uids.lightdm;
+    };
+
+    users.extraGroups.lightdm.gid = config.ids.gids.lightdm;
+  };
+}
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
new file mode 100644
index 00000000000..9e8b9391f45
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -0,0 +1,113 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  dmcfg = config.services.xserver.displayManager;
+  cfg = dmcfg.slim;
+
+  slimConfig = pkgs.writeText "slim.cfg"
+    ''
+      xauth_path ${dmcfg.xauthBin}
+      default_xserver ${dmcfg.xserverBin}
+      xserver_arguments ${dmcfg.xserverArgs}
+      sessions ${pkgs.lib.concatStringsSep "," (dmcfg.session.names ++ ["custom"])}
+      login_cmd exec ${pkgs.stdenv.shell} ${dmcfg.session.script} "%session"
+      halt_cmd ${config.systemd.package}/sbin/shutdown -h now
+      reboot_cmd ${config.systemd.package}/sbin/shutdown -r now
+      ${optionalString (cfg.defaultUser != "") ("default_user " + cfg.defaultUser)}
+      ${optionalString cfg.autoLogin "auto_login yes"}
+    '';
+
+  # Unpack the SLiM theme, or use the default.
+  slimThemesDir =
+    let
+      unpackedTheme = pkgs.stdenv.mkDerivation {
+        name = "slim-theme";
+        buildCommand = ''
+          ensureDir $out
+          cd $out
+          unpackFile ${cfg.theme}
+          ln -s * default
+        '';
+      };
+    in if cfg.theme == null then "${pkgs.slim}/share/slim/themes" else unpackedTheme;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.displayManager.slim = {
+
+      enable = mkOption {
+        default = true;
+        description = ''
+          Whether to enable SLiM as the display manager.
+        '';
+      };
+
+      theme = mkOption {
+        default = null;
+        example = pkgs.fetchurl {
+          url = http://download.berlios.de/slim/slim-wave.tar.gz;
+          sha256 = "0ndr419i5myzcylvxb89m9grl2xyq6fbnyc3lkd711mzlmnnfxdy";
+        };
+        description = ''
+          The theme for the SLiM login manager.  If not specified, SLiM's
+          default theme is used.  See <link
+          xlink:href='http://slim.berlios.de/themes01.php'/> for a
+          collection of themes.
+        '';
+      };
+
+      defaultUser = mkOption {
+        default = "";
+        example = "login";
+        description = ''
+          The default user to load. If you put a username here you
+          get it automatically loaded into the username field, and
+          the focus is placed on the password.
+        '';
+      };
+
+      autoLogin = mkOption {
+        default = false;
+        example = true;
+        description = ''
+          Automatically log in as the default user.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.displayManager.job =
+      { preStart =
+          ''
+            rm -f /var/log/slim.log
+          '';
+        environment =
+          { SLIM_CFGFILE = slimConfig;
+            SLIM_THEMESDIR = slimThemesDir;
+          };
+        execCmd = "exec ${pkgs.slim}/bin/slim";
+      };
+
+    # Allow null passwords so that the user can login as root on the
+    # installation CD.
+    security.pam.services = [ { name = "slim"; allowNullPassword = true; startSession = true; } ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/hardware/multitouch.nix b/nixos/modules/services/x11/hardware/multitouch.nix
new file mode 100644
index 00000000000..4f9048bfd91
--- /dev/null
+++ b/nixos/modules/services/x11/hardware/multitouch.nix
@@ -0,0 +1,60 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let cfg = config.services.xserver.multitouch; in
+
+{
+
+  options = {
+
+    services.xserver.multitouch = {
+
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Whether to enable multitouch touchpad support.";
+      };
+
+      invertScroll = mkOption {
+        default = false;
+        example = true;
+        type = types.bool;
+        description = "Whether to invert scrolling direction à la OSX Lion";
+      };
+
+      ignorePalm = mkOption {
+        default = false;
+        example = true;
+        type = types.bool;
+        description = "Whether to ignore touches detected as being the palm (i.e when typing)";
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.modules = [ pkgs.xf86_input_mtrack ];
+
+    services.xserver.config =
+      ''
+        # Automatically enable the multitouch driver
+        Section "InputClass"
+          MatchIsTouchpad "on"
+          Identifier "Touchpads"
+          Driver "mtrack"
+          Option "IgnorePalm" "${if cfg.ignorePalm then "true" else "false"}"
+          ${optionalString cfg.invertScroll ''
+            Option "ScrollUpButton" "5"
+            Option "ScrollDownButton" "4"
+            Option "ScrollLeftButton" "7"
+            Option "ScrollRightButton" "6"
+          ''}
+        EndSection
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
new file mode 100644
index 00000000000..d16142a5fdf
--- /dev/null
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -0,0 +1,122 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let cfg = config.services.xserver.synaptics; in
+
+{
+
+  options = {
+
+    services.xserver.synaptics = {
+
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Whether to enable touchpad support.";
+      };
+
+      dev = mkOption {
+        default = null;
+        example = "/dev/input/event0";
+        description =
+          ''
+            Path for touchpad device.  Set to null to apply to any
+            auto-detected touchpad.
+          '';
+      };
+
+      accelFactor = mkOption {
+        default = "0.001";
+        description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed).";
+      };
+
+      minSpeed = mkOption {
+        default = "0.6";
+        description = "Cursor speed factor for precision finger motion.";
+      };
+
+      maxSpeed = mkOption {
+        default = "1.0";
+        description = "Cursor speed factor for highest-speed finger motion.";
+      };
+
+      twoFingerScroll = mkOption {
+        default = false;
+        description = "Whether to enable two-finger drag-scrolling.";
+      };
+
+      vertEdgeScroll = mkOption {
+        default = ! cfg.twoFingerScroll;
+        description = "Whether to enable vertical edge drag-scrolling.";
+      };
+
+      tapButtons = mkOption {
+        default = true;
+        example = false;
+        description = "Whether to enable tap buttons.";
+      };
+
+      palmDetect = mkOption {
+        default = false;
+        example = true;
+        description = "Whether to enable palm detection (hardware support required)";
+      };
+
+      horizontalScroll = mkOption {
+        default = true;
+        example = false;
+        description = "Whether to enable horizontal scrolling (on touchpad)";
+      };
+
+      additionalOptions = mkOption {
+        default = "";
+        example = ''
+          Option "RTCornerButton" "2"
+          Option "RBCornerButton" "3"
+		'';
+        description = ''
+          Additional options for synaptics touchpad driver.
+        '';
+      };
+
+    };
+
+  };
+
+
+  config = mkIf cfg.enable {
+
+    services.xserver.modules = [ pkgs.xorg.xf86inputsynaptics ];
+
+    environment.systemPackages = [ pkgs.xorg.xf86inputsynaptics ];
+
+    services.xserver.config =
+      ''
+        # Automatically enable the synaptics driver for all touchpads.
+        Section "InputClass"
+          Identifier "synaptics touchpad catchall"
+          MatchIsTouchpad "on"
+          ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''}
+          Driver "synaptics"
+          Option "MaxTapTime" "180"
+          Option "MaxTapMove" "220"
+          Option "MinSpeed" "${cfg.minSpeed}"
+          Option "MaxSpeed" "${cfg.maxSpeed}"
+          Option "AccelFactor" "${cfg.accelFactor}"
+          Option "TapButton1" "${if cfg.tapButtons then "1" else "0"}"
+          Option "TapButton2" "${if cfg.tapButtons then "2" else "0"}"
+          Option "TapButton3" "${if cfg.tapButtons then "3" else "0"}"
+          ${if cfg.tapButtons then "" else ''Option "MaxTapTime" "0"''}
+          Option "VertTwoFingerScroll" "${if cfg.twoFingerScroll then "1" else "0"}"
+          Option "HorizTwoFingerScroll" "${if cfg.twoFingerScroll then "1" else "0"}"
+          Option "VertEdgeScroll" "${if cfg.vertEdgeScroll then "1" else "0"}"
+          ${if cfg.palmDetect then ''Option "PalmDetect" "1"'' else ""}
+          ${if cfg.horizontalScroll then "" else ''Option "HorizScrollDelta" "0"''}
+          ${cfg.additionalOptions}
+        EndSection
+      '';
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/hardware/wacom.nix b/nixos/modules/services/x11/hardware/wacom.nix
new file mode 100644
index 00000000000..dfc588cd213
--- /dev/null
+++ b/nixos/modules/services/x11/hardware/wacom.nix
@@ -0,0 +1,47 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.wacom;
+
+in
+
+{
+
+  options = {
+
+    services.xserver.wacom = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the Wacom touchscreen/digitizer/tablet.
+          If you ever have any issues such as, try switching to terminal (ctrl-alt-F1) and back
+          which will make Xorg reconfigure the device ?
+
+          If you're not satisfied by the default behaviour you can override
+          <option>environment.etc."X11/xorg.conf.d/50-wacom.conf"</option> in
+          configuration.nix easily.
+        '';
+      };
+
+    };
+
+  };
+
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.xf86_input_wacom ]; # provides xsetwacom
+
+    services.xserver.modules = [ pkgs.xf86_input_wacom ];
+
+    services.udev.packages = [ pkgs.xf86_input_wacom ];
+
+    environment.etc."X11/xorg.conf.d/50-wacom.conf".source = "${pkgs.xf86_input_wacom}/share/X11/xorg.conf.d/50-wacom.conf";
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/terminal-server.nix b/nixos/modules/services/x11/terminal-server.nix
new file mode 100644
index 00000000000..ab05639aeca
--- /dev/null
+++ b/nixos/modules/services/x11/terminal-server.nix
@@ -0,0 +1,66 @@
+# This module implements a terminal service based on ‘x11vnc’.  It
+# listens on port 5900 for VNC connections.  It then presents a login
+# screen to the user.  If the user successfully authenticates, x11vnc
+# checks to see if a X server is already running for that user.  If
+# not, a X server (Xvfb) is started for that user.  The Xvfb instances
+# persist across VNC sessions.
+
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  # Wrap Xvfb to set some flags/variables.
+  xvfbWrapper = pkgs.writeScriptBin "Xvfb"
+    ''
+      #! ${pkgs.stdenv.shell}
+      export XKB_BINDIR=${pkgs.xorg.xkbcomp}/bin
+      export XORG_DRI_DRIVER_PATH=${pkgs.mesa}/lib/dri
+      exec ${pkgs.xorg.xorgserver}/bin/Xvfb "$@" -xkbdir "${pkgs.xkeyboard_config}/etc/X11/xkb"
+    '';
+
+  # ‘xinetd’ is insanely braindamaged in that it sends stderr to
+  # stdout.  Thus requires just about any xinetd program to be
+  # wrapped to redirect its stderr.  Sigh.
+  x11vncWrapper = pkgs.writeScriptBin "x11vnc-wrapper"
+    ''
+      #! ${pkgs.stdenv.shell}
+      export PATH=${makeSearchPath "bin" [ xvfbWrapper pkgs.gawk pkgs.which pkgs.openssl pkgs.xorg.xauth pkgs.nettools pkgs.shadow pkgs.procps pkgs.utillinux pkgs.bash ]}:$PATH
+      export FD_GEOM=1024x786x24
+      exec ${pkgs.x11vnc}/bin/x11vnc -inetd -display WAIT:1024x786:cmd=FINDCREATEDISPLAY-Xvfb.xdmcp -unixpw -ssl SAVE 2> /var/log/x11vnc.log
+    '';
+
+in 
+
+{
+
+  config = {
+  
+    services.xserver.enable = true;
+
+    # Enable KDM.  Any display manager will do as long as it supports XDMCP.
+    services.xserver.displayManager.kdm.enable = true;
+    services.xserver.displayManager.kdm.enableXDMCP = true;
+    services.xserver.displayManager.kdm.extraConfig =
+      ''
+        [General]
+        # We're headless, so don't bother starting an X server.
+        StaticServers=
+
+        [Xdmcp]
+        Xaccess=${pkgs.writeText "Xaccess" "localhost"}
+      '';
+
+    services.xinetd.enable = true;
+    services.xinetd.services = singleton
+      { name = "x11vnc";
+        port = 5900;
+        unlisted = true;
+        user = "root";
+        server = "${x11vncWrapper}/bin/x11vnc-wrapper";
+      };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix
new file mode 100644
index 00000000000..880ebf1eca6
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/awesome.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.awesome;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.windowManager.awesome.enable = mkOption {
+      default = false;
+      description = "Enable the Awesome window manager.";
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      { name = "awesome";
+        start =
+          ''
+            ${pkgs.awesome}/bin/awesome &
+            waitPID=$!
+          '';
+      };
+
+    environment.x11Packages = [ pkgs.awesome ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/compiz.nix b/nixos/modules/services/x11/window-managers/compiz.nix
new file mode 100644
index 00000000000..209401f2646
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/compiz.nix
@@ -0,0 +1,63 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.compiz;
+  xorg = config.services.xserver.package;
+
+in
+
+{
+
+  options = {
+
+    services.xserver.windowManager.compiz = {
+
+      enable = mkOption {
+        default = false;
+        description = "Enable the Compiz window manager.";
+      };
+
+      renderingFlag = mkOption {
+        default = "";
+        example = "--indirect-rendering";
+        description = "Pass the <option>--indirect-rendering</option> flag to Compiz.";
+      };
+
+    };
+
+  };
+
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      { name = "compiz";
+        start =
+          ''
+            # Start Compiz using the flat-file configuration backend
+            # (ccp).
+            export COMPIZ_PLUGINDIR=${config.system.path}/lib/compiz
+            export COMPIZ_METADATADIR=${config.system.path}/share/compiz
+            ${pkgs.compiz}/bin/compiz ccp ${cfg.renderingFlag} &
+
+            # Start GTK-style window decorator.
+            ${pkgs.compiz}/bin/gtk-window-decorator &
+          '';
+      };
+
+    environment.systemPackages =
+      [ pkgs.compiz
+        pkgs.compiz_ccsm
+        pkgs.compiz_plugins_main
+        pkgs.compiz_plugins_extra
+        pkgs.libcompizconfig # for the "ccp" plugin
+      ];
+
+    environment.pathsToLink = [ "/lib/compiz" "/share/compiz" ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
new file mode 100644
index 00000000000..c201b789ae4
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -0,0 +1,61 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+  cfg = config.services.xserver.windowManager;
+in
+
+{
+  imports =
+    [ ./compiz.nix
+      ./openbox.nix
+      ./metacity.nix
+      ./none.nix
+      ./twm.nix
+      ./wmii.nix
+      ./xmonad.nix
+      ./i3.nix
+      ./xbmc.nix
+    ];
+
+  options = {
+
+    services.xserver.windowManager = {
+
+      session = mkOption {
+        default = [];
+        example = [{
+          name = "wmii";
+          start = "...";
+        }];
+        description = ''
+          Internal option used to add some common line to window manager
+          scripts before forwarding the value to the
+          <varname>displayManager</varname>.
+        '';
+        apply = map (d: d // {
+          manage = "window";
+        });
+      };
+
+      default = mkOption {
+        default = "none";
+        example = "wmii";
+        description = "Default window manager loaded if none have been chosen.";
+        merge = mergeOneOption;
+        apply = defaultWM:
+          if any (w: w.name == defaultWM) cfg.session then
+            defaultWM
+          else
+            throw "Default window manager (${defaultWM}) not found.";
+      };
+
+    };
+
+  };
+
+  config = {
+    services.xserver.displayManager.session = cfg.session;
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
new file mode 100644
index 00000000000..6777a95ddc8
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -0,0 +1,43 @@
+{ pkgs, config, ... }:
+
+with pkgs.lib;
+
+let
+  cfg = config.services.xserver.windowManager.i3;
+in
+
+{
+  options = {
+    services.xserver.windowManager.i3 = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the i3 tiling window manager.";
+      };
+
+      configFile = mkOption {
+        default = null;
+        type = types.nullOr types.path;
+        description = ''
+          Path to the i3 configuration file.
+          If left at the default value, $HOME/.i3/config will be used.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager = {
+      session = [{
+        name = "i3";
+        start = "
+          ${pkgs.i3}/bin/i3 ${optionalString (cfg.configFile != null)
+            "-c \"${cfg.configFile}\""
+          } &
+          waitPID=$!
+        ";
+      }];
+    };
+    environment.x11Packages = [ pkgs.i3 ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/icewm.nix b/nixos/modules/services/x11/window-managers/icewm.nix
new file mode 100644
index 00000000000..9da4a415fad
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/icewm.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.icewm;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.windowManager.icewm.enable = mkOption {
+      default = false;
+      description = "Enable the IceWM window manager.";
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      { name = "icewm";
+        start =
+          ''
+            ${pkgs.icewm}/bin/icewm &
+            waitPID=$!
+          '';
+      };
+
+    environment.x11Packages = [ pkgs.icewm ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/metacity.nix b/nixos/modules/services/x11/window-managers/metacity.nix
new file mode 100644
index 00000000000..712e2038594
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/metacity.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.metacity;
+  xorg = config.services.xserver.package;
+  gnome = pkgs.gnome;
+
+in
+
+{
+  options = {
+
+    services.xserver.windowManager.metacity.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable the metacity window manager.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      { name = "metacity";
+        start = ''
+          env LD_LIBRARY_PATH=${xorg.libX11}/lib:${xorg.libXext}/lib:/usr/lib/
+          # !!! Hack: load the schemas for Metacity.
+          GCONF_CONFIG_SOURCE=xml::~/.gconf ${gnome.GConf}/bin/gconftool-2 \
+            --makefile-install-rule ${gnome.metacity}/etc/gconf/schemas/*.schemas # */
+          ${gnome.metacity}/bin/metacity &
+          waitPID=$!
+        '';
+      };
+
+    environment.systemPackages = [ gnome.metacity ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/none.nix b/nixos/modules/services/x11/window-managers/none.nix
new file mode 100644
index 00000000000..84cf1d77077
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/none.nix
@@ -0,0 +1,12 @@
+{
+  services = {
+    xserver = {
+      windowManager = {
+        session = [{
+          name = "none";
+          start = "";
+        }];
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/openbox.nix b/nixos/modules/services/x11/window-managers/openbox.nix
new file mode 100644
index 00000000000..ae34a938c4a
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/openbox.nix
@@ -0,0 +1,30 @@
+{pkgs, config, ...}:
+
+let
+  inherit (pkgs.lib) mkOption mkIf;
+  cfg = config.services.xserver.windowManager.openbox;
+in
+
+{
+  options = {
+    services.xserver.windowManager.openbox = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the Openbox window manager.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager = {
+      session = [{
+        name = "openbox";
+        start = "
+          ${pkgs.openbox}/bin/openbox-session
+        ";
+      }];
+    };
+    environment.x11Packages = [ pkgs.openbox ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/twm.nix b/nixos/modules/services/x11/window-managers/twm.nix
new file mode 100644
index 00000000000..c1a99b97566
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/twm.nix
@@ -0,0 +1,42 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.twm;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xserver.windowManager.twm.enable = mkOption {
+      default = false;
+      description = "Enable the twm window manager.";
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      { name = "twm";
+        start =
+          ''
+            ${pkgs.xorg.twm}/bin/twm &
+            waitPID=$!
+          '';
+      };
+
+    environment.x11Packages = [ pkgs.xorg.twm ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/wmii.nix b/nixos/modules/services/x11/window-managers/wmii.nix
new file mode 100644
index 00000000000..b61521274fb
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/wmii.nix
@@ -0,0 +1,47 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  cfg = config.services.xserver.windowManager.wmii;
+
+in
+
+{
+  options = {
+
+    services.xserver.windowManager.wmii.enable = mkOption {
+      default = false;
+      example = true;
+      description = "Enable the wmii window manager.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.xserver.windowManager.session = singleton
+      # stop wmii by
+      #   $wmiir xwrite /ctl quit
+      # this will cause wmii exiting with exit code 0
+      #
+      # why this loop?
+      # wmii crashes once a month here. That doesn't matter that much
+      # wmii can recover very well. However without loop the x session terminates and then your workspace setup is
+      # lost and all applications running on X will terminate.
+      # Another use case is kill -9 wmii; after rotating screen.
+      # Note: we don't like kill for that purpose. But it works (-> subject "wmii and xrandr" on mailinglist)
+      { name = "wmii";
+        start = ''
+          while :; do
+            ${pkgs.wmiiSnap}/bin/wmii && break
+          done
+        '';
+      };
+
+    environment.systemPackages = [ pkgs.wmiiSnap ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/xbmc.nix b/nixos/modules/services/x11/window-managers/xbmc.nix
new file mode 100644
index 00000000000..46494202b40
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/xbmc.nix
@@ -0,0 +1,31 @@
+{pkgs, config, ...}:
+
+let
+  inherit (pkgs.lib) mkOption mkIf;
+  cfg = config.services.xserver.windowManager.xbmc;
+in
+
+{
+  options = {
+    services.xserver.windowManager.xbmc = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the xbmc multimedia center.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    services.xserver.windowManager = {
+      session = [{
+        name = "xbmc";
+        start = "
+          ${pkgs.xbmc}/bin/xbmc --lircdev /var/run/lirc/lircd --standalone &
+          waitPID=$!
+        ";
+      }];
+    };
+    environment.systemPackages = [ pkgs.xbmc ];
+  };
+}
diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
new file mode 100644
index 00000000000..2cbb5002d6c
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -0,0 +1,30 @@
+{pkgs, config, ...}:
+
+let
+  inherit (pkgs.lib) mkOption mkIf;
+  cfg = config.services.xserver.windowManager.xmonad;
+in
+
+{
+  options = {
+    services.xserver.windowManager.xmonad = {
+      enable = mkOption {
+        default = false;
+        example = true;
+        description = "Enable the xmonad window manager.";
+      };
+    };
+  };
+
+  config = {
+    services.xserver.windowManager = {
+      session = mkIf cfg.enable [{
+        name = "xmonad";
+        start = "
+          ${pkgs.haskellPackages.xmonad}/bin/xmonad &
+          waitPID=$!
+        ";
+      }];
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/xfs.conf b/nixos/modules/services/x11/xfs.conf
new file mode 100644
index 00000000000..13dcf803db2
--- /dev/null
+++ b/nixos/modules/services/x11/xfs.conf
@@ -0,0 +1,15 @@
+# font server configuration file
+# $Xorg: config.cpp,v 1.3 2000/08/17 19:54:19 cpqbld Exp $
+
+clone-self = on
+use-syslog = off
+error-file = /var/log/xfs.log
+# in decipoints
+default-point-size = 120
+default-resolutions = 75,75,100,100
+
+# font cache control, specified in KB
+cache-hi-mark = 2048
+cache-low-mark = 1433
+cache-balance = 70
+catalogue = /run/current-system/sw/share/X11-fonts/
diff --git a/nixos/modules/services/x11/xfs.nix b/nixos/modules/services/x11/xfs.nix
new file mode 100644
index 00000000000..f4a40dbb08f
--- /dev/null
+++ b/nixos/modules/services/x11/xfs.nix
@@ -0,0 +1,46 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  configFile = ./xfs.conf;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.xfs = {
+
+      enable = mkOption {
+        default = false;
+        description = "Whether to enable the X Font Server.";
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.xfs.enable (
+  mkAssert config.fonts.enableFontDir "
+    Please enable fontDir (fonts.enableFontDir) to use xfs.
+  " {
+
+    jobs.xfs =
+      { description = "X Font Server";
+
+        startOn = "started networking";
+
+        exec = "${pkgs.xorg.xfs}/bin/xfs -config ${configFile}";
+      };
+
+  });
+
+}
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
new file mode 100644
index 00000000000..d42d7caaa06
--- /dev/null
+++ b/nixos/modules/services/x11/xserver.nix
@@ -0,0 +1,641 @@
+{ config, pkgs, pkgs_i686, ... }:
+
+with pkgs.lib;
+
+let
+
+  kernelPackages = config.boot.kernelPackages;
+
+  # Abbreviations.
+  cfg = config.services.xserver;
+  xorg = pkgs.xorg;
+
+
+  # Map video driver names to driver packages.
+  knownVideoDrivers = {
+    ati_unfree   = { modules = [ kernelPackages.ati_drivers_x11 ]; driverName = "fglrx"; };
+    nouveau       = { modules = [ pkgs.xf86_video_nouveau ]; };
+    nvidia       = { modules = [ kernelPackages.nvidia_x11 ]; };
+    nvidiaLegacy96 = { modules = [ kernelPackages.nvidia_x11_legacy96 ]; driverName = "nvidia"; };
+    nvidiaLegacy173 = { modules = [ kernelPackages.nvidia_x11_legacy173 ]; driverName = "nvidia"; };
+    nvidiaLegacy304 = { modules = [ kernelPackages.nvidia_x11_legacy304 ]; driverName = "nvidia"; };
+    unichrome    = { modules = [ pkgs.xorgVideoUnichrome ]; };
+    virtualbox   = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
+  };
+
+  driverNames =
+    optional (cfg.videoDriver != null) cfg.videoDriver ++ cfg.videoDrivers;
+
+  drivers = flip map driverNames
+    (name: { inherit name; driverName = name; } //
+      attrByPath [name] (if (hasAttr ("xf86video" + name) xorg) then { modules = [(getAttr ("xf86video" + name) xorg) ]; } else throw "unknown video driver `${name}'") knownVideoDrivers);
+
+  fontsForXServer =
+    config.fonts.fonts ++
+    # We don't want these fonts in fonts.conf, because then modern,
+    # fontconfig-based applications will get horrible bitmapped
+    # Helvetica fonts.  It's better to get a substitution (like Nimbus
+    # Sans) than that horror.  But we do need the Adobe fonts for some
+    # old non-fontconfig applications.  (Possibly this could be done
+    # better using a fontconfig rule.)
+    [ pkgs.xorg.fontadobe100dpi
+      pkgs.xorg.fontadobe75dpi
+    ];
+
+
+  # Just enumerate all heads without discarding XRandR output information.
+  xrandrHeads = let
+    mkHead = num: output: {
+      name = "multihead${toString num}";
+      inherit output;
+    };
+  in imap mkHead cfg.xrandrHeads;
+
+  xrandrDeviceSection = flip concatMapStrings xrandrHeads (h: ''
+    Option "monitor-${h.output}" "${h.name}"
+  '');
+
+  # Here we chain every monitor from the left to right, so we have:
+  # m4 right of m3 right of m2 right of m1   .----.----.----.----.
+  # Which will end up in reverse ----------> | m1 | m2 | m3 | m4 |
+  #                                          `----^----^----^----'
+  xrandrMonitorSections = let
+    mkMonitor = previous: current: previous ++ singleton {
+      inherit (current) name;
+      value = ''
+        Section "Monitor"
+          Identifier "${current.name}"
+          ${optionalString (previous != []) ''
+          Option "RightOf" "${(head previous).name}"
+          ''}
+        EndSection
+      '';
+    };
+    monitors = foldl mkMonitor [] xrandrHeads;
+  in concatMapStrings (getAttr "value") monitors;
+
+
+  configFile = pkgs.stdenv.mkDerivation {
+    name = "xserver.conf";
+
+    xfs = optionalString (cfg.useXFS != false)
+      ''FontPath "${toString cfg.useXFS}"'';
+
+    inherit (cfg) config;
+
+    buildCommand =
+      ''
+        echo 'Section "Files"' >> $out
+        echo $xfs >> $out
+
+        for i in ${toString fontsForXServer}; do
+          if test "''${i:0:''${#NIX_STORE}}" == "$NIX_STORE"; then
+            for j in $(find $i -name fonts.dir); do
+              echo "  FontPath \"$(dirname $j)\"" >> $out
+            done
+          fi
+        done
+
+        for i in $(find ${toString cfg.modules} -type d); do
+          if test $(echo $i/*.so* | wc -w) -ne 0; then
+            echo "  ModulePath \"$i\"" >> $out
+          fi
+        done
+
+        echo 'EndSection' >> $out
+
+        echo "$config" >> $out
+      ''; # */
+  };
+
+
+  checkAgent = mkAssert (!(cfg.startOpenSSHAgent && cfg.startGnuPGAgent))
+    ''
+      The OpenSSH agent and GnuPG agent cannot be started both.
+      Choose between `startOpenSSHAgent' and `startGnuPGAgent'.
+    '';
+
+  checkPolkit = mkAssert config.security.polkit.enable
+    "X11 requires Polkit to be enabled (‘security.polkit.enable = true’).";
+
+
+in
+
+{
+
+  imports =
+    [ ./display-managers/default.nix
+      ./window-managers/default.nix
+      ./desktop-managers/default.nix
+    ];
+
+
+  ###### interface
+
+  options = {
+
+    services.xserver = {
+
+      enable = mkOption {
+        default = false;
+        description = ''
+          Whether to enable the X server.
+        '';
+      };
+
+      autorun = mkOption {
+        default = true;
+        description = ''
+          Whether to start the X server automatically.
+        '';
+      };
+
+      exportConfiguration = mkOption {
+        default = false;
+        description = ''
+          Whether to symlink the X server configuration under
+          <filename>/etc/X11/xorg.conf</filename>.
+        '';
+      };
+
+      enableTCP = mkOption {
+        default = false;
+        description = ''
+          Whether to allow the X server to accept TCP connections.
+        '';
+      };
+
+      modules = mkOption {
+        default = [];
+        example = [ pkgs.xf86_input_wacom ];
+        description = "Packages to be added to the module search path of the X server.";
+      };
+
+      resolutions = mkOption {
+        default = [];
+        example = [ { x = 1600; y = 1200; } { x = 1024; y = 786; } ];
+        description = ''
+          The screen resolutions for the X server.  The first element
+          is the default resolution.  If this list is empty, the X
+          server will automatically configure the resolution.
+        '';
+      };
+
+      videoDriver = mkOption {
+        default = null;
+        example = "i810";
+        description = ''
+          The name of the video driver for your graphics card.  This
+          option is obsolete; please set the
+          <option>videoDrivers</option> instead.
+        '';
+      };
+
+      videoDrivers = mkOption {
+        # !!! We'd like "nv" here, but it segfaults the X server.
+        default = [ "ati" "cirrus" "intel" "vesa" "vmware" ];
+        example = [ "vesa" ];
+        description = ''
+          The names of the video drivers that the X server should
+          support.  The X server will try all of the drivers listed
+          here until it finds one that supports your video card.
+        '';
+      };
+
+      vaapiDrivers = mkOption {
+        default = [ ];
+        defaultText = "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]";
+        example = "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]";
+        description = ''
+          Packages providing libva acceleration drivers.
+        '';
+      };
+
+      driSupport = mkOption {
+        default = true;
+        description = ''
+          Whether to enable accelerated OpenGL rendering through the
+          Direct Rendering Interface (DRI).
+        '';
+      };
+
+      driSupport32Bit = mkOption {
+        default = false;
+        description = ''
+          On 64-bit systems, whether to support Direct Rendering for
+          32-bit applications (such as Wine).  This is currently only
+          supported for the <literal>nvidia</literal> driver and for
+          <literal>mesa</literal>.
+        '';
+      };
+
+      startOpenSSHAgent = mkOption {
+        default = true;
+        description = ''
+          Whether to start the OpenSSH agent when you log in.  The OpenSSH agent
+          remembers private keys for you so that you don't have to type in
+          passphrases every time you make an SSH connection.  Use
+          <command>ssh-add</command> to add a key to the agent.
+        '';
+      };
+
+      startGnuPGAgent = mkOption {
+        default = false;
+        description = ''
+          Whether to start the GnuPG agent when you log in.  The GnuPG agent
+          remembers private keys for you so that you don't have to type in
+          passphrases every time you make an SSH connection or sign/encrypt
+          data.  Use <command>ssh-add</command> to add a key to the agent.
+        '';
+      };
+
+      layout = mkOption {
+        default = "us";
+        description = ''
+          Keyboard layout.
+        '';
+      };
+
+      xkbModel = mkOption {
+        default = "pc104";
+        example = "presario";
+        description = ''
+          Keyboard model.
+        '';
+      };
+
+      xkbOptions = mkOption {
+        default = "terminate:ctrl_alt_bksp";
+        example = "grp:caps_toggle, grp_led:scroll";
+        description = ''
+          X keyboard options; layout switching goes here.
+        '';
+      };
+
+      xkbVariant = mkOption {
+        default = "";
+        example = "colemak";
+        description = ''
+          X keyboard variant.
+        '';
+      };
+
+      config = mkOption {
+        description = ''
+          The contents of the configuration file of the X server
+          (<filename>xorg.conf</filename>).
+        '';
+      };
+
+      deviceSection = mkOption {
+        default = "";
+        example = "VideoRAM 131072";
+        description = "Contents of the first Device section of the X server configuration file.";
+      };
+
+      screenSection = mkOption {
+        default = "";
+        example = ''
+          Option "RandRRotation" "on"
+        '';
+        description = "Contents of the first Screen section of the X server configuration file.";
+      };
+
+      monitorSection = mkOption {
+        default = "";
+        example = "HorizSync 28-49";
+        description = "Contents of the first Monitor section of the X server configuration file.";
+      };
+
+      xrandrHeads = mkOption {
+        default = [];
+        example = [ "HDMI-0" "DVI-0" ];
+        type = with types; listOf string;
+        description = ''
+          Simple multiple monitor configuration, just specify a list of XRandR
+          outputs which will be mapped from left to right in the order of the
+          list.
+
+          Be careful using this option with multiple graphic adapters or with
+          drivers that have poor support for XRandR, unexpected things might
+          happen with those.
+        '';
+      };
+
+      moduleSection = mkOption {
+        default = "";
+        example =
+          ''
+            SubSection "extmod"
+            EndSubsection
+          '';
+        description = "Contents of the Module section of the X server configuration file.";
+      };
+
+      serverLayoutSection = mkOption {
+        default = "";
+        example =
+          ''
+            Option "AIGLX" "true"
+          '';
+        description = "Contents of the ServerLayout section of the X server configuration file.";
+      };
+
+      extraDisplaySettings = mkOption {
+        default = "";
+        example = "Virtual 2048 2048";
+        description = "Lines to be added to every Display subsection of the Screen section.";
+      };
+
+      defaultDepth = mkOption {
+        default = 0;
+        example = 8;
+        description = "Default colour depth.";
+      };
+
+      useXFS = mkOption {
+        default = false;
+        example = "unix/:7100";
+        description = "Determines how to connect to the X Font Server.";
+      };
+
+      tty = mkOption {
+        default = 7;
+        example = 9;
+        description = "Virtual console for the X server.";
+      };
+
+      display = mkOption {
+        default = 0;
+        example = 1;
+        description = "Display number for the X server.";
+      };
+
+      virtualScreen = mkOption {
+        default = null;
+        example = { x = 2048; y = 2048; };
+        description = ''
+          Virtual screen size for Xrandr.
+        '';
+      };
+
+    };
+
+    environment.x11Packages = mkOption {
+      default = [];
+      type = types.listOf types.package;
+      description = ''
+        List of packages added to the system when the X server is
+        activated (<option>services.xserver.enable</option>).
+      '';
+    };
+
+  };
+
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable (checkAgent (checkPolkit {
+
+    boot.extraModulePackages =
+      optional (elem "nvidia" driverNames) kernelPackages.nvidia_x11 ++
+      optional (elem "nvidiaLegacy96" driverNames) kernelPackages.nvidia_x11_legacy96 ++
+      optional (elem "nvidiaLegacy173" driverNames) kernelPackages.nvidia_x11_legacy173 ++
+      optional (elem "nvidiaLegacy304" driverNames) kernelPackages.nvidia_x11_legacy304 ++
+      optional (elem "virtualbox" driverNames) kernelPackages.virtualboxGuestAdditions ++
+      optional (elem "ati_unfree" driverNames) kernelPackages.ati_drivers_x11;
+
+    boot.blacklistedKernelModules =
+      optionals (elem "nvidia" driverNames) [ "nouveau" "nvidiafb" ];
+
+    environment.variables.LD_LIBRARY_PATH =
+      [ "/run/opengl-driver/lib" "/run/opengl-driver-32/lib" ];
+
+    environment.etc =
+      (optionals cfg.exportConfiguration
+        [ { source = "${configFile}";
+            target = "X11/xorg.conf";
+          }
+          # -xkbdir command line option does not seems to be passed to xkbcomp.
+          { source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
+            target = "X11/xkb";
+          }
+        ])
+      ++ (optionals (elem "ati_unfree" driverNames) [
+
+          # according toiive on #ati you don't need the pcs, it is like registry... keeps old stuff to make your
+          # life harder ;) Still it seems to be required
+          { source = "${kernelPackages.ati_drivers_x11}/etc/ati";
+            target = "ati";
+          }
+      ])
+      ++ (optionals (elem "nvidia" driverNames) [
+
+          { source = "${kernelPackages.nvidia_x11}/lib/vendors/nvidia.icd";
+            target = "OpenCL/vendors/nvidia.icd";
+          }
+      ]);
+
+    environment.x11Packages =
+      [ xorg.xorgserver
+        xorg.xrandr
+        xorg.xrdb
+        xorg.setxkbmap
+        xorg.iceauth # required for KDE applications (it's called by dcopserver)
+        xorg.xlsclients
+        xorg.xset
+        xorg.xsetroot
+        xorg.xinput
+        xorg.xprop
+        pkgs.xterm
+        pkgs.xdg_utils
+      ]
+      ++ optional (elem "nvidia" driverNames) kernelPackages.nvidia_x11
+      ++ optional (elem "nvidiaLegacy96" driverNames) kernelPackages.nvidia_x11_legacy96
+      ++ optional (elem "nvidiaLegacy173" driverNames) kernelPackages.nvidia_x11_legacy173
+      ++ optional (elem "nvidiaLegacy304" driverNames) kernelPackages.nvidia_x11_legacy304
+      ++ optional (elem "virtualbox" driverNames) xorg.xrefresh
+      ++ optional (elem "ati_unfree" driverNames) kernelPackages.ati_drivers_x11;
+
+    environment.systemPackages = config.environment.x11Packages;
+
+    environment.pathsToLink =
+      [ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
+
+    systemd.defaultUnit = mkIf cfg.autorun "graphical.target";
+
+    systemd.services."display-manager" =
+      { description = "X11 Server";
+
+        after = [ "systemd-udev-settle.service" "local-fs.target" ];
+
+        restartIfChanged = false;
+
+        environment =
+          { FONTCONFIG_FILE = "/etc/fonts/fonts.conf"; # !!! cleanup
+            XKB_BINDIR = "${xorg.xkbcomp}/bin"; # Needed for the Xkb extension.
+            XORG_DRI_DRIVER_PATH = "/run/opengl-driver/lib/dri"; # !!! Depends on the driver selected at runtime.
+          } // optionalAttrs (elem "nvidia" driverNames) {
+            LD_LIBRARY_PATH = "${xorg.libX11}/lib:${xorg.libXext}/lib:${kernelPackages.nvidia_x11}/lib";
+          } // optionalAttrs (elem "nvidiaLegacy96" driverNames) {
+            LD_LIBRARY_PATH = "${xorg.libX11}/lib:${xorg.libXext}/lib:${kernelPackages.nvidia_x11_legacy96}/lib";
+          } // optionalAttrs (elem "nvidiaLegacy173" driverNames) {
+            LD_LIBRARY_PATH = "${xorg.libX11}/lib:${xorg.libXext}/lib:${kernelPackages.nvidia_x11_legacy173}/lib";
+          } // optionalAttrs (elem "nvidiaLegacy304" driverNames) {
+            LD_LIBRARY_PATH = "${xorg.libX11}/lib:${xorg.libXext}/lib:${kernelPackages.nvidia_x11_legacy304}/lib";
+          } // optionalAttrs (elem "ati_unfree" driverNames) {
+            LD_LIBRARY_PATH = "${xorg.libX11}/lib:${xorg.libXext}/lib:${kernelPackages.ati_drivers_x11}/lib:${kernelPackages.ati_drivers_x11}/X11R6/lib64/modules/linux";
+            #XORG_DRI_DRIVER_PATH = "${kernelPackages.ati_drivers_x11}/lib/dri"; # is ignored because ati drivers ship their own unpatched libglx.so !
+          } // cfg.displayManager.job.environment;
+
+        preStart =
+          ''
+            rm -f /run/opengl-driver{,-32}
+            ${optionalString (!cfg.driSupport32Bit) "ln -sf opengl-driver /run/opengl-driver-32"}
+
+            ${# !!! The OpenGL driver depends on what's detected at runtime.
+              if elem "nvidia" driverNames then
+                ''
+                  ln -sf ${kernelPackages.nvidia_x11} /run/opengl-driver
+                  ${optionalString cfg.driSupport32Bit
+                    "ln -sf ${pkgs_i686.linuxPackages.nvidia_x11.override { libsOnly = true; kernelDev = null; } } /run/opengl-driver-32"}
+                ''
+              else if elem "nvidiaLegacy96" driverNames then
+                "ln -sf ${kernelPackages.nvidia_x11_legacy96} /run/opengl-driver"
+              else if elem "nvidiaLegacy173" driverNames then
+                "ln -sf ${kernelPackages.nvidia_x11_legacy173} /run/opengl-driver"
+              else if elem "nvidiaLegacy304" driverNames then
+                ''
+                  ln -sf ${kernelPackages.nvidia_x11_legacy304} /run/opengl-driver
+                  ${optionalString cfg.driSupport32Bit
+                    "ln -sf ${pkgs_i686.linuxPackages.nvidia_x11_legacy304.override { libsOnly = true; kernelDev = null; } } /run/opengl-driver-32"}
+                ''
+              else if elem "ati_unfree" driverNames then
+                "ln -sf ${kernelPackages.ati_drivers_x11} /run/opengl-driver"
+              else
+                ''
+                  ${optionalString cfg.driSupport "ln -sf ${pkgs.mesa_drivers} /run/opengl-driver"}
+                  ${optionalString cfg.driSupport32Bit
+                    "ln -sf ${pkgs_i686.mesa_drivers} /run/opengl-driver-32"}
+                ''
+            }
+
+            ${cfg.displayManager.job.preStart}
+
+            rm -f /tmp/.X0-lock
+          '';
+
+        script = "${cfg.displayManager.job.execCmd}";
+      };
+
+    services.xserver.displayManager.xserverArgs =
+      [ "-ac"
+        "-logverbose"
+        "-verbose"
+        "-terminate"
+        "-logfile" "/var/log/X.${toString cfg.display}.log"
+        "-config ${configFile}"
+        ":${toString cfg.display}" "vt${toString cfg.tty}"
+        "-xkbdir" "${pkgs.xkeyboard_config}/etc/X11/xkb"
+      ] ++ optional (!cfg.enableTCP) "-nolisten tcp";
+
+    services.xserver.modules =
+      concatLists (catAttrs "modules" drivers) ++
+      [ xorg.xorgserver
+        xorg.xf86inputevdev
+      ];
+
+    services.xserver.config =
+      ''
+        Section "ServerFlags"
+          Option "AllowMouseOpenFail" "on"
+        EndSection
+
+        Section "Module"
+          ${cfg.moduleSection}
+        EndSection
+
+        Section "Monitor"
+          Identifier "Monitor[0]"
+          ${cfg.monitorSection}
+        EndSection
+
+        Section "InputClass"
+          Identifier "Keyboard catchall"
+          MatchIsKeyboard "on"
+          Option "XkbRules" "base"
+          Option "XkbModel" "${cfg.xkbModel}"
+          Option "XkbLayout" "${cfg.layout}"
+          Option "XkbOptions" "${cfg.xkbOptions}"
+          Option "XkbVariant" "${cfg.xkbVariant}"
+        EndSection
+
+        Section "ServerLayout"
+          Identifier "Layout[all]"
+          ${cfg.serverLayoutSection}
+          # Reference the Screen sections for each driver.  This will
+          # cause the X server to try each in turn.
+          ${flip concatMapStrings drivers (d: ''
+            Screen "Screen-${d.name}[0]"
+          '')}
+        EndSection
+
+        # For each supported driver, add a "Device" and "Screen"
+        # section.
+        ${flip concatMapStrings drivers (driver: ''
+
+          Section "Device"
+            Identifier "Device-${driver.name}[0]"
+            Driver "${driver.driverName}"
+            ${cfg.deviceSection}
+            ${xrandrDeviceSection}
+          EndSection
+
+          Section "Screen"
+            Identifier "Screen-${driver.name}[0]"
+            Device "Device-${driver.name}[0]"
+            ${optionalString (cfg.monitorSection != "") ''
+              Monitor "Monitor[0]"
+            ''}
+
+            ${cfg.screenSection}
+
+            ${optionalString (cfg.defaultDepth != 0) ''
+              DefaultDepth ${toString cfg.defaultDepth}
+            ''}
+
+            ${optionalString (driver.name == "nvidia") ''
+              Option "RandRRotation" "on"
+            ''}
+
+            ${optionalString
+                (driver.name != "virtualbox" &&
+                 (cfg.resolutions != [] ||
+                  cfg.extraDisplaySettings != "" ||
+                  cfg.virtualScreen != null))
+              (let
+                f = depth:
+                  ''
+                    SubSection "Display"
+                      Depth ${toString depth}
+                      ${optionalString (cfg.resolutions != [])
+                        "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}"}
+                      ${cfg.extraDisplaySettings}
+                      ${optionalString (cfg.virtualScreen != null)
+                        "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"}
+                    EndSubSection
+                  '';
+              in concatMapStrings f [8 16 24]
+            )}
+
+          EndSection
+        '')}
+
+        ${xrandrMonitorSections}
+      '';
+
+  }));
+
+}
+