1 { config, lib, pkgs, utils, ... }:
4 xcfg = config.services.xserver;
5 cfg = xcfg.desktopManager.plasma5;
7 # Use only for **internal** options.
8 # This is not exactly user-friendly.
9 kdeConfigurationType = with types;
17 description = "KDE Configuration value";
18 emptyValue.value = "";
20 set = (nullOr (lazyAttrsOf valueTypes)) // {
21 description = "KDE Configuration set";
22 emptyValue.value = {};
24 in (lazyAttrsOf set) // {
25 description = "KDE Configuration file";
26 emptyValue.value = {};
29 libsForQt5 = pkgs.plasma5Packages;
30 inherit (libsForQt5) kdeGear kdeFrameworks plasma5;
32 getBin optionalAttrs optionalString literalExpression
33 mkRemovedOptionModule mkRenamedOptionModule
34 mkDefault mkIf mkMerge mkOption mkPackageOptionMD types;
37 ${set_XDG_CONFIG_HOME}
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
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
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'
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*
68 ${libsForQt5.kservice}/bin/kbuildsycoca5
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}
85 services.xserver.desktopManager.plasma5 = {
89 description = lib.mdDoc "Enable the Plasma 5 (KDE 5) desktop environment.";
92 phononBackend = mkOption {
93 type = types.enum [ "gstreamer" "vlc" ];
95 example = "gstreamer";
96 description = lib.mdDoc "Phonon audio backend to install.";
99 useQtScaling = mkOption {
102 description = lib.mdDoc "Enable HiDPI scaling in Qt.";
105 runUsingSystemd = mkOption {
106 description = lib.mdDoc "Use systemd to manage the Plasma session";
111 notoPackage = mkPackageOptionMD pkgs "Noto fonts" {
112 default = [ "noto-fonts" ];
113 example = "noto-fonts-lgc-plus";
116 # Internally allows configuring kdeglobals globally
117 kdeglobals = mkOption {
120 type = kdeConfigurationType;
123 # Internally allows configuring kwin globally
127 type = kdeConfigurationType;
130 mobile.enable = mkOption {
133 description = lib.mdDoc ''
134 Enable support for running the Plasma Mobile shell.
138 mobile.installRecommendedSoftware = mkOption {
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.
147 bigscreen.enable = mkOption {
150 description = lib.mdDoc ''
151 Enable support for running the Plasma Bigscreen session.
155 environment.plasma5.excludePackages = mkOption {
156 description = lib.mdDoc "List of default packages to exclude from the configuration";
157 type = types.listOf types.package;
159 example = literalExpression "[ pkgs.plasma5Packages.oxygen ]";
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" ])
171 # Common Plasma dependencies
172 (mkIf (cfg.enable || cfg.mobile.enable || cfg.bigscreen.enable) {
174 security.wrappers = {
178 capabilities = "cap_sys_nice+ep";
179 source = "${getBin plasma5.kwin}/bin/kwin_wayland";
181 } // optionalAttrs (!cfg.runUsingSystemd) {
186 source = "${getBin libsForQt5.kinit}/libexec/kf5/start_kdeinit";
190 environment.systemPackages =
192 with plasma5; with kdeGear; with kdeFrameworks;
216 kirigami2 # In system profile for SDDM theme. TODO: wrapper.
261 plasma-workspace-wallpapers
266 pkgs.hicolor-icon-theme
273 pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
276 pkgs.aha # needed by kinfocenter for fwupd support
277 plasma-browser-integration
280 (lib.getBin qttools) # Expose qdbus in PATH
284 ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages
286 # Phonon audio backend
287 ++ lib.optional (cfg.phononBackend == "gstreamer") libsForQt5.phonon-backend-gstreamer
288 ++ lib.optional (cfg.phononBackend == "vlc") libsForQt5.phonon-backend-vlc
290 # Optional hardware support features
291 ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt pkgs.openobex pkgs.obexftp ]
292 ++ lib.optional config.networking.networkmanager.enable plasma-nm
293 ++ lib.optional config.hardware.pulseaudio.enable plasma-pa
294 ++ lib.optional config.services.pipewire.pulse.enable plasma-pa
295 ++ lib.optional config.powerManagement.enable powerdevil
296 ++ lib.optional config.services.colord.enable pkgs.colord-kde
297 ++ lib.optional config.services.hardware.bolt.enable pkgs.plasma5Packages.plasma-thunderbolt
298 ++ lib.optionals config.services.samba.enable [ kdenetwork-filesharing pkgs.samba ]
299 ++ lib.optional config.services.xserver.wacom.enable pkgs.wacomtablet
300 ++ lib.optional config.services.flatpak.enable flatpak-kcm;
302 # Extra services for D-Bus activation
303 services.dbus.packages = [
304 plasma5.kactivitymanagerd
307 environment.pathsToLink = [
308 # FIXME: modules should link subdirs of `/share` rather than relying on this
312 environment.etc."X11/xkb".source = xcfg.xkb.dir;
314 environment.sessionVariables = {
315 PLASMA_USE_QT_SCALING = mkIf cfg.useQtScaling "1";
317 # Needed for things that depend on other store.kde.org packages to install correctly,
318 # notably Plasma look-and-feel packages (a.k.a. Global Themes)
320 # FIXME: this is annoyingly impure and should really be fixed at source level somehow,
321 # but kpackage is a library so we can't just wrap the one thing invoking it and be done.
322 # This also means things won't work for people not on Plasma, but at least this way it
323 # works for SOME people.
324 KPACKAGE_DEP_RESOLVERS_PATH = "${pkgs.plasma5Packages.frameworkintegration.out}/libexec/kf5/kpackagehandlers";
327 # Enable GTK applications to load SVG icons
328 services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
330 fonts.packages = with pkgs; [ cfg.notoPackage hack-font ];
331 fonts.fontconfig.defaultFonts = {
332 monospace = [ "Hack" "Noto Sans Mono" ];
333 sansSerif = [ "Noto Sans" ];
334 serif = [ "Noto Serif" ];
337 programs.ssh.askPassword = mkDefault "${plasma5.ksshaskpass.out}/bin/ksshaskpass";
339 # Enable helpful DBus services.
340 services.accounts-daemon.enable = true;
341 # when changing an account picture the accounts-daemon reads a temporary file containing the image which systemsettings5 may place under /tmp
342 systemd.services.accounts-daemon.serviceConfig.PrivateTmp = false;
343 services.power-profiles-daemon.enable = mkDefault true;
344 services.system-config-printer.enable = mkIf config.services.printing.enable (mkDefault true);
345 services.udisks2.enable = true;
346 services.upower.enable = config.powerManagement.enable;
347 services.xserver.libinput.enable = mkDefault true;
349 # Extra UDEV rules used by Solid
350 services.udev.packages = [
351 # libmtp has "bin", "dev", "out" outputs. UDEV rules file is in "out".
353 pkgs.media-player-info
356 services.xserver.displayManager.sddm = {
357 theme = mkDefault "breeze";
360 security.pam.services.kde = { allowNullPassword = true; };
362 security.pam.services.login.enableKwallet = true;
364 systemd.user.services = {
365 plasma-early-setup = mkIf cfg.runUsingSystemd {
366 description = "Early Plasma setup";
367 wantedBy = [ "graphical-session-pre.target" ];
368 serviceConfig.Type = "oneshot";
369 script = activationScript;
373 xdg.portal.enable = true;
374 xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ];
375 xdg.portal.configPackages = mkDefault [ plasma5.xdg-desktop-portal-kde ];
376 # xdg-desktop-portal-kde expects PipeWire to be running.
377 # This does not, by default, replace PulseAudio.
378 services.pipewire.enable = mkDefault true;
380 # Update the start menu for each user that is currently logged in
381 system.userActivationScripts.plasmaSetup = activationScript;
383 programs.firefox.nativeMessagingHosts.packages = [ pkgs.plasma5Packages.plasma-browser-integration ];
386 (mkIf (cfg.kwinrc != {}) {
387 environment.etc."xdg/kwinrc".text = lib.generators.toINI {} cfg.kwinrc;
390 (mkIf (cfg.kdeglobals != {}) {
391 environment.etc."xdg/kdeglobals".text = lib.generators.toINI {} cfg.kdeglobals;
397 # Seed our configuration into nixos-generate-config
398 system.nixos-generate-config.desktopConfiguration = [
400 # Enable the Plasma 5 Desktop Environment.
401 services.xserver.displayManager.sddm.enable = true;
402 services.xserver.desktopManager.plasma5.enable = true;
406 services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-workspace ];
407 # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
409 # See: https://github.com/NixOS/nixpkgs/issues/143272
410 services.xserver.displayManager.defaultSession = mkDefault "plasma";
412 environment.systemPackages =
414 with plasma5; with kdeGear; with kdeFrameworks;
427 kdegraphics-thumbnailers
440 in requiredPackages ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages;
442 systemd.user.services = {
443 plasma-run-with-systemd = {
444 description = "Run KDE Plasma via systemd";
445 wantedBy = [ "basic.target" ];
446 serviceConfig.Type = "oneshot";
448 ${set_XDG_CONFIG_HOME}
450 ${kdeFrameworks.kconfig}/bin/kwriteconfig5 \
451 --file startkderc --group General --key systemdBoot ${lib.boolToString cfg.runUsingSystemd}
458 (mkIf cfg.mobile.enable {
461 # The user interface breaks without NetworkManager
462 assertion = config.networking.networkmanager.enable;
463 message = "Plasma Mobile requires NetworkManager.";
466 # The user interface breaks without bluetooth
467 assertion = config.hardware.bluetooth.enable;
468 message = "Plasma Mobile requires Bluetooth.";
471 # The user interface breaks without pulse
472 assertion = config.hardware.pulseaudio.enable || (config.services.pipewire.enable && config.services.pipewire.pulse.enable);
473 message = "Plasma Mobile requires pulseaudio.";
477 environment.systemPackages =
479 with plasma5; with kdeApplications; with kdeFrameworks;
481 # Basic packages without which Plasma Mobile fails to work properly.
484 pkgs.maliit-framework
487 ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with libsForQt5.plasmaMobileGear;[
488 # Additional software made for Plasma Mobile.
508 # The following services are needed or the UI is broken.
509 hardware.bluetooth.enable = true;
510 hardware.pulseaudio.enable = true;
511 networking.networkmanager.enable = true;
512 # Required for autorotate
513 hardware.sensor.iio.enable = lib.mkDefault true;
515 # Recommendations can be found here:
516 # - https://invent.kde.org/plasma-mobile/plasma-phone-settings/-/tree/master/etc/xdg
517 # This configuration is the minimum required for Plasma Mobile to *work*.
518 services.xserver.desktopManager.plasma5 = {
521 # This forces a numeric PIN for the lockscreen, which is the
522 # recommendation from upstream.
523 LookAndFeelPackage = lib.mkDefault "org.kde.plasma.phone";
528 "InputMethod[$e]" = "/run/current-system/sw/share/applications/com.github.maliit.keyboard.desktop";
529 "VirtualKeyboardEnabled" = "true";
531 "org.kde.kdecoration2" = {
532 # No decorations (title bar)
533 NoPlugin = lib.mkDefault "true";
538 services.xserver.displayManager.sessionPackages = [ pkgs.libsForQt5.plasma5.plasma-mobile ];
542 (mkIf cfg.bigscreen.enable {
543 environment.systemPackages =
544 with pkgs.plasma5Packages;
549 plasma-remotecontrollers
559 services.xserver.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ];
561 # required for plasma-remotecontrollers to work correctly
562 hardware.uinput.enable = true;