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