greshake / i3status-rust

Very resourcefriendly and feature-rich replacement for i3status, written in pure Rust
GNU General Public License v3.0
2.88k stars 475 forks source link

Toggle block not working with xrandr script #709

Closed 2ico closed 4 years ago

2ico commented 4 years ago

Toggle block in ~/.config/i3/status.toml

[[block]]
block = "toggle"
text = "VGA 1080"
command_state = "xrandr --listactivemonitors | grep VGA1"
command_on = "~/.screenlayout/VGA_auto.sh"
command_off = "~/.screenlayout/default.sh"
interval = 60

I am used to changing displays with those two scripts, which always work if they are manually executed. The first time I toggle off, default.sh is properly executed but, after I toggle on, the second time i toggle off turns the LVDS1 display on with unresponsive WM (except the mouse cursor) as it seems the resolution is still set to 1920x1080. I tried to print the output of xrandr to a log file (screenlayout.debug) and nothing gets printed but the date command.

~/.screenlayout/default.sh

#!/bin/sh
date -u >> /tmp/screenlayout.debug
xrandr --verbose --output VGA1 --off --output LVDS1 --auto 2>&1 >> /tmp/screenlayout.debug

~/.screenlayout/VGA_auto.sh

#!/bin/sh
date -u >> /tmp/screenlayout.debug
xrandr --verbose --output LVDS1 --off --output VGA1 --auto 2>&1 >> /tmp/screenlayout.debug

/tmp/screenlayout.debug

Tue 26 May 2020 06:26:15 PM UTC
crtc 1: disable
screen 0: 1366x768 360x202 mm  96.25dpi
crtc 0:     1366x768  60.10 +0+0 "LVDS1"
Tue 26 May 2020 06:26:20 PM UTC
crtc 0: disable
screen 0: 1920x1080 505x284 mm  96.57dpi
crtc 1:    1920x1080  60.00 +0+0 "VGA1"
Tue 26 May 2020 06:26:44 PM UTC

I know this may be an issue with xrandr and not the statusbar; I'm posting here because it's only happened when using it.

ammgws commented 4 years ago

Can you see if it happens with another bar such as i3blocks?

2ico commented 4 years ago

Just tried with i3blocks [clickme]. It doesn't work as well. With two clickme (toggle on and off) the off button doesn't do anything and outputs the same as the on button: crtc 1: 1920x1080 60.00 +0+0 "VGA1" With one single button (off) i get exactly the same behavior i had with i3status-rust.

2ico commented 4 years ago

In both cases, there's no bug for the first toggle after starting the WM. It appears when switching monitor two or more times or after running a toggle script manually.

ammgws commented 4 years ago

Yet when running the same sequence of commands manually at the terminal, it doesn't freeze up?

I'm not sure what else to try. What distro are you on? And what version is your xrandr? Perhaps you could try with the newest version or compile the latest source for it and try that in case there was a bug that was fixed. Or report this upstream to your distro where someone can provide some better troubleshooting help.

2ico commented 4 years ago

Yes, it doesn't freeze up with manual execution of the commands. I'm on Arch Linux 5.6.14. Xrandr is at the last stable version, 1.5.1.

ammgws commented 4 years ago

Could you please see if the xrandr block causes freezes too?

That block also causes freezes for some people, and the underlying cause might be related to your issue as well: https://github.com/greshake/i3status-rust/issues/668, https://github.com/greshake/i3status-rust/issues/459#issuecomment-560396033, #274

2ico commented 4 years ago

The brightness control works fine (not considering the fact that it uses color and not hardware brightness), and clicking the block changes the display the brightness control acts on.

ammgws commented 4 years ago

Argh, I was hoping it would freeze since that would probably have made tracking this down a lot easier...

What happens if you make and run a script like the below? The aim is to emulate what i3status-rs is doing by running each command in a separate process.

sh -c "xrandr --listactivemonitors | grep VGA1"
sleep 5
sh -c "~/.screenlayout/VGA_auto.sh"
sleep 5
sh -c "~/.screenlayout/default.sh"
sleep 50
sh -c "xrandr --listactivemonitors | grep VGA1"
ammgws commented 4 years ago

Also this rust version you can try:

use std::env;
use std::process::Command;
use std::{thread, time};

fn main() {
    println!("xrandr bug troubleshooting");

    println!("running `xrandr --listactivemonitors | grep VGA1`");
    let output = Command::new(env::var("SHELL").unwrap_or_else(|_| "sh".to_owned()))
        .args(&["-c", "xrandr --listactivemonitors | grep VGA1"])
        .output()
        .map(|o| String::from_utf8_lossy(&o.stdout).trim().to_owned())
        .unwrap_or_else(|e| e.to_string());
    println!("{}", format!("state command output: {}", output.trim_start()));

    thread::sleep(time::Duration::from_secs(5));
    println!("running vga_auto cmd");
    let _output = Command::new(env::var("SHELL").unwrap_or_else(|_| "sh".to_owned()))
        .args(&[
            "-c",
            "xrandr --verbose --output LVDS1 --off --output VGA1 --auto",
        ])
        .output()
        .expect("failed to run command");

    thread::sleep(time::Duration::from_secs(5));
    println!("running default cmd");
    let _output = Command::new(env::var("SHELL").unwrap_or_else(|_| "sh".to_owned()))
        .args(&[
            "-c",
            "xrandr --verbose --output VGA1 --off --output LVDS1 --auto",
        ])
        .output()
        .expect("failed to run command");
}
2ico commented 4 years ago

Argh, I was hoping it would freeze since that would probably have made tracking this down a lot easier...

What happens if you make and run a script like the below? The aim is to emulate what i3status-rs is doing by running each command in a separate process.

sh -c "xrandr --listactivemonitors | grep VGA1"
sleep 5
sh -c "~/.screenlayout/VGA_auto.sh"
sleep 5
sh -c "~/.screenlayout/default.sh"
sleep 50
sh -c "xrandr --listactivemonitors | grep VGA1"

I'll try asap

2ico commented 4 years ago

The script works just fine, after adjusting the first sleep to 15 seconds, since my external display takes ~5 seconds just to wake up.

2ico commented 4 years ago

The Rust version works as well! I have to mention that the toggle block doesn't have any problem with the first attempt as well, it only happens after toggling 3+ times.

2ico commented 4 years ago

I copy pasted the commands in the Rust script to have them run multiple times in sequence and it still works as expected.

ammgws commented 4 years ago

Is your bar set to autohide?

2ico commented 4 years ago

I think not, how do you set that?

ammgws commented 4 years ago

IIRC It's an option in the i3 bar config . When the bar is set to hide or an app is fullscreened i3 forcefully pauses i3status-rust. Was wondering if maybe that was somehow affecting the xrandr block since you said the sample rust program from above worked fine.

Try running i3status-rust with the --never-pause option

2ico commented 4 years ago

I didn't find the --never-pause option, so I reinstalled i3status-rust-git instead of i3status-rust and it isn't showing problems anymore.

ammgws commented 4 years ago

Wow if that actually fixed the issue then I think I might make --never-pause the default. Please keep us updated!

2ico commented 4 years ago

Hold on, it wasn't --never-pause to fix the issue. It was simply the more recent build coming with i3status-rust-git. All I had to do was install that version, and it worked fine.

ammgws commented 4 years ago

Hmm, IIRC there was a change to how we call external commands (or maybe it was just that we change the way we receive output from them) but I can't think of anything else other than that...