| 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 | dbus |
| 51 | ]; |
| 52 | }; |
| 53 | cargoArtifacts = craneLib.buildDepsOnly commonArgs; |
| 54 | in |
| 55 | { |
| 56 | inherit craneLib lavapipeIcd commonArgs; |
| 57 | |
| 58 | package = craneLib.buildPackage ( |
| 59 | commonArgs |
| 60 | // { |
| 61 | inherit cargoArtifacts; |
| 62 | doCheck = false; |
| 63 | postInstall = '' |
| 64 | install -Dm644 res/monolith-portals.conf -t $out/share/xdg-desktop-portal |
| 65 | install -Dm644 res/monolith.desktop -t $out/share/wayland-sessions |
| 66 | ''; |
| 67 | # ash opens libvulkan at runtime, so it is not in the linked rpath. |
| 68 | postFixup = '' |
| 69 | patchelf --add-rpath ${lib.makeLibraryPath [ pkgs.vulkan-loader ]} $out/bin/monolith |
| 70 | ''; |
| 71 | passthru.providedSessions = [ "monolith" ]; |
| 72 | meta = { |
| 73 | description = "A tiling Wayland compositor"; |
| 74 | license = lib.licenses.eupl12; |
| 75 | platforms = lib.platforms.linux; |
| 76 | mainProgram = "monolith"; |
| 77 | }; |
| 78 | } |
| 79 | ); |
| 80 | |
| 81 | checks = { |
| 82 | clippy = craneLib.cargoClippy ( |
| 83 | commonArgs |
| 84 | // { |
| 85 | inherit cargoArtifacts; |
| 86 | cargoClippyExtraArgs = "--all-targets -- --deny warnings"; |
| 87 | } |
| 88 | ); |
| 89 | fmt = craneLib.cargoFmt { |
| 90 | inherit src; |
| 91 | pname = "monolith"; |
| 92 | version = "0.0.0"; |
| 93 | }; |
| 94 | test = craneLib.cargoTest ( |
| 95 | commonArgs |
| 96 | // { |
| 97 | inherit cargoArtifacts; |
| 98 | VK_DRIVER_FILES = lavapipeIcd; |
| 99 | LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.vulkan-loader ]; |
| 100 | } |
| 101 | ); |
| 102 | }; |
| 103 | }; |
| 104 | nixosModule = |
| 105 | { |
| 106 | config, |
| 107 | lib, |
| 108 | pkgs, |
| 109 | ... |
| 110 | }: |
| 111 | let |
| 112 | inherit (lib) |
| 113 | getExe |
| 114 | literalExpression |
| 115 | mkDefault |
| 116 | mkEnableOption |
| 117 | mkIf |
| 118 | mkOption |
| 119 | optional |
| 120 | types |
| 121 | ; |
| 122 | |
| 123 | cfg = config.programs.monolith; |
| 124 | in |
| 125 | { |
| 126 | options.programs.monolith = { |
| 127 | enable = mkEnableOption "monolith, a tiling Wayland compositor"; |
| 128 | |
| 129 | package = mkOption { |
| 130 | type = types.package; |
| 131 | default = (mkProject pkgs).package; |
| 132 | defaultText = literalExpression "monolith.packages.\${system}.default"; |
| 133 | description = "The monolith package to use."; |
| 134 | }; |
| 135 | |
| 136 | realtime-scheduling = mkOption { |
| 137 | type = types.bool; |
| 138 | default = true; |
| 139 | description = '' |
| 140 | Wrap the monolith binary with CAP_SYS_NICE so its compositor thread runs |
| 141 | SCHED_RR and its Vulkan queue gets realtime global priority. monolith clears |
| 142 | the capability from everything it launches. |
| 143 | ''; |
| 144 | }; |
| 145 | |
| 146 | xwayland.enable = mkEnableOption "Xwayland, started on the first X11 client" // { |
| 147 | default = true; |
| 148 | }; |
| 149 | }; |
| 150 | |
| 151 | config = mkIf cfg.enable { |
| 152 | environment.systemPackages = optional (!cfg.realtime-scheduling) cfg.package; |
| 153 | |
| 154 | programs = { |
| 155 | dconf.enable = mkDefault true; |
| 156 | xwayland.enable = mkIf cfg.xwayland.enable (mkDefault true); |
| 157 | }; |
| 158 | |
| 159 | security = { |
| 160 | polkit.enable = true; |
| 161 | pam.services.swaylock = { }; |
| 162 | |
| 163 | wrappers = mkIf cfg.realtime-scheduling { |
| 164 | monolith = { |
| 165 | owner = "root"; |
| 166 | group = "root"; |
| 167 | permissions = "a+rx"; |
| 168 | source = getExe cfg.package; |
| 169 | capabilities = "cap_sys_nice+p"; |
| 170 | }; |
| 171 | }; |
| 172 | }; |
| 173 | |
| 174 | xdg.portal = { |
| 175 | enable = mkDefault true; |
| 176 | configPackages = mkDefault [ cfg.package ]; |
| 177 | extraPortals = [ |
| 178 | pkgs.xdg-desktop-portal-gtk |
| 179 | pkgs.xdg-desktop-portal-wlr |
| 180 | ]; |
| 181 | }; |
| 182 | |
| 183 | services.displayManager.sessionPackages = [ cfg.package ]; |
| 184 | }; |
| 185 | }; |
| 186 | in |
| 187 | { |
| 188 | packages = forAllSystems (pkgs: { |
| 189 | default = (mkProject pkgs).package; |
| 190 | }); |
| 191 | |
| 192 | overlays.default = final: _: { monolith = (mkProject final).package; }; |
| 193 | |
| 194 | nixosModules.default = nixosModule; |
| 195 | |
| 196 | checks = forAllSystems (pkgs: (mkProject pkgs).checks); |
| 197 | |
| 198 | devShells = forAllSystems ( |
| 199 | pkgs: |
| 200 | let |
| 201 | project = mkProject pkgs; |
| 202 | in |
| 203 | { |
| 204 | default = project.craneLib.devShell { |
| 205 | inputsFrom = [ project.package ]; |
| 206 | packages = with pkgs; [ |
| 207 | rust-analyzer |
| 208 | vulkan-tools |
| 209 | vulkan-validation-layers |
| 210 | tracy |
| 211 | ]; |
| 212 | LD_LIBRARY_PATH = lib.makeLibraryPath [ pkgs.vulkan-loader ]; |
| 213 | LAVAPIPE_ICD = project.lavapipeIcd; |
| 214 | }; |
| 215 | } |
| 216 | ); |
| 217 | |
| 218 | formatter = forAllSystems (pkgs: pkgs.nixfmt); |
| 219 | }; |
| 220 | } |