Xorg on non-NixOS

Hi everyone,

I am trying to run Xorg installed via nix on Ubuntu. Before I dive
into details, maybe someone has experience in running Xorg on Ubuntu?
A link to working environment configuration would be great! I have
seen various configurations for NixOS, but hard to translate them on
non-NixOS.

The machine I am working on is ThinkPad T14s, I have already installed
Xorg with Xinit and managed to fix all obvious errors in Xorg logs
(mostly related to OpenGL issues). But whenever I startx, keyboard
and mouse stops working, so it’s pretty much unusable.

I have installed multi-user nix on a fresh installation Ubuntu Server
21.04. Then I’ve installed nixUnstable (because I manage my
environment with home-manager and flakes).

My flakes.nix is straight-forward:

{
  description = "d12frosted systems configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
    home.url = "github:nix-community/home-manager";
    emacs-overlay.url = "github:nix-community/emacs-overlay";

    # Follows
    home.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, home, emacs-overlay }:
    let
      overlays = [
        emacs-overlay.overlay
        (import ./nix/overlays)
      ];
    in {
      homeConfigurations = {
        d12frosted = home.lib.homeManagerConfiguration {
          configuration = { pkgs, lib, config, ... }: {
            imports = [ ./nix/home.nix ];
            nixpkgs.config.allowUnfree = true;
            nixpkgs.overlays = overlays;
          };
          system = "x86_64-linux";
          homeDirectory = "/home/d12frosted";
          username = "d12frosted";
        };
      };
    };
}

And nix/home.nix:

let
  # some irrelevant constants
in {
  home = {
    packages = pkgs.callPackage ./packages.nix {};

    # ... many irrelevant configurations (xdg, git, gpg, etc.)

    xsession = {
      enable = true;
      windowManager = {
        xmonad = {
          enable = true;
          enableContribAndExtras = true;
        };
      };
    };
  };
}

My packages look like this:

{ pkgs, lib, stdenv, ... }:

with pkgs;
let exe = haskell.lib.justStaticExecutables;
in [
  # common utilities
] ++ lib.optionals stdenv.isDarwin [
  # mac-only packages
] ++ lib.optionals stdenv.isLinux [
  xorg.xauth
  xorg.xclock
  # it feels like many of them are not needed, tried selecting only one of them
  xorg.xf86inputevdev
  # xorg.xf86inputlibinput # tried enabling
  xorg.xf86inputsynaptics
  # xorg.xf86videoati # tried enabling
  # xorg.xf86videofbdev # tried enablig
  xorg.xf86videointel
  # xorg.xf86videonouveau # tried enabling
  # xorg.xf86videovesa # tried enabling
  xorg.xinit
  xorg.xkill
  xorg.xorgserver
  xorg.xrandr
  xorg.xrdb
  xorg.xsetroot
  xterm
]

Now, I build/assemble it using the following steps:

$ cd $XDG_CONFIG_HOME
$ nix build \
  --experimental-features 'nix-command flakes' \
  ./#homeConfigurations.d12frosted.activationPackage
$ ./result/activate switch

All good. I tried calling startx without any custom xinitrc and I
saw 3 (I suspect) xterm windows and could not select any of them nor
type anywhere, my mouse cursor was frozen. Had to restart. By checking
Xorg logs at ~/.local/share/xorg/Xorg.0.log I figured that it
struggles to load some OpenGL libraries, so I found
GitHub - guibou/nixGL: A wrapper tool for nix OpenGL application. After I installed nixGLDefault, I
tried to start my x-es like this:

nixGL startx

I’ve got the same state, 3 xterm windows and locked input. I checked
logs again, and the only errors I see now are:

(EE) Failed to load module "intel" (module does not exist, 0)
...
(EE) Failed to load module "fbdev" (module does not exist, 0)
...
(EE) Failed to load module "vesa" (module does not exist, 0)
...
(EE) modset(0): eglGetDisplay() failed
(EE) modset(0): glamor initialization failed

Now I think that I simply missing something obvious. I am new to all
this stuff, so apologies if I missed something, just let me know if
you need more information. And thank you in for reading this long
post.

Any help would be appreciated!

You’ll want to add

  nativeBuildInputs = [ addOpenGLRunpath ];

  postFixUp = ''
    addOpenGLRunpath $out/bin/...
  '';

This will add /run/opengl-driver/lib to the RPATH of any elf. May also need to be applied to any library which also does something similar.

Hey @jonringer

Thanks for your answer. As far as I understand, nativeBuildInputs is part of package declaration, right? According to Appendix A. Configuration Options there is no such option in home mamaber. So could you please elaborate a little bit more?

I’ve been using startx to use xmonad instead of Gnome on Ubuntu for a few days now. The machine I’m using is an HP Elitebook x360 1040 G7.

The issues I encountered were different than yours, but the config I ended up with may be useful to compare.

(EE) open /dev/fb0: Permission denied

I first got this error, which I tried to work around with this overlay:

self: super: {
  xorg = super.xorg // {
    xorgserver = super.xorg.xorgserver.overrideAttrs (old: {
      configureFlags = old.configureFlags ++ [ "--enable-suid-wrapper" ];
      postInstall = old.postInstall + ''
        mkdir -p $out/etc/X11
        echo "needs_root_rights=yes" >> $out/etc/X11/Xwrapper.config
      '';
    });
  };
}

Which seemed to work at first, but then it didn’t, and I eventually added my user to the video group with:

sudo usermod -a -G video $USER

Incorporating some pieces from “Using X without a Display Manager” from the NixOS wiki, I got startx to show xterm windows and a clock, but the screen got only repainted when I moved the mouse cursor. After reading that the xf86-video-intel driver has been mostly superseded by the modesetting driver, I removed xorg.xf86videointel from the list of packages to install, and that fixed the repaint issue.

My config now looks like:

home.nix:

{ config, pkgs, ... }:

{
  imports = [
    ./modules/xserver.nix
  ];

  xsession = {
    enable = true;
    windowManager.xmonad.enable = true;
    windowManager.xmonad.enableContribAndExtras = true;
  };

  programs.xserver.enable = true;
  programs.xserver.debug = false;

  # ...
}

modules/xserver.nix:

{ config, lib, pkgs, ... }:
with lib;
let
  cfg = config.programs.xserver;
in {
  options = {
    programs.xserver = {
      enable = mkEnableOption "xserver";

      debug = mkEnableOption "log errors";

      errfilePath = mkOption {
        type = types.str;
        default = ".xsession-errors";
        description = ''
          Path, relative to <envar>HOME</envar>, for X session log/error.
        '';
      };

    };
  };
  config = mkIf cfg.enable {
    home.file.".xserverrc".source = pkgs.writeShellScript "xserverrc" ''
      exec ${pkgs.xorg.xorgserver}/bin/X -configdir ${config.home.profileDirectory}/share/X11/xorg.conf.d "$@"
    '';

    home.file.".xinitrc".source = pkgs.writeShellScript "xinitrc" (''
      set -e
      ''
      + (optionalString cfg.debug ''
      exec >>"${config.home.homeDirectory}/${cfg.errfilePath}" 2>&1
      '')
      +
      ''
      set +e
      . "${config.home.homeDirectory}/${config.xsession.scriptPath}"
      set -e

      exit 0
    '');

    home.sessionVariables.LIBGL_DRIVERS_PATH = "${pkgs.mesa_drivers}/lib/dri/";

    home.packages = with pkgs; [
      xorg.xorgserver
      xorg.xf86inputlibinput
      xorg.xinit
      xorg.xkill
      xorg.xrandr
      xorg.xrdb
      xorg.xsetroot
      xterm
      (
        pkgs.writeTextFile {
          name = "xorg-conf-module-paths.conf";
          destination = "/share/X11/xorg.conf.d/00-module-paths.conf";
          text = ''
          Section "Files"
            ModulePath "${config.home.profileDirectory}/lib/xorg/modules/"
            FontPath "${config.home.profileDirectory}/share/fonts/"
            FontPath "${config.home.profileDirectory}/lib/X11/fonts/"
          EndSection
          '';
        }
      )
    ];
  };
}

$HOME/.xinitrc written by the config above sources $HOME/.xsession instead of launching xterm and xclock, which I believe is the behavior of the default xinitrc.

I also installed nixGL but ended up not using it. Setting LIBGL_DRIVERS_PATH took care of an error that was about loading drivers. (Regrettably, I didn’t write down the exact error message.)

I get the same errors with this setup, but apparently the last two modset errors are not fatal. The first three are expected, as those modules aren’t installed in my environment.