1{
2 config,
3 lib,
4 pkgs,
5 utils,
6 ...
7}:
8let
9 cfg = config.services.desktopManager.plasma6;
10
11 inherit (pkgs) kdePackages;
12 inherit (lib)
13 literalExpression
14 mkDefault
15 mkIf
16 mkOption
17 mkPackageOption
18 types
19 ;
20
21 activationScript = ''
22 # will be rebuilt automatically
23 rm -fv "$HOME/.cache/ksycoca"*
24 '';
25in
26{
27 options = {
28 services.desktopManager.plasma6 = {
29 enable = mkOption {
30 type = types.bool;
31 default = false;
32 description = "Enable the Plasma 6 (KDE 6) desktop environment.";
33 };
34
35 enableQt5Integration = mkOption {
36 type = types.bool;
37 default = true;
38 description = "Enable Qt 5 integration (theming, etc). Disable for a pure Qt 6 system.";
39 };
40
41 notoPackage = mkPackageOption pkgs "Noto fonts - used for UI by default" {
42 default = [ "noto-fonts" ];
43 example = "noto-fonts-lgc-plus";
44 };
45 };
46
47 environment.plasma6.excludePackages = mkOption {
48 description = "List of default packages to exclude from the configuration";
49 type = types.listOf types.package;
50 default = [ ];
51 example = literalExpression "[ pkgs.kdePackages.elisa ]";
52 };
53 };
54
55 imports = [
56 (lib.mkRenamedOptionModule
57 [ "services" "xserver" "desktopManager" "plasma6" "enable" ]
58 [ "services" "desktopManager" "plasma6" "enable" ]
59 )
60 (lib.mkRenamedOptionModule
61 [ "services" "xserver" "desktopManager" "plasma6" "enableQt5Integration" ]
62 [ "services" "desktopManager" "plasma6" "enableQt5Integration" ]
63 )
64 (lib.mkRenamedOptionModule
65 [ "services" "xserver" "desktopManager" "plasma6" "notoPackage" ]
66 [ "services" "desktopManager" "plasma6" "notoPackage" ]
67 )
68 ];
69
70 config = mkIf cfg.enable {
71 qt.enable = true;
72 programs.xwayland.enable = true;
73 environment.systemPackages =
74 with kdePackages;
75 let
76 requiredPackages = [
77 qtwayland # Hack? To make everything run on Wayland
78 qtsvg # Needed to render SVG icons
79
80 # Frameworks with globally loadable bits
81 frameworkintegration # provides Qt plugin
82 kauth # provides helper service
83 kcoreaddons # provides extra mime type info
84 kded # provides helper service
85 kfilemetadata # provides Qt plugins
86 kguiaddons # provides geo URL handlers
87 kiconthemes # provides Qt plugins
88 kimageformats # provides Qt plugins
89 qtimageformats # provides optional image formats such as .webp and .avif
90 kio # provides helper service + a bunch of other stuff
91 kio-admin # managing files as admin
92 kio-extras # stuff for MTP, AFC, etc
93 kio-fuse # fuse interface for KIO
94 kpackage # provides kpackagetool tool
95 kservice # provides kbuildsycoca6 tool
96 kunifiedpush # provides a background service and a KCM
97 kwallet # provides helper service
98 kwallet-pam # provides helper service
99 kwalletmanager # provides KCMs and stuff
100 plasma-activities # provides plasma-activities-cli tool
101 solid # provides solid-hardware6 tool
102 phonon-vlc # provides Phonon plugin
103
104 # Core Plasma parts
105 kwin
106 kscreen
107 libkscreen
108 kscreenlocker
109 kactivitymanagerd
110 kde-cli-tools
111 kglobalacceld # keyboard shortcut daemon
112 kwrited # wall message proxy, not to be confused with kwrite
113 baloo # system indexer
114 milou # search engine atop baloo
115 kdegraphics-thumbnailers # pdf etc thumbnailer
116 polkit-kde-agent-1 # polkit auth ui
117 plasma-desktop
118 plasma-workspace
119 drkonqi # crash handler
120 kde-inotify-survey # warns the user on low inotifywatch limits
121
122 # Application integration
123 libplasma # provides Kirigami platform theme
124 plasma-integration # provides Qt platform theme
125 kde-gtk-config # syncs KDE settings to GTK
126
127 # Artwork + themes
128 breeze
129 breeze-icons
130 breeze-gtk
131 ocean-sound-theme
132 pkgs.hicolor-icon-theme # fallback icons
133 qqc2-breeze-style
134 qqc2-desktop-style
135
136 # misc Plasma extras
137 kdeplasma-addons
138 pkgs.xdg-user-dirs # recommended upstream
139
140 # Plasma utilities
141 kmenuedit
142 kinfocenter
143 plasma-systemmonitor
144 ksystemstats
145 libksysguard
146 systemsettings
147 kcmutils
148 ];
149 optionalPackages = [
150 aurorae
151 plasma-browser-integration
152 plasma-workspace-wallpapers
153 konsole
154 kwin-x11
155 (lib.getBin qttools) # Expose qdbus in PATH
156 ark
157 elisa
158 gwenview
159 okular
160 kate
161 ktexteditor # provides elevated actions for kate
162 khelpcenter
163 dolphin
164 baloo-widgets # baloo information in Dolphin
165 dolphin-plugins
166 spectacle
167 ffmpegthumbs
168 krdp
169 xwaylandvideobridge # exposes Wayland windows to X11 screen capture
170 ]
171 ++ lib.optionals config.hardware.sensor.iio.enable [
172 # This is required for autorotation in Plasma 6
173 qtsensors
174 ]
175 ++ lib.optionals config.services.flatpak.enable [
176 # Since PackageKit Nix support is not there yet,
177 # only install discover if flatpak is enabled.
178 discover
179 ];
180 in
181 requiredPackages
182 ++ utils.removePackagesByName optionalPackages config.environment.plasma6.excludePackages
183 ++ lib.optionals config.services.desktopManager.plasma6.enableQt5Integration [
184 breeze.qt5
185 plasma-integration.qt5
186 kwayland-integration
187 (
188 # Only symlink the KIO plugins, so we don't accidentally pull any services
189 # like KCMs or kcookiejar
190 let
191 kioPluginPath = "${pkgs.plasma5Packages.qtbase.qtPluginPrefix}/kf5/kio";
192 inherit (pkgs.plasma5Packages) kio;
193 in
194 pkgs.runCommand "kio5-plugins-only" { } ''
195 mkdir -p $out/${kioPluginPath}
196 ln -s ${kio}/${kioPluginPath}/* $out/${kioPluginPath}
197 ''
198 )
199 kio-extras-kf5
200 ]
201 # Optional and hardware support features
202 ++ lib.optionals config.hardware.bluetooth.enable [
203 bluedevil
204 bluez-qt
205 pkgs.openobex
206 pkgs.obexftp
207 ]
208 ++ lib.optional config.networking.networkmanager.enable plasma-nm
209 ++ lib.optional config.services.pulseaudio.enable plasma-pa
210 ++ lib.optional config.services.pipewire.pulse.enable plasma-pa
211 ++ lib.optional config.powerManagement.enable powerdevil
212 ++ lib.optional config.services.printing.enable print-manager
213 ++ lib.optional config.services.colord.enable colord-kde
214 ++ lib.optional config.services.hardware.bolt.enable plasma-thunderbolt
215 ++ lib.optional config.services.samba.enable kdenetwork-filesharing
216 ++ lib.optional config.services.xserver.wacom.enable wacomtablet
217 ++ lib.optional config.services.flatpak.enable flatpak-kcm;
218
219 environment.pathsToLink = [
220 # FIXME: modules should link subdirs of `/share` rather than relying on this
221 "/share"
222 "/libexec" # for drkonqi
223 ];
224
225 environment.etc."X11/xkb".source = config.services.xserver.xkb.dir;
226
227 # Add ~/.config/kdedefaults to XDG_CONFIG_DIRS for shells, since Plasma sets that.
228 # FIXME: maybe we should append to XDG_CONFIG_DIRS in /etc/set-environment instead?
229 environment.sessionVariables.XDG_CONFIG_DIRS = [ "$HOME/.config/kdedefaults" ];
230
231 # Needed for things that depend on other store.kde.org packages to install correctly,
232 # notably Plasma look-and-feel packages (a.k.a. Global Themes)
233 #
234 # FIXME: this is annoyingly impure and should really be fixed at source level somehow,
235 # but kpackage is a library so we can't just wrap the one thing invoking it and be done.
236 # This also means things won't work for people not on Plasma, but at least this way it
237 # works for SOME people.
238 environment.sessionVariables.KPACKAGE_DEP_RESOLVERS_PATH = "${kdePackages.frameworkintegration.out}/libexec/kf6/kpackagehandlers";
239
240 # Enable GTK applications to load SVG icons
241 programs.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
242
243 fonts.packages = [
244 cfg.notoPackage
245 pkgs.hack-font
246 ];
247 fonts.fontconfig.defaultFonts = {
248 monospace = [
249 "Hack"
250 "Noto Sans Mono"
251 ];
252 sansSerif = [ "Noto Sans" ];
253 serif = [ "Noto Serif" ];
254 };
255
256 programs.gnupg.agent.pinentryPackage = mkDefault pkgs.pinentry-qt;
257 programs.kde-pim.enable = mkDefault true;
258 programs.ssh.askPassword = mkDefault "${kdePackages.ksshaskpass.out}/bin/ksshaskpass";
259
260 # Enable helpful DBus services.
261 services.accounts-daemon.enable = true;
262 # when changing an account picture the accounts-daemon reads a temporary file containing the image which systemsettings5 may place under /tmp
263 systemd.services.accounts-daemon.serviceConfig.PrivateTmp = false;
264
265 services.power-profiles-daemon.enable = mkDefault true;
266 services.system-config-printer.enable = mkIf config.services.printing.enable (mkDefault true);
267 services.udisks2.enable = true;
268 services.upower.enable = config.powerManagement.enable;
269 services.libinput.enable = mkDefault true;
270
271 # Extra UDEV rules used by Solid
272 services.udev.packages = [
273 # libmtp has "bin", "dev", "out" outputs. UDEV rules file is in "out".
274 pkgs.libmtp.out
275 pkgs.media-player-info
276 ];
277
278 # Set up Dr. Konqi as crash handler
279 systemd.packages = [ kdePackages.drkonqi ];
280 systemd.services."drkonqi-coredump-processor@".wantedBy = [ "systemd-coredump@.service" ];
281
282 xdg.icons.enable = true;
283 xdg.icons.fallbackCursorThemes = mkDefault [ "breeze_cursors" ];
284
285 xdg.portal.enable = true;
286 xdg.portal.extraPortals = [
287 kdePackages.kwallet
288 kdePackages.xdg-desktop-portal-kde
289 pkgs.xdg-desktop-portal-gtk
290 ];
291 xdg.portal.configPackages = mkDefault [ kdePackages.plasma-workspace ];
292 services.pipewire.enable = mkDefault true;
293
294 # Enable screen reader by default
295 services.orca.enable = mkDefault true;
296
297 services.displayManager = {
298 sessionPackages = [ kdePackages.plasma-workspace ];
299 defaultSession = mkDefault "plasma";
300 };
301 services.displayManager.sddm = {
302 package = kdePackages.sddm;
303 theme = mkDefault "breeze";
304 wayland = mkDefault {
305 enable = true;
306 compositor = "kwin";
307 };
308 extraPackages = with kdePackages; [
309 breeze-icons
310 kirigami
311 libplasma
312 plasma5support
313 qtsvg
314 qtvirtualkeyboard
315 ];
316 };
317
318 security.pam.services = {
319 login.kwallet = {
320 enable = true;
321 package = kdePackages.kwallet-pam;
322 };
323 kde = {
324 allowNullPassword = true;
325 kwallet = {
326 enable = true;
327 package = kdePackages.kwallet-pam;
328 };
329 };
330 kde-fingerprint = lib.mkIf config.services.fprintd.enable { fprintAuth = true; };
331 kde-smartcard = lib.mkIf config.security.pam.p11.enable { p11Auth = true; };
332 };
333
334 security.wrappers = {
335 kwin_wayland = {
336 owner = "root";
337 group = "root";
338 capabilities = "cap_sys_nice+ep";
339 source = "${lib.getBin pkgs.kdePackages.kwin}/bin/kwin_wayland";
340 };
341
342 ksystemstats_intel_helper = {
343 owner = "root";
344 group = "root";
345 capabilities = "cap_perfmon+ep";
346 source = "${pkgs.kdePackages.ksystemstats}/libexec/ksystemstats_intel_helper";
347 };
348
349 ksgrd_network_helper = {
350 owner = "root";
351 group = "root";
352 capabilities = "cap_net_raw+ep";
353 source = "${pkgs.kdePackages.libksysguard}/libexec/ksysguard/ksgrd_network_helper";
354 };
355 };
356
357 # Upstream recommends allowing set-timezone and set-ntp so that the KCM and
358 # the automatic timezone logic work without user interruption.
359 # However, on NixOS NTP cannot be overwritten via dbus, and timezone
360 # can only be set if `time.timeZone` is set to `null`. So, we only allow
361 # set-timezone, and we only allow it when the timezone can actually be set.
362 security.polkit.extraConfig = lib.mkIf (config.time.timeZone != null) ''
363 polkit.addRule(function(action, subject) {
364 if (action.id == "org.freedesktop.timedate1.set-timezone" && subject.active) {
365 return polkit.Result.YES;
366 }
367 });
368 '';
369
370 programs.dconf.enable = true;
371
372 programs.firefox.nativeMessagingHosts.packages = [ kdePackages.plasma-browser-integration ];
373
374 programs.chromium = {
375 enablePlasmaBrowserIntegration = true;
376 plasmaBrowserIntegrationPackage = pkgs.kdePackages.plasma-browser-integration;
377 };
378
379 programs.kdeconnect.package = kdePackages.kdeconnect-kde;
380 programs.partition-manager.package = kdePackages.partitionmanager;
381
382 # FIXME: ugly hack. See #292632 for details.
383 system.userActivationScripts.rebuildSycoca = activationScript;
384 systemd.user.services.nixos-rebuild-sycoca = {
385 description = "Rebuild KDE system configuration cache";
386 wantedBy = [ "graphical-session-pre.target" ];
387 serviceConfig.Type = "oneshot";
388 script = activationScript;
389 };
390 };
391}