summaryrefslogtreecommitdiff
path: root/tests/helpers/run_x11_tablet.py
blob: cdd36ab64c63129a69cdfa53519f0309cb74835d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#!/usr/bin/env python3
"""Run pen pressure through Xorg's virtual input driver and the example app."""

import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time


def main():
    xorg, test = sys.argv[1:]
    module_path = os.environ.get("YASL_XORG_MODULE_PATH")
    if not module_path:
        module_path = subprocess.check_output(
            [xorg, "-showDefaultModulePath"], text=True, timeout=5).strip()
    if any(c in module_path for c in ('"', "\n", "\r")):
        raise ValueError("Invalid Xorg module path")
    paths = [Path(path) for path in module_path.split(",")]
    for module in ("drivers/dummy_drv.so", "input/inputtest_drv.so"):
        if not any((path / module).is_file() for path in paths):
            raise RuntimeError(f"Missing Xorg module: {module}")
    with tempfile.TemporaryDirectory(prefix="yasl-tablet-") as directory:
        root = Path(directory)
        pen, eraser = root / "pen.sock", root / "eraser.sock"
        config = root / "xorg.conf"
        config.write_text(f'''
Section "ServerFlags"
    Option "AutoAddDevices" "false"
    Option "AutoAddGPU" "false"
    Option "DontVTSwitch" "true"
EndSection
Section "Files"
    ModulePath "{module_path}"
EndSection
Section "Module"
    Disable "glx"
EndSection
Section "Device"
    Identifier "virtual-video"
    Driver "dummy"
    VideoRam 16384
EndSection
Section "Monitor"
    Identifier "virtual-monitor"
    HorizSync 5.0 - 1000.0
    VertRefresh 5.0 - 200.0
    Modeline "1200x900" 96.96 1200 1280 1408 1616 900 901 904 932
EndSection
Section "Screen"
    Identifier "virtual-screen"
    Device "virtual-video"
    Monitor "virtual-monitor"
    DefaultDepth 24
    SubSection "Display"
        Depth 24
        Modes "1200x900"
    EndSubSection
EndSection
Section "InputDevice"
    Identifier "YASL Test Pen"
    Driver "inputtest"
    Option "DeviceType" "PointerAbsoluteProximity"
    Option "PointerHasPressure" "true"
    Option "SocketPath" "{pen}"
EndSection
Section "InputDevice"
    Identifier "YASL Test Reverse Tool"
    Driver "inputtest"
    Option "DeviceType" "PointerAbsoluteProximity"
    Option "PointerHasPressure" "true"
    Option "SocketPath" "{eraser}"
EndSection
Section "InputDevice"
    Identifier "YASL Test Keyboard"
    Driver "inputtest"
    Option "DeviceType" "Keyboard"
    Option "SocketPath" "{root / 'keyboard.sock'}"
EndSection
Section "ServerLayout"
    Identifier "virtual-layout"
    Screen "virtual-screen"
    InputDevice "YASL Test Pen" "CorePointer"
    InputDevice "YASL Test Reverse Tool" "SendCoreEvents"
    InputDevice "YASL Test Keyboard" "CoreKeyboard"
EndSection
''')
        display_file = root / "display"
        with display_file.open("w") as display_fd, (root / "server.log").open("w+") as log:
            server = subprocess.Popen([
                xorg, "-config", str(config), "-logfile", str(root / "xorg.log"),
                "-displayfd", str(display_fd.fileno()), "-noreset", "-nolisten", "tcp",
                "-novtswitch", "-sharevts", "-seat", f"yasl-tablet-test-{os.getpid()}",
            ], pass_fds=(display_fd.fileno(),), stdout=log, stderr=log)
            try:
                deadline = time.monotonic() + 10
                while not (display_file.read_text().strip() and pen.is_socket() and eraser.is_socket()):
                    if server.poll() is not None:
                        raise RuntimeError("The virtual X server stopped")
                    if time.monotonic() >= deadline:
                        raise TimeoutError("The virtual X server did not start")
                    time.sleep(0.02)
                env = os.environ.copy()
                env["DISPLAY"] = ":" + display_file.read_text().strip()
                env.pop("XAUTHORITY", None)
                subprocess.run([test, str(pen), str(eraser)], env=env, check=True, timeout=10)
            except BaseException:
                log.flush()
                log.seek(0, 2)
                log.seek(max(0, log.tell() - 8000))
                print(log.read(), file=sys.stderr)
                raise
            finally:
                server.terminate()
                try:
                    server.wait(timeout=5)
                except subprocess.TimeoutExpired:
                    server.kill()
                    server.wait()


if __name__ == "__main__":
    main()