Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be aware of lid state #104

Open
Vladimir-csp opened this issue Apr 11, 2018 · 30 comments
Open

Be aware of lid state #104

Vladimir-csp opened this issue Apr 11, 2018 · 30 comments

Comments

@Vladimir-csp
Copy link
Contributor

Vladimir-csp commented Apr 11, 2018

To handle situations like laptop lid being closed or open with regards to external monitor:

  • save lid state into profile's setup along with output matches
  • trigger profile reload on lid state change.

Lid states can be acquired from /proc/acpi/button/lid/*/state

@phillipberndt
Copy link
Owner

This change would increase the complexity from a user's perspective a lot. Currently, it's fairly easy: A set of specific monitors connected to specific physical outputs is what autorandr calls a setup. Reproduce a setup, and autorandr will reload the configuration you stored earlier for you. I'd rather not add complexity to this. (For example, valid follow up questions would be: Shouldn't we then distinguish between monitors in stand-by and powered-on monitors as well?)

That being said, you can use the block hook to add this to your personal configurations.

@Vladimir-csp
Copy link
Contributor Author

For example, valid follow up questions would be: Shouldn't we then distinguish between monitors in stand-by and powered-on monitors as well?

No, there isn't any ambiguous continuation for this. The laptop case is pretty straightforward: if lid is closed, internal monitor becomes useless and is expected to be unused.

There may be a different approach: add a config option to mark output(s) as internal. Treat those outputs as disconnected if lid is closed.

@gabri94
Copy link

gabri94 commented Feb 21, 2019

I think it would be very useful too

@chmduquesne
Copy link
Contributor

chmduquesne commented Feb 26, 2019

@phillipberndt As a user, I would have expected autorandr to treat lid open/close events as a screen connect/disconnect. At least this is essentially how I think about it when I open/close the lid, since there is no way to actually disconnect it.

That being said, even though I would enjoy if autorandr's behavior would match my way of thinking, it is nice to see that it also provides ways to work around such edge cases and I thank you for that. I just spent an hour figuring this out, so I figured I would share for others who bump into the same issue.


Automatically switch display configuration based on lid state

  1. Create 2 separate display configurations, one with the lid closed, one with the lid open (I will assume you save them as config-open and config-close).
  2. Create the executable file .config/autorandr/config-open/block, which indicates when to block the config
#!/bin/bash

exec grep -q close /proc/acpi/button/lid/LID0/state
  1. And the executable file .config/autorandr/config-open/block
#!/bin/bash

exec grep -q open /proc/acpi/button/lid/LID0/state
  1. It's time to test: open/close the lid and then run
autorandr --change

Your preferred config should apply accordingly. If it does not, make sure you made both block files executables.

  1. Repeat steps 1-4 for as many configs where you want to a different behavior when the lid is open/closed

  2. Automate the whole thing. I used acpid for this, but there could be better ways. Create the executable file /etc/acpi/autorandr.sh

#!/bin/bash

/usr/bin/autorandr --batch --change --default default

Create the file /etc/acpi/events/lid-switch

event=button/lid LID (open|close)
action=/etc/acpi/autorandr.sh

And then restart acpid. The configuration switch should now happen automatically. If not, double check that /etc/acpi/autorandr.sh is executable.

@chmduquesne
Copy link
Contributor

This change would increase the complexity from a user's perspective a lot.

Honestly, after going through this, I would find it easier if autorandr treated a closed lid as disconnected (what am I going to display on it when it is closed anyway?)

@phillipberndt
Copy link
Owner

phillipberndt commented Mar 10, 2019

Honestly, after going through this, I would find it easier if autorandr treated a closed lid as disconnected (what am I going to display on it when it is closed anyway?)

Open questions:

  • Does every notebook expose lid state through /proc/acpi/button/lid/LID0/state? (I guess the answer to that is yes)
  • How can autorandr find out which display is the notebook's LCD? Hardcoding a couple of common names doesn't sound good enough. (Forcing users to configure this manually doesn't sound considerably better than what's possible already.)
  • How should it store the additional information about lid state? I made the promise not to break with the original autorandr's format, so this'd have to be an additional file I guess. A generic additional data file, json-encoded or .ini, probably?

@phillipberndt phillipberndt reopened this Mar 10, 2019
@Vladimir-csp
Copy link
Contributor Author

  1. it was exposed at this path on at least three of my laptops, otherwise no idea.
  2. config option in settings.ini, something like laptop_output. If it is set, then also enable the mechanism.
  3. there is no need to store additional information (at least in this case). If laptop_output is considered disconnected, profile configuration does not need any change.

@phillipberndt
Copy link
Owner

config option in settings.ini, something like laptop_output. If it is set, then also enable the mechanism.

As I wrote, I don't think this should be something that needs manual configuration. If it does then there's no real advantage over the block script - users still need to know about the feature and configure something to make this work.

there is no need to store additional information (at least in this case). If laptop_output is considered disconnected, profile configuration does not need any change.

The profile must store whether the lid is supposed to be open or closed, for the profile to apply, doesn't it?

@Vladimir-csp
Copy link
Contributor Author

The profile must store whether the lid is supposed to be open or closed, for the profile to apply, doesn't it?

Why? The profile would just lack an internal output, no EDID, no config (or off). Just like with any other disconnected outputs.

@phillipberndt
Copy link
Owner

Why? The profile would just lack an internal output, no EDID, no config (or off). Just like with any other disconnected outputs.

The config file contains the parameters that need to be passed to xrandr. And xrandr needs to be passed the information that the internal output is to be disabled. The setup file contains the displays attached to outputs as reported by the system. If the internal display is missing autorandr won't be able to detect that the profile applies.

@Vladimir-csp
Copy link
Contributor Author

Send --off to every output that isn't listed in config.
No EDID on "disconnected" output, no EDID in profile's setup. What is the problem?

@phillipberndt
Copy link
Owner

phillipberndt commented Mar 10, 2019

No EDID on "disconnected" output

If the system reports that an output has a monitor attached and the setup says that there should be none then the profile doesn't match and autorandr won't attempt to load it. If that'd change, then a profile where a notebook isn't attached to any output but its internal LCD would match even if there's something else attached.

@Vladimir-csp
Copy link
Contributor Author

By treating internal output as disconnected I meant faking it at info gathering stage. Inject xrandr data characteristic of a disconnected output if lid is closed. Everything else does not need to change in this case.
If autorandr receives output as disconnected, then:

if not match["connected"]:
    edid = None

This bit is already in the code. Just fake disconnected before this if happens.

@chmduquesne
Copy link
Contributor

Does every notebook expose lid state through /proc/acpi/button/lid/LID0/state? (I guess the answer to that is yes)

For some laptops, the lid state appears to be reported in /proc/acpi/button/lid/LID/state (see this thread for example). A good catch-all seems to be /proc/acpi/button/lid/*/state

How can autorandr find out which display is the notebook's LCD? Hardcoding a couple of common names doesn't sound good enough. (Forcing users to configure this manually doesn't sound considerably better than what's possible already.)

Unfortunately, I don't know about a bulletproof approach. I would suggest using a list of common names, but make it override-able. This way we would catch 80% of the users by default, and the last 20% can fine-tune their configuration if their use-case is not covered.

How should it store the additional information about lid state? I made the promise not to break with the original autorandr's format, so this'd have to be an additional file I guess. A generic additional data file, json-encoded or .ini, probably?

What would make sense to me would be that autoxrandr would just pretend the screen is disconnected if the lid is closed. Looking at the setup files I have in my profiles, that would correspond to removing the line of the lid from the setup file when the lid is closed.

@monokrome
Copy link

monokrome commented Jul 16, 2019

@chmduquesne Looks like Lenovo X1 Carbon is a practical example of one of the ones that use LID as opposed to LID0. One thing that seems confusing here is whether or not it is safe to assume that a lid always maps to a device called eDP*. /proc/ doesn't seem to tell us which display maps to the lid...

@chmduquesne
Copy link
Contributor

Hi,

I developed a branch where a closed lid is treated as if it was a disconnected output. This means, essentially, that running autorandr --save while the lid is closed will generate a setup file without a line for the lid. This line will still be present when the lid is open.

This is of course not backward compatible with current configurations, but I think it matches better what any user would expect. I know @phillipberndt wants to stay backward compatible, but I find it silly to make this behavior optional, because I can't think of anyone who would like to configure an output they can't see. If there is a situation justifying doing this, I am willing to modify my PR, but I am curious to read about it.

I also wrote code to trigger autorandr automatically when the lid is open/closed. On this part, I would particularly like to have feedback: Generally I tried to avoid depending on acpid, since nowadays I don't see a reason for installing it. I ended up writing a desktop autostart script monitoring the output of libinput debug-events, which I find pretty clean since it runs in userspace. However, there is a catch: for this to work, you must be in the group input. I am not sure whether the benefit of running this process in userspace is a good reason enough to justify forcing the user to be in a given group. The alternative is to make this a systemd service and to run the snippet as root.

What is your general opinion? Does it make sense to make this the default? Is it desirable to keep supporting old configs? Should the lid monitor be a systemd script, or an autostart desktop entry?

@Vladimir-csp
Copy link
Contributor Author

  1. If internal output is the only one connected, it should not be ignored. So mabye don't do edid = None during xrandr parsing. Count connected outputs after xrandr parsing and then decide.
  2. Internal output name and lid button device needs to be overrideable by config in case autodetection is wrong.
  3. Listener looks rather crude, and input group requirement is not good.
    A couple of ideas for listening:
    https://github.com/airtonix/laptop-lid-event-listener/blob/master/dbus-laptop-lid-listener.py
    https://www.freedesktop.org/software/systemd/python-systemd/login.html

@chmduquesne
Copy link
Contributor

chmduquesne commented Nov 5, 2019

  1. Good idea, I will count the number of screens.
  2. Ok, I will add command line options to override lid output name and lid state file.
  3. I disagree with your comment that it looks crude: It solves the problem in a clean, unix way. The output has a known format, the event has a known name. What I will do, however, is to limit the grep to the second field.

Some comments about the two links you suggested:

The systemd service that I provided solves the problem and does not require the user to be in input. I will make the parsing of this output a bit more rigorous, but mostly I think that libinput is the cleanest way of getting the lid events: libinput is also how window managers get keystrokes, and how wayland handles the lid.

@phillipberndt
Copy link
Owner

Thanks for implementing this, this makes the decision whether to do this way easier ;-)

re 3: I'm fine with the systemd stuff as it is in the PR. Those files are in the contrib folder, and others are free to improve it later.

re 2: IMHO it'd suffice to add this once someone complains. Your version should cover almost all cases.

re 1: Sounds good, and having this logic outside the xrandr parser is nicer from a code perspective, too.

@Vladimir-csp
Copy link
Contributor Author

re 3: If overhead of dumping and grepping through all input events is negligible, then ok.

@chmduquesne
Copy link
Contributor

1 is now implemented.

I elected not to implement 2, because I believe that my version covers all cases (as I mentioned in the PR, I went through the code of the graphic drivers to determine how the output names are generated for xrandr). I would prefer to add code only if we are sure that somebody needs it.

I understand why 3 is controversial. I agree that there is an small overhead: libinput does indeed receive all input events. I tried to mitigate this by improving the regexp performance and only look at the relevant part of the events. All I can say is that I am already using this code on my personal laptop as well as my work laptop without noticeable impact, but that is a totally subjective remark.

Alternatively, I can include code for doing this based on acpid hooks in the contrib directory. I was doing this before and it was working quite well. IMHO it's a heavier dependency, but the users may choose as they wish.

@Vladimir-csp if you can come up with a better implementation, you are very welcome to do so!

@phillipberndt
Copy link
Owner

Merged as is for now, thanks for your work! (Happy to accept further PRs if you guys have good ideas for improving lid event integration.)

@chmduquesne
Copy link
Contributor

Cool, thanks!

As far as I am concerned, this issue can be closed, then 🙂

@Vladimir-csp
Copy link
Contributor Author

Thanks!
I've tested it.
There was an issue, fix in PR.

@Diaoul
Copy link

Diaoul commented Jun 18, 2021

In case anyone is interested, I used acpid to trigger autorandr on lid change.

sudo pacman -S acpid
sudo systemctl enable --now acpid

Then in /etc/acpi/handler.sh I added this call on the lid close and open to trigger autorandr the same way udev does.

systemctl start --no-block autorandr.service

acpid also supports custom event configuration in /etc/acpi/events/ so I guess this may be another way to do it

ivankovnatsky added a commit to ivankovnatsky/nixos-config that referenced this issue Dec 13, 2021
@ivankovnatsky
Copy link

I used NixOS own module for acpid:

  services.acpid = {
    enable = true;

    lidEventCommands = ''
      #!${pkgs.bash}/bin/bash

      export DISPLAY=:0

      if grep -q open /proc/acpi/button/lid/LID/state; then
        ${pkgs.sudo}/bin/sudo -u ivan ${pkgs.autorandr}/bin/autorandr all
      else
        ${pkgs.sudo}/bin/sudo -u ivan ${pkgs.autorandr}/bin/autorandr monitor
      fi
    '';
  };

In plain it looks similar to this:

cat /nix/store/grkf04p1asj2q07ac472njl8wi8lz4np-acpi-events/lidEvent
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /nix/store/grkf04p1asj2q07ac472njl8wi8lz4np-acpi-events/lidEvent
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ event=button/lid.*
   2   │ action=/nix/store/l333rww8bci83pnwbr06i1la0kcfcs1p-lidEvent.sh/bin/lidEvent.sh '%e'
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
cat /nix/store/l333rww8bci83pnwbr06i1la0kcfcs1p-lidEvent.sh/bin/lidEvent.sh
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /nix/store/l333rww8bci83pnwbr06i1la0kcfcs1p-lidEvent.sh/bin/lidEvent.sh
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ #!/nix/store/a54wrar1jym1d8yvlijq0l2gghmy8szz-bash-5.1-p12/bin/bash
   2   │ export DISPLAY=:0
   3   │
   4   │ if grep -q open /proc/acpi/button/lid/LID/state; then
   5   │   /nix/store/rh30apmhk2vsnzd9dp60zyfni87v500i-sudo-1.9.7p2/bin/sudo -u ivan /nix/store/igzf3bhn1brjvx07mi2yw270f7c1npab-autorandr-1.11/bin/autorandr all
   6   │ else
   7   │   /nix/store/rh30apmhk2vsnzd9dp60zyfni87v500i-sudo-1.9.7p2/bin/sudo -u ivan /nix/store/igzf3bhn1brjvx07mi2yw270f7c1npab-autorandr-1.11/bin/autorandr monitor
   8   │ fi

@ghost
Copy link

ghost commented Dec 26, 2022

Here is a small script I created & it worked for me without issues:

#!/bin/bash
# Allows to automatically disable/enable the laptop screen when the lid is opend/closed

sudo pacman -S acpid --needed --noconfirm

sudo mkdir /etc/acpi/actions

sudo tee /etc/acpi/actions/lid.sh > /dev/null <<EOT
#!/bin/bash
# Automatically enable/disable output to Laptop (LVDS1) when lid close/open event happens

export XAUTHORITY=/home/$USER/.Xauthority
export DISPLAY=":0.0"

case "$3" in
    close)
        logger 'LID closed'
        xrandr --output LVDS1 --off
        ;;
    open)
        logger 'LID opened'
        xrandr --output LVDS1 --auto
        ;;
    *)
        logger "ACPI action undefined: $3"
        ;;
esac
EOT

sudo tee /etc/acpi/events/lid > /dev/null <<EOT
event=button/lid LID (open|close)
action=/etc/acpi/actions/lid.sh
EOT

sudo chmod +x /etc/acpi/actions/lid.sh

# remove 'anything' event handler
sudo rm /etc/acpi/events/anything

# restart acpid
sudo systemctl stop acpid
sudo systemctl enable acpid
sudo systemctl start acpid

Checked in at https://github.com/Xcalizorz/endeavouros-i3wm-setup/blob/main/custom-scripts/install-acpid-events.sh

@Nikratio
Copy link

For what it's worth, with current autorandr the lid is handled exactly as I expect, i.e. "lid closed" means internal monitor is disconnected. However, I need to manually run autorandr --change to detect this. It would be great if autorandr were to run automatically when the lid is closed/opened.

@chmduquesne
Copy link
Contributor

For what it's worth, with current autorandr the lid is handled exactly as I expect, i.e. "lid closed" means internal monitor is disconnected.

Yes, that was implemented in #169.

However, I need to manually run autorandr --change to detect this. It would be great if autorandr were to run automatically when the lid is closed/opened.

For this to happen, make sure contrib/etc/xdg/autostart/autorandr-lid-listener.desktop is installed properly.

Alternatively, you can run the script I suggested in #269, available in https://github.com/chmduquesne/autorandr/blob/dbus_monitor/contrib/autorandr_dbus_monitor.sh, which can replace every script that triggers autorandr.

@Nikratio
Copy link

Nikratio commented Jul 12, 2023

Thanks! Why not close this issue as fixed then? :-).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants