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