Opening i3 from home-manager automatically

Before switching to home-manager I used this xserver block in configuration.nix to automatically open my graphical session (I use full disk encryption, thus, I don’t want to enter password twice at boot) :

services.xserver = {
  enable = true;
  desktopManager.default = "none";
  windowManager.default = "i3";
  windowManager.i3 = {
    enable = true;
    package = pkgs.i3-gaps;
  };
  layout = "us";
  xkbVariant = "intl";
  libinput.enable = true;
  displayManager.auto = { enable = true; user = "elyhaka"; };
};

Now, in my home.nix I have :

xsession.enable = true;
xsession.windowManager.i3 = {
  enable = true;
  package = pkgs.i3-gaps;
}

I see that home-manager has created a .xsession script inside my home directory that can be used for a xorg initialization.

My question is, how can I obtain the same behavior? That is:

  1. I want to automatically open my i3 session
  2. I do not want to type a password at boot, but,
  3. If my i3 session is closed I want to be brought back to lightdm or whatever displayManager.

After a really huge amount of tests, crashes and retries, I figured out something that works (with all the previous points checked).
I’m not really fan of the way it is expressed in the configuration.nix file, and it give kind of a warning at nixos-rebuild time. I will work on a PR to give a cleaner way of expression such scenarios. For now, here is a working solution :

    xserver = {
      enable = true;
      libinput.enable = true;
      displayManager.lightdm.enable = true;
      displayManager.lightdm.autoLogin = { enable = true; user = "elyhaka"; };
      desktopManager.default = "xsession";
      displayManager.session = [
         {
           manage = "desktop";
           name = "xsession";
           start = ''exec $HOME/.xsession'';
         }
      ];
    };

I believe the same hack could be used to launch wayland session (maybe sway ?). I would need require some test, though.

I hope it will help somebody else, and if somebody knows a better way of doing it, please let me know :slight_smile:

Bellow works for me

     xserver = {
        enable = true;
  #      autorun = false;
        videoDrivers = [ "nvidia" ];
  
        layout = "us";
        xkbOptions = "eurosign:e";
        libinput = {
          enable = true;
          disableWhileTyping = true;
          naturalScrolling = true;
          additionalOptions = ''
            Option "PalmDetection" "True"
          '';
        };
        desktopManager = {
          default = "none";
          xterm.enable = false;
        };
        displayManager = {
          lightdm = {
            enable = true;
            greeter.enable = false;
            autoLogin.enable = true;
            autoLogin.user = "mudrii";
          };
        };
  
        windowManager = {
          default = "i3";
          i3.enable = true;
          i3.package = pkgs.i3-gaps;
          i3.extraPackages = with pkgs; [
            dmenu #application launcher most people use
            i3lock #default i3 screen locker
            i3status-rust
            i3-gaps
            i3lock-fancy
            rofi
...
...
...

On this subject, and especially if you are configuring a default session as @Elyhaka suggests, nixos/x11: provide selected session to custom session was recently merged, to enable the user to override the session to launch in LightDM while still doing the things you asked for.

It however needs a very simple change in home-manager (not submitted yet), so that the generated .xsession falls back to the NixOS-provided session script if the user did not select the xsession session.

Also, the current behaviour is to always execute the user’s .xsession script, whatever the choice of the user in the DM. So the value of start in @Elyhaka’s example will actually never be used (but .xsession will still be launched, just through another code path). Because of this, I suggest setting start to "". This is actually why I submitted the linked PR : as the .xsession script is always executed, we need it to have access to the session script that would have been executed instead, if we want to allow respecting the user choice. Otherwise, displayManager.session is totally useless as soon as $USER/.xsession exists.

Sorry for piggy-backing on your thread, but I felt my experiences on the subject could be interesting. I’m also interested in comments in how to integrate this (plus allowing the user to select a session in the DM) in home-manager. It would probably require a “default” session as in the above post, with special support for this session in home-manager. I’m already using such a patch on my system, bit haven’t submitted it yet because I’m not sure it’s the best way.

Thank you for your very complete answer :slight_smile:.

Strangely, while I was testing, I’ve made a typo in the displayManager.session.start and my session did not opened, so I have the feeling that what’s written in it was taken into account in my case. (btw, I’m running on unstable maybe something changed since ?).

I believe that if the .xsession file is created by home-manager, then the only needed thing is to provide a xorg-session desktop file to simply execute it. It would be clean, and working as expected. This is almost what’s doing the session I proposed as a solution. It just requires adding a helper to create it (and check it on evaluation time). For now have the following message in my nixos-rebuild triggers, which is a warning I simply ignore :

trace: Default desktop manager (xsession) not found at evaluation time.
These are the known valid session names:
  services.xserver.desktopManager.default = "none";

Strangely, while I was testing, I’ve made a typo in the displayManager.session.start and my session did not opened, so I have the feeling that what’s written in it was taken into account in my case. (btw, I’m running on unstable maybe something changed since ?).

Well that is weird. I’ve checked, and both on master and release-19.09 the display manager’s session script contains (because of the exec, if the test succeeds this will be the last command run by the script) :

  # Allow the user to setup a custom session type.
  if test -x ~/.xsession; then
      eval exec ~/.xsession "$@"
  fi

If the test fails, this script goes on to execute the “selected session script”, which is the session script corresponding to the session selected by the user in the DM, and which contains exec $HOME/.xsession.

I believe that if the .xsession file is created by home-manager, then the only needed thing is to provide a xorg-session desktop file to simply execute it. It would be clean, and working as expected.

Well it is similar to what I’m doing (with a custom session as in your example, and a patch to home-manager to allow me to override the configured session):

  1. home-manager creates the ~/.xsession
  2. on login, LightDM calls the system-level session script
  3. this script finds ~/.xsession, and executes it, whatever the session selected in LightDM
  4. /.xsession runs the WM configured in home.nix if the selected session was xsession, otherwise it runs the script corresponding to the selected session.

(now it should be clear why I set start to "" : it should never be executed, as it’s a fake session that defers to .Xsession).

I don’t understand what you mean by:

It just requires adding a helper to create it (and check it on evaluation time).

In order to create what ? The session in xserver.displayManager.session ?

I’m already running the setup you described, but I did not need such a helper. Just a few lines in the system config to configure the special session for xsession, and the two patches in NixOS+nixpkgs to allow overriding the session at runtime.

Well that is weird. I’ve checked, and both on master and release-19.09 the display manager’s session script contains (because of the exec, if the test succeeds this will be the last command run by the script) :

  # Allow the user to setup a custom session type.
  if test -x ~/.xsession; then
      eval exec ~/.xsession "$@"
  fi

My bad ! You were right here, I set the value to "" and it worked as intended.

(now it should be clear why I set start to "" : it should never be executed, as it’s a fake session that defers to .Xsession ).

Yes I do see it now, it was early in the morning on my way to work, I missed a thing :wink:

I’m already running the setup you described, but I did not need such a helper. Just a few lines in the system config to configure the special session for xsession, and the two patches in NixOS+nixpkgs to allow overriding the session at runtime.

Yes, indeed, I ended up with this setup too.

Thank you for your help :slight_smile:

An alternative is to have something like

services.xserver.desktopManager.session = [
  {
    name = "home-manager";
    start = ''
      ${pkgs.runtimeShell} $HOME/.hm-xsession &
      waitPID=$!
    '';
  }
];

in your system configuration and

xsession.scriptPath = ".hm-xsession";

in your HM configuration.

10 Likes

This works really well, and also allows overriding the session from the DM, without any patches. I don’t know how I missed that it could be done this way. I’ll try to add it to the docs, as the current situation may confuse some users (that enabling xsession in HM breaks desktopManager.session unless scriptPath is changed).

Like @pstch said, it works really well. Thank you @rycee !

For reference, I am using a fake session in the system configuration:

  services.xserver.enable = true;
  services.xserver.displayManager.lightdm.enable = true;
  services.xserver.displayManager.autoLogin.enable = true;
  services.xserver.displayManager.autoLogin.user = "dominik";
  # Use a fake session. The actual session is managed by Home Manager.
  services.xserver.displayManager.defaultSession = "none+fake";
  services.xserver.displayManager.session =
    let fakeSession = { manage = "window";
                        name = "fake";
                        start = "";
                      };
    in [ fakeSession ];

And let Home Manager take care of the X session.

3 Likes

Hi, Is this the best practice until now? not sure why it is not working for me?

It is, though it depends on your display manager. Maybe open a new post and detail what “not working for me” means so we can help debug :slight_smile:

I have Home Manager’s xsession enabled and managing my window manager setup, and I have the following in /etc/nixos/configuration.nix:

{ pkgs, ... }:

{
  services.xserver = {
    # Log in automatically
    displayManager.autoLogin.user = "zeorin";
    # We need to create at least one session for auto login to work
    desktopManager.session = [
      {
        name = "xsession";
        start = ''
          ${pkgs.runtimeShell} $HOME/.xsession &
          waitPID=$!
        '';
      }
    ];
  };
}

which seems to work just fine for me. No need to change Home Manager’s xsession.scriptPath this way.

1 Like

I should note I discovered that I was unable to unlock keyrings after setting that up, but I did find a fix for it:

{ pkgs, lib, ... }:

{
  services.xserver.displayManager.sessionCommands = ''
    ${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
  '';
}

Hi @Elyhaka ! I’m new to NixOS and Home Manager and would like to use i3wm and X server with Home Manager by configuring the home.nix file. Do you have your dot files on GitHub so I can see how you solved this?"