You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
91 lines
2.7 KiB
91 lines
2.7 KiB
#!/usr/bin/env python |
|
# |
|
# * Corey Goldberg, 2012, 2013, 2015 |
|
# |
|
# * inspired by: |
|
# PyVirtualDisplay: http://pypi.python.org/pypi/PyVirtualDisplay |
|
|
|
|
|
"""wrapper for running display inside X virtual framebuffer (Xvfb)""" |
|
|
|
|
|
import os |
|
import fnmatch |
|
import random |
|
import subprocess |
|
import time |
|
|
|
|
|
class Xvfb: |
|
|
|
def __init__(self, width=800, height=680, colordepth=24, **kwargs): |
|
self.width = width |
|
self.height = height |
|
self.colordepth = colordepth |
|
|
|
self.xvfb_cmd = [ |
|
'-screen', '0', '%dx%dx%d' % |
|
(self.width, self.height, self.colordepth) |
|
] |
|
|
|
for key, value in kwargs.items(): |
|
self.xvfb_cmd = self.xvfb_cmd + ['-%s' % key, value] |
|
|
|
self.proc = None |
|
if 'DISPLAY' in os.environ: |
|
self.old_display_num = os.environ['DISPLAY'].split(':')[1] |
|
else: |
|
self.old_display_num = 0 |
|
|
|
def __enter__(self): |
|
self.start() |
|
return self |
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb): |
|
self.stop() |
|
|
|
def start(self): |
|
self.vdisplay_num = self.search_for_free_display() |
|
self.xvfb_cmd = ['Xvfb', ':%d' % self.vdisplay_num] + self.xvfb_cmd |
|
with open(os.devnull, 'w') as fnull: |
|
self.proc = subprocess.Popen(self.xvfb_cmd, |
|
stdout=fnull, |
|
stderr=fnull, |
|
close_fds=True) |
|
time.sleep(0.2) # give Xvfb time to start |
|
ret_code = self.proc.poll() |
|
if ret_code is None: |
|
self._redirect_display(self.vdisplay_num) |
|
else: |
|
self._redirect_display(self.old_display_num) |
|
self.proc = None |
|
print('Error: Xvfb did not start') |
|
|
|
def stop(self): |
|
self._redirect_display(self.old_display_num) |
|
if self.proc is not None: |
|
self.proc.kill() |
|
self.proc.wait() |
|
self.proc = None |
|
|
|
def search_for_free_display(self): |
|
ls = [int(x.split('X')[1].split('-')[0]) for x in self._lock_files()] |
|
min_display_num = 1000 |
|
if len(ls): |
|
display_num = max(min_display_num, max(ls) + 1) |
|
else: |
|
display_num = min_display_num |
|
random.seed() |
|
display_num += random.randint(0, 100) |
|
return display_num |
|
|
|
def _lock_files(self): |
|
tmpdir = '/tmp' |
|
pattern = '.X*-lock' |
|
names = fnmatch.filter(os.listdir(tmpdir), pattern) |
|
ls = [os.path.join(tmpdir, child) for child in names] |
|
ls = [p for p in ls if os.path.isfile(p)] |
|
return ls |
|
|
|
def _redirect_display(self, display_num): |
|
os.environ['DISPLAY'] = ':%s' % display_num
|
|
|