• Stars
    star
    687
  • Rank 65,799 (Top 2 %)
  • Language
    Python
  • License
    BSD 2-Clause "Sim...
  • Created almost 14 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Python wrapper for Xvfb, Xephyr and Xvnc

pyvirtualdisplay is a python wrapper for Xvfb, Xephyr and Xvnc

Links:

workflow

Features:

  • python wrapper
  • supported python versions: 3.6, 3.7, 3.8, 3.9, 3.10, 3.11
  • back-ends: Xvfb, Xephyr and Xvnc

Possible applications:

  • headless run
  • GUI testing
  • automatic GUI screenshot

Installation

install the program:

$ python3 -m pip install pyvirtualdisplay

optional: Pillow should be installed for smartdisplay submodule:

$ python3 -m pip install pillow

optional: EasyProcess should be installed for some examples:

$ python3 -m pip install EasyProcess

optional: xmessage and gnumeric should be installed for some examples.

On Ubuntu 20.04:

$ sudo apt install x11-utils gnumeric

If you get this error message on Linux then your Pillow version is old.

ImportError: ImageGrab is macOS and Windows only

Install all dependencies and backends on Ubuntu 20.04:

$ sudo apt-get install xvfb xserver-xephyr tigervnc-standalone-server x11-utils gnumeric
$ python3 -m pip install pyvirtualdisplay pillow EasyProcess

Usage

Controlling the display with context manager:

from pyvirtualdisplay import Display
with Display() as disp:
    # display is active
    print(disp.is_alive()) # True
# display is stopped
print(disp.is_alive()) # False

Controlling the display with start() and stop() methods (not recommended):

from pyvirtualdisplay import Display
disp = Display()
disp.start()
# display is active
disp.stop()
# display is stopped

After Xvfb display is activated "DISPLAY" environment variable is set for Xvfb. (e.g. os.environ["DISPLAY"] = :1) After Xvfb display is stopped start() and stop() are not allowed to be called again, "DISPLAY" environment variable is restored to its original value.

Selecting Xvfb backend:

disp=Display()
# or
disp=Display(visible=False)
# or
disp=Display(backend="xvfb")

Selecting Xephyr backend:

disp=Display(visible=True)
# or
disp=Display(backend="xephyr")

Selecting Xvnc backend:

disp=Display(backend="xvnc")

Setting display size:

disp=Display(size=(100, 60))

Setting display color depth:

disp=Display(color_depth=24)

Headless run

A messagebox is displayed on a hidden display.

# pyvirtualdisplay/examples/headless.py

"Start Xvfb server. Open xmessage window."

from easyprocess import EasyProcess

from pyvirtualdisplay import Display

with Display(visible=False, size=(100, 60)) as disp:
    with EasyProcess(["xmessage", "hello"]) as proc:
        proc.wait()

Run it:

$ python3 -m pyvirtualdisplay.examples.headless

If visible=True then a nested Xephyr window opens and the GUI can be controlled.

vncserver

The same as headless example, but it can be controlled with a VNC client.

# pyvirtualdisplay/examples/vncserver.py

"Start virtual VNC server. Connect with: vncviewer localhost:5904"

from easyprocess import EasyProcess

from pyvirtualdisplay import Display

with Display(backend="xvnc", size=(100, 60), rfbport=5904) as disp:
    with EasyProcess(["xmessage", "hello"]) as proc:
        proc.wait()

Run it:

$ python3 -m pyvirtualdisplay.examples.vncserver

Check it with vncviewer:

$ vncviewer localhost:5904

GUI Test

# pyvirtualdisplay/examples/lowres.py

"Testing gnumeric on low resolution."
from easyprocess import EasyProcess

from pyvirtualdisplay import Display

# start Xephyr
with Display(visible=True, size=(320, 240)) as disp:
    # start Gnumeric
    with EasyProcess(["gnumeric"]) as proc:
        proc.wait()

Run it:

$ python3 -m pyvirtualdisplay.examples.lowres

Image:

Screenshot

# pyvirtualdisplay/examples/screenshot.py

"Create screenshot of xmessage in background using 'smartdisplay' submodule"
from easyprocess import EasyProcess

from pyvirtualdisplay.smartdisplay import SmartDisplay

# 'SmartDisplay' instead of 'Display'
# It has 'waitgrab()' method.
# It has more dependencies than Display.
with SmartDisplay() as disp:
    with EasyProcess(["xmessage", "hello"]):
        # wait until something is displayed on the virtual display (polling method)
        # and then take a fullscreen screenshot
        # and then crop it. Background is black.
        img = disp.waitgrab()
img.save("xmessage.png")

Run it:

$ python3 -m pyvirtualdisplay.examples.screenshot

Image:

Nested Xephyr

# pyvirtualdisplay/examples/nested.py

"Nested Xephyr servers"
from easyprocess import EasyProcess

from pyvirtualdisplay import Display

with Display(visible=True, size=(220, 180), bgcolor="black"):
    with Display(visible=True, size=(200, 160), bgcolor="white"):
        with Display(visible=True, size=(180, 140), bgcolor="black"):
            with Display(visible=True, size=(160, 120), bgcolor="white"):
                with Display(visible=True, size=(140, 100), bgcolor="black"):
                    with Display(visible=True, size=(120, 80), bgcolor="white"):
                        with Display(visible=True, size=(100, 60), bgcolor="black"):
                            with EasyProcess(["xmessage", "hello"]) as proc:
                                proc.wait()

Run it:

$ python3 -m pyvirtualdisplay.examples.nested

Image:

xauth

Some programs require a functional Xauthority file. PyVirtualDisplay can generate one and set the appropriate environment variables if you pass use_xauth=True to the Display constructor. Note however that this feature needs xauth installed, otherwise a pyvirtualdisplay.xauth.NotFoundError is raised.

Concurrency

If more X servers are started at the same time then there is race for free display numbers.

"Recent X servers as of version 1.13 (Xvfb, too) support the -displayfd command line option: It will make the X server choose the display itself" https://stackoverflow.com/questions/2520704/find-a-free-x11-display-number/

Version 1.13 was released in 2012: https://www.x.org/releases/individual/xserver/

First help text is checked (e.g. Xvfb -help) to find if -displayfd flag is available. If -displayfd flag is available then it is used to choose the display number. If not then a free display number is generated and there are 10 retries by default which should be enough for starting 10 X servers at the same time.

displayfd usage is disabled on macOS because it doesn't work with XQuartz-2.7.11, always 0 is returned.

Thread safety

All previous examples are not thread-safe, because pyvirtualdisplay replaces $DISPLAY environment variable in global os.environ in start() and sets back to original value in stop(). To make it thread-safe you have to manage the $DISPLAY variable. Set manage_global_env to False in constructor.

# pyvirtualdisplay/examples/threadsafe.py

"Start Xvfb server and open xmessage window. Thread safe."

import threading

from easyprocess import EasyProcess

from pyvirtualdisplay.smartdisplay import SmartDisplay


def thread_function(index):
    # manage_global_env=False is thread safe
    with SmartDisplay(manage_global_env=False) as disp:
        cmd = ["xmessage", str(index)]
        # disp.new_display_var should be used for new processes
        # disp.env() copies global os.environ and adds disp.new_display_var
        with EasyProcess(cmd, env=disp.env()):
            img = disp.waitgrab()
            img.save("xmessage{}.png".format(index))


t1 = threading.Thread(target=thread_function, args=(1,))
t2 = threading.Thread(target=thread_function, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()

Run it:

$ python3 -m pyvirtualdisplay.examples.threadsafe

Images:

Hierarchy

Alt text

More Repositories

1

pyscreenshot

Python screenshot library, replacement for the Pillow ImageGrab module on Linux.
Python
495
star
2

framebuffer-vncserver

VNC server for Linux framebuffer devices
C
162
star
3

EasyProcess

Easy to use python subprocess interface
Python
112
star
4

pyunpack

unpack archive files in python
Python
97
star
5

pysimavr

python wrapper for simavr which is AVR and arduino simulator
C
48
star
6

psidialogs

Python Simple Dialogs
Python
34
star
7

arduino-rtttl-player

Arduino library to play RTTTL melodies
Python
16
star
8

pysimavrgui

Simple GUI elements for AVR and arduino simulation. Programmed in python, based on pygame. Simavr is used for simulation.
Python
15
star
9

pyavrutils

pyavrutils is a Python library that can build AVR and arduino code at runtime.
Python
11
star
10

confduino

arduino library installer
Python
9
star
11

eagexp

export Eagle 6.6.0 schematic or board to image
POV-Ray SDL
9
star
12

entrypoint2

easy to use command-line interface for python modules
Python
8
star
13

discogui

Experimental Python library for discovering GUI elements.
Python
6
star
14

softusbduino

Arduino control over USB in Python
C
5
star
15

sphinxcontrib-programscreenshot

Sphinx extension to include program screenshot
Python
4
star
16

sphinxcontrib-gtkwave

Sphinx extension to include VCD (value change dump) files using GTKWave
Python
4
star
17

sphinxcontrib-eagle

Sphinx extension to include image or partlist of eagle schematic or board
Python
3
star
18

abandi

Console-based abandonware game installer
Python
3
star
19

MyElectronicProjects

Hobby electronic projects built by me
Python
3
star
20

fb-test-app

copy of https://github.com/prpplague/fb-test-app
C
2
star
21

mangui

GUI generator for command-line programs on Linux.
Python
2
star
22

serial_port_tester

Python serial port tester / monitor GUI
Python
2
star
23

nanpy-drivers

drivers for Nanpy + Arduino
C
1
star
24

StripboardProto

Stripboard based modular hardware prototyping system.
Python
1
star
25

nanpy-gui

TraitsUI based GUI for Nanpy
Python
1
star
26

electronic-measurements

Electronic measurements using Arduino, some additional hardware, USB port and Python libraries
Python
1
star