diff --git a/flake.nix b/flake.nix index 1207303..66e7d97 100644 --- a/flake.nix +++ b/flake.nix @@ -22,7 +22,7 @@ flake-utils, ... }@inputs: - flake-utils.lib.eachDefaultSystem ( + (flake-utils.lib.eachDefaultSystem ( system: let pkgs = import inputs.nixpkgs { @@ -105,16 +105,31 @@ # MY_CUSTOM_VAR = "some value"; } ); + + # winit dlopens libwayland and wgpu the vulkan loader at runtime, which + # rpath alone does not cover; wrap the binary with LD_LIBRARY_PATH so + # the package also runs outside the devShell (e.g. from systemd). + barbar = pkgs.symlinkJoin { + name = "barbar-${my-crate.version}"; + paths = [ my-crate ]; + nativeBuildInputs = [ pkgs.makeWrapper ]; + postBuild = '' + wrapProgram $out/bin/core \ + --prefix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath guiLibs} + ''; + meta.mainProgram = "core"; + }; in { checks = { inherit my-crate; }; - packages.default = my-crate; + packages.default = barbar; apps.default = flake-utils.lib.mkApp { - drv = my-crate; + drv = barbar; + exePath = "/bin/core"; }; devShells.default = craneLib.devShell { @@ -135,5 +150,9 @@ packages = guiLibs ++ pkgs.lib.optionals pkgs.stdenv.hostPlatform.isLinux [ pkgs.mold ]; }; } - ); + )) + // { + # System-independent, so it lives outside eachDefaultSystem. + homeManagerModules.default = import ./nix/home-manager.nix self; + }; } diff --git a/nix/home-manager.nix b/nix/home-manager.nix new file mode 100644 index 0000000..8e40854 --- /dev/null +++ b/nix/home-manager.nix @@ -0,0 +1,86 @@ +# Home Manager module for barbar. +# +# imports = [ inputs.barbar.homeManagerModules.default ]; +# +# Generates barbar.toml from `programs.barbar.settings` and runs the bar as a +# systemd user service bound to the graphical session. +self: +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.programs.barbar; + toml = pkgs.formats.toml { }; + configFile = toml.generate "barbar.toml" cfg.settings; +in +{ + options.programs.barbar = { + enable = lib.mkEnableOption "barbar, a Wayland layer-shell status bar"; + + package = lib.mkOption { + type = lib.types.package; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; + defaultText = lib.literalExpression "barbar.packages.\${system}.default"; + description = "The barbar package to run."; + }; + + settings = lib.mkOption { + type = toml.type; + default.order = { + left = [ ]; + middle = [ ]; + right = [ ]; + }; + defaultText = lib.literalExpression ''{ order = { left = [ ]; middle = [ ]; right = [ ]; }; }''; + description = '' + Contents of barbar.toml, written verbatim. Only `order` is required by + barbar; `[display]`, `[modules.*]` and `[services.*]` are optional. + See test.toml in the barbar repo for the full schema. + ''; + example = lib.literalExpression '' + { + display = { + monitor = "DP-2"; + height = 24; + }; + order = { + left = [ "workspaces" "weather" ]; + middle = [ ]; + right = [ "clock" ]; + }; + modules.clock.show_seconds = false; + } + ''; + }; + + systemd.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Run barbar as a systemd user service."; + }; + + systemd.target = lib.mkOption { + type = lib.types.str; + default = "graphical-session.target"; + description = "Systemd target the bar is bound to."; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.user.services.barbar = lib.mkIf cfg.systemd.enable { + Unit = { + Description = "barbar status bar"; + After = [ cfg.systemd.target ]; + PartOf = [ cfg.systemd.target ]; + }; + Service = { + ExecStart = "${lib.getExe' cfg.package "core"} --config ${configFile}"; + Restart = "on-failure"; + }; + Install.WantedBy = [ cfg.systemd.target ]; + }; + }; +}