pythonlinuxsubprocesswmctrl

How to fix wmctrl Cannot open display when Python open subprocess


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.


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()