Help with setting up a different desktop environment / window manager

Hey, folks! I’m trying to move away from EXWM and onto a different setup on NixOS, but can’t seem to get it to work. There’s a number of different factors here, and there may also well be some understandings going on, so I’m hoping I could get some help clearing it up.

In short

The short version of my question is:

How do I successfully start a graphical session that isn’t run by EXWM? I’ve tried a number of different combinations (by setting xserver.desktopManager / windowManager to gnome, lightdm, pantheon), but nothing ever happens after logging in: it just stays at the login background image.

My goal is: to have an experience that isn’t centered around Emacs running everything. I want a tiling window manager and probably some kind of status bar as a minimum, but don’t really know what past that.

It is also likely that I’m misunderstanding a lot of things here. I’ve run EXWM for 2–3 years now, but haven’t really ever used anything else, so I don’t know when you do and don’t need a desktop manager, for instance. So it’s quite possible that I’m not asking the right questions, but that’s because I don’t know what those questions are.

The longer version

As mentioned above: I’m trying to migrate off EXWM (for a variety of reasons, but that’s for a different time), but haven’t been able to start any other kinds of sessions from the login screen. I tried with a couple different configuration options as mentioned in the manual / configuration options. I tried enabling desktopManager.gnome, desktopManager.pantheon, but don’t really know what I need. When at the login screens, the sessions either fail to start or let me log in, but then get stuck after removing the login dialog (using lightdm and the default).

It is possible that home manager is to blame for some of this too, as I use it to initialize EXWM. I tried changing it a bit, but maybe not enough.

I also thought about using Wayland, but couldn’t find any documentation on how you go about doing that. But I think using Sway would be out of the question anyway, though, as I’ve got an nvidia gpu.


When trying to change this settings, is there a way to check whether they work without logging out and back in? I’ve found that sometimes rebooting is necessary for the changes to work as expected. This makes it very slow and tedious to check. Plus, the added tension of maybe not being able to start a graphical session isn’t great :see_no_evil:

Ideally: could I start an extra graphical session somehow (with the new settings) and flip between them? Maybe something using build-vm?

Current setup

In my configuration.nix file, I’ve got this setup:

  services.xserver = {
    enable = true;

    # ... more unrelated config

    windowManager.exwm = {
      enable = true;
      enableDefaultConfig = false;
      extraPackages = epkgs: [

    displayManager.lightdm = {
      enable = true;
      greeters.enso = {
        enable = true;
        blur = true;

    ## this doesn't work 👇
    # desktopManager.gnome.enable = true;
    # windowManager.i3.enable = true;

    displayManager.defaultSession = "none+exwm";

Home manager

  xsession = {
    enable = true;
    ## this didn't seem to make a difference 👇
    # windowManager.command = ''test -n "$1" && eval "$@"'';
    windowManager.command = ''
      ${config.programs.emacs.package}/bin/emacs -l "${exwm-load-script}"
    initExtra = ''
      xset r rate 200 100

I tried commenting out the windowManager.command I’ve got there now, but that didn’t seem to change anything. I’ll try removing it / changing it after posting. Maybe setting windowManager.i3.enable or something would work instead?

Final comments

Thanks for getting this far and for helping me out. I’m very happy to provide more info if there’s anything you need; I just don’t know what that would be at the moment.

I also got some help in the matrix chatroom yesterday, so thanks to everyone who helped me out there. However, I wasn’t able to make it work in the end, and I think a forum post may be better suited for this.

As for the WM, I’m using instantWM to great satisfaction, since it provides a tiling WM but also tries to add consistent UX features that are normally provided by the DE.

AFAICS (I haven’t changed it in a long time, so I’m not 100% sure I caught everything relevant) the crucial parts of the config for it are here… It’s for nixOS running on a HP Spectre x360 4k touch screen, so some of it is specific to HiDPI and laptops. Notably instantWM uses a few config utilities from xfcefor power management and toolkit-theming.

Below just a dump of some parts of my configuration.nix (I have mostly factored this in imported files, so you’ll see some attributes scattered, you could join them if you wish). There’s a lot of things there that don’t actually matter to the WM/DE per-se, but you may recognize them :wink:

  nixpkgs.config.packageOverrides = pkgs: rec {
    nur = import (builtins.fetchTarball "") {
      inherit pkgs;

  hardware.opengl.enable = true;
  # X server settings
  services.xserver = {
    enable = true;
    autorun = true;
    exportConfiguration = true;
    # input
    layout = "us";
    xkbModel = "thinkpad";
    xkbVariant = "altgr-intl";
    libinput.enable = true;  # Enable touchpad support.
  services.xserver.displayManager = {
    defaultSession = "none+instantwm";
    #startx.enable = true;
    gdm.enable = false;
    sddm.enable = false;
    # sessionCommands = ''
    # ${pkgs.xorg.xrdb}/bin/xrdb -merge <<EOF
    #       Xft.dpi: 220
    #       Xcursor.theme: Adwaita
    #       Xcursor.size: 64
    #   EOF
    # '';
  services.xserver.desktopManager = {
    gnome.enable = false;
    plasma5.enable = false;
    xterm.enable = false;
  services.xserver.windowManager = {
    session = pkgs.lib.singleton {
      name = "instantwm";
      start = ''
        startinstantos &

  # X server related programs and services
  programs.slock.enable = false; # use lightlocker instead
  services.clipmenu.enable = true;
  # services.dconf.enable = true;

  services.xserver = {
    dpi = 220;
    xrandrHeads = [
      "Monitor[0]" {
        output = "eDP-1";
        primary = true;
        monitorConfig = ''
          DisplaySize   298 165
          Option "DPI"  "220 x 220"
    displayManager.lightdm.greeters.gtk = { = "Sweet-mars";
      cursorTheme = {
        package = pkgs.bibata-cursors;
        name = "Bibata_Amber";
        size = 32;

  services = {
    gnome.gnome-keyring.enable = true;
    # gnome.gnome-settings-daemon.enable = true;
    autorandr.enable = true;
    blueman.enable = true;
    ofono.enable = true;
    logind.lidSwitch = "suspend";
    upower.enable = true;
    flatpak.enable = true;
    avahi.enable = true;

xdg.portal.enable = true;

  security = { = {
      login.enableGnomeKeyring = true;
      sshd.enableGnomeKeyring = true;
      lightdm.enableGnomeKeyring = true;
    polkit = {
      enable = true;
      extraConfig = ''
        polkit.addRule(function(action, subject) {
          if ( == "org.xfce.power.backlight-helper" &&
            subject.isInGroup("users")) {
            return polkit.Result.YES;

  environment.systemPackages = with pkgs; [
    # unstable.pulseaudioFull
    htop screen tree file tmux lm_sensors dmidecode
    fasd fzf direnv
    wget curl inetutils dnsutils nmap openssl mkpasswd
    gitAndTools.git git-lfs
    nix-prefetch-scripts nix-update nixpkgs-review cachix
    papirus-icon-theme lxappearance

  nixpkgs.config = {
    pulseaudio = true;
    enableQt = true;
    allowBroken = true;
    allowUnfree = true; 
    joypixels.acceptLicense = true; # needed for terminal

  fonts = {
    enableDefaultFonts = true;
    fontconfig = {
      enable = true;
      dpi = 220;
      hinting.enable = false; # false for HiDPI

    fonts = with pkgs; [ 
        carlito  # like calibri
        (nerdfonts.override { fonts = [ "FiraCode" "FiraMono" ]; })

  programs = {
    seahorse.enable = true;
    qt5ct.enable = true;
    gnupg.agent.enable = true;
    gnupg.agent.pinentryFlavor = "gtk2"; # use gpg-agent.conf
    # gnupg.package = pkgs.gnome.seahorse;

  environment.variables = { 
    GDK_SCALE = "2.0";
    GDK_DPI_SCALE = "0.5";
    QT_SCALE_FACTOR = "1.0";
    _JAVA_OPTIONS = "-Dsun.java2d.uiScale=1.0"; 

For polkit to work without prompting for a password on every automatic brightness adjustment, I had to add a 30-line config file, I’ll post it if you need it (to not clutter this too much).

I’m using home-manager, and in my user config I have added

home.packages = with pkgs; [
    # X-utils
    autorandr arandr xpra touchegg pavucontrol glxinfo 
    xfce.xfce4-power-manager xfce.xfconf fusuma xdotool

since I seemed to have some permission issues related to the xfce stuff for power management, not sure if it could be moved to the global config after the whole polkit fix…

In all fairness, I’m still using a custom ~/.config/instantos/ to make gpg-agent and some DE stuff work well, this should be moved to home-manager ideally I guess… Just to indicate that the “100% UX” I appear to be close to now is not entirely covered by above configs (but relies on some hacks too), feel free to ask for more info on that…

That’s great; thanks! :grinning_face_with_smiling_eyes: Finally got around to having a little look at this yesterday. I think it’s too early for me to pick a specific WM, so anything will do for now.

Having a little look at your config made me dig a little deeper and I definitely got a bit further:

By setting xsession.windowManager.i3.enable = true; in my Home Manager config, I at least got a little further. I tried to use it with Gnome (desktopManager.gnome.enable = true;), but it didn’t go exactly as expected.

After selecting the gnome session at the login screen, The whole screen turns grey and what I can only assume is i3’s status bar appears at the bottom of the screen. This is a step up, but there’s no desktop environment and I can’t seem to do anything at all.

Are there any other dependencies that I need to activate or something? When selecting a session on the login screen, is there any reason why it wouldn’t start as expected? Are there any logs anywhere or some other way I can troubleshoot this?

I’m not at all sure, but it “feels” like with desktopManager.gnome.enable = true; you’re basically requesting a gnome desktop as a complete DE, which already includes its own WM. So it may collide with separately enabling another xsession.windowManager (which should ideally be detected by the nix modules and lead to a warning I suppose.)

On a side note, I generally had bad experiences enabling parts of gnome without actually using a gnome DE, possibly if you’re using an independent WM you may be better off using parts of a “more modular” DE, such as the above example with xfce, but YMMV of course.

Generally it appears to be necessary (which is logical) to make sure that your WM starts with additional env vars (for such things like e.g. gnome-keyring-agent and DE related utils) set in the environment that starts the WM (i.e. its start script) which requires tweaking of said script. Eventually this may be best done also through home-manager but you might have it easier experimenting/debugging if you just change the files directly.

with desktopManager.gnome.enable = true; you’re basically requesting a gnome desktop as a complete DE, which already includes its own WM

Oh, okay, I can see that. Yeah, I’ll try with xfce or just gdm(?), then. I thought using mixing and matching DEs and WMs was pretty unproblematic; is that not the case?

Again: thanks for the input! I’ll give this a go and then see what happens.


@ppenguin As you theorized, it does seem that Gnome not starting was caused by me trying to start i3 in gnome. If I don’t do that, it starts as expected. xfce did not seem to start with i3 either. (Haven’t tested without yet. Doesn’t start without i3 either :man_shrugging: )

So how do you use a tiling window manager with a DE? Can you, or are they mutually exclusive somehow? Maybe there’s an easier way about this? Maybe you don’t need both? I was under the impression that a DE (or DM?) will take care of managing your session, launch new apps, display notifications, etc, and that a WM only positions windows. Do WMs also handle all the extra stuff?

As always: thanks! :pray:

AFAIK you shouldn’t be trying to start any DE in combination with a separate WM, but only selected components of a DE. In the case of gnome or xfce that means you’d be installing some package you want for e.g. theme management and such, and define necessary env vars/start DE-services for those from the (manually customized) session start script before starting the WM (with & as necessary so they’d background so your WM can be started).

Just in case, I have all DE disabled like so:

  services.xserver.desktopManager = {
    gnome.enable = false;
    plasma5.enable = false;
    xterm.enable = false;

BTW gdm you mentioned earlier is just the display manager (gdm is gnome's), which gives you a graphical login and starts the desktop session through a session definition file, which in turn executes a start script starting your WM and DE-components. A “light” variation for this is lightdm, which AFAIK provides all functionality you need without possible “bloat” from specific DE’s.

Ah, okay; thanks! I’ve probably misunderstood some of the fundamentals around DEs and WMs, then. Thanks for clarifying!

If I read your reply correctly, then, I should be able to use lightdm and combine it with something like i3 or another WM to get what I need. I’ll give that a go! :grinning_face_with_smiling_eyes:

Would you happen to have any resources where I can read up on this, by the way? Maybe I could visit the arch wiki or something, but that may be too specific. I think something more higher level might be better at first. I’ll have a look anyway. Thanks!

While the Arch wiki is quite specific, I still find it one of the best resources for real information on how the internals of such things work, so it’s absolutely a valuable source. Of course you need to “get a feeling” for which parts are more generic and which ones more arch-specific, but that comes in time…

Especially for things like where to tweak e.g. DPI settings and x-session specifics, use-cases on the arch wiki will give you a lot of info what files are used in what stage of e.g. starting an x-session with e.g. i3.

In the end the solution will then likely be to do these tweaks in the respective settings files at first, and possibly move their contents to home-manager, either as a raw “config-writing-expression” or using a certain hm-module if supported. (This last part I also haven’t yet done…)

1 Like

Hey! Sorry for disappearing for a while, but I finally managed to solve my issue and switch to i3. The solution I went with in the end was using XFCE as a DE and i3 as a WM. I could probably simplify that, but it seems to work well for now.

While it works, though, there is still one thing I haven’t quite figured out. Right now I have both of these:

in my configuration.nix:

    windowManager.i3 = {
      enable = true;
      package = pkgs.i3-gaps;
      # ... more config

and in my home.nix:

    windowManager.i3 = {
      enable = true;
      package = pkgs.i3-gaps;
      # ... more config

I’ve got a feeling I don’t need the entry in configuration.nix anymore, but haven’t dared to take it out for fear of things not working anymore :see_no_evil: Do you know whether it’s safe to remove it? I’ll probably try it out and find out pretty soon :sweat_smile:

Anyway, thank you so much for all your input; it’s really helped me along!

The way I’m looking at it: everything you want to be user independent (or which is needed to start the base system before you log in) on the machine you’re setting up goes in configuration.nix, user specific config in home.nix.

If you setup any machine as a (potential) multi-user machine (which IMHO anyone should, except for “embedded” systems), that means everything up to including the xsession definition would go in configuration, meaning services.xserver.*.
Since DE settings are personal, but it’s availability may be partly needed to define the xsession, that’s where the split would be, i.e. personal settings in home.nix but installation in configuration.nix (technically your user should be able to login to the desktop-session before installing/refreshing his HM config.)

That appears to be working for me. (You might argue things like DPI settings are as much hardware-dependent as user-preference, I have them defined globally, not sure how it plays out if you later override them in home.nix, should be possible through the passed-in config.?)

Yeah, that’s totally fair. I’ve only ever had one user, so it’s all a bit blurry, to be honest :sweat_smile:

Maybe I should go and read through the home manager docs again :man_shrugging:

But thanks! I’ll look into it at some point :relaxed: