diff --git a/nixos/modules/services/x11/window-managers/xmonad.nix b/nixos/modules/services/x11/window-managers/xmonad.nix
index ecad411ff683..68f97c2f504b 100644
--- a/nixos/modules/services/x11/window-managers/xmonad.nix
+++ b/nixos/modules/services/x11/window-managers/xmonad.nix
@@ -2,7 +2,7 @@
with lib;
let
- inherit (lib) mkOption mkIf optionals literalExpression;
+ inherit (lib) mkOption mkIf optionals literalExpression optionalString;
cfg = config.services.xserver.windowManager.xmonad;
ghcWithPackages = cfg.haskellPackages.ghcWithPackages;
@@ -26,11 +26,14 @@ let
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 \
+ '' + optionalString cfg.enableConfiguredRecompile ''
+ --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 {
@@ -95,12 +98,14 @@ in {
xmonad from PATH. This allows e.g. switching to the new xmonad binary
after rebuilding your system with nixos-rebuild.
For the same reason, ghc is not added to the environment when this
- option is set.
+ option is set, unless is
+ set to true.
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.
+ $HOME/.xmonad on the fly, set
+ to true and implement 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.
'';
@@ -116,6 +121,29 @@ in {
compiledConfig = printf "xmonad-%s-%s" arch os
+ myConfig = defaultConfig
+ { modMask = mod4Mask -- Use Super instead of Alt
+ , terminal = "urxvt" }
+ `additionalKeys`
+ [ ( (mod4Mask,xK_r), compileRestart True)
+ , ( (mod4Mask,xK_q), restart "xmonad" True ) ]
+
+ --------------------------------------------
+ {- version 0.17.0 -}
+ --------------------------------------------
+ -- compileRestart resume =
+ -- dirs <- io getDirectories
+ -- whenX (recompile dirs True) $
+ -- when resume writeStateToFile
+ -- *> catchIO
+ -- ( do
+ -- args <- getArgs
+ -- executeFile (cacheDir dirs > compiledConfig) False args Nothing
+ -- )
+ --
+ -- main = getDirectories >>= launch myConfig
+ --------------------------------------------
+
compileRestart resume =
whenX (recompile True) $
when resume writeStateToFile
@@ -126,12 +154,17 @@ in {
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 ) ]
+ main = launch myConfig
+ '';
+ };
+
+ enableConfiguredRecompile = mkOption {
+ default = false;
+ type = lib.types.bool;
+ description = ''
+ Enable recompilation even if is set to a
+ non-null value. This adds the necessary Haskell dependencies (GHC with
+ packages) to the xmonad binary's environment.
'';
};
diff --git a/nixos/tests/xmonad.nix b/nixos/tests/xmonad.nix
index 078cd2118107..a14d4b819eb6 100644
--- a/nixos/tests/xmonad.nix
+++ b/nixos/tests/xmonad.nix
@@ -1,4 +1,55 @@
-import ./make-test-python.nix ({ pkgs, ...} : {
+import ./make-test-python.nix ({ pkgs, ...}:
+
+let
+ mkConfig = name: keys: ''
+ import XMonad
+ import XMonad.Operations (restart)
+ import XMonad.Util.EZConfig
+ import XMonad.Util.SessionStart
+ 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 ((>))
+
+ main = launch $ def { startupHook = startup } `additionalKeysP` myKeys
+
+ startup = isSessionStart >>= \sessInit ->
+ spawn "touch /tmp/${name}"
+ >> if sessInit then setSessionStarted else spawn "xterm"
+
+ myKeys = [${builtins.concatStringsSep ", " keys}]
+
+ 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
+ )
+ '';
+
+ oldKeys =
+ [ ''("M-C-x", spawn "xterm")''
+ ''("M-q", restart "xmonad" True)''
+ ''("M-C-q", compileRestart True)''
+ ''("M-C-t", spawn "touch /tmp/somefile")'' # create somefile
+ ];
+
+ newKeys =
+ [ ''("M-C-x", spawn "xterm")''
+ ''("M-q", restart "xmonad" True)''
+ ''("M-C-q", compileRestart True)''
+ ''("M-C-r", spawn "rm /tmp/somefile")'' # delete somefile
+ ];
+
+ newConfig = pkgs.writeText "xmonad.hs" (mkConfig "newXMonad" newKeys);
+in {
name = "xmonad";
meta = with pkgs.lib.maintainers; {
maintainers = [ nequissimus ];
@@ -10,21 +61,10 @@ import ./make-test-python.nix ({ pkgs, ...} : {
services.xserver.displayManager.defaultSession = "none+xmonad";
services.xserver.windowManager.xmonad = {
enable = true;
+ enableConfiguredRecompile = true;
enableContribAndExtras = true;
extraPackages = with pkgs.haskellPackages; haskellPackages: [ xmobar ];
- config = ''
- import XMonad
- import XMonad.Operations (restart)
- import XMonad.Util.EZConfig
- import XMonad.Util.SessionStart
-
- main = launch $ def { startupHook = startup } `additionalKeysP` myKeys
-
- startup = isSessionStart >>= \sessInit ->
- if sessInit then setSessionStarted else spawn "xterm"
-
- myKeys = [ ("M-C-x", spawn "xterm"), ("M-q", restart "xmonad" True) ]
- '';
+ config = mkConfig "oldXMonad" oldKeys;
};
};
@@ -38,10 +78,40 @@ import ./make-test-python.nix ({ pkgs, ...} : {
machine.wait_for_window("${user.name}.*machine")
machine.sleep(1)
machine.screenshot("terminal1")
+ machine.succeed("rm /tmp/oldXMonad")
machine.send_key("alt-q")
- machine.sleep(3)
+ machine.wait_for_file("/tmp/oldXMonad")
machine.wait_for_window("${user.name}.*machine")
machine.sleep(1)
machine.screenshot("terminal2")
+
+ # /tmp/somefile should not exist yet
+ machine.fail("stat /tmp/somefile")
+
+ # original config has a keybinding that creates somefile
+ machine.send_key("alt-ctrl-t")
+ machine.sleep(1)
+ machine.succeed("stat /tmp/somefile")
+
+ # set up the new config
+ machine.succeed("mkdir -p ${user.home}/.xmonad")
+ machine.copy_from_host("${newConfig}", "${user.home}/.xmonad/xmonad.hs")
+
+ # recompile xmonad using the new config
+ machine.send_key("alt-ctrl-q")
+ machine.wait_for_file("/tmp/newXMonad")
+
+ # new config has a keybinding that deletes somefile
+ machine.send_key("alt-ctrl-r")
+ machine.sleep(1)
+ machine.fail("stat /tmp/somefile")
+
+ # restart with the old config, and confirm the old keybinding is back
+ machine.succeed("rm /tmp/oldXMonad")
+ machine.send_key("alt-q")
+ machine.wait_for_file("/tmp/oldXMonad")
+ machine.send_key("alt-ctrl-t")
+ machine.sleep(1)
+ machine.succeed("stat /tmp/somefile")
'';
})