Lid status determines eDP-1 display state

Hi. I’m trying to enable the eDP-1 (integrated laptop screen) when lid is open and disable it when lid is closed.
I tried using acpid lid event, but ran into insufficient privileges for xrandr execution. sudo with passed user and su didn’t help.

        services.acpid = {
            enable = true;
            lidEventCommands = ''
                mode=""
                echo "$1" >> /tmp/lid.log
                if echo "$1" | grep -iq "open"; then
                    echo "LID opened at $(date)" >> /tmp/lid.log
                    mode="--auto"
                elif echo "$1" | grep -iq "close"; then
                    echo "LID closed at $(date)" >> /tmp/lid.log
                    mode="--off"
                fi
                ${pkgs.su}/bin/su -p -c "xrandr --output eDP-1 $mode --pos 0x0 --output HDMI-2 --primary --rate 120 --pos 1920x0" >> /tmp/lid.log 2>&1
            '';
        };

i also tried using autorandr for this purpose, but couldn’t find solution, which allows display to be dynamically turned on/off.

Any thought is appreciated.

What does it mean to “enable” and “disable” the display? Do you mean turning the screen on and off? I’m assuming that this is probably what you meant.

If you’re using a compositor for Wayland, then you should use the accompanying program that can communicate with the compositor and tell it to do things. For example, I use Niri and I can use niri msg output eDP-1 off and niri msg output eDP-1 on to toggle the display. You should use whatever program your compositor comes with and control this functionality that way.

If you’re using a window manager with Xorg, then you can use something like xset (accessible at pkgs.xorg.xset for Nixpkgs) to control the monitor. Glancing at xset(1) provided by Arch Linux, it seems that the equivalent commands for turning the display off and on would be xset dpms off and xset dpms on respectively.

That’s kind of strange because from what I can see, acpid.service should be running as the root user by default. Could you provide more logs of this issue?

1 Like

Thank you for the reply.

By enabling and disabling the display i meant switching display off in such manner, that window manager, i3, in my case, stops registering it as active, thus preventing you from interacting with it in any (for example, sliding your mouse to the monitor you don’t see).
xset doesn’t solve the issue here, it lack functionality to disable the screen. xrandr, on the other hand, possesses the trait.
As for the logs:

  • with su
xset:  unable to open display ""
xset:  unable to open display ""
xset:  unable to open display ""
Can't open display
  • with/without sudo, with/without -u
Authorization required, but no authorization protocol specified

Can't open display :0

I use i3 X11. Unfortinately, i3msg doesn’t have functionality to turn off scrin directly, but it has functionality to monitor processes.
I could set up i3msg to monitor something like journalctl -f -u systemd-logind and call xrandr from there, but it’s not nixos style per-say.

I’ll try to setup i3msg listener and update the message.

Update:

i3msg isn’t the way to go. journalctl logs can be monitored with simple bash:

journalctl -S now -f -u systemd-logind | while read -r line; do
    if echo "$line" | grep -iq "Lid opened"; then
        echo "LID opened at $(date)"
        autorandr -l dualScreen
        #eww open bar --screen=1
    elif echo "$line" | grep -iq "Lid closed"; then
        echo "LID closed at $(date)"
        autorandr -l docked
        #eww close bar
    fi
done

I provide autorandr configuration for context:

{ lib, config, pkgs, ... }:
let
default = "docked";
laptopScreenEdid = "00ffffffffffff000daec91400000000081a0104951f11780228659759548e271e505400000001010101010101010101010101010101b43b804a71383440503c680035ad10000018000000fe004e3134304843412d4541420a20000000fe00434d4e0a202020202020202020000000fe004e3134304843412d4541420a20003e";
externalMonitorEdid = "00ffffffffffff0005e30324952100002e22010380351e782a9f05aa534fa3250d5054bfef00d1c0b3009500818081c0010101010101023a801871382d40582c45000f282100001e000000fd0030781e8c1c000a202020202020000000fc003234423331480a202020202020000000ff0041555952363941303038353937019a020321b14b101f05140413031202110167030c001000003c681a000001013078e6605980a070381440302035000f282100001e314480a070382740302035000f282100001a011d007251d01e206e2855000f282100001e8c0ad08a20e02d10103e96000f2821000018406b80a070381440302035000f282100001e0000000084";
in 
{
    options = {
        autorandr.laptopDocStation.enable = lib.mkEnableOption {
            description = "Enable autorandr with laptop config";
            default = false;
        };
    };

    config = lib.mkIf config.autorandr.laptopDocStation.enable {
        services.autorandr = {
            enable = true;
            matchEdid = true;
            ignoreLid = true;
            defaultTarget = "docked";

            profiles = {
                mobile = {
                    fingerprint = {
                        eDP-1 = laptopScreenEdid;
                    };

                    config = {
                        eDP-1 = {
                            enable = true;
                            primary = true;
                            mode = "1920x1080";
                            rate = "60.00";
                        };
                    };
                };

                docked = {
                    fingerprint = {
                        HDMI-2 = externalMonitorEdid;
                    };

                    config = {
                        eDP-1.enable = false;

                        HDMI-2 = {
                            enable = true;
                            primary = true;
                            mode = "1920x1080";
                            rate = "120.00";
                        };
                    };
                };

                dualScreen = {
                    fingerprint = {
                        eDP-1 = laptopScreenEdid;
                        HDMI-2 = externalMonitorEdid;
                    };

                    config = {
                        eDP-1 = {
                            enable = true;
                            mode = "1920x1080";
                            rate = "60.00";
                            position = "0x0";
                        };

                        HDMI-2 = {
                            enable = true;
                            primary = true;
                            mode = "1920x1080";
                            rate = "120.00";
                            position = "1920x0";
                        };
                    };
                };
            };
        };

        services.logind = lib.mkForce {
            lidSwitch = "ignore";
            lidSwitchDocked = "ignore";
            lidSwitchExternalPower = "ignore";
        };
    };
}

Update:

I transformed the script with autorandr, which workes fine for me, into acipd.lidEventCommands. It didn’t go well:

        services.acpid = {
            enable = true;
            lidEventCommands = ''
                if echo "$1" | grep -iq "open"; then
                    echo "LID opened at $(date)" >> /tmp/lid.log
                    ${pkgs.autorandr}/bin/autorandr -l dualScreen >> /tmp/lid.log 2>&1
                    # eww open bar --screen=1 >> /tmp/lid.log 2>&1
                elif echo "$1" | grep -iq "close"; then
                    echo "LID closed at $(date)" >> /tmp/lid.log
                    ${pkgs.autorandr}/bin/autorandr -l docked >> /tmp/lid.log 2>&1
                    # eww close bar >> /tmp/lid.log 2>&1
                fi
            '';
        };

Logs:

LID opened at вівторок, 16 грудня 2025 00:12:35 +0100
Can't open display 
Failed to run xrandr (line 627; /nix/store/igp430ar80v1ivmyr82fjqn0winj5vl3-autorandr-1.15/bin/.autorandr-wrapped)
LID closed at вівторок, 16 грудня 2025 00:12:41 +0100
Can't open display 
Failed to run xrandr (line 627; /nix/store/igp430ar80v1ivmyr82fjqn0winj5vl3-autorandr-1.15/bin/.autorandr-wrapped)

To me it seems like this command in lidEventCommands is run in detached state, which is not directly tied to the system. Something like nix-shell?

No, it runs as a service: nixpkgs/nixos/modules/services/hardware/acpid.nix at c8cfcd6ccd422e41cc631a0b73ed4d5a925c393d · NixOS/nixpkgs · GitHub

2 Likes