Script does not behave properly when called by acpi and udev events

acpiudevxrandr

I have the following files in /etc/acpi/events and /etc/udev/rules.d.

  • /etc/acpi/events/lidclose

    # Pass all events to our one handler script
    event=button/lid
    action=/etc/acpi/monitors.sh
    
  • /etc/udev/rules.d/80-monitor.rules

    # change monitor settings when monitor is plugged in or o$
    ACTION=="change", SUBSYSTEM=="drm", HOTPLUG=="1", RUN+="/etc/acpi/monitors.sh"
    
  • Now, the (executable and owned by root) /etc/acpi/monitors.sh

    #!/bin/sh
    
    # default monitor is LVDS1
    STATE=internal
    INTERNAL=LVDS1
    EXTERNAL=HDMI3
    
    # functions to switch from LVDS1 to VGA and vice versa
    function internal {
        echo "Switching to internal"
        xrandr --output $EXTERNAL --off --output $INTERNAL --auto
        STATE=internal
    }
    function external {
        echo "Switching to external"
        xrandr --output $EXTERNAL --auto --output $INTERNAL --off
        STATE=external
    }
    function both {
        echo "Switching to both"
        xrandr --output $EXTERNAL --auto --right-of $INTERNAL --output $INTERNAL --auto --primary
        STATE=both
    }
    
    # functions to check if VGA is connected and in use
    function externalConnected {
        ! xrandr | grep "^$EXTERNAL" | grep disconnected >/dev/null
    }
    function lidOpen {
        ! cat /proc/acpi/button/lid/LID/state | grep closed >/dev/null
    }
    
    # actual script
    if ! [ $STATE == "both" ] && externalConnected && lidOpen
    then
        both
    fi
    
    if ! [ $STATE == "external" ] && externalConnected && ! lidOpen
    then
        external
    fi
    
    if ! [ $STATE == "internal" ] && ! externalConnected && lidOpen
    then
        internal
    fi
    

Now, I tested the script both as root and as my user, and it worked like a charm. I also put some test output via echo bla > /home/me/test in it, and when called by udev and acpid it generated the output, so it is executed. The only thing is, that nothing happens with xrandr.

What am I missing? How could I log the output of the script to find errors?

Best Answer

With the help of the guys who commented on my question, I figured out what was wrong and fixed it in the script.

Here now the updated routines how to get automatic screen switching with your laptop to work. You need acpid, kms and udev.

Create the following rules for acpi and udev

/etc/acpi/events/lidclose

# Pass all events to our one handler script
event=button/lid
action=/etc/acpi/monitors.sh

/etc/udev/rules.d/80-monitor.rules

# change monitor settings when monitor is plugged in or o$
ACTION=="change", SUBSYSTEM=="drm", HOTPLUG=="1", RUN+="/etc/acpi/monitors.sh"

now create /etc/acpi/monitors.sh

#!/bin/sh

# specify the monitors to use
INTERNAL=LVDS1
EXTERNAL=HDMI3
USERNAME=oli

# set some variables needed to control the x server
export XAUTHORITY=/home/$USERNAME/.Xauthority
export DISPLAY=:0

# functions to switch from internal screen to external screen and vice versa or to use both screens together
function internal {
    echo "Switching to internal" >> /var/log/monitors.log
    xrandr --verbose --output $EXTERNAL --off --output $INTERNAL --auto >> /var/log/monitors.log 2>&1
}
function external {
    echo "Switching to external" >> /var/log/monitors.log
    xrandr --verbose --output $EXTERNAL --auto --output $INTERNAL --off >> /var/log/monitors.log 2>&1
}
function both {
    echo "Switching to both" >> /var/log/monitors.log
    xrandr --verbose --output $EXTERNAL --auto --right-of $INTERNAL --output $INTERNAL --auto --primary >> /var/log/monitors.log 2>&1
}

# functions to check if external monitor is connected and in use
function externalConnected {
    ! xrandr | grep "^$EXTERNAL" | grep disconnected >/dev/null
}
function lidOpen {
    ! cat /proc/acpi/button/lid/LID/state | grep closed >/dev/null
}

# actual script
if externalConnected && lidOpen
then
    both
fi

if externalConnected && ! lidOpen
then
    external
fi

if ! externalConnected && lidOpen
then
    internal
fi

And hopefully it'll work.

Related Question