1 { config, lib, pkgs, ... }:
6 cfg = config.services.xserver.desktopManager.phosh;
8 # Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop
9 oskItem = pkgs.makeDesktopItem {
10 name = "sm.puri.OSK0";
11 desktopName = "On-screen keyboard";
12 exec = "${pkgs.squeekboard}/bin/squeekboard";
13 categories = [ "GNOME" "Core" ];
14 onlyShowIn = [ "GNOME" ];
17 X-GNOME-Autostart-Phase = "Panel";
18 X-GNOME-Provides = "inputmethod";
19 X-GNOME-Autostart-Notify = "true";
20 X-GNOME-AutoRestart = "true";
24 phocConfigType = types.submodule {
27 description = lib.mdDoc ''
28 Whether to enable XWayland support.
30 To start XWayland immediately, use `immediate`.
32 type = types.enum [ "true" "false" "immediate" ];
35 cursorTheme = mkOption {
36 description = lib.mdDoc ''
37 Cursor theme to use in Phosh.
43 description = lib.mdDoc ''
44 Output configurations.
46 type = types.attrsOf phocOutputType;
56 phocOutputType = types.submodule {
59 description = lib.mdDoc ''
60 One or more modelines.
62 type = types.either types.str (types.listOf types.str);
65 "87.25 720 776 848 976 1440 1443 1453 1493 -hsync +vsync"
66 "65.13 768 816 896 1024 1024 1025 1028 1060 -HSync +VSync"
70 description = lib.mdDoc ''
73 type = types.nullOr types.str;
78 description = lib.mdDoc ''
79 Display scaling factor.
83 (types.either types.int types.float)
86 description = "null or positive integer or float";
92 description = lib.mdDoc ''
93 Screen transformation.
96 "90" "180" "270" "flipped" "flipped-90" "flipped-180" "flipped-270" null
103 optionalKV = k: v: optionalString (v != null) "${k} = ${builtins.toString v}";
105 renderPhocOutput = name: output: let
106 modelines = if builtins.isList output.modeline
108 else [ output.modeline ];
109 renderModeline = l: "modeline = ${l}";
112 ${concatStringsSep "\n" (map renderModeline modelines)}
113 ${optionalKV "mode" output.mode}
114 ${optionalKV "scale" output.scale}
115 ${optionalKV "rotate" output.rotate}
118 renderPhocConfig = phoc: let
119 outputs = mapAttrsToList renderPhocOutput phoc.outputs;
122 xwayland = ${phoc.xwayland}
123 ${concatStringsSep "\n" outputs}
125 theme = ${phoc.cursorTheme}
131 services.xserver.desktopManager.phosh = {
135 description = lib.mdDoc "Enable the Phone Shell.";
139 type = types.package;
140 default = pkgs.phosh;
141 defaultText = literalExpression "pkgs.phosh";
142 example = literalExpression "pkgs.phosh";
143 description = lib.mdDoc ''
144 Package that should be used for Phosh.
149 description = lib.mdDoc "The user to run the Phosh service.";
155 description = lib.mdDoc "The group to run the Phosh service.";
160 phocConfig = mkOption {
161 description = lib.mdDoc ''
162 Configurations for the Phoc compositor.
164 type = types.oneOf [ types.lines types.path phocConfigType ];
170 config = mkIf cfg.enable {
171 systemd.defaultUnit = "graphical.target";
172 # Inspired by https://gitlab.gnome.org/World/Phosh/phosh/-/blob/main/data/phosh.service
173 systemd.services.phosh = {
174 wantedBy = [ "graphical.target" ];
176 ExecStart = "${cfg.package}/bin/phosh-session";
180 WorkingDirectory = "~";
183 TTYPath = "/dev/tty7";
186 TTYVTDisallocate = "yes";
188 # Fail to start if not controlling the tty.
189 StandardInput = "tty-fail";
190 StandardOutput = "journal";
191 StandardError = "journal";
193 # Log this user with utmp, letting it show up with commands 'w' and 'who'.
194 UtmpIdentifier = "tty7";
199 environment.systemPackages = [
206 systemd.packages = [ cfg.package ];
208 programs.feedbackd.enable = true;
210 security.pam.services.phosh = {};
212 hardware.opengl.enable = mkDefault true;
214 services.gnome.core-shell.enable = true;
215 services.gnome.core-os-services.enable = true;
216 services.xserver.displayManager.sessionPackages = [ cfg.package ];
218 environment.etc."phosh/phoc.ini".source =
219 if builtins.isPath cfg.phocConfig then cfg.phocConfig
220 else if builtins.isString cfg.phocConfig then pkgs.writeText "phoc.ini" cfg.phocConfig
221 else pkgs.writeText "phoc.ini" (renderPhocConfig cfg.phocConfig);