How to determine from a python application if X server/X forwarding is running?
Asked Answered
P

4

8

I'm writing a linux application which uses PyQt4 for GUI and which will only be used during remote sessions
(ssh -XY / vnc).

So sometimes it may occur that a user will forget to run ssh with X forwarding parameters or X forwarding will be unavailable for some reason. In this case the application crashes badly (unfortunately I am force to use an old C++ library wrapped into python and it completely messes user's current session if the application crashes).

I cannot use something else so my idea is to check if X forwarding is available before loading that library. However I have no idea how to do that.

I usually use xclock to check if my session has X forwarding enabled, but using xclock sounds like a big workaround.

ADDED
If possible I would like to use another way than creating an empty PyQt window and catching an exception.

Pence answered 25/8, 2012 at 14:5 Comment(0)
P
8

Check to see that the $DISPLAY environment variable is set - if they didn't use ssh -X, it will be empty (instead of containing something like localhost:10).

Pennyroyal answered 25/8, 2012 at 15:46 Comment(2)
That's examply what I was looking for, clean and simple, thanks.Pence
What happens if they use ssh -X but have no X server running? From my casual testing it seems that $DISPLAY won't be set, but is that reliably true?Selfheal
B
8

As mentioned before, you can check the DISPLAY environment variable:

>>> os.environ['DISPLAY']
'localhost:10.0'

If you're so inclined, you could actually connect to the display port to see that sshd is listening on it:

import os
import socket

def tcp_connect_to_display():
        # get the display from the environment
        display_env = os.environ['DISPLAY']

        # parse the display string
        display_host, display_num = display_env.split(':')
        display_num_major, display_num_minor = display_num.split('.')

        # calculate the port number
        display_port = 6000 + int(display_num_major)

        # attempt a TCP connection
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
                sock.connect((display_host, display_port))
        except socket.error:
                return False
        finally:
            sock.close()
        return True

This relies on standard X configuration using ports 6000 + display number.

Byronbyrum answered 25/8, 2012 at 17:3 Comment(1)
I will remember this solution, maybe it will prove useful in the future thanks.Pence
H
2

Similar to your xclock solution, I like to run xdpyinfo and see if it returns an error.

Hewitt answered 25/8, 2012 at 17:8 Comment(1)
This is great as it exits with zero if the client hasn't got a X-server running (a common thing for windows users who forget to start xming). I'm going to use this in a bash script, thanks.Sergiosergipe
D
0

X-Server can be checked with TkInter as in the following example (but there should be a similar way with PyQt4):

import time
import sys
try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk

while True:
    try:
        root = tk.Tk()
        break
    except tk.TclError as e:
        if "$DISPLAY" in str(e):
            print("$DISPLAY not set. Exiting.")
            sys.exit(1)
        print("Waiting for X server to start...")
        time.sleep(1)

print("X server running")
root.destroy()
sys.exit(0)

This will check $DISPLAY setting, X-Server process and related xhost authorization (but uses TkInter instead of PyQt4).

Demetria answered 27/1, 2019 at 10:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.