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}