1{ config
2, lib
3, pkgs
4, ...
5}:
6let
7 inherit (lib) mkDefault mkEnableOption mkIf mkOption mkPackageOption types;
8
9 cfg = config.services.monado;
10
11in
12{
13 options.services.monado = {
14 enable = mkEnableOption "Monado user service";
15
16 package = mkPackageOption pkgs "monado" { };
17
18 defaultRuntime = mkOption {
19 type = types.bool;
20 description = ''
21 Whether to enable Monado as the default OpenXR runtime on the system.
22
23 Note that applications can bypass this option by setting an active
24 runtime in a writable XDG_CONFIG_DIRS location like `~/.config`.
25 '';
26 default = false;
27 example = true;
28 };
29
30 highPriority = mkEnableOption "high priority capability for monado-service"
31 // mkOption { default = true; };
32 };
33
34 config = mkIf cfg.enable {
35 security.wrappers."monado-service" = mkIf cfg.highPriority {
36 setuid = false;
37 owner = "root";
38 group = "root";
39 # cap_sys_nice needed for asynchronous reprojection
40 capabilities = "cap_sys_nice+eip";
41 source = lib.getExe' cfg.package "monado-service";
42 };
43
44 services.udev.packages = with pkgs; [ xr-hardware ];
45
46 systemd.user = {
47 services.monado = {
48 description = "Monado XR runtime service module";
49 requires = [ "monado.socket" ];
50 conflicts = [ "monado-dev.service" ];
51
52 unitConfig.ConditionUser = "!root";
53
54 environment = {
55 # Default options
56 # https://gitlab.freedesktop.org/monado/monado/-/blob/4548e1738591d0904f8db4df8ede652ece889a76/src/xrt/targets/service/monado.in.service#L12
57 XRT_COMPOSITOR_LOG = mkDefault "debug";
58 XRT_PRINT_OPTIONS = mkDefault "on";
59 IPC_EXIT_ON_DISCONNECT = mkDefault "off";
60 };
61
62 serviceConfig = {
63 ExecStart =
64 if cfg.highPriority
65 then "${config.security.wrapperDir}/monado-service"
66 else lib.getExe' cfg.package "monado-service";
67 Restart = "no";
68 };
69
70 restartTriggers = [ cfg.package ];
71 };
72
73 sockets.monado = {
74 description = "Monado XR service module connection socket";
75 conflicts = [ "monado-dev.service" ];
76
77 unitConfig.ConditionUser = "!root";
78
79 socketConfig = {
80 ListenStream = "%t/monado_comp_ipc";
81 RemoveOnStop = true;
82
83 # If Monado crashes while starting up, we want to close incoming OpenXR connections
84 FlushPending = true;
85 };
86
87 restartTriggers = [ cfg.package ];
88
89 wantedBy = [ "sockets.target" ];
90 };
91 };
92
93 environment.systemPackages = [ cfg.package ];
94 environment.pathsToLink = [ "/share/openxr" ];
95
96 environment.etc."xdg/openxr/1/active_runtime.json" = mkIf cfg.defaultRuntime {
97 source = "${cfg.package}/share/openxr/1/openxr_monado.json";
98 };
99 };
100
101 meta.maintainers = with lib.maintainers; [ Scrumplex ];
102}