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 = {};
30 getBin optionalAttrs literalExpression
31 mkRemovedOptionModule mkRenamedOptionModule
32 mkDefault mkIf mkMerge mkOption mkPackageOption types;
35 ${set_XDG_CONFIG_HOME}
37 # The KDE icon cache is supposed to update itself automatically, but it uses
38 # the timestamp on the icon theme directory as a trigger. This doesn't work
39 # on NixOS because the timestamp never changes. As a workaround, delete the
40 # icon cache at login and session activation.
41 # See also: http://lists-archives.org/kde-devel/26175-what-when-will-icon-cache-refresh.html
42 rm -fv $HOME/.cache/icon-cache.kcache
44 # xdg-desktop-settings generates this empty file but
45 # it makes kbuildsyscoca5 fail silently. To fix this
46 # remove that menu if it exists.
47 rm -fv ''${XDG_CONFIG_HOME}/menus/applications-merged/xdg-desktop-menu-dummy.menu
49 # Qt writes a weird ‘libraryPath’ line to
50 # ~/.config/Trolltech.conf that causes the KDE plugin
51 # paths of previous KDE invocations to be searched.
52 # Obviously using mismatching KDE libraries is potentially
53 # disastrous, so here we nuke references to the Nix store
54 # in Trolltech.conf. A better solution would be to stop
55 # Qt from doing this wackiness in the first place.
56 trolltech_conf="''${XDG_CONFIG_HOME}/Trolltech.conf"
57 if [ -e "$trolltech_conf" ]; then
58 ${getBin pkgs.gnused}/bin/sed -i "$trolltech_conf" -e '/nix\\store\|nix\/store/ d'
61 # Remove the kbuildsyscoca5 cache. It will be regenerated
62 # immediately after. This is necessary for kbuildsyscoca5 to
63 # recognize that software that has been removed.
64 rm -fv $HOME/.cache/ksycoca*
66 ${pkgs.plasma5Packages.kservice}/bin/kbuildsycoca5
69 set_XDG_CONFIG_HOME = ''
70 # Set the default XDG_CONFIG_HOME if it is unset.
71 # Per the XDG Base Directory Specification:
72 # https://specifications.freedesktop.org/basedir-spec/latest
73 # 1. Never export this variable! If it is unset, then child processes are
74 # expected to set the default themselves.
75 # 2. Contaminate / if $HOME is unset; do not check if $HOME is set.
76 XDG_CONFIG_HOME=''${XDG_CONFIG_HOME:-$HOME/.config}
83 services.xserver.desktopManager.plasma5 = {
87 description = "Enable the Plasma 5 (KDE 5) desktop environment.";
90 phononBackend = mkOption {
91 type = types.enum [ "gstreamer" "vlc" ];
93 example = "gstreamer";
94 description = "Phonon audio backend to install.";
97 useQtScaling = mkOption {
100 description = "Enable HiDPI scaling in Qt.";
103 runUsingSystemd = mkOption {
104 description = "Use systemd to manage the Plasma session";
109 notoPackage = mkPackageOption pkgs "Noto fonts" {
110 default = [ "noto-fonts" ];
111 example = "noto-fonts-lgc-plus";
114 # Internally allows configuring kdeglobals globally
115 kdeglobals = mkOption {
118 type = kdeConfigurationType;
121 # Internally allows configuring kwin globally
125 type = kdeConfigurationType;
128 mobile.enable = mkOption {
132 Enable support for running the Plasma Mobile shell.
136 mobile.installRecommendedSoftware = mkOption {
140 Installs software recommended for use with Plasma Mobile, but which
141 is not strictly required for Plasma Mobile to run.
145 bigscreen.enable = mkOption {
149 Enable support for running the Plasma Bigscreen session.
153 environment.plasma5.excludePackages = mkOption {
154 description = "List of default packages to exclude from the configuration";
155 type = types.listOf types.package;
157 example = literalExpression "[ pkgs.plasma5Packages.oxygen ]";
162 (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "enableQt4Support" ] "Phonon no longer supports Qt 4.")
163 (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "supportDDC" ] "DDC/CI is no longer supported upstream.")
164 (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "kde5" ] [ "services" "xserver" "desktopManager" "plasma5" ])
165 (mkRenamedOptionModule [ "services" "xserver" "desktopManager" "plasma5" "excludePackages" ] [ "environment" "plasma5" "excludePackages" ])
169 # Common Plasma dependencies
170 (mkIf (cfg.enable || cfg.mobile.enable || cfg.bigscreen.enable) {
172 security.wrappers = {
176 capabilities = "cap_sys_nice+ep";
177 source = "${getBin pkgs.plasma5Packages.kwin}/bin/kwin_wayland";
179 } // optionalAttrs (!cfg.runUsingSystemd) {
184 source = "${getBin pkgs.plasma5Packages.kinit}/libexec/kf5/start_kdeinit";
190 environment.systemPackages =
191 with pkgs.plasma5Packages;
215 kirigami2 # In system profile for SDDM theme. TODO: wrapper.
263 plasma-workspace-wallpapers
268 pkgs.hicolor-icon-theme
275 pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
278 pkgs.aha # needed by kinfocenter for fwupd support
279 plasma-browser-integration
282 (lib.getBin qttools) # Expose qdbus in PATH
286 ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages
288 # Phonon audio backend
289 ++ lib.optional (cfg.phononBackend == "gstreamer") pkgs.plasma5Packages.phonon-backend-gstreamer
290 ++ lib.optional (cfg.phononBackend == "vlc") pkgs.plasma5Packages.phonon-backend-vlc
292 # Optional hardware support features
293 ++ lib.optionals config.hardware.bluetooth.enable [ bluedevil bluez-qt pkgs.openobex pkgs.obexftp ]
294 ++ lib.optional config.networking.networkmanager.enable plasma-nm
295 ++ lib.optional config.hardware.pulseaudio.enable plasma-pa
296 ++ lib.optional config.services.pipewire.pulse.enable plasma-pa
297 ++ lib.optional config.powerManagement.enable powerdevil
298 ++ lib.optional config.services.colord.enable pkgs.colord-kde
299 ++ lib.optional config.services.hardware.bolt.enable pkgs.plasma5Packages.plasma-thunderbolt
300 ++ lib.optional config.services.samba.enable kdenetwork-filesharing
301 ++ lib.optional config.services.xserver.wacom.enable pkgs.wacomtablet
302 ++ lib.optional config.services.flatpak.enable flatpak-kcm;
304 # Extra services for D-Bus activation
305 services.dbus.packages = [
306 pkgs.plasma5Packages.kactivitymanagerd
309 environment.pathsToLink = [
310 # FIXME: modules should link subdirs of `/share` rather than relying on this
314 environment.etc."X11/xkb".source = xcfg.xkb.dir;
316 environment.sessionVariables = {
317 PLASMA_USE_QT_SCALING = mkIf cfg.useQtScaling "1";
319 # Needed for things that depend on other store.kde.org packages to install correctly,
320 # notably Plasma look-and-feel packages (a.k.a. Global Themes)
322 # FIXME: this is annoyingly impure and should really be fixed at source level somehow,
323 # but kpackage is a library so we can't just wrap the one thing invoking it and be done.
324 # This also means things won't work for people not on Plasma, but at least this way it
325 # works for SOME people.
326 KPACKAGE_DEP_RESOLVERS_PATH = "${pkgs.plasma5Packages.frameworkintegration.out}/libexec/kf5/kpackagehandlers";
329 # Enable GTK applications to load SVG icons
330 programs.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
332 fonts.packages = with pkgs; [ cfg.notoPackage hack-font ];
333 fonts.fontconfig.defaultFonts = {
334 monospace = [ "Hack" "Noto Sans Mono" ];
335 sansSerif = [ "Noto Sans" ];
336 serif = [ "Noto Serif" ];
339 programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
340 programs.ssh.askPassword = mkDefault "${pkgs.plasma5Packages.ksshaskpass.out}/bin/ksshaskpass";
342 # Enable helpful DBus services.
343 services.accounts-daemon.enable = true;
344 programs.dconf.enable = true;
345 # when changing an account picture the accounts-daemon reads a temporary file containing the image which systemsettings5 may place under /tmp
346 systemd.services.accounts-daemon.serviceConfig.PrivateTmp = false;
347 services.power-profiles-daemon.enable = mkDefault true;
348 services.system-config-printer.enable = mkIf config.services.printing.enable (mkDefault true);
349 services.udisks2.enable = true;
350 services.upower.enable = config.powerManagement.enable;
351 services.libinput.enable = mkDefault true;
353 # Extra UDEV rules used by Solid
354 services.udev.packages = [
355 # libmtp has "bin", "dev", "out" outputs. UDEV rules file is in "out".
357 pkgs.media-player-info
360 # Enable screen reader by default
361 services.orca.enable = mkDefault true;
363 services.displayManager.sddm = {
364 theme = mkDefault "breeze";
367 security.pam.services.kde = { allowNullPassword = true; };
369 security.pam.services.login.kwallet.enable = true;
371 systemd.user.services = {
372 plasma-early-setup = mkIf cfg.runUsingSystemd {
373 description = "Early Plasma setup";
374 wantedBy = [ "graphical-session-pre.target" ];
375 serviceConfig.Type = "oneshot";
376 script = activationScript;
380 xdg.icons.enable = true;
382 xdg.portal.enable = true;
383 xdg.portal.extraPortals = [ pkgs.plasma5Packages.xdg-desktop-portal-kde ];
384 xdg.portal.configPackages = mkDefault [ pkgs.plasma5Packages.xdg-desktop-portal-kde ];
385 # xdg-desktop-portal-kde expects PipeWire to be running.
386 services.pipewire.enable = mkDefault true;
388 # Update the start menu for each user that is currently logged in
389 system.userActivationScripts.plasmaSetup = activationScript;
391 programs.firefox.nativeMessagingHosts.packages = [ pkgs.plasma5Packages.plasma-browser-integration ];
392 programs.chromium.enablePlasmaBrowserIntegration = true;
395 (mkIf (cfg.kwinrc != {}) {
396 environment.etc."xdg/kwinrc".text = lib.generators.toINI {} cfg.kwinrc;
399 (mkIf (cfg.kdeglobals != {}) {
400 environment.etc."xdg/kdeglobals".text = lib.generators.toINI {} cfg.kdeglobals;
406 # Seed our configuration into nixos-generate-config
407 system.nixos-generate-config.desktopConfiguration = [
409 # Enable the Plasma 5 Desktop Environment.
410 services.displayManager.sddm.enable = true;
411 services.xserver.desktopManager.plasma5.enable = true;
415 services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-workspace ];
416 # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
418 # See: https://github.com/NixOS/nixpkgs/issues/143272
419 services.displayManager.defaultSession = mkDefault "plasma";
421 environment.systemPackages =
422 with pkgs.plasma5Packages;
435 kdegraphics-thumbnailers
448 in requiredPackages ++ utils.removePackagesByName optionalPackages config.environment.plasma5.excludePackages;
450 systemd.user.services = {
451 plasma-run-with-systemd = {
452 description = "Run KDE Plasma via systemd";
453 wantedBy = [ "basic.target" ];
454 serviceConfig.Type = "oneshot";
456 ${set_XDG_CONFIG_HOME}
458 ${pkgs.plasma5Packages.kconfig}/bin/kwriteconfig5 \
459 --file startkderc --group General --key systemdBoot ${lib.boolToString cfg.runUsingSystemd}
466 (mkIf cfg.mobile.enable {
469 # The user interface breaks without NetworkManager
470 assertion = config.networking.networkmanager.enable;
471 message = "Plasma Mobile requires NetworkManager.";
474 # The user interface breaks without bluetooth
475 assertion = config.hardware.bluetooth.enable;
476 message = "Plasma Mobile requires Bluetooth.";
479 # The user interface breaks without pulse
480 assertion = config.hardware.pulseaudio.enable || (config.services.pipewire.enable && config.services.pipewire.pulse.enable);
481 message = "Plasma Mobile requires a Pulseaudio compatible sound server.";
485 environment.systemPackages =
486 with pkgs.plasma5Packages;
488 # Basic packages without which Plasma Mobile fails to work properly.
491 pkgs.maliit-framework
494 ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with pkgs.plasma5Packages.plasmaMobileGear; [
495 # Additional software made for Plasma Mobile.
515 # The following services are needed or the UI is broken.
516 hardware.bluetooth.enable = true;
517 networking.networkmanager.enable = true;
518 # Required for autorotate
519 hardware.sensor.iio.enable = lib.mkDefault true;
521 # Recommendations can be found here:
522 # - https://invent.kde.org/plasma-mobile/plasma-phone-settings/-/tree/master/etc/xdg
523 # This configuration is the minimum required for Plasma Mobile to *work*.
524 services.xserver.desktopManager.plasma5 = {
527 # This forces a numeric PIN for the lockscreen, which is the
528 # recommendation from upstream.
529 LookAndFeelPackage = lib.mkDefault "org.kde.plasma.phone";
534 "InputMethod[$e]" = "/run/current-system/sw/share/applications/com.github.maliit.keyboard.desktop";
535 "VirtualKeyboardEnabled" = "true";
537 "org.kde.kdecoration2" = {
538 # No decorations (title bar)
539 NoPlugin = lib.mkDefault "true";
544 services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-mobile ];
548 (mkIf cfg.bigscreen.enable {
549 environment.systemPackages =
550 with pkgs.plasma5Packages;
555 plasma-remotecontrollers
565 services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ];
567 # required for plasma-remotecontrollers to work correctly
568 hardware.uinput.enable = true;