summaryrefslogtreecommitdiffstats
path: root/krebs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2021-01-25 01:54:28 +0100
committertv <tv@krebsco.de>2021-01-26 20:54:47 +0100
commit6e9f5602a92933dafc1f6c0420aa4329cdd9a17d (patch)
tree2c39f3998ba9d06d15cf9757c282b47bc4dec7cd /krebs
parent21303714afa87ca3081a9fbc4585d86badc131bb (diff)
nixos/xmonad: import and make reloadable
Import nixos/modules/services/x11/window-managers/xmonad.nix from nixpkgs de121de16ef947bc8e8bfdaa37b5c6cc506050c6 and turn it into a user service that reloads xmonad whenever its configuration changes.
Diffstat (limited to 'krebs')
-rw-r--r--krebs/3modules/upstream/window-managers/default.nix22
-rw-r--r--krebs/3modules/upstream/window-managers/xmonad.nix189
2 files changed, 211 insertions, 0 deletions
diff --git a/krebs/3modules/upstream/window-managers/default.nix b/krebs/3modules/upstream/window-managers/default.nix
new file mode 100644
index 000000000..eecadca7e
--- /dev/null
+++ b/krebs/3modules/upstream/window-managers/default.nix
@@ -0,0 +1,22 @@
+{
+ imports = [
+ # Replace upstream xmonad module with one that will be reloaded if changed.
+ #
+ # This module is intended to be upstreamed once fully tested.
+ # The patch to be committed can be obtained using:
+ #
+ # diff -u <nixpkgs/nixos/modules/services/x11/window-managers/xmonad.nix> \
+ # <stockholm/tv/3modules/window-managers/xmonad.nix>
+ #
+ {
+ disabledModules = [ "services/x11/window-managers/xmonad.nix" ];
+ imports = [ ./xmonad.nix ];
+ nixpkgs.overlays = [(self: super: {
+ writers = super.writers // {
+ writeHaskellBin = name: spec: with import <stockholm/lib>;
+ super.writers.writeHaskellBin name (removeAttrs spec ["ghcArgs"]);
+ };
+ })];
+ }
+ ];
+}
diff --git a/krebs/3modules/upstream/window-managers/xmonad.nix b/krebs/3modules/upstream/window-managers/xmonad.nix
new file mode 100644
index 000000000..356fa46bf
--- /dev/null
+++ b/krebs/3modules/upstream/window-managers/xmonad.nix
@@ -0,0 +1,189 @@
+{pkgs, lib, config, ...}:
+
+with lib;
+let
+ inherit (lib) mkOption mkIf optionals literalExample;
+ cfg = config.services.xserver.windowManager.xmonad;
+
+ ghcWithPackages = cfg.haskellPackages.ghcWithPackages;
+ packages = self: cfg.extraPackages self ++
+ optionals cfg.enableContribAndExtras
+ [ self.xmonad-contrib self.xmonad-extras ];
+
+ xmonad-vanilla = pkgs.xmonad-with-packages.override {
+ inherit ghcWithPackages packages;
+ };
+
+ xmonad-config =
+ let
+ xmonadAndPackages = self: [ self.xmonad ] ++ packages self;
+ xmonadEnv = ghcWithPackages xmonadAndPackages;
+ configured = pkgs.writers.writeHaskellBin "xmonad" {
+ ghc = cfg.haskellPackages.ghc;
+ libraries = xmonadAndPackages cfg.haskellPackages;
+ inherit (cfg) ghcArgs;
+ } cfg.config;
+ in
+ pkgs.runCommandLocal "xmonad" {
+ nativeBuildInputs = [ pkgs.makeWrapper ];
+ } ''
+ install -D ${xmonadEnv}/share/man/man1/xmonad.1.gz $out/share/man/man1/xmonad.1.gz
+ makeWrapper ${configured}/bin/xmonad $out/bin/xmonad \
+ --set NIX_GHC "${xmonadEnv}/bin/ghc" \
+ --set XMONAD_XMESSAGE "${pkgs.xorg.xmessage}/bin/xmessage"
+ '';
+
+ xmonad = if (cfg.config != null) then xmonad-config else xmonad-vanilla;
+in {
+ meta.maintainers = with maintainers; [ lassulus xaverdh ivanbrennan ];
+
+ options = {
+ services.xserver.windowManager.xmonad = {
+ enable = mkEnableOption "xmonad";
+ haskellPackages = mkOption {
+ default = pkgs.haskellPackages;
+ defaultText = "pkgs.haskellPackages";
+ example = literalExample "pkgs.haskell.packages.ghc784";
+ description = ''
+ haskellPackages used to build Xmonad and other packages.
+ This can be used to change the GHC version used to build
+ Xmonad and the packages listed in
+ <varname>extraPackages</varname>.
+ '';
+ };
+
+ extraPackages = mkOption {
+ default = self: [];
+ defaultText = "self: []";
+ example = literalExample ''
+ haskellPackages: [
+ haskellPackages.xmonad-contrib
+ haskellPackages.monad-logger
+ ]
+ '';
+ description = ''
+ Extra packages available to ghc when rebuilding Xmonad. The
+ value must be a function which receives the attrset defined
+ in <varname>haskellPackages</varname> as the sole argument.
+ '';
+ };
+
+ enableContribAndExtras = mkOption {
+ default = false;
+ type = lib.types.bool;
+ description = "Enable xmonad-{contrib,extras} in Xmonad.";
+ };
+
+ config = mkOption {
+ default = null;
+ type = with lib.types; nullOr (either path str);
+ description = ''
+ Configuration from which XMonad gets compiled. If no value is
+ specified, a vanilla xmonad binary is put in PATH, which will
+ attempt to recompile and exec your xmonad config from $HOME/.xmonad.
+ This setup is then analogous to other (non-NixOS) linux distributions.
+
+ If you do set this option, you likely want to use "launch" as your
+ entry point for xmonad (as in the example), to avoid xmonad's
+ recompilation logic on startup. Doing so will render the default
+ "mod+q" restart key binding dysfunctional though, because that attempts
+ to call your binary with the "--restart" command line option, unless
+ you implement that yourself. You way mant to bind "mod+q" to
+ <literal>(restart "xmonad" True)</literal> instead, which will just restart
+ xmonad from PATH. This allows e.g. switching to the new xmonad binary
+ after rebuilding your system with nixos-rebuild.
+
+ If you actually want to run xmonad with a config specified here, but
+ also be able to recompile and restart it from a copy of that source in
+ $HOME/.xmonad on the fly, you will have to implement that yourself
+ using something like "compileRestart" from the example.
+ This should allow you to switch at will between the local xmonad and
+ the one NixOS puts in your PATH.
+ '';
+ example = ''
+ import XMonad
+ import XMonad.Util.EZConfig (additionalKeys)
+ import Control.Monad (when)
+ import Text.Printf (printf)
+ import System.Posix.Process (executeFile)
+ import System.Info (arch,os)
+ import System.Environment (getArgs)
+ import System.FilePath ((</>))
+
+ compiledConfig = printf "xmonad-%s-%s" arch os
+
+ compileRestart resume =
+ whenX (recompile True) $
+ when resume writeStateToFile
+ *> catchIO
+ ( do
+ dir <- getXMonadDataDir
+ args <- getArgs
+ executeFile (dir </> compiledConfig) False args Nothing
+ )
+
+ main = launch defaultConfig
+ { modMask = mod4Mask -- Use Super instead of Alt
+ , terminal = "urxvt" }
+ `additionalKeys`
+ [ ( (mod4Mask,xK_r), compileRestart True)
+ , ( (mod4Mask,xK_q), restart "xmonad" True ) ]
+ '';
+ };
+
+ xmonadCliArgs = mkOption {
+ default = [];
+ type = with lib.types; listOf str;
+ description = ''
+ Command line arguments passed to the xmonad binary.
+ '';
+ };
+
+ ghcArgs = mkOption {
+ default = [];
+ type = with lib.types; listOf str;
+ description = ''
+ Command line arguments passed to the compiler (ghc)
+ invocation when xmonad.config is set.
+ '';
+ };
+
+ };
+ };
+ config = mkIf cfg.enable {
+ services.xserver.windowManager = {
+ session = [{
+ name = "xmonad";
+ start = ''
+ systemctl --user start --wait xmonad.service &
+ waitPID=$!
+ '';
+ }];
+ };
+
+ system.userActivationScripts.xmonad-reload = /* sh */ ''
+ if ${pkgs.systemd}/bin/systemctl --user is-active --quiet xmonad.service; then
+ if [ "$(readlink -f "$XDG_RUNTIME_DIR"/xmonad/xmonad)" != ${xmonad}/bin/xmonad ]; then
+ ${pkgs.systemd}/bin/systemctl --user reload xmonad.service
+ fi
+ fi
+ '';
+
+ systemd.user.services.xmonad = {
+ requisite = [ "graphical-session.target" ];
+ after = [ "graphical-session.target" ];
+ environment.PATH = mkForce "%t/xmonad";
+ environment.XMONAD_DATA_DIR = "%t/xmonad";
+ serviceConfig = rec {
+ ExecStartPre = [
+ "${pkgs.coreutils}/bin/mkdir -p %t/xmonad"
+ "${pkgs.coreutils}/bin/ln -fns ${xmonad}/bin/xmonad %t/xmonad/xmonad"
+ ];
+ ExecStart = "%t/xmonad/xmonad ${lib.escapeShellArgs cfg.xmonadCliArgs}";
+ ExecReload = ExecStartPre ++ [ "${xmonad-vanilla}/bin/xmonad --restart" ];
+ };
+ };
+
+ environment.systemPackages = [ xmonad ];
+ };
+}