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}