0
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-07-13 13:40:28 +03:00

Merge pull request #53843 from hedning/session-default

nixos/displayManager: introduce defaultSession
This commit is contained in:
Jan Tojnar 2019-12-18 21:16:06 +01:00 committed by GitHub
commit 6be14ee97b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 305 additions and 224 deletions

View file

@ -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 ];

View file

@ -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.
'';
};
};

View file

@ -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 {

View file

@ -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

View file

@ -118,7 +118,7 @@ in {
};
config = mkIf cfg.enable {
services.xserver.displayManager.extraSessionFilePackages = [
services.xserver.displayManager.sessionPackages = [
pkgs.surf-display
];

View file

@ -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
'';
}

View file

@ -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" ])
];
}

View file

@ -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 = {

View file

@ -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"/>.
'';
};

View file

@ -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

View file

@ -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.
'';
}
];

View file

@ -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.
'';
};
};