nixos/preload: init
[NixPkgs.git] / nixos / modules / services / x11 / desktop-managers / gnome.nix
blob20eca7746447b8ba4ac360f318081c1d25a43633
1 { config, lib, pkgs, utils, ... }:
3 with lib;
5 let
7   cfg = config.services.xserver.desktopManager.gnome;
8   serviceCfg = config.services.gnome;
10   # Prioritize nautilus by default when opening directories
11   mimeAppsList = pkgs.writeTextFile {
12     name = "gnome-mimeapps";
13     destination = "/share/applications/mimeapps.list";
14     text = ''
15       [Default Applications]
16       inode/directory=nautilus.desktop;org.gnome.Nautilus.desktop
17     '';
18   };
20   defaultFavoriteAppsOverride = ''
21     [org.gnome.shell]
22     favorite-apps=[ 'org.gnome.Epiphany.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Nautilus.desktop' ]
23   '';
25   nixos-background-light = pkgs.nixos-artwork.wallpapers.simple-blue;
26   nixos-background-dark = pkgs.nixos-artwork.wallpapers.simple-dark-gray;
28   # TODO: Having https://github.com/NixOS/nixpkgs/issues/54150 would supersede this
29   nixos-gsettings-desktop-schemas = pkgs.gnome.nixos-gsettings-overrides.override {
30     inherit (cfg) extraGSettingsOverrides extraGSettingsOverridePackages favoriteAppsOverride;
31     inherit flashbackEnabled nixos-background-dark nixos-background-light;
32   };
34   nixos-background-info = pkgs.writeTextFile rec {
35     name = "nixos-background-info";
36     text = ''
37       <?xml version="1.0"?>
38       <!DOCTYPE wallpapers SYSTEM "gnome-wp-list.dtd">
39       <wallpapers>
40         <wallpaper deleted="false">
41           <name>Blobs</name>
42           <filename>${nixos-background-light.gnomeFilePath}</filename>
43           <filename-dark>${nixos-background-dark.gnomeFilePath}</filename-dark>
44           <options>zoom</options>
45           <shade_type>solid</shade_type>
46           <pcolor>#3a4ba0</pcolor>
47           <scolor>#2f302f</scolor>
48         </wallpaper>
49       </wallpapers>
50     '';
51     destination = "/share/gnome-background-properties/nixos.xml";
52   };
54   flashbackEnabled = cfg.flashback.enableMetacity || length cfg.flashback.customSessions > 0;
55   flashbackWms = optional cfg.flashback.enableMetacity {
56     wmName = "metacity";
57     wmLabel = "Metacity";
58     wmCommand = "${pkgs.gnome.metacity}/bin/metacity";
59     enableGnomePanel = true;
60   } ++ cfg.flashback.customSessions;
62   notExcluded = pkg: mkDefault (!(lib.elem pkg config.environment.gnome.excludePackages));
68   meta = {
69     doc = ./gnome.md;
70     maintainers = teams.gnome.members;
71   };
73   imports = [
74     # Added 2021-05-07
75     (mkRenamedOptionModule
76       [ "services" "gnome3" "core-os-services" "enable" ]
77       [ "services" "gnome" "core-os-services" "enable" ]
78     )
79     (mkRenamedOptionModule
80       [ "services" "gnome3" "core-shell" "enable" ]
81       [ "services" "gnome" "core-shell" "enable" ]
82     )
83     (mkRenamedOptionModule
84       [ "services" "gnome3" "core-utilities" "enable" ]
85       [ "services" "gnome" "core-utilities" "enable" ]
86     )
87     (mkRenamedOptionModule
88       [ "services" "gnome3" "core-developer-tools" "enable" ]
89       [ "services" "gnome" "core-developer-tools" "enable" ]
90     )
91     (mkRenamedOptionModule
92       [ "services" "gnome3" "games" "enable" ]
93       [ "services" "gnome" "games" "enable" ]
94     )
95     (mkRenamedOptionModule
96       [ "services" "gnome3" "experimental-features" "realtime-scheduling" ]
97       [ "services" "gnome" "experimental-features" "realtime-scheduling" ]
98     )
99     (mkRenamedOptionModule
100       [ "services" "xserver" "desktopManager" "gnome3" "enable" ]
101       [ "services" "xserver" "desktopManager" "gnome" "enable" ]
102     )
103     (mkRenamedOptionModule
104       [ "services" "xserver" "desktopManager" "gnome3" "sessionPath" ]
105       [ "services" "xserver" "desktopManager" "gnome" "sessionPath" ]
106     )
107     (mkRenamedOptionModule
108       [ "services" "xserver" "desktopManager" "gnome3" "favoriteAppsOverride" ]
109       [ "services" "xserver" "desktopManager" "gnome" "favoriteAppsOverride" ]
110     )
111     (mkRenamedOptionModule
112       [ "services" "xserver" "desktopManager" "gnome3" "extraGSettingsOverrides" ]
113       [ "services" "xserver" "desktopManager" "gnome" "extraGSettingsOverrides" ]
114     )
115     (mkRenamedOptionModule
116       [ "services" "xserver" "desktopManager" "gnome3" "extraGSettingsOverridePackages" ]
117       [ "services" "xserver" "desktopManager" "gnome" "extraGSettingsOverridePackages" ]
118     )
119     (mkRenamedOptionModule
120       [ "services" "xserver" "desktopManager" "gnome3" "debug" ]
121       [ "services" "xserver" "desktopManager" "gnome" "debug" ]
122     )
123     (mkRenamedOptionModule
124       [ "services" "xserver" "desktopManager" "gnome3" "flashback" ]
125       [ "services" "xserver" "desktopManager" "gnome" "flashback" ]
126     )
127     (mkRenamedOptionModule
128       [ "environment" "gnome3" "excludePackages" ]
129       [ "environment" "gnome" "excludePackages" ]
130     )
131     (mkRemovedOptionModule
132       [ "services" "gnome" "experimental-features" "realtime-scheduling" ]
133       "Set `security.rtkit.enable = true;` to make realtime scheduling possible. (Still needs to be enabled using GSettings.)"
134     )
135   ];
137   options = {
139     services.gnome = {
140       core-os-services.enable = mkEnableOption (lib.mdDoc "essential services for GNOME3");
141       core-shell.enable = mkEnableOption (lib.mdDoc "GNOME Shell services");
142       core-utilities.enable = mkEnableOption (lib.mdDoc "GNOME core utilities");
143       core-developer-tools.enable = mkEnableOption (lib.mdDoc "GNOME core developer tools");
144       games.enable = mkEnableOption (lib.mdDoc "GNOME games");
145     };
147     services.xserver.desktopManager.gnome = {
148       enable = mkOption {
149         type = types.bool;
150         default = false;
151         description = lib.mdDoc "Enable GNOME desktop manager.";
152       };
154       sessionPath = mkOption {
155         default = [];
156         type = types.listOf types.package;
157         example = literalExpression "[ pkgs.gnome.gpaste ]";
158         description = lib.mdDoc ''
159           Additional list of packages to be added to the session search path.
160           Useful for GNOME Shell extensions or GSettings-conditional autostart.
162           Note that this should be a last resort; patching the package is preferred (see GPaste).
163         '';
164       };
166       favoriteAppsOverride = mkOption {
167         internal = true; # this is messy
168         default = defaultFavoriteAppsOverride;
169         type = types.lines;
170         example = literalExpression ''
171           '''
172             [org.gnome.shell]
173             favorite-apps=[ 'firefox.desktop', 'org.gnome.Calendar.desktop' ]
174           '''
175         '';
176         description = lib.mdDoc "List of desktop files to put as favorite apps into gnome-shell. These need to be installed somehow globally.";
177       };
179       extraGSettingsOverrides = mkOption {
180         default = "";
181         type = types.lines;
182         description = lib.mdDoc "Additional gsettings overrides.";
183       };
185       extraGSettingsOverridePackages = mkOption {
186         default = [];
187         type = types.listOf types.path;
188         description = lib.mdDoc "List of packages for which gsettings are overridden.";
189       };
191       debug = mkEnableOption (lib.mdDoc "gnome-session debug messages");
193       flashback = {
194         enableMetacity = mkEnableOption (lib.mdDoc "the standard GNOME Flashback session with Metacity");
196         customSessions = mkOption {
197           type = types.listOf (types.submodule {
198             options = {
199               wmName = mkOption {
200                 type = types.strMatching "[a-zA-Z0-9_-]+";
201                 description = lib.mdDoc "A unique identifier for the window manager.";
202                 example = "xmonad";
203               };
205               wmLabel = mkOption {
206                 type = types.str;
207                 description = lib.mdDoc "The name of the window manager to show in the session chooser.";
208                 example = "XMonad";
209               };
211               wmCommand = mkOption {
212                 type = types.str;
213                 description = lib.mdDoc "The executable of the window manager to use.";
214                 example = literalExpression ''"''${pkgs.haskellPackages.xmonad}/bin/xmonad"'';
215               };
217               enableGnomePanel = mkOption {
218                 type = types.bool;
219                 default = true;
220                 example = false;
221                 description = lib.mdDoc "Whether to enable the GNOME panel in this session.";
222               };
223             };
224           });
225           default = [];
226           description = lib.mdDoc "Other GNOME Flashback sessions to enable.";
227         };
229         panelModulePackages = mkOption {
230           default = [ pkgs.gnome.gnome-applets ];
231           defaultText = literalExpression "[ pkgs.gnome.gnome-applets ]";
232           type = types.listOf types.package;
233           description = lib.mdDoc ''
234             Packages containing modules that should be made available to `gnome-panel` (usually for applets).
236             If you're packaging something to use here, please install the modules in `$out/lib/gnome-panel/modules`.
237           '';
238         };
239       };
240     };
242     environment.gnome.excludePackages = mkOption {
243       default = [];
244       example = literalExpression "[ pkgs.gnome.totem ]";
245       type = types.listOf types.package;
246       description = lib.mdDoc "Which packages gnome should exclude from the default environment";
247     };
249   };
251   config = mkMerge [
252     (mkIf (cfg.enable || flashbackEnabled) {
253       # Seed our configuration into nixos-generate-config
254       system.nixos-generate-config.desktopConfiguration = [''
255         # Enable the GNOME Desktop Environment.
256         services.xserver.displayManager.gdm.enable = true;
257         services.xserver.desktopManager.gnome.enable = true;
258       ''];
260       services.gnome.core-os-services.enable = true;
261       services.gnome.core-shell.enable = true;
262       services.gnome.core-utilities.enable = mkDefault true;
264       services.xserver.displayManager.sessionPackages = [ pkgs.gnome.gnome-session.sessions ];
266       environment.extraInit = ''
267         ${concatMapStrings (p: ''
268           if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
269             export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
270           fi
272           if [ -d "${p}/lib/girepository-1.0" ]; then
273             export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
274             export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
275           fi
276         '') cfg.sessionPath}
277       '';
279       environment.systemPackages = cfg.sessionPath;
281       environment.sessionVariables.GNOME_SESSION_DEBUG = mkIf cfg.debug "1";
283       # Override GSettings schemas
284       environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
285     })
287     (mkIf flashbackEnabled {
288       services.xserver.displayManager.sessionPackages =
289         let
290           wmNames = map (wm: wm.wmName) flashbackWms;
291           namesAreUnique = lib.unique wmNames == wmNames;
292         in
293           assert (assertMsg namesAreUnique "Flashback WM names must be unique.");
294           map
295             (wm:
296               pkgs.gnome.gnome-flashback.mkSessionForWm {
297                 inherit (wm) wmName wmLabel wmCommand;
298               }
299             ) flashbackWms;
301       security.pam.services.gnome-flashback = {
302         enableGnomeKeyring = true;
303       };
305       systemd.packages = with pkgs.gnome; [
306         gnome-flashback
307       ] ++ map gnome-flashback.mkSystemdTargetForWm flashbackWms;
309       environment.systemPackages = with pkgs.gnome; [
310         gnome-flashback
311         (gnome-panel-with-modules.override {
312           panelModulePackages = cfg.flashback.panelModulePackages;
313         })
314       ]
315       # For /share/applications/${wmName}.desktop
316       ++ (map (wm: gnome-flashback.mkWmApplication { inherit (wm) wmName wmLabel wmCommand; }) flashbackWms)
317       # For /share/gnome-session/sessions/gnome-flashback-${wmName}.session
318       ++ (map (wm: gnome-flashback.mkGnomeSession { inherit (wm) wmName wmLabel enableGnomePanel; }) flashbackWms);
319     })
321     (mkIf serviceCfg.core-os-services.enable {
322       hardware.bluetooth.enable = mkDefault true;
323       hardware.pulseaudio.enable = mkDefault true;
324       programs.dconf.enable = true;
325       security.polkit.enable = true;
326       services.accounts-daemon.enable = true;
327       services.dleyna-renderer.enable = mkDefault true;
328       services.dleyna-server.enable = mkDefault true;
329       services.power-profiles-daemon.enable = mkDefault true;
330       services.gnome.at-spi2-core.enable = true;
331       services.gnome.evolution-data-server.enable = true;
332       services.gnome.gnome-keyring.enable = true;
333       services.gnome.gnome-online-accounts.enable = mkDefault true;
334       services.gnome.gnome-online-miners.enable = true;
335       services.gnome.tracker-miners.enable = mkDefault true;
336       services.gnome.tracker.enable = mkDefault true;
337       services.hardware.bolt.enable = mkDefault true;
338       # TODO: Enable once #177946 is resolved
339       # services.packagekit.enable = mkDefault true;
340       services.udisks2.enable = true;
341       services.upower.enable = config.powerManagement.enable;
342       services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
344       # Explicitly enabled since GNOME will be severely broken without these.
345       xdg.mime.enable = true;
346       xdg.icons.enable = true;
348       xdg.portal.enable = true;
349       xdg.portal.extraPortals = [
350         pkgs.xdg-desktop-portal-gnome
351         (pkgs.xdg-desktop-portal-gtk.override {
352           # Do not build portals that we already have.
353           buildPortalsInGnome = false;
354         })
355       ];
356       xdg.portal.configPackages = mkDefault [ pkgs.gnome.gnome-session ];
358       networking.networkmanager.enable = mkDefault true;
360       services.xserver.updateDbusEnvironment = true;
362       # gnome has a custom alert theme but it still
363       # inherits from the freedesktop theme.
364       environment.systemPackages = with pkgs; [
365         sound-theme-freedesktop
366       ];
368       # Needed for themes and backgrounds
369       environment.pathsToLink = [
370         "/share" # TODO: https://github.com/NixOS/nixpkgs/issues/47173
371       ];
372     })
374     (mkIf serviceCfg.core-shell.enable {
375       services.xserver.desktopManager.gnome.sessionPath =
376         let
377           mandatoryPackages = [
378             pkgs.gnome.gnome-shell
379           ];
380           optionalPackages = [
381             pkgs.gnome.gnome-shell-extensions
382           ];
383         in
384         mandatoryPackages
385         ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages;
387       services.colord.enable = mkDefault true;
388       services.gnome.glib-networking.enable = true;
389       services.gnome.gnome-browser-connector.enable = mkDefault true;
390       services.gnome.gnome-initial-setup.enable = mkDefault true;
391       services.gnome.gnome-remote-desktop.enable = mkDefault true;
392       services.gnome.gnome-settings-daemon.enable = true;
393       services.gnome.gnome-user-share.enable = mkDefault true;
394       services.gnome.rygel.enable = mkDefault true;
395       services.gvfs.enable = true;
396       services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
398       systemd.packages = with pkgs.gnome; [
399         gnome-session
400         gnome-shell
401       ];
403       services.udev.packages = with pkgs.gnome; [
404         # Force enable KMS modifiers for devices that require them.
405         # https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1443
406         mutter
407       ];
409       services.avahi.enable = mkDefault true;
411       xdg.portal.extraPortals = [
412         pkgs.gnome.gnome-shell
413       ];
415       services.geoclue2.enable = mkDefault true;
416       services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent
418       services.geoclue2.appConfig.gnome-datetime-panel = {
419         isAllowed = true;
420         isSystem = true;
421       };
422       services.geoclue2.appConfig.gnome-color-panel = {
423         isAllowed = true;
424         isSystem = true;
425       };
426       services.geoclue2.appConfig."org.gnome.Shell" = {
427         isAllowed = true;
428         isSystem = true;
429       };
431       fonts.packages = with pkgs; [
432         cantarell-fonts
433         dejavu_fonts
434         source-code-pro # Default monospace font in 3.32
435         source-sans
436       ];
438       # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst
439       environment.systemPackages =
440         let
441           mandatoryPackages = with pkgs.gnome; [
442             gnome-shell
443           ];
444           optionalPackages = with pkgs.gnome; [
445             adwaita-icon-theme
446             nixos-background-info
447             gnome-backgrounds
448             gnome-bluetooth
449             gnome-color-manager
450             gnome-control-center
451             gnome-shell-extensions
452             gnome-themes-extra
453             pkgs.gnome-tour # GNOME Shell detects the .desktop file on first log-in.
454             pkgs.gnome-user-docs
455             pkgs.orca
456             pkgs.glib # for gsettings program
457             pkgs.gnome-menus
458             pkgs.gtk3.out # for gtk-launch program
459             pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
460           ];
461         in
462         mandatoryPackages
463         ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages;
464     })
466     # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/gnome-45/elements/core/meta-gnome-core-utilities.bst
467     (mkIf serviceCfg.core-utilities.enable {
468       environment.systemPackages =
469         with pkgs.gnome;
470         utils.removePackagesByName
471           ([
472             baobab
473             epiphany
474             pkgs.gnome-text-editor
475             gnome-calculator
476             gnome-calendar
477             gnome-characters
478             gnome-clocks
479             pkgs.gnome-console
480             gnome-contacts
481             gnome-font-viewer
482             gnome-logs
483             gnome-maps
484             gnome-music
485             gnome-system-monitor
486             gnome-weather
487             pkgs.loupe
488             nautilus
489             pkgs.gnome-connections
490             simple-scan
491             pkgs.snapshot
492             totem
493             yelp
494           ] ++ lib.optionals config.services.flatpak.enable [
495             # Since PackageKit Nix support is not there yet,
496             # only install gnome-software if flatpak is enabled.
497             gnome-software
498           ])
499           config.environment.gnome.excludePackages;
501       # Enable default program modules
502       # Since some of these have a corresponding package, we only
503       # enable that program module if the package hasn't been excluded
504       # through `environment.gnome.excludePackages`
505       programs.evince.enable = notExcluded pkgs.gnome.evince;
506       programs.file-roller.enable = notExcluded pkgs.gnome.file-roller;
507       programs.geary.enable = notExcluded pkgs.gnome.geary;
508       programs.gnome-disks.enable = notExcluded pkgs.gnome.gnome-disk-utility;
509       programs.seahorse.enable = notExcluded pkgs.gnome.seahorse;
510       services.gnome.sushi.enable = notExcluded pkgs.gnome.sushi;
512       # VTE shell integration for gnome-console
513       programs.bash.vteIntegration = mkDefault true;
514       programs.zsh.vteIntegration = mkDefault true;
516       # Let nautilus find extensions
517       # TODO: Create nautilus-with-extensions package
518       environment.sessionVariables.NAUTILUS_4_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-4";
520       # Override default mimeapps for nautilus
521       environment.sessionVariables.XDG_DATA_DIRS = [ "${mimeAppsList}/share" ];
523       environment.pathsToLink = [
524         "/share/nautilus-python/extensions"
525       ];
526     })
528     (mkIf serviceCfg.games.enable {
529       environment.systemPackages = with pkgs.gnome; utils.removePackagesByName [
530         aisleriot
531         atomix
532         five-or-more
533         four-in-a-row
534         pkgs.gnome-2048
535         gnome-chess
536         gnome-klotski
537         gnome-mahjongg
538         gnome-mines
539         gnome-nibbles
540         gnome-robots
541         gnome-sudoku
542         gnome-taquin
543         gnome-tetravex
544         hitori
545         iagno
546         lightsoff
547         quadrapassel
548         swell-foop
549         tali
550       ] config.environment.gnome.excludePackages;
551     })
553     # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst
554     (mkIf serviceCfg.core-developer-tools.enable {
555       environment.systemPackages = with pkgs.gnome; utils.removePackagesByName [
556         dconf-editor
557         devhelp
558         pkgs.gnome-builder
559         # boxes would make sense in this option, however
560         # it doesn't function well enough to be included
561         # in default configurations.
562         # https://github.com/NixOS/nixpkgs/issues/60908
563         /* gnome-boxes */
564       ] config.environment.gnome.excludePackages;
566       services.sysprof.enable = notExcluded pkgs.sysprof;
567     })
568   ];