grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / x11 / desktop-managers / plasma5.nix
blob90a1596d57e6926cb0400b4998ba4d71ff7a83ce
1 { config, lib, pkgs, utils, ... }:
3 let
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;
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       };
29   inherit (lib)
30     getBin optionalAttrs literalExpression
31     mkRemovedOptionModule mkRenamedOptionModule
32     mkDefault mkIf mkMerge mkOption mkPackageOption types;
34   activationScript = ''
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'
59     fi
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
67   '';
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}
77   '';
82   options = {
83     services.xserver.desktopManager.plasma5 = {
84       enable = mkOption {
85         type = types.bool;
86         default = false;
87         description = "Enable the Plasma 5 (KDE 5) desktop environment.";
88       };
90       phononBackend = mkOption {
91         type = types.enum [ "gstreamer" "vlc" ];
92         default = "vlc";
93         example = "gstreamer";
94         description = "Phonon audio backend to install.";
95       };
97       useQtScaling = mkOption {
98         type = types.bool;
99         default = false;
100         description = "Enable HiDPI scaling in Qt.";
101       };
103       runUsingSystemd = mkOption {
104         description = "Use systemd to manage the Plasma session";
105         type = types.bool;
106         default = true;
107       };
109       notoPackage = mkPackageOption pkgs "Noto fonts" {
110         default = [ "noto-fonts" ];
111         example = "noto-fonts-lgc-plus";
112       };
114       # Internally allows configuring kdeglobals globally
115       kdeglobals = mkOption {
116         internal = true;
117         default = {};
118         type = kdeConfigurationType;
119       };
121       # Internally allows configuring kwin globally
122       kwinrc = mkOption {
123         internal = true;
124         default = {};
125         type = kdeConfigurationType;
126       };
128       mobile.enable = mkOption {
129         type = types.bool;
130         default = false;
131         description = ''
132           Enable support for running the Plasma Mobile shell.
133         '';
134       };
136       mobile.installRecommendedSoftware = mkOption {
137         type = types.bool;
138         default = true;
139         description = ''
140           Installs software recommended for use with Plasma Mobile, but which
141           is not strictly required for Plasma Mobile to run.
142         '';
143       };
145       bigscreen.enable = mkOption {
146         type = types.bool;
147         default = false;
148         description = ''
149           Enable support for running the Plasma Bigscreen session.
150         '';
151       };
152     };
153     environment.plasma5.excludePackages = mkOption {
154         description = "List of default packages to exclude from the configuration";
155         type = types.listOf types.package;
156         default = [];
157         example = literalExpression "[ pkgs.plasma5Packages.oxygen ]";
158       };
159   };
161   imports = [
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" ])
166   ];
168   config = mkMerge [
169     # Common Plasma dependencies
170     (mkIf (cfg.enable || cfg.mobile.enable || cfg.bigscreen.enable) {
172       security.wrappers = {
173         kwin_wayland = {
174           owner = "root";
175           group = "root";
176           capabilities = "cap_sys_nice+ep";
177           source = "${getBin pkgs.plasma5Packages.kwin}/bin/kwin_wayland";
178         };
179       } // optionalAttrs (!cfg.runUsingSystemd) {
180         start_kdeinit = {
181           setuid = true;
182           owner = "root";
183           group = "root";
184           source = "${getBin pkgs.plasma5Packages.kinit}/libexec/kf5/start_kdeinit";
185         };
186       };
188       qt.enable = true;
190       environment.systemPackages =
191         with pkgs.plasma5Packages;
192         let
193           requiredPackages = [
194             frameworkintegration
195             kactivities
196             kauth
197             kcmutils
198             kconfig
199             kconfigwidgets
200             kcoreaddons
201             kdoctools
202             kdbusaddons
203             kdeclarative
204             kded
205             kdesu
206             kdnssd
207             kemoticons
208             kfilemetadata
209             kglobalaccel
210             kguiaddons
211             kiconthemes
212             kidletime
213             kimageformats
214             kinit
215             kirigami2 # In system profile for SDDM theme. TODO: wrapper.
216             kio
217             kjobwidgets
218             knewstuff
219             knotifications
220             knotifyconfig
221             kpackage
222             kparts
223             kpeople
224             krunner
225             kservice
226             ktextwidgets
227             kwallet
228             kwallet-pam
229             kwalletmanager
230             kwayland
231             kwayland-integration
232             kwidgetsaddons
233             kxmlgui
234             kxmlrpcclient
235             plasma-framework
236             solid
237             sonnet
238             threadweaver
240             breeze-qt5
241             kactivitymanagerd
242             kde-cli-tools
243             kdecoration
244             kdeplasma-addons
245             kgamma5
246             khotkeys
247             kscreen
248             kscreenlocker
249             kwayland
250             kwin
251             kwrited
252             libkscreen
253             libksysguard
254             milou
255             plasma-integration
256             polkit-kde-agent
258             qqc2-breeze-style
259             qqc2-desktop-style
261             plasma-desktop
262             plasma-workspace
263             plasma-workspace-wallpapers
265             oxygen-sounds
267             breeze-icons
268             pkgs.hicolor-icon-theme
270             kde-gtk-config
271             breeze-gtk
273             qtvirtualkeyboard
275             pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
276           ];
277           optionalPackages = [
278             pkgs.aha # needed by kinfocenter for fwupd support
279             plasma-browser-integration
280             konsole
281             oxygen
282             (lib.getBin qttools) # Expose qdbus in PATH
283           ];
284         in
285         requiredPackages
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
307       ];
309       environment.pathsToLink = [
310         # FIXME: modules should link subdirs of `/share` rather than relying on this
311         "/share"
312       ];
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)
321         #
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";
327       };
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" ];
337       };
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".
356         pkgs.libmtp.out
357         pkgs.media-player-info
358       ];
360       # Enable screen reader by default
361       services.orca.enable = mkDefault true;
363       services.displayManager.sddm = {
364         theme = mkDefault "breeze";
365       };
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;
377         };
378       };
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;
393     })
395     (mkIf (cfg.kwinrc != {}) {
396       environment.etc."xdg/kwinrc".text = lib.generators.toINI {} cfg.kwinrc;
397     })
399     (mkIf (cfg.kdeglobals != {}) {
400       environment.etc."xdg/kdeglobals".text = lib.generators.toINI {} cfg.kdeglobals;
401     })
403     # Plasma Desktop
404     (mkIf cfg.enable {
406       # Seed our configuration into nixos-generate-config
407       system.nixos-generate-config.desktopConfiguration = [
408         ''
409           # Enable the Plasma 5 Desktop Environment.
410           services.displayManager.sddm.enable = true;
411           services.xserver.desktopManager.plasma5.enable = true;
412         ''
413       ];
415       services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-workspace ];
416       # Default to be `plasma` (X11) instead of `plasmawayland`, since plasma wayland currently has
417       # many tiny bugs.
418       # See: https://github.com/NixOS/nixpkgs/issues/143272
419       services.displayManager.defaultSession = mkDefault "plasma";
421       environment.systemPackages =
422         with pkgs.plasma5Packages;
423         let
424           requiredPackages = [
425             ksystemstats
426             kinfocenter
427             kmenuedit
428             plasma-systemmonitor
429             spectacle
430             systemsettings
432             dolphin
433             dolphin-plugins
434             ffmpegthumbs
435             kdegraphics-thumbnailers
436             kde-inotify-survey
437             kio-admin
438             kio-extras
439           ];
440           optionalPackages = [
441             ark
442             elisa
443             gwenview
444             okular
445             khelpcenter
446             print-manager
447           ];
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";
455           script = ''
456             ${set_XDG_CONFIG_HOME}
458             ${pkgs.plasma5Packages.kconfig}/bin/kwriteconfig5 \
459               --file startkderc --group General --key systemdBoot ${lib.boolToString cfg.runUsingSystemd}
460           '';
461         };
462       };
463     })
465     # Plasma Mobile
466     (mkIf cfg.mobile.enable {
467       assertions = [
468         {
469           # The user interface breaks without NetworkManager
470           assertion = config.networking.networkmanager.enable;
471           message = "Plasma Mobile requires NetworkManager.";
472         }
473         {
474           # The user interface breaks without bluetooth
475           assertion = config.hardware.bluetooth.enable;
476           message = "Plasma Mobile requires Bluetooth.";
477         }
478         {
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.";
482         }
483       ];
485       environment.systemPackages =
486         with pkgs.plasma5Packages;
487         [
488           # Basic packages without which Plasma Mobile fails to work properly.
489           plasma-mobile
490           plasma-nano
491           pkgs.maliit-framework
492           pkgs.maliit-keyboard
493         ]
494         ++ lib.optionals (cfg.mobile.installRecommendedSoftware) (with pkgs.plasma5Packages.plasmaMobileGear; [
495           # Additional software made for Plasma Mobile.
496           alligator
497           angelfish
498           audiotube
499           calindori
500           kalk
501           kasts
502           kclock
503           keysmith
504           koko
505           krecorder
506           ktrip
507           kweather
508           plasma-dialer
509           plasma-phonebook
510           plasma-settings
511           spacebar
512         ])
513       ;
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 = {
525         kdeglobals = {
526           KDE = {
527             # This forces a numeric PIN for the lockscreen, which is the
528             # recommendation from upstream.
529             LookAndFeelPackage = lib.mkDefault "org.kde.plasma.phone";
530           };
531         };
532         kwinrc = {
533           "Wayland" = {
534             "InputMethod[$e]" = "/run/current-system/sw/share/applications/com.github.maliit.keyboard.desktop";
535             "VirtualKeyboardEnabled" = "true";
536           };
537           "org.kde.kdecoration2" = {
538             # No decorations (title bar)
539             NoPlugin = lib.mkDefault "true";
540           };
541         };
542       };
544       services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-mobile ];
545     })
547     # Plasma Bigscreen
548     (mkIf cfg.bigscreen.enable {
549       environment.systemPackages =
550         with pkgs.plasma5Packages;
551         [
552           plasma-nano
553           plasma-settings
554           plasma-bigscreen
555           plasma-remotecontrollers
557           aura-browser
558           plank-player
560           plasma-pa
561           plasma-nm
562           kdeconnect-kde
563         ];
565       services.displayManager.sessionPackages = [ pkgs.plasma5Packages.plasma-bigscreen ];
567       # required for plasma-remotecontrollers to work correctly
568       hardware.uinput.enable = true;
569     })
570   ];