at 23.11-pre 19 kB view raw
1{ config, lib, pkgs, utils, ... }: 2 3let 4 xcfg = config.services.xserver; 5 cfg = xcfg.desktopManager.plasma5; 6 7 # Use only for **internal** options. 8 # This is not exactly user-friendly. 9 kdeConfigurationType = with types; 10 let 11 valueTypes = (oneOf [ 12 bool 13 float 14 int 15 str 16 ]) // { 17 description = "KDE Configuration value"; 18 emptyValue.value = ""; 19 }; 20 set = (nullOr (lazyAttrsOf valueTypes)) // { 21 description = "KDE Configuration set"; 22 emptyValue.value = {}; 23 }; 24 in (lazyAttrsOf set) // { 25 description = "KDE Configuration file"; 26 emptyValue.value = {}; 27 }; 28 29 libsForQt5 = pkgs.plasma5Packages; 30 inherit (libsForQt5) kdeGear kdeFrameworks plasma5; 31 inherit (lib) 32 getBin optionalString literalExpression 33 mkRemovedOptionModule mkRenamedOptionModule 34 mkDefault mkIf mkMerge mkOption mkPackageOptionMD types; 35 36 activationScript = '' 37 ${set_XDG_CONFIG_HOME} 38 39 # The KDE icon cache is supposed to update itself automatically, but it uses 40 # the timestamp on the icon theme directory as a trigger. This doesn't work 41 # on NixOS because the timestamp never changes. As a workaround, delete the 42 # icon cache at login and session activation. 43 # See also: http://lists-archives.org/kde-devel/26175-what-when-will-icon-cache-refresh.html 44 rm -fv $HOME/.cache/icon-cache.kcache 45 46 # xdg-desktop-settings generates this empty file but 47 # it makes kbuildsyscoca5 fail silently. To fix this 48 # remove that menu if it exists. 49 rm -fv ''${XDG_CONFIG_HOME}/menus/applications-merged/xdg-desktop-menu-dummy.menu 50 51 # Qt writes a weird libraryPath line to 52 # ~/.config/Trolltech.conf that causes the KDE plugin 53 # paths of previous KDE invocations to be searched. 54 # Obviously using mismatching KDE libraries is potentially 55 # disastrous, so here we nuke references to the Nix store 56 # in Trolltech.conf. A better solution would be to stop 57 # Qt from doing this wackiness in the first place. 58 trolltech_conf="''${XDG_CONFIG_HOME}/Trolltech.conf" 59 if [ -e "$trolltech_conf" ]; then 60 ${getBin pkgs.gnused}/bin/sed -i "$trolltech_conf" -e '/nix\\store\|nix\/store/ d' 61 fi 62 63 # Remove the kbuildsyscoca5 cache. It will be regenerated 64 # immediately after. This is necessary for kbuildsyscoca5 to 65 # recognize that software that has been removed. 66 rm -fv $HOME/.cache/ksycoca* 67 68 ${libsForQt5.kservice}/bin/kbuildsycoca5 69 ''; 70 71 set_XDG_CONFIG_HOME = '' 72 # Set the default XDG_CONFIG_HOME if it is unset. 73 # Per the XDG Base Directory Specification: 74 # https://specifications.freedesktop.org/basedir-spec/latest 75 # 1. Never export this variable! If it is unset, then child processes are 76 # expected to set the default themselves. 77 # 2. Contaminate / if $HOME is unset; do not check if $HOME is set. 78 XDG_CONFIG_HOME=''${XDG_CONFIG_HOME:-$HOME/.config} 79 ''; 80 81in 82 83{ 84 options = { 85 services.xserver.desktopManager.plasma5 = { 86 enable = mkOption { 87 type = types.bool; 88 default = false; 89 description = lib.mdDoc "Enable the Plasma 5 (KDE 5) desktop environment."; 90 }; 91 92 phononBackend = mkOption { 93 type = types.enum [ "gstreamer" "vlc" ]; 94 default = "vlc"; 95 example = "gstreamer"; 96 description = lib.mdDoc "Phonon audio backend to install."; 97 }; 98 99 useQtScaling = mkOption { 100 type = types.bool; 101 default = false; 102 description = lib.mdDoc "Enable HiDPI scaling in Qt."; 103 }; 104 105 runUsingSystemd = mkOption { 106 description = lib.mdDoc "Use systemd to manage the Plasma session"; 107 type = types.bool; 108 default = true; 109 }; 110 111 notoPackage = mkPackageOptionMD pkgs "Noto fonts" { 112 default = [ "noto-fonts" ]; 113 example = "noto-fonts-lgc-plus"; 114 }; 115 116 # Internally allows configuring kdeglobals globally 117 kdeglobals = mkOption { 118 internal = true; 119 default = {}; 120 type = kdeConfigurationType; 121 }; 122 123 # Internally allows configuring kwin globally 124 kwinrc = mkOption { 125 internal = true; 126 default = {}; 127 type = kdeConfigurationType; 128 }; 129 130 mobile.enable = mkOption { 131 type = types.bool; 132 default = false; 133 description = lib.mdDoc '' 134 Enable support for running the Plasma Mobile shell. 135 ''; 136 }; 137 138 mobile.installRecommendedSoftware = mkOption { 139 type = types.bool; 140 default = true; 141 description = lib.mdDoc '' 142 Installs software recommended for use with Plasma Mobile, but which 143 is not strictly required for Plasma Mobile to run. 144 ''; 145 }; 146 147 bigscreen.enable = mkOption { 148 type = types.bool; 149 default = false; 150 description = lib.mdDoc '' 151 Enable support for running the Plasma Bigscreen session. 152 ''; 153 }; 154 }; 155 environment.plasma5.excludePackages = mkOption { 156 description = lib.mdDoc "List of default packages to exclude from the configuration"; 157 type = types.listOf types.package; 158 default = []; 159 example = literalExpression "[ pkgs.plasma5Packages.oxygen ]"; 160 }; 161 }; 162 163 imports = [ 164 (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "enableQt4Support" ] "Phonon no longer supports Qt 4.") 165 (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "supportDDC" ] "DDC/CI is no longer supported upstream.") 166 (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "kde5" ] [ "services" "xserver" "desktopManager" "plasma5" ]) 167 (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "excludePackages" ] [ "environment" "plasma5" "excludePackages" ]) 168 ]; 169 170 config = mkMerge [ 171 # Common Plasma dependencies 172 (mkIf (cfg.enable || cfg.mobile.enable || cfg.bigscreen.enable) { 173 174 security.wrappers = { 175 kscreenlocker_greet = { 176 setuid = true; 177 owner = "root"; 178 group = "root"; 179 source = "${getBin libsForQt5.kscreenlocker}/libexec/kscreenlocker_greet"; 180 }; 181 start_kdeinit = { 182 setuid = true; 183 owner = "root"; 184 group = "root"; 185 source = "${getBin libsForQt5.kinit}/libexec/kf5/start_kdeinit"; 186 }; 187 kwin_wayland = { 188 owner = "root"; 189 group = "root"; 190 capabilities = "cap_sys_nice+ep"; 191 source = "${getBin plasma5.kwin}/bin/kwin_wayland"; 192 }; 193 }; 194 195 environment.systemPackages = 196 with libsForQt5; 197 with plasma5; with kdeGear; with kdeFrameworks; 198 let 199 requiredPackages = [ 200 frameworkintegration 201 kactivities 202 kauth 203 kcmutils 204 kconfig 205 kconfigwidgets 206 kcoreaddons 207 kdoctools 208 kdbusaddons 209 kdeclarative 210 kded 211 kdesu 212 kdnssd 213 kemoticons 214 kfilemetadata 215 kglobalaccel 216 kguiaddons 217 kiconthemes 218 kidletime 219 kimageformats 220 kinit 221 kirigami2 # In system profile for SDDM theme. TODO: wrapper. 222 kio 223 kjobwidgets 224 knewstuff 225 knotifications 226 knotifyconfig 227 kpackage 228 kparts 229 kpeople 230 krunner 231 kservice 232 ktextwidgets 233 kwallet 234 kwallet-pam 235 kwalletmanager 236 kwayland 237 kwayland-integration 238 kwidgetsaddons 239 kxmlgui 240 kxmlrpcclient 241 plasma-framework 242 solid 243 sonnet 244 threadweaver 245 246 breeze-qt5 247 kactivitymanagerd 248 kde-cli-tools 249 kdecoration 250 kdeplasma-addons 251 kgamma5 252 khotkeys 253 kscreen 254 kscreenlocker 255 kwayland 256 kwin 257 kwrited 258 libkscreen 259 libksysguard 260 milou 261 plasma-integration 262 polkit-kde-agent 263 264 plasma-desktop 265 plasma-workspace 266 plasma-workspace-wallpapers 267 268 oxygen-sounds 269 270 breeze-icons 271 pkgs.hicolor-icon-theme 272 273 kde-gtk-config 274 breeze-gtk 275 276 qtvirtualkeyboard 277 278 pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/ 279 ]; 280 optionalPackages = [ 281 pkgs.aha # needed by kinfocenter for fwupd support 282 plasma-browser-integration 283 konsole 284 oxygen 285 (lib.getBin qttools) # Expose qdbus in PATH 286 ]; 287 in 288 requiredPackages 289 ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages 290 291 # Phonon audio backend 292 ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer 293 ++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc 294 295 # Optional hardware support features 296 ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt pkgs.openobex pkgs.obexftp ] 297 ++ lib.optional config.networking.networkmanager.enable plasma-nm 298 ++ lib.optional config.hardware.pulseaudio.enable plasma-pa 299 ++ lib.optional config.services.pipewire.pulse.enable plasma-pa 300 ++ lib.optional config.powerManagement.enable powerdevil 301 ++ lib.optional config.services.colord.enable pkgs.colord-kde 302 ++ lib.optional config.services.hardware.bolt.enable pkgs.plasma5Packages.plasma-thunderbolt 303 ++ lib.optionals config.services.samba.enable [ kdenetwork-filesharing pkgs.samba ] 304 ++ lib.optional config.services.xserver.wacom.enable pkgs.wacomtablet 305 ++ lib.optional config.services.flatpak.enable flatpak-kcm; 306 307 # Extra services for D-Bus activation 308 services.dbus.packages = [ 309 plasma5.kactivitymanagerd 310 ]; 311 312 environment.pathsToLink = [ 313 # FIXME: modules should link subdirs of `/share` rather than relying on this 314 "/share" 315 ]; 316 317 environment.etc."X11/xkb".source = xcfg.xkbDir; 318 319 environment.sessionVariables = { 320 PLASMA_USE_QT_SCALING = mkIf cfg.useQtScaling "1"; 321 322 # Needed for things that depend on other store.kde.org packages to install correctly, 323 # notably Plasma look-and-feel packages (a.k.a. Global Themes) 324 # 325 # FIXME: this is annoyingly impure and should really be fixed at source level somehow, 326 # but kpackage is a library so we can't just wrap the one thing invoking it and be done. 327 # This also means things won't work for people not on Plasma, but at least this way it 328 # works for SOME people. 329 KPACKAGE_DEP_RESOLVERS_PATH = "${pkgs.plasma5Packages.frameworkintegration.out}/libexec/kf5/kpackagehandlers"; 330 }; 331 332 # Enable GTK applications to load SVG icons 333 services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ]; 334 335 fonts.fonts = with pkgs; [ cfg.notoPackage hack-font ]; 336 fonts.fontconfig.defaultFonts = { 337 monospace = [ "Hack" "Noto Sans Mono" ]; 338 sansSerif = [ "Noto Sans" ]; 339 serif = [ "Noto Serif" ]; 340 }; 341 342 programs.ssh.askPassword = mkDefault "${plasma5.ksshaskpass.out}/bin/ksshaskpass"; 343 344 # Enable helpful DBus services. 345 services.accounts-daemon.enable = true; 346 # when changing an account picture the accounts-daemon reads a temporary file containing the image which systemsettings5 may place under /tmp 347 systemd.services.accounts-daemon.serviceConfig.PrivateTmp = false; 348 services.power-profiles-daemon.enable = mkDefault true; 349 services.system-config-printer.enable = mkIf config.services.printing.enable (mkDefault true); 350 services.udisks2.enable = true; 351 services.upower.enable = config.powerManagement.enable; 352 services.xserver.libinput.enable = mkDefault true; 353 354 # Extra UDEV rules used by Solid 355 services.udev.packages = [ 356 # libmtp has "bin", "dev", "out" outputs. UDEV rules file is in "out". 357 pkgs.libmtp.out 358 pkgs.media-player-info 359 ]; 360 361 services.xserver.displayManager.sddm = { 362 theme = mkDefault "breeze"; 363 }; 364 365 security.pam.services.kde = { allowNullPassword = true; }; 366 367 security.pam.services.login.enableKwallet = true; 368 369 systemd.user.services = { 370 plasma-early-setup = mkIf cfg.runUsingSystemd { 371 description = "Early Plasma setup"; 372 wantedBy = [ "graphical-session-pre.target" ]; 373 serviceConfig.Type = "oneshot"; 374 script = activationScript; 375 }; 376 }; 377 378 xdg.portal.enable = true; 379 xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ]; 380 # xdg-desktop-portal-kde expects PipeWire to be running. 381 # This does not, by default, replace PulseAudio. 382 services.pipewire.enable = mkDefault true; 383 384 # Update the start menu for each user that is currently logged in 385 system.userActivationScripts.plasmaSetup = activationScript; 386 387 nixpkgs.config.firefox.enablePlasmaBrowserIntegration = true; 388 }) 389 390 (mkIf (cfg.kwinrc != {}) { 391 environment.etc."xdg/kwinrc".text = lib.generators.toINI {} cfg.kwinrc; 392 }) 393 394 (mkIf (cfg.kdeglobals != {}) { 395 environment.etc."xdg/kdeglobals".text = lib.generators.toINI {} cfg.kdeglobals; 396 }) 397 398 # Plasma Desktop 399 (mkIf cfg.enable { 400 401 # Seed our configuration into nixos-generate-config 402 system.nixos-generate-config.desktopConfiguration = [ 403 '' 404 # Enable the Plasma 5 Desktop Environment. 405 services.xserver.displayManager.sddm.enable = true; 406 services.xserver.desktopManager.plasma5.enable = true; 407 '' 408 ]; 409 410 services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-workspace ]; 411 # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has 412 # many tiny bugs. 413 # See: https://github.com/NixOS/nixpkgs/issues/143272 414 services.xserver.displayManager.defaultSession = mkDefault "plasma"; 415 416 environment.systemPackages = 417 with libsForQt5; 418 with plasma5; with kdeGear; with kdeFrameworks; 419 let 420 requiredPackages = [ 421 ksystemstats 422 kinfocenter 423 kmenuedit 424 plasma-systemmonitor 425 spectacle 426 systemsettings 427 428 dolphin 429 dolphin-plugins 430 ffmpegthumbs 431 kdegraphics-thumbnailers 432 kde-inotify-survey 433 kio-admin 434 kio-extras 435 ]; 436 optionalPackages = [ 437 ark 438 elisa 439 gwenview 440 okular 441 khelpcenter 442 print-manager 443 ]; 444 in requiredPackages ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages; 445 446 systemd.user.services = { 447 plasma-run-with-systemd = { 448 description = "Run KDE Plasma via systemd"; 449 wantedBy = [ "basic.target" ]; 450 serviceConfig.Type = "oneshot"; 451 script = '' 452 ${set_XDG_CONFIG_HOME} 453 454 ${kdeFrameworks.kconfig}/bin/kwriteconfig5 \ 455 --file startkderc --group General --key systemdBoot ${lib.boolToString cfg.runUsingSystemd} 456 ''; 457 }; 458 }; 459 }) 460 461 # Plasma Mobile 462 (mkIf cfg.mobile.enable { 463 assertions = [ 464 { 465 # The user interface breaks without NetworkManager 466 assertion = config.networking.networkmanager.enable; 467 message = "Plasma Mobile requires NetworkManager."; 468 } 469 { 470 # The user interface breaks without bluetooth 471 assertion = config.hardware.bluetooth.enable; 472 message = "Plasma Mobile requires Bluetooth."; 473 } 474 { 475 # The user interface breaks without pulse 476 assertion = config.hardware.pulseaudio.enable || (config.services.pipewire.enable && config.services.pipewire.pulse.enable); 477 message = "Plasma Mobile requires pulseaudio."; 478 } 479 ]; 480 481 environment.systemPackages = 482 with libsForQt5; 483 with plasma5; with kdeApplications; with kdeFrameworks; 484 [ 485 # Basic packages without which Plasma Mobile fails to work properly. 486 plasma-mobile 487 plasma-nano 488 pkgs.maliit-framework 489 pkgs.maliit-keyboard 490 ] 491 ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with libsForQt5.plasmaMobileGear;[ 492 # Additional software made for Plasma Mobile. 493 alligator 494 angelfish 495 audiotube 496 calindori 497 kalk 498 kasts 499 kclock 500 keysmith 501 koko 502 krecorder 503 ktrip 504 kweather 505 plasma-dialer 506 plasma-phonebook 507 plasma-settings 508 spacebar 509 ]) 510 ; 511 512 # The following services are needed or the UI is broken. 513 hardware.bluetooth.enable = true; 514 hardware.pulseaudio.enable = true; 515 networking.networkmanager.enable = true; 516 # Required for autorotate 517 hardware.sensor.iio.enable = lib.mkDefault true; 518 519 # Recommendations can be found here: 520 # - https://invent.kde.org/plasma-mobile/plasma-phone-settings/-/tree/master/etc/xdg 521 # This configuration is the minimum required for Plasma Mobile to *work*. 522 services.xserver.desktopManager.plasma5 = { 523 kdeglobals = { 524 KDE = { 525 # This forces a numeric PIN for the lockscreen, which is the 526 # recommendation from upstream. 527 LookAndFeelPackage = lib.mkDefault "org.kde.plasma.phone"; 528 }; 529 }; 530 kwinrc = { 531 "Wayland" = { 532 "InputMethod[$e]" = "/run/current-system/sw/share/applications/com.github.maliit.keyboard.desktop"; 533 "VirtualKeyboardEnabled" = "true"; 534 }; 535 "org.kde.kdecoration2" = { 536 # No decorations (title bar) 537 NoPlugin = lib.mkDefault "true"; 538 }; 539 }; 540 }; 541 542 services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-mobile ]; 543 }) 544 545 # Plasma Bigscreen 546 (mkIf cfg.bigscreen.enable { 547 environment.systemPackages = 548 with pkgs.plasma5Packages; 549 [ 550 plasma-nano 551 plasma-settings 552 plasma-bigscreen 553 plasma-remotecontrollers 554 555 aura-browser 556 plank-player 557 558 plasma-pa 559 plasma-nm 560 kdeconnect-kde 561 ]; 562 563 services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ]; 564 565 # required for plasma-remotecontrollers to work correctly 566 hardware.uinput.enable = true; 567 }) 568 ]; 569}