1{ config, lib, pkgs, utils, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.xserver.desktopManager.gnome;
8 serviceCfg = config.services.gnome;
9
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 };
19
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.Photos.desktop', 'org.gnome.Nautilus.desktop' ]
23 '';
24
25 nixos-background-light = pkgs.nixos-artwork.wallpapers.simple-blue;
26 nixos-background-dark = pkgs.nixos-artwork.wallpapers.simple-dark-gray;
27
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 };
33
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 };
53
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;
61
62 notExcluded = pkg: mkDefault (!(lib.elem pkg config.environment.gnome.excludePackages));
63
64in
65
66{
67
68 meta = {
69 doc = ./gnome.md;
70 maintainers = teams.gnome.members;
71 };
72
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 ];
136
137 options = {
138
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 };
146
147 services.xserver.desktopManager.gnome = {
148 enable = mkOption {
149 type = types.bool;
150 default = false;
151 description = lib.mdDoc "Enable GNOME desktop manager.";
152 };
153
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.
161
162 Note that this should be a last resort; patching the package is preferred (see GPaste).
163 '';
164 };
165
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 };
178
179 extraGSettingsOverrides = mkOption {
180 default = "";
181 type = types.lines;
182 description = lib.mdDoc "Additional gsettings overrides.";
183 };
184
185 extraGSettingsOverridePackages = mkOption {
186 default = [];
187 type = types.listOf types.path;
188 description = lib.mdDoc "List of packages for which gsettings are overridden.";
189 };
190
191 debug = mkEnableOption (lib.mdDoc "gnome-session debug messages");
192
193 flashback = {
194 enableMetacity = mkEnableOption (lib.mdDoc "the standard GNOME Flashback session with Metacity");
195
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 };
204
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 };
210
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 };
216
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 };
228
229 panelModulePackages = mkOption {
230 default = [ pkgs.gnome.gnome-applets ];
231 defaultText = literalExpression "[ pkgs.gnome.gnome-applets ]";
232 type = types.listOf types.path;
233 description = lib.mdDoc ''
234 Packages containing modules that should be made available to `gnome-panel` (usually for applets).
235
236 If you're packaging something to use here, please install the modules in `$out/lib/gnome-panel/modules`.
237 '';
238 };
239 };
240 };
241
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 };
248
249 };
250
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 ''];
259
260 services.gnome.core-os-services.enable = true;
261 services.gnome.core-shell.enable = true;
262 services.gnome.core-utilities.enable = mkDefault true;
263
264 services.xserver.displayManager.sessionPackages = [ pkgs.gnome.gnome-session.sessions ];
265
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
271
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 '';
278
279 environment.systemPackages = cfg.sessionPath;
280
281 environment.sessionVariables.GNOME_SESSION_DEBUG = mkIf cfg.debug "1";
282
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
286 # If gnome is installed, build vim for gtk3 too.
287 nixpkgs.config.vim.gui = "gtk3";
288 })
289
290 (mkIf flashbackEnabled {
291 services.xserver.displayManager.sessionPackages =
292 let
293 wmNames = map (wm: wm.wmName) flashbackWms;
294 namesAreUnique = lib.unique wmNames == wmNames;
295 in
296 assert (assertMsg namesAreUnique "Flashback WM names must be unique.");
297 map
298 (wm:
299 pkgs.gnome.gnome-flashback.mkSessionForWm {
300 inherit (wm) wmName wmLabel wmCommand enableGnomePanel;
301 inherit (cfg.flashback) panelModulePackages;
302 }
303 ) flashbackWms;
304
305 security.pam.services.gnome-flashback = {
306 enableGnomeKeyring = true;
307 };
308
309 systemd.packages = with pkgs.gnome; [
310 gnome-flashback
311 ] ++ map gnome-flashback.mkSystemdTargetForWm flashbackWms;
312
313 # gnome-panel needs these for menu applet
314 environment.sessionVariables.XDG_DATA_DIRS = [ "${pkgs.gnome.gnome-flashback}/share" ];
315 # TODO: switch to sessionVariables (resolve conflict)
316 environment.variables.XDG_CONFIG_DIRS = [ "${pkgs.gnome.gnome-flashback}/etc/xdg" ];
317 })
318
319 (mkIf serviceCfg.core-os-services.enable {
320 hardware.bluetooth.enable = mkDefault true;
321 hardware.pulseaudio.enable = mkDefault true;
322 programs.dconf.enable = true;
323 security.polkit.enable = true;
324 services.accounts-daemon.enable = true;
325 services.dleyna-renderer.enable = mkDefault true;
326 services.dleyna-server.enable = mkDefault true;
327 services.power-profiles-daemon.enable = mkDefault true;
328 services.gnome.at-spi2-core.enable = true;
329 services.gnome.evolution-data-server.enable = true;
330 services.gnome.gnome-keyring.enable = true;
331 services.gnome.gnome-online-accounts.enable = mkDefault true;
332 services.gnome.gnome-online-miners.enable = true;
333 services.gnome.tracker-miners.enable = mkDefault true;
334 services.gnome.tracker.enable = mkDefault true;
335 services.hardware.bolt.enable = mkDefault true;
336 # TODO: Enable once #177946 is resolved
337 # services.packagekit.enable = mkDefault true;
338 services.udisks2.enable = true;
339 services.upower.enable = config.powerManagement.enable;
340 services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
341
342 # Explicitly enabled since GNOME will be severely broken without these.
343 xdg.mime.enable = true;
344 xdg.icons.enable = true;
345
346 xdg.portal.enable = true;
347 xdg.portal.extraPortals = [
348 pkgs.xdg-desktop-portal-gnome
349 (pkgs.xdg-desktop-portal-gtk.override {
350 # Do not build portals that we already have.
351 buildPortalsInGnome = false;
352 })
353 ];
354
355 # Harmonize Qt application style and also make them use the portal for file chooser dialog.
356 qt = {
357 enable = mkDefault true;
358 platformTheme = mkDefault "gnome";
359 style = mkDefault "adwaita";
360 };
361
362 networking.networkmanager.enable = mkDefault true;
363
364 services.xserver.updateDbusEnvironment = true;
365
366 # gnome has a custom alert theme but it still
367 # inherits from the freedesktop theme.
368 environment.systemPackages = with pkgs; [
369 sound-theme-freedesktop
370 ];
371
372 # Needed for themes and backgrounds
373 environment.pathsToLink = [
374 "/share" # TODO: https://github.com/NixOS/nixpkgs/issues/47173
375 ];
376 })
377
378 (mkIf serviceCfg.core-shell.enable {
379 services.xserver.desktopManager.gnome.sessionPath =
380 let
381 mandatoryPackages = [
382 pkgs.gnome.gnome-shell
383 ];
384 optionalPackages = [
385 pkgs.gnome.gnome-shell-extensions
386 ];
387 in
388 mandatoryPackages
389 ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages;
390
391 services.colord.enable = mkDefault true;
392 services.gnome.glib-networking.enable = true;
393 services.gnome.gnome-browser-connector.enable = mkDefault true;
394 services.gnome.gnome-initial-setup.enable = mkDefault true;
395 services.gnome.gnome-remote-desktop.enable = mkDefault true;
396 services.gnome.gnome-settings-daemon.enable = true;
397 services.gnome.gnome-user-share.enable = mkDefault true;
398 services.gnome.rygel.enable = mkDefault true;
399 services.gvfs.enable = true;
400 services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
401
402 systemd.packages = with pkgs.gnome; [
403 gnome-session
404 gnome-shell
405 ];
406
407 services.udev.packages = with pkgs.gnome; [
408 # Force enable KMS modifiers for devices that require them.
409 # https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1443
410 mutter
411 ];
412
413 services.avahi.enable = mkDefault true;
414
415 xdg.portal.extraPortals = [
416 pkgs.gnome.gnome-shell
417 ];
418
419 services.geoclue2.enable = mkDefault true;
420 services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent
421
422 services.geoclue2.appConfig.gnome-datetime-panel = {
423 isAllowed = true;
424 isSystem = true;
425 };
426 services.geoclue2.appConfig.gnome-color-panel = {
427 isAllowed = true;
428 isSystem = true;
429 };
430 services.geoclue2.appConfig."org.gnome.Shell" = {
431 isAllowed = true;
432 isSystem = true;
433 };
434
435 fonts.fonts = with pkgs; [
436 cantarell-fonts
437 dejavu_fonts
438 source-code-pro # Default monospace font in 3.32
439 source-sans
440 ];
441
442 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst
443 environment.systemPackages =
444 let
445 mandatoryPackages = with pkgs.gnome; [
446 gnome-shell
447 ];
448 optionalPackages = with pkgs.gnome; [
449 adwaita-icon-theme
450 nixos-background-info
451 gnome-backgrounds
452 gnome-bluetooth
453 gnome-color-manager
454 gnome-control-center
455 gnome-shell-extensions
456 gnome-themes-extra
457 pkgs.gnome-tour # GNOME Shell detects the .desktop file on first log-in.
458 pkgs.gnome-user-docs
459 pkgs.orca
460 pkgs.glib # for gsettings program
461 pkgs.gnome-menus
462 pkgs.gtk3.out # for gtk-launch program
463 pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
464 ];
465 in
466 mandatoryPackages
467 ++ utils.removePackagesByName optionalPackages config.environment.gnome.excludePackages;
468 })
469
470 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst
471 (mkIf serviceCfg.core-utilities.enable {
472 environment.systemPackages =
473 with pkgs.gnome;
474 utils.removePackagesByName
475 ([
476 baobab
477 cheese
478 eog
479 epiphany
480 pkgs.gnome-text-editor
481 gnome-calculator
482 gnome-calendar
483 gnome-characters
484 gnome-clocks
485 pkgs.gnome-console
486 gnome-contacts
487 gnome-font-viewer
488 gnome-logs
489 gnome-maps
490 gnome-music
491 pkgs.gnome-photos
492 gnome-system-monitor
493 gnome-weather
494 nautilus
495 pkgs.gnome-connections
496 simple-scan
497 totem
498 yelp
499 ] ++ lib.optionals config.services.flatpak.enable [
500 # Since PackageKit Nix support is not there yet,
501 # only install gnome-software if flatpak is enabled.
502 gnome-software
503 ])
504 config.environment.gnome.excludePackages;
505
506 # Enable default program modules
507 # Since some of these have a corresponding package, we only
508 # enable that program module if the package hasn't been excluded
509 # through `environment.gnome.excludePackages`
510 programs.evince.enable = notExcluded pkgs.gnome.evince;
511 programs.file-roller.enable = notExcluded pkgs.gnome.file-roller;
512 programs.geary.enable = notExcluded pkgs.gnome.geary;
513 programs.gnome-disks.enable = notExcluded pkgs.gnome.gnome-disk-utility;
514 programs.seahorse.enable = notExcluded pkgs.gnome.seahorse;
515 services.gnome.sushi.enable = notExcluded pkgs.gnome.sushi;
516
517 # VTE shell integration for gnome-console
518 programs.bash.vteIntegration = mkDefault true;
519 programs.zsh.vteIntegration = mkDefault true;
520
521 # Let nautilus find extensions
522 # TODO: Create nautilus-with-extensions package
523 environment.sessionVariables.NAUTILUS_4_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-4";
524
525 # Override default mimeapps for nautilus
526 environment.sessionVariables.XDG_DATA_DIRS = [ "${mimeAppsList}/share" ];
527
528 environment.pathsToLink = [
529 "/share/nautilus-python/extensions"
530 ];
531 })
532
533 (mkIf serviceCfg.games.enable {
534 environment.systemPackages = with pkgs.gnome; utils.removePackagesByName [
535 aisleriot
536 atomix
537 five-or-more
538 four-in-a-row
539 pkgs.gnome-2048
540 gnome-chess
541 gnome-klotski
542 gnome-mahjongg
543 gnome-mines
544 gnome-nibbles
545 gnome-robots
546 gnome-sudoku
547 gnome-taquin
548 gnome-tetravex
549 hitori
550 iagno
551 lightsoff
552 quadrapassel
553 swell-foop
554 tali
555 ] config.environment.gnome.excludePackages;
556 })
557
558 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst
559 (mkIf serviceCfg.core-developer-tools.enable {
560 environment.systemPackages = with pkgs.gnome; utils.removePackagesByName [
561 dconf-editor
562 devhelp
563 pkgs.gnome-builder
564 # boxes would make sense in this option, however
565 # it doesn't function well enough to be included
566 # in default configurations.
567 # https://github.com/NixOS/nixpkgs/issues/60908
568 /* gnome-boxes */
569 ] config.environment.gnome.excludePackages;
570
571 services.sysprof.enable = notExcluded pkgs.sysprof;
572 })
573 ];
574
575}