diff --git a/flakes/common/hm_modules/de_plasma/default.nix b/flakes/common/hm_modules/de_plasma/default.nix deleted file mode 100644 index 9b1a12f5..00000000 --- a/flakes/common/hm_modules/de_plasma/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: -{ - imports = [ ]; -} - diff --git a/flakes/common/nix_modules/de_plasma.nix b/flakes/common/nix_modules/de_plasma.nix deleted file mode 100644 index e69de29b..00000000 diff --git a/flakes/de_plasma/de_plasma.nix b/flakes/de_plasma/de_plasma.nix new file mode 100644 index 00000000..bd793954 --- /dev/null +++ b/flakes/de_plasma/de_plasma.nix @@ -0,0 +1,372 @@ +{ + config, + lib, + pkgs, + plasma-manager, + ... +}: +let + inherit (lib) + mkOption + types + mkEnableOption + mkIf + mkMerge + optionals + length + filter + ; + cfg = config.ringofstorms.dePlasma; + oneGpuEnabled = + (length ( + filter (x: x) [ + cfg.gpu.nvidia.enable or false + cfg.gpu.amd.enable or false + cfg.gpu.intel.enable or false + ] + )) <= 1; + panelDefaults = { + enabled = true; + location = "top"; + height = 28; + opacity = "translucent"; # "adaptive" | "translucent" | "opaque" + widgets = [ + "org.kde.plasma.kickoff" + "org.kde.plasma.icontasks" + "org.kde.plasma.systemtray" + "org.kde.plasma.networkmanagement" + "org.kde.plasma.bluetooth" + "org.kde.plasma.volume" + "org.kde.plasma.battery" + "org.kde.plasma.powerprofiles" + "org.kde.plasma.notifications" + "org.kde.plasma.digitalclock" + ]; + }; +in +{ + options.ringofstorms.dePlasma = { + enable = mkEnableOption "KDE Plasma desktop"; + + wayland = mkOption { + type = types.bool; + default = true; + description = "Enable SDDM Wayland and Plasma Wayland session."; + }; + + appearance.dark.enable = mkOption { + type = types.bool; + default = true; + description = "Enable Breeze Dark, GTK Breeze-Dark, and dark cursors."; + }; + + flatpak.enable = mkOption { + type = types.bool; + default = false; + description = "Enable Flatpak."; + }; + + sddm.autologinUser = mkOption { + type = types.nullOr types.str; + default = null; + description = "Set an autologin user for SDDM (optional)."; + }; + + gpu = { + enable32Bit = mkOption { + type = types.bool; + default = true; + description = "Install 32-bit OpenGL/VA-API bits (useful for Steam/Wine)."; + }; + nvidia = { + enable = mkOption { + type = types.bool; + default = false; + }; + open = mkOption { + type = types.bool; + default = true; + }; + package = mkOption { + type = types.package; + default = pkgs.linuxPackages.nvidiaPackages.production; + }; + }; + amd = { + enable = mkOption { + type = types.bool; + default = false; + }; + useAmdvlk = mkOption { + type = types.bool; + default = false; + }; + }; + intel = { + enable = mkOption { + type = types.bool; + default = false; + }; + legacyVaapi = mkOption { + type = types.bool; + default = false; + }; + }; + }; + + panel = { + enabled = mkOption { + type = types.bool; + default = panelDefaults.enabled; + }; + location = mkOption { + type = types.enum [ + "top" + "bottom" + "left" + "right" + ]; + default = panelDefaults.location; + }; + height = mkOption { + type = types.int; + default = panelDefaults.height; + }; + opacity = mkOption { + type = types.enum [ + "adaptive" + "translucent" + "opaque" + ]; + default = panelDefaults.opacity; + }; + widgets = mkOption { + type = types.listOf types.str; + default = panelDefaults.widgets; + }; + }; + + shortcuts = { + terminal = mkOption { + type = types.str; + default = "kitty"; + }; + launcher = mkOption { + type = types.enum [ + "krunner" + "rofi" + ]; + default = "krunner"; + }; + useI3Like = mkOption { + type = types.bool; + default = true; + }; + closeWindow = mkOption { + type = types.str; + default = "Meta+Q"; + }; + workspaceKeys = mkOption { + type = types.listOf types.str; + default = [ + "Meta+1" + "Meta+2" + "Meta+3" + "Meta+4" + "Meta+5" + "Meta+6" + "Meta+7" + "Meta+8" + "Meta+9" + ]; + }; + moveWindowWorkspaceKeys = mkOption { + type = types.listOf types.str; + default = [ + "Meta+Shift+1" + "Meta+Shift+2" + "Meta+Shift+3" + "Meta+Shift+4" + "Meta+Shift+5" + "Meta+Shift+6" + "Meta+Shift+7" + "Meta+Shift+8" + "Meta+Shift+9" + ]; + }; + }; + + monitors = { + enableOverrides = mkOption { + type = types.bool; + default = false; + }; + commands = mkOption { + type = types.listOf types.str; + default = [ ]; + }; + scriptDelayMs = mkOption { + type = types.int; + default = 500; + }; + }; + + apps.include = mkOption { + type = types.listOf types.package; + default = with pkgs; [ + kdePackages.kde-gtk-config + kdePackages.konsole + kdePackages.dolphin + kdePackages.spectacle + kdePackages.plasma-browser-integration + kdePackages.plasma-workspace-wallpapers + ]; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { + services.displayManager.sddm = { + enable = true; + wayland.enable = cfg.wayland; + theme = "breeze"; + autoLogin = mkIf (cfg.sddm.autologinUser != null) { + enable = true; + user = cfg.sddm.autologinUser; + }; + }; + services.desktopManager.plasma6.enable = true; + + # Portals + xdg.portal.enable = true; + xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; + + # Audio / IPC + services.pipewire = { + enable = true; + alsa.enable = true; + pulse.enable = true; + wireplumber.enable = true; + }; + + services.power-profiles-daemon.enable = true; + services.flatpak.enable = cfg.flatpak.enable; + + # Wayland-friendly Electron/Chromium + environment.sessionVariables.NIXOS_OZONE_WL = "1"; + + # OpenGL base + hardware.opengl = { + enable = true; + driSupport32Bit = cfg.gpu.enable32Bit; + }; + + # KDEConnect + programs.kdeconnect.enable = true; + + # Useful KDE packages + environment.systemPackages = cfg.apps.include; + + # Keyboard like sway/i3 + console.useXkbConfig = true; + services.xserver.xkb = { + layout = "us"; + options = "caps:escape"; + }; + + # Home Manager modules (plasma-manager + our HM layer) + home-manager.sharedModules = [ + plasma-manager.homeManagerModules.plasma-manager + ./home_manager + ]; + } + + # Make GTK apps dark too if enabled + (mkIf cfg.appearance.dark.enable { + environment.sessionVariables = { + GTK_THEME = "Breeze-Dark"; + XCURSOR_THEME = "breeze_cursors"; + }; + }) + + (mkIf cfg.appearance.dark.enable { + environment.systemPackages = with pkgs; [ + kdePackages.breeze + kdePackages.breeze-icons + kdePackages.breeze-gtk + ]; + environment.etc."xdg/kdeglobals".text = '' + [General] + ColorScheme=BreezeDark + + [KDE] + LookAndFeelPackage=org.kde.breezedark.desktop + widgetStyle=Breeze + + [Icons] + Theme=breeze-dark + + [Theme] + cursorTheme=breeze_cursors + ''; + }) + + # GPU blocks + (mkIf cfg.gpu.amd.enable { + services.xserver.videoDrivers = [ "amdgpu" ]; + hardware.opengl.extraPackages = with pkgs; [ + vaapiVdpau + libvdpau-va-gl + ]; + hardware.opengl.extraPackages32 = with pkgs.pkgsi686Linux; [ + libva + vaapiVdpau + libvdpau-va-gl + ]; + environment.systemPackages = optionals cfg.gpu.amd.useAmdvlk [ pkgs.amdvlk ]; + }) + + (mkIf cfg.gpu.intel.enable { + services.xserver.videoDrivers = [ "modesetting" ]; + hardware.opengl.extraPackages = + with pkgs; + [ + intel-media-driver + libvdpau-va-gl + ] + ++ optionals cfg.gpu.intel.legacyVaapi [ pkgs.vaapiIntel ]; + hardware.opengl.extraPackages32 = + with pkgs.pkgsi686Linux; + [ + libva + libvdpau-va-gl + ] + ++ optionals cfg.gpu.intel.legacyVaapi [ pkgs.vaapiIntel ]; + }) + + (mkIf cfg.gpu.nvidia.enable { + services.xserver.videoDrivers = [ "nvidia" ]; + hardware.nvidia = { + package = cfg.gpu.nvidia.package; + modesetting.enable = true; + powerManagement.enable = true; + open = cfg.gpu.nvidia.open; + nvidiaSettings = true; + }; + environment.sessionVariables = { + GBM_BACKEND = "nvidia-drm"; + __GL_GSYNC_ALLOWED = "0"; + __GL_VRR_ALLOWED = "0"; + }; + }) + + { + assertions = [ + { + assertion = oneGpuEnabled; + message = "Enable at most one of ringofstorms.dePlasma.gpu.{nvidia,amd,intel}.enable."; + } + ]; + } + ]); +} diff --git a/flakes/de_plasma/flake.nix b/flakes/de_plasma/flake.nix new file mode 100644 index 00000000..5e1408c7 --- /dev/null +++ b/flakes/de_plasma/flake.nix @@ -0,0 +1,22 @@ +{ + inputs = { + plasma-manager.url = "github:nix-community/plasma-manager"; + }; + + outputs = { plasma-manager, ... }: { + nixosModules = { + default = + { config, lib, pkgs, ... }: + { + imports = [ + ./de_plasma.nix + ]; + config = { + _module.args = { + inherit plasma-manager; + }; + }; + }; + }; + }; +} diff --git a/flakes/de_plasma/home_manager/autostart.nix b/flakes/de_plasma/home_manager/autostart.nix new file mode 100644 index 00000000..4271c644 --- /dev/null +++ b/flakes/de_plasma/home_manager/autostart.nix @@ -0,0 +1,21 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ringofstorms.dePlasma; + inherit (lib) mkIf; + delayMs = cfg.monitors.scriptDelayMs; + script = pkgs.writeShellScriptBin "plasma-kscreen-overrides" '' + set -euo pipefail + sleep $((${toString delayMs} / 1000)).$(( ${toString delayMs} % 1000 )) + ${lib.concatStringsSep "\n" (map (c: c) cfg.monitors.commands)} + ''; +in +{ + options = {}; + config = mkIf (cfg.enable && cfg.monitors.enableOverrides && cfg.monitors.commands != [ ]) { + # Use XDG autostart + xdg.autostart."ringofstorms-kscreen-overrides" = { + name = "Apply monitor overrides"; + exec = "${script}/bin/plasma-kscreen-overrides"; + }; + }; +} diff --git a/flakes/de_plasma/home_manager/default.nix b/flakes/de_plasma/home_manager/default.nix new file mode 100644 index 00000000..f5443e5e --- /dev/null +++ b/flakes/de_plasma/home_manager/default.nix @@ -0,0 +1,11 @@ +{ ... }: +{ + imports = [ + ./plasma.nix + ./shortcuts.nix + ./panel.nix + ./theme.nix + ./polkit.nix + ./autostart.nix + ]; +} diff --git a/flakes/de_plasma/home_manager/panel.nix b/flakes/de_plasma/home_manager/panel.nix new file mode 100644 index 00000000..d1021355 --- /dev/null +++ b/flakes/de_plasma/home_manager/panel.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ringofstorms.dePlasma; + inherit (lib) mkIf; + mkPanel = { + location ? cfg.panel.location, + height ? cfg.panel.height, + opacity ? cfg.panel.opacity, + widgets ? cfg.panel.widgets + }: { + location = location; + height = height; + opacity = opacity; + widgets = widgets; + }; +in +{ + options = {}; + config = mkIf (cfg.enable && cfg.panel.enabled) { + programs.plasma.panels = [ (mkPanel {}) ]; + }; +} diff --git a/flakes/de_plasma/home_manager/plasma.nix b/flakes/de_plasma/home_manager/plasma.nix new file mode 100644 index 00000000..783d4e93 --- /dev/null +++ b/flakes/de_plasma/home_manager/plasma.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ringofstorms.dePlasma; + inherit (lib) mkIf; +in +{ + options = {}; + config = mkIf cfg.enable { + # plasma-manager base enable + programs.plasma = { + enable = true; + # Tweak some global Plasma config if desired later + }; + }; +} diff --git a/flakes/de_plasma/home_manager/polkit.nix b/flakes/de_plasma/home_manager/polkit.nix new file mode 100644 index 00000000..6fd495ac --- /dev/null +++ b/flakes/de_plasma/home_manager/polkit.nix @@ -0,0 +1,4 @@ +{ ... }: +{ + # Plasma ships polkit-agent in its session; keep placeholder for parity +} diff --git a/flakes/de_plasma/home_manager/shortcuts.nix b/flakes/de_plasma/home_manager/shortcuts.nix new file mode 100644 index 00000000..0fbd1256 --- /dev/null +++ b/flakes/de_plasma/home_manager/shortcuts.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ringofstorms.dePlasma; + inherit (lib) mkIf; + workspaces = builtins.genList (i: i + 1) 9; + kwinWorkspace = builtins.listToAttrs (map (i: { + name = "Switch to Desktop ${toString i}"; + value = "Meta+${toString i}"; + }) workspaces); + kwinMoveWorkspace = builtins.listToAttrs (map (i: { + name = "Window to Desktop ${toString i}"; + value = "Meta+Shift+${toString i}"; + }) workspaces); + krunnerShortcut = if cfg.shortcuts.launcher == "krunner" then { + krunner = { "Run Command" = "Meta+Space"; }; + } else { }; +in +{ + options = {}; + config = mkIf (cfg.enable && cfg.shortcuts.useI3Like) { + programs.plasma.shortcuts = + ({ + kwin = ({ "Close Window" = cfg.shortcuts.closeWindow; } // kwinWorkspace // kwinMoveWorkspace); + } // krunnerShortcut); + + programs.plasma.hotkeys.commands = { + ringofstorms_terminal = { + key = "Meta+Return"; + command = cfg.shortcuts.terminal; + }; + } // (if cfg.shortcuts.launcher == "rofi" then { + ringofstorms_launcher = { + key = "Meta+Space"; + command = "rofi -show drun"; + }; + } else {}); + }; +} diff --git a/flakes/de_plasma/home_manager/theme.nix b/flakes/de_plasma/home_manager/theme.nix new file mode 100644 index 00000000..83376b8f --- /dev/null +++ b/flakes/de_plasma/home_manager/theme.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ringofstorms.dePlasma; + inherit (lib) mkIf; +in +{ + options = {}; + config = mkIf (cfg.enable && cfg.appearance.dark.enable) { + programs.plasma = { + workspace = { + colorScheme = "Breeze Dark"; + lookAndFeel = "org.kde.breezedark.desktop"; + cursorTheme = "breeze_cursors"; + }; + fonts = { }; # keep defaults + kscreenlocker = { }; # swaylock analog not applicable; left default + }; + }; +} diff --git a/hosts/lio/plasma_overrides.nix b/hosts/lio/plasma_overrides.nix new file mode 100644 index 00000000..0208f0cd --- /dev/null +++ b/hosts/lio/plasma_overrides.nix @@ -0,0 +1,37 @@ +{ pkgs, lib, config, ... }: +let + inherit (lib) mkIf; + cfg = config.ringofstorms.dePlasma; +in +{ + options = {}; + config = mkIf cfg.enable { + # Example per-host overrides for Plasma on lio + ringofstorms.dePlasma = { + monitors = { + enableOverrides = false; # start disabled for non-overridden machine + commands = [ + # Example: uncomment and adjust outputs + # "kscreen-doctor output.DP-1.mode.3840x2160@60 output.DP-1.position.0,0 output.DP-1.primary.true" + # "kscreen-doctor output.DP-2.mode.3440x1440@99.98 output.DP-2.rotation.left output.DP-2.position.-1440,0" + ]; + scriptDelayMs = 500; + }; + shortcuts = { + terminal = "kitty"; + launcher = "krunner"; + useI3Like = true; + closeWindow = "Meta+Q"; + }; + panel = { + enabled = true; + location = "top"; + height = 28; + opacity = "translucent"; + }; + sddm.autologinUser = null; + flatpak.enable = false; + # GPU vendor left unset; set per machine if needed + }; + }; +}