How to fix wmctrl Cannot open display when Python open subprocess
Question:
This is my program, and it works very well.
import subprocess
result = subprocess.check_output("wmctrl -l",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
print(result)
Output:
0x03800003 -1 name-PC Desktop
0x03e00037 0 name-PC How to fix wmctrl Cannot open display when Python open subprocess - Stack
Overflow - Firefox
0x05000006 0 name-PC name@name-PC: ~
0x05a00001 0 name-PC pr.py — ~/Program — Atom
0x05001c85 0 name-PC Terminal
But if I want to run this program at startup as root in Linux Mint I have problems. I want to run this py file at startup as root but I don’t know how to do it. The main question is how to do it.
This is my attempt to solve the problem. It does not work.
I added a file pr.service
to folder /etc/systemd/system/
:
[Unit]
After=network.target
[Service]
ExecStart=/usr/local/bin/pr.sh
[Install]
WantedBy=default.target
I created a file pr.sh in folder /usr/local/bin/
:
#!/bin/bash
/usr/bin/python3 '/home/name/Program/pr.py'
I used these commands:
sudo chmod 744 /usr/local/bin/pr.sh
sudo chmod 664 /etc/systemd/system/pr.service
sudo systemctl daemon-reload
sudo systemctl enable pr.service
If I run my program with command
systemctl start pr.service
I can see this error with command
sudo journalctl -u pr.service
I have an error command subprocess.CalledProcess Error: Command ‘wmctrl -l’ returned non-zero exit status 1.
I can change my py file, for example I can run
result = subprocess.check_output("/usr/bin/wmctrl -l",shell=True,stderr=subprocess.STDOUT)
I can change my py file to see error:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
RuntimeError: command ‘/usr/bin/wmctrl -l -p’ return with error (code 1): b’Cannot open display.
I have read about this attempt to find solution: https://linuxconfig.org/how-to-automatically-execute-shell-script-at-startup-boot-on-systemd-linux
This is an article how to autorun script in Linux as root. I did these things.
My main goal is to autostart my program as root:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
You don’t need to find mistake in my solution. It will be interesting to find any solution.
Answers:
I have find solution myself. The key is to use two commands:
os.system("xhost local:root &>/dev/null")
allow root opening X windows.
And
subprocess.check_output([command], shell=True, stderr=subprocess.STDOUT).decode('UTF-8')
command = "env DISPLAY=:0 XAUTHORITY=/home/ourname/.Xauthority "+"wmctrl -l -p -lp"
allow root to read our settings.
So we can rewrite our program.
import subprocess
import gc
import time
prf = ["env", "DISPLAY=:0", "XAUTHORITY=/home/ourname/.Xauthority"]
while True:
r1 = subprocess.run(['xhost', 'local:root'],stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL )
r2 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
if r1.returncode == 0 and r1.returncode == 0:
print("Now we will not have problem with display error")
break
time.sleep(3)
while True:
r1 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
for line in r1.stdout.split('n'):
print(line)
time.sleep(3)
gc.collect()
Te error "Cannot open display." also caused me trouble. This is how I could resolve it on Linux Mint 20.3 – only the DISPLAY code needed to be different from @ddd777’s answer. The xhost part was not necessary.
user = 'yourusername'
env = dict(DISPLAY = ':0.0', XAUTHORITY = f'/home/{user}/.Xauthority')
def get(cmd):
return subprocess.check_output(['/bin/bash', '-c', cmd], env=env
).decode('utf-8')
This is the error I was getting on Ubuntu 22.04. I was trying to use cron to run a python script.
Cannot open display.
Traceback (most recent call last):
File "/home/usera/Applications/auto_close_old_nautilus_windows.py", line 55, in <module>
wlist1 = [l.strip() for l in get(["wmctrl", "-lp"]).splitlines() if nautpid in l]
AttributeError: 'NoneType' object has no attribute 'splitlines'
These 2 solutions worked for me.
Solution 1
Run
crontab -e
Use export
to export the DISPLAY
and XAUTHORITY
variables. Note that a backslash is required prior to the equal symbol(XAUTHORITY=
).
# /tmp/crontab.kCWtBN/crontab
# Edit this file to introduce tasks to be run by cron.
#
# [...]
# m h dom mon dow command
*/1 * * * * export DISPLAY=:1 && export XAUTHORITY=/run/user/1000/gdm/Xauthority && python3 /home/usera/Applications/auto_close_old_nautilus_windows.py >>/home/usera/Applications/script.log 2>>/hom>
CTRL+X
and Y
to save your edits.
This should work. Below is what my python script had.
# auto_close_old_nautilus_windows.py - Note I do not pass in env=
subprocess.check_output(cmd).decode("utf-8").strip()
Solution 2
In your python script, specify the DISPLAY and XAUTHORITY variables and pass them in with the env argument.
env = dict(DISPLAY = ':1', XAUTHORITY = f'/run/user/1000/gdm/Xauthority')
subprocess.check_output(cmd, env=env).decode("utf-8").strip()
How were the DISPLAY and XAUTHORITY variables obtained?
Add these 2 lines (os.environ.get) to your script.
# auto_close_old_nautilus_windows.py
# ...
# other code in script
print(os.environ.get("DISPLAY"))
print(os.environ.get("XAUTHORITY"))
# other code in script
# ...
Run your script.
python3 auto_close_old_nautilus_windows.py
The script works and you get this output.
:1
/run/user/1000/gdm/Xauthority
The DISPLAY variable is :1
and the XAUTHORITY is /run/user/1000/gdm/Xauthority
. Your output will be different.
Why is the error happening to begin with?
When cron executes your script, DISPLAY and XAUTHORITY are not set. The 2 solutions I mention configure DISPLAY and XAUTHORITY before cron executes your python script.
References
This is my program, and it works very well.
import subprocess
result = subprocess.check_output("wmctrl -l",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
print(result)
Output:
0x03800003 -1 name-PC Desktop
0x03e00037 0 name-PC How to fix wmctrl Cannot open display when Python open subprocess - Stack
Overflow - Firefox
0x05000006 0 name-PC name@name-PC: ~
0x05a00001 0 name-PC pr.py — ~/Program — Atom
0x05001c85 0 name-PC Terminal
But if I want to run this program at startup as root in Linux Mint I have problems. I want to run this py file at startup as root but I don’t know how to do it. The main question is how to do it.
This is my attempt to solve the problem. It does not work.
I added a file pr.service
to folder /etc/systemd/system/
:
[Unit]
After=network.target
[Service]
ExecStart=/usr/local/bin/pr.sh
[Install]
WantedBy=default.target
I created a file pr.sh in folder /usr/local/bin/
:
#!/bin/bash
/usr/bin/python3 '/home/name/Program/pr.py'
I used these commands:
sudo chmod 744 /usr/local/bin/pr.sh
sudo chmod 664 /etc/systemd/system/pr.service
sudo systemctl daemon-reload
sudo systemctl enable pr.service
If I run my program with command
systemctl start pr.service
I can see this error with command
sudo journalctl -u pr.service
I have an error command subprocess.CalledProcess Error: Command ‘wmctrl -l’ returned non-zero exit status 1.
I can change my py file, for example I can run
result = subprocess.check_output("/usr/bin/wmctrl -l",shell=True,stderr=subprocess.STDOUT)
I can change my py file to see error:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
RuntimeError: command ‘/usr/bin/wmctrl -l -p’ return with error (code 1): b’Cannot open display.
I have read about this attempt to find solution: https://linuxconfig.org/how-to-automatically-execute-shell-script-at-startup-boot-on-systemd-linux
This is an article how to autorun script in Linux as root. I did these things.
My main goal is to autostart my program as root:
import subprocess
try:
result = subprocess.check_output("/usr/bin/wmctrl -l -p",shell=True,stderr=subprocess.STDOUT)
result = result.decode('UTF-8')
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
print(result)
You don’t need to find mistake in my solution. It will be interesting to find any solution.
I have find solution myself. The key is to use two commands:
os.system("xhost local:root &>/dev/null")
allow root opening X windows.
And
subprocess.check_output([command], shell=True, stderr=subprocess.STDOUT).decode('UTF-8')
command = "env DISPLAY=:0 XAUTHORITY=/home/ourname/.Xauthority "+"wmctrl -l -p -lp"
allow root to read our settings.
So we can rewrite our program.
import subprocess
import gc
import time
prf = ["env", "DISPLAY=:0", "XAUTHORITY=/home/ourname/.Xauthority"]
while True:
r1 = subprocess.run(['xhost', 'local:root'],stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL )
r2 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
if r1.returncode == 0 and r1.returncode == 0:
print("Now we will not have problem with display error")
break
time.sleep(3)
while True:
r1 = subprocess.run([prf[0], prf[1], prf[2],"wmctrl", "-l", "-p", "-lp"], encoding='utf-8', stdout=subprocess.PIPE)
for line in r1.stdout.split('n'):
print(line)
time.sleep(3)
gc.collect()
Te error "Cannot open display." also caused me trouble. This is how I could resolve it on Linux Mint 20.3 – only the DISPLAY code needed to be different from @ddd777’s answer. The xhost part was not necessary.
user = 'yourusername'
env = dict(DISPLAY = ':0.0', XAUTHORITY = f'/home/{user}/.Xauthority')
def get(cmd):
return subprocess.check_output(['/bin/bash', '-c', cmd], env=env
).decode('utf-8')
This is the error I was getting on Ubuntu 22.04. I was trying to use cron to run a python script.
Cannot open display.
Traceback (most recent call last):
File "/home/usera/Applications/auto_close_old_nautilus_windows.py", line 55, in <module>
wlist1 = [l.strip() for l in get(["wmctrl", "-lp"]).splitlines() if nautpid in l]
AttributeError: 'NoneType' object has no attribute 'splitlines'
These 2 solutions worked for me.
Solution 1
Run
crontab -e
Use export
to export the DISPLAY
and XAUTHORITY
variables. Note that a backslash is required prior to the equal symbol(XAUTHORITY=
).
# /tmp/crontab.kCWtBN/crontab
# Edit this file to introduce tasks to be run by cron.
#
# [...]
# m h dom mon dow command
*/1 * * * * export DISPLAY=:1 && export XAUTHORITY=/run/user/1000/gdm/Xauthority && python3 /home/usera/Applications/auto_close_old_nautilus_windows.py >>/home/usera/Applications/script.log 2>>/hom>
CTRL+X
and Y
to save your edits.
This should work. Below is what my python script had.
# auto_close_old_nautilus_windows.py - Note I do not pass in env=
subprocess.check_output(cmd).decode("utf-8").strip()
Solution 2
In your python script, specify the DISPLAY and XAUTHORITY variables and pass them in with the env argument.
env = dict(DISPLAY = ':1', XAUTHORITY = f'/run/user/1000/gdm/Xauthority')
subprocess.check_output(cmd, env=env).decode("utf-8").strip()
How were the DISPLAY and XAUTHORITY variables obtained?
Add these 2 lines (os.environ.get) to your script.
# auto_close_old_nautilus_windows.py
# ...
# other code in script
print(os.environ.get("DISPLAY"))
print(os.environ.get("XAUTHORITY"))
# other code in script
# ...
Run your script.
python3 auto_close_old_nautilus_windows.py
The script works and you get this output.
:1
/run/user/1000/gdm/Xauthority
The DISPLAY variable is :1
and the XAUTHORITY is /run/user/1000/gdm/Xauthority
. Your output will be different.
Why is the error happening to begin with?
When cron executes your script, DISPLAY and XAUTHORITY are not set. The 2 solutions I mention configure DISPLAY and XAUTHORITY before cron executes your python script.
References