Files
cthulhu/tests/native_qt_controls.py

115 lines
4.7 KiB
Python

#!/usr/bin/env python3
# Copyright (c) 2026 Storm Dragon
# Authors: Storm Dragon, Angus Kola
# SPDX-License-Identifier: GPL-3.0-or-later
"""Check Qt menu and button states on a private X11/AT-SPI desktop."""
import os
from pathlib import Path
import subprocess
import sys
import tempfile
sys.dont_write_bytecode = True
from native_x11 import wait_for
from native_test_session import run_private_session
def fixture(version):
if version == '5':
from PyQt5 import QtCore, QtWidgets
else:
from PySide6 import QtCore, QtWidgets
class ControlWindow(QtWidgets.QMainWindow):
def keyPressEvent(self, event):
nonlocal option
targets = {QtCore.Qt.Key_F6: option, QtCore.Qt.Key_F7: ordinary,
QtCore.Qt.Key_F8: contextOption}
if event.key() in targets:
target = targets[event.key()]
popup = contextMenu if target is contextOption else menu
popup.popup(self.mapToGlobal(QtCore.QPoint(20, 50)))
popup.setActiveAction(target)
elif event.key() == QtCore.Qt.Key_F9:
checkbox.setFocus()
elif event.key() == QtCore.Qt.Key_F10:
toggle.setFocus()
elif event.key() == QtCore.Qt.Key_F11:
menu.removeAction(option)
option.deleteLater()
option = menu.addAction('Optional feature')
elif event.key() == QtCore.Qt.Key_F12:
option.setCheckable(False)
else:
super().keyPressEvent(event)
application = QtWidgets.QApplication([])
window = ControlWindow()
window.setWindowTitle('Qt control states probe')
content = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(content)
checkbox = QtWidgets.QCheckBox('Updates')
layout.addWidget(checkbox)
toggle = QtWidgets.QPushButton('Power')
toggle.setCheckable(True)
layout.addWidget(toggle)
window.setCentralWidget(content)
menu = window.menuBar().addMenu('&Actions')
option = menu.addAction('Optional feature')
option.setCheckable(True)
ordinary = menu.addAction('Ordinary action')
nestedMenu = menu.addMenu('Nested actions')
nestedMenu.addAction('Nested command')
contextMenu = QtWidgets.QMenu(window)
contextOption = contextMenu.addAction('Context option')
contextOption.setCheckable(True)
# Shared actions can retain their menu-bar accessibility parent even
# while the context menu emits their focus events.
contextMenu.addAction(ordinary)
contextMenu.addAction('Context command')
contextMenu.addAction(option)
window.resize(400, 250)
window.show()
checkbox.setFocus()
application.exec()
def run_inside():
root = Path(__file__).resolve().parents[1]
for version in ('5', '6'):
process = subprocess.Popen([sys.executable, __file__, '--fixture', version])
try:
def find_window():
result = subprocess.run(['xdotool', 'search', '--onlyvisible', '--name',
'^Qt control states probe$'], capture_output=True, text=True)
return result.stdout.strip().splitlines()[0] if result.stdout.strip() else None
windowId = wait_for(find_window, 'Qt fixture window missing')
subprocess.run(['xdotool', 'windowfocus', windowId], check=True)
from native_x11 import set_active_window
set_active_window(int(windowId))
subprocess.run(['go', 'test', './internal/app', '-run', '^TestNativeQtControlStates$',
'-count=1', '-v', '-timeout=45s'], cwd=root, check=True, timeout=60,
env=dict(os.environ, CTHULHU_NATIVE_QT_CONTROLS=version,
GOCACHE='/tmp/cthulhu-cache'))
finally:
process.terminate()
process.wait(timeout=5)
if __name__ == '__main__':
if '--fixture' in sys.argv:
fixture(sys.argv[-1])
elif '--inside' in sys.argv:
run_inside()
else:
with tempfile.TemporaryDirectory(prefix='cthulhu-qt-controls-') as temporary:
environment = dict(os.environ, HOME=temporary, XDG_CONFIG_HOME=temporary,
XDG_CACHE_HOME=temporary, XDG_DATA_HOME=temporary,
GOMODCACHE=subprocess.check_output(['go', 'env', 'GOMODCACHE'], text=True).strip(),
QT_QPA_PLATFORM='xcb', QT_LINUX_ACCESSIBILITY_ALWAYS_ON='1',
NO_AT_BRIDGE='0')
environment.pop('AT_SPI_BUS_ADDRESS', None)
run_private_session(['xvfb-run', '-a', 'dbus-run-session', '--', sys.executable,
__file__, '--inside'], env=environment, check=True)