Files
2026-05-31 00:01:13 +02:00

244 lines
6.3 KiB
Nix

{
config,
lib,
utils,
pkgs,
...
}:
let
dmcfg = config.services.displayManager;
xcfg = config.services.xserver;
xdmcfg = xcfg.displayManager;
cfg = config.services.displayManager.ly;
xEnv = config.systemd.services.display-manager.environment;
ly = cfg.package.override { x11Support = cfg.x11Support; };
iniFmt = pkgs.formats.iniWithGlobalSection { };
inherit (lib)
attrNames
concatMapStrings
getAttr
mkIf
mkOption
mkEnableOption
mkPackageOption
optionalAttrs
;
xserverWrapper = pkgs.writeShellScript "xserver-wrapper" ''
${concatMapStrings (n: ''
export ${n}="${getAttr n xEnv}"
'') (attrNames xEnv)}
exec systemd-cat -t xserver-wrapper ${xdmcfg.xserverBin} ${toString xdmcfg.xserverArgs} "$@"
'';
defaultConfig = {
shutdown_cmd = "/run/current-system/systemd/bin/systemctl poweroff";
restart_cmd = "/run/current-system/systemd/bin/systemctl reboot";
service_name = "ly";
path = "/run/current-system/sw/bin";
term_reset_cmd = "${pkgs.ncurses}/bin/tput reset";
term_restore_cursor_cmd = "${pkgs.ncurses}/bin/tput cnorm";
waylandsessions = "${dmcfg.sessionData.desktops}/share/wayland-sessions";
xsessions = "${dmcfg.sessionData.desktops}/share/xsessions";
xauth_cmd = lib.optionalString xcfg.enable "${pkgs.xauth}/bin/xauth";
x_cmd = lib.optionalString xcfg.enable xserverWrapper;
setup_cmd = dmcfg.sessionData.wrapper;
brightness_up_cmd = "${lib.getExe pkgs.brightnessctl} -q -n s +10%";
brightness_down_cmd = "${lib.getExe pkgs.brightnessctl} -q -n s 10%-";
}
// optionalAttrs dmcfg.autoLogin.enable {
auto_login_service = "ly-autologin";
auto_login_session = dmcfg.sessionData.autologinSession;
auto_login_user = dmcfg.autoLogin.user;
};
finalConfig = defaultConfig // cfg.settings;
cfgFile = iniFmt.generate "config.ini" { globalSection = finalConfig; };
in
{
options = {
services.displayManager.ly = {
enable = mkEnableOption "ly as the display manager";
x11Support = mkOption {
description = "Whether to enable support for X11";
type = lib.types.bool;
default = true;
};
package = mkPackageOption pkgs [ "ly" ] { };
settings = mkOption {
type = with lib.types; attrsOf iniFmt.lib.types.atom;
default = { };
example = {
load = false;
save = false;
};
description = ''
Extra settings merged in and overwriting defaults in config.ini.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = dmcfg.autoLogin.enable -> dmcfg.sessionData.autologinSession != null;
message = ''
ly auto-login requires that services.displayManager.defaultSession is set.
'';
}
];
security.pam.services = {
ly = {
useDefaultRules = false;
rules = {
auth = utils.pam.autoOrderRules [
{
name = "login";
control = "substack";
modulePath = "login";
}
];
account = utils.pam.autoOrderRules [
{
name = "login";
control = "include";
modulePath = "login";
}
];
password = utils.pam.autoOrderRules [
{
name = "login";
control = "substack";
modulePath = "login";
}
];
session = utils.pam.autoOrderRules [
{
name = "login";
control = "include";
modulePath = "login";
}
];
};
};
}
// optionalAttrs dmcfg.autoLogin.enable {
ly-autologin = {
useDefaultRules = false;
rules = {
auth = utils.pam.autoOrderRules [
{
name = "nologin";
control = "requisite";
modulePath = "${config.security.pam.package}/lib/security/pam_nologin.so";
}
{
name = "ly-normal-user";
control = "required";
modulePath = "${config.security.pam.package}/lib/security/pam_succeed_if.so";
settings.quiet = true;
args = lib.mkBefore [
"uid"
">="
"1000"
];
}
{
name = "permit";
control = "required";
modulePath = "${config.security.pam.package}/lib/security/pam_permit.so";
}
];
account = utils.pam.autoOrderRules [
{
name = "ly";
control = "include";
modulePath = "ly";
}
];
password = utils.pam.autoOrderRules [
{
name = "ly";
control = "include";
modulePath = "ly";
}
];
session = utils.pam.autoOrderRules [
{
name = "ly";
control = "include";
modulePath = "ly";
}
];
};
};
};
environment = {
etc."ly/config.ini".source = cfgFile;
systemPackages = [ ly ];
pathsToLink = [ "/share/ly" ];
};
services = {
dbus.packages = [ ly ];
displayManager = {
enable = true;
generic = {
enable = true;
execCmd = "exec /run/current-system/sw/bin/ly";
};
# Set this here instead of 'defaultConfig' so users get eval
# errors when they change it.
ly.settings.tty = 1;
};
xserver = {
# To enable user switching, allow ly to allocate displays dynamically.
display = null;
};
};
systemd = {
# We're not using the upstream unit, so copy these:
# https://github.com/fairyglade/ly/blob/master/res/ly.service
services.display-manager = {
after = [
"systemd-user-sessions.service"
"plymouth-quit-wait.service"
];
serviceConfig = {
Type = "idle";
StandardInput = "tty";
TTYPath = "/dev/tty${toString finalConfig.tty}";
TTYReset = "yes";
TTYVHangup = "yes";
};
};
};
};
meta.maintainers = with lib.maintainers; [
vonfry
zacharyarnaise
];
}