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.
Best Answer
ACPI is a low-level interface for mainboard vendors to provide information about built-in devices that cannot be (reliably) autodetected to the operating system. It also provides methods for power management and hardware monitoring to the kernel. One interesting thing ACPI provides are so called ACPI events. To create these, the hardware emits a special interrupt (the General Purpose Event Interrupt) when something happens on built in hardware and the kernel then calls the ACPI code which determines what happened on which built-in device. See the specification if you want to know how the whole thing works in detail.
acpid is a daemon that listens for the events generated by the ACPI subsystem in the kernel and allows to run commands when a specific event happened. For example if the hardware signaled via ACPI that the power button was pressed, you get an event on a device in the "button/power" class. The daemon can only react to these events generated via ACPI and not to events on e.g. the USB bus.
udev is a Linux-specific daemon that allows to react on changes in the device tree managed by the kernel. For example if you plug in an USB stick, the kernel is notified by the USB controller and a new device is added to the Linux device tree. Then the
usb_storage
driver detects that the new device is a storage device and creates sub-device nodes in the tree that allow the user space to handle the USB stick like any other hard drive. If you plug it out, these devices are removed from the tree. udev is notified on each of these additions and removals. udev can also react to some events that aren't device additions/removals like opening/closing of a CD tray, but that's most of it. You can runudevadm monitor --kernel
to see what events udev gets in real time.You can say that acpid and udev complement each other. udev is useful to react to major changes about any device the OS knows about, while acpid is useful to react to more specific events that happen to some built-in devices.