| 1 | { |
| 2 | inputs = { |
| 3 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; |
| 4 | crane.url = "github:ipetkov/crane"; |
| 5 | }; |
| 6 | |
| 7 | outputs = |
| 8 | { |
| 9 | self, |
| 10 | nixpkgs, |
| 11 | crane, |
| 12 | }: |
| 13 | let |
| 14 | lib = nixpkgs.lib; |
| 15 | systems = [ |
| 16 | "x86_64-linux" |
| 17 | "aarch64-linux" |
| 18 | ]; |
| 19 | forAllSystems = f: lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system}); |
| 20 | |
| 21 | mkProject = |
| 22 | pkgs: |
| 23 | let |
| 24 | craneLib = crane.mkLib pkgs; |
| 25 | src = lib.cleanSourceWith { |
| 26 | src = ./.; |
| 27 | filter = |
| 28 | path: type: |
| 29 | (craneLib.filterCargoSources path type) || lib.hasInfix "/shaders" path || lib.hasInfix "/res" path; |
| 30 | name = "source"; |
| 31 | }; |
| 32 | lavapipeIcd = "${pkgs.mesa}/share/vulkan/icd.d/lvp_icd.${pkgs.stdenv.hostPlatform.parsed.cpu.name}.json"; |
| 33 | commonArgs = { |
| 34 | inherit src; |
| 35 | pname = "monolith"; |
| 36 | version = "0.0.0"; |
| 37 | strictDeps = true; |
| 38 | nativeBuildInputs = [ |
| 39 | pkgs.pkg-config |
| 40 | pkgs.glslang |
| 41 | ]; |
| 42 | buildInputs = with pkgs; [ |
| 43 | libxkbcommon |
| 44 | vulkan-loader |
| 45 | libinput |
| 46 | seatd |
| 47 | libgbm |
| 48 | libdrm |
| 49 | udev |
| 50 | ]; |
| 51 | }; |
| 52 | cargoArtifacts = craneLib.buildDepsOnly commonArgs; |
| 53 | in |
| 54 | { |
| 55 | inherit craneLib lavapipeIcd commonArgs; |
| 56 | |
| 57 | package = craneLib.buildPackage ( |
| 58 | commonArgs |
| 59 | // { |
| 60 | inherit cargoArtifacts; |
| 61 | doCheck = false; |
| 62 | postInstall = '' |
| 63 | install -Dm644 res/monolith-portals.conf -t $out/share/xdg-desktop-portal |
| 64 | install -Dm644 res/monolith.desktop -t $out/share/wayland-sessions |
| 65 | ''; |
| 66 | # ash opens libvulkan at runtime, so it is not in the linked rpath. |
| 67 | postFixup = '' |
| 68 | patchelf --add-rpath ${lib.makeLibraryPath [ pkgs.vulkan-loader ]} $out/bin/monolith |
| 69 | ''; |
| 70 | passthru.providedSessions = [ "monolith" ]; |
| 71 | meta = { |
| 72 | description = "A tiling Wayland compositor"; |
| 73 | license = lib.licenses.eupl12; |
| 74 | platforms = lib.platforms.linux; |
| 75 | mainProgram = "monolith"; |
| 76 | }; |
| 77 | } |
| 78 | ); |
| 79 | |
| 80 | checks = { |
| 81 | clippy = craneLib.cargoClippy ( |
| 82 | commonArgs |
| 83 | // { |
| 84 | inherit cargoArtifacts; |
| 85 | cargoClippyExtraArgs = "--all-targets -- --deny warnings"; |
| 86 | } |
| 87 | ); |
| 88 | fmt = craneLib.cargoFmt { |
| 89 | inherit src; |
| 90 | pname = "monolith"; |
| 91 | version = "0.0.0"; |
| 92 | }; |
| 93 | test = craneLib.cargoTest ( |
| 94 | commonArgs |
| 95 | // { |
| 96 | inherit cargoArtifacts; |
| 97 | VK_DRIVER_FILES = lavapipeIcd; |
| 98 | LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.vulkan-loader ]; |
| 99 | } |
| 100 | ); |
| 101 | }; |
| 102 | }; |
| 103 | nixosModule = |
| 104 | { |
| 105 | config, |
| 106 | lib, |
| 107 | pkgs, |
| 108 | ... |
| 109 | }: |
| 110 | let |
| 111 | inherit (lib) |
| 112 | getExe |
| 113 | literalExpression |
| 114 | mkDefault |
| 115 | mkEnableOption |
| 116 | mkIf |
| 117 | mkOption |
| 118 | optional |
| 119 | types |
| 120 | ; |
| 121 | |
| 122 | cfg = config.programs.monolith; |
| 123 | in |
| 124 | { |
| 125 | options.programs.monolith = { |
| 126 | enable = mkEnableOption "monolith, a tiling Wayland compositor"; |
| 127 | |
| 128 | package = mkOption { |
| 129 | type = types.package; |
| 130 | default = (mkProject pkgs).package; |
| 131 | defaultText = literalExpression "monolith.packages.\${system}.default"; |
| 132 | description = "The monolith package to use."; |
| 133 | }; |
| 134 | |
| 135 | realtime-scheduling = mkOption { |
| 136 | type = types.bool; |
| 137 | default = true; |
| 138 | description = '' |
| 139 | Wrap the monolith binary with CAP_SYS_NICE so its compositor thread runs |
| 140 | SCHED_RR and its Vulkan queue gets realtime global priority. monolith clears |
| 141 | the capability from everything it launches. |
| 142 | ''; |
| 143 | }; |
| 144 | |
| 145 | xwayland.enable = mkEnableOption "Xwayland, started on the first X11 client" // { |
| 146 | default = true; |
| 147 | }; |
| 148 | |
| 149 | extraPackages = mkOption { |
| 150 | type = with types; listOf package; |
| 151 | default = with pkgs; [ |
| 152 | foot |
| 153 | fuzzel |
| 154 | swaylock |
| 155 | wl-clipboard |
| 156 | ]; |
| 157 | defaultText = literalExpression "with pkgs; [ foot fuzzel swaylock wl-clipboard ]"; |
| 158 | description = "Extra packages to be installed system wide."; |
| 159 | }; |
| 160 | }; |
| 161 | |
| 162 | config = mkIf cfg.enable { |
| 163 | environment.systemPackages = (optional (!cfg.realtime-scheduling) cfg.package) ++ cfg.extraPackages; |
| 164 | |
| 165 | programs = { |
| 166 | dconf.enable = mkDefault true; |
| 167 | xwayland.enable = mkIf cfg.xwayland.enable (mkDefault true); |
| 168 | }; |
| 169 | |
| 170 | security = { |
| 171 | polkit.enable = true; |
| 172 | pam.services.swaylock = { }; |
| 173 | |
| 174 | wrappers = mkIf cfg.realtime-scheduling { |
| 175 | monolith = { |
| 176 | owner = "root"; |
| 177 | group = "root"; |
| 178 | permissions = "a+rx"; |
| 179 | source = getExe cfg.package; |
| 180 | capabilities = "cap_sys_nice+p"; |
| 181 | }; |
| 182 | }; |
| 183 | }; |
| 184 | |
| 185 | xdg.portal = { |
| 186 | enable = mkDefault true; |
| 187 | configPackages = mkDefault [ cfg.package ]; |
| 188 | extraPortals = [ |
| 189 | pkgs.xdg-desktop-portal-gtk |
| 190 | pkgs.xdg-desktop-portal-wlr |
| 191 | ]; |
| 192 | }; |
| 193 | |
| 194 | services.displayManager.sessionPackages = [ cfg.package ]; |
| 195 | }; |
| 196 | }; |
| 197 | in |
| 198 | { |
| 199 | packages = forAllSystems (pkgs: { |
| 200 | default = (mkProject pkgs).package; |
| 201 | }); |
| 202 | |
| 203 | overlays.default = final: _: { monolith = (mkProject final).package; }; |
| 204 | |
| 205 | nixosModules.default = nixosModule; |
| 206 | |
| 207 | checks = forAllSystems (pkgs: (mkProject pkgs).checks); |
| 208 | |
| 209 | devShells = forAllSystems ( |
| 210 | pkgs: |
| 211 | let |
| 212 | project = mkProject pkgs; |
| 213 | in |
| 214 | { |
| 215 | default = project.craneLib.devShell { |
| 216 | inputsFrom = [ project.package ]; |
| 217 | packages = with pkgs; [ |
| 218 | rust-analyzer |
| 219 | vulkan-tools |
| 220 | vulkan-validation-layers |
| 221 | tracy |
| 222 | ]; |
| 223 | LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.vulkan-loader ]; |
| 224 | LAVAPIPE_ICD = project.lavapipeIcd; |
| 225 | }; |
| 226 | } |
| 227 | ); |
| 228 | |
| 229 | formatter = forAllSystems (pkgs: pkgs.nixfmt); |
| 230 | }; |
| 231 | } |