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