summaryrefslogtreecommitdiff
path: root/tests/helpers/run_x11_tablet.py
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-12 10:53:22 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-12 10:53:22 +0300
commit5206933399775e5ff46baefbbb3a776c2a9bb84c (patch)
treee7549216ac626c1f3ac22345f79fbf80cc5a90fb /tests/helpers/run_x11_tablet.py
parent881fb6cb1d64868132287bd9637f4ae1cbc3504c (diff)
feat: add type-safe native platform headers and portable drag support
- Add include/yasl/native/{wayland,cocoa,x11}.h with type-safe handle accessors. - Unify drag-and-drop and window carry support across Wayland, X11, and Cocoa. - Preserve full ABI compatibility for capability flags. - Install native headers conditionally based on enabled backend. - Include missing tablet example and backend test suites.
Diffstat (limited to 'tests/helpers/run_x11_tablet.py')
-rw-r--r--tests/helpers/run_x11_tablet.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/tests/helpers/run_x11_tablet.py b/tests/helpers/run_x11_tablet.py
new file mode 100644
index 0000000..cdd36ab
--- /dev/null
+++ b/tests/helpers/run_x11_tablet.py
@@ -0,0 +1,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()