From b6ed262f72fb268c330e93c13b1e530fe1e7d6a6 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Thu, 10 Sep 2026 15:22:40 +0200 Subject: [PATCH] test(gui): probe native window recreation on Wayland --- README.md | 15 +++++++++++++++ bec_widgets/examples/qt_window_probe.py | 25 ++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c9c7ad6b..b8f4471f 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,21 @@ cannot determine whether another application's window obscures it. Record what y the output and the result of `gnome-shell --version` when reporting a GNOME issue. Run again with `QT_QPA_PLATFORM=xcb` to compare backends. This script starts no BEC services and imports no BEC code. +If `cycle` alternates between appearing and disappearing, try `recreate` at least four times, +one command at a time. It runs hide/destroy/show on the same QWidget: unlike `cycle`, it releases +the native window resources before showing the widget again. This isolates native surface reuse +without changing BEC's window behavior. It is a diagnostic experiment, not a validated workaround +for BEC windows with docked widgets or embedded rendering contexts. + +To capture the Wayland protocol alongside the probe output, write to a unique temporary file if +the checkout is not writable: + +```bash +probe_log=$(mktemp /tmp/qt-window-wayland.XXXXXX) +WAYLAND_DEBUG=1 QT_QPA_PLATFORM=wayland python -u bec_widgets/examples/qt_window_probe.py 2>&1 | tee "$probe_log" +echo "$probe_log" +``` + ### 4. Rapid development (extensible by design) Build new widgets fast: Inherit from `BECWidget`, list your RPC methods in `USER_ACCESS`, and use `bec_dispatcher` to diff --git a/bec_widgets/examples/qt_window_probe.py b/bec_widgets/examples/qt_window_probe.py index d0845a0a..255d9f9d 100644 --- a/bec_widgets/examples/qt_window_probe.py +++ b/bec_widgets/examples/qt_window_probe.py @@ -3,6 +3,8 @@ Run this file directly with the affected environment's Python interpreter. Enter ``cycle`` repeatedly to hide/show a plain QWidget in one event-loop callback. Compare with separate ``hide`` and ``show`` commands and with ``raise``. +The ``recreate`` command also releases the native window resources before showing +the same QWidget again, to test whether reusing the native surface causes the problem. """ import json @@ -14,16 +16,25 @@ from qtpy.QtCore import QSocketNotifier, QTimer, qVersion from qtpy.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget +class ProbeWindow(QWidget): + """Plain widget with a diagnostic operation to recreate its native window.""" + + def recreate_native_window(self) -> None: + """Release native resources without closing or deleting the QWidget.""" + self.hide() + self.destroy() + self.show() + + def main() -> int: """Run a plain Qt window controlled through standard input on macOS or Linux.""" app = QApplication(sys.argv) - window = QWidget() + window = ProbeWindow() window.setWindowTitle("Qt window visibility probe") window.resize(800, 600) layout = QVBoxLayout(window) layout.addWidget(QLabel("Control this plain Qt window from the terminal.")) window.show() - handle = window.windowHandle() command_number = 0 print( @@ -40,18 +51,20 @@ def main() -> int: ), flush=True, ) - print("Commands: cycle, hide, show, raise, state, quit", flush=True) + print("Commands: cycle, recreate, hide, show, raise, state, quit", flush=True) def report(stage: str, number: int) -> None: + # Recreating the native window invalidates the previous QWindow wrapper. + handle = window.windowHandle() print( json.dumps( { "command": number, "stage": stage, "visible": window.isVisible(), - "native_visible": handle.isVisible(), + "native_visible": handle.isVisible() if handle is not None else None, "active": window.isActiveWindow(), - "exposed": handle.isExposed(), + "exposed": handle.isExposed() if handle is not None else None, "minimized": window.isMinimized(), } ), @@ -74,6 +87,8 @@ def main() -> int: if command == "cycle": window.hide() window.show() + elif command == "recreate": + window.recreate_native_window() elif command == "hide": window.hide() elif command == "show":