1{ config, lib, pkgs, ... }:
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-gsettings-desktop-schemas = let
26 defaultPackages = with pkgs; [ gsettings-desktop-schemas gnome.gnome-shell ];
27 in
28 pkgs.runCommand "nixos-gsettings-desktop-schemas" { preferLocalBuild = true; }
29 ''
30 mkdir -p $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
31
32 ${concatMapStrings
33 (pkg: "cp -rf ${pkg}/share/gsettings-schemas/*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas\n")
34 (defaultPackages ++ cfg.extraGSettingsOverridePackages)}
35
36 cp -f ${pkgs.gnome.gnome-shell}/share/gsettings-schemas/*/glib-2.0/schemas/*.gschema.override $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
37
38 ${optionalString flashbackEnabled ''
39 cp -f ${pkgs.gnome.gnome-flashback}/share/gsettings-schemas/*/glib-2.0/schemas/*.gschema.override $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
40 ''}
41
42 chmod -R a+w $out/share/gsettings-schemas/nixos-gsettings-overrides
43 cat - > $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF
44 [org.gnome.desktop.background]
45 picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray.gnomeFilePath}'
46
47 [org.gnome.desktop.screensaver]
48 picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath}'
49
50 ${cfg.favoriteAppsOverride}
51
52 ${cfg.extraGSettingsOverrides}
53 EOF
54
55 ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
56 '';
57
58 flashbackEnabled = cfg.flashback.enableMetacity || length cfg.flashback.customSessions > 0;
59
60 notExcluded = pkg: mkDefault (!(lib.elem pkg config.environment.gnome.excludePackages));
61
62in
63
64{
65
66 meta = {
67 doc = ./gnome.xml;
68 maintainers = teams.gnome.members;
69 };
70
71 imports = [
72 # Added 2021-05-07
73 (mkRenamedOptionModule
74 [ "services" "gnome3" "core-os-services" "enable" ]
75 [ "services" "gnome" "core-os-services" "enable" ]
76 )
77 (mkRenamedOptionModule
78 [ "services" "gnome3" "core-shell" "enable" ]
79 [ "services" "gnome" "core-shell" "enable" ]
80 )
81 (mkRenamedOptionModule
82 [ "services" "gnome3" "core-utilities" "enable" ]
83 [ "services" "gnome" "core-utilities" "enable" ]
84 )
85 (mkRenamedOptionModule
86 [ "services" "gnome3" "core-developer-tools" "enable" ]
87 [ "services" "gnome" "core-developer-tools" "enable" ]
88 )
89 (mkRenamedOptionModule
90 [ "services" "gnome3" "games" "enable" ]
91 [ "services" "gnome" "games" "enable" ]
92 )
93 (mkRenamedOptionModule
94 [ "services" "gnome3" "experimental-features" "realtime-scheduling" ]
95 [ "services" "gnome" "experimental-features" "realtime-scheduling" ]
96 )
97 (mkRenamedOptionModule
98 [ "services" "xserver" "desktopManager" "gnome3" "enable" ]
99 [ "services" "xserver" "desktopManager" "gnome" "enable" ]
100 )
101 (mkRenamedOptionModule
102 [ "services" "xserver" "desktopManager" "gnome3" "sessionPath" ]
103 [ "services" "xserver" "desktopManager" "gnome" "sessionPath" ]
104 )
105 (mkRenamedOptionModule
106 [ "services" "xserver" "desktopManager" "gnome3" "favoriteAppsOverride" ]
107 [ "services" "xserver" "desktopManager" "gnome" "favoriteAppsOverride" ]
108 )
109 (mkRenamedOptionModule
110 [ "services" "xserver" "desktopManager" "gnome3" "extraGSettingsOverrides" ]
111 [ "services" "xserver" "desktopManager" "gnome" "extraGSettingsOverrides" ]
112 )
113 (mkRenamedOptionModule
114 [ "services" "xserver" "desktopManager" "gnome3" "extraGSettingsOverridePackages" ]
115 [ "services" "xserver" "desktopManager" "gnome" "extraGSettingsOverridePackages" ]
116 )
117 (mkRenamedOptionModule
118 [ "services" "xserver" "desktopManager" "gnome3" "debug" ]
119 [ "services" "xserver" "desktopManager" "gnome" "debug" ]
120 )
121 (mkRenamedOptionModule
122 [ "services" "xserver" "desktopManager" "gnome3" "flashback" ]
123 [ "services" "xserver" "desktopManager" "gnome" "flashback" ]
124 )
125 (mkRenamedOptionModule
126 [ "environment" "gnome3" "excludePackages" ]
127 [ "environment" "gnome" "excludePackages" ]
128 )
129 ];
130
131 options = {
132
133 services.gnome = {
134 core-os-services.enable = mkEnableOption "essential services for GNOME3";
135 core-shell.enable = mkEnableOption "GNOME Shell services";
136 core-utilities.enable = mkEnableOption "GNOME core utilities";
137 core-developer-tools.enable = mkEnableOption "GNOME core developer tools";
138 games.enable = mkEnableOption "GNOME games";
139
140 experimental-features = {
141 realtime-scheduling = mkOption {
142 type = types.bool;
143 default = false;
144 description = ''
145 Makes mutter (which propagates to gnome-shell) request a low priority real-time
146 scheduling which is only available on the wayland session.
147 To enable this experimental feature it requires a restart of the compositor.
148 Note that enabling this option only enables the <emphasis>capability</emphasis>
149 for realtime-scheduling to be used. It doesn't automatically set the gsetting
150 so that mutter actually uses realtime-scheduling. This would require adding <literal>
151 rt-scheduler</literal> to <literal>/org/gnome/mutter/experimental-features</literal>
152 with dconf-editor. You cannot use extraGSettingsOverrides because that will only
153 change the default value of the setting.
154
155 Please be aware of these known issues with the feature in nixos:
156 <itemizedlist>
157 <listitem>
158 <para>
159 <link xlink:href="https://github.com/NixOS/nixpkgs/issues/90201">NixOS/nixpkgs#90201</link>
160 </para>
161 </listitem>
162 <listitem>
163 <para>
164 <link xlink:href="https://github.com/NixOS/nixpkgs/issues/86730">NixOS/nixpkgs#86730</link>
165 </para>
166 </listitem>
167 </itemizedlist>
168 '';
169 };
170 };
171 };
172
173 services.xserver.desktopManager.gnome = {
174 enable = mkOption {
175 type = types.bool;
176 default = false;
177 description = "Enable Gnome 3 desktop manager.";
178 };
179
180 sessionPath = mkOption {
181 default = [];
182 type = types.listOf types.package;
183 example = literalExample "[ pkgs.gnome.gpaste ]";
184 description = ''
185 Additional list of packages to be added to the session search path.
186 Useful for GNOME Shell extensions or GSettings-conditional autostart.
187
188 Note that this should be a last resort; patching the package is preferred (see GPaste).
189 '';
190 apply = list: list ++ [ pkgs.gnome.gnome-shell pkgs.gnome.gnome-shell-extensions ];
191 };
192
193 favoriteAppsOverride = mkOption {
194 internal = true; # this is messy
195 default = defaultFavoriteAppsOverride;
196 type = types.lines;
197 example = literalExample ''
198 [org.gnome.shell]
199 favorite-apps=[ 'firefox.desktop', 'org.gnome.Calendar.desktop' ]
200 '';
201 description = "List of desktop files to put as favorite apps into gnome-shell. These need to be installed somehow globally.";
202 };
203
204 extraGSettingsOverrides = mkOption {
205 default = "";
206 type = types.lines;
207 description = "Additional gsettings overrides.";
208 };
209
210 extraGSettingsOverridePackages = mkOption {
211 default = [];
212 type = types.listOf types.path;
213 description = "List of packages for which gsettings are overridden.";
214 };
215
216 debug = mkEnableOption "gnome-session debug messages";
217
218 flashback = {
219 enableMetacity = mkEnableOption "the standard GNOME Flashback session with Metacity";
220
221 customSessions = mkOption {
222 type = types.listOf (types.submodule {
223 options = {
224 wmName = mkOption {
225 type = types.str;
226 description = "The filename-compatible name of the window manager to use.";
227 example = "xmonad";
228 };
229
230 wmLabel = mkOption {
231 type = types.str;
232 description = "The pretty name of the window manager to use.";
233 example = "XMonad";
234 };
235
236 wmCommand = mkOption {
237 type = types.str;
238 description = "The executable of the window manager to use.";
239 example = "\${pkgs.haskellPackages.xmonad}/bin/xmonad";
240 };
241 };
242 });
243 default = [];
244 description = "Other GNOME Flashback sessions to enable.";
245 };
246 };
247 };
248
249 environment.gnome.excludePackages = mkOption {
250 default = [];
251 example = literalExample "[ pkgs.gnome.totem ]";
252 type = types.listOf types.package;
253 description = "Which packages gnome should exclude from the default environment";
254 };
255
256 };
257
258 config = mkMerge [
259 (mkIf (cfg.enable || flashbackEnabled) {
260 # Seed our configuration into nixos-generate-config
261 system.nixos-generate-config.desktopConfiguration = [''
262 # Enable the GNOME 3 Desktop Environment.
263 services.xserver.displayManager.gdm.enable = true;
264 services.xserver.desktopManager.gnome.enable = true;
265 ''];
266
267 services.gnome.core-os-services.enable = true;
268 services.gnome.core-shell.enable = true;
269 services.gnome.core-utilities.enable = mkDefault true;
270
271 services.xserver.displayManager.sessionPackages = [ pkgs.gnome.gnome-session.sessions ];
272
273 environment.extraInit = ''
274 ${concatMapStrings (p: ''
275 if [ -d "${p}/share/gsettings-schemas/${p.name}" ]; then
276 export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${p}/share/gsettings-schemas/${p.name}
277 fi
278
279 if [ -d "${p}/lib/girepository-1.0" ]; then
280 export GI_TYPELIB_PATH=$GI_TYPELIB_PATH''${GI_TYPELIB_PATH:+:}${p}/lib/girepository-1.0
281 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:}${p}/lib
282 fi
283 '') cfg.sessionPath}
284 '';
285
286 environment.systemPackages = cfg.sessionPath;
287
288 environment.sessionVariables.GNOME_SESSION_DEBUG = mkIf cfg.debug "1";
289
290 # Override GSettings schemas
291 environment.sessionVariables.NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
292
293 # If gnome is installed, build vim for gtk3 too.
294 nixpkgs.config.vim.gui = "gtk3";
295 })
296
297 (mkIf flashbackEnabled {
298 services.xserver.displayManager.sessionPackages = map
299 (wm: pkgs.gnome.gnome-flashback.mkSessionForWm {
300 inherit (wm) wmName wmLabel wmCommand;
301 }) (optional cfg.flashback.enableMetacity {
302 wmName = "metacity";
303 wmLabel = "Metacity";
304 wmCommand = "${pkgs.gnome.metacity}/bin/metacity";
305 } ++ cfg.flashback.customSessions);
306
307 security.pam.services.gnome-flashback = {
308 enableGnomeKeyring = true;
309 };
310
311 systemd.packages = with pkgs.gnome; [
312 gnome-flashback
313 ] ++ (map
314 (wm: gnome-flashback.mkSystemdTargetForWm {
315 inherit (wm) wmName;
316 }) cfg.flashback.customSessions);
317
318 # gnome-panel needs these for menu applet
319 environment.sessionVariables.XDG_DATA_DIRS = [ "${pkgs.gnome.gnome-flashback}/share" ];
320 # TODO: switch to sessionVariables (resolve conflict)
321 environment.variables.XDG_CONFIG_DIRS = [ "${pkgs.gnome.gnome-flashback}/etc/xdg" ];
322 })
323
324 (mkIf serviceCfg.core-os-services.enable {
325 hardware.bluetooth.enable = mkDefault true;
326 hardware.pulseaudio.enable = mkDefault true;
327 programs.dconf.enable = true;
328 security.polkit.enable = true;
329 services.accounts-daemon.enable = true;
330 services.dleyna-renderer.enable = mkDefault true;
331 services.dleyna-server.enable = mkDefault true;
332 services.power-profiles-daemon.enable = mkDefault true;
333 services.gnome.at-spi2-core.enable = true;
334 services.gnome.evolution-data-server.enable = true;
335 services.gnome.gnome-keyring.enable = true;
336 services.gnome.gnome-online-accounts.enable = mkDefault true;
337 services.gnome.gnome-online-miners.enable = true;
338 services.gnome.tracker-miners.enable = mkDefault true;
339 services.gnome.tracker.enable = mkDefault true;
340 services.hardware.bolt.enable = mkDefault true;
341 services.packagekit.enable = mkDefault true;
342 services.udisks2.enable = true;
343 services.upower.enable = config.powerManagement.enable;
344 services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
345
346 xdg.portal.enable = true;
347 xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
348
349 networking.networkmanager.enable = mkDefault true;
350
351 services.xserver.updateDbusEnvironment = true;
352
353 # gnome has a custom alert theme but it still
354 # inherits from the freedesktop theme.
355 environment.systemPackages = with pkgs; [
356 sound-theme-freedesktop
357 ];
358
359 # Needed for themes and backgrounds
360 environment.pathsToLink = [
361 "/share" # TODO: https://github.com/NixOS/nixpkgs/issues/47173
362 ];
363 })
364
365 (mkIf serviceCfg.core-shell.enable {
366 services.colord.enable = mkDefault true;
367 services.gnome.chrome-gnome-shell.enable = mkDefault true;
368 services.gnome.glib-networking.enable = true;
369 services.gnome.gnome-initial-setup.enable = mkDefault true;
370 services.gnome.gnome-remote-desktop.enable = mkDefault true;
371 services.gnome.gnome-settings-daemon.enable = true;
372 services.gnome.gnome-user-share.enable = mkDefault true;
373 services.gnome.rygel.enable = mkDefault true;
374 services.gvfs.enable = true;
375 services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
376 services.telepathy.enable = mkDefault true;
377
378 systemd.packages = with pkgs.gnome; [
379 gnome-session
380 gnome-shell
381 ];
382
383 services.udev.packages = with pkgs.gnome; [
384 # Force enable KMS modifiers for devices that require them.
385 # https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1443
386 mutter
387 ];
388
389 services.avahi.enable = mkDefault true;
390
391 xdg.portal.extraPortals = [
392 pkgs.gnome.gnome-shell
393 ];
394
395 services.geoclue2.enable = mkDefault true;
396 services.geoclue2.enableDemoAgent = false; # GNOME has its own geoclue agent
397
398 services.geoclue2.appConfig.gnome-datetime-panel = {
399 isAllowed = true;
400 isSystem = true;
401 };
402 services.geoclue2.appConfig.gnome-color-panel = {
403 isAllowed = true;
404 isSystem = true;
405 };
406 services.geoclue2.appConfig."org.gnome.Shell" = {
407 isAllowed = true;
408 isSystem = true;
409 };
410
411 fonts.fonts = with pkgs; [
412 cantarell-fonts
413 dejavu_fonts
414 source-code-pro # Default monospace font in 3.32
415 source-sans-pro
416 ];
417
418 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst
419 environment.systemPackages = with pkgs.gnome; [
420 adwaita-icon-theme
421 gnome-backgrounds
422 gnome-bluetooth
423 gnome-color-manager
424 gnome-control-center
425 gnome-shell
426 gnome-shell-extensions
427 gnome-themes-extra
428 pkgs.gnome-tour # GNOME Shell detects the .desktop file on first log-in.
429 pkgs.nixos-artwork.wallpapers.simple-dark-gray
430 pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom
431 pkgs.gnome-user-docs
432 pkgs.orca
433 pkgs.glib # for gsettings
434 pkgs.gnome-menus
435 pkgs.gtk3.out # for gtk-launch
436 pkgs.hicolor-icon-theme
437 pkgs.shared-mime-info # for update-mime-database
438 pkgs.xdg-user-dirs # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
439 ];
440 })
441
442 # Enable soft realtime scheduling, only supported on wayland
443 (mkIf serviceCfg.experimental-features.realtime-scheduling {
444 security.wrappers.".gnome-shell-wrapped" = {
445 source = "${pkgs.gnome.gnome-shell}/bin/.gnome-shell-wrapped";
446 capabilities = "cap_sys_nice=ep";
447 };
448
449 systemd.user.services.gnome-shell-wayland = let
450 gnomeShellRT = with pkgs.gnome; pkgs.runCommand "gnome-shell-rt" {} ''
451 mkdir -p $out/bin/
452 cp ${gnome-shell}/bin/gnome-shell $out/bin
453 sed -i "s@${gnome-shell}/bin/@${config.security.wrapperDir}/@" $out/bin/gnome-shell
454 '';
455 in {
456 # Note we need to clear ExecStart before overriding it
457 serviceConfig.ExecStart = ["" "${gnomeShellRT}/bin/gnome-shell"];
458 # Do not use the default environment, it provides a broken PATH
459 environment = mkForce {};
460 };
461 })
462
463 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst
464 (mkIf serviceCfg.core-utilities.enable {
465 environment.systemPackages =
466 with pkgs.gnome;
467 removePackagesByName
468 ([
469 baobab
470 cheese
471 eog
472 epiphany
473 gedit
474 gnome-calculator
475 gnome-calendar
476 gnome-characters
477 gnome-clocks
478 gnome-contacts
479 gnome-font-viewer
480 gnome-logs
481 gnome-maps
482 gnome-music
483 pkgs.gnome-photos
484 gnome-screenshot
485 gnome-system-monitor
486 gnome-weather
487 nautilus
488 pkgs.gnome-connections
489 simple-scan
490 totem
491 yelp
492 ] ++ lib.optionals config.services.flatpak.enable [
493 # Since PackageKit Nix support is not there yet,
494 # only install gnome-software if flatpak is enabled.
495 gnome-software
496 ])
497 config.environment.gnome.excludePackages;
498
499 # Enable default program modules
500 # Since some of these have a corresponding package, we only
501 # enable that program module if the package hasn't been excluded
502 # through `environment.gnome.excludePackages`
503 programs.evince.enable = notExcluded pkgs.gnome.evince;
504 programs.file-roller.enable = notExcluded pkgs.gnome.file-roller;
505 programs.geary.enable = notExcluded pkgs.gnome.geary;
506 programs.gnome-disks.enable = notExcluded pkgs.gnome.gnome-disk-utility;
507 programs.gnome-terminal.enable = notExcluded pkgs.gnome.gnome-terminal;
508 programs.seahorse.enable = notExcluded pkgs.gnome.seahorse;
509 services.gnome.sushi.enable = notExcluded pkgs.gnome.sushi;
510
511 # Let nautilus find extensions
512 # TODO: Create nautilus-with-extensions package
513 environment.sessionVariables.NAUTILUS_EXTENSION_DIR = "${config.system.path}/lib/nautilus/extensions-3.0";
514
515 # Override default mimeapps for nautilus
516 environment.sessionVariables.XDG_DATA_DIRS = [ "${mimeAppsList}/share" ];
517
518 environment.pathsToLink = [
519 "/share/nautilus-python/extensions"
520 ];
521 })
522
523 (mkIf serviceCfg.games.enable {
524 environment.systemPackages = (with pkgs.gnome; removePackagesByName [
525 aisleriot
526 atomix
527 five-or-more
528 four-in-a-row
529 gnome-chess
530 gnome-klotski
531 gnome-mahjongg
532 gnome-mines
533 gnome-nibbles
534 gnome-robots
535 gnome-sudoku
536 gnome-taquin
537 gnome-tetravex
538 hitori
539 iagno
540 lightsoff
541 quadrapassel
542 swell-foop
543 tali
544 ] config.environment.gnome.excludePackages);
545 })
546
547 # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst
548 (mkIf serviceCfg.core-developer-tools.enable {
549 environment.systemPackages = (with pkgs.gnome; removePackagesByName [
550 dconf-editor
551 devhelp
552 pkgs.gnome-builder
553 # boxes would make sense in this option, however
554 # it doesn't function well enough to be included
555 # in default configurations.
556 # https://github.com/NixOS/nixpkgs/issues/60908
557 /* gnome-boxes */
558 ] config.environment.gnome.excludePackages);
559
560 services.sysprof.enable = notExcluded pkgs.sysprof;
561 })
562 ];
563
564}