summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorJan Tojnar <jtojnar@gmail.com>2019-12-18 21:16:06 +0100
committerGitHub <noreply@github.com>2019-12-18 21:16:06 +0100
commit6be14ee97b5ab32453dddd749fc14e859c2d9214 (patch)
tree0d21472f656d39d30d906e65539d2128cecd2235 /nixos
parent6fd5a4383b5d4102f32d019bdc4379af64ba65c4 (diff)
parent8dc5ff7dcfd1c58c32004ffae25e6d31ed83d86c (diff)
downloadnixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar.gz
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar.bz2
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar.lz
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar.xz
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.tar.zst
nixpkgs-6be14ee97b5ab32453dddd749fc14e859c2d9214.zip
Merge pull request #53843 from hedning/session-default
nixos/displayManager: introduce defaultSession
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/configuration/x-windows.xml3
-rw-r--r--nixos/doc/manual/configuration/xfce.xml5
-rw-r--r--nixos/doc/manual/release-notes/rl-2003.xml13
-rw-r--r--nixos/lib/testing-python.nix3
-rw-r--r--nixos/lib/testing.nix3
-rw-r--r--nixos/modules/programs/sway.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix23
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/pantheon.nix8
-rw-r--r--nixos/modules/services/x11/desktop-managers/surf-display.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/account-service-util.nix39
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix251
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix62
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix5
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix35
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix20
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix15
-rw-r--r--nixos/tests/common/x11.nix8
-rw-r--r--nixos/tests/gnome3-xorg.nix2
-rw-r--r--nixos/tests/i3wm.nix2
-rw-r--r--nixos/tests/lightdm.nix3
-rw-r--r--nixos/tests/plasma5.nix2
-rw-r--r--nixos/tests/sddm.nix6
-rw-r--r--nixos/tests/xmonad.nix4
24 files changed, 297 insertions, 224 deletions
diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml
index 9206f43ea39..55ad9fe6e65 100644
--- a/nixos/doc/manual/configuration/x-windows.xml
+++ b/nixos/doc/manual/configuration/x-windows.xml
@@ -83,8 +83,7 @@
   desktop environment. If you wanted no desktop environment and i3 as your your
   window manager, you'd define:
 <programlisting>
-<xref linkend="opt-services.xserver.desktopManager.default"/> = "none";
-<xref linkend="opt-services.xserver.windowManager.default"/> = "i3";
+<xref linkend="opt-services.xserver.displayManager.defaultSession"/> = "none+i3";
 </programlisting>
   And, finally, to enable auto-login for a user <literal>johndoe</literal>:
 <programlisting>
diff --git a/nixos/doc/manual/configuration/xfce.xml b/nixos/doc/manual/configuration/xfce.xml
index 6ac99c6b2be..027828bb936 100644
--- a/nixos/doc/manual/configuration/xfce.xml
+++ b/nixos/doc/manual/configuration/xfce.xml
@@ -7,9 +7,8 @@
  <para>
   To enable the Xfce Desktop Environment, set
 <programlisting>
-<link linkend="opt-services.xserver.desktopManager.default">services.xserver.desktopManager</link> = {
-  <link linkend="opt-services.xserver.desktopManager.xfce.enable">xfce.enable</link> = true;
-  <link linkend="opt-services.xserver.desktopManager.default">default</link> = "xfce";
+<xref linkend="opt-services.xserver.desktopManager.xfce.enable" /> = true;
+<xref linkend="opt-services.xserver.displayManager.defaultSession" /> = "xfce";
 };
 </programlisting>
  </para>
diff --git a/nixos/doc/manual/release-notes/rl-2003.xml b/nixos/doc/manual/release-notes/rl-2003.xml
index 2a38b2adbbb..247e9cd063c 100644
--- a/nixos/doc/manual/release-notes/rl-2003.xml
+++ b/nixos/doc/manual/release-notes/rl-2003.xml
@@ -55,6 +55,19 @@
       and adding a <option>--all</option> option which prints all options and their values.
     </para>
    </listitem>
+   <listitem>
+    <para>
+     <option>services.xserver.desktopManager.default</option> and <option>services.xserver.windowManager.default</option> options were replaced by a single <xref linkend="opt-services.xserver.displayManager.defaultSession"/> option to improve support for upstream session files. If you used something like:
+<programlisting>
+services.xserver.desktopManager.default = "xfce";
+services.xserver.windowManager.default = "icewm";
+</programlisting>
+     you should change it to:
+<programlisting>
+services.xserver.displayManager.defaultSession = "xfce+icewm";
+</programlisting>
+    </para>
+   </listitem>
   </itemizedlist>
  </section>
 
diff --git a/nixos/lib/testing-python.nix b/nixos/lib/testing-python.nix
index d567d268765..c4eb9328b1d 100644
--- a/nixos/lib/testing-python.nix
+++ b/nixos/lib/testing-python.nix
@@ -262,9 +262,8 @@ in rec {
           virtualisation.memorySize = 1024;
           services.xserver.enable = true;
           services.xserver.displayManager.auto.enable = true;
-          services.xserver.windowManager.default = "icewm";
+          services.xserver.displayManager.defaultSession = "none+icewm";
           services.xserver.windowManager.icewm.enable = true;
-          services.xserver.desktopManager.default = "none";
         };
     in
       runInMachine ({
diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix
index a5f060a8d8e..ae8ecd6270c 100644
--- a/nixos/lib/testing.nix
+++ b/nixos/lib/testing.nix
@@ -249,9 +249,8 @@ in rec {
           virtualisation.memorySize = 1024;
           services.xserver.enable = true;
           services.xserver.displayManager.auto.enable = true;
-          services.xserver.windowManager.default = "icewm";
+          services.xserver.displayManager.defaultSession = "none+icewm";
           services.xserver.windowManager.icewm.enable = true;
-          services.xserver.desktopManager.default = "none";
         };
     in
       runInMachine ({
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index 9a15c773463..d685a525932 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -24,6 +24,7 @@ let
   swayJoined = pkgs.symlinkJoin {
     name = "sway-joined";
     paths = [ swayWrapped swayPackage ];
+    passthru.providedSessions = [ "sway" ];
   };
 in {
   options.programs.sway = {
@@ -88,7 +89,7 @@ in {
     fonts.enableDefaultFonts = mkDefault true;
     programs.dconf.enable = mkDefault true;
     # To make a Sway session available if a display manager like SDDM is enabled:
-    services.xserver.displayManager.extraSessionFilePackages = [ swayJoined ];
+    services.xserver.displayManager.sessionPackages = [ swayJoined ];
   };
 
   meta.maintainers = with lib.maintainers; [ gnidorah primeos colemickens ];
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 671a959cdde..534551c0c4a 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -86,23 +86,14 @@ in
       };
 
       default = mkOption {
-        type = types.str;
-        default = "";
+        type = types.nullOr types.str;
+        default = null;
         example = "none";
-        description = "Default desktop manager loaded if none have been chosen.";
-        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
-            builtins.trace ''
-              Default desktop manager (${defaultDM}) not found at evaluation time.
-              These are the known valid session names:
-                ${concatMapStringsSep "\n  " (w: "services.xserver.desktopManager.default = \"${w.name}\";") cfg.session.list}
-              It's also possible the default can be found in one of these packages:
-                ${concatMapStringsSep "\n  " (p: p.name) config.services.xserver.displayManager.extraSessionFilePackages}
-            '' defaultDM;
+        description = ''
+          <emphasis role="strong">Deprecated</emphasis>, please use <xref linkend="opt-services.xserver.displayManager.defaultSession"/> instead.
+
+          Default desktop manager loaded if none have been chosen.
+        '';
       };
 
     };
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 6725595e1cf..6d9bd284bc7 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -144,7 +144,7 @@ in
       services.gnome3.core-shell.enable = true;
       services.gnome3.core-utilities.enable = mkDefault true;
 
-      services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ];
+      services.xserver.displayManager.sessionPackages = [ pkgs.gnome3.gnome-session ];
 
       environment.extraInit = ''
         ${concatMapStrings (p: ''
@@ -171,7 +171,7 @@ in
     })
 
     (mkIf flashbackEnabled {
-      services.xserver.displayManager.extraSessionFilePackages =  map
+      services.xserver.displayManager.sessionPackages =  map
         (wm: pkgs.gnome3.gnome-flashback.mkSessionForWm {
           inherit (wm) wmName wmLabel wmCommand;
         }) (optional cfg.flashback.enableMetacity {
diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix
index 99db5b17b64..e07d5b5eaad 100644
--- a/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -69,7 +69,7 @@ in
 
   config = mkIf cfg.enable {
 
-    services.xserver.displayManager.extraSessionFilePackages = [ pkgs.pantheon.elementary-session-settings ];
+    services.xserver.displayManager.sessionPackages = [ pkgs.pantheon.elementary-session-settings ];
 
     # Ensure lightdm is used when Pantheon is enabled
     # Without it screen locking will be nonfunctional because of the use of lightlocker
@@ -81,9 +81,9 @@ in
 
     services.xserver.displayManager.lightdm.greeters.pantheon.enable = mkDefault true;
 
-    # If not set manually Pantheon session cannot be started
-    # Known issue of https://github.com/NixOS/nixpkgs/pull/43992
-    services.xserver.desktopManager.default = mkForce "pantheon";
+    # Without this, Elementary LightDM greeter will pre-select non-existent `default` session
+    # https://github.com/elementary/greeter/issues/368
+    services.xserver.displayManager.defaultSession = "pantheon";
 
     services.xserver.displayManager.sessionCommands = ''
       if test "$XDG_CURRENT_DESKTOP" = "Pantheon"; then
diff --git a/nixos/modules/services/x11/desktop-managers/surf-display.nix b/nixos/modules/services/x11/desktop-managers/surf-display.nix
index 140dde828da..9aeb0bbd2a8 100644
--- a/nixos/modules/services/x11/desktop-managers/surf-display.nix
+++ b/nixos/modules/services/x11/desktop-managers/surf-display.nix
@@ -118,7 +118,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    services.xserver.displayManager.extraSessionFilePackages = [
+    services.xserver.displayManager.sessionPackages = [
       pkgs.surf-display
     ];
 
diff --git a/nixos/modules/services/x11/display-managers/account-service-util.nix b/nixos/modules/services/x11/display-managers/account-service-util.nix
new file mode 100644
index 00000000000..1dbe703b566
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/account-service-util.nix
@@ -0,0 +1,39 @@
+{ accountsservice
+, glib
+, gobject-introspection
+, python3
+, wrapGAppsHook
+}:
+
+python3.pkgs.buildPythonApplication {
+  name = "set-session";
+
+  format = "other";
+
+  src = ./set-session.py;
+
+  dontUnpack = true;
+
+  strictDeps = false;
+
+  nativeBuildInputs = [
+    wrapGAppsHook
+    gobject-introspection
+  ];
+
+  buildInputs = [
+    accountsservice
+    glib
+  ];
+
+  propagatedBuildInputs = with python3.pkgs; [
+    pygobject3
+    ordered-set
+  ];
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp $src $out/bin/set-session
+    chmod +x $out/bin/set-session
+  '';
+}
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index c252c3c90c9..2d809b5cc9f 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -27,16 +27,7 @@ let
     Xft.hintstyle: hintslight
   '';
 
-  mkCases = session:
-    concatStrings (
-      mapAttrsToList (name: starts: ''
-                       (${name})
-                         ${concatMapStringsSep "\n  " (n: n.start) starts}
-                         ;;
-                     '') (lib.groupBy (n: n.name) session)
-    );
-
-  # file provided by services.xserver.displayManager.session.wrapper
+  # file provided by services.xserver.displayManager.sessionData.wrapper
   xsessionWrapper = pkgs.writeScript "xsession-wrapper"
     ''
       #! ${pkgs.bash}/bin/bash
@@ -116,94 +107,44 @@ let
           # Run the supplied session command. Remove any double quotes with eval.
           eval exec "$@"
       else
-          # Fall back to the default window/desktopManager
-          exec ${cfg.displayManager.session.script}
+          # TODO: Do we need this? Should not the session always exist?
+          echo "error: unknown session $1" 1>&2
+          exit 1
       fi
     '';
 
-  # file provided by services.xserver.displayManager.session.script
-  xsession = wm: dm: pkgs.writeScript "xsession"
-    ''
-      #! ${pkgs.bash}/bin/bash
-
-      # Legacy session script used to construct .desktop files from
-      # `services.xserver.displayManager.session` entries. Called from
-      # `sessionWrapper`.
-
-      # Expected parameters:
-      #   $1 = <desktop-manager>+<window-manager>
-
-      # The first argument of this script is the session type.
-      sessionType="$1"
-      if [ "$sessionType" = default ]; then sessionType=""; fi
-
-      # The session type is "<desktop-manager>+<window-manager>", so
-      # extract those (see:
-      # http://wiki.bash-hackers.org/syntax/pe#substring_removal).
-      windowManager="''${sessionType##*+}"
-      : ''${windowManager:=${cfg.windowManager.default}}
-      desktopManager="''${sessionType%%+*}"
-      : ''${desktopManager:=${cfg.desktopManager.default}}
-
-      # Start the window manager.
-      case "$windowManager" in
-        ${mkCases wm}
-        (*) echo "$0: Window manager '$windowManager' not found.";;
-      esac
-
-      # Start the desktop manager.
-      case "$desktopManager" in
-        ${mkCases dm}
-        (*) echo "$0: Desktop manager '$desktopManager' not found.";;
-      esac
-
-      ${optionalString cfg.updateDbusEnvironment ''
-        ${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
-      ''}
-
-      test -n "$waitPID" && wait "$waitPID"
-
-      ${config.systemd.package}/bin/systemctl --user stop graphical-session.target
-
-      exit 0
-    '';
-
-  # Desktop Entry Specification:
-  # - https://standards.freedesktop.org/desktop-entry-spec/latest/
-  # - https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
-  mkDesktops = names: pkgs.runCommand "desktops"
+  installedSessions = pkgs.runCommand "desktops"
     { # trivial derivation
       preferLocalBuild = true;
       allowSubstitutes = false;
     }
     ''
-      mkdir -p "$out/share/xsessions"
-      ${concatMapStrings (n: ''
-        cat - > "$out/share/xsessions/${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}
+      mkdir -p "$out/share/"{xsessions,wayland-sessions}
 
       ${concatMapStrings (pkg: ''
+        for n in ${concatStringsSep " " pkg.providedSessions}; do
+          if ! test -f ${pkg}/share/wayland-sessions/$n.desktop -o \
+                    -f ${pkg}/share/xsessions/$n.desktop; then
+            echo "Couldn't find provided session name, $n.desktop, in session package ${pkg.name}:"
+            echo "  ${pkg}"
+            return 1
+          fi
+        done
+
         if test -d ${pkg}/share/xsessions; then
           ${xorg.lndir}/bin/lndir ${pkg}/share/xsessions $out/share/xsessions
         fi
-      '') cfg.displayManager.extraSessionFilePackages}
-
-      ${concatMapStrings (pkg: ''
         if test -d ${pkg}/share/wayland-sessions; then
-          mkdir -p "$out/share/wayland-sessions"
           ${xorg.lndir}/bin/lndir ${pkg}/share/wayland-sessions $out/share/wayland-sessions
         fi
-      '') cfg.displayManager.extraSessionFilePackages}
+      '') cfg.displayManager.sessionPackages}
     '';
 
+  dmDefault = cfg.desktopManager.default;
+  wmDefault = cfg.windowManager.default;
+
+  defaultSessionFromLegacyOptions = concatStringsSep "+" (filter (s: s != null) ([ dmDefault ] ++ optional (wmDefault != "none") wmDefault));
+
 in
 
 {
@@ -261,11 +202,24 @@ in
         '';
       };
 
-      extraSessionFilePackages = mkOption {
-        type = types.listOf types.package;
+      sessionPackages = mkOption {
+        type = with types; listOf (package // {
+          description = "package with provided sessions";
+          check = p: assertMsg
+            (package.check p && p ? providedSessions
+            && p.providedSessions != [] && all isString p.providedSessions)
+            ''
+              Package, '${p.name}', did not specify any session names, as strings, in
+              'passthru.providedSessions'. This is required when used as a session package.
+
+              The session names can be looked up in:
+                ${p}/share/xsessions
+                ${p}/share/wayland-sessions
+           '';
+        });
         default = [];
         description = ''
-          A list of packages containing xsession files to be passed to the display manager.
+          A list of packages containing x11 or wayland session files to be passed to the display manager.
         '';
       };
 
@@ -296,18 +250,50 @@ in
           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;
+      };
+
+      sessionData = mkOption {
+        description = "Data exported for display managers’ convenience";
+        internal = true;
+        default = {};
+        apply = val: {
           wrapper = xsessionWrapper;
+          desktops = installedSessions;
+          sessionNames = concatMap (p: p.providedSessions) cfg.displayManager.sessionPackages;
+          # We do not want to force users to set defaultSession when they have only single DE.
+          autologinSession =
+            if cfg.displayManager.defaultSession != null then
+              cfg.displayManager.defaultSession
+            else if cfg.displayManager.sessionData.sessionNames != [] then
+              head cfg.displayManager.sessionData.sessionNames
+            else
+              null;
         };
       };
 
+      defaultSession = mkOption {
+        type = with types; nullOr str // {
+          description = "session name";
+          check = d:
+            assertMsg (d != null -> (str.check d && elem d cfg.displayManager.sessionData.sessionNames)) ''
+                Default graphical session, '${d}', not found.
+                Valid names for 'services.xserver.displayManager.defaultSession' are:
+                  ${concatStringsSep "\n  " cfg.displayManager.sessionData.sessionNames}
+              '';
+        };
+        default =
+          if dmDefault != null || wmDefault != null then
+            defaultSessionFromLegacyOptions
+          else
+            null;
+        example = "gnome";
+        description = ''
+          Graphical session to pre-select in the session chooser (only effective for GDM and LightDM).
+
+          On GDM, LightDM and SDDM, it will also be used as a session for auto-login.
+        '';
+      };
+
       job = {
 
         preStart = mkOption {
@@ -356,6 +342,27 @@ in
   };
 
   config = {
+    assertions = [
+      {
+        assertion = cfg.desktopManager.default != null || cfg.windowManager.default != null -> cfg.displayManager.defaultSession == defaultSessionFromLegacyOptions;
+        message = "You cannot use both services.xserver.displayManager.defaultSession option and legacy options (services.xserver.desktopManager.default and services.xserver.windowManager.default).";
+      }
+    ];
+
+    warnings =
+      mkIf (dmDefault != null || wmDefault != null) [
+        ''
+          The following options are deprecated:
+            ${concatStringsSep "\n  " (map ({c, t}: t) (filter ({c, t}: c != null) [
+            { c = dmDefault; t = "- services.xserver.desktopManager.default"; }
+            { c = wmDefault; t = "- services.xserver.windowManager.default"; }
+            ]))}
+          Please use
+            services.xserver.displayManager.defaultSession = "${concatStringsSep "+" (filter (s: s != null) [ dmDefault wmDefault ])}";
+          instead.
+        ''
+      ];
+
     services.xserver.displayManager.xserverBin = "${xorg.xorgserver.out}/bin/X";
 
     systemd.user.targets.graphical-session = {
@@ -364,6 +371,67 @@ in
         StopWhenUnneeded = false;
       };
     };
+
+    # Create desktop files and scripts for starting sessions for WMs/DMs
+    # that do not have upstream session files (those defined using services.{display,desktop,window}Manager.session options).
+    services.xserver.displayManager.sessionPackages =
+      let
+        dms = filter (s: s.manage == "desktop") cfg.displayManager.session;
+        wms = filter (s: s.manage == "window") cfg.displayManager.session;
+
+        # Script responsible for starting the window manager and the desktop manager.
+        xsession = wm: dm: pkgs.writeScript "xsession" ''
+          #! ${pkgs.bash}/bin/bash
+
+          # Legacy session script used to construct .desktop files from
+          # `services.xserver.displayManager.session` entries. Called from
+          # `sessionWrapper`.
+
+          # Start the window manager.
+          ${wm.start}
+
+          # Start the desktop manager.
+          ${dm.start}
+
+          ${optionalString cfg.updateDbusEnvironment ''
+            ${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
+          ''}
+
+          test -n "$waitPID" && wait "$waitPID"
+
+          ${config.systemd.package}/bin/systemctl --user stop graphical-session.target
+
+          exit 0
+        '';
+      in
+        # We will generate every possible pair of WM and DM.
+        concatLists (
+          crossLists
+            (dm: wm: let
+              sessionName = "${dm.name}${optionalString (wm.name != "none") ("+" + wm.name)}";
+              script = xsession dm wm;
+            in
+              optional (dm.name != "none" || wm.name != "none")
+                (pkgs.writeTextFile {
+                  name = "${sessionName}-xsession";
+                  destination = "/share/xsessions/${sessionName}.desktop";
+                  # Desktop Entry Specification:
+                  # - https://standards.freedesktop.org/desktop-entry-spec/latest/
+                  # - https://standards.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
+                  text = ''
+                    [Desktop Entry]
+                    Version=1.0
+                    Type=XSession
+                    TryExec=${script}
+                    Exec=${script}
+                    Name=${sessionName}
+                  '';
+                } // {
+                  providedSessions = [ sessionName ];
+                })
+            )
+            [dms wms]
+          );
   };
 
   imports = [
@@ -371,6 +439,7 @@ in
      "The option is no longer necessary because all display managers have already delegated lid management to systemd.")
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "job" "logsXsession" ] [ "services" "xserver" "displayManager" "job" "logToFile" ])
     (mkRenamedOptionModule [ "services" "xserver" "displayManager" "logToJournal" ] [ "services" "xserver" "displayManager" "job" "logToJournal" ])
+    (mkRenamedOptionModule [ "services" "xserver" "displayManager" "extraSessionFilesPackages" ] [ "services" "xserver" "displayManager" "sessionPackages" ])
   ];
 
 }
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 095569fa08a..6630f012f04 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -31,44 +31,9 @@ let
     load-module module-position-event-sounds
   '';
 
-  dmDefault = config.services.xserver.desktopManager.default;
-  wmDefault = config.services.xserver.windowManager.default;
-  hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
-  defaultSessionName = dmDefault + optionalString (wmDefault != "none") ("+" + wmDefault);
-
-  setSessionScript = pkgs.python3.pkgs.buildPythonApplication {
-    name = "set-session";
-
-    format = "other";
-
-    src = ./set-session.py;
-
-    dontUnpack = true;
-
-    strictDeps = false;
-
-    nativeBuildInputs = with pkgs; [
-      wrapGAppsHook
-      gobject-introspection
-    ];
-
-    buildInputs = with pkgs; [
-      accountsservice
-      glib
-    ];
-
-    propagatedBuildInputs = with pkgs.python3.pkgs; [
-      pygobject3
-      ordered-set
-    ];
-
-    installPhase = ''
-      mkdir -p $out/bin
-      cp $src $out/bin/set-session
-      chmod +x $out/bin/set-session
-    '';
-  };
+  defaultSessionName = config.services.xserver.displayManager.defaultSession;
 
+  setSessionScript = pkgs.callPackage ./account-service-util.nix { };
 in
 
 {
@@ -186,7 +151,7 @@ in
         environment = {
           GDM_X_SERVER_EXTRA_ARGS = toString
             (filter (arg: arg != "-terminate") cfg.xserverArgs);
-          XDG_DATA_DIRS = "${cfg.session.desktops}/share/";
+          XDG_DATA_DIRS = "${cfg.sessionData.desktops}/share/";
         } // optionalAttrs (xSessionWrapper != null) {
           # Make GDM use this wrapper before running the session, which runs the
           # configured setupCommands. This relies on a patched GDM which supports
@@ -204,16 +169,19 @@ in
           cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF
           yes
           EOF
-        ''
-        # TODO: Make setSessionScript aware of previously used sessions
-        # + optionalString hasDefaultUserSession ''
-        #   ${setSessionScript}/bin/set-session ${defaultSessionName}
-        # ''
-        ;
+        '' + optionalString (defaultSessionName != null) ''
+          # Set default session in session chooser to a specified values – basically ignore session history.
+          ${setSessionScript}/bin/set-session ${cfg.sessionData.autologinSession}
+        '';
       };
 
-    # Because sd_login_monitor_new requires /run/systemd/machines
-    systemd.services.display-manager.wants = [ "systemd-machined.service" ];
+    systemd.services.display-manager.wants = [
+      # Because sd_login_monitor_new requires /run/systemd/machines
+      "systemd-machined.service"
+      # setSessionScript wants AccountsService
+      "accounts-daemon.service"
+    ];
+
     systemd.services.display-manager.after = [
       "rc-local.service"
       "systemd-machined.service"
@@ -329,7 +297,7 @@ in
       ${optionalString cfg.gdm.debug "Enable=true"}
     '';
 
-    environment.etc."gdm/Xsession".source = config.services.xserver.displayManager.session.wrapper;
+    environment.etc."gdm/Xsession".source = config.services.xserver.displayManager.sessionData.wrapper;
 
     # GDM LFS PAM modules, adapted somehow to NixOS
     security.pam.services = {
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
index fa9445af32e..0025f9b3603 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
@@ -53,9 +53,8 @@ in
           Whether to enable lightdm-mini-greeter as the lightdm greeter.
 
           Note that this greeter starts only the default X session.
-          You can configure the default X session by
-          <option>services.xserver.desktopManager.default</option> and
-          <option>services.xserver.windowManager.default</option>.
+          You can configure the default X session using
+          <xref linkend="opt-services.xserver.displayManager.defaultSession"/>.
         '';
       };
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index cf4c05acbcc..f7face0adb7 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -8,10 +8,9 @@ let
   dmcfg = xcfg.displayManager;
   xEnv = config.systemd.services.display-manager.environment;
   cfg = dmcfg.lightdm;
+  sessionData = dmcfg.sessionData;
 
-  dmDefault = xcfg.desktopManager.default;
-  wmDefault = xcfg.windowManager.default;
-  hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
+  setSessionScript = pkgs.callPackage ./account-service-util.nix { };
 
   inherit (pkgs) lightdm writeScript writeText;
 
@@ -45,22 +44,19 @@ let
         greeter-user = ${config.users.users.lightdm.name}
         greeters-directory = ${cfg.greeter.package}
       ''}
-      sessions-directory = ${dmcfg.session.desktops}/share/xsessions
+      sessions-directory = ${dmcfg.sessionData.desktops}/share/xsessions:${dmcfg.sessionData.desktops}/share/wayland-sessions
       ${cfg.extraConfig}
 
       [Seat:*]
       xserver-command = ${xserverWrapper}
-      session-wrapper = ${dmcfg.session.wrapper}
+      session-wrapper = ${dmcfg.sessionData.wrapper}
       ${optionalString cfg.greeter.enable ''
         greeter-session = ${cfg.greeter.name}
       ''}
       ${optionalString cfg.autoLogin.enable ''
         autologin-user = ${cfg.autoLogin.user}
         autologin-user-timeout = ${toString cfg.autoLogin.timeout}
-        autologin-session = ${defaultSessionName}
-      ''}
-      ${optionalString hasDefaultUserSession ''
-        user-session=${defaultSessionName}
+        autologin-session = ${sessionData.autologinSession}
       ''}
       ${optionalString (dmcfg.setupCommands != "") ''
         display-setup-script=${pkgs.writeScript "lightdm-display-setup" ''
@@ -71,7 +67,6 @@ let
       ${cfg.extraSeatDefaults}
     '';
 
-  defaultSessionName = dmDefault + optionalString (wmDefault != "none") ("+" + wmDefault);
 in
 {
   # Note: the order in which lightdm greeter modules are imported
@@ -199,11 +194,9 @@ in
           LightDM auto-login requires services.xserver.displayManager.lightdm.autoLogin.user to be set
         '';
       }
-      { assertion = cfg.autoLogin.enable -> dmDefault != "none" || wmDefault != "none";
+      { assertion = cfg.autoLogin.enable -> sessionData.autologinSession != null;
         message = ''
-          LightDM auto-login requires that services.xserver.desktopManager.default and
-          services.xserver.windowManager.default are set to valid values. The current
-          default session: ${defaultSessionName} is not valid.
+          LightDM auto-login requires that services.xserver.displayManager.defaultSession is set.
         '';
       }
       { assertion = !cfg.greeter.enable -> (cfg.autoLogin.enable && cfg.autoLogin.timeout == 0);
@@ -214,6 +207,20 @@ in
       }
     ];
 
+    # Set default session in session chooser to a specified values – basically ignore session history.
+    # Auto-login is already covered by a config value.
+    services.xserver.displayManager.job.preStart = optionalString (!cfg.autoLogin.enable && dmcfg.defaultSession != null) ''
+      ${setSessionScript}/bin/set-session ${dmcfg.defaultSession}
+    '';
+
+    # setSessionScript needs session-files in XDG_DATA_DIRS
+    services.xserver.displayManager.job.environment.XDG_DATA_DIRS = "${dmcfg.sessionData.desktops}/share/";
+
+    # setSessionScript wants AccountsService
+    systemd.services.display-manager.wants = [
+      "accounts-daemon.service"
+    ];
+
     # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH
     services.xserver.displayManager.job.execCmd = ''
       export PATH=${lightdm}/sbin:$PATH
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 24e120c4f2c..4224c557ed6 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -50,8 +50,8 @@ let
     MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
     ServerPath=${xserverWrapper}
     XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
-    SessionCommand=${dmcfg.session.wrapper}
-    SessionDir=${dmcfg.session.desktops}/share/xsessions
+    SessionCommand=${dmcfg.sessionData.wrapper}
+    SessionDir=${dmcfg.sessionData.desktops}/share/xsessions
     XauthPath=${pkgs.xorg.xauth}/bin/xauth
     DisplayCommand=${Xsetup}
     DisplayStopCommand=${Xstop}
@@ -59,23 +59,19 @@ let
 
     [Wayland]
     EnableHidpi=${if cfg.enableHidpi then "true" else "false"}
-    SessionDir=${dmcfg.session.desktops}/share/wayland-sessions
+    SessionDir=${dmcfg.sessionData.desktops}/share/wayland-sessions
 
     ${optionalString cfg.autoLogin.enable ''
     [Autologin]
     User=${cfg.autoLogin.user}
-    Session=${defaultSessionName}.desktop
+    Session=${autoLoginSessionName}.desktop
     Relogin=${boolToString cfg.autoLogin.relogin}
     ''}
 
     ${cfg.extraConfig}
   '';
 
-  defaultSessionName =
-    let
-      dm = xcfg.desktopManager.default;
-      wm = xcfg.windowManager.default;
-    in dm + optionalString (wm != "none") ("+" + wm);
+  autoLoginSessionName = dmcfg.sessionData.autologinSession;
 
 in
 {
@@ -210,11 +206,9 @@ in
           SDDM auto-login requires services.xserver.displayManager.sddm.autoLogin.user to be set
         '';
       }
-      { assertion = cfg.autoLogin.enable -> elem defaultSessionName dmcfg.session.names;
+      { assertion = cfg.autoLogin.enable -> autoLoginSessionName != null;
         message = ''
-          SDDM auto-login requires that services.xserver.desktopManager.default and
-          services.xserver.windowManager.default are set to valid values. The current
-          default session: ${defaultSessionName} is not valid.
+          SDDM auto-login requires that services.xserver.displayManager.defaultSession is set.
         '';
       }
     ];
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index c17f3830d0e..04a9fc46628 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -59,15 +59,14 @@ in
       };
 
       default = mkOption {
-        type = types.str;
-        default = "none";
+        type = types.nullOr types.str;
+        default = null;
         example = "wmii";
-        description = "Default window manager loaded if none have been chosen.";
-        apply = defaultWM:
-          if any (w: w.name == defaultWM) cfg.session then
-            defaultWM
-          else
-            throw "Default window manager (${defaultWM}) not found.";
+        description = ''
+          <emphasis role="strong">Deprecated</emphasis>, please use <xref linkend="opt-services.xserver.displayManager.defaultSession"/> instead.
+
+          Default window manager loaded if none have been chosen.
+        '';
       };
 
     };
diff --git a/nixos/tests/common/x11.nix b/nixos/tests/common/x11.nix
index c5a7c165d12..5ad0ac20fac 100644
--- a/nixos/tests/common/x11.nix
+++ b/nixos/tests/common/x11.nix
@@ -1,12 +1,12 @@
+{ lib, ... }:
+
 { services.xserver.enable = true;
 
   # Automatically log in.
   services.xserver.displayManager.auto.enable = true;
 
   # Use IceWM as the window manager.
-  services.xserver.windowManager.default = "icewm";
-  services.xserver.windowManager.icewm.enable = true;
-
   # Don't use a desktop manager.
-  services.xserver.desktopManager.default = "none";
+  services.xserver.displayManager.defaultSession = lib.mkDefault "none+icewm";
+  services.xserver.windowManager.icewm.enable = true;
 }
diff --git a/nixos/tests/gnome3-xorg.nix b/nixos/tests/gnome3-xorg.nix
index eb4c376319b..aa03501f6a5 100644
--- a/nixos/tests/gnome3-xorg.nix
+++ b/nixos/tests/gnome3-xorg.nix
@@ -16,7 +16,7 @@ import ./make-test.nix ({ pkgs, ...} : {
       services.xserver.displayManager.lightdm.autoLogin.enable = true;
       services.xserver.displayManager.lightdm.autoLogin.user = "alice";
       services.xserver.desktopManager.gnome3.enable = true;
-      services.xserver.desktopManager.default = "gnome-xorg";
+      services.xserver.displayManager.defaultSession = "gnome-xorg";
 
       virtualisation.memorySize = 1024;
     };
diff --git a/nixos/tests/i3wm.nix b/nixos/tests/i3wm.nix
index 8afa845f1e2..126178d1187 100644
--- a/nixos/tests/i3wm.nix
+++ b/nixos/tests/i3wm.nix
@@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, ...} : {
   machine = { lib, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     services.xserver.displayManager.auto.user = "alice";
-    services.xserver.windowManager.default = lib.mkForce "i3";
+    services.xserver.displayManager.defaultSession = lib.mkForce "none+i3";
     services.xserver.windowManager.i3.enable = true;
   };
 
diff --git a/nixos/tests/lightdm.nix b/nixos/tests/lightdm.nix
index ef30f7741e2..46c2ed7ccc5 100644
--- a/nixos/tests/lightdm.nix
+++ b/nixos/tests/lightdm.nix
@@ -8,9 +8,8 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.displayManager.lightdm.enable = true;
-    services.xserver.windowManager.default = "icewm";
+    services.xserver.displayManager.defaultSession = "none+icewm";
     services.xserver.windowManager.icewm.enable = true;
-    services.xserver.desktopManager.default = "none";
   };
 
   enableOCR = true;
diff --git a/nixos/tests/plasma5.nix b/nixos/tests/plasma5.nix
index 6884f17aabb..2eccfdf47f5 100644
--- a/nixos/tests/plasma5.nix
+++ b/nixos/tests/plasma5.nix
@@ -12,8 +12,8 @@ import ./make-test-python.nix ({ pkgs, ...} :
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.displayManager.sddm.enable = true;
+    services.xserver.displayManager.defaultSession = "plasma5";
     services.xserver.desktopManager.plasma5.enable = true;
-    services.xserver.desktopManager.default = "plasma5";
     services.xserver.displayManager.sddm.autoLogin = {
       enable = true;
       user = "alice";
diff --git a/nixos/tests/sddm.nix b/nixos/tests/sddm.nix
index 4bdcd701dcf..a145705250f 100644
--- a/nixos/tests/sddm.nix
+++ b/nixos/tests/sddm.nix
@@ -16,9 +16,8 @@ let
         imports = [ ./common/user-account.nix ];
         services.xserver.enable = true;
         services.xserver.displayManager.sddm.enable = true;
-        services.xserver.windowManager.default = "icewm";
+        services.xserver.displayManager.defaultSession = "none+icewm";
         services.xserver.windowManager.icewm.enable = true;
-        services.xserver.desktopManager.default = "none";
       };
 
       enableOCR = true;
@@ -52,9 +51,8 @@ let
             user = "alice";
           };
         };
-        services.xserver.windowManager.default = "icewm";
+        services.xserver.displayManager.defaultSession = "none+icewm";
         services.xserver.windowManager.icewm.enable = true;
-        services.xserver.desktopManager.default = "none";
       };
 
       testScript = { nodes, ... }: let
diff --git a/nixos/tests/xmonad.nix b/nixos/tests/xmonad.nix
index ab3888ca43f..ef711f8dcf6 100644
--- a/nixos/tests/xmonad.nix
+++ b/nixos/tests/xmonad.nix
@@ -4,10 +4,10 @@ import ./make-test-python.nix ({ pkgs, ...} : {
     maintainers = [ nequissimus ];
   };
 
-  machine = { lib, pkgs, ... }: {
+  machine = { pkgs, ... }: {
     imports = [ ./common/x11.nix ./common/user-account.nix ];
     services.xserver.displayManager.auto.user = "alice";
-    services.xserver.windowManager.default = lib.mkForce "xmonad";
+    services.xserver.displayManager.defaultSession = "none+xmonad";
     services.xserver.windowManager.xmonad = {
       enable = true;
       enableContribAndExtras = true;