1{ config, pkgs, lib, ... }:
2let
3 inherit (lib) mapAttrs mkIf mkOption optional optionals types;
4
5 cfg = config.services.kmscon;
6
7 autologinArg = lib.optionalString (cfg.autologinUser != null) "-f ${cfg.autologinUser}";
8
9 configDir = pkgs.writeTextFile { name = "kmscon-config"; destination = "/kmscon.conf"; text = cfg.extraConfig; };
10in {
11 options = {
12 services.kmscon = {
13 enable = mkOption {
14 description = lib.mdDoc ''
15 Use kmscon as the virtual console instead of gettys.
16 kmscon is a kms/dri-based userspace virtual terminal implementation.
17 It supports a richer feature set than the standard linux console VT,
18 including full unicode support, and when the video card supports drm
19 should be much faster.
20 '';
21 type = types.bool;
22 default = false;
23 };
24
25 hwRender = mkOption {
26 description = lib.mdDoc "Whether to use 3D hardware acceleration to render the console.";
27 type = types.bool;
28 default = false;
29 };
30
31 fonts = mkOption {
32 description = lib.mdDoc "Fonts used by kmscon, in order of priority.";
33 default = null;
34 example = lib.literalExpression ''[ { name = "Source Code Pro"; package = pkgs.source-code-pro; } ]'';
35 type = with types;
36 let fontType = submodule {
37 options = {
38 name = mkOption { type = str; description = lib.mdDoc "Font name, as used by fontconfig."; };
39 package = mkOption { type = package; description = lib.mdDoc "Package providing the font."; };
40 };
41 }; in nullOr (nonEmptyListOf fontType);
42 };
43
44 extraConfig = mkOption {
45 description = lib.mdDoc "Extra contents of the kmscon.conf file.";
46 type = types.lines;
47 default = "";
48 example = "font-size=14";
49 };
50
51 extraOptions = mkOption {
52 description = lib.mdDoc "Extra flags to pass to kmscon.";
53 type = types.separatedString " ";
54 default = "";
55 example = "--term xterm-256color";
56 };
57
58 autologinUser = mkOption {
59 type = types.nullOr types.str;
60 default = null;
61 description = lib.mdDoc ''
62 Username of the account that will be automatically logged in at the console.
63 If unspecified, a login prompt is shown as usual.
64 '';
65 };
66 };
67 };
68
69 config = mkIf cfg.enable {
70 # Largely copied from unit provided with kmscon source
71 systemd.units."kmsconvt@.service".text = ''
72 [Unit]
73 Description=KMS System Console on %I
74 Documentation=man:kmscon(1)
75 After=systemd-user-sessions.service
76 After=plymouth-quit-wait.service
77 After=systemd-logind.service
78 After=systemd-vconsole-setup.service
79 Requires=systemd-logind.service
80 Before=getty.target
81 Conflicts=getty@%i.service
82 OnFailure=getty@%i.service
83 IgnoreOnIsolate=yes
84 ConditionPathExists=/dev/tty0
85
86 [Service]
87 ExecStart=
88 ExecStart=${pkgs.kmscon}/bin/kmscon "--vt=%I" ${cfg.extraOptions} --seats=seat0 --no-switchvt --configdir ${configDir} --login -- ${pkgs.shadow}/bin/login -p ${autologinArg}
89 UtmpIdentifier=%I
90 TTYPath=/dev/%I
91 TTYReset=yes
92 TTYVHangup=yes
93 TTYVTDisallocate=yes
94
95 X-RestartIfChanged=false
96 '';
97
98 systemd.suppressedSystemUnits = [ "autovt@.service" ];
99 systemd.units."kmsconvt@.service".aliases = [ "autovt@.service" ];
100
101 systemd.services.systemd-vconsole-setup.enable = false;
102 systemd.services.reload-systemd-vconsole-setup.enable = false;
103
104 services.kmscon.extraConfig =
105 let
106 render = optionals cfg.hwRender [ "drm" "hwaccel" ];
107 fonts = optional (cfg.fonts != null) "font-name=${lib.concatMapStringsSep ", " (f: f.name) cfg.fonts}";
108 in lib.concatStringsSep "\n" (render ++ fonts);
109
110 hardware.opengl.enable = mkIf cfg.hwRender true;
111
112 fonts = mkIf (cfg.fonts != null) {
113 fontconfig.enable = true;
114 packages = map (f: f.package) cfg.fonts;
115 };
116 };
117}